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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2022-07-20 18:25:31 +0300
committerJulian Eisel <julian@blender.org>2022-07-20 18:25:31 +0300
commit9dbcefb10e53cc809eb2e99333376b2a881c0863 (patch)
tree9ea058c2877c472aba82650e24e5927e3f03eded
parente1ced645fa208b3b77e07c99cb289cf7fa659ad3 (diff)
parent85f0b2ef5d5bfb67c245da0a52aeec44e63445fa (diff)
Merge branch 'asset-browser-grid-view' into file-browser-grid-view
-rw-r--r--.clang-format1
-rw-r--r--CMakeLists.txt79
-rw-r--r--build_files/build_environment/CMakeLists.txt15
-rw-r--r--build_files/build_environment/cmake/check_software.cmake5
-rw-r--r--build_files/build_environment/cmake/download.cmake15
-rw-r--r--build_files/build_environment/cmake/dpcpp.cmake109
-rw-r--r--build_files/build_environment/cmake/dpcpp_deps.cmake61
-rw-r--r--build_files/build_environment/cmake/embree.cmake23
-rw-r--r--build_files/build_environment/cmake/flex.cmake2
-rw-r--r--build_files/build_environment/cmake/gmmlib.cmake13
-rw-r--r--build_files/build_environment/cmake/harvest.cmake6
-rw-r--r--build_files/build_environment/cmake/igc.cmake126
-rw-r--r--build_files/build_environment/cmake/ispc.cmake6
-rw-r--r--build_files/build_environment/cmake/llvm.cmake8
-rw-r--r--build_files/build_environment/cmake/macros.cmake18
-rw-r--r--build_files/build_environment/cmake/ocloc.cmake24
-rw-r--r--build_files/build_environment/cmake/openimagedenoise.cmake2
-rw-r--r--build_files/build_environment/cmake/options.cmake2
-rw-r--r--build_files/build_environment/cmake/versions.cmake139
-rwxr-xr-xbuild_files/build_environment/install_deps.sh282
-rw-r--r--build_files/build_environment/patches/dpcpp.diff54
-rw-r--r--build_files/build_environment/patches/embree.diff65
-rw-r--r--build_files/build_environment/patches/flex.diff15
-rw-r--r--build_files/build_environment/patches/igc_opencl_clang.diff44
-rw-r--r--build_files/build_environment/windows/build_deps.cmd11
-rw-r--r--build_files/cmake/Modules/FindLevelZero.cmake56
-rw-r--r--build_files/cmake/Modules/FindPythonLibsUnix.cmake4
-rw-r--r--build_files/cmake/Modules/FindSYCL.cmake88
-rwxr-xr-xbuild_files/cmake/cmake_netbeans_project.py2
-rwxr-xr-xbuild_files/cmake/cmake_qtcreator_project.py2
-rw-r--r--build_files/cmake/cmake_static_check_clang_array.py2
-rw-r--r--build_files/cmake/cmake_static_check_cppcheck.py2
-rw-r--r--build_files/cmake/cmake_static_check_smatch.py2
-rw-r--r--build_files/cmake/cmake_static_check_sparse.py2
-rw-r--r--build_files/cmake/cmake_static_check_splint.py2
-rw-r--r--build_files/cmake/config/blender_lite.cmake3
-rw-r--r--build_files/cmake/config/blender_release.cmake11
-rw-r--r--build_files/cmake/platform/platform_unix.cmake55
-rw-r--r--build_files/cmake/platform/platform_win32.cmake3
-rwxr-xr-xbuild_files/cmake/project_info.py2
-rw-r--r--build_files/cmake/project_source_info.py2
-rw-r--r--build_files/config/pipeline_config.yaml2
-rwxr-xr-xbuild_files/package_spec/build_archive.py2
-rwxr-xr-xdoc/manpage/blender.1.py2
-rw-r--r--doc/python_api/requirements.txt12
-rw-r--r--doc/python_api/rst/info_best_practice.rst9
-rw-r--r--doc/python_api/rst_from_bmesh_opdefines.py2
-rw-r--r--doc/python_api/sphinx_changelog_gen.py366
-rw-r--r--doc/python_api/sphinx_doc_gen.py254
-rw-r--r--doc/python_api/sphinx_doc_gen_monkeypatch.py2
-rw-r--r--doc/python_api/static/css/theme_overrides.css7
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.cpp22
-rw-r--r--extern/audaspace/bindings/C/AUD_Special.h16
-rw-r--r--extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp2
-rw-r--r--extern/curve_fit_nd/README.blender2
-rw-r--r--extern/curve_fit_nd/curve_fit_nd.h12
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic.c126
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic_refit.c1
-rw-r--r--extern/curve_fit_nd/intern/generic_alloc_impl.h2
-rw-r--r--extern/curve_fit_nd/intern/generic_heap.c2
-rw-r--r--extern/draco/README.blender4
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc95
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h31
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc113
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h38
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_transform.cc25
-rw-r--r--extern/draco/draco/src/draco/attributes/attribute_transform.h36
-rw-r--r--extern/draco/draco/src/draco/attributes/geometry_attribute.cc12
-rw-r--r--extern/draco/draco/src/draco/attributes/geometry_attribute.h42
-rw-r--r--extern/draco/draco/src/draco/attributes/point_attribute.cc43
-rw-r--r--extern/draco/draco/src/draco/attributes/point_attribute.h6
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc22
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc16
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc19
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc15
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h6
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h133
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h4
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h9
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h9
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h7
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc33
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h4
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h6
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h18
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h2
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc4
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc15
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc3
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc44
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h3
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc13
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc64
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h8
-rw-r--r--extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc19
-rw-r--r--extern/draco/draco/src/draco/compression/config/compression_shared.h3
-rw-r--r--extern/draco/draco/src/draco/compression/config/draco_options.h6
-rw-r--r--extern/draco/draco/src/draco/compression/decode.cc5
-rw-r--r--extern/draco/draco/src/draco/compression/encode_base.h8
-rw-r--r--extern/draco/draco/src/draco/compression/entropy/ans.h7
-rw-r--r--extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h9
-rw-r--r--extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h4
-rw-r--r--extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc2
-rw-r--r--extern/draco/draco/src/draco/compression/expert_encode.cc2
-rw-r--r--extern/draco/draco/src/draco/compression/expert_encode.h6
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc31
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc1
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc2
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h1
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h2
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h7
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc7
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc4
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h1
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h2
-rw-r--r--extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h2
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h5
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h5
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc27
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h4
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h3
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h3
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h2
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc10
-rw-r--r--extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc14
-rw-r--r--extern/draco/draco/src/draco/core/bounding_box.cc13
-rw-r--r--extern/draco/draco/src/draco/core/bounding_box.h42
-rw-r--r--extern/draco/draco/src/draco/core/cycle_timer.cc14
-rw-r--r--extern/draco/draco/src/draco/core/cycle_timer.h7
-rw-r--r--extern/draco/draco/src/draco/core/data_buffer.cc2
-rw-r--r--extern/draco/draco/src/draco/core/decoder_buffer.h12
-rw-r--r--extern/draco/draco/src/draco/core/draco_index_type_vector.h3
-rw-r--r--extern/draco/draco/src/draco/core/draco_version.h2
-rw-r--r--extern/draco/draco/src/draco/core/macros.h27
-rw-r--r--extern/draco/draco/src/draco/core/options.h2
-rw-r--r--extern/draco/draco/src/draco/core/status.h4
-rw-r--r--extern/draco/draco/src/draco/core/varint_decoding.h1
-rw-r--r--extern/draco/draco/src/draco/core/vector_d.h14
-rw-r--r--extern/draco/draco/src/draco/draco_features.h2
-rw-r--r--extern/draco/draco/src/draco/mesh/corner_table.cc7
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh.h4
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h6
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_cleanup.cc321
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_cleanup.h27
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_misc_functions.h1
-rw-r--r--extern/draco/draco/src/draco/mesh/mesh_stripifier.h8
-rw-r--r--extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc2
-rw-r--r--extern/draco/draco/src/draco/metadata/geometry_metadata.cc15
-rw-r--r--extern/draco/draco/src/draco/metadata/geometry_metadata.h2
-rw-r--r--extern/draco/draco/src/draco/metadata/metadata.cc8
-rw-r--r--extern/draco/draco/src/draco/metadata/metadata.h1
-rw-r--r--extern/draco/draco/src/draco/metadata/metadata_decoder.cc10
-rw-r--r--extern/draco/draco/src/draco/point_cloud/point_cloud.cc16
-rw-r--r--extern/draco/patches/blender.patch30
-rw-r--r--extern/draco/src/common.cpp28
-rw-r--r--extern/draco/src/common.h2
-rw-r--r--extern/draco/src/decoder.cpp74
-rw-r--r--extern/draco/src/decoder.h36
-rw-r--r--extern/draco/src/encoder.cpp97
-rw-r--r--extern/draco/src/encoder.h33
-rw-r--r--extern/mantaflow/README.blender3
-rw-r--r--extern/mantaflow/helper/pwrapper/registry.cpp31
-rw-r--r--extern/mantaflow/helper/pwrapper/registry.h7
-rw-r--r--extern/mantaflow/patches/local_namespace.diff86
-rw-r--r--intern/CMakeLists.txt7
-rw-r--r--intern/atomic/atomic_ops.h2
-rw-r--r--intern/atomic/intern/atomic_ops_ext.h18
-rw-r--r--intern/atomic/tests/atomic_test.cc19
-rw-r--r--intern/cycles/CMakeLists.txt4
-rw-r--r--intern/cycles/blender/CMakeLists.txt4
-rw-r--r--intern/cycles/blender/addon/__init__.py2
-rw-r--r--intern/cycles/blender/addon/camera.py2
-rw-r--r--intern/cycles/blender/addon/engine.py2
-rw-r--r--intern/cycles/blender/addon/operators.py2
-rw-r--r--intern/cycles/blender/addon/osl.py2
-rw-r--r--intern/cycles/blender/addon/presets.py28
-rw-r--r--intern/cycles/blender/addon/properties.py35
-rw-r--r--intern/cycles/blender/addon/ui.py26
-rw-r--r--intern/cycles/blender/addon/version_update.py2
-rw-r--r--intern/cycles/blender/camera.cpp13
-rw-r--r--intern/cycles/blender/curves.cpp64
-rw-r--r--intern/cycles/blender/device.cpp4
-rw-r--r--intern/cycles/blender/display_driver.cpp6
-rw-r--r--intern/cycles/blender/geometry.cpp8
-rw-r--r--intern/cycles/blender/image.cpp165
-rw-r--r--intern/cycles/blender/mesh.cpp244
-rw-r--r--intern/cycles/blender/object.cpp2
-rw-r--r--intern/cycles/blender/pointcloud.cpp61
-rw-r--r--intern/cycles/blender/python.cpp9
-rw-r--r--intern/cycles/blender/session.cpp4
-rw-r--r--intern/cycles/blender/sync.cpp4
-rw-r--r--intern/cycles/blender/volume.cpp2
-rw-r--r--intern/cycles/bvh/build.cpp44
-rw-r--r--intern/cycles/bvh/embree.cpp8
-rw-r--r--intern/cycles/bvh/params.h2
-rw-r--r--intern/cycles/cmake/external_libs.cmake21
-rw-r--r--intern/cycles/device/CMakeLists.txt19
-rw-r--r--intern/cycles/device/cpu/device_impl.cpp28
-rw-r--r--intern/cycles/device/cuda/device.cpp28
-rw-r--r--intern/cycles/device/cuda/device_impl.cpp64
-rw-r--r--intern/cycles/device/cuda/queue.cpp6
-rw-r--r--intern/cycles/device/device.cpp46
-rw-r--r--intern/cycles/device/device.h9
-rw-r--r--intern/cycles/device/hip/device.cpp25
-rw-r--r--intern/cycles/device/hip/device_impl.cpp58
-rw-r--r--intern/cycles/device/hip/queue.cpp6
-rw-r--r--intern/cycles/device/hip/util.h2
-rw-r--r--intern/cycles/device/kernel.cpp2
-rw-r--r--intern/cycles/device/memory.h2
-rw-r--r--intern/cycles/device/metal/bvh.mm2
-rw-r--r--intern/cycles/device/metal/device.mm14
-rw-r--r--intern/cycles/device/metal/device_impl.h14
-rw-r--r--intern/cycles/device/metal/device_impl.mm240
-rw-r--r--intern/cycles/device/metal/kernel.h30
-rw-r--r--intern/cycles/device/metal/kernel.mm224
-rw-r--r--intern/cycles/device/metal/queue.h76
-rw-r--r--intern/cycles/device/metal/queue.mm598
-rw-r--r--intern/cycles/device/metal/util.h14
-rw-r--r--intern/cycles/device/metal/util.mm74
-rw-r--r--intern/cycles/device/oneapi/device.cpp185
-rw-r--r--intern/cycles/device/oneapi/device.h24
-rw-r--r--intern/cycles/device/oneapi/device_impl.cpp426
-rw-r--r--intern/cycles/device/oneapi/device_impl.h100
-rw-r--r--intern/cycles/device/oneapi/dll_interface.h17
-rw-r--r--intern/cycles/device/oneapi/queue.cpp165
-rw-r--r--intern/cycles/device/oneapi/queue.h51
-rw-r--r--intern/cycles/device/optix/device.cpp6
-rw-r--r--intern/cycles/device/optix/device_impl.cpp97
-rw-r--r--intern/cycles/device/optix/device_impl.h3
-rw-r--r--intern/cycles/device/optix/queue.cpp8
-rw-r--r--intern/cycles/device/queue.cpp21
-rw-r--r--intern/cycles/device/queue.h7
-rw-r--r--intern/cycles/hydra/display_driver.cpp85
-rw-r--r--intern/cycles/hydra/display_driver.h9
-rw-r--r--intern/cycles/hydra/output_driver.cpp8
-rw-r--r--intern/cycles/hydra/render_buffer.cpp18
-rw-r--r--intern/cycles/hydra/render_buffer.h4
-rw-r--r--intern/cycles/integrator/denoiser.cpp4
-rw-r--r--intern/cycles/integrator/denoiser_device.cpp2
-rw-r--r--intern/cycles/integrator/denoiser_oidn.cpp4
-rw-r--r--intern/cycles/integrator/path_trace.cpp68
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.cpp74
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.h4
-rw-r--r--intern/cycles/integrator/render_scheduler.cpp21
-rw-r--r--intern/cycles/integrator/shader_eval.cpp4
-rw-r--r--intern/cycles/integrator/work_tile_scheduler.cpp6
-rw-r--r--intern/cycles/kernel/CMakeLists.txt227
-rw-r--r--intern/cycles/kernel/bake/bake.h8
-rw-r--r--intern/cycles/kernel/bvh/bvh.h64
-rw-r--r--intern/cycles/kernel/bvh/embree.h20
-rw-r--r--intern/cycles/kernel/bvh/local.h33
-rw-r--r--intern/cycles/kernel/bvh/nodes.h50
-rw-r--r--intern/cycles/kernel/bvh/shadow_all.h69
-rw-r--r--intern/cycles/kernel/bvh/traversal.h52
-rw-r--r--intern/cycles/kernel/bvh/util.h51
-rw-r--r--intern/cycles/kernel/bvh/volume.h43
-rw-r--r--intern/cycles/kernel/bvh/volume_all.h57
-rw-r--r--intern/cycles/kernel/camera/camera.h28
-rw-r--r--intern/cycles/kernel/closure/alloc.h4
-rw-r--r--intern/cycles/kernel/closure/bsdf.h10
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair_principled.h28
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h4
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet_multi.h10
-rw-r--r--intern/cycles/kernel/closure/volume.h2
-rw-r--r--intern/cycles/kernel/data_arrays.h82
-rw-r--r--intern/cycles/kernel/data_template.h206
-rw-r--r--intern/cycles/kernel/device/cpu/compat.h14
-rw-r--r--intern/cycles/kernel/device/cpu/globals.h26
-rw-r--r--intern/cycles/kernel/device/cpu/image.h4
-rw-r--r--intern/cycles/kernel/device/cpu/kernel.cpp8
-rw-r--r--intern/cycles/kernel/device/cuda/globals.h26
-rw-r--r--intern/cycles/kernel/device/gpu/image.h4
-rw-r--r--intern/cycles/kernel/device/gpu/kernel.h25
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_active_index.h100
-rw-r--r--intern/cycles/kernel/device/hip/compat.h2
-rw-r--r--intern/cycles/kernel/device/hip/globals.h26
-rw-r--r--intern/cycles/kernel/device/metal/context_end.h2
-rw-r--r--intern/cycles/kernel/device/metal/function_constants.h15
-rw-r--r--intern/cycles/kernel/device/metal/globals.h18
-rw-r--r--intern/cycles/kernel/device/metal/kernel.metal85
-rw-r--r--intern/cycles/kernel/device/oneapi/compat.h206
-rw-r--r--intern/cycles/kernel/device/oneapi/context_begin.h13
-rw-r--r--intern/cycles/kernel/device/oneapi/context_end.h7
-rw-r--r--intern/cycles/kernel/device/oneapi/dll_interface_template.h53
-rw-r--r--intern/cycles/kernel/device/oneapi/globals.h47
-rw-r--r--intern/cycles/kernel/device/oneapi/image.h385
-rw-r--r--intern/cycles/kernel/device/oneapi/kernel.cpp914
-rw-r--r--intern/cycles/kernel/device/oneapi/kernel.h57
-rw-r--r--intern/cycles/kernel/device/oneapi/kernel_templates.h123
-rw-r--r--intern/cycles/kernel/device/optix/globals.h16
-rw-r--r--intern/cycles/kernel/device/optix/kernel.cu66
-rw-r--r--intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu12
-rw-r--r--intern/cycles/kernel/film/accumulate.h12
-rw-r--r--intern/cycles/kernel/film/passes.h7
-rw-r--r--intern/cycles/kernel/geom/attribute.h31
-rw-r--r--intern/cycles/kernel/geom/curve.h44
-rw-r--r--intern/cycles/kernel/geom/curve_intersect.h64
-rw-r--r--intern/cycles/kernel/geom/motion_curve.h24
-rw-r--r--intern/cycles/kernel/geom/motion_point.h4
-rw-r--r--intern/cycles/kernel/geom/motion_triangle.h30
-rw-r--r--intern/cycles/kernel/geom/motion_triangle_intersect.h8
-rw-r--r--intern/cycles/kernel/geom/motion_triangle_shader.h4
-rw-r--r--intern/cycles/kernel/geom/object.h72
-rw-r--r--intern/cycles/kernel/geom/patch.h24
-rw-r--r--intern/cycles/kernel/geom/point.h14
-rw-r--r--intern/cycles/kernel/geom/point_intersect.h21
-rw-r--r--intern/cycles/kernel/geom/primitive.h58
-rw-r--r--intern/cycles/kernel/geom/shader_data.h60
-rw-r--r--intern/cycles/kernel/geom/subd_triangle.h119
-rw-r--r--intern/cycles/kernel/geom/triangle.h136
-rw-r--r--intern/cycles/kernel/geom/triangle_intersect.h32
-rw-r--r--intern/cycles/kernel/geom/volume.h2
-rw-r--r--intern/cycles/kernel/integrator/init_from_bake.h28
-rw-r--r--intern/cycles/kernel/integrator/init_from_camera.h6
-rw-r--r--intern/cycles/kernel/integrator/intersect_closest.h108
-rw-r--r--intern/cycles/kernel/integrator/intersect_shadow.h6
-rw-r--r--intern/cycles/kernel/integrator/intersect_subsurface.h2
-rw-r--r--intern/cycles/kernel/integrator/intersect_volume_stack.h17
-rw-r--r--intern/cycles/kernel/integrator/megakernel.h3
-rw-r--r--intern/cycles/kernel/integrator/mnee.h46
-rw-r--r--intern/cycles/kernel/integrator/path_state.h3
-rw-r--r--intern/cycles/kernel/integrator/shade_background.h11
-rw-r--r--intern/cycles/kernel/integrator/shade_light.h21
-rw-r--r--intern/cycles/kernel/integrator/shade_shadow.h23
-rw-r--r--intern/cycles/kernel/integrator/shade_surface.h79
-rw-r--r--intern/cycles/kernel/integrator/shade_volume.h93
-rw-r--r--intern/cycles/kernel/integrator/shader_eval.h16
-rw-r--r--intern/cycles/kernel/integrator/shadow_catcher.h2
-rw-r--r--intern/cycles/kernel/integrator/shadow_state_template.h3
-rw-r--r--intern/cycles/kernel/integrator/state.h3
-rw-r--r--intern/cycles/kernel/integrator/state_flow.h273
-rw-r--r--intern/cycles/kernel/integrator/state_template.h10
-rw-r--r--intern/cycles/kernel/integrator/state_util.h12
-rw-r--r--intern/cycles/kernel/integrator/subsurface.h28
-rw-r--r--intern/cycles/kernel/integrator/subsurface_disk.h8
-rw-r--r--intern/cycles/kernel/integrator/subsurface_random_walk.h21
-rw-r--r--intern/cycles/kernel/integrator/volume_stack.h6
-rw-r--r--intern/cycles/kernel/light/background.h40
-rw-r--r--intern/cycles/kernel/light/light.h62
-rw-r--r--intern/cycles/kernel/light/sample.h13
-rw-r--r--intern/cycles/kernel/osl/services.cpp15
-rw-r--r--intern/cycles/kernel/sample/jitter.h6
-rw-r--r--intern/cycles/kernel/sample/pattern.h2
-rw-r--r--intern/cycles/kernel/svm/ao.h5
-rw-r--r--intern/cycles/kernel/svm/bevel.h9
-rw-r--r--intern/cycles/kernel/svm/closure.h4
-rw-r--r--intern/cycles/kernel/svm/color_util.h2
-rw-r--r--intern/cycles/kernel/svm/ies.h12
-rw-r--r--intern/cycles/kernel/svm/map_range.h8
-rw-r--r--intern/cycles/kernel/svm/mapping_util.h7
-rw-r--r--intern/cycles/kernel/svm/math_util.h4
-rw-r--r--intern/cycles/kernel/svm/node_types_template.h110
-rw-r--r--intern/cycles/kernel/svm/ramp.h2
-rw-r--r--intern/cycles/kernel/svm/svm.h696
-rw-r--r--intern/cycles/kernel/svm/tex_coord.h4
-rw-r--r--intern/cycles/kernel/svm/types.h101
-rw-r--r--intern/cycles/kernel/svm/voronoi.h4
-rw-r--r--intern/cycles/kernel/textures.h82
-rw-r--r--intern/cycles/kernel/types.h280
-rw-r--r--intern/cycles/kernel/util/lookup_table.h4
-rw-r--r--intern/cycles/scene/alembic.cpp2
-rw-r--r--intern/cycles/scene/attribute.cpp52
-rw-r--r--intern/cycles/scene/attribute.h1
-rw-r--r--intern/cycles/scene/camera.cpp4
-rw-r--r--intern/cycles/scene/colorspace.cpp19
-rw-r--r--intern/cycles/scene/constant_fold.cpp13
-rw-r--r--intern/cycles/scene/film.cpp10
-rw-r--r--intern/cycles/scene/geometry.cpp52
-rw-r--r--intern/cycles/scene/image.cpp15
-rw-r--r--intern/cycles/scene/image_oiio.cpp47
-rw-r--r--intern/cycles/scene/image_vdb.cpp8
-rw-r--r--intern/cycles/scene/integrator.cpp6
-rw-r--r--intern/cycles/scene/light.cpp23
-rw-r--r--intern/cycles/scene/mesh.cpp2
-rw-r--r--intern/cycles/scene/mesh_displace.cpp2
-rw-r--r--intern/cycles/scene/object.cpp6
-rw-r--r--intern/cycles/scene/osl.cpp4
-rw-r--r--intern/cycles/scene/particles.cpp2
-rw-r--r--intern/cycles/scene/scene.cpp172
-rw-r--r--intern/cycles/scene/scene.h6
-rw-r--r--intern/cycles/scene/shader_graph.cpp16
-rw-r--r--intern/cycles/scene/shader_nodes.cpp18
-rw-r--r--intern/cycles/scene/svm.cpp24
-rw-r--r--intern/cycles/scene/svm.h1
-rw-r--r--intern/cycles/scene/tables.cpp2
-rw-r--r--intern/cycles/scene/volume.cpp10
-rw-r--r--intern/cycles/session/denoising.cpp2
-rw-r--r--intern/cycles/session/session.cpp6
-rw-r--r--intern/cycles/session/tile.cpp16
-rw-r--r--intern/cycles/test/render_graph_finalize_test.cpp2
-rw-r--r--intern/cycles/util/atomic.h110
-rw-r--r--intern/cycles/util/color.h6
-rw-r--r--intern/cycles/util/debug.cpp2
-rw-r--r--intern/cycles/util/half.h16
-rw-r--r--intern/cycles/util/image.h20
-rw-r--r--intern/cycles/util/log.h19
-rw-r--r--intern/cycles/util/math.h32
-rw-r--r--intern/cycles/util/math_float3.h62
-rw-r--r--intern/cycles/util/math_float4.h148
-rw-r--r--intern/cycles/util/math_intersect.h37
-rw-r--r--intern/cycles/util/string.cpp18
-rw-r--r--intern/cycles/util/string.h2
-rw-r--r--intern/cycles/util/task.cpp2
-rw-r--r--intern/cycles/util/time.cpp2
-rw-r--r--intern/cycles/util/transform.cpp6
-rw-r--r--intern/cycles/util/transform.h6
-rw-r--r--intern/cycles/util/types_float2.h4
-rw-r--r--intern/cycles/util/types_float2_impl.h4
-rw-r--r--intern/cycles/util/types_float3.h4
-rw-r--r--intern/cycles/util/types_float3_impl.h4
-rw-r--r--intern/cycles/util/types_float4.h4
-rw-r--r--intern/cycles/util/types_float4_impl.h4
-rw-r--r--intern/cycles/util/types_float8.h4
-rw-r--r--intern/cycles/util/types_float8_impl.h4
-rw-r--r--intern/cycles/util/types_int2.h4
-rw-r--r--intern/cycles/util/types_int2_impl.h4
-rw-r--r--intern/cycles/util/types_int3.h4
-rw-r--r--intern/cycles/util/types_int3_impl.h4
-rw-r--r--intern/cycles/util/types_int4.h4
-rw-r--r--intern/cycles/util/types_int4_impl.h6
-rw-r--r--intern/cycles/util/types_uchar2.h4
-rw-r--r--intern/cycles/util/types_uchar2_impl.h4
-rw-r--r--intern/cycles/util/types_uchar3.h4
-rw-r--r--intern/cycles/util/types_uchar3_impl.h4
-rw-r--r--intern/cycles/util/types_uchar4.h4
-rw-r--r--intern/cycles/util/types_uchar4_impl.h4
-rw-r--r--intern/cycles/util/types_uint2.h4
-rw-r--r--intern/cycles/util/types_uint2_impl.h4
-rw-r--r--intern/cycles/util/types_uint3.h4
-rw-r--r--intern/cycles/util/types_uint3_impl.h4
-rw-r--r--intern/cycles/util/types_uint4.h4
-rw-r--r--intern/cycles/util/types_uint4_impl.h4
-rw-r--r--intern/cycles/util/types_ushort4.h2
-rw-r--r--intern/ghost/CMakeLists.txt81
-rw-r--r--intern/ghost/GHOST_C-api.h79
-rw-r--r--intern/ghost/GHOST_ISystem.h39
-rw-r--r--intern/ghost/GHOST_IWindow.h11
-rw-r--r--intern/ghost/GHOST_Rect.h61
-rw-r--r--intern/ghost/GHOST_Types.h50
-rw-r--r--intern/ghost/intern/GHOST_Buttons.cpp4
-rw-r--r--intern/ghost/intern/GHOST_Buttons.h4
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp182
-rw-r--r--intern/ghost/intern/GHOST_CallbackEventConsumer.cpp2
-rw-r--r--intern/ghost/intern/GHOST_Context.h19
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.cpp94
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp107
-rw-r--r--intern/ghost/intern/GHOST_ContextSDL.cpp65
-rw-r--r--intern/ghost/intern/GHOST_Debug.h15
-rw-r--r--intern/ghost/intern/GHOST_DisplayManager.cpp8
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerSDL.cpp18
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerX11.cpp9
-rw-r--r--intern/ghost/intern/GHOST_DropTargetX11.cpp54
-rw-r--r--intern/ghost/intern/GHOST_EventButton.h2
-rw-r--r--intern/ghost/intern/GHOST_EventKey.h17
-rw-r--r--intern/ghost/intern/GHOST_EventPrinter.cpp17
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp33
-rw-r--r--intern/ghost/intern/GHOST_ISystemPaths.cpp8
-rw-r--r--intern/ghost/intern/GHOST_ModifierKeys.cpp6
-rw-r--r--intern/ghost/intern/GHOST_ModifierKeys.h6
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp14
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerUnix.cpp6
-rw-r--r--intern/ghost/intern/GHOST_Path-api.cpp11
-rw-r--r--intern/ghost/intern/GHOST_System.cpp83
-rw-r--r--intern/ghost/intern/GHOST_System.h17
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm29
-rw-r--r--intern/ghost/intern/GHOST_SystemNULL.h6
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.cpp51
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp346
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp3544
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h133
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp30
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp410
-rw-r--r--intern/ghost/intern/GHOST_TaskbarX11.cpp20
-rw-r--r--intern/ghost/intern/GHOST_TimerTask.h2
-rw-r--r--intern/ghost/intern/GHOST_WaylandCursorSettings.h21
-rw-r--r--intern/ghost/intern/GHOST_WaylandUtils.h19
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp75
-rw-r--r--intern/ghost/intern/GHOST_Window.h11
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp37
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.h6
-rw-r--r--intern/ghost/intern/GHOST_WindowNULL.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.cpp39
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp795
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.h47
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp191
-rw-r--r--intern/ghost/intern/GHOST_Wintab.cpp23
-rw-r--r--intern/ghost/intern/GHOST_Wintab.h6
-rw-r--r--intern/ghost/intern/GHOST_XrAction.cpp37
-rw-r--r--intern/ghost/intern/GHOST_utildefines.h210
-rw-r--r--intern/ghost/intern/GHOST_utildefines_variadic.h36
-rw-r--r--intern/ghost/test/gears/GHOST_C-Test.c12
-rw-r--r--intern/ghost/test/multitest/EventToBuf.c6
-rw-r--r--intern/ghost/test/multitest/MultiTest.c6
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h4
-rw-r--r--intern/guardedalloc/intern/mallocn_lockfree_impl.c15
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp97
-rw-r--r--intern/opensubdiv/CMakeLists.txt12
-rw-r--r--intern/opensubdiv/internal/base/opensubdiv_capi.cc40
-rw-r--r--intern/opensubdiv/internal/device/device_context_cuda.cc39
-rw-r--r--intern/opensubdiv/internal/device/device_context_cuda.h38
-rw-r--r--intern/opensubdiv/internal/device/device_context_glsl_compute.cc40
-rw-r--r--intern/opensubdiv/internal/device/device_context_glsl_compute.h38
-rw-r--r--intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.cc40
-rw-r--r--intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.h38
-rw-r--r--intern/opensubdiv/internal/device/device_context_opencl.cc39
-rw-r--r--intern/opensubdiv/internal/device/device_context_opencl.h38
-rw-r--r--intern/opensubdiv/internal/device/device_context_openmp.cc42
-rw-r--r--intern/opensubdiv/internal/device/device_context_openmp.h38
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output.h36
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_cpu.h2
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_gpu.cc2
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_gpu.h1
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc2
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_capi.cc18
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.cc29
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.h6
-rw-r--r--intern/opensubdiv/internal/evaluator/gl_compute_evaluator.cc8
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h3
-rw-r--r--intern/opensubdiv/opensubdiv_capi_type.h10
-rw-r--r--intern/opensubdiv/opensubdiv_evaluator_capi.h17
-rw-r--r--intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc3
-rw-r--r--intern/opensubdiv/stub/opensubdiv_stub.cc5
-rw-r--r--intern/sky/include/sky_model.h10
-rw-r--r--intern/sky/source/sky_model.cpp2
-rw-r--r--intern/sky/source/sky_model_data.h2
-rw-r--r--intern/wayland_dynload/CMakeLists.txt44
-rw-r--r--intern/wayland_dynload/extern/wayland_dynload_API.h31
-rw-r--r--intern/wayland_dynload/extern/wayland_dynload_client.h128
-rw-r--r--intern/wayland_dynload/extern/wayland_dynload_cursor.h76
-rw-r--r--intern/wayland_dynload/extern/wayland_dynload_egl.h68
-rw-r--r--intern/wayland_dynload/extern/wayland_dynload_libdecor.h143
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_client.c79
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_cursor.c61
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_egl.c61
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_libdecor.c61
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_utils.c40
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_utils.h29
-rw-r--r--pyproject.toml4
-rwxr-xr-xrelease/bin/blender-softwaregl8
-rwxr-xr-xrelease/datafiles/alert_icons_update.py2
-rw-r--r--release/datafiles/blender_icons.svg18510
-rw-r--r--release/datafiles/blender_icons16/icon16_snap_face_nearest.datbin0 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_snap_face_nearest.datbin0 -> 4120 bytes
-rwxr-xr-xrelease/datafiles/blender_icons_geom_update.py2
-rwxr-xr-xrelease/datafiles/blender_icons_update.py2
-rw-r--r--release/datafiles/brushicons/curves_sculpt_add.pngbin0 -> 2697 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_comb.pngbin0 -> 4508 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_cut.pngbin0 -> 3212 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_delete.pngbin0 -> 2297 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_density.pngbin0 -> 2411 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_grow_shrink.pngbin0 -> 3461 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_pinch.pngbin0 -> 3836 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_puff.pngbin0 -> 2393 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_slide.pngbin0 -> 2872 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_smooth.pngbin0 -> 3006 bytes
-rw-r--r--release/datafiles/brushicons/curves_sculpt_snake_hook.pngbin0 -> 2944 bytes
-rw-r--r--release/datafiles/brushicons/paint_select.pngbin0 -> 2660 bytes
-rw-r--r--release/datafiles/colormanagement/config.ocio6
-rwxr-xr-xrelease/datafiles/ctodata.py2
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_density.datbin0 -> 3032 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_slide.datbin0 -> 1394 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_smooth.datbin0 -> 746 bytes
m---------release/datafiles/locale0
-rwxr-xr-xrelease/datafiles/prvicons_update.py2
-rw-r--r--release/datafiles/userdef/userdef_default.c1
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/freestyle/modules/freestyle/shaders.py10
-rw-r--r--release/scripts/freestyle/modules/freestyle/utils.py4
-rw-r--r--release/scripts/freestyle/modules/parameter_editor.py2
-rw-r--r--release/scripts/modules/addon_utils.py2
-rw-r--r--release/scripts/modules/animsys_refactor.py2
-rw-r--r--release/scripts/modules/bl_app_override/__init__.py2
-rw-r--r--release/scripts/modules/bl_app_override/helpers.py2
-rw-r--r--release/scripts/modules/bl_app_template_utils.py2
-rw-r--r--release/scripts/modules/bl_console_utils/__init__.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/__init__.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/complete_import.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py2
-rw-r--r--release/scripts/modules/bl_console_utils/autocomplete/intellisense.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/__init__.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/bl_extract_messages.py32
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/merge_po.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py19
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings_user.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py38
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_cli.py2
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/utils_languages_menu.py2
-rwxr-xr-xrelease/scripts/modules/bl_i18n_utils/utils_rtl.py2
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py10
-rw-r--r--release/scripts/modules/bl_keymap_utils/__init__.py2
-rw-r--r--release/scripts/modules/bl_keymap_utils/io.py2
-rw-r--r--release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py2
-rw-r--r--release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py6
-rw-r--r--release/scripts/modules/bl_keymap_utils/versioning.py2
-rw-r--r--release/scripts/modules/bl_previews_utils/bl_previews_render.py2
-rw-r--r--release/scripts/modules/bl_rna_utils/data_path.py2
-rw-r--r--release/scripts/modules/bl_ui_utils/bug_report_url.py2
-rwxr-xr-xrelease/scripts/modules/blend_render_info.py129
-rw-r--r--release/scripts/modules/bpy/__init__.py2
-rw-r--r--release/scripts/modules/bpy/ops.py2
-rw-r--r--release/scripts/modules/bpy/path.py2
-rw-r--r--release/scripts/modules/bpy/utils/__init__.py2
-rw-r--r--release/scripts/modules/bpy/utils/previews.py2
-rw-r--r--release/scripts/modules/bpy/utils/toolsystem.py2
-rw-r--r--release/scripts/modules/bpy_extras/__init__.py2
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/asset_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/id_map_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/image_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/io_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/keyconfig_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/mesh_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/node_shader_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/node_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/object_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/view3d_utils.py2
-rw-r--r--release/scripts/modules/bpy_extras/wm_utils/progress_report.py2
-rw-r--r--release/scripts/modules/bpy_restrict_state.py2
-rw-r--r--release/scripts/modules/bpy_types.py17
-rw-r--r--release/scripts/modules/console_python.py2
-rw-r--r--release/scripts/modules/console_shell.py2
-rw-r--r--release/scripts/modules/graphviz_export.py2
-rw-r--r--release/scripts/modules/keyingsets_utils.py2
-rw-r--r--release/scripts/modules/nodeitems_utils.py2
-rw-r--r--release/scripts/modules/rna_info.py38
-rw-r--r--release/scripts/modules/rna_keymap_ui.py2
-rw-r--r--release/scripts/modules/rna_manual_reference.py89
-rw-r--r--release/scripts/modules/rna_prop_ui.py2
-rw-r--r--release/scripts/modules/rna_xml.py2
-rw-r--r--release/scripts/modules/sys_info.py2
-rw-r--r--release/scripts/presets/cycles/performance/Default.py12
-rw-r--r--release/scripts/presets/cycles/performance/Faster_Render.py12
-rw-r--r--release/scripts/presets/cycles/performance/Lower_Memory.py12
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py92
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py12
-rw-r--r--release/scripts/startup/bl_operators/__init__.py2
-rw-r--r--release/scripts/startup/bl_operators/add_mesh_torus.py2
-rw-r--r--release/scripts/startup/bl_operators/anim.py2
-rw-r--r--release/scripts/startup/bl_operators/assets.py2
-rw-r--r--release/scripts/startup/bl_operators/bmesh/find_adjacent.py2
-rw-r--r--release/scripts/startup/bl_operators/clip.py2
-rw-r--r--release/scripts/startup/bl_operators/console.py2
-rw-r--r--release/scripts/startup/bl_operators/constraint.py2
-rw-r--r--release/scripts/startup/bl_operators/file.py2
-rw-r--r--release/scripts/startup/bl_operators/freestyle.py2
-rw-r--r--release/scripts/startup/bl_operators/image.py2
-rw-r--r--release/scripts/startup/bl_operators/mesh.py2
-rw-r--r--release/scripts/startup/bl_operators/node.py13
-rw-r--r--release/scripts/startup/bl_operators/object.py44
-rw-r--r--release/scripts/startup/bl_operators/object_align.py2
-rw-r--r--release/scripts/startup/bl_operators/object_quick_effects.py2
-rw-r--r--release/scripts/startup/bl_operators/object_randomize_transform.py2
-rw-r--r--release/scripts/startup/bl_operators/presets.py2
-rw-r--r--release/scripts/startup/bl_operators/rigidbody.py2
-rw-r--r--release/scripts/startup/bl_operators/screen_play_rendered_anim.py2
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py2
-rw-r--r--release/scripts/startup/bl_operators/userpref.py2
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_follow_active.py2
-rw-r--r--release/scripts/startup/bl_operators/uvcalc_lightmap.py2
-rw-r--r--release/scripts/startup/bl_operators/vertexpaint_dirt.py24
-rw-r--r--release/scripts/startup/bl_operators/view3d.py2
-rw-r--r--release/scripts/startup/bl_operators/wm.py39
-rw-r--r--release/scripts/startup/bl_ui/__init__.py6
-rw-r--r--release/scripts/startup/bl_ui/properties_animviz.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_collection.py35
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_armature.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_bone.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_camera.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curve.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_curves.py13
-rw-r--r--release/scripts/startup/bl_ui/properties_data_empty.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_gpencil.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lattice.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_light.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_lightprobe.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_mesh.py41
-rw-r--r--release/scripts/startup/bl_ui/properties_data_metaball.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_pointcloud.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_data_shaderfx.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_speaker.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_data_volume.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_freestyle.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py21
-rw-r--r--release/scripts/startup/bl_ui/properties_mask_common.py12
-rw-r--r--release/scripts/startup/bl_ui/properties_material.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_material_gpencil.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_object.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_output.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py9
-rw-r--r--release/scripts/startup/bl_ui/properties_particle.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_cloth.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_field.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_fluid.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_physics_softbody.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py47
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_texture.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_view_layer.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_workspace.py4
-rw-r--r--release/scripts/startup/bl_ui/properties_world.py17
-rw-r--r--release/scripts/startup/bl_ui/space_clip.py24
-rw-r--r--release/scripts/startup/bl_ui/space_console.py2
-rw-r--r--release/scripts/startup/bl_ui/space_dopesheet.py24
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py2
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py2
-rw-r--r--release/scripts/startup/bl_ui/space_image.py9
-rw-r--r--release/scripts/startup/bl_ui/space_info.py2
-rw-r--r--release/scripts/startup/bl_ui/space_nla.py4
-rw-r--r--release/scripts/startup/bl_ui/space_node.py2
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py4
-rw-r--r--release/scripts/startup/bl_ui/space_properties.py2
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py22
-rw-r--r--release/scripts/startup/bl_ui/space_statusbar.py2
-rw-r--r--release/scripts/startup/bl_ui/space_text.py2
-rw-r--r--release/scripts/startup/bl_ui/space_time.py2
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_common.py2
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py131
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py27
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py18
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py178
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py2
-rw-r--r--release/scripts/startup/bl_ui/utils.py2
-rw-r--r--release/scripts/startup/keyingsets_builtins.py2
-rw-r--r--release/scripts/startup/nodeitems_builtins.py46
-rw-r--r--release/windows/manifest/blender.exe.manifest.in5
-rw-r--r--source/blender/CMakeLists.txt4
-rw-r--r--source/blender/blendthumb/src/blendthumb_extract.cc6
-rw-r--r--source/blender/blenfont/BLF_api.h49
-rw-r--r--source/blender/blenfont/intern/blf.c28
-rw-r--r--source/blender/blenfont/intern/blf_font.c33
-rw-r--r--source/blender/blenfont/intern/blf_font_default.c43
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c585
-rw-r--r--source/blender/blenfont/intern/blf_internal.h6
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h31
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c2
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h4
-rw-r--r--source/blender/blenkernel/BKE_action.h5
-rw-r--r--source/blender/blenkernel/BKE_armature.h4
-rw-r--r--source/blender/blenkernel/BKE_attribute.h64
-rw-r--r--source/blender/blenkernel/BKE_attribute.hh834
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh543
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh2
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenkernel/BKE_brush.h4
-rw-r--r--source/blender/blenkernel/BKE_callbacks.h6
-rw-r--r--source/blender/blenkernel/BKE_camera.h9
-rw-r--r--source/blender/blenkernel/BKE_collection.h12
-rw-r--r--source/blender/blenkernel/BKE_constraint.h31
-rw-r--r--source/blender/blenkernel/BKE_context.h7
-rw-r--r--source/blender/blenkernel/BKE_curve_legacy_convert.hh19
-rw-r--r--source/blender/blenkernel/BKE_curves.h2
-rw-r--r--source/blender/blenkernel/BKE_curves.hh144
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh65
-rw-r--r--source/blender/blenkernel/BKE_customdata.h101
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h60
-rw-r--r--source/blender/blenkernel/BKE_geometry_fields.hh22
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh278
-rw-r--r--source/blender/blenkernel/BKE_geometry_set_instances.hh11
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h12
-rw-r--r--source/blender/blenkernel/BKE_gpencil_modifier.h2
-rw-r--r--source/blender/blenkernel/BKE_image.h15
-rw-r--r--source/blender/blenkernel/BKE_image_save.h7
-rw-r--r--source/blender/blenkernel/BKE_key.h5
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h10
-rw-r--r--source/blender/blenkernel/BKE_lib_override.h22
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h8
-rw-r--r--source/blender/blenkernel/BKE_main.h14
-rw-r--r--source/blender/blenkernel/BKE_main_namemap.h51
-rw-r--r--source/blender/blenkernel/BKE_material.h11
-rw-r--r--source/blender/blenkernel/BKE_mball.h23
-rw-r--r--source/blender/blenkernel/BKE_mesh.h104
-rw-r--r--source/blender/blenkernel/BKE_mesh_boolean_convert.hh5
-rw-r--r--source/blender/blenkernel/BKE_mesh_legacy_convert.h73
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_runtime.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh69
-rw-r--r--source/blender/blenkernel/BKE_mesh_wrapper.h2
-rw-r--r--source/blender/blenkernel/BKE_modifier.h18
-rw-r--r--source/blender/blenkernel/BKE_nla.h30
-rw-r--r--source/blender/blenkernel/BKE_node.h13
-rw-r--r--source/blender/blenkernel/BKE_node_runtime.hh89
-rw-r--r--source/blender/blenkernel/BKE_object.h12
-rw-r--r--source/blender/blenkernel/BKE_paint.h20
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h5
-rw-r--r--source/blender/blenkernel/BKE_pointcloud.h4
-rw-r--r--source/blender/blenkernel/BKE_scene.h4
-rw-r--r--source/blender/blenkernel/BKE_screen.h8
-rw-r--r--source/blender/blenkernel/BKE_sound.h2
-rw-r--r--source/blender/blenkernel/BKE_spline.hh4
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h2
-rw-r--r--source/blender/blenkernel/BKE_subdiv_modifier.h36
-rw-r--r--source/blender/blenkernel/BKE_tracking.h7
-rw-r--r--source/blender/blenkernel/BKE_unit.h4
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt17
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc89
-rw-r--r--source/blender/blenkernel/intern/action.c22
-rw-r--r--source/blender/blenkernel/intern/action_mirror.c2
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c2
-rw-r--r--source/blender/blenkernel/intern/armature.c30
-rw-r--r--source/blender/blenkernel/intern/attribute.cc (renamed from source/blender/blenkernel/intern/attribute.c)283
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc977
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh320
-rw-r--r--source/blender/blenkernel/intern/brush.cc (renamed from source/blender/blenkernel/intern/brush.c)240
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc11
-rw-r--r--source/blender/blenkernel/intern/camera.c129
-rw-r--r--source/blender/blenkernel/intern/cloth.c2
-rw-r--r--source/blender/blenkernel/intern/collection.c28
-rw-r--r--source/blender/blenkernel/intern/constraint.c223
-rw-r--r--source/blender/blenkernel/intern/curve.cc1
-rw-r--r--source/blender/blenkernel/intern/curve_bezier.cc38
-rw-r--r--source/blender/blenkernel/intern/curve_catmull_rom.cc103
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc139
-rw-r--r--source/blender/blenkernel/intern/curve_legacy_convert.cc215
-rw-r--r--source/blender/blenkernel/intern/curve_nurbs.cc4
-rw-r--r--source/blender/blenkernel/intern/curve_poly.cc65
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc108
-rw-r--r--source/blender/blenkernel/intern/curves.cc82
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc340
-rw-r--r--source/blender/blenkernel/intern/curves_geometry_test.cc2
-rw-r--r--source/blender/blenkernel/intern/curves_utils.cc100
-rw-r--r--source/blender/blenkernel/intern/customdata.cc383
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c2
-rw-r--r--source/blender/blenkernel/intern/displist.cc7
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c6
-rw-r--r--source/blender/blenkernel/intern/effect.c2
-rw-r--r--source/blender/blenkernel/intern/fcurve.c270
-rw-r--r--source/blender/blenkernel/intern/fluid.c19
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c4
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc254
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc197
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc101
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc250
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc102
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc70
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc48
-rw-r--r--source/blender/blenkernel/intern/gpencil.c4
-rw-r--r--source/blender/blenkernel/intern/gpencil_curve.c2
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc15
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c52
-rw-r--r--source/blender/blenkernel/intern/idprop.c2
-rw-r--r--source/blender/blenkernel/intern/idtype.c39
-rw-r--r--source/blender/blenkernel/intern/image.cc117
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc38
-rw-r--r--source/blender/blenkernel/intern/image_save.cc69
-rw-r--r--source/blender/blenkernel/intern/key.c123
-rw-r--r--source/blender/blenkernel/intern/lib_id.c296
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c3
-rw-r--r--source/blender/blenkernel/intern/lib_id_remapper.cc1
-rw-r--r--source/blender/blenkernel/intern/lib_id_test.cc335
-rw-r--r--source/blender/blenkernel/intern/lib_override.cc (renamed from source/blender/blenkernel/intern/lib_override.c)1069
-rw-r--r--source/blender/blenkernel/intern/lib_query.c18
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c7
-rw-r--r--source/blender/blenkernel/intern/library.c32
-rw-r--r--source/blender/blenkernel/intern/linestyle.c2
-rw-r--r--source/blender/blenkernel/intern/main.c5
-rw-r--r--source/blender/blenkernel/intern/main_namemap.cc361
-rw-r--r--source/blender/blenkernel/intern/material.c23
-rw-r--r--source/blender/blenkernel/intern/mball.c121
-rw-r--r--source/blender/blenkernel/intern/mesh.cc178
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc24
-rw-r--r--source/blender/blenkernel/intern/mesh_calc_edges.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc28
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc272
-rw-r--r--source/blender/blenkernel/intern/mesh_legacy_convert.cc876
-rw-r--r--source/blender/blenkernel/intern/mesh_merge_customdata.cc6
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.cc32
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc181
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_tessellate.c364
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.cc44
-rw-r--r--source/blender/blenkernel/intern/modifier.c47
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_apply_base.c2
-rw-r--r--source/blender/blenkernel/intern/nla.c98
-rw-r--r--source/blender/blenkernel/intern/node.cc62
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc94
-rw-r--r--source/blender/blenkernel/intern/object.cc212
-rw-r--r--source/blender/blenkernel/intern/object_update.c5
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/paint.c107
-rw-r--r--source/blender/blenkernel/intern/particle.c3
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c5
-rw-r--r--source/blender/blenkernel/intern/particle_system.c5
-rw-r--r--source/blender/blenkernel/intern/pbvh.c155
-rw-r--r--source/blender/blenkernel/intern/pbvh.cc12
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h10
-rw-r--r--source/blender/blenkernel/intern/pointcache.c35
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc72
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c129
-rw-r--r--source/blender/blenkernel/intern/scene.cc15
-rw-r--r--source/blender/blenkernel/intern/screen.c13
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c4
-rw-r--r--source/blender/blenkernel/intern/sound.c41
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc2
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg_mask.c2
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c9
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c6
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c66
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c8
-rw-r--r--source/blender/blenkernel/intern/tracking.c100
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c2
-rw-r--r--source/blender/blenkernel/intern/unit.c21
-rw-r--r--source/blender/blenkernel/intern/volume.cc17
-rw-r--r--source/blender/blenkernel/intern/workspace.c11
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c2
-rw-r--r--source/blender/blenlib/BLI_any.hh51
-rw-r--r--source/blender/blenlib/BLI_assert.h2
-rw-r--r--source/blender/blenlib/BLI_bitmap.h13
-rw-r--r--source/blender/blenlib/BLI_bounds.hh6
-rw-r--r--source/blender/blenlib/BLI_color.hh10
-rw-r--r--source/blender/blenlib/BLI_cpp_type.hh5
-rw-r--r--source/blender/blenlib/BLI_float3x3.hh7
-rw-r--r--source/blender/blenlib/BLI_generic_span.hh66
-rw-r--r--source/blender/blenlib/BLI_generic_virtual_array.hh308
-rw-r--r--source/blender/blenlib/BLI_ghash.h2
-rw-r--r--source/blender/blenlib/BLI_hash_tables.hh6
-rw-r--r--source/blender/blenlib/BLI_index_mask.hh2
-rw-r--r--source/blender/blenlib/BLI_index_mask_ops.hh14
-rw-r--r--source/blender/blenlib/BLI_index_range.hh29
-rw-r--r--source/blender/blenlib/BLI_kdtree.h8
-rw-r--r--source/blender/blenlib/BLI_kdtree_impl.h27
-rw-r--r--source/blender/blenlib/BLI_length_parameterize.hh135
-rw-r--r--source/blender/blenlib/BLI_math_base.h13
-rw-r--r--source/blender/blenlib/BLI_math_base.hh22
-rw-r--r--source/blender/blenlib/BLI_math_color.h2
-rw-r--r--source/blender/blenlib/BLI_math_geom.h2
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h3
-rw-r--r--source/blender/blenlib/BLI_math_mpq.hh6
-rw-r--r--source/blender/blenlib/BLI_math_rotation.hh9
-rw-r--r--source/blender/blenlib/BLI_math_vec_types.hh4
-rw-r--r--source/blender/blenlib/BLI_math_vector.h4
-rw-r--r--source/blender/blenlib/BLI_math_vector.hh47
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh17
-rw-r--r--source/blender/blenlib/BLI_utildefines_iter.h2
-rw-r--r--source/blender/blenlib/BLI_vector.hh10
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh363
-rw-r--r--source/blender/blenlib/CMakeLists.txt2
-rw-r--r--source/blender/blenlib/intern/bitmap.c20
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc1
-rw-r--r--source/blender/blenlib/intern/filereader_zstd.c5
-rw-r--r--source/blender/blenlib/intern/generic_virtual_array.cc398
-rw-r--r--source/blender/blenlib/intern/hash_md5.c6
-rw-r--r--source/blender/blenlib/intern/index_mask.cc52
-rw-r--r--source/blender/blenlib/intern/kdtree_impl.h27
-rw-r--r--source/blender/blenlib/intern/length_parameterize.cc150
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c38
-rw-r--r--source/blender/blenlib/intern/math_matrix.c16
-rw-r--r--source/blender/blenlib/intern/math_rotation.cc13
-rw-r--r--source/blender/blenlib/intern/math_solvers.c4
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c29
-rw-r--r--source/blender/blenlib/intern/rct.c4
-rw-r--r--source/blender/blenlib/intern/string_utf8.c4
-rw-r--r--source/blender/blenlib/intern/timeit.cc18
-rw-r--r--source/blender/blenlib/tests/BLI_bitmap_test.cc46
-rw-r--r--source/blender/blenlib/tests/BLI_bounds_test.cc7
-rw-r--r--source/blender/blenlib/tests/BLI_index_range_test.cc6
-rw-r--r--source/blender/blenlib/tests/BLI_kdtree_test.cc63
-rw-r--r--source/blender/blenlib/tests/BLI_length_parameterize_test.cc20
-rw-r--r--source/blender/blenlib/tests/BLI_math_color_test.cc68
-rw-r--r--source/blender/blenlib/tests/BLI_math_vector_test.cc20
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_virtual_array_test.cc35
-rw-r--r--source/blender/blenloader/intern/readfile.c3
-rw-r--r--source/blender/blenloader/intern/versioning_250.c12
-rw-r--r--source/blender/blenloader/intern/versioning_280.c11
-rw-r--r--source/blender/blenloader/intern/versioning_290.c23
-rw-r--r--source/blender/blenloader/intern/versioning_300.c740
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c9
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c4
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c253
-rw-r--r--source/blender/blenloader/intern/writefile.c8
-rw-r--r--source/blender/blentranslation/BLT_translation.h7
-rw-r--r--source/blender/blentranslation/intern/blt_lang.c9
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c15
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c2
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c21
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c32
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h113
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc5
-rw-r--r--source/blender/bmesh/operators/bmo_join_triangles.c2
-rw-r--r--source/blender/compositor/intern/COM_Converter.h4
-rw-r--r--source/blender/compositor/intern/COM_NodeConverter.h2
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cc9
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc4
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc16
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cc4
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cc5
-rw-r--r--source/blender/compositor/operations/COM_TonemapOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_ViewerOperation.cc4
-rwxr-xr-xsource/blender/datatoc/datatoc_icon.py2
-rwxr-xr-xsource/blender/datatoc/datatoc_icon_split.py2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.cc31
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder.h14
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.cc15
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cache.h24
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.cc6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_cycle.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_map.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc10
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc78
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_transitive.h6
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline.h6
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline_all_objects.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline_all_objects.h6
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline_compositor.h6
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline_from_ids.cc4
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline_from_ids.h6
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline_render.h6
-rw-r--r--source/blender/depsgraph/intern/builder/pipeline_view_layer.h6
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug.h6
-rw-r--r--source/blender/depsgraph/intern/debug/deg_time_average.h6
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc6
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc4
-rw-r--r--source/blender/depsgraph/intern/depsgraph_physics.h6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc2
-rw-r--r--source/blender/depsgraph/intern/depsgraph_registry.h6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_relation.h6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc12
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.h6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type.h6
-rw-r--r--source/blender/depsgraph/intern/depsgraph_update.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc63
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h6
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_stats.h6
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h6
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h57
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_factory.h7
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_factory_impl.h6
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_id.h6
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h16
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_time.h6
-rw-r--r--source/blender/draw/CMakeLists.txt232
-rw-r--r--source/blender/draw/DRW_engine.h9
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c10
-rw-r--r--source/blender/draw/engines/basic/basic_private.h1
-rw-r--r--source/blender/draw/engines/basic/basic_shader.c17
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl (renamed from source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_curves_vert.glsl27
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_frag.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl (renamed from source/blender/draw/engines/basic/shaders/depth_vert.glsl)0
-rw-r--r--source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh14
-rw-r--r--source/blender/draw/engines/eevee/eevee_bloom.c24
-rw-r--r--source/blender/draw/engines/eevee/eevee_cryptomatte.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c12
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h6
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c5
-rw-r--r--source/blender/draw/engines/eevee/eevee_sampling.c5
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shaders.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c9
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/surface_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl10
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_camera.cc11
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_camera.hh3
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_defines.hh4
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_engine.cc22
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_film.cc579
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_film.hh187
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.cc83
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_instance.hh29
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_material.cc2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_pipeline.cc28
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc96
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh57
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sampling.cc264
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sampling.hh172
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.cc5
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader.hh5
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_shader_shared.hh192
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_sync.cc16
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.cc6
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_velocity.hh2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.cc76
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_view.hh21
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_world.cc2
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl6
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_film_comp.glsl13
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_film_frag.glsl29
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl387
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl18
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl44
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl8
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_film_info.hh44
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh64
-rw-r--r--source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh1
-rw-r--r--source/blender/draw/engines/external/external_engine.c4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl2
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl2
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl4
-rw-r--r--source/blender/draw/engines/overlay/overlay_antialiasing.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_edit_uv.c2
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c16
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c22
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c15
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h9
-rw-r--r--source/blender/draw/engines/overlay/overlay_sculpt_curves.cc96
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c26
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/armature_info.hh)44
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/background_info.hh)8
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh)140
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/extra_info.hh)50
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/facing_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/grid_info.hh)14
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/outline_info.hh)26
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/paint_info.hh)26
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_curves_info.hh21
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/volume_info.hh)12
-rw-r--r--source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh (renamed from source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl)14
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl)8
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl)6
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl)12
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/background_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl (renamed from source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl6
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl)6
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_vert.glsl)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/facing_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/facing_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_frag.glsl)4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/grid_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/image_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/image_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl81
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl)6
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/particle_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/particle_vert.glsl)2
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl23
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl27
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl5
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl34
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl)0
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl (renamed from source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl)6
-rw-r--r--source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl (renamed from source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl)0
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl6
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl6
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.c5
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c5
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh1
-rw-r--r--source/blender/draw/intern/DRW_render.h20
-rw-r--r--source/blender/draw/intern/draw_attributes.cc16
-rw-r--r--source/blender/draw/intern/draw_attributes.h13
-rw-r--r--source/blender/draw/intern/draw_cache.c32
-rw-r--r--source/blender/draw/intern/draw_cache_extract.hh (renamed from source/blender/draw/intern/draw_cache_extract.h)136
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc91
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc (renamed from source/blender/draw/intern/draw_cache_extract_mesh_render_data.c)133
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h26
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curve.cc2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc209
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.cc (renamed from source/blender/draw/intern/draw_cache_impl_mesh.c)743
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_pointcloud.c13
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc131
-rw-r--r--source/blender/draw/intern/draw_common.h2
-rw-r--r--source/blender/draw/intern/draw_curves.cc51
-rw-r--r--source/blender/draw/intern/draw_curves_private.h39
-rw-r--r--source/blender/draw/intern/draw_hair.cc14
-rw-r--r--source/blender/draw/intern/draw_manager.c3
-rw-r--r--source/blender/draw/intern/draw_manager_data.c3
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h6
-rw-r--r--source/blender/draw/intern/draw_subdivision.h11
-rw-r--r--source/blender/draw/intern/draw_volume.cc12
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.cc (renamed from source/blender/draw/intern/mesh_extractors/extract_mesh.c)6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.hh (renamed from source/blender/draw/intern/mesh_extractors/extract_mesh.h)138
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc26
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_fdots.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc60
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc12
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_paint_mask.cc13
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc12
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc14
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc190
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_nor.cc12
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc16
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc8
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc14
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc10
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc115
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc8
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl37
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_lib.glsl18
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl6
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl38
-rw-r--r--source/blender/draw/tests/shaders_test.cc3
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c24
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c76
-rw-r--r--source/blender/editors/animation/anim_deps.c2
-rw-r--r--source/blender/editors/animation/anim_draw.c24
-rw-r--r--source/blender/editors/animation/anim_filter.c13
-rw-r--r--source/blender/editors/animation/anim_markers.c17
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c8
-rw-r--r--source/blender/editors/animation/anim_ops.c18
-rw-r--r--source/blender/editors/animation/drivers.c4
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c2
-rw-r--r--source/blender/editors/animation/keyframes_edit.c6
-rw-r--r--source/blender/editors/animation/keyframes_general.c109
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc4
-rw-r--r--source/blender/editors/animation/keyframing.c65
-rw-r--r--source/blender/editors/armature/armature_add.c17
-rw-r--r--source/blender/editors/armature/armature_edit.c7
-rw-r--r--source/blender/editors/armature/armature_naming.c21
-rw-r--r--source/blender/editors/armature/armature_relations.c32
-rw-r--r--source/blender/editors/armature/pose_group.c1
-rw-r--r--source/blender/editors/armature/pose_lib.c14
-rw-r--r--source/blender/editors/armature/pose_lib_2.c2
-rw-r--r--source/blender/editors/armature/pose_select.c9
-rw-r--r--source/blender/editors/armature/pose_slide.c4
-rw-r--r--source/blender/editors/armature/pose_transform.c6
-rw-r--r--source/blender/editors/curve/editcurve.c47
-rw-r--r--source/blender/editors/curve/editcurve_add.c2
-rw-r--r--source/blender/editors/curve/editcurve_paint.c8
-rw-r--r--source/blender/editors/curve/editcurve_pen.c10
-rw-r--r--source/blender/editors/curve/editfont.c66
-rw-r--r--source/blender/editors/curves/CMakeLists.txt14
-rw-r--r--source/blender/editors/curves/intern/curves_add.cc84
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc645
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt17
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc149
-rw-r--r--source/blender/editors/geometry/geometry_intern.hh1
-rw-r--r--source/blender/editors/geometry/geometry_ops.cc1
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c62
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c30
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c110
-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.c6
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c8
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c19
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c4
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c47
-rw-r--r--source/blender/editors/gpencil/gpencil_add_blank.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_add_monkey.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_add_stroke.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_bake_animation.cc9
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c12
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c125
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h10
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.cc4
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c18
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_trace_ops.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c39
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c2
-rw-r--r--source/blender/editors/include/BIF_glutil.h20
-rw-r--r--source/blender/editors/include/ED_anim_api.h6
-rw-r--r--source/blender/editors/include/ED_clip.h42
-rw-r--r--source/blender/editors/include/ED_curve.h2
-rw-r--r--source/blender/editors/include/ED_curves.h9
-rw-r--r--source/blender/editors/include/ED_datafiles.h38
-rw-r--r--source/blender/editors/include/ED_geometry.h12
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h22
-rw-r--r--source/blender/editors/include/ED_gpencil.h13
-rw-r--r--source/blender/editors/include/ED_image.h43
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h23
-rw-r--r--source/blender/editors/include/ED_keyframing.h9
-rw-r--r--source/blender/editors/include/ED_mask.h29
-rw-r--r--source/blender/editors/include/ED_mesh.h4
-rw-r--r--source/blender/editors/include/ED_object.h12
-rw-r--r--source/blender/editors/include/ED_screen.h3
-rw-r--r--source/blender/editors/include/ED_sculpt.h2
-rw-r--r--source/blender/editors/include/ED_select_utils.h8
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h105
-rw-r--r--source/blender/editors/include/ED_view3d.h7
-rw-r--r--source/blender/editors/include/UI_abstract_view.hh280
-rw-r--r--source/blender/editors/include/UI_grid_view.hh55
-rw-r--r--source/blender/editors/include/UI_icons.h17
-rw-r--r--source/blender/editors/include/UI_interface.h155
-rw-r--r--source/blender/editors/include/UI_interface.hh6
-rw-r--r--source/blender/editors/include/UI_tree_view.hh181
-rw-r--r--source/blender/editors/include/UI_view2d.h31
-rw-r--r--source/blender/editors/interface/CMakeLists.txt26
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_color.c (renamed from source/blender/editors/interface/interface_eyedropper_color.c)10
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_colorband.c (renamed from source/blender/editors/interface/interface_eyedropper_colorband.c)2
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_datablock.c (renamed from source/blender/editors/interface/interface_eyedropper_datablock.c)4
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_depth.c (renamed from source/blender/editors/interface/interface_eyedropper_depth.c)4
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_driver.c (renamed from source/blender/editors/interface/interface_eyedropper_driver.c)2
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.c (renamed from source/blender/editors/interface/interface_eyedropper_gpencil_color.c)2
-rw-r--r--source/blender/editors/interface/eyedroppers/eyedropper_intern.h (renamed from source/blender/editors/interface/interface_eyedropper_intern.h)4
-rw-r--r--source/blender/editors/interface/eyedroppers/interface_eyedropper.c (renamed from source/blender/editors/interface/interface_eyedropper.c)2
-rw-r--r--source/blender/editors/interface/interface.cc183
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_context_menu.c10
-rw-r--r--source/blender/editors/interface/interface_drag.cc146
-rw-r--r--source/blender/editors/interface/interface_draw.c4
-rw-r--r--source/blender/editors/interface/interface_dropboxes.cc32
-rw-r--r--source/blender/editors/interface/interface_handlers.c173
-rw-r--r--source/blender/editors/interface/interface_icons.c17
-rw-r--r--source/blender/editors/interface/interface_icons_event.c6
-rw-r--r--source/blender/editors/interface/interface_intern.h38
-rw-r--r--source/blender/editors/interface/interface_ops.c88
-rw-r--r--source/blender/editors/interface/interface_query.cc36
-rw-r--r--source/blender/editors/interface/interface_region_hud.cc7
-rw-r--r--source/blender/editors/interface/interface_region_menu_pie.cc2
-rw-r--r--source/blender/editors/interface/interface_region_search.cc7
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c4
-rw-r--r--source/blender/editors/interface/interface_style.cc18
-rw-r--r--source/blender/editors/interface/interface_template_attribute_search.cc17
-rw-r--r--source/blender/editors/interface/interface_templates.c61
-rw-r--r--source/blender/editors/interface/interface_view.cc229
-rw-r--r--source/blender/editors/interface/interface_widgets.c56
-rw-r--r--source/blender/editors/interface/view2d.cc137
-rw-r--r--source/blender/editors/interface/view2d_ops.cc4
-rw-r--r--source/blender/editors/interface/views/abstract_view.cc109
-rw-r--r--source/blender/editors/interface/views/abstract_view_item.cc373
-rw-r--r--source/blender/editors/interface/views/grid_view.cc (renamed from source/blender/editors/interface/grid_view.cc)102
-rw-r--r--source/blender/editors/interface/views/interface_view.cc196
-rw-r--r--source/blender/editors/interface/views/tree_view.cc (renamed from source/blender/editors/interface/tree_view.cc)411
-rw-r--r--source/blender/editors/io/CMakeLists.txt27
-rw-r--r--source/blender/editors/io/io_alembic.c10
-rw-r--r--source/blender/editors/io/io_collada.c4
-rw-r--r--source/blender/editors/io/io_gpencil_export.c66
-rw-r--r--source/blender/editors/io/io_gpencil_import.c46
-rw-r--r--source/blender/editors/io/io_gpencil_utils.c14
-rw-r--r--source/blender/editors/io/io_obj.c102
-rw-r--r--source/blender/editors/io/io_ops.c17
-rw-r--r--source/blender/editors/io/io_stl_ops.c133
-rw-r--r--source/blender/editors/io/io_stl_ops.h12
-rw-r--r--source/blender/editors/io/io_usd.c31
-rw-r--r--source/blender/editors/mask/mask_add.c62
-rw-r--r--source/blender/editors/mask/mask_draw.c68
-rw-r--r--source/blender/editors/mask/mask_edit.c32
-rw-r--r--source/blender/editors/mask/mask_editaction.c2
-rw-r--r--source/blender/editors/mask/mask_intern.h3
-rw-r--r--source/blender/editors/mask/mask_ops.c34
-rw-r--r--source/blender/editors/mask/mask_query.c5
-rw-r--r--source/blender/editors/mask/mask_relationships.c3
-rw-r--r--source/blender/editors/mask/mask_select.c29
-rw-r--r--source/blender/editors/mask/mask_shapekey.c16
-rw-r--r--source/blender/editors/mesh/editface.cc53
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c14
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c8
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c8
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c4
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c260
-rw-r--r--source/blender/editors/object/CMakeLists.txt1
-rw-r--r--source/blender/editors/object/object_add.cc189
-rw-r--r--source/blender/editors/object/object_bake.c20
-rw-r--r--source/blender/editors/object/object_bake_api.c121
-rw-r--r--source/blender/editors/object/object_constraint.c26
-rw-r--r--source/blender/editors/object/object_data_transfer.c15
-rw-r--r--source/blender/editors/object/object_edit.c12
-rw-r--r--source/blender/editors/object/object_modes.c10
-rw-r--r--source/blender/editors/object/object_modifier.cc56
-rw-r--r--source/blender/editors/object/object_ops.c12
-rw-r--r--source/blender/editors/object/object_relations.c158
-rw-r--r--source/blender/editors/object/object_remesh.cc13
-rw-r--r--source/blender/editors/object/object_shapekey.c43
-rw-r--r--source/blender/editors/object/object_transform.cc7
-rw-r--r--source/blender/editors/object/object_vgroup.c34
-rw-r--r--source/blender/editors/physics/particle_edit.c7
-rw-r--r--source/blender/editors/physics/particle_object.c1
-rw-r--r--source/blender/editors/physics/physics_fluid.c8
-rw-r--r--source/blender/editors/render/render_opengl.cc18
-rw-r--r--source/blender/editors/render/render_preview.cc2
-rw-r--r--source/blender/editors/render/render_view.cc8
-rw-r--r--source/blender/editors/screen/area.c24
-rw-r--r--source/blender/editors/screen/screen_context.c67
-rw-r--r--source/blender/editors/screen/screen_edit.c4
-rw-r--r--source/blender/editors/screen/screen_ops.c71
-rw-r--r--source/blender/editors/screen/screen_user_menu.c9
-rw-r--r--source/blender/editors/screen/workspace_edit.c107
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt13
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc671
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_brush.cc103
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc117
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc71
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_density.cc827
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc212
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh56
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc1014
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_pinch.cc307
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_puff.cc393
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection.cc105
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc395
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_slide.cc307
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_smooth.cc259
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc125
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.cc16
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_ops_paint.cc6
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h18
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c8
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c151
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c70
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c61
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.cc262
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c485
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc514
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c75
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c245
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.cc (renamed from source/blender/editors/sculpt_paint/sculpt_automasking.c)59
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c16
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c49
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_expand.c34
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_color.c10
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h40
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c11
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_paint_color.c31
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c182
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c37
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c14
-rw-r--r--source/blender/editors/sound/sound_ops.c15
-rw-r--r--source/blender/editors/space_action/action_edit.c392
-rw-r--r--source/blender/editors/space_action/action_select.c234
-rw-r--r--source/blender/editors/space_action/space_action.c12
-rw-r--r--source/blender/editors/space_api/spacetypes.c1
-rw-r--r--source/blender/editors/space_assets/asset_catalog_tree_view.cc69
-rw-r--r--source/blender/editors/space_buttons/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c6
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c3
-rw-r--r--source/blender/editors/space_clip/clip_draw.c22
-rw-r--r--source/blender/editors/space_clip/clip_editor.c28
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c8
-rw-r--r--source/blender/editors/space_clip/clip_intern.h3
-rw-r--r--source/blender/editors/space_clip/clip_ops.c16
-rw-r--r--source/blender/editors/space_clip/clip_utils.c12
-rw-r--r--source/blender/editors/space_clip/space_clip.c4
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c154
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c4
-rw-r--r--source/blender/editors/space_clip/tracking_select.c2
-rw-r--r--source/blender/editors/space_console/console_ops.c12
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc69
-rw-r--r--source/blender/editors/space_file/file_draw.c4
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c48
-rw-r--r--source/blender/editors/space_file/filelist.c23
-rw-r--r--source/blender/editors/space_file/fsmenu.c2
-rw-r--r--source/blender/editors/space_file/space_file.c1
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c2
-rw-r--r--source/blender/editors/space_graph/graph_draw.c5
-rw-r--r--source/blender/editors/space_graph/graph_edit.c151
-rw-r--r--source/blender/editors/space_graph/graph_ops.c23
-rw-r--r--source/blender/editors/space_graph/graph_select.c40
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c4
-rw-r--r--source/blender/editors/space_graph/graph_utils.c11
-rw-r--r--source/blender/editors/space_graph/graph_view.c7
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_image/image_buttons.c7
-rw-r--r--source/blender/editors/space_image/image_draw.c3
-rw-r--r--source/blender/editors/space_image/image_edit.c29
-rw-r--r--source/blender/editors/space_image/image_intern.h1
-rw-r--r--source/blender/editors/space_image/image_ops.c239
-rw-r--r--source/blender/editors/space_image/image_sequence.c4
-rw-r--r--source/blender/editors/space_image/image_undo.c2
-rw-r--r--source/blender/editors/space_image/space_image.c5
-rw-r--r--source/blender/editors/space_info/info_stats.cc18
-rw-r--r--source/blender/editors/space_info/textview.c13
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c6
-rw-r--r--source/blender/editors/space_nla/nla_channels.c12
-rw-r--r--source/blender/editors/space_nla/nla_draw.c137
-rw-r--r--source/blender/editors/space_nla/nla_edit.c100
-rw-r--r--source/blender/editors/space_nla/nla_ops.c24
-rw-r--r--source/blender/editors/space_nla/nla_select.c16
-rw-r--r--source/blender/editors/space_nla/space_nla.c6
-rw-r--r--source/blender/editors/space_node/drawnode.cc7
-rw-r--r--source/blender/editors/space_node/node_add.cc6
-rw-r--r--source/blender/editors/space_node/node_context_path.cc2
-rw-r--r--source/blender/editors/space_node/node_draw.cc89
-rw-r--r--source/blender/editors/space_node/node_edit.cc26
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc18
-rw-r--r--source/blender/editors/space_node/node_relationships.cc6
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.cc84
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc4
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc67
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh14
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc4
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc71
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc10
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_libraries.cc5
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc274
-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.hh8
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc10
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc37
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.cc7
-rw-r--r--source/blender/editors/space_outliner/tree/tree_iterator.hh2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c73
-rw-r--r--source/blender/editors/space_sequencer/sequencer_channels_draw.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_drag_drop.c12
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c713
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c274
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h7
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c138
-rw-r--r--source/blender/editors/space_sequencer/sequencer_thumbnails.c54
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c22
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c5
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc7
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh6
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc92
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc10
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc32
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_ops.cc10
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc160
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc32
-rw-r--r--source/blender/editors/space_text/text_format_lua.c13
-rw-r--r--source/blender/editors/space_text/text_format_osl.c11
-rw-r--r--source/blender/editors/space_text/text_format_pov.c11
-rw-r--r--source/blender/editors/space_text/text_format_pov_ini.c11
-rw-r--r--source/blender/editors/space_text/text_format_py.c13
-rw-r--r--source/blender/editors/space_text/text_ops.c17
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c3
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_cursor_snap.c73
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c28
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c17
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_navigate_walk.c108
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c6
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c15
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c7
-rw-r--r--source/blender/editors/transform/CMakeLists.txt1
-rw-r--r--source/blender/editors/transform/transform.c27
-rw-r--r--source/blender/editors/transform/transform.h38
-rw-r--r--source/blender/editors/transform/transform_constraints.c2
-rw-r--r--source/blender/editors/transform/transform_convert.c148
-rw-r--r--source/blender/editors/transform/transform_convert.h8
-rw-r--r--source/blender/editors/transform/transform_convert_action.c113
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c8
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c2
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c2
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c30
-rw-r--r--source/blender/editors/transform/transform_convert_lattice.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c14
-rw-r--r--source/blender/editors/transform/transform_convert_mball.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c30
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_edge.c4
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_uv.c4
-rw-r--r--source/blender/editors/transform/transform_convert_mesh_vert_cdata.c289
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c24
-rw-r--r--source/blender/editors/transform/transform_convert_object.c8
-rw-r--r--source/blender/editors/transform/transform_convert_object_texspace.c2
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c2
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c425
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c69
-rw-r--r--source/blender/editors/transform/transform_generics.c4
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c11
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c448
-rw-r--r--source/blender/editors/transform/transform_mode.c21
-rw-r--r--source/blender/editors/transform/transform_mode.h2
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c10
-rw-r--r--source/blender/editors/transform/transform_mode_edge_bevelweight.c11
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c11
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c2
-rw-r--r--source/blender/editors/transform/transform_mode_edge_seq_slide.c2
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c4
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c2
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c2
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c2
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c108
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c28
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c2
-rw-r--r--source/blender/editors/transform/transform_mode_timescale.c4
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c61
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c71
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c4
-rw-r--r--source/blender/editors/transform/transform_ops.c72
-rw-r--r--source/blender/editors/transform/transform_snap.c457
-rw-r--r--source/blender/editors/transform/transform_snap.h20
-rw-r--r--source/blender/editors/transform/transform_snap_object.cc891
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c44
-rw-r--r--source/blender/editors/util/CMakeLists.txt1
-rw-r--r--source/blender/editors/util/ed_util.c13
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c2
-rw-r--r--source/blender/editors/util/numinput.c13
-rw-r--r--source/blender/editors/util/select_utils.c14
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h1
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c392
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c681
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c12
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c258
-rw-r--r--source/blender/functions/FN_field.hh2
-rw-r--r--source/blender/functions/FN_multi_function_params.hh37
-rw-r--r--source/blender/functions/FN_multi_function_procedure.hh8
-rw-r--r--source/blender/functions/FN_multi_function_signature.hh25
-rw-r--r--source/blender/functions/intern/field.cc29
-rw-r--r--source/blender/functions/intern/multi_function_procedure.cc4
-rw-r--r--source/blender/functions/intern/multi_function_procedure_executor.cc408
-rw-r--r--source/blender/geometry/CMakeLists.txt26
-rw-r--r--source/blender/geometry/GEO_add_curves_on_mesh.hh54
-rw-r--r--source/blender/geometry/GEO_fillet_curves.hh23
-rw-r--r--source/blender/geometry/GEO_mesh_to_curve.hh12
-rw-r--r--source/blender/geometry/GEO_mesh_to_volume.hh55
-rw-r--r--source/blender/geometry/GEO_point_merge_by_distance.hh2
-rw-r--r--source/blender/geometry/GEO_reverse_uv_sampler.hh46
-rw-r--r--source/blender/geometry/GEO_set_curve_type.hh32
-rw-r--r--source/blender/geometry/GEO_subdivide_curves.hh24
-rw-r--r--source/blender/geometry/GEO_uv_parametrizer.h42
-rw-r--r--source/blender/geometry/intern/add_curves_on_mesh.cc370
-rw-r--r--source/blender/geometry/intern/fillet_curves.cc561
-rw-r--r--source/blender/geometry/intern/mesh_primitive_cuboid.cc12
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc43
-rw-r--r--source/blender/geometry/intern/mesh_to_volume.cc172
-rw-r--r--source/blender/geometry/intern/point_merge_by_distance.cc44
-rw-r--r--source/blender/geometry/intern/realize_instances.cc359
-rw-r--r--source/blender/geometry/intern/resample_curves.cc104
-rw-r--r--source/blender/geometry/intern/reverse_uv_sampler.cc101
-rw-r--r--source/blender/geometry/intern/set_curve_type.cc689
-rw-r--r--source/blender/geometry/intern/subdivide_curves.cc428
-rw-r--r--source/blender/geometry/intern/uv_parametrizer.c1125
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillength.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c142
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c18
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c5
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c7
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c9
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c4
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c3
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h561
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c387
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c3027
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h106
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c6
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c1418
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_util.c17
-rw-r--r--source/blender/gpu/CMakeLists.txt65
-rw-r--r--source/blender/gpu/GPU_buffers.h48
-rw-r--r--source/blender/gpu/GPU_common_types.h10
-rw-r--r--source/blender/gpu/GPU_context.h15
-rw-r--r--source/blender/gpu/GPU_framebuffer.h39
-rw-r--r--source/blender/gpu/GPU_material.h8
-rw-r--r--source/blender/gpu/GPU_shader_shared_utils.h1
-rw-r--r--source/blender/gpu/GPU_texture.h2
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh1
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc1
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c11
-rw-r--r--source/blender/gpu/intern/gpu_batch_utils.c1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c637
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc19
-rw-r--r--source/blender/gpu/intern/gpu_compute.cc1
-rw-r--r--source/blender/gpu/intern/gpu_context.cc69
-rw-r--r--source/blender/gpu/intern/gpu_context_private.hh22
-rw-r--r--source/blender/gpu/intern/gpu_drawlist.cc3
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc62
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer_private.hh7
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc1
-rw-r--r--source/blender/gpu/intern/gpu_immediate_private.hh6
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c35
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c7
-rw-r--r--source/blender/gpu/intern/gpu_material.c8
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h2
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c12
-rw-r--r--source/blender/gpu/intern/gpu_private.h4
-rw-r--r--source/blender/gpu/intern/gpu_select.c4
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc1
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder_stubs.cc64
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c16
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.cc12
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh25
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc1
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc2
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh14
-rw-r--r--source/blender/gpu/intern/gpu_shader_log.cc2
-rw-r--r--source/blender/gpu/intern/gpu_state.cc2
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer.cc1
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc7
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc1
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c3
-rw-r--r--source/blender/gpu/metal/mtl_backend.hh11
-rw-r--r--source/blender/gpu/metal/mtl_backend.mm41
-rw-r--r--source/blender/gpu/metal/mtl_capabilities.hh5
-rw-r--r--source/blender/gpu/metal/mtl_command_buffer.mm652
-rw-r--r--source/blender/gpu/metal/mtl_common.hh6
-rw-r--r--source/blender/gpu/metal/mtl_context.hh398
-rw-r--r--source/blender/gpu/metal/mtl_context.mm307
-rw-r--r--source/blender/gpu/metal/mtl_debug.mm10
-rw-r--r--source/blender/gpu/metal/mtl_framebuffer.hh233
-rw-r--r--source/blender/gpu/metal/mtl_framebuffer.mm1899
-rw-r--r--source/blender/gpu/metal/mtl_memory.hh482
-rw-r--r--source/blender/gpu/metal/mtl_memory.mm895
-rw-r--r--source/blender/gpu/metal/mtl_query.hh41
-rw-r--r--source/blender/gpu/metal/mtl_query.mm122
-rw-r--r--source/blender/gpu/metal/mtl_state.hh16
-rw-r--r--source/blender/gpu/metal/mtl_state.mm156
-rw-r--r--source/blender/gpu/metal/mtl_texture.hh85
-rw-r--r--source/blender/gpu/metal/mtl_texture.mm854
-rw-r--r--source/blender/gpu/metal/mtl_texture_util.mm14
-rw-r--r--source/blender/gpu/metal/mtl_uniform_buffer.hh50
-rw-r--r--source/blender/gpu/metal/mtl_uniform_buffer.mm162
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc4
-rw-r--r--source/blender/gpu/opengl/gl_backend.hh8
-rw-r--r--source/blender/gpu/opengl/gl_batch.cc3
-rw-r--r--source/blender/gpu/opengl/gl_batch.hh4
-rw-r--r--source/blender/gpu/opengl/gl_compute.cc2
-rw-r--r--source/blender/gpu/opengl/gl_context.cc11
-rw-r--r--source/blender/gpu/opengl/gl_context.hh2
-rw-r--r--source/blender/gpu/opengl/gl_debug.cc2
-rw-r--r--source/blender/gpu/opengl/gl_debug_layer.cc2
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.cc3
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.cc2
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.hh9
-rw-r--r--source/blender/gpu/opengl/gl_immediate.cc2
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.cc1
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc5
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc1
-rw-r--r--source/blender/gpu/opengl/gl_state.cc3
-rw-r--r--source/blender/gpu/opengl/gl_storage_buffer.cc2
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc8
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh2
-rw-r--r--source/blender/gpu/opengl/gl_uniform_buffer.cc4
-rw-r--r--source/blender/gpu/opengl/gl_vertex_array.cc1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_point_varying_color_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl8
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl9
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl6
-rw-r--r--source/blender/gpu/tests/gpu_testing.cc1
-rw-r--r--source/blender/imbuf/CMakeLists.txt8
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h10
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h7
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h9
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h17
-rw-r--r--source/blender/imbuf/intern/anim_movie.c273
-rw-r--r--source/blender/imbuf/intern/cineon/cineon_dpx.c4
-rw-r--r--source/blender/imbuf/intern/colormanagement.c168
-rw-r--r--source/blender/imbuf/intern/divers.c28
-rw-r--r--source/blender/imbuf/intern/imageprocess.c1
-rw-r--r--source/blender/imbuf/intern/indexer.c4
-rw-r--r--source/blender/imbuf/intern/jpeg.c4
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp10
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h4
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c31
-rw-r--r--source/blender/imbuf/intern/thumbs.c5
-rw-r--r--source/blender/imbuf/intern/tiff.c22
-rw-r--r--source/blender/imbuf/intern/transform.cc23
-rw-r--r--source/blender/imbuf/intern/util_gpu.c65
-rw-r--r--source/blender/io/CMakeLists.txt19
-rw-r--r--source/blender/io/alembic/exporter/abc_custom_props.cc4
-rw-r--r--source/blender/io/alembic/exporter/abc_export_capi.cc18
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_hair.cc1
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc4
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc10
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc48
-rw-r--r--source/blender/io/avi/AVI_avi.h3
-rw-r--r--source/blender/io/collada/AnimationImporter.cpp4
-rw-r--r--source/blender/io/collada/BCAnimationCurve.cpp2
-rw-r--r--source/blender/io/collada/BCAnimationSampler.cpp12
-rw-r--r--source/blender/io/collada/BCMath.cpp6
-rw-r--r--source/blender/io/collada/MeshImporter.cpp38
-rw-r--r--source/blender/io/collada/MeshImporter.h4
-rw-r--r--source/blender/io/collada/SceneExporter.cpp11
-rw-r--r--source/blender/io/collada/collada_utils.cpp1
-rw-r--r--source/blender/io/common/CMakeLists.txt3
-rw-r--r--source/blender/io/common/IO_abstract_hierarchy_iterator.h5
-rw-r--r--source/blender/io/common/IO_orientation.h16
-rw-r--r--source/blender/io/common/intern/abstract_hierarchy_iterator.cc5
-rw-r--r--source/blender/io/common/intern/orientation.c14
-rw-r--r--source/blender/io/common/intern/path_util.cc4
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.cc3
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.hh4
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_capi.cc4
-rw-r--r--source/blender/io/stl/CMakeLists.txt44
-rw-r--r--source/blender/io/stl/IO_stl.cc16
-rw-r--r--source/blender/io/stl/IO_stl.h35
-rw-r--r--source/blender/io/stl/importer/stl_import.cc133
-rw-r--r--source/blender/io/stl/importer/stl_import.hh24
-rw-r--r--source/blender/io/stl/importer/stl_import_ascii_reader.cc160
-rw-r--r--source/blender/io/stl/importer/stl_import_ascii_reader.hh35
-rw-r--r--source/blender/io/stl/importer/stl_import_binary_reader.cc63
-rw-r--r--source/blender/io/stl/importer/stl_import_binary_reader.hh31
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.cc114
-rw-r--r--source/blender/io/stl/importer/stl_import_mesh.hh71
-rw-r--r--source/blender/io/usd/intern/usd_capi_export.cc18
-rw-r--r--source/blender/io/usd/intern/usd_capi_import.cc31
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc117
-rw-r--r--source/blender/io/usd/intern/usd_reader_prim.h15
-rw-r--r--source/blender/io/usd/intern/usd_writer_material.cc3
-rw-r--r--source/blender/io/usd/intern/usd_writer_volume.cc2
-rw-r--r--source/blender/io/usd/tests/usd_imaging_test.cc6
-rw-r--r--source/blender/io/usd/tests/usd_tests_common.h2
-rw-r--r--source/blender/io/usd/usd.h8
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h29
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc36
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh6
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh4
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc15
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh7
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc7
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh2
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc8
-rw-r--r--source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc9
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc169
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.cc97
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mesh.hh7
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mtl.cc2
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_objects.hh53
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc48
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh32
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc58
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh5
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc35
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_importer_tests.cc208
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc16
-rw-r--r--source/blender/makesdna/DNA_ID.h19
-rw-r--r--source/blender/makesdna/DNA_ID_enums.h2
-rw-r--r--source/blender/makesdna/DNA_action_types.h14
-rw-r--r--source/blender/makesdna/DNA_anim_types.h2
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h12
-rw-r--r--source/blender/makesdna/DNA_brush_types.h9
-rw-r--r--source/blender/makesdna/DNA_camera_types.h4
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h4
-rw-r--r--source/blender/makesdna/DNA_collection_types.h4
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h7
-rw-r--r--source/blender/makesdna/DNA_curves_types.h32
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h8
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h8
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h42
-rw-r--r--source/blender/makesdna/DNA_ipo_types.h2
-rw-r--r--source/blender/makesdna/DNA_layer_types.h1
-rw-r--r--source/blender/makesdna/DNA_light_types.h2
-rw-r--r--source/blender/makesdna/DNA_lineart_types.h25
-rw-r--r--source/blender/makesdna/DNA_mask_types.h3
-rw-r--r--source/blender/makesdna/DNA_material_types.h7
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h21
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h7
-rw-r--r--source/blender/makesdna/DNA_node_types.h135
-rw-r--r--source/blender/makesdna/DNA_object_types.h16
-rw-r--r--source/blender/makesdna/DNA_pointcloud_types.h4
-rw-r--r--source/blender/makesdna/DNA_scene_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h140
-rw-r--r--source/blender/makesdna/DNA_screen_types.h6
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h17
-rw-r--r--source/blender/makesdna/DNA_space_defaults.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h10
-rw-r--r--source/blender/makesdna/DNA_texture_types.h3
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h10
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h22
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h5
-rw-r--r--source/blender/makesrna/RNA_access.h14
-rw-r--r--source/blender/makesrna/RNA_enum_items.h16
-rw-r--r--source/blender/makesrna/RNA_types.h21
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt3
-rw-r--r--source/blender/makesrna/intern/makesrna.c10
-rw-r--r--source/blender/makesrna/intern/rna_ID.c26
-rw-r--r--source/blender/makesrna/intern/rna_access.c59
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c7
-rw-r--r--source/blender/makesrna/intern/rna_action.c10
-rw-r--r--source/blender/makesrna/intern/rna_attribute.c34
-rw-r--r--source/blender/makesrna/intern/rna_brush.c74
-rw-r--r--source/blender/makesrna/intern/rna_camera.c95
-rw-r--r--source/blender/makesrna/intern/rna_collection.c16
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c32
-rw-r--r--source/blender/makesrna/intern/rna_curve.c17
-rw-r--r--source/blender/makesrna/intern/rna_curves.c106
-rw-r--r--source/blender/makesrna/intern/rna_define.c18
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c25
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c107
-rw-r--r--source/blender/makesrna/intern/rna_image.c77
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c8
-rw-r--r--source/blender/makesrna/intern/rna_internal.h4
-rw-r--r--source/blender/makesrna/intern/rna_internal_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_key.c16
-rw-r--r--source/blender/makesrna/intern/rna_layer.c1
-rw-r--r--source/blender/makesrna/intern/rna_main.c4
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_material.c26
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c111
-rw-r--r--source/blender/makesrna/intern/rna_meta.c14
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c24
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c25
-rw-r--r--source/blender/makesrna/intern/rna_nla.c308
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c282
-rw-r--r--source/blender/makesrna/intern/rna_object.c42
-rw-r--r--source/blender/makesrna/intern/rna_particle.c1
-rw-r--r--source/blender/makesrna/intern/rna_pointcloud.c48
-rw-r--r--source/blender/makesrna/intern/rna_pose.c6
-rw-r--r--source/blender/makesrna/intern/rna_rna.c208
-rw-r--r--source/blender/makesrna/intern/rna_scene.c98
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c21
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c205
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c37
-rw-r--r--source/blender/makesrna/intern/rna_sound.c2
-rw-r--r--source/blender/makesrna/intern/rna_space.c54
-rw-r--r--source/blender/makesrna/intern/rna_texture.c10
-rw-r--r--source/blender/makesrna/intern/rna_ui.c9
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c115
-rw-r--r--source/blender/makesrna/intern/rna_wm.c66
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c7
-rw-r--r--source/blender/makesrna/intern/rna_wm_gizmo.c5
-rw-r--r--source/blender/makesrna/intern/rna_wm_gizmo_api.c40
-rw-r--r--source/blender/makesrna/intern/rna_workspace.c8
-rw-r--r--source/blender/makesrna/intern/rna_xr.c2
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c10
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c3
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc116
-rw-r--r--source/blender/modifiers/intern/MOD_build.c4
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c2
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c2
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c2
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c5
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c2
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c2
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c3
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c8
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c9
-rw-r--r--source/blender/modifiers/intern/MOD_fluid.c2
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c2
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c5
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c2
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_mesh_to_volume.cc166
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c2
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c7
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c2
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c2
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc114
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c4
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c2
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.cc10
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c2
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c2
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c6
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c2
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c2
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c2
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c2
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c2
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c2
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c44
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c2
-rw-r--r--source/blender/modifiers/intern/MOD_surfacedeform.c17
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c2
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c2
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c2
-rw-r--r--source/blender/modifiers/intern/MOD_volume_displace.cc4
-rw-r--r--source/blender/modifiers/intern/MOD_volume_to_mesh.cc4
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c3
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c13
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c1
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c4
-rw-r--r--source/blender/modifiers/intern/MOD_weld.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/NOD_geometry.h9
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh63
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh12
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh3
-rw-r--r--source/blender/nodes/NOD_static_types.h215
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc1
-rw-r--r--source/blender/nodes/composite/node_composite_util.hh12
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diff_matte.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc22
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_map_value.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc1
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_output_file.cc8
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc32
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.cc31
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc4
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc8
-rw-r--r--source/blender/nodes/function/nodes/node_fn_separate_color.cc41
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt9
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc4
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc56
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc31
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc46
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc68
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc596
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc46
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc387
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc322
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc360
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc476
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc76
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc375
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc126
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc147
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc43
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc15
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc187
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points.cc102
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc34
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc61
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc46
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc75
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc14
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc34
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc152
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc199
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc197
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc14
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc14
-rw-r--r--source/blender/nodes/intern/node_common.cc38
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc135
-rw-r--r--source/blender/nodes/intern/node_socket.cc5
-rw-r--r--source/blender/nodes/intern/node_socket_declarations.cc7
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc10
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_light.cc18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.cc2
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c8
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c17
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c39
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_texture.c2
-rw-r--r--source/blender/python/BPY_extern.h5
-rw-r--r--source/blender/python/generic/bgl.c66
-rw-r--r--source/blender/python/generic/py_capi_utils.c8
-rw-r--r--source/blender/python/gpu/gpu_py_api.c4
-rw-r--r--source/blender/python/gpu/gpu_py_batch.c4
-rw-r--r--source/blender/python/gpu/gpu_py_element.c1
-rw-r--r--source/blender/python/gpu/gpu_py_framebuffer.c4
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c3
-rw-r--r--source/blender/python/gpu/gpu_py_platform.c2
-rw-r--r--source/blender/python/gpu/gpu_py_select.c2
-rw-r--r--source/blender/python/gpu/gpu_py_shader.c1
-rw-r--r--source/blender/python/gpu/gpu_py_shader_create_info.cc1
-rw-r--r--source/blender/python/gpu/gpu_py_types.c1
-rw-r--r--source/blender/python/gpu/gpu_py_uniformbuffer.c2
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_buffer.c8
-rw-r--r--source/blender/python/gpu/gpu_py_vertex_format.c4
-rw-r--r--source/blender/python/intern/CMakeLists.txt14
-rw-r--r--source/blender/python/intern/bpy.c196
-rw-r--r--source/blender/python/intern/bpy_app.c54
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c21
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c76
-rw-r--r--source/blender/python/intern/bpy_driver.c254
-rw-r--r--source/blender/python/intern/bpy_driver.h10
-rw-r--r--source/blender/python/intern/bpy_interface.c22
-rw-r--r--source/blender/python/intern/bpy_props.c215
-rw-r--r--source/blender/python/intern/bpy_rna_anim.c3
-rw-r--r--source/blender/python/intern/bpy_rna_gizmo.c2
-rw-r--r--source/blender/python/intern/bpy_traceback.c5
-rw-r--r--source/blender/python/mathutils/CMakeLists.txt2
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c23
-rw-r--r--source/blender/python/rna_dump.py2
-rw-r--r--source/blender/render/RE_pipeline.h16
-rw-r--r--source/blender/render/RE_texture.h3
-rw-r--r--source/blender/render/RE_texture_margin.h9
-rw-r--r--source/blender/render/intern/engine.c12
-rw-r--r--source/blender/render/intern/pipeline.c22
-rw-r--r--source/blender/render/intern/render_result.c6
-rw-r--r--source/blender/render/intern/render_result.h2
-rw-r--r--source/blender/render/intern/texture_image.c308
-rw-r--r--source/blender/render/intern/texture_procedural.c414
-rw-r--r--source/blender/sequencer/SEQ_add.h9
-rw-r--r--source/blender/sequencer/SEQ_channels.h4
-rw-r--r--source/blender/sequencer/SEQ_edit.h5
-rw-r--r--source/blender/sequencer/SEQ_effects.h5
-rw-r--r--source/blender/sequencer/SEQ_iterator.h19
-rw-r--r--source/blender/sequencer/SEQ_relations.h1
-rw-r--r--source/blender/sequencer/SEQ_render.h13
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h22
-rw-r--r--source/blender/sequencer/SEQ_sound.h1
-rw-r--r--source/blender/sequencer/SEQ_time.h33
-rw-r--r--source/blender/sequencer/SEQ_transform.h17
-rw-r--r--source/blender/sequencer/SEQ_utils.h10
-rw-r--r--source/blender/sequencer/intern/disk_cache.c5
-rw-r--r--source/blender/sequencer/intern/effects.c60
-rw-r--r--source/blender/sequencer/intern/image_cache.c46
-rw-r--r--source/blender/sequencer/intern/iterator.c37
-rw-r--r--source/blender/sequencer/intern/prefetch.c2
-rw-r--r--source/blender/sequencer/intern/proxy.c41
-rw-r--r--source/blender/sequencer/intern/render.c71
-rw-r--r--source/blender/sequencer/intern/render.h3
-rw-r--r--source/blender/sequencer/intern/sequence_lookup.c94
-rw-r--r--source/blender/sequencer/intern/sequencer.c67
-rw-r--r--source/blender/sequencer/intern/sequencer.h26
-rw-r--r--source/blender/sequencer/intern/sound.c20
-rw-r--r--source/blender/sequencer/intern/strip_add.c56
-rw-r--r--source/blender/sequencer/intern/strip_edit.c196
-rw-r--r--source/blender/sequencer/intern/strip_relations.c38
-rw-r--r--source/blender/sequencer/intern/strip_time.c367
-rw-r--r--source/blender/sequencer/intern/strip_time.h7
-rw-r--r--source/blender/sequencer/intern/strip_transform.c525
-rw-r--r--source/blender/sequencer/intern/utils.c75
-rw-r--r--source/blender/windowmanager/CMakeLists.txt2
-rw-r--r--source/blender/windowmanager/WM_api.h42
-rw-r--r--source/blender/windowmanager/WM_types.h58
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h2
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c7
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c4
-rw-r--r--source/blender/windowmanager/intern/wm.c10
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c17
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c25
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c247
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c34
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.cc (renamed from source/blender/windowmanager/intern/wm_event_system.c)909
-rw-r--r--source/blender/windowmanager/intern/wm_files.c14
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c8
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c43
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c60
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c5
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c6
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c8
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c27
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c1
-rw-r--r--source/blender/windowmanager/intern/wm_window.c77
-rw-r--r--source/blender/windowmanager/wm_event_types.h6
-rw-r--r--source/blender/windowmanager/wm_window.h7
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_action.c9
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h6
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c5
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c8
-rw-r--r--source/creator/CMakeLists.txt2
-rw-r--r--source/creator/blender.map3
m---------source/tools0
-rw-r--r--tests/performance/tests/eevee.py129
-rw-r--r--tests/python/CMakeLists.txt5
-rw-r--r--tests/python/alembic_export_tests.py2
-rw-r--r--tests/python/batch_import.py2
-rw-r--r--tests/python/bl_alembic_io_test.py2
-rw-r--r--tests/python/bl_animation_fcurves.py2
-rw-r--r--tests/python/bl_blendfile_library_overrides.py116
-rw-r--r--tests/python/bl_bundled_modules.py2
-rw-r--r--tests/python/bl_keymap_completeness.py2
-rw-r--r--tests/python/bl_keymap_validate.py2
-rw-r--r--tests/python/bl_load_addons.py2
-rw-r--r--tests/python/bl_load_py_modules.py2
-rw-r--r--tests/python/bl_mesh_modifiers.py2
-rw-r--r--tests/python/bl_mesh_validate.py2
-rw-r--r--tests/python/bl_pyapi_bpy_driver_secure_eval.py220
-rw-r--r--tests/python/bl_rigging_symmetrize.py28
-rw-r--r--tests/python/bl_rna_manual_reference.py2
-rw-r--r--tests/python/bl_rst_completeness.py2
-rw-r--r--tests/python/bl_run_operators.py2
-rw-r--r--tests/python/bl_run_operators_event_simulate.py2
-rw-r--r--tests/python/bl_test.py2
-rw-r--r--tests/python/bl_usd_import_test.py2
-rw-r--r--tests/python/boolean_operator.py2
-rw-r--r--tests/python/deform_modifiers.py2
-rw-r--r--tests/python/eevee_render_tests.py6
-rw-r--r--tests/python/ffmpeg_tests.py2
-rw-r--r--tests/python/geo_node_test.py2
-rw-r--r--tests/python/modifiers.py19
-rw-r--r--tests/python/modules/mesh_test.py2
-rwxr-xr-xtests/python/modules/render_report.py8
-rwxr-xr-xtests/python/modules/test_utils.py2
-rw-r--r--tests/python/operators.py2
-rw-r--r--tests/python/pep8.py21
-rw-r--r--tests/python/physics_cloth.py2
-rw-r--r--tests/python/physics_dynamic_paint.py2
-rw-r--r--tests/python/physics_ocean.py2
-rw-r--r--tests/python/physics_particle_instance.py2
-rw-r--r--tests/python/physics_particle_system.py2
-rw-r--r--tests/python/physics_softbody.py2
-rw-r--r--tests/python/rna_info_dump.py2
-rw-r--r--tests/python/rst_to_doctree_mini.py2
-rw-r--r--tests/python/workbench_render_tests.py7
2407 files changed, 86816 insertions, 45440 deletions
diff --git a/.clang-format b/.clang-format
index f7b785adaf2..7b8e0ef8eba 100644
--- a/.clang-format
+++ b/.clang-format
@@ -265,6 +265,7 @@ ForEachMacros:
- SET_SLOT_PROBING_BEGIN
- MAP_SLOT_PROBING_BEGIN
- VECTOR_SET_SLOT_PROBING_BEGIN
+ - WL_ARRAY_FOR_EACH
StatementMacros:
- PyObject_HEAD
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3e97e393f17..c998919622e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -222,6 +222,17 @@ if(UNIX AND NOT (APPLE OR HAIKU))
option(WITH_GHOST_WAYLAND "Enable building Blender against Wayland for windowing (under development)" OFF)
mark_as_advanced(WITH_GHOST_WAYLAND)
+
+ if (WITH_GHOST_WAYLAND)
+ option(WITH_GHOST_WAYLAND_LIBDECOR "Optionally build with LibDecor window decorations" OFF)
+ mark_as_advanced(WITH_GHOST_WAYLAND_LIBDECOR)
+
+ option(WITH_GHOST_WAYLAND_DBUS "Optionally build with DBUS support (used for Cursor themes). May hang on startup systems where DBUS is not used." OFF)
+ mark_as_advanced(WITH_GHOST_WAYLAND_DBUS)
+
+ option(WITH_GHOST_WAYLAND_DYNLOAD "Enable runtime dynamic WAYLAND libraries loading" OFF)
+ mark_as_advanced(WITH_GHOST_WAYLAND_DYNLOAD)
+ endif()
endif()
if(WITH_GHOST_X11)
@@ -255,19 +266,11 @@ if(WITH_GHOST_X11)
endif()
if(UNIX AND NOT APPLE)
- option(WITH_SYSTEM_GLEW "Use GLEW OpenGL wrapper library provided by the operating system" OFF)
- option(WITH_SYSTEM_GLES "Use OpenGL ES library provided by the operating system" ON)
option(WITH_SYSTEM_FREETYPE "Use the freetype library provided by the operating system" OFF)
+ option(WITH_SYSTEM_EIGEN3 "Use the systems Eigen3 library" OFF)
else()
- # not an option for other OS's
- set(WITH_SYSTEM_GLEW OFF)
- set(WITH_SYSTEM_GLES OFF)
set(WITH_SYSTEM_FREETYPE OFF)
-endif()
-
-
-if(UNIX AND NOT APPLE)
- option(WITH_SYSTEM_EIGEN3 "Use the systems Eigen3 library" OFF)
+ set(WITH_SYSTEM_EIGEN3 OFF)
endif()
@@ -300,6 +303,9 @@ option(WITH_USD "Enable Universal Scene Description (USD) Suppor
# 3D format support
# Disable opencollada when we don't have precompiled libs
option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.org)" ON)
+option(WITH_IO_WAVEFRONT_OBJ "Enable Wavefront-OBJ 3D file format support (*.obj)" ON)
+option(WITH_IO_STL "Enable STL 3D file format support (*.stl)" ON)
+option(WITH_IO_GPENCIL "Enable grease-pencil file format IO (*.svg, *.pdf)" ON)
# Sound output
option(WITH_SDL "Enable SDL for sound" ON)
@@ -441,7 +447,7 @@ endif()
if(NOT APPLE)
option(WITH_CYCLES_DEVICE_HIP "Enable Cycles AMD HIP support" ON)
option(WITH_CYCLES_HIP_BINARIES "Build Cycles AMD HIP binaries" OFF)
- set(CYCLES_HIP_BINARIES_ARCH gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 CACHE STRING "AMD HIP architectures to build binaries for")
+ set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx906 gfx90c gfx902 gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032 gfx1034 gfx1035 CACHE STRING "AMD HIP architectures to build binaries for")
mark_as_advanced(WITH_CYCLES_DEVICE_HIP)
mark_as_advanced(CYCLES_HIP_BINARIES_ARCH)
endif()
@@ -451,6 +457,21 @@ if(APPLE)
option(WITH_CYCLES_DEVICE_METAL "Enable Cycles Apple Metal compute support" ON)
endif()
+# oneAPI
+if(NOT APPLE)
+ option(WITH_CYCLES_DEVICE_ONEAPI "Enable Cycles oneAPI compute support" OFF)
+ option(WITH_CYCLES_ONEAPI_BINARIES "Enable Ahead-Of-Time compilation for Cycles oneAPI device" OFF)
+ option(WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED "Enable use of SYCL host (CPU) device execution by oneAPI implementation. This option is for debugging purposes and impacts GPU execution." OFF)
+
+ # https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compilation/ahead-of-time-compilation.html
+ SET (CYCLES_ONEAPI_SPIR64_GEN_DEVICES "dg2" CACHE STRING "oneAPI Intel GPU architectures to build binaries for")
+ SET (CYCLES_ONEAPI_SYCL_TARGETS spir64 spir64_gen CACHE STRING "oneAPI targets to build AOT binaries for")
+
+ mark_as_advanced(WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED)
+ mark_as_advanced(CYCLES_ONEAPI_SPIR64_GEN_DEVICES)
+ mark_as_advanced(CYCLES_ONEAPI_SYCL_TARGETS)
+endif()
+
# Draw Manager
option(WITH_DRAW_DEBUG "Add extra debug capabilities to Draw Manager" OFF)
mark_as_advanced(WITH_DRAW_DEBUG)
@@ -515,20 +536,48 @@ endif()
# OpenGL
+# Experimental EGL option.
+option(WITH_GL_EGL "Use the EGL OpenGL system library instead of the platform specific OpenGL system library (CGL, GLX or WGL)" OFF)
+mark_as_advanced(WITH_GL_EGL)
+
+if(WITH_GHOST_WAYLAND)
+ # Wayland can only use EGL to create OpenGL contexts, not GLX.
+ set(WITH_GL_EGL ON)
+endif()
+
+if(UNIX AND NOT APPLE)
+ if(WITH_GL_EGL)
+ # GLEW can only be built with either GLX or EGL support. Most binary distributions are
+ # built with GLX support and we have no automated way to detect this. So always build
+ # GLEW from source to be sure it has EGL support.
+ set(WITH_SYSTEM_GLEW OFF)
+ else()
+ option(WITH_SYSTEM_GLEW "Use GLEW OpenGL wrapper library provided by the operating system" OFF)
+ endif()
+
+ option(WITH_SYSTEM_GLES "Use OpenGL ES library provided by the operating system" ON)
+else()
+ # System GLEW and GLES not an option on other platforms.
+ set(WITH_SYSTEM_GLEW OFF)
+ set(WITH_SYSTEM_GLES OFF)
+endif()
+
option(WITH_OPENGL "When off limits visibility of the opengl headers to just bf_gpu and gawain (temporary option for development purposes)" ON)
option(WITH_GLEW_ES "Switches to experimental copy of GLEW that has support for OpenGL ES. (temporary option for development purposes)" OFF)
-option(WITH_GL_EGL "Use the EGL OpenGL system library instead of the platform specific OpenGL system library (CGL, glX, or WGL)" OFF)
option(WITH_GL_PROFILE_ES20 "Support using OpenGL ES 2.0. (through either EGL or the AGL/WGL/XGL 'es20' profile)" OFF)
-option(WITH_GPU_SHADER_BUILDER "Shader builder is a developer option enabling linting on GLSL during compilation" OFF)
+option(WITH_GPU_BUILDTIME_SHADER_BUILDER "Shader builder is a developer option enabling linting on GLSL during compilation" OFF)
mark_as_advanced(
WITH_OPENGL
WITH_GLEW_ES
- WITH_GL_EGL
WITH_GL_PROFILE_ES20
- WITH_GPU_SHADER_BUILDER
+ WITH_GPU_BUILDTIME_SHADER_BUILDER
)
+if(WITH_HEADLESS)
+ set(WITH_OPENGL OFF)
+endif()
+
# Metal
if (APPLE)
diff --git a/build_files/build_environment/CMakeLists.txt b/build_files/build_environment/CMakeLists.txt
index b63e86a3ac2..e0350901cd0 100644
--- a/build_files/build_environment/CMakeLists.txt
+++ b/build_files/build_environment/CMakeLists.txt
@@ -29,10 +29,12 @@ cmake_minimum_required(VERSION 3.5)
include(ExternalProject)
include(cmake/check_software.cmake)
-include(cmake/versions.cmake)
include(cmake/options.cmake)
+# versions.cmake needs to be included after options.cmake due to the BLENDER_PLATFORM_ARM variable being needed.
+include(cmake/versions.cmake)
include(cmake/boost_build_options.cmake)
include(cmake/download.cmake)
+include(cmake/macros.cmake)
if(ENABLE_MINGW64)
include(cmake/setup_mingw64.cmake)
@@ -57,7 +59,6 @@ include(cmake/alembic.cmake)
include(cmake/opensubdiv.cmake)
include(cmake/sdl.cmake)
include(cmake/opencollada.cmake)
-include(cmake/llvm.cmake)
if(APPLE)
include(cmake/openmp.cmake)
endif()
@@ -75,6 +76,7 @@ include(cmake/osl.cmake)
include(cmake/tbb.cmake)
include(cmake/openvdb.cmake)
include(cmake/python.cmake)
+include(cmake/llvm.cmake)
option(USE_PIP_NUMPY "Install NumPy using pip wheel instead of building from source" OFF)
if(APPLE AND ("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64"))
set(USE_PIP_NUMPY ON)
@@ -96,6 +98,15 @@ include(cmake/fmt.cmake)
include(cmake/robinmap.cmake)
if(NOT APPLE)
include(cmake/xr_openxr.cmake)
+ if(NOT WIN32 OR BUILD_MODE STREQUAL Release)
+ include(cmake/dpcpp.cmake)
+ include(cmake/dpcpp_deps.cmake)
+ endif()
+ if(NOT WIN32)
+ include(cmake/igc.cmake)
+ include(cmake/gmmlib.cmake)
+ include(cmake/ocloc.cmake)
+ endif()
endif()
# OpenColorIO and dependencies.
diff --git a/build_files/build_environment/cmake/check_software.cmake b/build_files/build_environment/cmake/check_software.cmake
index 2a1aaef0bee..080c1e52973 100644
--- a/build_files/build_environment/cmake/check_software.cmake
+++ b/build_files/build_environment/cmake/check_software.cmake
@@ -56,10 +56,7 @@ if(UNIX)
"On Debian and Ubuntu:\n"
" apt install autoconf automake libtool yasm tcl ninja-build meson python3-mako\n"
"\n"
- "On macOS Intel (with homebrew):\n"
- " brew install autoconf automake bison libtool pkg-config yasm\n"
- "\n"
- "On macOS ARM (with homebrew):\n"
+ "On macOS (with homebrew):\n"
" brew install autoconf automake bison flex libtool pkg-config yasm\n"
"\n"
"Other platforms:\n"
diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake
index 81e7f7ab3fe..b7150525a65 100644
--- a/build_files/build_environment/cmake/download.cmake
+++ b/build_files/build_environment/cmake/download.cmake
@@ -101,3 +101,18 @@ download_source(ROBINMAP)
download_source(IMATH)
download_source(PYSTRING)
download_source(LEVEL_ZERO)
+download_source(DPCPP)
+download_source(VCINTRINSICS)
+download_source(OPENCLHEADERS)
+download_source(ICDLOADER)
+download_source(MP11)
+download_source(SPIRV_HEADERS)
+download_source(IGC)
+download_source(IGC_LLVM)
+download_source(IGC_OPENCL_CLANG)
+download_source(IGC_VCINTRINSICS)
+download_source(IGC_SPIRV_HEADERS)
+download_source(IGC_SPIRV_TOOLS)
+download_source(IGC_SPIRV_TRANSLATOR)
+download_source(GMMLIB)
+download_source(OCLOC)
diff --git a/build_files/build_environment/cmake/dpcpp.cmake b/build_files/build_environment/cmake/dpcpp.cmake
new file mode 100644
index 00000000000..3c3fe201073
--- /dev/null
+++ b/build_files/build_environment/cmake/dpcpp.cmake
@@ -0,0 +1,109 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+
+if(WIN32)
+ set(LLVM_GENERATOR "Ninja")
+else()
+ set(LLVM_GENERATOR "Unix Makefiles")
+endif()
+
+set(DPCPP_CONFIGURE_ARGS
+ # When external deps dpcpp needs are not found it will automatically
+ # download the during the configure stage using FetchContent. Given
+ # we need to keep an archive of all source used during build for compliance
+ # reasons it CANNOT download anything we do not know about. By setting
+ # this property to ON, all downloads are disabled, and we will have to
+ # provide the missing deps some other way, a build error beats a compliance
+ # violation
+ --cmake-opt FETCHCONTENT_FULLY_DISCONNECTED=ON
+)
+set(DPCPP_SOURCE_ROOT ${BUILD_DIR}/dpcpp/src/external_dpcpp/)
+set(DPCPP_EXTRA_ARGS
+ # When external deps dpcpp needs are not found it will automatically
+ # download the during the configure stage using FetchContent. Given
+ # we need to keep an archive of all source used during build for compliance
+ # reasons it CANNOT download anything we do not know about. By setting
+ # this property to ON, all downloads are disabled, and we will have to
+ # provide the missing deps some other way, a build or configure error
+ # beats a compliance violation
+ -DFETCHCONTENT_FULLY_DISCONNECTED=ON
+ -DLLVMGenXIntrinsics_SOURCE_DIR=${BUILD_DIR}/vcintrinsics/src/external_vcintrinsics/
+ -DOpenCL_HEADERS=file://${PACKAGE_DIR}/${OPENCLHEADERS_FILE}
+ -DOpenCL_LIBRARY_SRC=file://${PACKAGE_DIR}/${ICDLOADER_FILE}
+ -DBOOST_MP11_SOURCE_DIR=${BUILD_DIR}/mp11/src/external_mp11/
+ -DLEVEL_ZERO_LIBRARY=${LIBDIR}/level-zero/lib/${LIBPREFIX}ze_loader${SHAREDLIBEXT}
+ -DLEVEL_ZERO_INCLUDE_DIR=${LIBDIR}/level-zero/include
+ -DLLVM_EXTERNAL_SPIRV_HEADERS_SOURCE_DIR=${BUILD_DIR}/spirvheaders/src/external_spirvheaders/
+ # Below here is copied from an invocation of buildbot/config.py
+ -DLLVM_ENABLE_ASSERTIONS=ON
+ -DLLVM_TARGETS_TO_BUILD=X86
+ -DLLVM_EXTERNAL_PROJECTS=sycl^^llvm-spirv^^opencl^^libdevice^^xpti^^xptifw
+ -DLLVM_EXTERNAL_SYCL_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/sycl
+ -DLLVM_EXTERNAL_LLVM_SPIRV_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/llvm-spirv
+ -DLLVM_EXTERNAL_XPTI_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/xpti
+ -DXPTI_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/xpti
+ -DLLVM_EXTERNAL_XPTIFW_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/xptifw
+ -DLLVM_EXTERNAL_LIBDEVICE_SOURCE_DIR=${DPCPP_SOURCE_ROOT}/libdevice
+ -DLLVM_ENABLE_PROJECTS=clang^^sycl^^llvm-spirv^^opencl^^libdevice^^xpti^^xptifw
+ -DLIBCLC_TARGETS_TO_BUILD=
+ -DLIBCLC_GENERATE_REMANGLED_VARIANTS=OFF
+ -DSYCL_BUILD_PI_HIP_PLATFORM=AMD
+ -DLLVM_BUILD_TOOLS=ON
+ -DSYCL_ENABLE_WERROR=OFF
+ -DSYCL_INCLUDE_TESTS=ON
+ -DLLVM_ENABLE_DOXYGEN=OFF
+ -DLLVM_ENABLE_SPHINX=OFF
+ -DBUILD_SHARED_LIBS=OFF
+ -DSYCL_ENABLE_XPTI_TRACING=ON
+ -DLLVM_ENABLE_LLD=OFF
+ -DXPTI_ENABLE_WERROR=OFF
+ -DSYCL_CLANG_EXTRA_FLAGS=
+ -DSYCL_ENABLE_PLUGINS=level_zero
+ -DCMAKE_INSTALL_RPATH=\$ORIGIN
+ -DPython3_ROOT_DIR=${LIBDIR}/python/
+ -DPython3_EXECUTABLE=${PYTHON_BINARY}
+ -DPYTHON_EXECUTABLE=${PYTHON_BINARY}
+ -DLLDB_ENABLE_CURSES=OFF
+ -DLLVM_ENABLE_TERMINFO=OFF
+)
+
+if(WIN32)
+ list(APPEND DPCPP_EXTRA_ARGS -DPython3_FIND_REGISTRY=NEVER)
+endif()
+
+ExternalProject_Add(external_dpcpp
+ URL file://${PACKAGE_DIR}/${DPCPP_FILE}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH ${DPCPP_HASH_TYPE}=${DPCPP_HASH}
+ PREFIX ${BUILD_DIR}/dpcpp
+ CMAKE_GENERATOR ${LLVM_GENERATOR}
+ SOURCE_SUBDIR llvm
+ LIST_SEPARATOR ^^
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/dpcpp ${DEFAULT_CMAKE_FLAGS} ${DPCPP_EXTRA_ARGS}
+ #CONFIGURE_COMMAND ${PYTHON_BINARY} ${BUILD_DIR}/dpcpp/src/external_dpcpp/buildbot/configure.py ${DPCPP_CONFIGURE_ARGS}
+ #BUILD_COMMAND echo "." #${PYTHON_BINARY} ${BUILD_DIR}/dpcpp/src/external_dpcpp/buildbot/compile.py
+ INSTALL_COMMAND ${CMAKE_COMMAND} --build . -- deploy-sycl-toolchain
+ PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/dpcpp/src/external_dpcpp < ${PATCH_DIR}/dpcpp.diff
+ INSTALL_DIR ${LIBDIR}/dpcpp
+)
+
+add_dependencies(
+ external_dpcpp
+ external_python
+ external_python_site_packages
+ external_vcintrinsics
+ external_openclheaders
+ external_icdloader
+ external_mp11
+ external_level-zero
+ external_spirvheaders
+)
+
+if(BUILD_MODE STREQUAL Release AND WIN32)
+ ExternalProject_Add_Step(external_dpcpp after_install
+ COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBDIR}/dpcpp/bin/clang-cl.exe
+ COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBDIR}/dpcpp/bin/clang-cpp.exe
+ COMMAND ${CMAKE_COMMAND} -E rm -f ${LIBDIR}/dpcpp/bin/clang.exe
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/dpcpp ${HARVEST_TARGET}/dpcpp
+ )
+endif()
diff --git a/build_files/build_environment/cmake/dpcpp_deps.cmake b/build_files/build_environment/cmake/dpcpp_deps.cmake
new file mode 100644
index 00000000000..e66006993f6
--- /dev/null
+++ b/build_files/build_environment/cmake/dpcpp_deps.cmake
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# These are build time requirements for dpcpp
+# We only have to unpack these dpcpp will build
+# them.
+
+ExternalProject_Add(external_vcintrinsics
+ URL file://${PACKAGE_DIR}/${VCINTRINSICS_FILE}
+ URL_HASH ${VCINTRINSICS_HASH_TYPE}=${VCINTRINSICS_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/vcintrinsics
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+)
+
+# opencl headers do not have to be unpacked, dpcpp will do it
+# but it wouldn't hurt to do it anyway as an opertunity to validate
+# the hash is correct.
+ExternalProject_Add(external_openclheaders
+ URL file://${PACKAGE_DIR}/${OPENCLHEADERS_FILE}
+ URL_HASH ${OPENCLHEADERS_HASH_TYPE}=${OPENCLHEADERS_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/openclheaders
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+)
+
+# icdloader does not have to be unpacked, dpcpp will do it
+# but it wouldn't hurt to do it anyway as an opertunity to validate
+# the hash is correct.
+ExternalProject_Add(external_icdloader
+ URL file://${PACKAGE_DIR}/${ICDLOADER_FILE}
+ URL_HASH ${ICDLOADER_HASH_TYPE}=${ICDLOADER_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/icdloader
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+)
+
+ExternalProject_Add(external_mp11
+ URL file://${PACKAGE_DIR}/${MP11_FILE}
+ URL_HASH ${MP11_HASH_TYPE}=${MP11_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/mp11
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+)
+
+ExternalProject_Add(external_spirvheaders
+ URL file://${PACKAGE_DIR}/${SPIRV_HEADERS_FILE}
+ URL_HASH ${SPIRV_HEADERS_HASH_TYPE}=${SPIRV_HEADERS_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/spirvheaders
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+)
diff --git a/build_files/build_environment/cmake/embree.cmake b/build_files/build_environment/cmake/embree.cmake
index 2eafc729111..8c689cf000b 100644
--- a/build_files/build_environment/cmake/embree.cmake
+++ b/build_files/build_environment/cmake/embree.cmake
@@ -10,18 +10,12 @@ set(EMBREE_EXTRA_ARGS
-DEMBREE_RAY_MASK=ON
-DEMBREE_FILTER_FUNCTION=ON
-DEMBREE_BACKFACE_CULLING=OFF
- -DEMBREE_MAX_ISA=AVX2
-DEMBREE_TASKING_SYSTEM=TBB
-DEMBREE_TBB_ROOT=${LIBDIR}/tbb
-DTBB_ROOT=${LIBDIR}/tbb
- -DTBB_STATIC_LIB=${TBB_STATIC_LIBRARY}
)
-if(BLENDER_PLATFORM_ARM)
- set(EMBREE_EXTRA_ARGS
- ${EMBREE_EXTRA_ARGS}
- -DEMBREE_MAX_ISA=NEON)
-else()
+if (NOT BLENDER_PLATFORM_ARM)
set(EMBREE_EXTRA_ARGS
${EMBREE_EXTRA_ARGS}
-DEMBREE_MAX_ISA=AVX2)
@@ -30,23 +24,10 @@ endif()
if(TBB_STATIC_LIBRARY)
set(EMBREE_EXTRA_ARGS
${EMBREE_EXTRA_ARGS}
- -DEMBREE_TBB_LIBRARY_NAME=tbb_static
- -DEMBREE_TBBMALLOC_LIBRARY_NAME=tbbmalloc_static
+ -DEMBREE_TBB_COMPONENT=tbb_static
)
endif()
-if(WIN32)
- set(EMBREE_BUILD_DIR ${BUILD_MODE}/)
- if(BUILD_MODE STREQUAL Debug)
- list(APPEND EMBREE_EXTRA_ARGS
- -DEMBREE_TBBMALLOC_LIBRARY_NAME=tbbmalloc_debug
- -DEMBREE_TBB_LIBRARY_NAME=tbb_debug
- )
- endif()
-else()
- set(EMBREE_BUILD_DIR)
-endif()
-
ExternalProject_Add(external_embree
URL file://${PACKAGE_DIR}/${EMBREE_FILE}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
diff --git a/build_files/build_environment/cmake/flex.cmake b/build_files/build_environment/cmake/flex.cmake
index 2b04c8d5d68..99233adbcdc 100644
--- a/build_files/build_environment/cmake/flex.cmake
+++ b/build_files/build_environment/cmake/flex.cmake
@@ -5,6 +5,8 @@ ExternalProject_Add(external_flex
URL_HASH ${FLEX_HASH_TYPE}=${FLEX_HASH}
DOWNLOAD_DIR ${DOWNLOAD_DIR}
PREFIX ${BUILD_DIR}/flex
+ # This patch fixes build with some versions of glibc (https://github.com/westes/flex/commit/24fd0551333e7eded87b64dd36062da3df2f6380)
+ PATCH_COMMAND ${PATCH_CMD} -d ${BUILD_DIR}/flex/src/external_flex < ${PATCH_DIR}/flex.diff
CONFIGURE_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flex/src/external_flex/ && ${CONFIGURE_COMMAND} --prefix=${LIBDIR}/flex
BUILD_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flex/src/external_flex/ && make -j${MAKE_THREADS}
INSTALL_COMMAND ${CONFIGURE_ENV} && cd ${BUILD_DIR}/flex/src/external_flex/ && make install
diff --git a/build_files/build_environment/cmake/gmmlib.cmake b/build_files/build_environment/cmake/gmmlib.cmake
new file mode 100644
index 00000000000..c46f5c8943d
--- /dev/null
+++ b/build_files/build_environment/cmake/gmmlib.cmake
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(GMMLIB_EXTRA_ARGS
+)
+
+ExternalProject_Add(external_gmmlib
+ URL file://${PACKAGE_DIR}/${GMMLIB_FILE}
+ URL_HASH ${GMMLIB_HASH_TYPE}=${GMMLIB_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/gmmlib
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/gmmlib ${DEFAULT_CMAKE_FLAGS} ${GMMLIB_EXTRA_ARGS}
+ INSTALL_DIR ${LIBDIR}/gmmlib
+)
diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake
index aeaa6fbd2b5..2865a5304d7 100644
--- a/build_files/build_environment/cmake/harvest.cmake
+++ b/build_files/build_environment/cmake/harvest.cmake
@@ -192,6 +192,10 @@ harvest(zstd/lib zstd/lib "*.a")
if(UNIX AND NOT APPLE)
harvest(libglu/lib mesa/lib "*.so*")
harvest(mesa/lib64 mesa/lib "*.so*")
-endif()
+
+ harvest(dpcpp dpcpp "*")
+ harvest(igc dpcpp/lib/igc "*")
+ harvest(ocloc dpcpp/lib/ocloc "*")
+ endif()
endif()
diff --git a/build_files/build_environment/cmake/igc.cmake b/build_files/build_environment/cmake/igc.cmake
new file mode 100644
index 00000000000..3b488a77b3f
--- /dev/null
+++ b/build_files/build_environment/cmake/igc.cmake
@@ -0,0 +1,126 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+unpack_only(igc_vcintrinsics)
+unpack_only(igc_spirv_headers)
+unpack_only(igc_spirv_tools)
+
+#
+# igc_opencl_clang contains patches that need to be applied
+# to external_igc_llvm and igc_spirv_translator, we unpack
+# igc_opencl_clang first, then have the patch stages of
+# external_igc_llvm and igc_spirv_translator apply them.
+#
+
+ExternalProject_Add(external_igc_opencl_clang
+ URL file://${PACKAGE_DIR}/${IGC_OPENCL_CLANG_FILE}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH ${IGC_OPENCL_CLANG_HASH_TYPE}=${IGC_OPENCL_CLANG_HASH}
+ PREFIX ${BUILD_DIR}/igc_opencl_clang
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+ PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/igc_opencl_clang/src/external_igc_opencl_clang/ < ${PATCH_DIR}/igc_opencl_clang.diff
+)
+
+set(IGC_OPENCL_CLANG_PATCH_DIR ${BUILD_DIR}/igc_opencl_clang/src/external_igc_opencl_clang/patches)
+set(IGC_LLVM_SOURCE_DIR ${BUILD_DIR}/igc_llvm/src/external_igc_llvm)
+set(IGC_SPIRV_TRANSLATOR_SOURCE_DIR ${BUILD_DIR}/igc_spirv_translator/src/external_igc_spirv_translator)
+
+ExternalProject_Add(external_igc_llvm
+ URL file://${PACKAGE_DIR}/${IGC_LLVM_FILE}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH ${IGC_LLVM_HASH_TYPE}=${IGC_LLVM_HASH}
+ PREFIX ${BUILD_DIR}/igc_llvm
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+ PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0001-OpenCL-3.0-support.patch &&
+ ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0002-Remove-__IMAGE_SUPPORT__-macro-for-SPIR.patch &&
+ ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0003-Avoid-calling-ParseCommandLineOptions-in-BackendUtil.patch &&
+ ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0004-OpenCL-support-cl_ext_float_atomics.patch &&
+ ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/clang/0005-OpenCL-Add-cl_khr_integer_dot_product.patch &&
+ ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/llvm/0001-Memory-leak-fix-for-Managed-Static-Mutex.patch &&
+ ${PATCH_CMD} -p 1 -d ${IGC_LLVM_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/llvm/0002-Remove-repo-name-in-LLVM-IR.patch
+)
+add_dependencies(
+ external_igc_llvm
+ external_igc_opencl_clang
+)
+
+ExternalProject_Add(external_igc_spirv_translator
+ URL file://${PACKAGE_DIR}/${IGC_SPIRV_TRANSLATOR_FILE}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH ${IGC_SPIRV_TRANSLATOR_HASH_TYPE}=${IGC_SPIRV_TRANSLATOR_HASH}
+ PREFIX ${BUILD_DIR}/igc_spirv_translator
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+ PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${IGC_SPIRV_TRANSLATOR_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/spirv/0001-update-SPIR-V-headers-for-SPV_INTEL_split_barrier.patch &&
+ ${PATCH_CMD} -p 1 -d ${IGC_SPIRV_TRANSLATOR_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/spirv/0002-Add-support-for-split-barriers-extension-SPV_INTEL_s.patch &&
+ ${PATCH_CMD} -p 1 -d ${IGC_SPIRV_TRANSLATOR_SOURCE_DIR} < ${IGC_OPENCL_CLANG_PATCH_DIR}/spirv/0003-Support-cl_bf16_conversions.patch
+)
+add_dependencies(
+ external_igc_spirv_translator
+ external_igc_opencl_clang
+)
+
+if(WIN32)
+ set(IGC_GENERATOR "Ninja")
+ set(IGC_TARGET Windows64)
+else()
+ set(IGC_GENERATOR "Unix Makefiles")
+ set(IGC_TARGET Linux64)
+endif()
+
+set(IGC_EXTRA_ARGS
+ -DIGC_OPTION__ARCHITECTURE_TARGET=${IGC_TARGET}
+ -DIGC_OPTION__ARCHITECTURE_HOST=${IGC_TARGET}
+)
+
+if(UNIX AND NOT APPLE)
+ list(APPEND IGC_EXTRA_ARGS
+ -DFLEX_EXECUTABLE=${LIBDIR}/flex/bin/flex
+ -DFLEX_INCLUDE_DIR=${LIBDIR}/flex/include
+ )
+endif()
+
+ExternalProject_Add(external_igc
+ URL file://${PACKAGE_DIR}/${IGC_FILE}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ URL_HASH ${IGC_HASH_TYPE}=${IGC_HASH}
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/igc ${DEFAULT_CMAKE_FLAGS} ${IGC_EXTRA_ARGS}
+
+ # IGC is pretty set in its way where sub projects ought to live, for some it offers
+ # hooks to supply alternatives folders, other are just hardocded with no way to configure
+ # we symlink everything here, since it's less work than trying to convince the cmake
+ # scripts to accept alternative locations.
+ #
+ PATCH_COMMAND ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_llvm/src/external_igc_llvm/ ${BUILD_DIR}/igc/src/llvm-project &&
+ ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_opencl_clang/src/external_igc_opencl_clang/ ${BUILD_DIR}/igc/src/llvm-project/llvm/projects/opencl-clang &&
+ ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_spirv_translator/src/external_igc_spirv_translator/ ${BUILD_DIR}/igc/src/llvm-project/llvm/projects/llvm-spirv &&
+ ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_spirv_tools/src/external_igc_spirv_tools/ ${BUILD_DIR}/igc/src/SPIRV-Tools &&
+ ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_spirv_headers/src/external_igc_spirv_headers/ ${BUILD_DIR}/igc/src/SPIRV-Headers &&
+ ${CMAKE_COMMAND} -E create_symlink ${BUILD_DIR}/igc_vcintrinsics/src/external_igc_vcintrinsics/ ${BUILD_DIR}/igc/src/vc-intrinsics
+ PREFIX ${BUILD_DIR}/igc
+ INSTALL_DIR ${LIBDIR}/igc
+ INSTALL_COMMAND ${CMAKE_COMMAND} --install . --strip
+ CMAKE_GENERATOR ${IGC_GENERATOR}
+)
+
+add_dependencies(
+ external_igc
+ external_igc_vcintrinsics
+ external_igc_llvm
+ external_igc_opencl_clang
+ external_igc_vcintrinsics
+ external_igc_spirv_headers
+ external_igc_spirv_tools
+ external_igc_spirv_translator
+)
+
+if(UNIX AND NOT APPLE)
+ add_dependencies(
+ external_igc
+ external_flex
+ )
+endif()
diff --git a/build_files/build_environment/cmake/ispc.cmake b/build_files/build_environment/cmake/ispc.cmake
index 160088bc16f..c2dbedca55f 100644
--- a/build_files/build_environment/cmake/ispc.cmake
+++ b/build_files/build_environment/cmake/ispc.cmake
@@ -6,6 +6,7 @@ if(WIN32)
-DBISON_EXECUTABLE=${LIBDIR}/flexbison/win_bison.exe
-DM4_EXECUTABLE=${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/m4.exe
-DARM_ENABLED=Off
+ -DPython3_FIND_REGISTRY=NEVER
)
elseif(APPLE)
# Use bison and flex installed via Homebrew.
@@ -27,7 +28,7 @@ elseif(UNIX)
set(ISPC_EXTRA_ARGS_UNIX
-DCMAKE_C_COMPILER=${LIBDIR}/llvm/bin/clang
-DCMAKE_CXX_COMPILER=${LIBDIR}/llvm/bin/clang++
- -DARM_ENABLED=Off
+ -DARM_ENABLED=${BLENDER_PLATFORM_ARM}
-DFLEX_EXECUTABLE=${LIBDIR}/flex/bin/flex
)
endif()
@@ -43,6 +44,8 @@ set(ISPC_EXTRA_ARGS
-DISPC_INCLUDE_TESTS=Off
-DCLANG_LIBRARY_DIR=${LIBDIR}/llvm/lib
-DCLANG_INCLUDE_DIRS=${LIBDIR}/llvm/include
+ -DPython3_ROOT_DIR=${LIBDIR}/python/
+ -DPython3_EXECUTABLE=${PYTHON_BINARY}
${ISPC_EXTRA_ARGS_WIN}
${ISPC_EXTRA_ARGS_APPLE}
${ISPC_EXTRA_ARGS_UNIX}
@@ -61,6 +64,7 @@ ExternalProject_Add(external_ispc
add_dependencies(
external_ispc
ll
+ external_python
)
if(WIN32)
diff --git a/build_files/build_environment/cmake/llvm.cmake b/build_files/build_environment/cmake/llvm.cmake
index cf92a5175a3..e4ddc7db846 100644
--- a/build_files/build_environment/cmake/llvm.cmake
+++ b/build_files/build_environment/cmake/llvm.cmake
@@ -25,11 +25,14 @@ set(LLVM_EXTRA_ARGS
-DLLVM_BUILD_LLVM_C_DYLIB=OFF
-DLLVM_ENABLE_UNWIND_TABLES=OFF
-DLLVM_ENABLE_PROJECTS=clang${LLVM_BUILD_CLANG_TOOLS_EXTRA}
+ -DPython3_ROOT_DIR=${LIBDIR}/python/
+ -DPython3_EXECUTABLE=${PYTHON_BINARY}
${LLVM_XML2_ARGS}
)
if(WIN32)
set(LLVM_GENERATOR "Ninja")
+ list(APPEND LLVM_EXTRA_ARGS -DPython3_FIND_REGISTRY=NEVER)
else()
set(LLVM_GENERATOR "Unix Makefiles")
endif()
@@ -74,3 +77,8 @@ if(APPLE)
external_xml2
)
endif()
+
+add_dependencies(
+ ll
+ external_python
+)
diff --git a/build_files/build_environment/cmake/macros.cmake b/build_files/build_environment/cmake/macros.cmake
new file mode 100644
index 00000000000..82fc151a038
--- /dev/null
+++ b/build_files/build_environment/cmake/macros.cmake
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# shorthand to only unpack a certain dependency
+macro(unpack_only name)
+ string(TOUPPER ${name} UPPER_NAME)
+ set(TARGET_FILE ${${UPPER_NAME}_FILE})
+ set(TARGET_HASH_TYPE ${${UPPER_NAME}_HASH_TYPE})
+ set(TARGET_HASH ${${UPPER_NAME}_HASH})
+ ExternalProject_Add(external_${name}
+ URL file://${PACKAGE_DIR}/${TARGET_FILE}
+ URL_HASH ${TARGET_HASH_TYPE}=${TARGET_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/${name}
+ CONFIGURE_COMMAND echo .
+ BUILD_COMMAND echo .
+ INSTALL_COMMAND echo .
+ )
+endmacro()
diff --git a/build_files/build_environment/cmake/ocloc.cmake b/build_files/build_environment/cmake/ocloc.cmake
new file mode 100644
index 00000000000..f686d2dd4fc
--- /dev/null
+++ b/build_files/build_environment/cmake/ocloc.cmake
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(OCLOC_EXTRA_ARGS
+ -DNEO_SKIP_UNIT_TESTS=1
+ -DNEO_BUILD_WITH_OCL=0
+ -DBUILD_WITH_L0=0
+ -DIGC_DIR=${LIBDIR}/igc
+ -DGMM_DIR=${LIBDIR}/gmmlib
+)
+
+ExternalProject_Add(external_ocloc
+ URL file://${PACKAGE_DIR}/${OCLOC_FILE}
+ URL_HASH ${OCLOC_HASH_TYPE}=${OCLOC_HASH}
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ PREFIX ${BUILD_DIR}/ocloc
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ocloc ${DEFAULT_CMAKE_FLAGS} ${OCLOC_EXTRA_ARGS}
+ INSTALL_DIR ${LIBDIR}/ocloc
+)
+
+add_dependencies(
+ external_ocloc
+ external_igc
+ external_gmmlib
+)
diff --git a/build_files/build_environment/cmake/openimagedenoise.cmake b/build_files/build_environment/cmake/openimagedenoise.cmake
index 3612e91a690..14a730d69b6 100644
--- a/build_files/build_environment/cmake/openimagedenoise.cmake
+++ b/build_files/build_environment/cmake/openimagedenoise.cmake
@@ -9,6 +9,7 @@ set(OIDN_EXTRA_ARGS
-DOIDN_STATIC_RUNTIME=OFF
-DISPC_EXECUTABLE=${LIBDIR}/ispc/bin/ispc
-DOIDN_FILTER_RTLIGHTMAP=OFF
+ -DPYTHON_EXECUTABLE=${PYTHON_BINARY}
)
if(WIN32)
@@ -38,6 +39,7 @@ add_dependencies(
external_openimagedenoise
external_tbb
external_ispc
+ external_python
)
if(WIN32)
diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake
index 7b9529068f4..9015ef9ac7c 100644
--- a/build_files/build_environment/cmake/options.cmake
+++ b/build_files/build_environment/cmake/options.cmake
@@ -38,6 +38,7 @@ message("BUILD_DIR = ${BUILD_DIR}")
if(WIN32)
set(PATCH_CMD ${DOWNLOAD_DIR}/mingw/mingw64/msys/1.0/bin/patch.exe)
set(LIBEXT ".lib")
+ set(SHAREDLIBEXT ".lib")
set(LIBPREFIX "")
# For OIIO and OSL
@@ -96,6 +97,7 @@ if(WIN32)
else()
set(PATCH_CMD patch)
set(LIBEXT ".a")
+ set(SHAREDLIBEXT ".so")
set(LIBPREFIX "lib")
if(APPLE)
diff --git a/build_files/build_environment/cmake/versions.cmake b/build_files/build_environment/cmake/versions.cmake
index 550be86b6b6..42c82b68654 100644
--- a/build_files/build_environment/cmake/versions.cmake
+++ b/build_files/build_environment/cmake/versions.cmake
@@ -147,7 +147,7 @@ set(OPENIMAGEIO_HASH de45fb38501c4581062b522b53b6141c)
set(OPENIMAGEIO_HASH_TYPE MD5)
set(OPENIMAGEIO_FILE OpenImageIO-${OPENIMAGEIO_VERSION}.tar.gz)
-# 8.0.0 is currently oiio's preferred vesion although never versions may be available.
+# 8.0.0 is currently oiio's preferred version although never versions may be available.
# the preferred version can be found in oiio's externalpackages.cmake
set(FMT_VERSION 8.0.0)
set(FMT_URI https://github.com/fmtlib/fmt/archive/refs/tags/${FMT_VERSION}.tar.gz)
@@ -155,7 +155,7 @@ set(FMT_HASH 7bce0e9e022e586b178b150002e7c2339994e3c2bbe44027e9abb0d60f9cce83)
set(FMT_HASH_TYPE SHA256)
set(FMT_FILE fmt-${FMT_VERSION}.tar.gz)
-# 0.6.2 is currently oiio's preferred vesion although never versions may be available.
+# 0.6.2 is currently oiio's preferred version although never versions may be available.
# the preferred version can be found in oiio's externalpackages.cmake
set(ROBINMAP_VERSION v0.6.2)
set(ROBINMAP_URI https://github.com/Tessil/robin-map/archive/refs/tags/${ROBINMAP_VERSION}.tar.gz)
@@ -410,9 +410,9 @@ set(SQLITE_HASH fb558c49ee21a837713c4f1e7e413309aabdd9c7)
set(SQLITE_HASH_TYPE SHA1)
set(SQLITE_FILE sqlite-src-3240000.zip)
-set(EMBREE_VERSION 3.13.3)
+set(EMBREE_VERSION 3.13.4)
set(EMBREE_URI https://github.com/embree/embree/archive/v${EMBREE_VERSION}.zip)
-set(EMBREE_HASH f62766ba54e48a2f327c3a22596e7133)
+set(EMBREE_HASH 52d0be294d6c88ba7a6c9e046796e7be)
set(EMBREE_HASH_TYPE MD5)
set(EMBREE_FILE embree-v${EMBREE_VERSION}.zip)
@@ -502,3 +502,134 @@ set(LEVEL_ZERO_URI https://github.com/oneapi-src/level-zero/archive/refs/tags/${
set(LEVEL_ZERO_HASH c39bb05a8e5898aa6c444e1704105b93d3f1888b9c333f8e7e73825ffbfb2617)
set(LEVEL_ZERO_HASH_TYPE SHA256)
set(LEVEL_ZERO_FILE level-zero-${LEVEL_ZERO_VERSION}.tar.gz)
+
+set(DPCPP_VERSION 20220620)
+set(DPCPP_URI https://github.com/intel/llvm/archive/refs/tags/sycl-nightly/${DPCPP_VERSION}.tar.gz)
+set(DPCPP_HASH a5f41abd5229d28afa92cbd8a5d8d786ee698bf239f722929fd686276bad692c)
+set(DPCPP_HASH_TYPE SHA256)
+set(DPCPP_FILE DPCPP-${DPCPP_VERSION}.tar.gz)
+
+########################
+### DPCPP DEPS BEGIN ###
+########################
+# The following deps are build time requirements for dpcpp, when possible
+# the source in the dpcpp source tree for the version chosen is documented
+# by each dep, these will only have to be downloaded and unpacked, dpcpp
+# will take care of building them, unpack is being done in dpcpp_deps.cmake
+
+# Source llvm/lib/SYCLLowerIR/CMakeLists.txt
+set(VCINTRINSICS_VERSION 984bb27baacce6ee5c716c2e64845f2a1928025b)
+set(VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/${VCINTRINSICS_VERSION}.tar.gz)
+set(VCINTRINSICS_HASH abea415a15a0dd11fdc94dee8fb462910f2548311b787e02f42509789e1b0d7b)
+set(VCINTRINSICS_HASH_TYPE SHA256)
+set(VCINTRINSICS_FILE vc-intrinsics-${VCINTRINSICS_VERSION}.tar.gz)
+
+# Source opencl/CMakeLists.txt
+set(OPENCLHEADERS_VERSION dcd5bede6859d26833cd85f0d6bbcee7382dc9b3)
+set(OPENCLHEADERS_URI https://github.com/KhronosGroup/OpenCL-Headers/archive/${OPENCLHEADERS_VERSION}.tar.gz)
+set(OPENCLHEADERS_HASH ca8090359654e94f2c41e946b7e9d826253d795ae809ce7c83a7d3c859624693)
+set(OPENCLHEADERS_HASH_TYPE SHA256)
+set(OPENCLHEADERS_FILE opencl_headers-${OPENCLHEADERS_VERSION}.tar.gz)
+
+# Source opencl/CMakeLists.txt
+set(ICDLOADER_VERSION aec3952654832211636fc4af613710f80e203b0a)
+set(ICDLOADER_URI https://github.com/KhronosGroup/OpenCL-ICD-Loader/archive/${ICDLOADER_VERSION}.tar.gz)
+set(ICDLOADER_HASH e1880551d67bd8dc31d13de63b94bbfd6b1f315b6145dad1ffcd159b89bda93c)
+set(ICDLOADER_HASH_TYPE SHA256)
+set(ICDLOADER_FILE icdloader-${ICDLOADER_VERSION}.tar.gz)
+
+# Source sycl/cmake/modules/AddBoostMp11Headers.cmake
+# Using external MP11 here, getting AddBoostMp11Headers.cmake to recognize
+# our copy in boost directly was more trouble than it was worth.
+set(MP11_VERSION 7bc4e1ae9b36ec8ee635c3629b59ec525bbe82b9)
+set(MP11_URI https://github.com/boostorg/mp11/archive/${MP11_VERSION}.tar.gz)
+set(MP11_HASH 071ee2bd3952ec89882edb3af25dd1816f6b61723f66e42eea32f4d02ceef426)
+set(MP11_HASH_TYPE SHA256)
+set(MP11_FILE mp11-${MP11_VERSION}.tar.gz)
+
+# Source llvm-spirv/CMakeLists.txt (repo)
+# Source llvm-spirv/spirv-headers-tag.conf (hash)
+set(SPIRV_HEADERS_VERSION 36c0c1596225e728bd49abb7ef56a3953e7ed468)
+set(SPIRV_HEADERS_URI https://github.com/KhronosGroup/SPIRV-Headers/archive/${SPIRV_HEADERS_VERSION}.tar.gz)
+set(SPIRV_HEADERS_HASH 7a5c89633f8740456fe8adee052033e134476d267411d1336c0cb1e587a9229a)
+set(SPIRV_HEADERS_HASH_TYPE SHA256)
+set(SPIRV_HEADERS_FILE SPIR-V-Headers-${SPIRV_HEADERS_VERSION}.tar.gz)
+
+######################
+### DPCPP DEPS END ###
+######################
+
+##########################################
+### Intel Graphics Compiler DEPS BEGIN ###
+##########################################
+# The following deps are build time requirements for the intel graphics
+# compiler, the versions used are taken from the following location
+# https://github.com/intel/intel-graphics-compiler/releases
+
+set(IGC_VERSION 1.0.11222)
+set(IGC_URI https://github.com/intel/intel-graphics-compiler/archive/refs/tags/igc-${IGC_VERSION}.tar.gz)
+set(IGC_HASH d92f0608dcbb52690855685f9447282e5c09c0ba98ae35fabf114fcf8b1e9fcf)
+set(IGC_HASH_TYPE SHA256)
+set(IGC_FILE igc-${IGC_VERSION}.tar.gz)
+
+set(IGC_LLVM_VERSION llvmorg-11.1.0)
+set(IGC_LLVM_URI https://github.com/llvm/llvm-project/archive/refs/tags/${IGC_LLVM_VERSION}.tar.gz)
+set(IGC_LLVM_HASH 53a0719f3f4b0388013cfffd7b10c7d5682eece1929a9553c722348d1f866e79)
+set(IGC_LLVM_HASH_TYPE SHA256)
+set(IGC_LLVM_FILE ${IGC_LLVM_VERSION}.tar.gz)
+
+# WARNING WARNING WARNING
+#
+# IGC_OPENCL_CLANG contains patches for some of its dependencies.
+#
+# Whenever IGC_OPENCL_CLANG_VERSION changes, one *MUST* inspect
+# IGC_OPENCL_CLANG's patches folder and update igc.cmake to account for
+# any added or removed patches.
+#
+# WARNING WARNING WARNING
+
+set(IGC_OPENCL_CLANG_VERSION bbdd1587f577397a105c900be114b56755d1f7dc)
+set(IGC_OPENCL_CLANG_URI https://github.com/intel/opencl-clang/archive/${IGC_OPENCL_CLANG_VERSION}.tar.gz)
+set(IGC_OPENCL_CLANG_HASH d08315f1b0d8a6fef33de2b3e6aa7356534c324910634962c72523d970773efc)
+set(IGC_OPENCL_CLANG_HASH_TYPE SHA256)
+set(IGC_OPENCL_CLANG_FILE opencl-clang-${IGC_OPENCL_CLANG_VERSION}.tar.gz)
+
+set(IGC_VCINTRINSICS_VERSION v0.4.0)
+set(IGC_VCINTRINSICS_URI https://github.com/intel/vc-intrinsics/archive/refs/tags/${IGC_VCINTRINSICS_VERSION}.tar.gz)
+set(IGC_VCINTRINSICS_HASH c8b92682ad5031cf9d5b82a40e7d5c0e763cd9278660adbcaa69aab988e4b589)
+set(IGC_VCINTRINSICS_HASH_TYPE SHA256)
+set(IGC_VCINTRINSICS_FILE vc-intrinsics-${IGC_VCINTRINSICS_VERSION}.tar.gz)
+
+set(IGC_SPIRV_HEADERS_VERSION sdk-1.3.204.1)
+set(IGC_SPIRV_HEADERS_URI https://github.com/KhronosGroup/SPIRV-Headers/archive/refs/tags/${IGC_SPIRV_HEADERS_VERSION}.tar.gz)
+set(IGC_SPIRV_HEADERS_HASH 262864053968c217d45b24b89044a7736a32361894743dd6cfe788df258c746c)
+set(IGC_SPIRV_HEADERS_HASH_TYPE SHA256)
+set(IGC_SPIRV_HEADERS_FILE SPIR-V-Headers-${IGC_SPIRV_HEADERS_VERSION}.tar.gz)
+
+set(IGC_SPIRV_TOOLS_VERSION sdk-1.3.204.1)
+set(IGC_SPIRV_TOOLS_URI https://github.com/KhronosGroup/SPIRV-Tools/archive/refs/tags/${IGC_SPIRV_TOOLS_VERSION}.tar.gz)
+set(IGC_SPIRV_TOOLS_HASH 6e19900e948944243024aedd0a201baf3854b377b9cc7a386553bc103b087335)
+set(IGC_SPIRV_TOOLS_HASH_TYPE SHA256)
+set(IGC_SPIRV_TOOLS_FILE SPIR-V-Tools-${IGC_SPIRV_TOOLS_VERSION}.tar.gz)
+
+set(IGC_SPIRV_TRANSLATOR_VERSION 99420daab98998a7e36858befac9c5ed109d4920)
+set(IGC_SPIRV_TRANSLATOR_URI https://github.com/KhronosGroup/SPIRV-LLVM-Translator/archive/${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz)
+set(IGC_SPIRV_TRANSLATOR_HASH 77dfb4ddb6bfb993535562c02ddea23f0a0d1c5a0258c1afe7e27c894ff783a8)
+set(IGC_SPIRV_TRANSLATOR_HASH_TYPE SHA256)
+set(IGC_SPIRV_TRANSLATOR_FILE SPIR-V-Translator-${IGC_SPIRV_TRANSLATOR_VERSION}.tar.gz)
+
+########################################
+### Intel Graphics Compiler DEPS END ###
+########################################
+
+set(GMMLIB_VERSION intel-gmmlib-22.1.2)
+set(GMMLIB_URI https://github.com/intel/gmmlib/archive/refs/tags/${GMMLIB_VERSION}.tar.gz)
+set(GMMLIB_HASH 3b9a6d5e7e3f5748b3d0a2fb0e980ae943907fece0980bd9c0508e71c838e334)
+set(GMMLIB_HASH_TYPE SHA256)
+set(GMMLIB_FILE ${GMMLIB_VERSION}.tar.gz)
+
+set(OCLOC_VERSION 22.20.23198)
+set(OCLOC_URI https://github.com/intel/compute-runtime/archive/refs/tags/${OCLOC_VERSION}.tar.gz)
+set(OCLOC_HASH ab22b8bf2560a57fdd3def0e35a62ca75991406f959c0263abb00cd6cd9ae998)
+set(OCLOC_HASH_TYPE SHA256)
+set(OCLOC_FILE ocloc-${OCLOC_VERSION}.tar.gz)
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 58702f69609..2441b9ad89b 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -36,19 +36,19 @@ getopt \
-o s:i:t:h \
--long source:,install:,tmp:,info:,threads:,help,show-deps,no-sudo,no-build,no-confirm,\
with-all,with-opencollada,with-jack,with-pulseaudio,with-embree,with-oidn,with-nanovdb,\
-ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,ver-xr-openxr:,\
+ver-ocio:,ver-oiio:,ver-llvm:,ver-osl:,ver-osd:,ver-openvdb:,ver-xr-openxr:,ver-level-zero:\
force-all,force-python,force-boost,force-tbb,\
force-ocio,force-imath,force-openexr,force-oiio,force-llvm,force-osl,force-osd,force-openvdb,\
force-ffmpeg,force-opencollada,force-alembic,force-embree,force-oidn,force-usd,\
-force-xr-openxr,\
+force-xr-openxr,force-level-zero,\
build-all,build-python,build-boost,build-tbb,\
build-ocio,build-imath,build-openexr,build-oiio,build-llvm,build-osl,build-osd,build-openvdb,\
build-ffmpeg,build-opencollada,build-alembic,build-embree,build-oidn,build-usd,\
-build-xr-openxr,\
+build-xr-openxr,build-level-zero,\
skip-python,skip-boost,skip-tbb,\
skip-ocio,skip-imath,skip-openexr,skip-oiio,skip-llvm,skip-osl,skip-osd,skip-openvdb,\
skip-ffmpeg,skip-opencollada,skip-alembic,skip-embree,skip-oidn,skip-usd,\
-skip-xr-openxr \
+skip-xr-openxr,skip-level-zero \
-- "$@" \
)
@@ -165,6 +165,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--ver-xr-openxr=<ver>
Force version of OpenXR-SDK.
+ --ver-level-zero=<ver>
+ Force version of OneAPI Level Zero library.
+
Note about the --ver-foo options:
It may not always work as expected (some libs are actually checked out from a git rev...), yet it might help
to fix some build issues (like LLVM mismatch with the version used by your graphic system).
@@ -226,6 +229,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--build-xr-openxr
Force the build of OpenXR-SDK.
+ --build-level-zero=<ver>
+ Force the build of OneAPI Level Zero library.
+
Note about the --build-foo options:
* They force the script to prefer building dependencies rather than using available packages.
This may make things simpler and allow working around some distribution bugs, but on the other hand it will
@@ -293,6 +299,9 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
--force-xr-openxr
Force the rebuild of OpenXR-SDK.
+ --force-level-zero=<ver>
+ Force the rebuild of OneAPI Level Zero library.
+
Note about the --force-foo options:
* They obviously only have an effect if those libraries are built by this script
(i.e. if there is no available and satisfactory package)!
@@ -351,7 +360,10 @@ ARGUMENTS_INFO="\"COMMAND LINE ARGUMENTS:
Unconditionally skip Universal Scene Description installation/building.
--skip-xr-openxr
- Unconditionally skip OpenXR-SDK installation/building.\""
+ Unconditionally skip OpenXR-SDK installation/building.
+
+ --skip-level-zero=<ver>
+ Unconditionally skip OneAPI Level Zero installation/building.\""
# ----------------------------------------------------------------------------
# Main Vars
@@ -453,7 +465,7 @@ TBB_VERSION="2020"
TBB_VERSION_SHORT="2020"
TBB_VERSION_UPDATE="_U3" # Used for source packages...
TBB_VERSION_MIN="2018"
-TBB_VERSION_MEX="2022"
+TBB_VERSION_MEX="2021" # 2021 introduces 'oneTBB', which has lots of compatibility breakage with previous versions
TBB_FORCE_BUILD=false
TBB_FORCE_REBUILD=false
TBB_SKIP=false
@@ -555,7 +567,7 @@ OPENCOLLADA_FORCE_BUILD=false
OPENCOLLADA_FORCE_REBUILD=false
OPENCOLLADA_SKIP=false
-EMBREE_VERSION="3.13.3"
+EMBREE_VERSION="3.13.4"
EMBREE_VERSION_SHORT="3.13"
EMBREE_VERSION_MIN="3.13"
EMBREE_VERSION_MEX="4.0"
@@ -573,14 +585,13 @@ OIDN_SKIP=false
ISPC_VERSION="1.17.0"
-FFMPEG_VERSION="4.4"
-FFMPEG_VERSION_SHORT="4.4"
-FFMPEG_VERSION_MIN="3.0"
-FFMPEG_VERSION_MEX="5.0"
-FFMPEG_FORCE_BUILD=false
-FFMPEG_FORCE_REBUILD=false
-FFMPEG_SKIP=false
-_ffmpeg_list_sep=";"
+LEVEL_ZERO_VERSION="1.7.15"
+LEVEL_ZERO_VERSION_SHORT="1.7"
+LEVEL_ZERO_VERSION_MIN="1.7"
+LEVEL_ZERO_VERSION_MEX="2.0"
+LEVEL_ZERO_FORCE_BUILD=false
+LEVEL_ZERO_FORCE_REBUILD=false
+LEVEL_ZERO_SKIP=false
XR_OPENXR_VERSION="1.0.22"
XR_OPENXR_VERSION_SHORT="1.0"
@@ -590,6 +601,15 @@ XR_OPENXR_FORCE_BUILD=false
XR_OPENXR_FORCE_REBUILD=false
XR_OPENXR_SKIP=false
+FFMPEG_VERSION="5.0"
+FFMPEG_VERSION_SHORT="5.0"
+FFMPEG_VERSION_MIN="4.0"
+FFMPEG_VERSION_MEX="6.0"
+FFMPEG_FORCE_BUILD=false
+FFMPEG_FORCE_REBUILD=false
+FFMPEG_SKIP=false
+_ffmpeg_list_sep=";"
+
# FFMPEG optional libs.
VORBIS_USE=false
VORBIS_DEV=""
@@ -615,9 +635,6 @@ MP3LAME_DEV=""
OPENJPEG_USE=false
OPENJPEG_DEV=""
-# Whether to use system GLEW or not (OpenSubDiv needs recent glew to work).
-NO_SYSTEM_GLEW=false
-
# Switch to english language, else some things (like check_package_DEB()) won't work!
LANG_BACK=$LANG
LANG=""
@@ -781,6 +798,12 @@ while true; do
XR_OPENXR_VERSION_SHORT=$XR_OPENXR_VERSION
shift; shift; continue
;;
+ --ver-level-zero)
+ LEVEL_ZERO_VERSION="$2"
+ LEVEL_ZERO_VERSION_MIN=$LEVEL_ZERO_VERSION
+ LEVEL_ZERO_VERSION_SHORT=$LEVEL_ZERO_VERSION
+ shift; shift; continue
+ ;;
--build-all)
PYTHON_FORCE_BUILD=true
BOOST_FORCE_BUILD=true
@@ -800,6 +823,7 @@ while true; do
ALEMBIC_FORCE_BUILD=true
USD_FORCE_BUILD=true
XR_OPENXR_FORCE_BUILD=true
+ LEVEL_ZERO_FORCE_BUILD=true
shift; continue
;;
--build-python)
@@ -857,6 +881,9 @@ while true; do
--build-xr-openxr)
XR_OPENXR_FORCE_BUILD=true; shift; continue
;;
+ --build-level-zero)
+ LEVEL_ZERO_FORCE_BUILD=true; shift; continue
+ ;;
--force-all)
PYTHON_FORCE_REBUILD=true
BOOST_FORCE_REBUILD=true
@@ -876,6 +903,7 @@ while true; do
ALEMBIC_FORCE_REBUILD=true
USD_FORCE_REBUILD=true
XR_OPENXR_FORCE_REBUILD=true
+ LEVEL_ZERO_FORCE_REBUILD=true
shift; continue
;;
--force-python)
@@ -933,6 +961,9 @@ while true; do
--force-xr-openxr)
XR_OPENXR_FORCE_REBUILD=true; shift; continue
;;
+ --force-level-zero)
+ LEVEL_ZERO_FORCE_REBUILD=true; shift; continue
+ ;;
--skip-python)
PYTHON_SKIP=true; shift; continue
;;
@@ -987,6 +1018,9 @@ while true; do
--skip-xr-openxr)
XR_OPENXR_SKIP=true; shift; continue
;;
+ --skip-level-zero)
+ LEVEL_ZERO_SKIP=true; shift; continue
+ ;;
--)
# no more arguments to parse
break
@@ -1128,14 +1162,16 @@ OIDN_SOURCE=( "https://github.com/OpenImageDenoise/oidn/releases/download/v${OID
ISPC_BINARY=( "https://github.com/ispc/ispc/releases/download/v${ISPC_VERSION}/ispc-v${ISPC_VERSION}-linux.tar.gz" )
-FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
-
XR_OPENXR_USE_REPO=false
XR_OPENXR_SOURCE=("https://github.com/KhronosGroup/OpenXR-SDK/archive/release-${XR_OPENXR_VERSION}.tar.gz")
XR_OPENXR_SOURCE_REPO=("https://github.com/KhronosGroup/OpenXR-SDK.git")
XR_OPENXR_REPO_UID="458984d7f59d1ae6dc1b597d94b02e4f7132eaba"
XR_OPENXR_REPO_BRANCH="master"
+LEVEL_ZERO_SOURCE=("https://github.com/oneapi-src/level-zero/archive/refs/tags/v${LEVEL_ZERO_VERSION}.tar.gz")
+
+FFMPEG_SOURCE=( "http://ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.bz2" )
+
# C++11 is required now
CXXFLAGS_BACK=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -std=c++11"
@@ -1154,7 +1190,7 @@ Those libraries should be available as packages in all recent distributions (opt
* libx11, libxcursor, libxi, libxrandr, libxinerama (and other libx... as needed).
* libwayland-client0, libwayland-cursor0, libwayland-egl1, libxkbcommon0, libdbus-1-3, libegl1 (Wayland)
* libsqlite3, libzstd, libbz2, libssl, libfftw3, libxml2, libtinyxml, yasm, libyaml-cpp, flex.
- * libsdl2, libglew, libpugixml, libpotrace, [libgmp], [libglewmx], fontconfig, [libharu/libhpdf].\""
+ * libsdl2, libglew, libpugixml, libpotrace, [libgmp], fontconfig, [libharu/libhpdf].\""
DEPS_SPECIFIC_INFO="\"BUILDABLE DEPENDENCIES:
@@ -1187,7 +1223,8 @@ You may also want to build them yourself (optional ones are [between brackets]):
* [OpenImageDenoise $OIDN_VERSION] (from $OIDN_SOURCE).
* [Alembic $ALEMBIC_VERSION] (from $ALEMBIC_SOURCE).
* [Universal Scene Description $USD_VERSION] (from $USD_SOURCE).
- * [OpenXR-SDK $XR_OPENXR_VERSION] (from $XR_OPENXR_SOURCE).\""
+ * [OpenXR-SDK $XR_OPENXR_VERSION] (from $XR_OPENXR_SOURCE).
+ * [OneAPI Level Zero $LEVEL_ZERO_VERSION] (from $LEVEL_ZERO_SOURCE).\""
if [ "$DO_SHOW_DEPS" = true ]; then
PRINT ""
@@ -1647,7 +1684,7 @@ compile_TBB() {
fi
# To be changed each time we make edits that would modify the compiled result!
- tbb_magic=0
+ tbb_magic=1
_init_tbb
# Force having own builds for the dependencies.
@@ -2656,14 +2693,13 @@ compile_OSD() {
mkdir build
cd build
+ cmake_d="-D CMAKE_BUILD_TYPE=Release"
if [ -d $INST/tbb ]; then
- cmake_d="$cmake_d $cmake_d -D TBB_LOCATION=$INST/tbb"
+ cmake_d="$cmake_d -D TBB_LOCATION=$INST/tbb"
fi
- cmake_d="-D CMAKE_BUILD_TYPE=Release"
cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
- # ptex is only needed when nicholas bishop is ready
cmake_d="$cmake_d -D NO_PTEX=1"
- cmake_d="$cmake_d -D NO_CLEW=1 -D NO_CUDA=1 -D NO_OPENCL=1"
+ cmake_d="$cmake_d -D NO_CLEW=1 -D NO_CUDA=1 -D NO_OPENCL=1 -D NO_GLEW=1"
# maya plugin, docs, tutorials, regression tests and examples are not needed
cmake_d="$cmake_d -D NO_MAYA=1 -D NO_DOC=1 -D NO_TUTORIALS=1 -D NO_REGRESSION=1 -DNO_EXAMPLES=1"
@@ -3286,7 +3322,7 @@ compile_Embree() {
fi
# To be changed each time we make edits that would modify the compiled results!
- embree_magic=10
+ embree_magic=11
_init_embree
# Force having own builds for the dependencies.
@@ -3346,7 +3382,7 @@ compile_Embree() {
cmake_d="$cmake_d -D EMBREE_TASKING_SYSTEM=TBB"
if [ -d $INST/tbb ]; then
- make_d="$make_d EMBREE_TBB_ROOT=$INST/tbb"
+ cmake_d="$cmake_d -D EMBREE_TBB_ROOT=$INST/tbb"
fi
cmake $cmake_d ../
@@ -3485,7 +3521,7 @@ compile_OIDN() {
install_ISPC
# To be changed each time we make edits that would modify the compiled results!
- oidn_magic=9
+ oidn_magic=10
_init_oidn
# Force having own builds for the dependencies.
@@ -3541,7 +3577,7 @@ compile_OIDN() {
cmake_d="$cmake_d -D ISPC_DIR_HINT=$_ispc_path_bin"
if [ -d $INST/tbb ]; then
- make_d="$make_d TBB_ROOT=$INST/tbb"
+ cmake_d="$cmake_d -D TBB_ROOT=$INST/tbb"
fi
cmake $cmake_d ../
@@ -3823,6 +3859,103 @@ compile_XR_OpenXR_SDK() {
# ----------------------------------------------------------------------------
+# Build OneAPI Level Zero library.
+
+_init_level_zero() {
+ _src=$SRC/level-zero-$LEVEL_ZERO_VERSION
+ _git=false
+ _inst=$INST/level-zero-$LEVEL_ZERO_VERSION_SHORT
+ _inst_shortcut=$INST/level-zero
+}
+
+_update_deps_level_zero() {
+ :
+}
+
+clean_Level_Zero() {
+ _init_level_zero
+ if [ -d $_inst ]; then
+ # Force rebuilding the dependencies if needed.
+ _update_deps_level_zero false true
+ fi
+ _clean
+}
+
+compile_Level_Zero() {
+ if [ "$NO_BUILD" = true ]; then
+ WARNING "--no-build enabled, Level Zero will not be compiled!"
+ return
+ fi
+
+ # To be changed each time we make edits that would modify the compiled result!
+ level_zero_magic=1
+ _init_level_zero
+
+ # Force having own builds for the dependencies.
+ _update_deps_level_zero true false
+
+ # Clean install if needed!
+ magic_compile_check level-zero-$LEVEL_ZERO_VERSION $level_zero_magic
+ if [ $? -eq 1 -o "$LEVEL_ZERO_FORCE_REBUILD" = true ]; then
+ clean_Level_Zero
+ fi
+
+ if [ ! -d $_inst ]; then
+ INFO "Building Level-Zero-$LEVEL_ZERO_VERSION"
+
+ # Force rebuilding the dependencies.
+ _update_deps_level_zero true true
+
+ prepare_inst
+
+ if [ ! -d $_src ]; then
+ mkdir -p $SRC
+
+ download LEVEL_ZERO_SOURCE[@] "$_src.tar.gz"
+ INFO "Unpacking Level-Zero-$LEVEL_ZERO_VERSION"
+ tar -C $SRC -xf $_src.tar.gz
+ fi
+
+ cd $_src
+
+ # Always refresh the whole build!
+ if [ -d build ]; then
+ rm -rf build
+ fi
+ mkdir build
+ cd build
+
+ # Keep flags in sync with LEVEL_ZERO_EXTRA_ARGS in level-zero.cmake!
+ cmake_d="-D CMAKE_BUILD_TYPE=Release"
+ cmake_d="$cmake_d -D CMAKE_INSTALL_PREFIX=$_inst"
+
+ cmake $cmake_d ..
+
+ make -j$THREADS && make install
+ make clean
+
+ if [ ! -d $_inst ]; then
+ ERROR "Level-Zero-$LEVEL_ZERO_VERSION failed to compile, exiting"
+ exit 1
+ fi
+
+ magic_compile_set level-zero-$LEVEL_ZERO_VERSION $level_zero_magic
+
+ cd $CWD
+ INFO "Done compiling Level-Zero-$LEVEL_ZERO_VERSION!"
+ else
+ INFO "Own Level-Zero-$LEVEL_ZERO_VERSION is up to date, nothing to do!"
+ INFO "If you want to force rebuild of this lib, use the --force-level-zero option."
+ fi
+
+ if [ -d $_inst ]; then
+ _create_inst_shortcut
+ fi
+ run_ldconfig "level-zero"
+}
+
+
+# ----------------------------------------------------------------------------
# Install on DEB-like
get_package_version_DEB() {
@@ -3925,7 +4058,6 @@ install_DEB() {
libopenal-dev libglew-dev yasm \
libsdl2-dev libfftw3-dev patch bzip2 libxml2-dev libtinyxml-dev libjemalloc-dev \
libgmp-dev libpugixml-dev libpotrace-dev libhpdf-dev libzstd-dev libpystring-dev"
- # libglewmx-dev (broken in deb testing currently...)
VORBIS_USE=true
OGG_USE=true
@@ -4034,7 +4166,7 @@ install_DEB() {
fi
fi
- # Check cmake/glew versions and disable features for older distros.
+ # Check cmake version and disable features for older distros.
# This is so Blender can at least compile.
PRINT ""
_cmake=`get_package_version_DEB cmake`
@@ -4052,28 +4184,6 @@ install_DEB() {
fi
PRINT ""
- _glew=`get_package_version_DEB libglew-dev`
- if [ -z $_glew ]; then
- # Stupid virtual package in Ubuntu 12.04 doesn't show version number...
- _glew=`apt-cache showpkg libglew-dev|tail -n1|awk '{print $2}'|sed 's/-.*//'`
- fi
- version_ge $_glew "1.9.0"
- if [ $? -eq 1 ]; then
- version_ge $_glew "1.7.0"
- if [ $? -eq 1 ]; then
- WARNING "OpenSubdiv disabled because GLEW-$_glew is not enough"
- WARNING "Blender will not use system GLEW library"
- OSD_SKIP=true
- NO_SYSTEM_GLEW=true
- else
- WARNING "OpenSubdiv will compile with GLEW-$_glew but with limited capability"
- WARNING "Blender will not use system GLEW library"
- NO_SYSTEM_GLEW=true
- fi
- fi
-
-
- PRINT ""
_do_compile_python=false
if [ "$PYTHON_SKIP" = true ]; then
WARNING "Skipping Python installation, as requested..."
@@ -4458,6 +4568,18 @@ install_DEB() {
PRINT ""
compile_XR_OpenXR_SDK
fi
+
+ PRINT ""
+ if [ "$LEVEL_ZERO_SKIP" = true ]; then
+ WARNING "Skipping Level Zero installation, as requested..."
+ elif [ "$LEVEL_ZERO_FORCE_BUILD" = true ]; then
+ INFO "Forced Level Zero building, as requested..."
+ compile_Level_Zero
+ else
+ # No package currently!
+ PRINT ""
+ compile_Level_Zero
+ fi
}
@@ -5144,6 +5266,18 @@ install_RPM() {
# No package currently!
compile_XR_OpenXR_SDK
fi
+
+ PRINT ""
+ if [ "$LEVEL_ZERO_SKIP" = true ]; then
+ WARNING "Skipping Level Zero installation, as requested..."
+ elif [ "$LEVEL_ZERO_FORCE_BUILD" = true ]; then
+ INFO "Forced Level Zero building, as requested..."
+ compile_Level_Zero
+ else
+ # No package currently!
+ PRINT ""
+ compile_Level_Zero
+ fi
}
@@ -5721,6 +5855,18 @@ install_ARCH() {
# No package currently!
compile_XR_OpenXR_SDK
fi
+
+ PRINT ""
+ if [ "$LEVEL_ZERO_SKIP" = true ]; then
+ WARNING "Skipping Level Zero installation, as requested..."
+ elif [ "$LEVEL_ZERO_FORCE_BUILD" = true ]; then
+ INFO "Forced Level Zero building, as requested..."
+ compile_Level_Zero
+ else
+ # No package currently!
+ PRINT ""
+ compile_Level_Zero
+ fi
}
@@ -5895,6 +6041,14 @@ install_OTHER() {
INFO "Forced OpenXR-SDK building, as requested..."
compile_XR_OpenXR_SDK
fi
+
+ PRINT ""
+ if [ "$LEVEL_ZERO_SKIP" = true ]; then
+ WARNING "Skipping Level Zero installation, as requested..."
+ elif [ "$LEVEL_ZERO_FORCE_BUILD" = true ]; then
+ INFO "Forced Level Zero building, as requested..."
+ compile_Level_Zero
+ fi
}
# ----------------------------------------------------------------------------
@@ -6109,12 +6263,6 @@ print_info() {
fi
fi
- if [ "$NO_SYSTEM_GLEW" = true ]; then
- _1="-D WITH_SYSTEM_GLEW=OFF"
- PRINT " $_1"
- _buildargs="$_buildargs $_1"
- fi
-
if [ "$FFMPEG_SKIP" = false ]; then
_1="-D WITH_CODEC_FFMPEG=ON"
PRINT " $_1"
@@ -6137,6 +6285,18 @@ print_info() {
fi
fi
+ # Not yet available in Blender.
+ #~ if [ "$LEVEL_ZERO_SKIP" = false ]; then
+ #~ _1="-D WITH_LEVEL_ZERO=ON"
+ #~ PRINT " $_1"
+ #~ _buildargs="$_buildargs $_1"
+ #~ if [ -d $INST/level-zero ]; then
+ #~ _1="-D LEVEL_ZERO_ROOT_DIR=$INST/level-zero"
+ #~ PRINT " $_1"
+ #~ _buildargs="$_buildargs $_1"
+ #~ fi
+ #~ fi
+
PRINT ""
PRINT "Or even simpler, just run (in your blender-source dir):"
PRINT " make -j$THREADS BUILD_CMAKE_ARGS=\"$_buildargs\""
diff --git a/build_files/build_environment/patches/dpcpp.diff b/build_files/build_environment/patches/dpcpp.diff
new file mode 100644
index 00000000000..9dbe032de0c
--- /dev/null
+++ b/build_files/build_environment/patches/dpcpp.diff
@@ -0,0 +1,54 @@
+diff -Naur external_dpcpp.orig/sycl/source/CMakeLists.txt external_dpcpp/sycl/source/CMakeLists.txt
+--- external_dpcpp.orig/sycl/source/CMakeLists.txt 2022-05-20 04:19:45.067771362 +0000
++++ external_dpcpp/sycl/source/CMakeLists.txt 2022-05-20 04:21:49.708025048 +0000
+@@ -66,10 +66,10 @@
+ target_compile_options(${LIB_OBJ_NAME} PUBLIC
+ -fvisibility=hidden -fvisibility-inlines-hidden)
+ set(linker_script "${CMAKE_CURRENT_SOURCE_DIR}/ld-version-script.txt")
+- set(abi_linker_script "${CMAKE_CURRENT_SOURCE_DIR}/abi_replacements_linux.txt")
+- target_link_libraries(
+- ${LIB_NAME} PRIVATE "-Wl,${abi_linker_script}")
+- set_target_properties(${LIB_NAME} PROPERTIES LINK_DEPENDS ${abi_linker_script})
++# set(abi_linker_script "${CMAKE_CURRENT_SOURCE_DIR}/abi_replacements_linux.txt")
++# target_link_libraries(
++# ${LIB_NAME} PRIVATE "-Wl,${abi_linker_script}")
++# set_target_properties(${LIB_NAME} PROPERTIES LINK_DEPENDS ${abi_linker_script})
+ target_link_libraries(
+ ${LIB_NAME} PRIVATE "-Wl,--version-script=${linker_script}")
+ set_target_properties(${LIB_NAME} PROPERTIES LINK_DEPENDS ${linker_script})
+diff -Naur llvm-sycl-nightly-20220501.orig\opencl/CMakeLists.txt llvm-sycl-nightly-20220501\opencl/CMakeLists.txt
+--- llvm-sycl-nightly-20220501.orig/opencl/CMakeLists.txt 2022-04-29 13:47:11 -0600
++++ llvm-sycl-nightly-20220501/opencl/CMakeLists.txt 2022-05-21 15:25:06 -0600
+@@ -11,6 +11,11 @@
+ )
+ endif()
+
++# Blender code below is determined to use FetchContent_Declare
++# temporarily allow it (but feed it our downloaded tarball
++# in the OpenCL_HEADERS variable
++set(FETCHCONTENT_FULLY_DISCONNECTED OFF)
++
+ # Repo URLs
+
+ set(OCL_HEADERS_REPO
+@@ -77,5 +82,6 @@
+
+ FetchContent_MakeAvailable(ocl-icd)
+ add_library(OpenCL-ICD ALIAS OpenCL)
++set(FETCHCONTENT_FULLY_DISCONNECTED ON)
+
+ add_subdirectory(opencl-aot)
+diff -Naur llvm-sycl-nightly-20220208.orig/libdevice/cmake/modules/SYCLLibdevice.cmake llvm-sycl-nightly-20220208/libdevice/cmake/modules/SYCLLibdevice.cmake
+--- llvm-sycl-nightly-20220208.orig/libdevice/cmake/modules/SYCLLibdevice.cmake 2022-02-08 09:17:24 -0700
++++ llvm-sycl-nightly-20220208/libdevice/cmake/modules/SYCLLibdevice.cmake 2022-05-24 11:35:51 -0600
+@@ -36,7 +36,9 @@
+ add_custom_target(libsycldevice-obj)
+ add_custom_target(libsycldevice-spv)
+
+-add_custom_target(libsycldevice DEPENDS
++# Blender: add ALL here otherwise this target will not build
++# and cause an error due to missing files during the install phase.
++add_custom_target(libsycldevice ALL DEPENDS
+ libsycldevice-obj
+ libsycldevice-spv)
+
diff --git a/build_files/build_environment/patches/embree.diff b/build_files/build_environment/patches/embree.diff
index e83d754a465..e448fe5ee2e 100644
--- a/build_files/build_environment/patches/embree.diff
+++ b/build_files/build_environment/patches/embree.diff
@@ -1,30 +1,37 @@
-diff -Naur orig/common/sys/platform.h external_embree/common/sys/platform.h
---- orig/common/sys/platform.h 2020-05-13 23:08:53 -0600
-+++ external_embree/common/sys/platform.h 2020-06-13 17:40:26 -0600
-@@ -84,8 +84,8 @@
- ////////////////////////////////////////////////////////////////////////////////
+diff -Naur org/kernels/rtcore_config.h.in embree-3.13.4/kernels/rtcore_config.h.in
+--- org/kernels/rtcore_config.h.in 2022-06-14 22:13:52 -0600
++++ embree-3.13.4/kernels/rtcore_config.h.in 2022-06-24 15:20:12 -0600
+@@ -14,6 +14,7 @@
+ #cmakedefine01 EMBREE_MIN_WIDTH
+ #define RTC_MIN_WIDTH EMBREE_MIN_WIDTH
+
++#cmakedefine EMBREE_STATIC_LIB
+ #cmakedefine EMBREE_API_NAMESPACE
+
+ #if defined(EMBREE_API_NAMESPACE)
+diff --git a/kernels/CMakeLists.txt b/kernels/CMakeLists.txt
+index 7c2f43d..106b1d5 100644
+--- a/kernels/CMakeLists.txt
++++ b/kernels/CMakeLists.txt
+@@ -201,6 +201,12 @@ embree_files(EMBREE_LIBRARY_FILES_AVX512 ${AVX512})
+ #message("AVX2: ${EMBREE_LIBRARY_FILES_AVX2}")
+ #message("AVX512: ${EMBREE_LIBRARY_FILES_AVX512}")
- #ifdef __WIN32__
--#define dll_export __declspec(dllexport)
--#define dll_import __declspec(dllimport)
-+#define dll_export
-+#define dll_import
- #else
- #define dll_export __attribute__ ((visibility ("default")))
- #define dll_import
-diff --git orig/common/tasking/CMakeLists.txt external_embree/common/tasking/CMakeLists.txt
---- orig/common/tasking/CMakeLists.txt
-+++ external_embree/common/tasking/CMakeLists.txt
-@@ -27,7 +27,11 @@
- else()
- # If not found try getting older TBB via module (FindTBB.cmake)
- unset(TBB_DIR CACHE)
-- find_package(TBB 4.1 REQUIRED tbb)
-+ if (TBB_STATIC_LIB)
-+ find_package(TBB 4.1 REQUIRED tbb_static)
-+ else()
-+ find_package(TBB 4.1 REQUIRED tbb)
-+ endif()
- if (TBB_FOUND)
- TARGET_LINK_LIBRARIES(tasking PUBLIC TBB)
- TARGET_INCLUDE_DIRECTORIES(tasking PUBLIC "${TBB_INCLUDE_DIRS}")
++# Bundle Neon2x into the main static library.
++IF(EMBREE_ISA_NEON2X AND EMBREE_STATIC_LIB)
++ LIST(APPEND EMBREE_LIBRARY_FILES ${EMBREE_LIBRARY_FILES_AVX2})
++ LIST(REMOVE_DUPLICATES EMBREE_LIBRARY_FILES)
++ENDIF()
++
+ # replaces all .cpp files with a dummy file that includes that .cpp file
+ # this is to work around an ICC name mangling issue related to lambda functions under windows
+ MACRO (CreateISADummyFiles list isa)
+@@ -277,7 +283,7 @@ IF (EMBREE_ISA_AVX AND EMBREE_LIBRARY_FILES_AVX)
+ ENDIF()
+ ENDIF()
+
+-IF (EMBREE_ISA_AVX2 AND EMBREE_LIBRARY_FILES_AVX2)
++IF (EMBREE_ISA_AVX2 AND EMBREE_LIBRARY_FILES_AVX2 AND NOT (EMBREE_ISA_NEON2X AND EMBREE_STATIC_LIB))
+ DISABLE_STACK_PROTECTOR_FOR_INTERSECTORS(${EMBREE_LIBRARY_FILES_AVX2})
+ ADD_LIBRARY(embree_avx2 STATIC ${EMBREE_LIBRARY_FILES_AVX2})
+ TARGET_LINK_LIBRARIES(embree_avx2 PRIVATE tasking)
diff --git a/build_files/build_environment/patches/flex.diff b/build_files/build_environment/patches/flex.diff
new file mode 100644
index 00000000000..d3f9e8b0a66
--- /dev/null
+++ b/build_files/build_environment/patches/flex.diff
@@ -0,0 +1,15 @@
+diff --git a/configure.ac b/configure.ac
+index c6f12d644..3c977a4e3 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -25,8 +25,10 @@
+ # autoconf requirements and initialization
+
+ AC_INIT([the fast lexical analyser generator],[2.6.4],[flex-help@lists.sourceforge.net],[flex])
++AC_PREREQ([2.60])
+ AC_CONFIG_SRCDIR([src/scan.l])
+ AC_CONFIG_AUX_DIR([build-aux])
++AC_USE_SYSTEM_EXTENSIONS
+ LT_INIT
+ AM_INIT_AUTOMAKE([1.15 -Wno-portability foreign std-options dist-lzip parallel-tests subdir-objects])
+ AC_CONFIG_HEADER([src/config.h])
diff --git a/build_files/build_environment/patches/igc_opencl_clang.diff b/build_files/build_environment/patches/igc_opencl_clang.diff
new file mode 100644
index 00000000000..adc592dd8b2
--- /dev/null
+++ b/build_files/build_environment/patches/igc_opencl_clang.diff
@@ -0,0 +1,44 @@
+diff -Naur external_igc_opencl_clang.orig/CMakeLists.txt external_igc_opencl_clang/CMakeLists.txt
+--- external_igc_opencl_clang.orig/CMakeLists.txt 2022-03-16 05:51:10 -0600
++++ external_igc_opencl_clang/CMakeLists.txt 2022-05-23 10:40:09 -0600
+@@ -126,22 +126,24 @@
+ )
+ endif()
+
+-
+- set(SPIRV_BASE_REVISION llvm_release_110)
+- set(TARGET_BRANCH "ocl-open-110")
+- get_filename_component(LLVM_MONOREPO_DIR ${LLVM_SOURCE_DIR} DIRECTORY)
+- set(LLVM_PATCHES_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm
+- ${CMAKE_CURRENT_SOURCE_DIR}/patches/clang)
+- apply_patches(${LLVM_MONOREPO_DIR}
+- "${LLVM_PATCHES_DIRS}"
+- ${LLVM_BASE_REVISION}
+- ${TARGET_BRANCH}
+- ret)
+- apply_patches(${SPIRV_SOURCE_DIR}
+- ${CMAKE_CURRENT_SOURCE_DIR}/patches/spirv
+- ${SPIRV_BASE_REVISION}
+- ${TARGET_BRANCH}
+- ret)
++ #
++ # Blender: Why apply these manually in igc.cmake
++ #
++ #set(SPIRV_BASE_REVISION llvm_release_110)
++ #set(TARGET_BRANCH "ocl-open-110")
++ #get_filename_component(LLVM_MONOREPO_DIR ${LLVM_SOURCE_DIR} DIRECTORY)
++ #set(LLVM_PATCHES_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/patches/llvm
++ # ${CMAKE_CURRENT_SOURCE_DIR}/patches/clang)
++ #apply_patches(${LLVM_MONOREPO_DIR}
++ # "${LLVM_PATCHES_DIRS}"
++ # ${LLVM_BASE_REVISION}
++ # ${TARGET_BRANCH}
++ # ret)
++ #apply_patches(${SPIRV_SOURCE_DIR}
++ # ${CMAKE_CURRENT_SOURCE_DIR}/patches/spirv
++ # ${SPIRV_BASE_REVISION}
++ # ${TARGET_BRANCH}
++ # ret)
+ endif(NOT USE_PREBUILT_LLVM)
+
+ #
diff --git a/build_files/build_environment/windows/build_deps.cmd b/build_files/build_environment/windows/build_deps.cmd
index d836a6a3a50..d3879f3d6ae 100644
--- a/build_files/build_environment/windows/build_deps.cmd
+++ b/build_files/build_environment/windows/build_deps.cmd
@@ -48,10 +48,13 @@ if "%4" == "nobuild" set dobuild=0
REM If Python is be available certain deps may try to
REM to use this over the version we build, to prevent that
-REM make sure python is NOT in the path
-for %%X in (python.exe) do (set PYTHON=%%~$PATH:X)
-if EXIST "%PYTHON%" (
- echo PYTHON found at %PYTHON% dependencies cannot be build with python available in the path
+REM make sure pythonw is NOT in the path. We look for pythonw.exe
+REM since windows apparently ships a python.exe that just opens up
+REM the windows store but does not ship any actual python files that
+REM could cause issues.
+for %%X in (pythonw.exe) do (set PYTHONW=%%~$PATH:X)
+if EXIST "%PYTHONW%" (
+ echo PYTHON found at %PYTHONW% dependencies cannot be build with python available in the path
goto exit
)
diff --git a/build_files/cmake/Modules/FindLevelZero.cmake b/build_files/cmake/Modules/FindLevelZero.cmake
new file mode 100644
index 00000000000..a60d8ba9978
--- /dev/null
+++ b/build_files/cmake/Modules/FindLevelZero.cmake
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2021-2022 Intel Corporation
+
+# - Find Level Zero library
+# Find Level Zero headers and libraries needed by oneAPI implementation
+# This module defines
+# LEVEL_ZERO_LIBRARY, libraries to link against in order to use L0.
+# LEVEL_ZERO_INCLUDE_DIR, directories where L0 headers can be found.
+# LEVEL_ZERO_ROOT_DIR, The base directory to search for L0 files.
+# This can also be an environment variable.
+# LEVEL_ZERO_FOUND, If false, then don't try to use L0.
+
+IF(NOT LEVEL_ZERO_ROOT_DIR AND NOT $ENV{LEVEL_ZERO_ROOT_DIR} STREQUAL "")
+ SET(LEVEL_ZERO_ROOT_DIR $ENV{LEVEL_ZERO_ROOT_DIR})
+ENDIF()
+
+SET(_level_zero_search_dirs
+ ${LEVEL_ZERO_ROOT_DIR}
+ /usr/lib
+ /usr/local/lib
+)
+
+FIND_LIBRARY(_LEVEL_ZERO_LIBRARY
+ NAMES
+ ze_loader
+ HINTS
+ ${_level_zero_search_dirs}
+ PATH_SUFFIXES
+ lib64 lib
+)
+
+FIND_PATH(_LEVEL_ZERO_INCLUDE_DIR
+ NAMES
+ level_zero/ze_api.h
+ HINTS
+ ${_level_zero_search_dirs}
+ PATH_SUFFIXES
+ include
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LevelZero DEFAULT_MSG _LEVEL_ZERO_LIBRARY _LEVEL_ZERO_INCLUDE_DIR)
+
+IF(LevelZero_FOUND)
+ SET(LEVEL_ZERO_LIBRARY ${_LEVEL_ZERO_LIBRARY})
+ SET(LEVEL_ZERO_INCLUDE_DIR ${_LEVEL_ZERO_INCLUDE_DIR} ${_LEVEL_ZERO_INCLUDE_PARENT_DIR})
+ SET(LEVEL_ZERO_FOUND TRUE)
+ELSE()
+ SET(LEVEL_ZERO_FOUND FALSE)
+ENDIF()
+
+MARK_AS_ADVANCED(
+ LEVEL_ZERO_LIBRARY
+ LEVEL_ZERO_INCLUDE_DIR
+)
diff --git a/build_files/cmake/Modules/FindPythonLibsUnix.cmake b/build_files/cmake/Modules/FindPythonLibsUnix.cmake
index 46e8a492972..1e88621303f 100644
--- a/build_files/cmake/Modules/FindPythonLibsUnix.cmake
+++ b/build_files/cmake/Modules/FindPythonLibsUnix.cmake
@@ -175,7 +175,9 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibsUnix DEFAULT_MSG
IF(PYTHONLIBSUNIX_FOUND)
# Assign cache items
SET(PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIR} ${PYTHON_INCLUDE_CONFIG_DIR})
- SET(PYTHON_LIBRARIES ${PYTHON_LIBRARY})
+ IF(NOT WITH_PYTHON_MODULE)
+ SET(PYTHON_LIBRARIES ${PYTHON_LIBRARY})
+ ENDIF()
FIND_FILE(PYTHON_SITE_PACKAGES
NAMES
diff --git a/build_files/cmake/Modules/FindSYCL.cmake b/build_files/cmake/Modules/FindSYCL.cmake
new file mode 100644
index 00000000000..ac90cbfbe43
--- /dev/null
+++ b/build_files/cmake/Modules/FindSYCL.cmake
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2021-2022 Intel Corporation
+
+# - Find SYCL library
+# Find the native SYCL header and libraries needed by oneAPI implementation
+# This module defines
+# SYCL_COMPILER, compiler which will be used for compilation of SYCL code
+# SYCL_LIBRARY, libraries to link against in order to use SYCL.
+# SYCL_INCLUDE_DIR, directories where SYCL headers can be found
+# SYCL_ROOT_DIR, The base directory to search for SYCL files.
+# This can also be an environment variable.
+# SYCL_FOUND, If false, then don't try to use SYCL.
+
+IF(NOT SYCL_ROOT_DIR AND NOT $ENV{SYCL_ROOT_DIR} STREQUAL "")
+ SET(SYCL_ROOT_DIR $ENV{SYCL_ROOT_DIR})
+ENDIF()
+
+SET(_sycl_search_dirs
+ ${SYCL_ROOT_DIR}
+ /usr/lib
+ /usr/local/lib
+ /opt/intel/oneapi/compiler/latest/linux/
+ C:/Program\ Files\ \(x86\)/Intel/oneAPI/compiler/latest/windows
+)
+
+# Find DPC++ compiler.
+# Since the compiler name is possibly conflicting with the system-wide
+# CLang start with looking for either dpcpp or clang binary in the given
+# list of search paths only. If that fails, try to look for a system-wide
+# dpcpp binary.
+FIND_PROGRAM(SYCL_COMPILER
+ NAMES
+ dpcpp
+ clang++
+ HINTS
+ ${_sycl_search_dirs}
+ PATH_SUFFIXES
+ bin
+ NO_CMAKE_FIND_ROOT_PATH
+ NAMES_PER_DIR
+)
+
+# NOTE: No clang++ here so that we do not pick up a system-wide CLang
+# compiler.
+if(NOT SYCL_COMPILER)
+ FIND_PROGRAM(SYCL_COMPILER
+ NAMES
+ dpcpp
+ HINTS
+ ${_sycl_search_dirs}
+ PATH_SUFFIXES
+ bin
+ )
+endif()
+
+FIND_LIBRARY(SYCL_LIBRARY
+ NAMES
+ sycl
+ HINTS
+ ${_sycl_search_dirs}
+ PATH_SUFFIXES
+ lib64 lib
+)
+
+FIND_PATH(SYCL_INCLUDE_DIR
+ NAMES
+ CL/sycl.hpp
+ HINTS
+ ${_sycl_search_dirs}
+ PATH_SUFFIXES
+ include
+ include/sycl
+)
+
+INCLUDE(FindPackageHandleStandardArgs)
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SYCL DEFAULT_MSG SYCL_LIBRARY SYCL_INCLUDE_DIR)
+
+IF(SYCL_FOUND)
+ get_filename_component(_SYCL_INCLUDE_PARENT_DIR ${SYCL_INCLUDE_DIR} DIRECTORY)
+ SET(SYCL_INCLUDE_DIR ${SYCL_INCLUDE_DIR} ${_SYCL_INCLUDE_PARENT_DIR})
+ELSE()
+ SET(SYCL_SYCL_FOUND FALSE)
+ENDIF()
+
+MARK_AS_ADVANCED(
+ _SYCL_INCLUDE_PARENT_DIR
+)
diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py
index e3fc9fd86ac..1abef605480 100755
--- a/build_files/cmake/cmake_netbeans_project.py
+++ b/build_files/cmake/cmake_netbeans_project.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Example linux usage
python3 ~/blender-git/blender/build_files/cmake/cmake_netbeans_project.py ~/blender-git/cmake
diff --git a/build_files/cmake/cmake_qtcreator_project.py b/build_files/cmake/cmake_qtcreator_project.py
index 395d24370da..45957e35817 100755
--- a/build_files/cmake/cmake_qtcreator_project.py
+++ b/build_files/cmake/cmake_qtcreator_project.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
r"""
Example Linux usage:
python ~/blender-git/blender/build_files/cmake/cmake_qtcreator_project.py --build-dir ~/blender-git/cmake
diff --git a/build_files/cmake/cmake_static_check_clang_array.py b/build_files/cmake/cmake_static_check_clang_array.py
index d98ab3d58e2..d3b6b971e05 100644
--- a/build_files/cmake/cmake_static_check_clang_array.py
+++ b/build_files/cmake/cmake_static_check_clang_array.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import project_source_info
import subprocess
import sys
diff --git a/build_files/cmake/cmake_static_check_cppcheck.py b/build_files/cmake/cmake_static_check_cppcheck.py
index 75c5ac79ff5..79f9498ce2e 100644
--- a/build_files/cmake/cmake_static_check_cppcheck.py
+++ b/build_files/cmake/cmake_static_check_cppcheck.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import project_source_info
import subprocess
import sys
diff --git a/build_files/cmake/cmake_static_check_smatch.py b/build_files/cmake/cmake_static_check_smatch.py
index b7c2e7817c6..63d8b524231 100644
--- a/build_files/cmake/cmake_static_check_smatch.py
+++ b/build_files/cmake/cmake_static_check_smatch.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
diff --git a/build_files/cmake/cmake_static_check_sparse.py b/build_files/cmake/cmake_static_check_sparse.py
index 51204e4de2e..35641f5f8d1 100644
--- a/build_files/cmake/cmake_static_check_sparse.py
+++ b/build_files/cmake/cmake_static_check_sparse.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
diff --git a/build_files/cmake/cmake_static_check_splint.py b/build_files/cmake/cmake_static_check_splint.py
index 3ee3617e7a8..238377e58cf 100644
--- a/build_files/cmake/cmake_static_check_splint.py
+++ b/build_files/cmake/cmake_static_check_splint.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
CHECKER_IGNORE_PREFIX = [
"extern",
"intern/moto",
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 2f6057ee9c0..5ce344d39e8 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -37,6 +37,9 @@ set(WITH_IMAGE_TIFF OFF CACHE BOOL "" FORCE)
set(WITH_IMAGE_WEBP OFF CACHE BOOL "" FORCE)
set(WITH_INPUT_NDOF OFF CACHE BOOL "" FORCE)
set(WITH_INTERNATIONAL OFF CACHE BOOL "" FORCE)
+set(WITH_IO_STL OFF CACHE BOOL "" FORCE)
+set(WITH_IO_WAVEFRONT_OBJ OFF CACHE BOOL "" FORCE)
+set(WITH_IO_GPENCIL OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_LIBMV OFF CACHE BOOL "" FORCE)
set(WITH_LLVM OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index 8ece5eec39e..b4609426069 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -70,7 +70,7 @@ if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
endif()
if(WIN32)
- set(WITH_WASAPI ON CACHE BOOL "" FORCE)
+ set(WITH_WASAPI ON CACHE BOOL "" FORCE)
endif()
if(UNIX AND NOT APPLE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
@@ -78,6 +78,11 @@ if(UNIX AND NOT APPLE)
set(WITH_PULSEAUDIO ON CACHE BOOL "" FORCE)
set(WITH_X11_XINPUT ON CACHE BOOL "" FORCE)
set(WITH_X11_XF86VMODE ON CACHE BOOL "" FORCE)
+
+ # Disable oneAPI on Linux for the time being.
+ # The AoT compilation takes too long to be used officially in the buildbot CI/CD and the JIT
+ # compilation has ABI compatibility issues when running builds made on centOS on Ubuntu.
+ set(WITH_CYCLES_DEVICE_ONEAPI OFF CACHE BOOL "" FORCE)
endif()
if(NOT APPLE)
set(WITH_XR_OPENXR ON CACHE BOOL "" FORCE)
@@ -86,4 +91,8 @@ if(NOT APPLE)
set(WITH_CYCLES_CUDA_BINARIES ON CACHE BOOL "" FORCE)
set(WITH_CYCLES_CUBIN_COMPILER OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_HIP_BINARIES ON CACHE BOOL "" FORCE)
+ set(WITH_CYCLES_DEVICE_ONEAPI ON CACHE BOOL "" FORCE)
+
+ # Disable AoT kernels compilations until buildbot can deliver them in a reasonabel time.
+ set(WITH_CYCLES_ONEAPI_BINARIES OFF CACHE BOOL "" FORCE)
endif()
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 6750c23d548..4b654420531 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -38,9 +38,15 @@ if(EXISTS ${LIBDIR})
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
file(GLOB LIB_SUBDIRS ${LIBDIR}/*)
+
# Ignore Mesa software OpenGL libraries, they are not intended to be
# linked against but to optionally override at runtime.
list(REMOVE_ITEM LIB_SUBDIRS ${LIBDIR}/mesa)
+
+ # Ignore DPC++ as it contains its own copy of LLVM/CLang which we do
+ # not need to be ever discovered for the Blender linking.
+ list(REMOVE_ITEM LIB_SUBDIRS ${LIBDIR}/dpcpp)
+
# NOTE: Make sure "proper" compiled zlib comes first before the one
# which is a part of OpenCollada. They have different ABI, and we
# do need to use the official one.
@@ -271,6 +277,18 @@ if(WITH_CYCLES AND WITH_CYCLES_OSL)
endif()
endif()
+if(WITH_CYCLES_DEVICE_ONEAPI)
+ set(CYCLES_LEVEL_ZERO ${LIBDIR}/level-zero CACHE PATH "Path to Level Zero installation")
+ if(EXISTS ${CYCLES_LEVEL_ZERO} AND NOT LEVEL_ZERO_ROOT_DIR)
+ set(LEVEL_ZERO_ROOT_DIR ${CYCLES_LEVEL_ZERO})
+ endif()
+
+ set(CYCLES_SYCL ${LIBDIR}/dpcpp CACHE PATH "Path to DPC++ and SYCL installation")
+ if(EXISTS ${CYCLES_SYCL} AND NOT SYCL_ROOT_DIR)
+ set(SYCL_ROOT_DIR ${CYCLES_SYCL})
+ endif()
+endif()
+
if(WITH_OPENVDB)
find_package_wrapper(OpenVDB)
find_package_wrapper(Blosc)
@@ -613,17 +631,42 @@ if(WITH_GHOST_WAYLAND)
pkg_check_modules(wayland-scanner REQUIRED wayland-scanner)
pkg_check_modules(xkbcommon REQUIRED xkbcommon)
pkg_check_modules(wayland-cursor REQUIRED wayland-cursor)
- pkg_check_modules(dbus REQUIRED dbus-1)
- set(WITH_GL_EGL ON)
+ if(WITH_GHOST_WAYLAND_DBUS)
+ pkg_check_modules(dbus REQUIRED dbus-1)
+ endif()
+
+ if(WITH_GHOST_WAYLAND_LIBDECOR)
+ pkg_check_modules(libdecor REQUIRED libdecor-0>=0.1)
+ endif()
list(APPEND PLATFORM_LINKLIBS
- ${wayland-client_LINK_LIBRARIES}
- ${wayland-egl_LINK_LIBRARIES}
${xkbcommon_LINK_LIBRARIES}
- ${wayland-cursor_LINK_LIBRARIES}
- ${dbus_LINK_LIBRARIES}
)
+
+ if(NOT WITH_GHOST_WAYLAND_DYNLOAD)
+ list(APPEND PLATFORM_LINKLIBS
+ ${wayland-client_LINK_LIBRARIES}
+ ${wayland-egl_LINK_LIBRARIES}
+ ${wayland-cursor_LINK_LIBRARIES}
+ )
+ endif()
+
+ if(WITH_GHOST_WAYLAND_DBUS)
+ list(APPEND PLATFORM_LINKLIBS
+ ${dbus_LINK_LIBRARIES}
+ )
+ add_definitions(-DWITH_GHOST_WAYLAND_DBUS)
+ endif()
+
+ if(WITH_GHOST_WAYLAND_LIBDECOR)
+ if(NOT WITH_GHOST_WAYLAND_DYNLOAD)
+ list(APPEND PLATFORM_LINKLIBS
+ ${libdecor_LIBRARIES}
+ )
+ endif()
+ add_definitions(-DWITH_GHOST_WAYLAND_LIBDECOR)
+ endif()
endif()
if(WITH_GHOST_X11)
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index 40c25abd585..7e272ea26b0 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -950,3 +950,6 @@ endif()
set(ZSTD_INCLUDE_DIRS ${LIBDIR}/zstd/include)
set(ZSTD_LIBRARIES ${LIBDIR}/zstd/lib/zstd_static.lib)
+
+set(LEVEL_ZERO_ROOT_DIR ${LIBDIR}/level_zero)
+set(SYCL_ROOT_DIR ${LIBDIR}/dpcpp)
diff --git a/build_files/cmake/project_info.py b/build_files/cmake/project_info.py
index 0661db3a18c..12f92235b2a 100755
--- a/build_files/cmake/project_info.py
+++ b/build_files/cmake/project_info.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Module for accessing project file data for Blender.
diff --git a/build_files/cmake/project_source_info.py b/build_files/cmake/project_source_info.py
index 7a00f756e03..a544f5733f0 100644
--- a/build_files/cmake/project_source_info.py
+++ b/build_files/cmake/project_source_info.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"build_info",
"SOURCE_DIR",
diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml
index 8222f2ff0b9..82cd009ea95 100644
--- a/build_files/config/pipeline_config.yaml
+++ b/build_files/config/pipeline_config.yaml
@@ -54,6 +54,8 @@ buildbot:
version: '10.1.243'
cuda11:
version: '11.4.1'
+ hip:
+ version: '5.2.21440'
optix:
version: '7.3.0'
cmake:
diff --git a/build_files/package_spec/build_archive.py b/build_files/package_spec/build_archive.py
index 06d11aef0e3..df7399942f3 100755
--- a/build_files/package_spec/build_archive.py
+++ b/build_files/package_spec/build_archive.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import shutil
import subprocess
diff --git a/doc/manpage/blender.1.py b/doc/manpage/blender.1.py
index 6cf2f54b26f..7d35dc0abb1 100755
--- a/doc/manpage/blender.1.py
+++ b/doc/manpage/blender.1.py
@@ -11,8 +11,6 @@ where <path-to-blender> is the path to the Blender executable,
and <output-filename> is where to write the generated man page.
'''
-# <pep8 compliant>
-
import argparse
import os
import subprocess
diff --git a/doc/python_api/requirements.txt b/doc/python_api/requirements.txt
index 51440046430..f93947c9d2d 100644
--- a/doc/python_api/requirements.txt
+++ b/doc/python_api/requirements.txt
@@ -1,12 +1,12 @@
-sphinx==4.1.1
+sphinx==5.0.1
# Sphinx dependencies that are important
-Jinja2==3.0.1
-Pygments==2.10.0
+Jinja2==3.1.2
+Pygments==2.12.0
docutils==0.17.1
-snowballstemmer==2.1.0
-babel==2.9.1
-requests==2.26.0
+snowballstemmer==2.2.0
+babel==2.10.1
+requests==2.27.1
# Only needed to match the theme used for the official documentation.
# Without this theme, the default theme will be used.
diff --git a/doc/python_api/rst/info_best_practice.rst b/doc/python_api/rst/info_best_practice.rst
index e88adcc0d70..6342680e149 100644
--- a/doc/python_api/rst/info_best_practice.rst
+++ b/doc/python_api/rst/info_best_practice.rst
@@ -40,15 +40,6 @@ As well as pep8 we have additional conventions used for Blender Python scripts:
- pep8 also defines that lines should not exceed 79 characters,
we have decided that this is too restrictive so it is optional per script.
-Periodically we run checks for pep8 compliance on Blender scripts,
-for scripts to be included in this check add this line as a comment at the top of the script:
-
-``# <pep8 compliant>``
-
-To enable line length checks use this instead:
-
-``# <pep8-80 compliant>``
-
User Interface Layout
=====================
diff --git a/doc/python_api/rst_from_bmesh_opdefines.py b/doc/python_api/rst_from_bmesh_opdefines.py
index c97b05b96b3..3d8ff1e6248 100644
--- a/doc/python_api/rst_from_bmesh_opdefines.py
+++ b/doc/python_api/rst_from_bmesh_opdefines.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This is a quite stupid script which extracts bmesh api docs from
# 'bmesh_opdefines.c' in order to avoid having to add a lot of introspection
# data access into the api.
diff --git a/doc/python_api/sphinx_changelog_gen.py b/doc/python_api/sphinx_changelog_gen.py
index 6c06178d603..4c9f7232a74 100644
--- a/doc/python_api/sphinx_changelog_gen.py
+++ b/doc/python_api/sphinx_changelog_gen.py
@@ -1,61 +1,111 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
-Dump the python API into a text file so we can generate changelogs.
+---------------
-output from this tool should be added into "doc/python_api/rst/change_log.rst"
+Dump the python API into a JSON file, or generate changelogs from those JSON API dumps.
-# dump api blender_version.py in CWD
-blender --background --python doc/python_api/sphinx_changelog_gen.py -- --dump
+Typically, changelog output from this tool should be added into "doc/python_api/rst/change_log.rst"
-# create changelog
-blender --background --factory-startup --python doc/python_api/sphinx_changelog_gen.py -- \
- --api_from blender_2_63_0.py \
- --api_to blender_2_64_0.py \
- --api_out changes.rst
+API dump files are saved together with the generated API doc on the server, with a general index file.
+This way the changelog generation simply needs to re-download the previous version's dump for the diffing process.
+---------------
-# Api comparison can also run without blender
+# Dump api blender_version.json in CWD:
+blender --background --factory-startup --python doc/python_api/sphinx_changelog_gen.py -- \
+ --indexpath="path/to/api/docs/api_dump_index.json" \
+ dump --filepath-out="path/to/api/docs/<version>/api_dump.json"
+
+# Create changelog:
+blender --background --factory-startup --python doc/python_api/sphinx_changelog_gen.py -- \
+ --indexpath="path/to/api/docs/api_dump_index.json" \
+ changelog --filepath-out doc/python_api/rst/change_log.rst
+
+# Api comparison can also run without blender,
+# will by default generate changeloig between the last two available versions listed in the index,
+# unless input files are provided explicitely:
python doc/python_api/sphinx_changelog_gen.py -- \
- --api_from blender_api_2_63_0.py \
- --api_to blender_api_2_64_0.py \
- --api_out changes.rst
+ --indexpath="path/to/api/docs/api_dump_index.json" \
+ changelog --filepath-in-from blender_api_2_63_0.json \
+ --filepath-in-to blender_api_2_64_0.json \
+ --filepath-out changes.rst
-# Save the latest API dump in this folder, renaming it with its revision.
-# This way the next person updating it doesn't need to build an old Blender only for that
+--------------
-"""
+API dump index format:
-# format
-'''
-{"module.name":
- {"parent.class":
- {"basic_type", "member_name":
- ("Name", type, range, length, default, descr, f_args, f_arg_types, f_ret_types)}, ...
- }, ...
+{[version_main, version_sub]: "<version>/api_dump.json", ...
}
-'''
-api_names = "basic_type" "name", "type", "range", "length", "default", "descr", "f_args", "f_arg_types", "f_ret_types"
+API dump format:
+[
+ [version_main, vserion_sub, version_path],
+ {"module.name":
+ {"parent.class":
+ {"basic_type", "member_name":
+ ["Name", type, range, length, default, descr, f_args, f_arg_types, f_ret_types]}, ...
+ }, ...
+ }
+]
+
+"""
+
+import json
+import os
+
+
+api_names = "basic_type" "name", "type", "range", "length", "default", "descr", "f_args", "f_arg_types", "f_ret_types"
API_BASIC_TYPE = 0
API_F_ARGS = 7
-def api_dunp_fname():
- import bpy
- return "blender_api_%s.py" % "_".join([str(i) for i in bpy.app.version])
+def api_version():
+ try:
+ import bpy
+ except:
+ return None, None
+ version = tuple(bpy.app.version[:2])
+ version_key = "%d.%d" % (version[0], version[1])
+ return version, version_key
+
+
+def api_version_previous_in_index(index, version):
+ print("Searching for previous version to %s in %r" % (version, index))
+ version_prev = (version[0], version[1])
+ while True:
+ version_prev = (version_prev[0], version_prev[1] - 1)
+ if version_prev[1] < 0:
+ version_prev = (version_prev[0] - 1, 99)
+ if version_prev[0] < 0:
+ return None, None
+ version_prev_key = "%d.%d" % (version_prev[0], version_prev[1])
+ if version_prev_key in index:
+ print("Found previous version %s: %r" % (version_prev, index[version_prev_key]))
+ return version_prev, version_prev_key
+
+
+class JSONEncoderAPIDump(json.JSONEncoder):
+ def default(self, o):
+ if o is ...:
+ return "..."
+ if isinstance(o, set):
+ return tuple(o)
+ return json.JSONEncoder.default(self, o)
+
+
+def api_dump(args):
+ import rna_info
+ import inspect
+ version, version_key = api_version()
+ if version is None:
+ raise(ValueError("API dumps can only be generated from within Blender."))
-def api_dump():
dump = {}
dump_module = dump["bpy.types"] = {}
- import rna_info
- import inspect
-
struct = rna_info.BuildRNAInfo()[0]
for struct_id, struct_info in sorted(struct.items()):
@@ -157,17 +207,25 @@ def api_dump():
)
del funcs
- import pprint
+ filepath_out = args.filepath_out
+ with open(filepath_out, 'w', encoding='utf-8') as file_handle:
+ json.dump((version, dump), file_handle, cls=JSONEncoderAPIDump)
- filename = api_dunp_fname()
- filehandle = open(filename, 'w', encoding='utf-8')
- tot = filehandle.write(pprint.pformat(dump, width=1))
- filehandle.close()
- print("%s, %d bytes written" % (filename, tot))
+ indexpath = args.indexpath
+ rootpath = os.path.dirname(indexpath)
+ if os.path.exists(indexpath):
+ with open(indexpath, 'r', encoding='utf-8') as file_handle:
+ index = json.load(file_handle)
+ else:
+ index = {}
+ index[version_key] = os.path.relpath(filepath_out, rootpath)
+ with open(indexpath, 'w', encoding='utf-8') as file_handle:
+ json.dump(index, file_handle)
+ print("API version %s dumped into %r, and index %r has been updated" % (version_key, filepath_out, indexpath))
-def compare_props(a, b, fuzz=0.75):
+def compare_props(a, b, fuzz=0.75):
# must be same basic_type, function != property
if a[0] != b[0]:
return False
@@ -182,15 +240,44 @@ def compare_props(a, b, fuzz=0.75):
return ((tot / totlen) >= fuzz)
-def api_changelog(api_from, api_to, api_out):
+def api_changelog(args):
+ indexpath = args.indexpath
+ filepath_in_from = args.filepath_in_from
+ filepath_in_to = args.filepath_in_to
+ filepath_out = args.filepath_out
+
+ rootpath = os.path.dirname(indexpath)
+
+ version, version_key = api_version()
+ if version is None and (filepath_in_from is None or filepath_in_to is None):
+ raise(ValueError("API dumps files must be given when ran outside of Blender."))
+
+ with open(indexpath, 'r', encoding='utf-8') as file_handle:
+ index = json.load(file_handle)
+
+ if filepath_in_to is None:
+ filepath_in_to = index.get(version_key, None)
+ if filepath_in_to is None:
+ raise(ValueError("Cannot find API dump file for Blender version " + str(version) + " in index file."))
- file_handle = open(api_from, 'r', encoding='utf-8')
- dict_from = eval(file_handle.read())
- file_handle.close()
+ print("Found to file: %r" % filepath_in_to)
- file_handle = open(api_to, 'r', encoding='utf-8')
- dict_to = eval(file_handle.read())
- file_handle.close()
+ if filepath_in_from is None:
+ version_from, version_from_key = api_version_previous_in_index(index, version)
+ if version_from is None:
+ raise(ValueError("No previous version of Blender could be found in the index."))
+ filepath_in_from = index.get(version_from_key, None)
+ if filepath_in_from is None:
+ raise(ValueError("Cannot find API dump file for previous Blender version " + str(version_from) + " in index file."))
+
+ print("Found from file: %r" % filepath_in_from)
+
+ with open(os.path.join(rootpath, filepath_in_from), 'r', encoding='utf-8') as file_handle:
+ _, dict_from = json.load(file_handle)
+
+ with open(os.path.join(rootpath, filepath_in_to), 'r', encoding='utf-8') as file_handle:
+ dump_version, dict_to = json.load(file_handle)
+ assert(tuple(dump_version) == version)
api_changes = []
@@ -251,63 +338,66 @@ def api_changelog(api_from, api_to, api_out):
# also document function argument changes
- fout = open(api_out, 'w', encoding='utf-8')
- fw = fout.write
- # print(api_changes)
-
- # :class:`bpy_struct.id_data`
-
- def write_title(title, title_char):
- fw("%s\n%s\n\n" % (title, title_char * len(title)))
-
- for mod_id, class_id, props_moved, props_new, props_old, func_args in api_changes:
- class_name = class_id.split(".")[-1]
- title = mod_id + "." + class_name
- write_title(title, "-")
-
- if props_new:
- write_title("Added", "^")
- for prop_id in props_new:
- fw("* :class:`%s.%s.%s`\n" % (mod_id, class_name, prop_id))
- fw("\n")
-
- if props_old:
- write_title("Removed", "^")
- for prop_id in props_old:
- fw("* **%s**\n" % prop_id) # can't link to removed docs
- fw("\n")
-
- if props_moved:
- write_title("Renamed", "^")
- for prop_id_old, prop_id in props_moved:
- fw("* **%s** -> :class:`%s.%s.%s`\n" % (prop_id_old, mod_id, class_name, prop_id))
- fw("\n")
-
- if func_args:
- write_title("Function Arguments", "^")
- for func_id, args_old, args_new in func_args:
- args_new = ", ".join(args_new)
- args_old = ", ".join(args_old)
- fw("* :class:`%s.%s.%s` (%s), *was (%s)*\n" % (mod_id, class_name, func_id, args_new, args_old))
- fw("\n")
-
- fout.close()
-
- print("Written: %r" % api_out)
-
-
-def main():
+ with open(filepath_out, 'w', encoding='utf-8') as fout:
+ fw = fout.write
+
+ # Write header.
+ fw(""
+ ":tocdepth: 2\n"
+ "\n"
+ "Blender API Change Log\n"
+ "**********************\n"
+ "\n"
+ ".. note, this document is auto generated by sphinx_changelog_gen.py\n"
+ "\n"
+ "\n"
+ "%s to %s\n"
+ "============\n"
+ "\n" % (version_from_key, version_key))
+
+ def write_title(title, title_char):
+ fw("%s\n%s\n\n" % (title, title_char * len(title)))
+
+ for mod_id, class_id, props_moved, props_new, props_old, func_args in api_changes:
+ class_name = class_id.split(".")[-1]
+ title = mod_id + "." + class_name
+ write_title(title, "-")
+
+ if props_new:
+ write_title("Added", "^")
+ for prop_id in props_new:
+ fw("* :class:`%s.%s.%s`\n" % (mod_id, class_name, prop_id))
+ fw("\n")
+
+ if props_old:
+ write_title("Removed", "^")
+ for prop_id in props_old:
+ fw("* **%s**\n" % prop_id) # can't link to removed docs
+ fw("\n")
+
+ if props_moved:
+ write_title("Renamed", "^")
+ for prop_id_old, prop_id in props_moved:
+ fw("* **%s** -> :class:`%s.%s.%s`\n" % (prop_id_old, mod_id, class_name, prop_id))
+ fw("\n")
+
+ if func_args:
+ write_title("Function Arguments", "^")
+ for func_id, args_old, args_new in func_args:
+ args_new = ", ".join(args_new)
+ args_old = ", ".join(args_old)
+ fw("* :class:`%s.%s.%s` (%s), *was (%s)*\n" % (mod_id, class_name, func_id, args_new, args_old))
+ fw("\n")
+
+ print("Written: %r" % filepath_out)
+
+
+def main(argv=None):
import sys
- import os
-
- try:
- import argparse
- except ImportError:
- print("Old Blender, just dumping")
- api_dump()
- return
+ import argparse
- argv = sys.argv
+ if argv is None:
+ argv = sys.argv
if "--" not in argv:
argv = [] # as if no args are passed
@@ -318,42 +408,42 @@ def main():
usage_text = "Run blender in background mode with this script: "
"blender --background --factory-startup --python %s -- [options]" % os.path.basename(__file__)
- epilog = "Run this before releases"
-
- parser = argparse.ArgumentParser(description=usage_text, epilog=epilog)
-
- parser.add_argument(
- "--dump", dest="dump", action='store_true',
- help="When set the api will be dumped into blender_version.py")
-
+ parser = argparse.ArgumentParser(description=usage_text,
+ epilog=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
- "--api_from", dest="api_from", metavar='FILE',
- help="File to compare from (previous version)")
- parser.add_argument(
- "--api_to", dest="api_to", metavar='FILE',
- help="File to compare from (current)")
- parser.add_argument(
- "--api_out", dest="api_out", metavar='FILE',
- help="Output sphinx changelog")
-
- args = parser.parse_args(argv) # In this example we won't use the args
-
- if not argv:
- print("No args given!")
- parser.print_help()
- return
-
- if args.dump:
- api_dump()
- else:
- if args.api_from and args.api_to and args.api_out:
- api_changelog(args.api_from, args.api_to, args.api_out)
- else:
- print("Error: --api_from/api_to/api_out args needed")
- parser.print_help()
- return
-
- print("batch job finished, exiting")
+ "--indexpath", dest="indexpath", metavar='FILE', required=True,
+ help="Path of the JSON file containing the index of all available API dumps.")
+
+ parser_commands = parser.add_subparsers(required=True)
+
+ parser_dump = parser_commands.add_parser('dump', help="Dump the current Blender Python API into a JSON file.")
+ parser_dump.add_argument(
+ "--filepath-out", dest="filepath_out", metavar='FILE', required=True,
+ help="Path of the JSON file containing the dump of the API.")
+ parser_dump.set_defaults(func=api_dump)
+
+ parser_changelog = parser_commands.add_parser(
+ 'changelog',
+ help="Generate the RST changelog page based on two Blender Python API JSON dumps.",
+ )
+
+ parser_changelog.add_argument(
+ "--filepath-in-from", dest="filepath_in_from", metavar='FILE', default=None,
+ help="JSON dump file to compare from (typically, previous version). "
+ "If not given, will be automatically determined from current Blender version and index file.")
+ parser_changelog.add_argument(
+ "--filepath-in-to", dest="filepath_in_to", metavar='FILE', default=None,
+ help="JSON dump file to compare to (typically, current version). "
+ "If not given, will be automatically determined from current Blender version and index file.")
+ parser_changelog.add_argument(
+ "--filepath-out", dest="filepath_out", metavar='FILE', required=True,
+ help="Output sphinx changelog RST file.")
+ parser_changelog.set_defaults(func=api_changelog)
+
+ args = parser.parse_args(argv)
+
+ args.func(args)
if __name__ == "__main__":
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index b29251b67cc..f5e0369cede 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
API dump in RST files
---------------------
@@ -78,6 +76,27 @@ SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
# See: D6261 for reference.
USE_ONLY_BUILTIN_RNA_TYPES = True
+# Write a page for each static enum defined in:
+# `source/blender/makesrna/RNA_enum_items.h` so the enums can be linked to instead of being expanded everywhere.
+USE_SHARED_RNA_ENUM_ITEMS_STATIC = True
+
+if USE_SHARED_RNA_ENUM_ITEMS_STATIC:
+ from _bpy import rna_enum_items_static
+ rna_enum_dict = rna_enum_items_static()
+ for key in ("DummyRNA_DEFAULT_items", "DummyRNA_NULL_items"):
+ del rna_enum_dict[key]
+ del key, rna_enum_items_static
+
+ # Build enum `{pointer: identifier}` map, so any enum property pointer can
+ # lookup an identifier using `InfoPropertyRNA.enum_pointer` as the key.
+ rna_enum_pointer_to_id_map = {
+ enum_prop.as_pointer(): key
+ for key, enum_items in rna_enum_dict.items()
+ # It's possible the first item is a heading (which has no identifier).
+ # skip these as the `EnumProperty.enum_items` does not expose them.
+ if (enum_prop := next(iter(enum_prop for enum_prop in enum_items if enum_prop.identifier), None))
+ }
+
def handle_args():
"""
@@ -123,6 +142,26 @@ def handle_args():
)
parser.add_argument(
+ "--api-changelog-generate",
+ dest="changelog",
+ default=False,
+ action='store_true',
+ help="Generate the API changelog RST file "
+ "(default=False, requires `--api-dump-index-path` parameter)",
+ required=False,
+ )
+
+ parser.add_argument(
+ "--api-dump-index-path",
+ dest="api_dump_index_path",
+ metavar='FILE',
+ default=None,
+ help="Path to the API dump index JSON file "
+ "(required when `--api-changelog-generate` is True)",
+ required=False,
+ )
+
+ parser.add_argument(
"-o", "--output",
dest="output_dir",
type=str,
@@ -495,6 +534,42 @@ if ARGS.sphinx_build_pdf:
sphinx_make_pdf_log = os.path.join(ARGS.output_dir, ".latex_make.log")
SPHINX_MAKE_PDF_STDOUT = open(sphinx_make_pdf_log, "w", encoding="utf-8")
+
+# --------------------------------CHANGELOG GENERATION--------------------------------------
+
+def generate_changelog():
+ import importlib.util
+ spec = importlib.util.spec_from_file_location(
+ "sphinx_changelog_gen",
+ os.path.abspath(os.path.join(SCRIPT_DIR, "sphinx_changelog_gen.py")),
+ )
+ sphinx_changelog_gen = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(sphinx_changelog_gen)
+
+ API_DUMP_INDEX_FILEPATH = ARGS.api_dump_index_path
+ API_DUMP_ROOT = os.path.dirname(API_DUMP_INDEX_FILEPATH)
+ API_DUMP_FILEPATH = os.path.abspath(os.path.join(API_DUMP_ROOT, BLENDER_VERSION_DOTS, "api_dump.json"))
+ API_CHANGELOG_FILEPATH = os.path.abspath(os.path.join(SPHINX_IN_TMP, "change_log.rst"))
+
+ sphinx_changelog_gen.main((
+ "--",
+ "--indexpath",
+ API_DUMP_INDEX_FILEPATH,
+ "dump",
+ "--filepath-out",
+ API_DUMP_FILEPATH,
+ ))
+
+ sphinx_changelog_gen.main((
+ "--",
+ "--indexpath",
+ API_DUMP_INDEX_FILEPATH,
+ "changelog",
+ "--filepath-out",
+ API_CHANGELOG_FILEPATH,
+ ))
+
+
# --------------------------------API DUMP--------------------------------------
# Lame, python won't give some access.
@@ -531,7 +606,7 @@ def import_value_from_module(module_name, import_name):
def execfile(filepath):
global_namespace = {"__file__": filepath, "__name__": "__main__"}
- with open(filepath) as file_handle:
+ with open(filepath, encoding="utf-8") as file_handle:
exec(compile(file_handle.read(), filepath, 'exec'), global_namespace)
@@ -693,26 +768,6 @@ def write_indented_lines(ident, fn, text, strip=True):
fn(ident + l + "\n")
-def pymethod2sphinx(ident, fw, identifier, py_func):
- """
- class method to sphinx
- """
- arg_str = inspect.formatargspec(*inspect.getargspec(py_func))
- if arg_str.startswith("(self, "):
- arg_str = "(" + arg_str[7:]
- func_type = "method"
- elif arg_str.startswith("(cls, "):
- arg_str = "(" + arg_str[6:]
- func_type = "classmethod"
- else:
- func_type = "staticmethod"
-
- fw(ident + ".. %s:: %s%s\n\n" % (func_type, identifier, arg_str))
- if py_func.__doc__:
- write_indented_lines(ident + " ", fw, py_func.__doc__)
- fw("\n")
-
-
def pyfunc2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_class=True):
"""
function or class method to sphinx
@@ -1220,15 +1275,23 @@ def pycontext2sphinx(basepath):
# No need to check if there are duplicates yet as it's known there wont be.
unique.add(prop.identifier)
+ enum_descr_override = None
+ if USE_SHARED_RNA_ENUM_ITEMS_STATIC:
+ enum_descr_override = pyrna_enum2sphinx_shared_link(prop)
+
type_descr = prop.get_type_description(
- class_fmt=":class:`bpy.types.%s`", collection_id=_BPY_PROP_COLLECTION_ID)
+ class_fmt=":class:`bpy.types.%s`",
+ collection_id=_BPY_PROP_COLLECTION_ID,
+ enum_descr_override=enum_descr_override,
+ )
fw(".. data:: %s\n\n" % prop.identifier)
if prop.description:
fw(" %s\n\n" % prop.description)
# Special exception, can't use generic code here for enums.
if prop.type == "enum":
- enum_text = pyrna_enum2sphinx(prop)
+ # If the link has been written, no need to inline the enum items.
+ enum_text = "" if enum_descr_override else pyrna_enum2sphinx(prop)
if enum_text:
write_indented_lines(" ", fw, enum_text)
fw("\n")
@@ -1290,6 +1353,11 @@ def pyrna_enum2sphinx(prop, use_empty_descriptions=False):
Write a bullet point list of enum + descriptions.
"""
+ # Write a link to the enum if this is part of `rna_enum_pointer_map`.
+ if USE_SHARED_RNA_ENUM_ITEMS_STATIC:
+ if (result := pyrna_enum2sphinx_shared_link(prop)) is not None:
+ return result
+
if use_empty_descriptions:
ok = True
else:
@@ -1368,10 +1436,15 @@ def pyrna2sphinx(basepath):
kwargs["collection_id"] = _BPY_PROP_COLLECTION_ID
- type_descr = prop.get_type_description(**kwargs)
+ enum_descr_override = None
+ if USE_SHARED_RNA_ENUM_ITEMS_STATIC:
+ enum_descr_override = pyrna_enum2sphinx_shared_link(prop)
+ kwargs["enum_descr_override"] = enum_descr_override
- enum_text = pyrna_enum2sphinx(prop)
+ type_descr = prop.get_type_description(**kwargs)
+ # If the link has been written, no need to inline the enum items.
+ enum_text = "" if enum_descr_override else pyrna_enum2sphinx(prop)
if prop.name or prop.description or enum_text:
fw(ident + ":%s%s:\n\n" % (id_name, identifier))
@@ -1456,7 +1529,8 @@ def pyrna2sphinx(basepath):
else:
fw(".. class:: %s\n\n" % struct_id)
- fw(" %s\n\n" % struct.description)
+ write_indented_lines(" ", fw, struct.description, False)
+ fw("\n")
# Properties sorted in alphabetical order.
sorted_struct_properties = struct.properties[:]
@@ -1472,7 +1546,15 @@ def pyrna2sphinx(basepath):
if identifier in struct_blacklist:
continue
- type_descr = prop.get_type_description(class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID)
+ enum_descr_override = None
+ if USE_SHARED_RNA_ENUM_ITEMS_STATIC:
+ enum_descr_override = pyrna_enum2sphinx_shared_link(prop)
+
+ type_descr = prop.get_type_description(
+ class_fmt=":class:`%s`",
+ collection_id=_BPY_PROP_COLLECTION_ID,
+ enum_descr_override=enum_descr_override,
+ )
# Read-only properties use "data" directive, variables properties use "attribute" directive.
if "readonly" in type_descr:
fw(" .. data:: %s\n" % identifier)
@@ -1489,7 +1571,8 @@ def pyrna2sphinx(basepath):
# Special exception, can't use generic code here for enums.
if prop.type == "enum":
- enum_text = pyrna_enum2sphinx(prop)
+ # If the link has been written, no need to inline the enum items.
+ enum_text = "" if enum_descr_override else pyrna_enum2sphinx(prop)
if enum_text:
write_indented_lines(" ", fw, enum_text)
fw("\n")
@@ -1528,8 +1611,16 @@ def pyrna2sphinx(basepath):
for prop in func.return_values:
# TODO: pyrna_enum2sphinx for multiple return values... actually don't
# think we even use this but still!
+
+ enum_descr_override = None
+ if USE_SHARED_RNA_ENUM_ITEMS_STATIC:
+ enum_descr_override = pyrna_enum2sphinx_shared_link(prop)
+
type_descr = prop.get_type_description(
- as_ret=True, class_fmt=":class:`%s`", collection_id=_BPY_PROP_COLLECTION_ID)
+ as_ret=True, class_fmt=":class:`%s`",
+ collection_id=_BPY_PROP_COLLECTION_ID,
+ enum_descr_override=enum_descr_override,
+ )
descr = prop.description
if not descr:
descr = prop.name
@@ -1778,11 +1869,16 @@ def write_sphinx_conf_py(basepath):
fw("extensions = ['sphinx.ext.intersphinx']\n\n")
fw("intersphinx_mapping = {'blender_manual': ('https://docs.blender.org/manual/en/dev/', None)}\n\n")
fw("project = 'Blender %s Python API'\n" % BLENDER_VERSION_STRING)
- fw("master_doc = 'index'\n")
- fw("copyright = u'Blender Foundation'\n")
+ fw("root_doc = 'index'\n")
+ fw("copyright = 'Blender Foundation'\n")
fw("version = '%s'\n" % BLENDER_VERSION_DOTS)
fw("release = '%s'\n" % BLENDER_VERSION_DOTS)
+ # Set this as the default is a super-set of Python3.
+ fw("highlight_language = 'python3'\n")
+ # No need to detect encoding.
+ fw("highlight_options = {'default': {'encoding': 'utf-8'}}\n\n")
+
# Quiet file not in table-of-contents warnings.
fw("exclude_patterns = [\n")
fw(" 'include__bmesh.rst',\n")
@@ -1978,6 +2074,14 @@ def write_rst_types_index(basepath):
fw(".. toctree::\n")
fw(" :glob:\n\n")
fw(" bpy.types.*\n\n")
+
+ # This needs to be included somewhere, while it's hidden, list to avoid warnings.
+ if USE_SHARED_RNA_ENUM_ITEMS_STATIC:
+ fw(".. toctree::\n")
+ fw(" :hidden:\n")
+ fw(" :maxdepth: 1\n\n")
+ fw(" Shared Enum Types <bpy_types_enum_items/index>\n\n")
+
file.close()
@@ -2048,6 +2152,81 @@ def write_rst_data(basepath):
EXAMPLE_SET_USED.add("bpy.data")
+def pyrna_enum2sphinx_shared_link(prop):
+ """
+ Return a reference to the enum used by ``prop`` or None when not found.
+ """
+ if (
+ (prop.type == "enum") and
+ (pointer := prop.enum_pointer) and
+ (identifier := rna_enum_pointer_to_id_map.get(pointer))
+ ):
+ return ":ref:`%s`" % identifier
+ return None
+
+
+def write_rst_enum_items(basepath, key, key_no_prefix, enum_items):
+ """
+ Write a single page for a static enum in RST.
+
+ This helps avoiding very large lists being in-lined in many places which is an issue
+ especially with icons in ``bpy.types.UILayout``. See T87008.
+ """
+ filepath = os.path.join(basepath, "%s.rst" % key_no_prefix)
+ with open(filepath, "w", encoding="utf-8") as fh:
+ fw = fh.write
+ # fw(".. noindex::\n\n")
+ fw(".. _%s:\n\n" % key)
+
+ fw(title_string(key_no_prefix.replace("_", " ").title(), "#"))
+ # fw(".. rubric:: %s\n\n" % key_no_prefix.replace("_", " ").title())
+
+ for item in enum_items:
+ identifier = item.identifier
+ name = item.name
+ description = item.description
+ if identifier:
+ fw(":%s: %s\n" % (item.identifier, (escape_rst(name) + ".") if name else ""))
+ if description:
+ fw("\n")
+ write_indented_lines(" ", fw, escape_rst(description) + ".")
+ else:
+ fw("\n")
+ else:
+ if name:
+ fw("\n\n**%s**\n\n" % name)
+ else:
+ fw("\n\n----\n\n")
+
+ if description:
+ fw(escape_rst(description) + ".")
+ fw("\n\n")
+
+
+def write_rst_enum_items_and_index(basepath):
+ """
+ Write shared enum items.
+ """
+ subdir = "bpy_types_enum_items"
+ basepath_bpy_types_rna_enum = os.path.join(basepath, subdir)
+ os.makedirs(basepath_bpy_types_rna_enum, exist_ok=True)
+ with open(os.path.join(basepath_bpy_types_rna_enum, "index.rst"), "w", encoding="utf-8") as fh:
+ fw = fh.write
+ fw(title_string("Shared Enum Items", "#"))
+ fw(".. toctree::\n")
+ fw("\n")
+ for key, enum_items in rna_enum_dict.items():
+ if not key.startswith("rna_enum_"):
+ raise Exception("Found RNA enum identifier that doesn't use the 'rna_enum_' prefix, found %r!" % key)
+ key_no_prefix = key.removeprefix("rna_enum_")
+ fw(" %s\n" % key_no_prefix)
+
+ for key, enum_items in rna_enum_dict.items():
+ key_no_prefix = key.removeprefix("rna_enum_")
+ write_rst_enum_items(basepath_bpy_types_rna_enum, key, key_no_prefix, enum_items)
+ fw("\n")
+
+
def write_rst_importable_modules(basepath):
"""
Write the RST files of importable modules.
@@ -2212,6 +2391,10 @@ def rna2sphinx(basepath):
write_rst_data(basepath) # bpy.data
write_rst_importable_modules(basepath)
+ # `bpy_types_enum_items/*` (referenced from `bpy.types`).
+ if USE_SHARED_RNA_ENUM_ITEMS_STATIC:
+ write_rst_enum_items_and_index(basepath)
+
# copy the other rsts
copy_handwritten_rsts(basepath)
@@ -2285,8 +2468,6 @@ def setup_monkey_patch():
# Avoid adding too many changes here.
def setup_blender():
- import bpy
-
# Remove handlers since the functions get included
# in the doc-string and don't have meaningful names.
lists_to_restore = []
@@ -2349,6 +2530,9 @@ def main():
rna2sphinx(SPHINX_IN_TMP)
+ if ARGS.changelog:
+ generate_changelog()
+
if ARGS.full_rebuild:
# Only for full updates.
shutil.rmtree(SPHINX_IN, True)
diff --git a/doc/python_api/sphinx_doc_gen_monkeypatch.py b/doc/python_api/sphinx_doc_gen_monkeypatch.py
index 09911e9b8a1..e3fba024446 100644
--- a/doc/python_api/sphinx_doc_gen_monkeypatch.py
+++ b/doc/python_api/sphinx_doc_gen_monkeypatch.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
bpy_types_Operator_bl_property__doc__ = (
"""
The name of a property to use as this operators primary property.
diff --git a/doc/python_api/static/css/theme_overrides.css b/doc/python_api/static/css/theme_overrides.css
index 0fea27a8ebd..5ab449044db 100644
--- a/doc/python_api/static/css/theme_overrides.css
+++ b/doc/python_api/static/css/theme_overrides.css
@@ -1,10 +1,3 @@
-/* T76453: Prevent Long enum lists */
-.field-list > dd p {
- max-height: 245px;
- overflow-y: auto !important;
- word-break: break-word;
-}
-
/* Hide home icon in search area */
.wy-side-nav-search > a:hover {background: none; opacity: 0.9}
.wy-side-nav-search > a.icon::before {content: none}
diff --git a/extern/audaspace/bindings/C/AUD_Special.cpp b/extern/audaspace/bindings/C/AUD_Special.cpp
index 1ce25dcd41c..a5ecb7a6dc0 100644
--- a/extern/audaspace/bindings/C/AUD_Special.cpp
+++ b/extern/audaspace/bindings/C/AUD_Special.cpp
@@ -270,7 +270,7 @@ AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, int sampl
return length;
}
-AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate, void(*callback)(float, void*), void* data)
+AUD_API int AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate, void(*callback)(float, void*), void* data, char* error, size_t errorsize)
{
try
{
@@ -282,15 +282,20 @@ AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned i
std::shared_ptr<IWriter> writer = FileWriter::createWriter(filename, convCToDSpec(specs), static_cast<Container>(format), static_cast<Codec>(codec), bitrate);
FileWriter::writeReader(reader, writer, length, buffersize, callback, data);
- return nullptr;
+ return true;
}
catch(Exception& e)
{
- return e.getMessage().c_str();
+ if(error && errorsize)
+ {
+ std::strncpy(error, e.getMessage().c_str(), errorsize);
+ error[errorsize - 1] = '\0';
+ }
+ return false;
}
}
-AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate, void(*callback)(float, void*), void* data)
+AUD_API int AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate, void(*callback)(float, void*), void* data, char* error, size_t errorsize)
{
try
{
@@ -328,11 +333,16 @@ AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start
reader->seek(start);
FileWriter::writeReader(reader, writers, length, buffersize, callback, data);
- return nullptr;
+ return true;
}
catch(Exception& e)
{
- return e.getMessage().c_str();
+ if(error && errorsize)
+ {
+ std::strncpy(error, e.getMessage().c_str(), errorsize);
+ error[errorsize - 1] = '\0';
+ }
+ return false;
}
}
diff --git a/extern/audaspace/bindings/C/AUD_Special.h b/extern/audaspace/bindings/C/AUD_Special.h
index 2f5d13c6fd9..1d181d33f87 100644
--- a/extern/audaspace/bindings/C/AUD_Special.h
+++ b/extern/audaspace/bindings/C/AUD_Special.h
@@ -70,13 +70,15 @@ extern AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, in
* \param bitrate The bitrate for encoding.
* \param callback A callback function that is called periodically during mixdown, reporting progress if length > 0. Can be NULL.
* \param data Pass through parameter that is passed to the callback.
- * \return An error message or NULL in case of success.
+ * \param error String buffer to copy the error message to in case of failure.
+ * \param errorsize The size of the error buffer.
+ * \return Whether or not the operation succeeded.
*/
-extern AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length,
+extern AUD_API int AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length,
unsigned int buffersize, const char* filename,
AUD_DeviceSpecs specs, AUD_Container format,
AUD_Codec codec, unsigned int bitrate,
- void(*callback)(float, void*), void* data);
+ void(*callback)(float, void*), void* data, char* error, size_t errorsize);
/**
* Mixes a sound down into multiple files.
@@ -91,13 +93,15 @@ extern AUD_API const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, uns
* \param bitrate The bitrate for encoding.
* \param callback A callback function that is called periodically during mixdown, reporting progress if length > 0. Can be NULL.
* \param data Pass through parameter that is passed to the callback.
- * \return An error message or NULL in case of success.
+ * \param error String buffer to copy the error message to in case of failure.
+ * \param errorsize The size of the error buffer.
+ * \return Whether or not the operation succeeded.
*/
-extern AUD_API const char* AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length,
+extern AUD_API int AUD_mixdown_per_channel(AUD_Sound* sound, unsigned int start, unsigned int length,
unsigned int buffersize, const char* filename,
AUD_DeviceSpecs specs, AUD_Container format,
AUD_Codec codec, unsigned int bitrate,
- void(*callback)(float, void*), void* data);
+ void(*callback)(float, void*), void* data, char* error, size_t errorsize);
/**
* Opens a read device and prepares it for mixdown of the sound scene.
diff --git a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
index cddc411cfc6..d2de89977a9 100644
--- a/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
+++ b/extern/audaspace/plugins/pulseaudio/PulseAudioDevice.cpp
@@ -41,7 +41,7 @@ double PulseAudioDevice::PulseAudioSynchronizer::getPosition(std::shared_ptr<IHa
void PulseAudioDevice::updateRingBuffer()
{
- unsigned int samplesize = AUD_SAMPLE_SIZE(m_specs);
+ unsigned int samplesize = AUD_DEVICE_SAMPLE_SIZE(m_specs);
std::unique_lock<std::mutex> lock(m_mixingLock);
diff --git a/extern/curve_fit_nd/README.blender b/extern/curve_fit_nd/README.blender
index 8e70fd796bb..ccc9627f5b5 100644
--- a/extern/curve_fit_nd/README.blender
+++ b/extern/curve_fit_nd/README.blender
@@ -1,5 +1,5 @@
Project: Curve-Fit-nD
URL: https://github.com/ideasman42/curve-fit-nd
License: BSD 3-Clause
-Upstream version: ddcd5bd (Last Release)
+Upstream version: ae32da9de264c3ed399673e2bc1bc09003799416 (Last Release)
Local modifications: None
diff --git a/extern/curve_fit_nd/curve_fit_nd.h b/extern/curve_fit_nd/curve_fit_nd.h
index 18244799b0f..56c3e968b1c 100644
--- a/extern/curve_fit_nd/curve_fit_nd.h
+++ b/extern/curve_fit_nd/curve_fit_nd.h
@@ -39,7 +39,7 @@
* Takes a flat array of points and evaluates that to calculate a bezier spline.
*
* \param points, points_len: The array of points to calculate a cubics from.
- * \param dims: The number of dimensions for for each element in \a points.
+ * \param dims: The number of dimensions for each element in \a points.
* \param error_threshold: the error threshold to allow for,
* the curve will be within this distance from \a points.
* \param corners, corners_len: indices for points which will not have aligned tangents (optional).
@@ -47,10 +47,10 @@
* to evaluate a line to detect corner indices.
*
* \param r_cubic_array, r_cubic_array_len: Resulting array of tangents and knots, formatted as follows:
- * ``r_cubic_array[r_cubic_array_len][3][dims]``,
+ * `r_cubic_array[r_cubic_array_len][3][dims]`,
* where each point has 0 and 2 for the tangents and the middle index 1 for the knot.
- * The size of the *flat* array will be ``r_cubic_array_len * 3 * dims``.
- * \param r_corner_index_array, r_corner_index_len: Corner indices in in \a r_cubic_array (optional).
+ * The size of the *flat* array will be `r_cubic_array_len * 3 * dims`.
+ * \param r_corner_index_array, r_corner_index_len: Corner indices in \a r_cubic_array (optional).
* This allows you to access corners on the resulting curve.
*
* \returns zero on success, nonzero is reserved for error values.
@@ -85,7 +85,7 @@ int curve_fit_cubic_to_points_fl(
* Takes a flat array of points and evaluates that to calculate handle lengths.
*
* \param points, points_len: The array of points to calculate a cubics from.
- * \param dims: The number of dimensions for for each element in \a points.
+ * \param dims: The number of dimensions for each element in \a points.
* \param points_length_cache: Optional pre-calculated lengths between points.
* \param error_threshold: the error threshold to allow for,
* \param tan_l, tan_r: Normalized tangents the handles will be aligned to.
@@ -166,7 +166,7 @@ int curve_fit_cubic_to_points_refit_fl(
* A helper function that takes a line and outputs its corner indices.
*
* \param points, points_len: Curve to evaluate.
- * \param dims: The number of dimensions for for each element in \a points.
+ * \param dims: The number of dimensions for each element in \a points.
* \param radius_min: Corners on the curve between points below this radius are ignored.
* \param radius_max: Corners on the curve above this radius are ignored.
* \param samples_max: Prevent testing corners beyond this many points
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic.c b/extern/curve_fit_nd/intern/curve_fit_cubic.c
index 47c5344c821..95e5d9f79e4 100644
--- a/extern/curve_fit_nd/intern/curve_fit_cubic.c
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic.c
@@ -43,20 +43,24 @@
#include "../curve_fit_nd.h"
-/* Take curvature into account when calculating the least square solution isn't usable. */
+/** Take curvature into account when calculating the least square solution isn't usable. */
#define USE_CIRCULAR_FALLBACK
-/* Use the maximum distance of any points from the direct line between 2 points
+/**
+ * Use the maximum distance of any points from the direct line between 2 points
* to calculate how long the handles need to be.
* Can do a 'perfect' reversal of subdivision when for curve has symmetrical handles and doesn't change direction
- * (as with an 'S' shape). */
+ * (as with an 'S' shape).
+ */
#define USE_OFFSET_FALLBACK
-/* avoid re-calculating lengths multiple times */
+/** Avoid re-calculating lengths multiple times. */
#define USE_LENGTH_CACHE
-/* store the indices in the cubic data so we can return the original indices,
- * useful when the caller has data associated with the curve. */
+/**
+ * Store the indices in the cubic data so we can return the original indices,
+ * useful when the caller has data associated with the curve.
+ */
#define USE_ORIG_INDEX_DATA
typedef unsigned int uint;
@@ -95,13 +99,15 @@ typedef unsigned int uint;
* \{ */
typedef struct Cubic {
- /* single linked lists */
+ /** Single linked lists. */
struct Cubic *next;
#ifdef USE_ORIG_INDEX_DATA
uint orig_span;
#endif
- /* 0: point_0, 1: handle_0, 2: handle_1, 3: point_1,
- * each one is offset by 'dims' */
+ /**
+ * 0: point_0, 1: handle_0, 2: handle_1, 3: point_1,
+ * each one is offset by 'dims'.
+ */
double pt_data[0];
} Cubic;
@@ -195,7 +201,7 @@ static double *cubic_list_as_array(
bool use_orig_index = (r_orig_index != NULL);
#endif
- /* fill the array backwards */
+ /* Fill the array backwards. */
const size_t array_chunk = 3 * dims;
double *array_iter = array + array_flat_len;
for (Cubic *citer = clist->items; citer; citer = citer->next) {
@@ -221,15 +227,15 @@ static double *cubic_list_as_array(
}
#endif
- /* flip tangent for first and last (we could leave at zero, but set to something useful) */
+ /* Flip tangent for first and last (we could leave at zero, but set to something useful). */
- /* first */
+ /* First. */
array_iter -= array_chunk;
memcpy(&array_iter[dims], handle_prev, sizeof(double) * 2 * dims);
flip_vn_vnvn(&array_iter[0 * dims], &array_iter[1 * dims], &array_iter[2 * dims], dims);
assert(array == array_iter);
- /* last */
+ /* Last. */
array_iter += array_flat_len - (3 * dims);
flip_vn_vnvn(&array_iter[2 * dims], &array_iter[1 * dims], &array_iter[0 * dims], dims);
@@ -455,7 +461,7 @@ static double points_calc_circumference_factor(
const double dot = dot_vnvn(tan_l, tan_r, dims);
const double len_tangent = dot < 0.0 ? len_vnvn(tan_l, tan_r, dims) : len_negated_vnvn(tan_l, tan_r, dims);
if (len_tangent > DBL_EPSILON) {
- /* only clamp to avoid precision error */
+ /* Only clamp to avoid precision error. */
double angle = acos(max(-fabs(dot), -1.0));
/* Angle may be less than the length when the tangents define >180 degrees of the circle,
* (tangents that point away from each other).
@@ -466,7 +472,7 @@ static double points_calc_circumference_factor(
return factor;
}
else {
- /* tangents are exactly aligned (think two opposite sides of a circle). */
+ /* Tangents are exactly aligned (think two opposite sides of a circle). */
return (M_PI / 2);
}
}
@@ -485,18 +491,18 @@ static double points_calc_circle_tangent_factor(
const double eps = 1e-8;
const double tan_dot = dot_vnvn(tan_l, tan_r, dims);
if (tan_dot > 1.0 - eps) {
- /* no angle difference (use fallback, length wont make any difference) */
+ /* No angle difference (use fallback, length won't make any difference). */
return (1.0 / 3.0) * 0.75;
}
else if (tan_dot < -1.0 + eps) {
- /* parallel tangents (half-circle) */
+ /* Parallel tangents (half-circle). */
return (1.0 / 2.0);
}
else {
- /* non-aligned tangents, calculate handle length */
+ /* Non-aligned tangents, calculate handle length. */
const double angle = acos(tan_dot) / 2.0;
- /* could also use 'angle_sin = len_vnvn(tan_l, tan_r, dims) / 2.0' */
+ /* Could also use `angle_sin = len_vnvn(tan_l, tan_r, dims) / 2.0`. */
const double angle_sin = sin(angle);
const double angle_cos = cos(angle);
return ((1.0 - angle_cos) / (angle_sin * 2.0)) / angle_sin;
@@ -516,15 +522,15 @@ static double points_calc_cubic_scale(
const double len_direct = len_vnvn(v_l, v_r, dims);
const double len_circle_factor = points_calc_circle_tangent_factor(tan_l, tan_r, dims);
- /* if this curve is a circle, this value doesn't need modification */
+ /* If this curve is a circle, this value doesn't need modification. */
const double len_circle_handle = (len_direct * (len_circle_factor / 0.75));
- /* scale by the difference from the circumference distance */
+ /* Scale by the difference from the circumference distance. */
const double len_circle = len_direct * points_calc_circumference_factor(tan_l, tan_r, dims);
double scale_handle = (coords_length / len_circle);
/* Could investigate an accurate calculation here,
- * though this gives close results */
+ * though this gives close results. */
scale_handle = ((scale_handle - 1.0) * 1.75) + 1.0;
return len_circle_handle * scale_handle;
@@ -554,9 +560,8 @@ static void cubic_from_points_fallback(
r_cubic->orig_span = (points_offset_len - 1);
#endif
- /* p1 = p0 - (tan_l * alpha);
- * p2 = p3 + (tan_r * alpha);
- */
+ /* `p1 = p0 - (tan_l * alpha);`
+ * `p2 = p3 + (tan_r * alpha);` */
msub_vn_vnvn_fl(p1, p0, tan_l, alpha, dims);
madd_vn_vnvn_fl(p2, p3, tan_r, alpha, dims);
}
@@ -594,7 +599,7 @@ static void cubic_from_points_offset_fallback(
project_plane_vn_vnvn_normalized(a[0], tan_l, dir_unit, dims);
project_plane_vn_vnvn_normalized(a[1], tan_r, dir_unit, dims);
- /* only for better accuracy, not essential */
+ /* Only for better accuracy, not essential. */
normalize_vn(a[0], dims);
normalize_vn(a[1], dims);
@@ -620,7 +625,7 @@ static void cubic_from_points_offset_fallback(
*
* The 'dists[..] + dir_dirs' limit is just a rough approximation.
* While a more exact value could be calculated,
- * in this case the error values approach divide by zero (inf)
+ * in this case the error values approach divide by zero (infinite)
* so there is no need to be too precise when checking if limits have been exceeded. */
double alpha_l = (dists[0] / 0.75) / fabs(dot_vnvn(tan_l, a[0], dims));
@@ -644,9 +649,8 @@ static void cubic_from_points_offset_fallback(
r_cubic->orig_span = (points_offset_len - 1);
#endif
- /* p1 = p0 - (tan_l * alpha_l);
- * p2 = p3 + (tan_r * alpha_r);
- */
+ /* `p1 = p0 - (tan_l * alpha_l);`
+ * `p2 = p3 + (tan_r * alpha_r);` */
msub_vn_vnvn_fl(p1, p0, tan_l, alpha_l, dims);
madd_vn_vnvn_fl(p2, p3, tan_r, alpha_r, dims);
}
@@ -674,7 +678,7 @@ static void cubic_from_points(
const double *p0 = &points_offset[0];
const double *p3 = &points_offset[(points_offset_len - 1) * dims];
- /* Point Pairs */
+ /* Point Pairs. */
double alpha_l, alpha_r;
#ifdef USE_VLA
double a[2][dims];
@@ -696,7 +700,7 @@ static void cubic_from_points(
const double b0_plus_b1 = B0plusB1(u_prime[i]);
const double b2_plus_b3 = B2plusB3(u_prime[i]);
- /* inline dot product */
+ /* Inline dot product. */
for (uint j = 0; j < dims; j++) {
const double tmp = (pt[j] - (p0[j] * b0_plus_b1)) + (p3[j] * b2_plus_b3);
@@ -719,7 +723,7 @@ static void cubic_from_points(
det_C0_C1 = c[0][0] * c[1][1] * 10e-12;
}
- /* may still divide-by-zero, check below will catch nan values */
+ /* May still divide-by-zero, check below will catch NAN values. */
alpha_l = det_X_C1 / det_C0_C1;
alpha_r = det_C_0X / det_C0_C1;
}
@@ -736,7 +740,7 @@ static void cubic_from_points(
bool use_clamp = true;
- /* flip check to catch nan values */
+ /* Flip check to catch NAN values. */
if (!(alpha_l >= 0.0) ||
!(alpha_r >= 0.0))
{
@@ -750,7 +754,7 @@ static void cubic_from_points(
alpha_l = alpha_r = len_vnvn(p0, p3, dims) / 3.0;
#endif
- /* skip clamping when we're using default handles */
+ /* Skip clamping when we're using default handles. */
use_clamp = false;
}
@@ -764,9 +768,8 @@ static void cubic_from_points(
r_cubic->orig_span = (points_offset_len - 1);
#endif
- /* p1 = p0 - (tan_l * alpha_l);
- * p2 = p3 + (tan_r * alpha_r);
- */
+ /* `p1 = p0 - (tan_l * alpha_l);`
+ * `p2 = p3 + (tan_r * alpha_r);` */
msub_vn_vnvn_fl(p1, p0, tan_l, alpha_l, dims);
madd_vn_vnvn_fl(p2, p3, tan_r, alpha_r, dims);
@@ -781,7 +784,7 @@ static void cubic_from_points(
#endif
points_calc_center_weighted(points_offset, points_offset_len, dims, center);
- const double clamp_scale = 3.0; /* clamp to 3x */
+ const double clamp_scale = 3.0; /* Clamp to 3x. */
double dist_sq_max = 0.0;
{
@@ -790,7 +793,7 @@ static void cubic_from_points(
#if 0
double dist_sq_test = sq(len_vnvn(center, pt, dims) * clamp_scale);
#else
- /* do inline */
+ /* Do inline. */
double dist_sq_test = 0.0;
for (uint j = 0; j < dims; j++) {
dist_sq_test += sq((pt[j] - center[j]) * clamp_scale);
@@ -816,10 +819,8 @@ static void cubic_from_points(
alpha_l = alpha_r = len_vnvn(p0, p3, dims) / 3.0;
#endif
- /*
- * p1 = p0 - (tan_l * alpha_l);
- * p2 = p3 + (tan_r * alpha_r);
- */
+ /* `p1 = p0 - (tan_l * alpha_l);`
+ * `p2 = p3 + (tan_r * alpha_r);` */
for (uint j = 0; j < dims; j++) {
p1[j] = p0[j] - (tan_l[j] * alpha_l);
p2[j] = p3[j] + (tan_r[j] * alpha_r);
@@ -829,7 +830,7 @@ static void cubic_from_points(
p2_dist_sq = len_squared_vnvn(center, p2, dims);
}
- /* clamp within the 3x radius */
+ /* Clamp within the 3x radius. */
if (p1_dist_sq > dist_sq_max) {
isub_vnvn(p1, center, dims);
imul_vn_fl(p1, sqrt(dist_sq_max) / sqrt(p1_dist_sq), dims);
@@ -841,7 +842,7 @@ static void cubic_from_points(
iadd_vnvn(p2, center, dims);
}
}
- /* end clamping */
+ /* End clamping. */
}
#ifdef USE_LENGTH_CACHE
@@ -917,7 +918,7 @@ static double cubic_find_root(
const uint dims)
{
/* Newton-Raphson Method. */
- /* all vectors */
+ /* All vectors. */
#ifdef USE_VLA
double q0_u[dims];
double q1_u[dims];
@@ -932,8 +933,8 @@ static double cubic_find_root(
cubic_calc_speed(cubic, u, dims, q1_u);
cubic_calc_acceleration(cubic, u, dims, q2_u);
- /* may divide-by-zero, caller must check for that case */
- /* u - ((q0_u - p) * q1_u) / (q1_u.length_squared() + (q0_u - p) * q2_u) */
+ /* May divide-by-zero, caller must check for that case. */
+ /* `u - ((q0_u - p) * q1_u) / (q1_u.length_squared() + (q0_u - p) * q2_u)` */
isub_vnvn(q0_u, p, dims);
return u - dot_vnvn(q0_u, q1_u, dims) /
(len_squared_vn(q1_u, dims) + dot_vnvn(q0_u, q2_u, dims));
@@ -1032,7 +1033,7 @@ static bool fit_cubic_to_points(
double error_max_sq;
uint split_index;
- /* Parameterize points, and attempt to fit curve */
+ /* Parameterize points, and attempt to fit curve. */
cubic_from_points(
points_offset, points_offset_len,
#ifdef USE_CIRCULAR_FALLBACK
@@ -1040,7 +1041,7 @@ static bool fit_cubic_to_points(
#endif
u, tan_l, tan_r, dims, r_cubic);
- /* Find max deviation of points to fitted curve */
+ /* Find max deviation of points to fitted curve. */
error_max_sq = cubic_calc_error(
r_cubic, points_offset, points_offset_len, u, dims,
&split_index);
@@ -1062,7 +1063,7 @@ static bool fit_cubic_to_points(
cubic_test, points_offset, points_offset_len, u, dims,
&split_index);
- /* intentionally use the newly calculated 'split_index',
+ /* Intentionally use the newly calculated 'split_index',
* even if the 'error_max_sq_test' is worse. */
if (error_max_sq > error_max_sq_test) {
error_max_sq = error_max_sq_test;
@@ -1071,7 +1072,7 @@ static bool fit_cubic_to_points(
}
#endif
- /* Test the offset fallback */
+ /* Test the offset fallback. */
#ifdef USE_OFFSET_FALLBACK
if (!(error_max_sq < error_threshold_sq)) {
/* Using the offset from the curve to calculate cubic handle length may give better results
@@ -1095,7 +1096,7 @@ static bool fit_cubic_to_points(
if (!(error_max_sq < error_threshold_sq)) {
cubic_copy(cubic_test, r_cubic, dims);
- /* If error not too large, try some reparameterization and iteration */
+ /* If error not too large, try some re-parameterization and iteration. */
double *u_prime = malloc(sizeof(double) * points_offset_len);
for (uint iter = 0; iter < iteration_max; iter++) {
if (!cubic_reparameterize(
@@ -1123,7 +1124,7 @@ static bool fit_cubic_to_points(
}
if (!(error_max_sq < error_threshold_sq)) {
- /* continue */
+ /* Continue. */
}
else {
assert((error_max_sq < error_threshold_sq));
@@ -1156,7 +1157,7 @@ static void fit_cubic_to_points_recursive(
const double error_threshold_sq,
const uint calc_flag,
const uint dims,
- /* fill in the list */
+ /* Fill in the list. */
CubicList *clist)
{
Cubic *cubic = cubic_alloc(dims);
@@ -1180,7 +1181,7 @@ static void fit_cubic_to_points_recursive(
cubic_free(cubic);
- /* Fitting failed -- split at max error point and fit recursively */
+ /* Fitting failed -- split at max error point and fit recursively. */
/* Check splinePoint is not an endpoint?
*
@@ -1212,7 +1213,7 @@ static void fit_cubic_to_points_recursive(
#endif
const double *pt = &points_offset[split_index * dims];
- /* tan_center = ((pt_a - pt).normalized() + (pt - pt_b).normalized()).normalized() */
+ /* `tan_center = ((pt_a - pt).normalized() + (pt - pt_b).normalized()).normalized()`. */
normalize_vn_vnvn(tan_center_a, pt_a, pt, dims);
normalize_vn_vnvn(tan_center_b, pt, pt_b, dims);
add_vn_vnvn(tan_center, tan_center_a, tan_center_b, dims);
@@ -1306,9 +1307,8 @@ int curve_fit_cubic_to_points_db(
const double *pt_l_next = pt_l + dims;
const double *pt_r_prev = pt_r - dims;
- /* tan_l = (pt_l - pt_l_next).normalized()
- * tan_r = (pt_r_prev - pt_r).normalized()
- */
+ /* `tan_l = (pt_l - pt_l_next).normalized();`
+ * `tan_r = (pt_r_prev - pt_r).normalized();` */
normalize_vn_vnvn(tan_l, pt_l, pt_l_next, dims);
normalize_vn_vnvn(tan_r, pt_r_prev, pt_r, dims);
@@ -1362,7 +1362,7 @@ int curve_fit_cubic_to_points_db(
*r_cubic_orig_index = NULL;
#endif
- /* allocate a contiguous array and free the linked list */
+ /* Allocate a contiguous array and free the linked list. */
*r_cubic_array = cubic_list_as_array(
&clist
#ifdef USE_ORIG_INDEX_DATA
@@ -1454,7 +1454,7 @@ int curve_fit_cubic_to_points_single_db(
{
Cubic *cubic = alloca(cubic_alloc_size(dims));
- /* in this instance theres no advantage in using length cache,
+ /* In this instance there are no advantage in using length cache,
* since we're not recursively calculating values. */
#ifdef USE_LENGTH_CACHE
double *points_length_cache_alloc = NULL;
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
index eda8ff27f8c..83b2383f58c 100644
--- a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
@@ -1490,3 +1490,4 @@ int curve_fit_cubic_to_points_refit_fl(
return result;
}
+
diff --git a/extern/curve_fit_nd/intern/generic_alloc_impl.h b/extern/curve_fit_nd/intern/generic_alloc_impl.h
index 687c154f14a..9ff2c24c1f6 100644
--- a/extern/curve_fit_nd/intern/generic_alloc_impl.h
+++ b/extern/curve_fit_nd/intern/generic_alloc_impl.h
@@ -37,7 +37,7 @@
* - #TPOOL_STRUCT: Name for pool struct name.
* - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
*
- * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``.
+ * \note #TPOOL_ALLOC_TYPE must be at least `sizeof(void *)`.
*
* Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
*
diff --git a/extern/curve_fit_nd/intern/generic_heap.c b/extern/curve_fit_nd/intern/generic_heap.c
index 09ed84bea43..f41025318c4 100644
--- a/extern/curve_fit_nd/intern/generic_heap.c
+++ b/extern/curve_fit_nd/intern/generic_heap.c
@@ -305,5 +305,3 @@ void *HEAP_node_ptr(HeapNode *node)
{
return node->ptr;
}
-
-/** \} */
diff --git a/extern/draco/README.blender b/extern/draco/README.blender
index b9c3bbb967d..a879ded978b 100644
--- a/extern/draco/README.blender
+++ b/extern/draco/README.blender
@@ -1,5 +1,5 @@
Project: Draco
URL: https://google.github.io/draco/
License: Apache 2.0
-Upstream version: 1.3.6
-Local modifications: None
+Upstream version: 1.5.2
+Local modifications: Apply patches/blender.patch
diff --git a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc
index 283a21251f4..51c3bb6c872 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc
+++ b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc
@@ -38,6 +38,46 @@ void AttributeOctahedronTransform::CopyToAttributeTransformData(
out_data->AppendParameterValue(quantization_bits_);
}
+bool AttributeOctahedronTransform::TransformAttribute(
+ const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) {
+ return GeneratePortableAttribute(attribute, point_ids,
+ target_attribute->size(), target_attribute);
+}
+
+bool AttributeOctahedronTransform::InverseTransformAttribute(
+ const PointAttribute &attribute, PointAttribute *target_attribute) {
+ if (target_attribute->data_type() != DT_FLOAT32) {
+ return false;
+ }
+
+ const int num_points = target_attribute->size();
+ const int num_components = target_attribute->num_components();
+ if (num_components != 3) {
+ return false;
+ }
+ constexpr int kEntrySize = sizeof(float) * 3;
+ float att_val[3];
+ const int32_t *source_attribute_data = reinterpret_cast<const int32_t *>(
+ attribute.GetAddress(AttributeValueIndex(0)));
+ uint8_t *target_address =
+ target_attribute->GetAddress(AttributeValueIndex(0));
+ OctahedronToolBox octahedron_tool_box;
+ if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_)) {
+ return false;
+ }
+ for (uint32_t i = 0; i < num_points; ++i) {
+ const int32_t s = *source_attribute_data++;
+ const int32_t t = *source_attribute_data++;
+ octahedron_tool_box.QuantizedOctahedralCoordsToUnitVector(s, t, att_val);
+
+ // Store the decoded floating point values into the attribute buffer.
+ std::memcpy(target_address, att_val, kEntrySize);
+ target_address += kEntrySize;
+ }
+ return true;
+}
+
void AttributeOctahedronTransform::SetParameters(int quantization_bits) {
quantization_bits_ = quantization_bits;
}
@@ -51,38 +91,55 @@ bool AttributeOctahedronTransform::EncodeParameters(
return false;
}
-std::unique_ptr<PointAttribute>
-AttributeOctahedronTransform::GeneratePortableAttribute(
+bool AttributeOctahedronTransform::DecodeParameters(
+ const PointAttribute &attribute, DecoderBuffer *decoder_buffer) {
+ uint8_t quantization_bits;
+ if (!decoder_buffer->Decode(&quantization_bits)) {
+ return false;
+ }
+ quantization_bits_ = quantization_bits;
+ return true;
+}
+
+bool AttributeOctahedronTransform::GeneratePortableAttribute(
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
- int num_points) const {
+ int num_points, PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
- // Allocate portable attribute.
- const int num_entries = static_cast<int>(point_ids.size());
- std::unique_ptr<PointAttribute> portable_attribute =
- InitPortableAttribute(num_entries, 2, num_points, attribute, true);
-
// Quantize all values in the order given by point_ids into portable
// attribute.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
- portable_attribute->GetAddress(AttributeValueIndex(0)));
+ target_attribute->GetAddress(AttributeValueIndex(0)));
float att_val[3];
int32_t dst_index = 0;
OctahedronToolBox converter;
if (!converter.SetQuantizationBits(quantization_bits_)) {
- return nullptr;
+ return false;
}
- for (uint32_t i = 0; i < point_ids.size(); ++i) {
- const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]);
- attribute.GetValue(att_val_id, att_val);
- // Encode the vector into a s and t octahedral coordinates.
- int32_t s, t;
- converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
- portable_attribute_data[dst_index++] = s;
- portable_attribute_data[dst_index++] = t;
+ if (!point_ids.empty()) {
+ for (uint32_t i = 0; i < point_ids.size(); ++i) {
+ const AttributeValueIndex att_val_id =
+ attribute.mapped_index(point_ids[i]);
+ attribute.GetValue(att_val_id, att_val);
+ // Encode the vector into a s and t octahedral coordinates.
+ int32_t s, t;
+ converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
+ portable_attribute_data[dst_index++] = s;
+ portable_attribute_data[dst_index++] = t;
+ }
+ } else {
+ for (PointIndex i(0); i < num_points; ++i) {
+ const AttributeValueIndex att_val_id = attribute.mapped_index(i);
+ attribute.GetValue(att_val_id, att_val);
+ // Encode the vector into a s and t octahedral coordinates.
+ int32_t s, t;
+ converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
+ portable_attribute_data[dst_index++] = s;
+ portable_attribute_data[dst_index++] = t;
+ }
}
- return portable_attribute;
+ return true;
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h
index 6e4e74284f0..21a1725bb52 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h
+++ b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h
@@ -37,19 +37,40 @@ class AttributeOctahedronTransform : public AttributeTransform {
void CopyToAttributeTransformData(
AttributeTransformData *out_data) const override;
+ bool TransformAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) override;
+
+ bool InverseTransformAttribute(const PointAttribute &attribute,
+ PointAttribute *target_attribute) override;
+
// Set number of quantization bits.
void SetParameters(int quantization_bits);
// Encode relevant parameters into buffer.
- bool EncodeParameters(EncoderBuffer *encoder_buffer) const;
+ bool EncodeParameters(EncoderBuffer *encoder_buffer) const override;
+
+ bool DecodeParameters(const PointAttribute &attribute,
+ DecoderBuffer *decoder_buffer) override;
bool is_initialized() const { return quantization_bits_ != -1; }
int32_t quantization_bits() const { return quantization_bits_; }
- // Create portable attribute.
- std::unique_ptr<PointAttribute> GeneratePortableAttribute(
- const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
- int num_points) const;
+ protected:
+ DataType GetTransformedDataType(
+ const PointAttribute &attribute) const override {
+ return DT_UINT32;
+ }
+ int GetTransformedNumComponents(
+ const PointAttribute &attribute) const override {
+ return 2;
+ }
+
+ // Perform the actual transformation.
+ bool GeneratePortableAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ int num_points,
+ PointAttribute *target_attribute) const;
private:
int32_t quantization_bits_;
diff --git a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc
index daa634ed03f..a7f93a488d7 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc
+++ b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc
@@ -1,4 +1,3 @@
-
// Copyright 2017 The Draco Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,13 +50,74 @@ void AttributeQuantizationTransform::CopyToAttributeTransformData(
out_data->AppendParameterValue(range_);
}
-void AttributeQuantizationTransform::SetParameters(int quantization_bits,
+bool AttributeQuantizationTransform::TransformAttribute(
+ const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) {
+ if (point_ids.empty()) {
+ GeneratePortableAttribute(attribute, target_attribute->size(),
+ target_attribute);
+ } else {
+ GeneratePortableAttribute(attribute, point_ids, target_attribute->size(),
+ target_attribute);
+ }
+ return true;
+}
+
+bool AttributeQuantizationTransform::InverseTransformAttribute(
+ const PointAttribute &attribute, PointAttribute *target_attribute) {
+ if (target_attribute->data_type() != DT_FLOAT32) {
+ return false;
+ }
+
+ // Convert all quantized values back to floats.
+ const int32_t max_quantized_value =
+ (1u << static_cast<uint32_t>(quantization_bits_)) - 1;
+ const int num_components = target_attribute->num_components();
+ const int entry_size = sizeof(float) * num_components;
+ const std::unique_ptr<float[]> att_val(new float[num_components]);
+ int quant_val_id = 0;
+ int out_byte_pos = 0;
+ Dequantizer dequantizer;
+ if (!dequantizer.Init(range_, max_quantized_value)) {
+ return false;
+ }
+ const int32_t *const source_attribute_data =
+ reinterpret_cast<const int32_t *>(
+ attribute.GetAddress(AttributeValueIndex(0)));
+
+ const int num_values = target_attribute->size();
+
+ for (uint32_t i = 0; i < num_values; ++i) {
+ for (int c = 0; c < num_components; ++c) {
+ float value =
+ dequantizer.DequantizeFloat(source_attribute_data[quant_val_id++]);
+ value = value + min_values_[c];
+ att_val[c] = value;
+ }
+ // Store the floating point value into the attribute buffer.
+ target_attribute->buffer()->Write(out_byte_pos, att_val.get(), entry_size);
+ out_byte_pos += entry_size;
+ }
+ return true;
+}
+
+bool AttributeQuantizationTransform::IsQuantizationValid(
+ int quantization_bits) {
+ // Currently we allow only up to 30 bit quantization.
+ return quantization_bits >= 1 && quantization_bits <= 30;
+}
+
+bool AttributeQuantizationTransform::SetParameters(int quantization_bits,
const float *min_values,
int num_components,
float range) {
+ if (!IsQuantizationValid(quantization_bits)) {
+ return false;
+ }
quantization_bits_ = quantization_bits;
min_values_.assign(min_values, min_values + num_components);
range_ = range;
+ return true;
}
bool AttributeQuantizationTransform::ComputeParameters(
@@ -65,6 +125,9 @@ bool AttributeQuantizationTransform::ComputeParameters(
if (quantization_bits_ != -1) {
return false; // already initialized.
}
+ if (!IsQuantizationValid(quantization_bits)) {
+ return false;
+ }
quantization_bits_ = quantization_bits;
const int num_components = attribute.num_components();
@@ -121,20 +184,37 @@ bool AttributeQuantizationTransform::EncodeParameters(
return false;
}
-std::unique_ptr<PointAttribute>
-AttributeQuantizationTransform::GeneratePortableAttribute(
- const PointAttribute &attribute, int num_points) const {
+bool AttributeQuantizationTransform::DecodeParameters(
+ const PointAttribute &attribute, DecoderBuffer *decoder_buffer) {
+ min_values_.resize(attribute.num_components());
+ if (!decoder_buffer->Decode(&min_values_[0],
+ sizeof(float) * min_values_.size())) {
+ return false;
+ }
+ if (!decoder_buffer->Decode(&range_)) {
+ return false;
+ }
+ uint8_t quantization_bits;
+ if (!decoder_buffer->Decode(&quantization_bits)) {
+ return false;
+ }
+ if (!IsQuantizationValid(quantization_bits)) {
+ return false;
+ }
+ quantization_bits_ = quantization_bits;
+ return true;
+}
+
+void AttributeQuantizationTransform::GeneratePortableAttribute(
+ const PointAttribute &attribute, int num_points,
+ PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
- // Allocate portable attribute.
- const int num_entries = num_points;
const int num_components = attribute.num_components();
- std::unique_ptr<PointAttribute> portable_attribute =
- InitPortableAttribute(num_entries, num_components, 0, attribute, true);
// Quantize all values using the order given by point_ids.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
- portable_attribute->GetAddress(AttributeValueIndex(0)));
+ target_attribute->GetAddress(AttributeValueIndex(0)));
const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
Quantizer quantizer;
quantizer.Init(range(), max_quantized_value);
@@ -149,24 +229,18 @@ AttributeQuantizationTransform::GeneratePortableAttribute(
portable_attribute_data[dst_index++] = q_val;
}
}
- return portable_attribute;
}
-std::unique_ptr<PointAttribute>
-AttributeQuantizationTransform::GeneratePortableAttribute(
+void AttributeQuantizationTransform::GeneratePortableAttribute(
const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
- int num_points) const {
+ int num_points, PointAttribute *target_attribute) const {
DRACO_DCHECK(is_initialized());
- // Allocate portable attribute.
- const int num_entries = static_cast<int>(point_ids.size());
const int num_components = attribute.num_components();
- std::unique_ptr<PointAttribute> portable_attribute = InitPortableAttribute(
- num_entries, num_components, num_points, attribute, true);
// Quantize all values using the order given by point_ids.
int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
- portable_attribute->GetAddress(AttributeValueIndex(0)));
+ target_attribute->GetAddress(AttributeValueIndex(0)));
const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
Quantizer quantizer;
quantizer.Init(range(), max_quantized_value);
@@ -181,7 +255,6 @@ AttributeQuantizationTransform::GeneratePortableAttribute(
portable_attribute_data[dst_index++] = q_val;
}
}
- return portable_attribute;
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h
index 934856f2db7..f1122b680ab 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h
+++ b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h
@@ -37,14 +37,24 @@ class AttributeQuantizationTransform : public AttributeTransform {
void CopyToAttributeTransformData(
AttributeTransformData *out_data) const override;
- void SetParameters(int quantization_bits, const float *min_values,
+ bool TransformAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) override;
+
+ bool InverseTransformAttribute(const PointAttribute &attribute,
+ PointAttribute *target_attribute) override;
+
+ bool SetParameters(int quantization_bits, const float *min_values,
int num_components, float range);
bool ComputeParameters(const PointAttribute &attribute,
const int quantization_bits);
// Encode relevant parameters into buffer.
- bool EncodeParameters(EncoderBuffer *encoder_buffer) const;
+ bool EncodeParameters(EncoderBuffer *encoder_buffer) const override;
+
+ bool DecodeParameters(const PointAttribute &attribute,
+ DecoderBuffer *decoder_buffer) override;
int32_t quantization_bits() const { return quantization_bits_; }
float min_value(int axis) const { return min_values_[axis]; }
@@ -52,16 +62,30 @@ class AttributeQuantizationTransform : public AttributeTransform {
float range() const { return range_; }
bool is_initialized() const { return quantization_bits_ != -1; }
+ protected:
// Create portable attribute using 1:1 mapping between points in the input and
// output attribute.
- std::unique_ptr<PointAttribute> GeneratePortableAttribute(
- const PointAttribute &attribute, int num_points) const;
+ void GeneratePortableAttribute(const PointAttribute &attribute,
+ int num_points,
+ PointAttribute *target_attribute) const;
// Create portable attribute using custom mapping between input and output
// points.
- std::unique_ptr<PointAttribute> GeneratePortableAttribute(
- const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
- int num_points) const;
+ void GeneratePortableAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ int num_points,
+ PointAttribute *target_attribute) const;
+
+ DataType GetTransformedDataType(
+ const PointAttribute &attribute) const override {
+ return DT_UINT32;
+ }
+ int GetTransformedNumComponents(
+ const PointAttribute &attribute) const override {
+ return attribute.num_components();
+ }
+
+ static bool IsQuantizationValid(int quantization_bits);
private:
int32_t quantization_bits_;
diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_transform.cc
index 55af630ac07..fb2ed18297a 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_transform.cc
+++ b/extern/draco/draco/src/draco/attributes/attribute_transform.cc
@@ -24,21 +24,18 @@ bool AttributeTransform::TransferToAttribute(PointAttribute *attribute) const {
return true;
}
-std::unique_ptr<PointAttribute> AttributeTransform::InitPortableAttribute(
- int num_entries, int num_components, int num_points,
- const PointAttribute &attribute, bool is_unsigned) const {
- const DataType dt = is_unsigned ? DT_UINT32 : DT_INT32;
- GeometryAttribute va;
- va.Init(attribute.attribute_type(), nullptr, num_components, dt, false,
+std::unique_ptr<PointAttribute> AttributeTransform::InitTransformedAttribute(
+ const PointAttribute &src_attribute, int num_entries) {
+ const int num_components = GetTransformedNumComponents(src_attribute);
+ const DataType dt = GetTransformedDataType(src_attribute);
+ GeometryAttribute ga;
+ ga.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false,
num_components * DataTypeLength(dt), 0);
- std::unique_ptr<PointAttribute> portable_attribute(new PointAttribute(va));
- portable_attribute->Reset(num_entries);
- if (num_points) {
- portable_attribute->SetExplicitMapping(num_points);
- } else {
- portable_attribute->SetIdentityMapping();
- }
- return portable_attribute;
+ std::unique_ptr<PointAttribute> transformed_attribute(new PointAttribute(ga));
+ transformed_attribute->Reset(num_entries);
+ transformed_attribute->SetIdentityMapping();
+ transformed_attribute->set_unique_id(src_attribute.unique_id());
+ return transformed_attribute;
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform.h b/extern/draco/draco/src/draco/attributes/attribute_transform.h
index d746fbf6eea..62aad60db91 100644
--- a/extern/draco/draco/src/draco/attributes/attribute_transform.h
+++ b/extern/draco/draco/src/draco/attributes/attribute_transform.h
@@ -17,6 +17,8 @@
#include "draco/attributes/attribute_transform_data.h"
#include "draco/attributes/point_attribute.h"
+#include "draco/core/decoder_buffer.h"
+#include "draco/core/encoder_buffer.h"
namespace draco {
@@ -35,10 +37,38 @@ class AttributeTransform {
AttributeTransformData *out_data) const = 0;
bool TransferToAttribute(PointAttribute *attribute) const;
+ // Applies the transform to |attribute| and stores the result in
+ // |target_attribute|. |point_ids| is an optional vector that can be used to
+ // remap values during the transform.
+ virtual bool TransformAttribute(const PointAttribute &attribute,
+ const std::vector<PointIndex> &point_ids,
+ PointAttribute *target_attribute) = 0;
+
+ // Applies an inverse transform to |attribute| and stores the result in
+ // |target_attribute|. In this case, |attribute| is an attribute that was
+ // already transformed (e.g. quantized) and |target_attribute| is the
+ // attribute before the transformation.
+ virtual bool InverseTransformAttribute(const PointAttribute &attribute,
+ PointAttribute *target_attribute) = 0;
+
+ // Encodes all data needed by the transformation into the |encoder_buffer|.
+ virtual bool EncodeParameters(EncoderBuffer *encoder_buffer) const = 0;
+
+ // Decodes all data needed to transform |attribute| back to the original
+ // format.
+ virtual bool DecodeParameters(const PointAttribute &attribute,
+ DecoderBuffer *decoder_buffer) = 0;
+
+ // Initializes a transformed attribute that can be used as target in the
+ // TransformAttribute() function call.
+ virtual std::unique_ptr<PointAttribute> InitTransformedAttribute(
+ const PointAttribute &src_attribute, int num_entries);
+
protected:
- std::unique_ptr<PointAttribute> InitPortableAttribute(
- int num_entries, int num_components, int num_points,
- const PointAttribute &attribute, bool is_unsigned) const;
+ virtual DataType GetTransformedDataType(
+ const PointAttribute &attribute) const = 0;
+ virtual int GetTransformedNumComponents(
+ const PointAttribute &attribute) const = 0;
};
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/geometry_attribute.cc b/extern/draco/draco/src/draco/attributes/geometry_attribute.cc
index f7ed6a86915..b624784261d 100644
--- a/extern/draco/draco/src/draco/attributes/geometry_attribute.cc
+++ b/extern/draco/draco/src/draco/attributes/geometry_attribute.cc
@@ -43,10 +43,6 @@ void GeometryAttribute::Init(GeometryAttribute::Type attribute_type,
}
bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) {
- if (buffer_ == nullptr || src_att.buffer_ == nullptr) {
- return false;
- }
- buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size());
num_components_ = src_att.num_components_;
data_type_ = src_att.data_type_;
normalized_ = src_att.normalized_;
@@ -55,6 +51,14 @@ bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) {
attribute_type_ = src_att.attribute_type_;
buffer_descriptor_ = src_att.buffer_descriptor_;
unique_id_ = src_att.unique_id_;
+ if (src_att.buffer_ == nullptr) {
+ buffer_ = nullptr;
+ } else {
+ if (buffer_ == nullptr) {
+ return false;
+ }
+ buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size());
+ }
return true;
}
diff --git a/extern/draco/draco/src/draco/attributes/geometry_attribute.h b/extern/draco/draco/src/draco/attributes/geometry_attribute.h
index b94ba8e22dd..c5faccc1b83 100644
--- a/extern/draco/draco/src/draco/attributes/geometry_attribute.h
+++ b/extern/draco/draco/src/draco/attributes/geometry_attribute.h
@@ -21,6 +21,7 @@
#include "draco/attributes/geometry_indices.h"
#include "draco/core/data_buffer.h"
#include "draco/core/hash_utils.h"
+#include "draco/draco_features.h"
namespace draco {
@@ -51,6 +52,16 @@ class GeometryAttribute {
// predefined use case. Such attributes are often used for a shader specific
// data.
GENERIC,
+#ifdef DRACO_TRANSCODER_SUPPORTED
+ // TODO(ostava): Adding a new attribute would be bit-stream change for GLTF.
+ // Older decoders wouldn't know what to do with this attribute type. This
+ // should be open-sourced only when we are ready to increase our bit-stream
+ // version.
+ TANGENT,
+ MATERIAL,
+ JOINTS,
+ WEIGHTS,
+#endif
// Total number of different attribute types.
// Always keep behind all named attributes.
NAMED_ATTRIBUTES_COUNT,
@@ -111,6 +122,9 @@ class GeometryAttribute {
const int64_t byte_pos = GetBytePos(att_index);
return buffer_->data() + byte_pos;
}
+ inline bool IsAddressValid(const uint8_t *address) const {
+ return ((buffer_->data() + buffer_->data_size()) > address);
+ }
// Fills out_data with the raw value of the requested attribute entry.
// out_data must be at least byte_stride_ long.
@@ -263,7 +277,35 @@ class GeometryAttribute {
// Convert all components available in both the original and output formats.
for (int i = 0; i < std::min(num_components_, out_num_components); ++i) {
+ if (!IsAddressValid(src_address)) {
+ return false;
+ }
const T in_value = *reinterpret_cast<const T *>(src_address);
+
+ // Make sure the in_value fits within the range of values that OutT
+ // is able to represent. Perform the check only for integral types.
+ if (std::is_integral<T>::value && std::is_integral<OutT>::value) {
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4804)
+#endif
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wbool-compare"
+#endif
+ static constexpr OutT kOutMin =
+ std::is_signed<T>::value ? std::numeric_limits<OutT>::lowest() : 0;
+ if (in_value < kOutMin || in_value > std::numeric_limits<OutT>::max()) {
+ return false;
+ }
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+ }
+
out_value[i] = static_cast<OutT>(in_value);
// When converting integer to floating point, normalize the value if
// necessary.
diff --git a/extern/draco/draco/src/draco/attributes/point_attribute.cc b/extern/draco/draco/src/draco/attributes/point_attribute.cc
index b28f860c15d..e54ab54278f 100644
--- a/extern/draco/draco/src/draco/attributes/point_attribute.cc
+++ b/extern/draco/draco/src/draco/attributes/point_attribute.cc
@@ -222,4 +222,47 @@ AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues(
}
#endif
+#ifdef DRACO_TRANSCODER_SUPPORTED
+void PointAttribute::RemoveUnusedValues() {
+ if (is_mapping_identity()) {
+ return; // For identity mapping, all values are always used.
+ }
+ // For explicit mapping we need to check if any point is mapped to a value.
+ // If not we can delete the value.
+ IndexTypeVector<AttributeValueIndex, bool> is_value_used(size(), false);
+ int num_used_values = 0;
+ for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
+ const AttributeValueIndex avi = indices_map_[pi];
+ if (!is_value_used[avi]) {
+ is_value_used[avi] = true;
+ num_used_values++;
+ }
+ }
+ if (num_used_values == size()) {
+ return; // All values are used.
+ }
+
+ // Remap the values and update the point to value mapping.
+ IndexTypeVector<AttributeValueIndex, AttributeValueIndex>
+ old_to_new_value_map(size(), kInvalidAttributeValueIndex);
+ AttributeValueIndex new_avi(0);
+ for (AttributeValueIndex avi(0); avi < size(); ++avi) {
+ if (!is_value_used[avi]) {
+ continue;
+ }
+ if (avi != new_avi) {
+ SetAttributeValue(new_avi, GetAddress(avi));
+ }
+ old_to_new_value_map[avi] = new_avi++;
+ }
+
+ // Remap all points to the new attribute values.
+ for (PointIndex pi(0); pi < indices_map_.size(); ++pi) {
+ indices_map_[pi] = old_to_new_value_map[indices_map_[pi]];
+ }
+
+ num_unique_entries_ = num_used_values;
+}
+#endif
+
} // namespace draco
diff --git a/extern/draco/draco/src/draco/attributes/point_attribute.h b/extern/draco/draco/src/draco/attributes/point_attribute.h
index ee36620313e..d55c50c8a57 100644
--- a/extern/draco/draco/src/draco/attributes/point_attribute.h
+++ b/extern/draco/draco/src/draco/attributes/point_attribute.h
@@ -133,6 +133,12 @@ class PointAttribute : public GeometryAttribute {
return attribute_transform_data_.get();
}
+#ifdef DRACO_TRANSCODER_SUPPORTED
+ // Removes unused values from the attribute. Value is unused when no point
+ // is mapped to the value. Only applicable when the mapping is not identity.
+ void RemoveUnusedValues();
+#endif
+
private:
#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
template <typename T>
diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc
index ce5b8b9c756..007dd2f4303 100644
--- a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc
@@ -43,9 +43,18 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
return false;
}
}
+
+ // Check that decoded number of attributes is valid.
if (num_attributes == 0) {
return false;
}
+ if (num_attributes > 5 * in_buffer->remaining_size()) {
+ // The decoded number of attributes is unreasonably high, because at least
+ // five bytes of attribute descriptor data per attribute are expected.
+ return false;
+ }
+
+ // Decode attribute descriptor data.
point_attribute_ids_.resize(num_attributes);
PointCloud *pc = point_cloud_;
for (uint32_t i = 0; i < num_attributes; ++i) {
@@ -69,9 +78,14 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
if (data_type == DT_INVALID || data_type >= DT_TYPES_COUNT) {
return false;
}
- const DataType draco_dt = static_cast<DataType>(data_type);
- // Add the attribute to the point cloud
+ // Check decoded attribute descriptor data.
+ if (num_components == 0) {
+ return false;
+ }
+
+ // Add the attribute to the point cloud.
+ const DataType draco_dt = static_cast<DataType>(data_type);
GeometryAttribute ga;
ga.Init(static_cast<GeometryAttribute::Type>(att_type), nullptr,
num_components, draco_dt, normalized > 0,
@@ -90,7 +104,9 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) {
} else
#endif
{
- DecodeVarint(&unique_id, in_buffer);
+ if (!DecodeVarint(&unique_id, in_buffer)) {
+ return false;
+ }
ga.set_unique_id(unique_id);
}
const int att_id = pc->AddAttribute(
diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc
index 797c62f30aa..480e3ff3436 100644
--- a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc
@@ -15,14 +15,16 @@
#include "draco/compression/attributes/attributes_encoder.h"
#include "draco/core/varint_encoding.h"
+#include "draco/draco_features.h"
namespace draco {
AttributesEncoder::AttributesEncoder()
: point_cloud_encoder_(nullptr), point_cloud_(nullptr) {}
-AttributesEncoder::AttributesEncoder(int att_id) : AttributesEncoder() {
- AddAttributeId(att_id);
+AttributesEncoder::AttributesEncoder(int point_attrib_id)
+ : AttributesEncoder() {
+ AddAttributeId(point_attrib_id);
}
bool AttributesEncoder::Init(PointCloudEncoder *encoder, const PointCloud *pc) {
@@ -37,7 +39,15 @@ bool AttributesEncoder::EncodeAttributesEncoderData(EncoderBuffer *out_buffer) {
for (uint32_t i = 0; i < num_attributes(); ++i) {
const int32_t att_id = point_attribute_ids_[i];
const PointAttribute *const pa = point_cloud_->attribute(att_id);
- out_buffer->Encode(static_cast<uint8_t>(pa->attribute_type()));
+ GeometryAttribute::Type type = pa->attribute_type();
+#ifdef DRACO_TRANSCODER_SUPPORTED
+ // Attribute types TANGENT, MATERIAL, JOINTS, and WEIGHTS are not supported
+ // in the official bitstream. They will be encoded as GENERIC.
+ if (type > GeometryAttribute::GENERIC) {
+ type = GeometryAttribute::GENERIC;
+ }
+#endif
+ out_buffer->Encode(static_cast<uint8_t>(type));
out_buffer->Encode(static_cast<uint8_t>(pa->data_type()));
out_buffer->Encode(static_cast<uint8_t>(pa->num_components()));
out_buffer->Encode(static_cast<uint8_t>(pa->normalized()));
diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc
index 99469f94590..c7c96d77007 100644
--- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc
@@ -72,7 +72,7 @@ class PointAttributeVectorOutputIterator {
Self &operator*() { return *this; }
// Still needed in some cases.
- // TODO(hemmer): remove.
+ // TODO(b/199760123): Remove.
// hardcoded to 3 based on legacy usage.
const Self &operator=(const VectorD<CoeffT, 3> &val) {
DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute.
@@ -278,8 +278,10 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
return false;
}
AttributeQuantizationTransform transform;
- transform.SetParameters(quantization_bits, min_value.data(),
- num_components, max_value_dif);
+ if (!transform.SetParameters(quantization_bits, min_value.data(),
+ num_components, max_value_dif)) {
+ return false;
+ }
const int num_transforms =
static_cast<int>(attribute_quantization_transforms_.size());
if (!transform.TransferToAttribute(
@@ -293,7 +295,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
// Decode transform data for signed integer attributes.
for (int i = 0; i < min_signed_values_.size(); ++i) {
int32_t val;
- DecodeVarint(&val, in_buffer);
+ if (!DecodeVarint(&val, in_buffer)) {
+ return false;
+ }
min_signed_values_[i] = val;
}
return true;
@@ -353,8 +357,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
return false;
}
if (6 < compression_level) {
- LOGE("KdTreeAttributesDecoder: compression level %i not supported.\n",
- compression_level);
+ DRACO_LOGE(
+ "KdTreeAttributesDecoder: compression level %i not supported.\n",
+ compression_level);
return false;
}
@@ -371,7 +376,7 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms(
GetDecoder()->point_cloud()->attribute(att_id);
attr->Reset(num_points);
attr->SetIdentityMapping();
- };
+ }
PointAttributeVectorOutputIterator<uint32_t> out_it(atts);
diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc
index 0f9c31565e5..b70deb9e01f 100644
--- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc
@@ -71,16 +71,21 @@ bool KdTreeAttributesEncoder::TransformAttributesToPortableFormat() {
att->num_components(), range);
} else {
// Compute quantization settings from the attribute values.
- attribute_quantization_transform.ComputeParameters(*att,
- quantization_bits);
+ if (!attribute_quantization_transform.ComputeParameters(
+ *att, quantization_bits)) {
+ return false;
+ }
}
attribute_quantization_transforms_.push_back(
attribute_quantization_transform);
// Store the quantized attribute in an array that will be used when we do
// the actual encoding of the data.
- quantized_portable_attributes_.push_back(
- attribute_quantization_transform.GeneratePortableAttribute(
- *att, static_cast<int>(num_points)));
+ auto portable_att =
+ attribute_quantization_transform.InitTransformedAttribute(*att,
+ num_points);
+ attribute_quantization_transform.TransformAttribute(*att, {},
+ portable_att.get());
+ quantized_portable_attributes_.push_back(std::move(portable_att));
} else if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 ||
att->data_type() == DT_INT8) {
// For signed types, find the minimum value for each component. These
diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h
index 8b4c4e2faab..80748e0bf5d 100644
--- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h
+++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
-#define DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
+#ifndef DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
+#define DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
#include "draco/attributes/attribute_quantization_transform.h"
#include "draco/compression/attributes/attributes_encoder.h"
@@ -48,4 +48,4 @@ class KdTreeAttributesEncoder : public AttributesEncoder {
} // namespace draco
-#endif // DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_
+#endif // DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_
diff --git a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h
index 32e27c711e3..be5ee5b09e3 100644
--- a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h
+++ b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h
@@ -53,6 +53,7 @@ class OctahedronToolBox {
: quantization_bits_(-1),
max_quantized_value_(-1),
max_value_(-1),
+ dequantization_scale_(1.f),
center_value_(-1) {}
bool SetQuantizationBits(int32_t q) {
@@ -62,6 +63,7 @@ class OctahedronToolBox {
quantization_bits_ = q;
max_quantized_value_ = (1 << quantization_bits_) - 1;
max_value_ = max_quantized_value_ - 1;
+ dequantization_scale_ = 2.f / max_value_;
center_value_ = max_value_ / 2;
return true;
}
@@ -192,64 +194,11 @@ class OctahedronToolBox {
}
}
- // TODO(b/149328891): Change function to not use templates as |T| is only
- // float.
- template <typename T>
- void OctaherdalCoordsToUnitVector(T in_s, T in_t, T *out_vector) const {
- DRACO_DCHECK_GE(in_s, 0);
- DRACO_DCHECK_GE(in_t, 0);
- DRACO_DCHECK_LE(in_s, 1);
- DRACO_DCHECK_LE(in_t, 1);
- T s = in_s;
- T t = in_t;
- T spt = s + t;
- T smt = s - t;
- T x_sign = 1.0;
- if (spt >= 0.5 && spt <= 1.5 && smt >= -0.5 && smt <= 0.5) {
- // Right hemisphere. Don't do anything.
- } else {
- // Left hemisphere.
- x_sign = -1.0;
- if (spt <= 0.5) {
- s = 0.5 - in_t;
- t = 0.5 - in_s;
- } else if (spt >= 1.5) {
- s = 1.5 - in_t;
- t = 1.5 - in_s;
- } else if (smt <= -0.5) {
- s = in_t - 0.5;
- t = in_s + 0.5;
- } else {
- s = in_t + 0.5;
- t = in_s - 0.5;
- }
- spt = s + t;
- smt = s - t;
- }
- const T y = 2.0 * s - 1.0;
- const T z = 2.0 * t - 1.0;
- const T x = std::min(std::min(2.0 * spt - 1.0, 3.0 - 2.0 * spt),
- std::min(2.0 * smt + 1.0, 1.0 - 2.0 * smt)) *
- x_sign;
- // Normalize the computed vector.
- const T normSquared = x * x + y * y + z * z;
- if (normSquared < 1e-6) {
- out_vector[0] = 0;
- out_vector[1] = 0;
- out_vector[2] = 0;
- } else {
- const T d = 1.0 / std::sqrt(normSquared);
- out_vector[0] = x * d;
- out_vector[1] = y * d;
- out_vector[2] = z * d;
- }
- }
-
- template <typename T>
- void QuantizedOctaherdalCoordsToUnitVector(int32_t in_s, int32_t in_t,
- T *out_vector) const {
- T scale = 1.0 / static_cast<T>(max_value_);
- OctaherdalCoordsToUnitVector(in_s * scale, in_t * scale, out_vector);
+ inline void QuantizedOctahedralCoordsToUnitVector(int32_t in_s, int32_t in_t,
+ float *out_vector) const {
+ OctahedralCoordsToUnitVector(in_s * dequantization_scale_ - 1.f,
+ in_t * dequantization_scale_ - 1.f,
+ out_vector);
}
// |s| and |t| are expected to be signed values.
@@ -333,9 +282,77 @@ class OctahedronToolBox {
int32_t center_value() const { return center_value_; }
private:
+ inline void OctahedralCoordsToUnitVector(float in_s_scaled, float in_t_scaled,
+ float *out_vector) const {
+ // Background about the encoding:
+ // A normal is encoded in a normalized space <s, t> depicted below. The
+ // encoding correponds to an octahedron that is unwrapped to a 2D plane.
+ // During encoding, a normal is projected to the surface of the octahedron
+ // and the projection is then unwrapped to the 2D plane. Decoding is the
+ // reverse of this process.
+ // All points in the central diamond are located on triangles on the
+ // right "hemisphere" of the octahedron while all points outside of the
+ // diamond are on the left hemisphere (basically, they would have to be
+ // wrapped along the diagonal edges to form the octahedron). The central
+ // point corresponds to the right most vertex of the octahedron and all
+ // corners of the plane correspond to the left most vertex of the
+ // octahedron.
+ //
+ // t
+ // ^ *-----*-----*
+ // | | /|\ |
+ // | / | \ |
+ // | / | \ |
+ // | / | \ |
+ // *-----*---- *
+ // | \ | / |
+ // | \ | / |
+ // | \ | / |
+ // | \|/ |
+ // *-----*-----* --> s
+
+ // Note that the input |in_s_scaled| and |in_t_scaled| are already scaled to
+ // <-1, 1> range. This way, the central point is at coordinate (0, 0).
+ float y = in_s_scaled;
+ float z = in_t_scaled;
+
+ // Remaining coordinate can be computed by projecting the (y, z) values onto
+ // the surface of the octahedron.
+ const float x = 1.f - std::abs(y) - std::abs(z);
+
+ // |x| is essentially a signed distance from the diagonal edges of the
+ // diamond shown on the figure above. It is positive for all points in the
+ // diamond (right hemisphere) and negative for all points outside the
+ // diamond (left hemisphere). For all points on the left hemisphere we need
+ // to update their (y, z) coordinates to account for the wrapping along
+ // the edges of the diamond.
+ float x_offset = -x;
+ x_offset = x_offset < 0 ? 0 : x_offset;
+
+ // This will do nothing for the points on the right hemisphere but it will
+ // mirror the (y, z) location along the nearest diagonal edge of the
+ // diamond.
+ y += y < 0 ? x_offset : -x_offset;
+ z += z < 0 ? x_offset : -x_offset;
+
+ // Normalize the computed vector.
+ const float norm_squared = x * x + y * y + z * z;
+ if (norm_squared < 1e-6) {
+ out_vector[0] = 0;
+ out_vector[1] = 0;
+ out_vector[2] = 0;
+ } else {
+ const float d = 1.0f / std::sqrt(norm_squared);
+ out_vector[0] = x * d;
+ out_vector[1] = y * d;
+ out_vector[2] = z * d;
+ }
+ }
+
int32_t quantization_bits_;
int32_t max_quantized_value_;
int32_t max_value_;
+ float dequantization_scale_;
int32_t center_value_;
};
} // namespace draco
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h
index f712952556a..2960a5e71b4 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_
-#define DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_
+#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_
+#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_
#include "draco/mesh/corner_table.h"
#include "draco/mesh/mesh.h"
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h
index bf1a6146111..775eded6b55 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h
@@ -69,7 +69,14 @@ class MeshPredictionSchemeGeometricNormalPredictorArea
// Computing cross product.
const VectorD<int64_t, 3> cross = CrossProduct(delta_next, delta_prev);
- normal = normal + cross;
+
+ // Prevent signed integer overflows by doing math as unsigned.
+ auto normal_data = reinterpret_cast<uint64_t *>(normal.data());
+ auto cross_data = reinterpret_cast<const uint64_t *>(cross.data());
+ normal_data[0] = normal_data[0] + cross_data[0];
+ normal_data[1] = normal_data[1] + cross_data[1];
+ normal_data[2] = normal_data[2] + cross_data[2];
+
cit.Next();
}
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h
index 485d457ccf6..fd10fb524b3 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h
@@ -60,8 +60,13 @@ inline bool ComputeParallelogramPrediction(
const int v_next_off = vert_next * num_components;
const int v_prev_off = vert_prev * num_components;
for (int c = 0; c < num_components; ++c) {
- out_prediction[c] = (in_data[v_next_off + c] + in_data[v_prev_off + c]) -
- in_data[v_opp_off + c];
+ const int64_t in_data_next_off = in_data[v_next_off + c];
+ const int64_t in_data_prev_off = in_data[v_prev_off + c];
+ const int64_t in_data_opp_off = in_data[v_opp_off + c];
+ const int64_t result =
+ (in_data_next_off + in_data_prev_off) - in_data_opp_off;
+
+ out_prediction[c] = static_cast<DataTypeT>(result);
}
return true;
}
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h
index 5d8a5060133..f05e5ddd713 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h
@@ -156,6 +156,13 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor<
const VectorD<int64_t, 2> x_uv =
n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv);
+ const int64_t pn_absmax_element =
+ std::max(std::max(std::abs(pn[0]), std::abs(pn[1])), std::abs(pn[2]));
+ if (cn_dot_pn > std::numeric_limits<int64_t>::max() / pn_absmax_element) {
+ // return false if squared length calculation would overflow.
+ return false;
+ }
+
// Compute squared length of vector CX in position coordinate system:
const VectorD<int64_t, 3> x_pos =
next_pos + (cn_dot_pn * pn) / pn_norm2_squared;
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
index 428340da013..60429d5c779 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc
@@ -18,34 +18,51 @@ namespace draco {
PredictionSchemeMethod SelectPredictionMethod(
int att_id, const PointCloudEncoder *encoder) {
- if (encoder->options()->GetSpeed() >= 10) {
+ return SelectPredictionMethod(att_id, *encoder->options(), encoder);
+}
+
+PredictionSchemeMethod SelectPredictionMethod(
+ int att_id, const EncoderOptions &options,
+ const PointCloudEncoder *encoder) {
+ if (options.GetSpeed() >= 10) {
// Selected fastest, though still doing some compression.
return PREDICTION_DIFFERENCE;
}
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
// Use speed setting to select the best encoding method.
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
- if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
- if (encoder->options()->GetSpeed() < 4) {
+ if (att->attribute_type() == GeometryAttribute::TEX_COORD &&
+ att->num_components() == 2) {
+ if (options.GetSpeed() < 4) {
// Use texture coordinate prediction for speeds 0, 1, 2, 3.
return MESH_PREDICTION_TEX_COORDS_PORTABLE;
}
}
if (att->attribute_type() == GeometryAttribute::NORMAL) {
#ifdef DRACO_NORMAL_ENCODING_SUPPORTED
- if (encoder->options()->GetSpeed() < 4) {
+ if (options.GetSpeed() < 4) {
// Use geometric normal prediction for speeds 0, 1, 2, 3.
- return MESH_PREDICTION_GEOMETRIC_NORMAL;
+ // For this prediction, the position attribute needs to be either
+ // integer or quantized as well.
+ const int pos_att_id = encoder->point_cloud()->GetNamedAttributeId(
+ GeometryAttribute::POSITION);
+ const PointAttribute *const pos_att =
+ encoder->point_cloud()->GetNamedAttribute(
+ GeometryAttribute::POSITION);
+ if (pos_att && (IsDataTypeIntegral(pos_att->data_type()) ||
+ options.GetAttributeInt(pos_att_id, "quantization_bits",
+ -1) > 0)) {
+ return MESH_PREDICTION_GEOMETRIC_NORMAL;
+ }
}
#endif
return PREDICTION_DIFFERENCE; // default
}
// Handle other attribute types.
- if (encoder->options()->GetSpeed() >= 8) {
+ if (options.GetSpeed() >= 8) {
return PREDICTION_DIFFERENCE;
}
- if (encoder->options()->GetSpeed() >= 2 ||
- encoder->point_cloud()->num_points() < 40) {
+ if (options.GetSpeed() >= 2 || encoder->point_cloud()->num_points() < 40) {
// Parallelogram prediction is used for speeds 2 - 7 or when the overhead
// of using constrained multi-parallelogram would be too high.
return MESH_PREDICTION_PARALLELOGRAM;
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
index 40a7683aa0d..b7e21224fad 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h
@@ -38,6 +38,10 @@ namespace draco {
PredictionSchemeMethod SelectPredictionMethod(int att_id,
const PointCloudEncoder *encoder);
+PredictionSchemeMethod SelectPredictionMethod(int att_id,
+ const EncoderOptions &options,
+ const PointCloudEncoder *encoder);
+
// Factory class for creating mesh prediction schemes.
template <typename DataTypeT>
struct MeshPredictionSchemeEncoderFactory {
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h
index ab64bce7114..37aa9f76a9c 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
-#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
+#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
+#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h"
#include "draco/core/encoder_buffer.h"
@@ -52,4 +52,4 @@ class PredictionSchemeTypedEncoderInterface
} // namespace draco
-#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_
+#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h
index 0a14d0d9ba4..e100c738a6c 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h
@@ -36,9 +36,25 @@ class PredictionSchemeWrapDecodingTransform
inline void ComputeOriginalValue(const DataTypeT *predicted_vals,
const CorrTypeT *corr_vals,
DataTypeT *out_original_vals) const {
+ // For now we assume both |DataTypeT| and |CorrTypeT| are equal.
+ static_assert(std::is_same<DataTypeT, CorrTypeT>::value,
+ "Predictions and corrections must have the same type.");
+
+ // The only valid implementation right now is for int32_t.
+ static_assert(std::is_same<DataTypeT, int32_t>::value,
+ "Only int32_t is supported for predicted values.");
+
predicted_vals = this->ClampPredictedValue(predicted_vals);
+
+ // Perform the wrapping using unsigned coordinates to avoid potential signed
+ // integer overflows caused by malformed input.
+ const uint32_t *const uint_predicted_vals =
+ reinterpret_cast<const uint32_t *>(predicted_vals);
+ const uint32_t *const uint_corr_vals =
+ reinterpret_cast<const uint32_t *>(corr_vals);
for (int i = 0; i < this->num_components(); ++i) {
- out_original_vals[i] = predicted_vals[i] + corr_vals[i];
+ out_original_vals[i] =
+ static_cast<DataTypeT>(uint_predicted_vals[i] + uint_corr_vals[i]);
if (out_original_vals[i] > this->max_value()) {
out_original_vals[i] -= this->max_dif();
} else if (out_original_vals[i] < this->min_value()) {
diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h
index 26f61fbaf6a..979c63c3d11 100644
--- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h
+++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h
@@ -73,7 +73,7 @@ class PredictionSchemeWrapTransformBase {
return &clamped_value_[0];
}
- // TODO(hemmer): Consider refactoring to avoid this dummy.
+ // TODO(b/199760123): Consider refactoring to avoid this dummy.
int quantization_bits() const {
DRACO_DCHECK(false);
return -1;
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
index 521935c1e99..7d5d1eeff26 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc
@@ -26,8 +26,8 @@ SequentialAttributeEncodersController::SequentialAttributeEncodersController(
: sequencer_(std::move(sequencer)) {}
SequentialAttributeEncodersController::SequentialAttributeEncodersController(
- std::unique_ptr<PointsSequencer> sequencer, int att_id)
- : AttributesEncoder(att_id), sequencer_(std::move(sequencer)) {}
+ std::unique_ptr<PointsSequencer> sequencer, int point_attrib_id)
+ : AttributesEncoder(point_attrib_id), sequencer_(std::move(sequencer)) {}
bool SequentialAttributeEncodersController::Init(PointCloudEncoder *encoder,
const PointCloud *pc) {
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc
index d01fb26aad4..17f32fc1612 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc
@@ -53,6 +53,11 @@ bool SequentialIntegerAttributeDecoder::DecodeValues(
if (!in_buffer->Decode(&prediction_transform_type)) {
return false;
}
+ // Check that decoded prediction scheme transform type is valid.
+ if (prediction_transform_type < PREDICTION_TRANSFORM_NONE ||
+ prediction_transform_type >= NUM_PREDICTION_SCHEME_TRANSFORM_TYPES) {
+ return false;
+ }
prediction_scheme_ = CreateIntPredictionScheme(
static_cast<PredictionSchemeMethod>(prediction_scheme_method),
static_cast<PredictionSchemeTransformType>(prediction_transform_type));
@@ -143,8 +148,9 @@ bool SequentialIntegerAttributeDecoder::DecodeIntegerValues(
return false;
}
for (size_t i = 0; i < num_values; ++i) {
- if (!in_buffer->Decode(portable_attribute_data + i, num_bytes))
+ if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) {
return false;
+ }
}
}
}
@@ -223,12 +229,13 @@ void SequentialIntegerAttributeDecoder::StoreTypedValues(uint32_t num_values) {
void SequentialIntegerAttributeDecoder::PreparePortableAttribute(
int num_entries, int num_components) {
- GeometryAttribute va;
- va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
+ GeometryAttribute ga;
+ ga.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32,
false, num_components * DataTypeLength(DT_INT32), 0);
- std::unique_ptr<PointAttribute> port_att(new PointAttribute(va));
+ std::unique_ptr<PointAttribute> port_att(new PointAttribute(ga));
port_att->SetIdentityMapping();
port_att->Reset(num_entries);
+ port_att->set_unique_id(attribute()->unique_id());
SetPortableAttribute(std::move(port_att));
}
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc
index 2889e0521a0..e66a0a8a40a 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc
@@ -81,6 +81,9 @@ bool SequentialIntegerAttributeEncoder::TransformAttributeToPortableFormat(
value_to_value_map[orig_att->mapped_index(point_ids[i])] =
AttributeValueIndex(i);
}
+ if (portable_att->is_mapping_identity()) {
+ portable_att->SetExplicitMapping(encoder()->point_cloud()->num_points());
+ }
// Go over all points of the original attribute and update the mapping in
// the portable attribute.
for (PointIndex i(0); i < encoder()->point_cloud()->num_points(); ++i) {
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc
index 017344393dc..de36c1c36f2 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc
@@ -14,18 +14,17 @@
//
#include "draco/compression/attributes/sequential_normal_attribute_decoder.h"
-#include "draco/attributes/attribute_octahedron_transform.h"
#include "draco/compression/attributes/normal_compression_utils.h"
namespace draco {
-SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder()
- : quantization_bits_(-1) {}
+SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder() {}
bool SequentialNormalAttributeDecoder::Init(PointCloudDecoder *decoder,
int attribute_id) {
- if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id))
+ if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) {
return false;
+ }
// Currently, this encoder works only for 3-component normal vectors.
if (attribute()->num_components() != 3) {
return false;
@@ -41,11 +40,13 @@ bool SequentialNormalAttributeDecoder::DecodeIntegerValues(
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
if (decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) {
- uint8_t quantization_bits;
- if (!in_buffer->Decode(&quantization_bits)) {
+ // Note: in older bitstreams, we do not have a PortableAttribute() decoded
+ // at this stage so we cannot pass it down to the DecodeParameters() call.
+ // It still works fine for octahedral transform because it does not need to
+ // use any data from the attribute.
+ if (!octahedral_transform_.DecodeParameters(*attribute(), in_buffer)) {
return false;
}
- quantization_bits_ = quantization_bits;
}
#endif
return SequentialIntegerAttributeDecoder::DecodeIntegerValues(point_ids,
@@ -56,39 +57,20 @@ bool SequentialNormalAttributeDecoder::DecodeDataNeededByPortableTransform(
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
if (decoder()->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 0)) {
// For newer file version, decode attribute transform data here.
- uint8_t quantization_bits;
- if (!in_buffer->Decode(&quantization_bits)) {
+ if (!octahedral_transform_.DecodeParameters(*GetPortableAttribute(),
+ in_buffer)) {
return false;
}
- quantization_bits_ = quantization_bits;
}
// Store the decoded transform data in portable attribute.
- AttributeOctahedronTransform octahedral_transform;
- octahedral_transform.SetParameters(quantization_bits_);
- return octahedral_transform.TransferToAttribute(portable_attribute());
+ return octahedral_transform_.TransferToAttribute(portable_attribute());
}
bool SequentialNormalAttributeDecoder::StoreValues(uint32_t num_points) {
// Convert all quantized values back to floats.
- const int num_components = attribute()->num_components();
- const int entry_size = sizeof(float) * num_components;
- float att_val[3];
- int quant_val_id = 0;
- int out_byte_pos = 0;
- const int32_t *const portable_attribute_data = GetPortableAttributeData();
- OctahedronToolBox octahedron_tool_box;
- if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_))
- return false;
- for (uint32_t i = 0; i < num_points; ++i) {
- const int32_t s = portable_attribute_data[quant_val_id++];
- const int32_t t = portable_attribute_data[quant_val_id++];
- octahedron_tool_box.QuantizedOctaherdalCoordsToUnitVector(s, t, att_val);
- // Store the decoded floating point value into the attribute buffer.
- attribute()->buffer()->Write(out_byte_pos, att_val, entry_size);
- out_byte_pos += entry_size;
- }
- return true;
+ return octahedral_transform_.InverseTransformAttribute(
+ *GetPortableAttribute(), attribute());
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h
index 860eacb4c84..8c2d801b763 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h
@@ -15,6 +15,7 @@
#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_
#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_
+#include "draco/attributes/attribute_octahedron_transform.h"
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h"
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h"
#include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h"
@@ -42,7 +43,7 @@ class SequentialNormalAttributeDecoder
bool StoreValues(uint32_t num_points) override;
private:
- int32_t quantization_bits_;
+ AttributeOctahedronTransform octahedral_transform_;
std::unique_ptr<PredictionSchemeTypedDecoderInterface<int32_t>>
CreateIntPredictionScheme(
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc
index 23fa8bb7b39..3c5ef0ebcbc 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc
@@ -20,8 +20,9 @@ namespace draco {
bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder,
int attribute_id) {
- if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id))
+ if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) {
return false;
+ }
// Currently this encoder works only for 3-component normal vectors.
if (attribute()->num_components() != 3) {
return false;
@@ -44,9 +45,13 @@ bool SequentialNormalAttributeEncoder::EncodeDataNeededByPortableTransform(
bool SequentialNormalAttributeEncoder::PrepareValues(
const std::vector<PointIndex> &point_ids, int num_points) {
- SetPortableAttribute(
- attribute_octahedron_transform_.GeneratePortableAttribute(
- *(attribute()), point_ids, num_points));
+ auto portable_att = attribute_octahedron_transform_.InitTransformedAttribute(
+ *(attribute()), point_ids.size());
+ if (!attribute_octahedron_transform_.TransformAttribute(
+ *(attribute()), point_ids, portable_att.get())) {
+ return false;
+ }
+ SetPortableAttribute(std::move(portable_att));
return true;
}
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc
index bf925c4a595..3d306e7dae6 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc
@@ -14,13 +14,12 @@
//
#include "draco/compression/attributes/sequential_quantization_attribute_decoder.h"
-#include "draco/attributes/attribute_quantization_transform.h"
#include "draco/core/quantization_utils.h"
namespace draco {
-SequentialQuantizationAttributeDecoder::SequentialQuantizationAttributeDecoder()
- : quantization_bits_(-1), max_value_dif_(0.f) {}
+SequentialQuantizationAttributeDecoder::
+ SequentialQuantizationAttributeDecoder() {}
bool SequentialQuantizationAttributeDecoder::Init(PointCloudDecoder *decoder,
int attribute_id) {
@@ -59,62 +58,31 @@ bool SequentialQuantizationAttributeDecoder::
}
// Store the decoded transform data in portable attribute;
- AttributeQuantizationTransform transform;
- transform.SetParameters(quantization_bits_, min_value_.get(),
- attribute()->num_components(), max_value_dif_);
- return transform.TransferToAttribute(portable_attribute());
+ return quantization_transform_.TransferToAttribute(portable_attribute());
}
-bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_values) {
- return DequantizeValues(num_values);
+bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_points) {
+ return DequantizeValues(num_points);
}
bool SequentialQuantizationAttributeDecoder::DecodeQuantizedDataInfo() {
- const int num_components = attribute()->num_components();
- min_value_ = std::unique_ptr<float[]>(new float[num_components]);
- if (!decoder()->buffer()->Decode(min_value_.get(),
- sizeof(float) * num_components)) {
- return false;
- }
- if (!decoder()->buffer()->Decode(&max_value_dif_)) {
- return false;
+ // Get attribute used as source for decoding.
+ auto att = GetPortableAttribute();
+ if (att == nullptr) {
+ // This should happen only in the backward compatibility mode. It will still
+ // work fine for this case because the only thing the quantization transform
+ // cares about is the number of components that is the same for both source
+ // and target attributes.
+ att = attribute();
}
- uint8_t quantization_bits;
- if (!decoder()->buffer()->Decode(&quantization_bits) ||
- quantization_bits > 31) {
- return false;
- }
- quantization_bits_ = quantization_bits;
- return true;
+ return quantization_transform_.DecodeParameters(*att, decoder()->buffer());
}
bool SequentialQuantizationAttributeDecoder::DequantizeValues(
uint32_t num_values) {
// Convert all quantized values back to floats.
- const int32_t max_quantized_value =
- (1u << static_cast<uint32_t>(quantization_bits_)) - 1;
- const int num_components = attribute()->num_components();
- const int entry_size = sizeof(float) * num_components;
- const std::unique_ptr<float[]> att_val(new float[num_components]);
- int quant_val_id = 0;
- int out_byte_pos = 0;
- Dequantizer dequantizer;
- if (!dequantizer.Init(max_value_dif_, max_quantized_value)) {
- return false;
- }
- const int32_t *const portable_attribute_data = GetPortableAttributeData();
- for (uint32_t i = 0; i < num_values; ++i) {
- for (int c = 0; c < num_components; ++c) {
- float value =
- dequantizer.DequantizeFloat(portable_attribute_data[quant_val_id++]);
- value = value + min_value_[c];
- att_val[c] = value;
- }
- // Store the floating point value into the attribute buffer.
- attribute()->buffer()->Write(out_byte_pos, att_val.get(), entry_size);
- out_byte_pos += entry_size;
- }
- return true;
+ return quantization_transform_.InverseTransformAttribute(
+ *GetPortableAttribute(), attribute());
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h
index c0b7637a750..ad372dcd8a6 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h
@@ -15,6 +15,7 @@
#ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_
#define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_
+#include "draco/attributes/attribute_quantization_transform.h"
#include "draco/compression/attributes/sequential_integer_attribute_decoder.h"
#include "draco/draco_features.h"
@@ -43,12 +44,7 @@ class SequentialQuantizationAttributeDecoder
virtual bool DequantizeValues(uint32_t num_values);
private:
- // Max number of quantization bits used to encode each component of the
- // attribute.
- int32_t quantization_bits_;
-
- std::unique_ptr<float[]> min_value_;
- float max_value_dif_;
+ AttributeQuantizationTransform quantization_transform_;
};
} // namespace draco
diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc
index cd5b8b141e0..d3666f7a411 100644
--- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc
@@ -50,9 +50,11 @@ bool SequentialQuantizationAttributeEncoder::Init(PointCloudEncoder *encoder,
&quantization_origin[0]);
const float range = encoder->options()->GetAttributeFloat(
attribute_id, "quantization_range", 1.f);
- attribute_quantization_transform_.SetParameters(
- quantization_bits, quantization_origin.data(),
- attribute->num_components(), range);
+ if (!attribute_quantization_transform_.SetParameters(
+ quantization_bits, quantization_origin.data(),
+ attribute->num_components(), range)) {
+ return false;
+ }
} else {
// Compute quantization settings from the attribute values.
if (!attribute_quantization_transform_.ComputeParameters(
@@ -70,9 +72,14 @@ bool SequentialQuantizationAttributeEncoder::
bool SequentialQuantizationAttributeEncoder::PrepareValues(
const std::vector<PointIndex> &point_ids, int num_points) {
- SetPortableAttribute(
- attribute_quantization_transform_.GeneratePortableAttribute(
- *(attribute()), point_ids, num_points));
+ auto portable_attribute =
+ attribute_quantization_transform_.InitTransformedAttribute(
+ *attribute(), point_ids.size());
+ if (!attribute_quantization_transform_.TransformAttribute(
+ *(attribute()), point_ids, portable_attribute.get())) {
+ return false;
+ }
+ SetPortableAttribute(std::move(portable_attribute));
return true;
}
diff --git a/extern/draco/draco/src/draco/compression/config/compression_shared.h b/extern/draco/draco/src/draco/compression/config/compression_shared.h
index 40061d3cd48..c43f303bd15 100644
--- a/extern/draco/draco/src/draco/compression/config/compression_shared.h
+++ b/extern/draco/draco/src/draco/compression/config/compression_shared.h
@@ -42,6 +42,7 @@ enum EncodedGeometryType {
INVALID_GEOMETRY_TYPE = -1,
POINT_CLOUD = 0,
TRIANGULAR_MESH,
+ NUM_ENCODED_GEOMETRY_TYPES
};
// List of encoding methods for point clouds.
@@ -105,6 +106,8 @@ enum PredictionSchemeTransformType {
// Specialized transform for normal coordinates using canonicalized inverted
// tiles.
PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED = 3,
+ // The number of valid (non-negative) prediction scheme transform types.
+ NUM_PREDICTION_SCHEME_TRANSFORM_TYPES
};
// List of all mesh traversal methods supported by Draco framework.
diff --git a/extern/draco/draco/src/draco/compression/config/draco_options.h b/extern/draco/draco/src/draco/compression/config/draco_options.h
index 0d1247b2ad1..2bd4a3b6761 100644
--- a/extern/draco/draco/src/draco/compression/config/draco_options.h
+++ b/extern/draco/draco/src/draco/compression/config/draco_options.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
-#define DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
+#ifndef DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
+#define DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
#include <map>
#include <memory>
@@ -246,4 +246,4 @@ void DracoOptions<AttributeKeyT>::SetAttributeOptions(
} // namespace draco
-#endif // DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
+#endif // DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_
diff --git a/extern/draco/draco/src/draco/compression/decode.cc b/extern/draco/draco/src/draco/compression/decode.cc
index ab70ef1ec60..92ae4ff66f9 100644
--- a/extern/draco/draco/src/draco/compression/decode.cc
+++ b/extern/draco/draco/src/draco/compression/decode.cc
@@ -56,7 +56,10 @@ StatusOr<EncodedGeometryType> Decoder::GetEncodedGeometryType(
DecoderBuffer *in_buffer) {
DecoderBuffer temp_buffer(*in_buffer);
DracoHeader header;
- DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header))
+ DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header));
+ if (header.encoder_type >= NUM_ENCODED_GEOMETRY_TYPES) {
+ return Status(Status::DRACO_ERROR, "Unsupported geometry type.");
+ }
return static_cast<EncodedGeometryType>(header.encoder_type);
}
diff --git a/extern/draco/draco/src/draco/compression/encode_base.h b/extern/draco/draco/src/draco/compression/encode_base.h
index 0c63a972bf4..6211efc221b 100644
--- a/extern/draco/draco/src/draco/compression/encode_base.h
+++ b/extern/draco/draco/src/draco/compression/encode_base.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
-#define DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
+#ifndef DRACO_COMPRESSION_ENCODE_BASE_H_
+#define DRACO_COMPRESSION_ENCODE_BASE_H_
#include "draco/attributes/geometry_attribute.h"
#include "draco/compression/config/compression_shared.h"
@@ -98,7 +98,7 @@ class EncoderBase {
"Invalid prediction scheme for attribute type.");
}
}
- // TODO(hemmer): Try to enable more prediction schemes for normals.
+ // TODO(b/199760123): Try to enable more prediction schemes for normals.
if (att_type == GeometryAttribute::NORMAL) {
if (!(prediction_scheme == PREDICTION_DIFFERENCE ||
prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) {
@@ -128,4 +128,4 @@ void EncoderBase<EncoderOptionsT>::SetTrackEncodedProperties(bool flag) {
} // namespace draco
-#endif // DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_
+#endif // DRACO_COMPRESSION_ENCODE_BASE_H_
diff --git a/extern/draco/draco/src/draco/compression/entropy/ans.h b/extern/draco/draco/src/draco/compression/entropy/ans.h
index c765256b96e..313546fee20 100644
--- a/extern/draco/draco/src/draco/compression/entropy/ans.h
+++ b/extern/draco/draco/src/draco/compression/entropy/ans.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_CORE_ANS_H_
-#define DRACO_CORE_ANS_H_
+#ifndef DRACO_COMPRESSION_ENTROPY_ANS_H_
+#define DRACO_COMPRESSION_ENTROPY_ANS_H_
// An implementation of Asymmetric Numeral Systems (rANS).
// See http://arxiv.org/abs/1311.2540v2 for more information on rANS.
// This file is based off libvpx's ans.h.
@@ -391,7 +391,6 @@ class RAnsEncoder {
ans_.buf[ans_.buf_offset++] = ans_.state % DRACO_ANS_IO_BASE;
ans_.state /= DRACO_ANS_IO_BASE;
}
- // TODO(ostava): The division and multiplication should be optimized.
ans_.state =
(ans_.state / p) * rans_precision + ans_.state % p + sym->cum_prob;
}
@@ -524,4 +523,4 @@ class RAnsDecoder {
} // namespace draco
-#endif // DRACO_CORE_ANS_H_
+#endif // DRACO_COMPRESSION_ENTROPY_ANS_H_
diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h
index 0a68e29fe26..cd4271193bf 100644
--- a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h
+++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h
@@ -31,11 +31,10 @@ constexpr int ComputeRAnsUnclampedPrecision(int symbols_bit_length) {
// our rANS library (which is between 12 to 20 bits).
constexpr int ComputeRAnsPrecisionFromUniqueSymbolsBitLength(
int symbols_bit_length) {
- return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12
- ? 12
- : ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20
- ? 20
- : ComputeRAnsUnclampedPrecision(symbols_bit_length);
+ return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12 ? 12
+ : ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20
+ ? 20
+ : ComputeRAnsUnclampedPrecision(symbols_bit_length);
}
// Compute approximate frequency table size needed for storing the provided
diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h
index 4e07ec87123..4b738b50a9d 100644
--- a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h
+++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h
@@ -125,8 +125,8 @@ bool RAnsSymbolEncoder<unique_symbols_bit_length_t>::Create(
for (int i = 0; i < num_symbols; ++i) {
sorted_probabilities[i] = i;
}
- std::sort(sorted_probabilities.begin(), sorted_probabilities.end(),
- ProbabilityLess(&probability_table_));
+ std::stable_sort(sorted_probabilities.begin(), sorted_probabilities.end(),
+ ProbabilityLess(&probability_table_));
if (total_rans_prob < rans_precision_) {
// This happens rather infrequently, just add the extra needed precision
// to the most frequent symbol.
diff --git a/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc b/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc
index 93d29971c89..79e81181830 100644
--- a/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc
+++ b/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc
@@ -72,7 +72,7 @@ bool DecodeTaggedSymbols(uint32_t num_values, int num_components,
int value_id = 0;
for (uint32_t i = 0; i < num_values; i += num_components) {
// Decode the tag.
- const int bit_length = tag_decoder.DecodeSymbol();
+ const uint32_t bit_length = tag_decoder.DecodeSymbol();
// Decode the actual value.
for (int j = 0; j < num_components; ++j) {
uint32_t val;
diff --git a/extern/draco/draco/src/draco/compression/expert_encode.cc b/extern/draco/draco/src/draco/compression/expert_encode.cc
index 4c70a72a765..f9aec15eb27 100644
--- a/extern/draco/draco/src/draco/compression/expert_encode.cc
+++ b/extern/draco/draco/src/draco/compression/expert_encode.cc
@@ -67,7 +67,7 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc,
kd_tree_possible = false;
}
if (kd_tree_possible && att->data_type() == DT_FLOAT32 &&
- options().GetAttributeInt(0, "quantization_bits", -1) <= 0) {
+ options().GetAttributeInt(i, "quantization_bits", -1) <= 0) {
kd_tree_possible = false; // Quantization not enabled.
}
if (!kd_tree_possible) {
diff --git a/extern/draco/draco/src/draco/compression/expert_encode.h b/extern/draco/draco/src/draco/compression/expert_encode.h
index a1aa7b8b3a8..ea59393d3d2 100644
--- a/extern/draco/draco/src/draco/compression/expert_encode.h
+++ b/extern/draco/draco/src/draco/compression/expert_encode.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
-#define DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
+#ifndef DRACO_COMPRESSION_EXPERT_ENCODE_H_
+#define DRACO_COMPRESSION_EXPERT_ENCODE_H_
#include "draco/compression/config/compression_shared.h"
#include "draco/compression/config/encoder_options.h"
@@ -144,4 +144,4 @@ class ExpertEncoder : public EncoderBase<EncoderOptions> {
} // namespace draco
-#endif // DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_
+#endif // DRACO_COMPRESSION_EXPERT_ENCODE_H_
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc
index 50d1971c15b..6d22e2f2a32 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc
@@ -162,6 +162,10 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::CreateAttributesDecoder(
if (!decoder_->buffer()->Decode(&traversal_method_encoded)) {
return false;
}
+ // Check that decoded traversal method is valid.
+ if (traversal_method_encoded >= NUM_TRAVERSAL_METHODS) {
+ return false;
+ }
traversal_method =
static_cast<MeshTraversalMethod>(traversal_method_encoded);
}
@@ -450,7 +454,7 @@ bool MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity() {
#endif
// Decode connectivity of non-position attributes.
- if (attribute_data_.size() > 0) {
+ if (!attribute_data_.empty()) {
#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
if (decoder_->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 1)) {
for (CornerIndex ci(0); ci < corner_table_->num_corners(); ci += 3) {
@@ -577,11 +581,16 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
SetOppositeCorners(corner_b, corner + 2);
// Update vertex mapping.
- corner_table_->MapCornerToVertex(corner, vertex_x);
- corner_table_->MapCornerToVertex(
- corner + 1, corner_table_->Vertex(corner_table_->Next(corner_b)));
const VertexIndex vert_a_prev =
corner_table_->Vertex(corner_table_->Previous(corner_a));
+ const VertexIndex vert_b_next =
+ corner_table_->Vertex(corner_table_->Next(corner_b));
+ if (vertex_x == vert_a_prev || vertex_x == vert_b_next) {
+ // Encoding is invalid, because face vertices are degenerate.
+ return -1;
+ }
+ corner_table_->MapCornerToVertex(corner, vertex_x);
+ corner_table_->MapCornerToVertex(corner + 1, vert_b_next);
corner_table_->MapCornerToVertex(corner + 2, vert_a_prev);
corner_table_->SetLeftMostCorner(vert_a_prev, corner + 2);
// Mark the vertex |x| as interior.
@@ -791,7 +800,7 @@ int MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeConnectivity(
return -1; // Unexpected number of decoded vertices.
}
// Decode start faces and connect them to the faces from the active stack.
- while (active_corner_stack.size() > 0) {
+ while (!active_corner_stack.empty()) {
const CornerIndex corner = active_corner_stack.back();
active_corner_stack.pop_back();
const bool interior_face =
@@ -952,9 +961,13 @@ MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeHoleAndTopologySplitEvents(
for (uint32_t i = 0; i < num_topology_splits; ++i) {
TopologySplitEventData event_data;
uint32_t delta;
- DecodeVarint<uint32_t>(&delta, decoder_buffer);
+ if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
+ return -1;
+ }
event_data.source_symbol_id = delta + last_source_symbol_id;
- DecodeVarint<uint32_t>(&delta, decoder_buffer);
+ if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
+ return -1;
+ }
if (delta > event_data.source_symbol_id) {
return -1;
}
@@ -1009,7 +1022,9 @@ MeshEdgebreakerDecoderImpl<TraversalDecoder>::DecodeHoleAndTopologySplitEvents(
for (uint32_t i = 0; i < num_hole_events; ++i) {
HoleEventData event_data;
uint32_t delta;
- DecodeVarint<uint32_t>(&delta, decoder_buffer);
+ if (!DecodeVarint<uint32_t>(&delta, decoder_buffer)) {
+ return -1;
+ }
event_data.symbol_id = delta + last_symbol_id;
last_symbol_id = event_data.symbol_id;
hole_event_data_.push_back(event_data);
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
index 5aff5d8cc10..a7f381480f1 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc
@@ -31,7 +31,6 @@ bool MeshEdgebreakerEncoder::InitializeEncoder() {
impl_ = nullptr;
// For tiny meshes it's usually better to use the basic edgebreaker as the
// overhead of the predictive one may turn out to be too big.
- // TODO(b/111065939): Check if this can be improved.
const bool is_tiny_mesh = mesh()->num_faces() < 1000;
int selected_edgebreaker_method =
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
index 0791dc6705a..4bf6aa92070 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc
@@ -408,7 +408,7 @@ Status MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() {
init_face_connectivity_corners.begin(),
init_face_connectivity_corners.end());
// Encode connectivity for all non-position attributes.
- if (attribute_data_.size() > 0) {
+ if (!attribute_data_.empty()) {
// Use the same order of corner that will be used by the decoder.
visited_faces_.assign(mesh_->num_faces(), false);
for (CornerIndex ci : processed_connectivity_corners_) {
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
index fb33771637e..979e1d373d8 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h
@@ -177,7 +177,6 @@ class MeshEdgebreakerEncoderImpl : public MeshEdgebreakerEncoderImplInterface {
uint32_t num_split_symbols_;
// Struct holding data used for encoding each non-position attribute.
- // TODO(ostava): This should be probably renamed to something better.
struct AttributeData {
AttributeData() : attribute_index(-1), is_connectivity_used(true) {}
int attribute_index;
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h
index cb3c29dd669..c650bc35210 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h
@@ -50,8 +50,6 @@ namespace draco {
// \ / S \ / / E \
// *-------* *-------*
//
-// TODO(ostava): Get rid of the topology bit pattern. It's important only for
-// encoding but the algorithms should use EdgebreakerSymbol instead.
enum EdgebreakerTopologyBitPattern {
TOPOLOGY_C = 0x0, // 0
TOPOLOGY_S = 0x1, // 1 0 0
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h
index 621883a5f1f..c00373727df 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h
@@ -106,7 +106,12 @@ class MeshEdgebreakerTraversalValenceDecoder
context_counters_.resize(context_symbols_.size());
for (int i = 0; i < context_symbols_.size(); ++i) {
uint32_t num_symbols;
- DecodeVarint<uint32_t>(&num_symbols, out_buffer);
+ if (!DecodeVarint<uint32_t>(&num_symbols, out_buffer)) {
+ return false;
+ }
+ if (num_symbols > static_cast<uint32_t>(corner_table_->num_faces())) {
+ return false;
+ }
if (num_symbols > 0) {
context_symbols_[i].resize(num_symbols);
DecodeSymbols(num_symbols, 1, out_buffer, context_symbols_[i].data());
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc
index 53f5e8651b8..fbc7383eef1 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc
@@ -53,6 +53,11 @@ bool MeshSequentialDecoder::DecodeConnectivity() {
if (faces_64 > 0xffffffff / 3) {
return false;
}
+ if (faces_64 > buffer()->remaining_size() / 3) {
+ // The number of faces is unreasonably high, because face indices do not
+ // fit in the remaining size of the buffer.
+ return false;
+ }
if (points_64 > faces_64 * 3) {
return false;
}
@@ -91,7 +96,7 @@ bool MeshSequentialDecoder::DecodeConnectivity() {
}
mesh()->AddFace(face);
}
- } else if (mesh()->num_points() < (1 << 21) &&
+ } else if (num_points < (1 << 21) &&
bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 2)) {
// Decode indices as uint32_t.
for (uint32_t i = 0; i < num_faces; ++i) {
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc
index 02ac7779ea3..fd8b1139253 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc
@@ -32,8 +32,6 @@ Status MeshSequentialEncoder::EncodeConnectivity() {
EncodeVarint(static_cast<uint32_t>(mesh()->num_points()), buffer());
// We encode all attributes in the original (possibly duplicated) format.
- // TODO(ostava): This may not be optimal if we have only one attribute or if
- // all attributes share the same index mapping.
if (options()->GetGlobalBool("compress_connectivity", false)) {
// 0 = Encode compressed indices.
buffer()->Encode(static_cast<uint8_t>(0));
@@ -44,8 +42,6 @@ Status MeshSequentialEncoder::EncodeConnectivity() {
// 1 = Encode indices directly.
buffer()->Encode(static_cast<uint8_t>(1));
// Store vertex indices using a smallest data type that fits their range.
- // TODO(ostava): This can be potentially improved by using a tighter
- // fit that is not bound by a bit-length of any particular data type.
if (mesh()->num_points() < 256) {
// Serialize indices as uint8_t.
for (FaceIndex i(0); i < num_faces; ++i) {
diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h
index 672609642b0..6e2b05877ab 100644
--- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h
+++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h
@@ -33,7 +33,6 @@ namespace draco {
// Class that encodes mesh data using a simple binary representation of mesh's
// connectivity and geometry.
-// TODO(ostava): Use a better name.
class MeshSequentialEncoder : public MeshEncoder {
public:
MeshSequentialEncoder();
diff --git a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h
index e66dd14b238..dd9738ba2d5 100644
--- a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h
+++ b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h
@@ -25,7 +25,7 @@ namespace draco {
// values based on the traversal of the encoded mesh. The class should be used
// as the TraversalObserverT member of a Traverser class such as the
// DepthFirstTraverser (depth_first_traverser.h).
-// TODO(hemmer): rename to AttributeIndicesCodingTraverserObserver
+// TODO(b/199760123): Rename to AttributeIndicesCodingTraverserObserver.
template <class CornerTableT>
class MeshAttributeIndicesEncodingObserver {
public:
diff --git a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h
index ebe1d5f7a9e..e55c93a7969 100644
--- a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h
+++ b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h
@@ -25,7 +25,7 @@ namespace draco {
// Sequencer that generates point sequence in an order given by a deterministic
// traversal on the mesh surface. Note that all attributes encoded with this
// sequence must share the same connectivity.
-// TODO(hemmer): Consider refactoring such that this is an observer.
+// TODO(b/199760123): Consider refactoring such that this is an observer.
template <class TraverserT>
class MeshTraversalSequencer : public PointsSequencer {
public:
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
index 87bc2b7ef3e..fa1b1e203e5 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h
@@ -227,7 +227,7 @@ bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodeInternal(
std::stack<Status> status_stack;
status_stack.push(init_status);
- // TODO(hemmer): use preallocated vector instead of stack.
+ // TODO(b/199760123): Use preallocated vector instead of stack.
while (!status_stack.empty()) {
const DecodingStatus status = status_stack.top();
status_stack.pop();
@@ -263,7 +263,8 @@ bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodeInternal(
// Fast decoding of remaining bits if number of points is 1 or 2.
if (num_remaining_points <= 2) {
- // TODO(hemmer): axes_ not necessary, remove would change bitstream!
+ // TODO(b/199760123): |axes_| not necessary, remove would change
+ // bitstream!
axes_[0] = axis;
for (uint32_t i = 1; i < dimension_; i++) {
axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_);
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h
index 14fa32d7083..65b3d07a6ad 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h
@@ -280,7 +280,7 @@ void DynamicIntegerPointsKdTreeEncoder<compression_level_t>::EncodeInternal(
std::stack<Status> status_stack;
status_stack.push(init_status);
- // TODO(hemmer): use preallocated vector instead of stack.
+ // TODO(b/199760123): Use preallocated vector instead of stack.
while (!status_stack.empty()) {
Status status = status_stack.top();
status_stack.pop();
@@ -305,7 +305,8 @@ void DynamicIntegerPointsKdTreeEncoder<compression_level_t>::EncodeInternal(
// Fast encoding of remaining bits if number of points is 1 or 2.
// Doing this also for 2 gives a slight additional speed up.
if (num_remaining_points <= 2) {
- // TODO(hemmer): axes_ not necessary, remove would change bitstream!
+ // TODO(b/199760123): |axes_| not necessary, remove would change
+ // bitstream!
axes_[0] = axis;
for (uint32_t i = 1; i < dimension_; i++) {
axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_);
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc
index 9e8d895f176..dffaa4c8d20 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc
@@ -69,18 +69,29 @@ FloatPointsTreeDecoder::FloatPointsTreeDecoder()
bool FloatPointsTreeDecoder::DecodePointCloudKdTreeInternal(
DecoderBuffer *buffer, std::vector<Point3ui> *qpoints) {
- if (!buffer->Decode(&qinfo_.quantization_bits)) return false;
- if (qinfo_.quantization_bits > 31) return false;
- if (!buffer->Decode(&qinfo_.range)) return false;
- if (!buffer->Decode(&num_points_)) return false;
- if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_)
+ if (!buffer->Decode(&qinfo_.quantization_bits)) {
return false;
- if (!buffer->Decode(&compression_level_)) return false;
+ }
+ if (qinfo_.quantization_bits > 31) {
+ return false;
+ }
+ if (!buffer->Decode(&qinfo_.range)) {
+ return false;
+ }
+ if (!buffer->Decode(&num_points_)) {
+ return false;
+ }
+ if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_) {
+ return false;
+ }
+ if (!buffer->Decode(&compression_level_)) {
+ return false;
+ }
// Only allow compression level in [0..6].
if (6 < compression_level_) {
- LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n",
- compression_level_);
+ DRACO_LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n",
+ compression_level_);
return false;
}
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h
index 26ba94f1f59..44c1b3d3a97 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h
@@ -44,7 +44,7 @@ namespace draco {
// there are more leading zeros, which is then compressed better by the
// arithmetic encoding.
-// TODO(hemmer): Remove class because it duplicates quantization code.
+// TODO(b/199760123): Remove class because it duplicates quantization code.
class FloatPointsTreeEncoder {
public:
explicit FloatPointsTreeEncoder(PointCloudCompressionMethod method);
@@ -91,7 +91,7 @@ bool FloatPointsTreeEncoder::EncodePointCloud(InputIteratorT points_begin,
// Collect necessary data for encoding.
num_points_ = std::distance(points_begin, points_end);
- // TODO(hemmer): Extend quantization tools to make this more automatic.
+ // TODO(b/199760123): Extend quantization tools to make this more automatic.
// Compute range of points for quantization
std::vector<Point3ui> qpoints;
qpoints.reserve(num_points_);
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h
index 94e523cadaf..bc31af58613 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-// TODO(hemmer): Make this a wrapper using DynamicIntegerPointsKdTreeDecoder.
+// TODO(b/199760123): Make this a wrapper using
+// DynamicIntegerPointsKdTreeDecoder.
//
// See integer_points_kd_tree_encoder.h for documentation.
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h
index b8811092ed7..654f14a7866 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h
@@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-// TODO(hemmer): Make this a wrapper using DynamicIntegerPointsKdTreeEncoder.
+// TODO(b/199760123): Make this a wrapper using
+// DynamicIntegerPointsKdTreeEncoder.
#ifndef DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_
#define DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h
index 01943ad9e6c..04aa1d95e11 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h
+++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h
@@ -22,7 +22,7 @@
namespace draco {
-// TODO(hemmer): Make this a stable bounding box.
+// TODO(b/199760123): Make this a stable bounding box.
struct QuantizationInfo {
uint32_t quantization_bits;
float range;
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc
index 5196edf960c..85f7bc94e33 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc
+++ b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc
@@ -88,7 +88,9 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options,
const uint8_t max_supported_minor_version =
header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMinor
: kDracoMeshBitstreamVersionMinor;
+
// Check for version compatibility.
+#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED
if (version_major_ < 1 || version_major_ > max_supported_major_version) {
return Status(Status::UNKNOWN_VERSION, "Unknown major version.");
}
@@ -96,6 +98,14 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options,
version_minor_ > max_supported_minor_version) {
return Status(Status::UNKNOWN_VERSION, "Unknown minor version.");
}
+#else
+ if (version_major_ != max_supported_major_version) {
+ return Status(Status::UNKNOWN_VERSION, "Unsupported major version.");
+ }
+ if (version_minor_ != max_supported_minor_version) {
+ return Status(Status::UNKNOWN_VERSION, "Unsupported minor version.");
+ }
+#endif
buffer_->set_bitstream_version(
DRACO_BITSTREAM_VERSION(version_major_, version_minor_));
diff --git a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc
index b4b0ee94093..a1fda8d5a50 100644
--- a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc
+++ b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc
@@ -62,12 +62,14 @@ Status PointCloudEncoder::EncodeHeader() {
buffer_->Encode("DRACO", 5);
// Version (major, minor).
const uint8_t encoder_type = GetGeometryType();
- const uint8_t version_major = encoder_type == POINT_CLOUD
- ? kDracoPointCloudBitstreamVersionMajor
- : kDracoMeshBitstreamVersionMajor;
- const uint8_t version_minor = encoder_type == POINT_CLOUD
- ? kDracoPointCloudBitstreamVersionMinor
- : kDracoMeshBitstreamVersionMinor;
+ uint8_t version_major, version_minor;
+ version_major = encoder_type == POINT_CLOUD
+ ? kDracoPointCloudBitstreamVersionMajor
+ : kDracoMeshBitstreamVersionMajor;
+ version_minor = encoder_type == POINT_CLOUD
+ ? kDracoPointCloudBitstreamVersionMinor
+ : kDracoMeshBitstreamVersionMinor;
+
buffer_->Encode(version_major);
buffer_->Encode(version_minor);
// Type of the encoder (point cloud, mesh, ...).
diff --git a/extern/draco/draco/src/draco/core/bounding_box.cc b/extern/draco/draco/src/draco/core/bounding_box.cc
index d95b1e90759..be0d209d857 100644
--- a/extern/draco/draco/src/draco/core/bounding_box.cc
+++ b/extern/draco/draco/src/draco/core/bounding_box.cc
@@ -16,8 +16,15 @@
namespace draco {
-BoundingBox::BoundingBox(const Vector3f &min_point_in,
- const Vector3f &max_point_in)
- : min_point_(min_point_in), max_point_(max_point_in) {}
+BoundingBox::BoundingBox()
+ : BoundingBox(Vector3f(std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max()),
+ Vector3f(std::numeric_limits<float>::lowest(),
+ std::numeric_limits<float>::lowest(),
+ std::numeric_limits<float>::lowest())) {}
+
+BoundingBox::BoundingBox(const Vector3f &min_point, const Vector3f &max_point)
+ : min_point_(min_point), max_point_(max_point) {}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/core/bounding_box.h b/extern/draco/draco/src/draco/core/bounding_box.h
index 1c20fad8bf2..31ba2d68340 100644
--- a/extern/draco/draco/src/draco/core/bounding_box.h
+++ b/extern/draco/draco/src/draco/core/bounding_box.h
@@ -19,22 +19,27 @@
namespace draco {
-// Class for detecting the bounding box of a point_cloud or mesh.
-// Use the minimum point and the maximum point to define the bounding box.
-// TODO(xiaoxumeng): Change the class of BoundingBox to a template, similar to
-// draco/src/draco/core/vector_d.h
+// Class for computing the bounding box of points in 3D space.
class BoundingBox {
public:
- // Initialization
- BoundingBox(const Vector3f &min_point_in, const Vector3f &max_point_in);
+ // Creates bounding box object with minimum and maximum points initialized to
+ // the largest positive and the smallest negative values, respectively. The
+ // resulting abstract bounding box effectively has no points and can be
+ // updated by providing any point to Update() method.
+ BoundingBox();
- inline const Vector3f &min_point() const { return min_point_; }
- inline const Vector3f &max_point() const { return max_point_; }
+ // Creates bounding box object with minimum and maximum points initialized to
+ // |min_point| and |max_point|, respectively.
+ BoundingBox(const Vector3f &min_point, const Vector3f &max_point);
- // Conditionally updates the bounding box.
- // TODO(xiaoxumeng): Change the function to a template function and change the
- // argument to an iterator.
- inline void update_bounding_box(const Vector3f &new_point) {
+ // Returns the minimum point of the bounding box.
+ inline const Vector3f &GetMinPoint() const { return min_point_; }
+
+ // Returns the maximum point of the bounding box.
+ inline const Vector3f &GetMaxPoint() const { return max_point_; }
+
+ // Conditionally updates the bounding box with a given |new_point|.
+ void Update(const Vector3f &new_point) {
for (int i = 0; i < 3; i++) {
if (new_point[i] < min_point_[i]) {
min_point_[i] = new_point[i];
@@ -45,6 +50,19 @@ class BoundingBox {
}
}
+ // Updates bounding box with minimum and maximum points of the |other|
+ // bounding box.
+ void Update(const BoundingBox &other) {
+ Update(other.GetMinPoint());
+ Update(other.GetMaxPoint());
+ }
+
+ // Returns the size of the bounding box along each axis.
+ Vector3f Size() const { return max_point_ - min_point_; }
+
+ // Returns the center of the bounding box.
+ Vector3f Center() const { return (min_point_ + max_point_) / 2; }
+
private:
Vector3f min_point_;
Vector3f max_point_;
diff --git a/extern/draco/draco/src/draco/core/cycle_timer.cc b/extern/draco/draco/src/draco/core/cycle_timer.cc
index 94b4b28b2f9..58df4df77de 100644
--- a/extern/draco/draco/src/draco/core/cycle_timer.cc
+++ b/extern/draco/draco/src/draco/core/cycle_timer.cc
@@ -17,31 +17,31 @@
namespace draco {
void DracoTimer::Start() {
#ifdef _WIN32
- QueryPerformanceCounter(&tv_start);
+ QueryPerformanceCounter(&tv_start_);
#else
- gettimeofday(&tv_start, nullptr);
+ gettimeofday(&tv_start_, nullptr);
#endif
}
void DracoTimer::Stop() {
#ifdef _WIN32
- QueryPerformanceCounter(&tv_end);
+ QueryPerformanceCounter(&tv_end_);
#else
- gettimeofday(&tv_end, nullptr);
+ gettimeofday(&tv_end_, nullptr);
#endif
}
int64_t DracoTimer::GetInMs() {
#ifdef _WIN32
LARGE_INTEGER elapsed = {0};
- elapsed.QuadPart = tv_end.QuadPart - tv_start.QuadPart;
+ elapsed.QuadPart = tv_end_.QuadPart - tv_start_.QuadPart;
LARGE_INTEGER frequency = {0};
QueryPerformanceFrequency(&frequency);
return elapsed.QuadPart * 1000 / frequency.QuadPart;
#else
- const int64_t seconds = (tv_end.tv_sec - tv_start.tv_sec) * 1000;
- const int64_t milliseconds = (tv_end.tv_usec - tv_start.tv_usec) / 1000;
+ const int64_t seconds = (tv_end_.tv_sec - tv_start_.tv_sec) * 1000;
+ const int64_t milliseconds = (tv_end_.tv_usec - tv_start_.tv_usec) / 1000;
return seconds + milliseconds;
#endif
}
diff --git a/extern/draco/draco/src/draco/core/cycle_timer.h b/extern/draco/draco/src/draco/core/cycle_timer.h
index 172f1c2e9b5..f480cc9d389 100644
--- a/extern/draco/draco/src/draco/core/cycle_timer.h
+++ b/extern/draco/draco/src/draco/core/cycle_timer.h
@@ -20,9 +20,10 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
-typedef LARGE_INTEGER timeval;
+typedef LARGE_INTEGER DracoTimeVal;
#else
#include <sys/time.h>
+typedef timeval DracoTimeVal;
#endif
#include <cinttypes>
@@ -39,8 +40,8 @@ class DracoTimer {
int64_t GetInMs();
private:
- timeval tv_start;
- timeval tv_end;
+ DracoTimeVal tv_start_;
+ DracoTimeVal tv_end_;
};
typedef DracoTimer CycleTimer;
diff --git a/extern/draco/draco/src/draco/core/data_buffer.cc b/extern/draco/draco/src/draco/core/data_buffer.cc
index f0b43d67dbd..96a3787987c 100644
--- a/extern/draco/draco/src/draco/core/data_buffer.cc
+++ b/extern/draco/draco/src/draco/core/data_buffer.cc
@@ -52,7 +52,7 @@ void DataBuffer::Resize(int64_t size) {
}
void DataBuffer::WriteDataToStream(std::ostream &stream) {
- if (data_.size() == 0) {
+ if (data_.empty()) {
return;
}
stream.write(reinterpret_cast<char *>(data_.data()), data_.size());
diff --git a/extern/draco/draco/src/draco/core/decoder_buffer.h b/extern/draco/draco/src/draco/core/decoder_buffer.h
index 0559abbe415..be98e52d60e 100644
--- a/extern/draco/draco/src/draco/core/decoder_buffer.h
+++ b/extern/draco/draco/src/draco/core/decoder_buffer.h
@@ -54,12 +54,11 @@ class DecoderBuffer {
// Decodes up to 32 bits into out_val. Can be called only in between
// StartBitDecoding and EndBitDecoding. Otherwise returns false.
- bool DecodeLeastSignificantBits32(int nbits, uint32_t *out_value) {
+ bool DecodeLeastSignificantBits32(uint32_t nbits, uint32_t *out_value) {
if (!bit_decoder_active()) {
return false;
}
- bit_decoder_.GetBits(nbits, out_value);
- return true;
+ return bit_decoder_.GetBits(nbits, out_value);
}
// Decodes an arbitrary data type.
@@ -158,9 +157,10 @@ class DecoderBuffer {
inline void ConsumeBits(int k) { bit_offset_ += k; }
// Returns |nbits| bits in |x|.
- inline bool GetBits(int32_t nbits, uint32_t *x) {
- DRACO_DCHECK_GE(nbits, 0);
- DRACO_DCHECK_LE(nbits, 32);
+ inline bool GetBits(uint32_t nbits, uint32_t *x) {
+ if (nbits > 32) {
+ return false;
+ }
uint32_t value = 0;
for (int32_t bit = 0; bit < nbits; ++bit) {
value |= GetBit() << bit;
diff --git a/extern/draco/draco/src/draco/core/draco_index_type_vector.h b/extern/draco/draco/src/draco/core/draco_index_type_vector.h
index d47ab3b04eb..0fefc43b23d 100644
--- a/extern/draco/draco/src/draco/core/draco_index_type_vector.h
+++ b/extern/draco/draco/src/draco/core/draco_index_type_vector.h
@@ -28,7 +28,6 @@ namespace draco {
// draco_index_type.h .
// TODO(ostava): Make the interface more complete. It's currently missing
// features such as iterators.
-// TODO(vytyaz): Add more unit tests for this class.
template <class IndexTypeT, class ValueTypeT>
class IndexTypeVector {
public:
@@ -56,7 +55,7 @@ class IndexTypeVector {
void push_back(ValueTypeT &&val) { vector_.push_back(std::move(val)); }
template <typename... Args>
- void emplace_back(Args &&... args) {
+ void emplace_back(Args &&...args) {
vector_.emplace_back(std::forward<Args>(args)...);
}
diff --git a/extern/draco/draco/src/draco/core/draco_version.h b/extern/draco/draco/src/draco/core/draco_version.h
index ffd7948c64d..5f2676ad7e9 100644
--- a/extern/draco/draco/src/draco/core/draco_version.h
+++ b/extern/draco/draco/src/draco/core/draco_version.h
@@ -18,7 +18,7 @@
namespace draco {
// Draco version is comprised of <major>.<minor>.<revision>.
-static const char kDracoVersion[] = "1.3.6";
+static const char kDracoVersion[] = "1.5.2";
const char *Version() { return kDracoVersion; }
diff --git a/extern/draco/draco/src/draco/core/macros.h b/extern/draco/draco/src/draco/core/macros.h
index 89b706e53a5..64647d129d5 100644
--- a/extern/draco/draco/src/draco/core/macros.h
+++ b/extern/draco/draco/src/draco/core/macros.h
@@ -21,11 +21,13 @@
#ifdef ANDROID_LOGGING
#include <android/log.h>
#define LOG_TAG "draco"
-#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
-#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+#define DRACO_LOGI(...) \
+ __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define DRACO_LOGE(...) \
+ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#else
-#define LOGI printf
-#define LOGE printf
+#define DRACO_LOGI printf
+#define DRACO_LOGE printf
#endif
#include <iostream>
@@ -88,6 +90,10 @@ namespace draco {
#define DRACO_MACROS_IMPL_CONCAT_INNER_(x, y) x##y
#define DRACO_MACROS_IMPL_CONCAT_(x, y) DRACO_MACROS_IMPL_CONCAT_INNER_(x, y)
+#define DRACO_MACROS_IMPL_CONCAT_INNER_3_(x, y, z) x##y##z
+#define DRACO_MACROS_IMPL_CONCAT_3_(x, y, z) \
+ DRACO_MACROS_IMPL_CONCAT_INNER_3_(x, y, z)
+
// Expand the n-th argument of the macro. Used to select an argument based on
// the number of entries in a variadic macro argument. Example usage:
//
@@ -98,13 +104,20 @@ namespace draco {
// #define VARIADIC_MACRO(...)
// DRACO_SELECT_NTH_FROM_3(__VA_ARGS__, FUNC_3, FUNC_2, FUNC_1) __VA_ARGS__
//
-#define DRACO_SELECT_NTH_FROM_2(_1, _2, NAME) NAME
-#define DRACO_SELECT_NTH_FROM_3(_1, _2, _3, NAME) NAME
-#define DRACO_SELECT_NTH_FROM_4(_1, _2, _3, _4, NAME) NAME
+#define DRACO_SELECT_NTH_FROM_2(_1, _2, NAME, ...) NAME
+#define DRACO_SELECT_NTH_FROM_3(_1, _2, _3, NAME, ...) NAME
+#define DRACO_SELECT_NTH_FROM_4(_1, _2, _3, _4, NAME, ...) NAME
// Macro that converts the Draco bit-stream into one uint16_t number.
// Useful mostly when checking version numbers.
#define DRACO_BITSTREAM_VERSION(MAJOR, MINOR) \
((static_cast<uint16_t>(MAJOR) << 8) | MINOR)
+// Macro that converts the uint16_t Draco bit-stream number into the major
+// and minor components respectively.
+#define DRACO_BISTREAM_VERSION_MAJOR(VERSION) \
+ (static_cast<uint8_t>(VERSION >> 8))
+#define DRACO_BISTREAM_VERSION_MINOR(VERSION) \
+ (static_cast<uint8_t>(VERSION & 0xFF))
+
#endif // DRACO_CORE_MACROS_H_
diff --git a/extern/draco/draco/src/draco/core/options.h b/extern/draco/draco/src/draco/core/options.h
index 1bc4dc0fb7b..9dc22ce16c2 100644
--- a/extern/draco/draco/src/draco/core/options.h
+++ b/extern/draco/draco/src/draco/core/options.h
@@ -71,8 +71,6 @@ class Options {
private:
// All entries are internally stored as strings and converted to the desired
// return type based on the used Get* method.
- // TODO(ostava): Consider adding type safety mechanism that would prevent
- // unsafe operations such as a conversion from vector to int.
std::map<std::string, std::string> options_;
};
diff --git a/extern/draco/draco/src/draco/core/status.h b/extern/draco/draco/src/draco/core/status.h
index 449ad8566de..ee7f43ee59c 100644
--- a/extern/draco/draco/src/draco/core/status.h
+++ b/extern/draco/draco/src/draco/core/status.h
@@ -15,6 +15,7 @@
#ifndef DRACO_CORE_STATUS_H_
#define DRACO_CORE_STATUS_H_
+#include <ostream>
#include <string>
namespace draco {
@@ -61,6 +62,9 @@ inline std::ostream &operator<<(std::ostream &os, const Status &status) {
}
inline Status OkStatus() { return Status(Status::OK); }
+inline Status ErrorStatus(const std::string &msg) {
+ return Status(Status::DRACO_ERROR, msg);
+}
// Evaluates an expression that returns draco::Status. If the status is not OK,
// the macro returns the status object.
diff --git a/extern/draco/draco/src/draco/core/varint_decoding.h b/extern/draco/draco/src/draco/core/varint_decoding.h
index 4e86df732e0..cff47e930b4 100644
--- a/extern/draco/draco/src/draco/core/varint_decoding.h
+++ b/extern/draco/draco/src/draco/core/varint_decoding.h
@@ -58,6 +58,7 @@ bool DecodeVarintUnsigned(int depth, IntTypeT *out_val, DecoderBuffer *buffer) {
// Decodes a specified integer as varint. Note that the IntTypeT must be the
// same as the one used in the corresponding EncodeVarint() call.
+// out_val is undefined if this returns false.
template <typename IntTypeT>
bool DecodeVarint(IntTypeT *out_val, DecoderBuffer *buffer) {
if (std::is_unsigned<IntTypeT>::value) {
diff --git a/extern/draco/draco/src/draco/core/vector_d.h b/extern/draco/draco/src/draco/core/vector_d.h
index bed97304feb..a0ec2dedf2e 100644
--- a/extern/draco/draco/src/draco/core/vector_d.h
+++ b/extern/draco/draco/src/draco/core/vector_d.h
@@ -20,6 +20,7 @@
#include <algorithm>
#include <array>
#include <cmath>
+#include <limits>
#include "draco/core/macros.h"
@@ -33,7 +34,7 @@ class VectorD {
typedef ScalarT Scalar;
typedef VectorD<Scalar, dimension_t> Self;
- // TODO(hemmer): Deprecate.
+ // TODO(b/199760123): Deprecate.
typedef ScalarT CoefficientType;
VectorD() {
@@ -44,7 +45,7 @@ class VectorD {
// The following constructor does not compile in opt mode, which for now led
// to the constructors further down, which is not ideal.
- // TODO(hemmer): fix constructor below and remove others.
+ // TODO(b/199760123): Fix constructor below and remove others.
// template <typename... Args>
// explicit VectorD(Args... args) : v_({args...}) {}
@@ -110,7 +111,7 @@ class VectorD {
Scalar &operator[](int i) { return v_[i]; }
const Scalar &operator[](int i) const { return v_[i]; }
- // TODO(hemmer): remove.
+ // TODO(b/199760123): Remove.
// Similar to interface of Eigen library.
Scalar &operator()(int i) { return v_[i]; }
const Scalar &operator()(int i) const { return v_[i]; }
@@ -236,7 +237,12 @@ class VectorD {
Scalar AbsSum() const {
Scalar result(0);
for (int i = 0; i < dimension; ++i) {
- result += std::abs(v_[i]);
+ Scalar next_value = std::abs(v_[i]);
+ if (result > std::numeric_limits<Scalar>::max() - next_value) {
+ // Return the max if adding would have caused an overflow.
+ return std::numeric_limits<Scalar>::max();
+ }
+ result += next_value;
}
return result;
}
diff --git a/extern/draco/draco/src/draco/draco_features.h b/extern/draco/draco/src/draco/draco_features.h
index 27e3d7f136a..d0a630e5465 100644
--- a/extern/draco/draco/src/draco/draco_features.h
+++ b/extern/draco/draco/src/draco/draco_features.h
@@ -4,7 +4,5 @@
#define DRACO_MESH_COMPRESSION_SUPPORTED
#define DRACO_NORMAL_ENCODING_SUPPORTED
#define DRACO_STANDARD_EDGEBREAKER_SUPPORTED
-#define DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
-#define DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED
#endif // DRACO_FEATURES_H_
diff --git a/extern/draco/draco/src/draco/mesh/corner_table.cc b/extern/draco/draco/src/draco/mesh/corner_table.cc
index 6066e58bd8b..3f92f651ab6 100644
--- a/extern/draco/draco/src/draco/mesh/corner_table.cc
+++ b/extern/draco/draco/src/draco/mesh/corner_table.cc
@@ -66,12 +66,13 @@ bool CornerTable::Reset(int num_faces, int num_vertices) {
if (num_faces < 0 || num_vertices < 0) {
return false;
}
- if (static_cast<unsigned int>(num_faces) >
+ const unsigned int num_faces_unsigned = num_faces;
+ if (num_faces_unsigned >
std::numeric_limits<CornerIndex::ValueType>::max() / 3) {
return false;
}
- corner_to_vertex_map_.assign(num_faces * 3, kInvalidVertexIndex);
- opposite_corners_.assign(num_faces * 3, kInvalidCornerIndex);
+ corner_to_vertex_map_.assign(num_faces_unsigned * 3, kInvalidVertexIndex);
+ opposite_corners_.assign(num_faces_unsigned * 3, kInvalidCornerIndex);
vertex_corners_.reserve(num_vertices);
valence_cache_.ClearValenceCache();
valence_cache_.ClearValenceCacheInaccurate();
diff --git a/extern/draco/draco/src/draco/mesh/mesh.h b/extern/draco/draco/src/draco/mesh/mesh.h
index f4506da81c9..b1577c03986 100644
--- a/extern/draco/draco/src/draco/mesh/mesh.h
+++ b/extern/draco/draco/src/draco/mesh/mesh.h
@@ -119,6 +119,10 @@ class Mesh : public PointCloud {
const std::vector<PointIndex> &unique_point_ids) override;
#endif
+ // Exposes |faces_|. Use |faces_| at your own risk. DO NOT store the
+ // reference: the |faces_| object is destroyed with the mesh.
+ IndexTypeVector<FaceIndex, Face> &faces() { return faces_; }
+
private:
// Mesh specific per-attribute data.
std::vector<AttributeData> attribute_data_;
diff --git a/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h b/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h
index 7dad25cf1d2..6f02453d2d4 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h
+++ b/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h
@@ -130,6 +130,12 @@ class MeshAttributeCornerTable {
return false;
}
+ bool IsDegenerated(FaceIndex face) const {
+ // Introducing seams can't change the degeneracy of the individual faces,
+ // therefore we can delegate the check to the original |corner_table_|.
+ return corner_table_->IsDegenerated(face);
+ }
+
bool no_interior_seams() const { return no_interior_seams_; }
const CornerTable *corner_table() const { return corner_table_; }
diff --git a/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc b/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc
index 773c1e18fe6..bc44c831c4e 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc
+++ b/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc
@@ -14,25 +14,42 @@
//
#include "draco/mesh/mesh_cleanup.h"
+#include <unordered_set>
+
+#include "draco/core/hash_utils.h"
+
namespace draco {
-bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) {
- if (!options.remove_degenerated_faces && !options.remove_unused_attributes) {
- return true; // Nothing to cleanup.
+Status MeshCleanup::Cleanup(Mesh *mesh, const MeshCleanupOptions &options) {
+ if (!options.remove_degenerated_faces && !options.remove_unused_attributes &&
+ !options.remove_duplicate_faces && !options.make_geometry_manifold) {
+ return OkStatus(); // Nothing to cleanup.
}
const PointAttribute *const pos_att =
mesh->GetNamedAttribute(GeometryAttribute::POSITION);
if (pos_att == nullptr) {
- return false;
+ return Status(Status::DRACO_ERROR, "Missing position attribute.");
}
- // Array that is going to store whether a corresponding point is used.
- std::vector<bool> is_point_used;
+
+ if (options.remove_degenerated_faces) {
+ RemoveDegeneratedFaces(mesh);
+ }
+
+ if (options.remove_duplicate_faces) {
+ RemoveDuplicateFaces(mesh);
+ }
+
if (options.remove_unused_attributes) {
- is_point_used.resize(mesh->num_points(), false);
+ RemoveUnusedAttributes(mesh);
}
+ return OkStatus();
+}
+
+void MeshCleanup::RemoveDegeneratedFaces(Mesh *mesh) {
+ const PointAttribute *const pos_att =
+ mesh->GetNamedAttribute(GeometryAttribute::POSITION);
FaceIndex::ValueType num_degenerated_faces = 0;
- PointIndex::ValueType num_new_points = 0;
// Array for storing position indices on a face.
std::array<AttributeValueIndex, 3> pos_indices;
for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
@@ -40,149 +57,195 @@ bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) {
for (int p = 0; p < 3; ++p) {
pos_indices[p] = pos_att->mapped_index(face[p]);
}
- bool is_face_valid = true;
- if (options.remove_degenerated_faces) {
- if (pos_indices[0] == pos_indices[1] ||
- pos_indices[0] == pos_indices[2] ||
- pos_indices[1] == pos_indices[2]) {
- ++num_degenerated_faces;
- is_face_valid = false;
- } else if (num_degenerated_faces > 0) {
- // Copy the face to its new location.
- mesh->SetFace(f - num_degenerated_faces, face);
- }
- }
- if (options.remove_unused_attributes && is_face_valid) {
- for (int p = 0; p < 3; ++p) {
- if (!is_point_used[face[p].value()]) {
- is_point_used[face[p].value()] = true;
- ++num_new_points;
- }
- }
+ if (pos_indices[0] == pos_indices[1] || pos_indices[0] == pos_indices[2] ||
+ pos_indices[1] == pos_indices[2]) {
+ ++num_degenerated_faces;
+ } else if (num_degenerated_faces > 0) {
+ // Copy the face to its new location.
+ mesh->SetFace(f - num_degenerated_faces, face);
}
}
if (num_degenerated_faces > 0) {
mesh->SetNumFaces(mesh->num_faces() - num_degenerated_faces);
}
- if (options.remove_unused_attributes) {
- bool points_changed = false;
- const PointIndex::ValueType num_original_points = mesh->num_points();
- // Map from old points to the new ones.
- IndexTypeVector<PointIndex, PointIndex> point_map(num_original_points);
- if (num_new_points < static_cast<int>(mesh->num_points())) {
- // Some of the points were removed. We need to remap the old points to the
- // new ones.
- num_new_points = 0;
- for (PointIndex i(0); i < num_original_points; ++i) {
- if (is_point_used[i.value()]) {
- point_map[i] = num_new_points++;
- } else {
- point_map[i] = kInvalidPointIndex;
- }
+}
+
+void MeshCleanup::RemoveDuplicateFaces(Mesh *mesh) {
+ const PointAttribute *const pos_att =
+ mesh->GetNamedAttribute(GeometryAttribute::POSITION);
+
+ typedef std::array<AttributeValueIndex::ValueType, 3> PosTriplet;
+ PosTriplet pos_indices;
+ std::unordered_set<PosTriplet, HashArray<PosTriplet>> is_face_used;
+
+ uint32_t num_duplicate_faces = 0;
+ for (FaceIndex fi(0); fi < mesh->num_faces(); ++fi) {
+ const auto f = mesh->face(fi);
+ for (int c = 0; c < 3; ++c) {
+ pos_indices[c] = pos_att->mapped_index(f[c]).value();
+ }
+ // Shift the position indices until the smallest index is the first one.
+ while (pos_indices[0] > pos_indices[1] || pos_indices[0] > pos_indices[2]) {
+ // Shift to the left.
+ std::swap(pos_indices[0], pos_indices[1]);
+ std::swap(pos_indices[1], pos_indices[2]);
+ }
+ // Check if have encountered the same position triplet on a different face.
+ if (is_face_used.find(pos_indices) != is_face_used.end()) {
+ // Duplicate face. Ignore it.
+ num_duplicate_faces++;
+ } else {
+ // Insert new face to the set.
+ is_face_used.insert(pos_indices);
+ if (num_duplicate_faces > 0) {
+ // Copy the face to its new location.
+ mesh->SetFace(fi - num_duplicate_faces, f);
}
- // Go over faces and update their points.
- for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
- Mesh::Face face = mesh->face(f);
- for (int p = 0; p < 3; ++p) {
- face[p] = point_map[face[p]];
- }
- mesh->SetFace(f, face);
+ }
+ }
+ if (num_duplicate_faces > 0) {
+ mesh->SetNumFaces(mesh->num_faces() - num_duplicate_faces);
+ }
+}
+
+void MeshCleanup::RemoveUnusedAttributes(Mesh *mesh) {
+ // Array that is going to store whether a corresponding point is used.
+ std::vector<bool> is_point_used;
+ PointIndex::ValueType num_new_points = 0;
+ is_point_used.resize(mesh->num_points(), false);
+ for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
+ const Mesh::Face &face = mesh->face(f);
+ for (int p = 0; p < 3; ++p) {
+ if (!is_point_used[face[p].value()]) {
+ is_point_used[face[p].value()] = true;
+ ++num_new_points;
}
- // Set the new number of points.
- mesh->set_num_points(num_new_points);
- points_changed = true;
- } else {
- // No points were removed. Initialize identity map between the old and new
- // points.
- for (PointIndex i(0); i < num_original_points; ++i) {
- point_map[i] = i;
+ }
+ }
+
+ bool points_changed = false;
+ const PointIndex::ValueType num_original_points = mesh->num_points();
+ // Map from old points to the new ones.
+ IndexTypeVector<PointIndex, PointIndex> point_map(num_original_points);
+ if (num_new_points < static_cast<int>(mesh->num_points())) {
+ // Some of the points were removed. We need to remap the old points to the
+ // new ones.
+ num_new_points = 0;
+ for (PointIndex i(0); i < num_original_points; ++i) {
+ if (is_point_used[i.value()]) {
+ point_map[i] = num_new_points++;
+ } else {
+ point_map[i] = kInvalidPointIndex;
+ }
+ }
+ // Go over faces and update their points.
+ for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
+ Mesh::Face face = mesh->face(f);
+ for (int p = 0; p < 3; ++p) {
+ face[p] = point_map[face[p]];
}
+ mesh->SetFace(f, face);
}
+ // Set the new number of points.
+ mesh->set_num_points(num_new_points);
+ points_changed = true;
+ } else {
+ // No points were removed. Initialize identity map between the old and new
+ // points.
+ for (PointIndex i(0); i < num_original_points; ++i) {
+ point_map[i] = i;
+ }
+ }
- // Update index mapping for attributes.
- IndexTypeVector<AttributeValueIndex, uint8_t> is_att_index_used;
- IndexTypeVector<AttributeValueIndex, AttributeValueIndex> att_index_map;
- for (int a = 0; a < mesh->num_attributes(); ++a) {
- PointAttribute *const att = mesh->attribute(a);
- // First detect which attribute entries are used (included in a point).
- is_att_index_used.assign(att->size(), 0);
- att_index_map.clear();
- AttributeValueIndex::ValueType num_used_entries = 0;
- for (PointIndex i(0); i < num_original_points; ++i) {
- if (point_map[i] != kInvalidPointIndex) {
- const AttributeValueIndex entry_id = att->mapped_index(i);
- if (!is_att_index_used[entry_id]) {
- is_att_index_used[entry_id] = 1;
- ++num_used_entries;
- }
+ // Update index mapping for attributes.
+ IndexTypeVector<AttributeValueIndex, uint8_t> is_att_index_used;
+ IndexTypeVector<AttributeValueIndex, AttributeValueIndex> att_index_map;
+ for (int a = 0; a < mesh->num_attributes(); ++a) {
+ PointAttribute *const att = mesh->attribute(a);
+ // First detect which attribute entries are used (included in a point).
+ is_att_index_used.assign(att->size(), 0);
+ att_index_map.clear();
+ AttributeValueIndex::ValueType num_used_entries = 0;
+ for (PointIndex i(0); i < num_original_points; ++i) {
+ if (point_map[i] != kInvalidPointIndex) {
+ const AttributeValueIndex entry_id = att->mapped_index(i);
+ if (!is_att_index_used[entry_id]) {
+ is_att_index_used[entry_id] = 1;
+ ++num_used_entries;
}
}
- bool att_indices_changed = false;
- // If there are some unused attribute entries, remap the attribute values
- // in the attribute buffer.
- if (num_used_entries < static_cast<int>(att->size())) {
- att_index_map.resize(att->size());
- num_used_entries = 0;
- for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size());
- ++i) {
- if (is_att_index_used[i]) {
- att_index_map[i] = num_used_entries;
- if (i > num_used_entries) {
- const uint8_t *const src_add = att->GetAddress(i);
- att->buffer()->Write(
- att->GetBytePos(AttributeValueIndex(num_used_entries)),
- src_add, att->byte_stride());
- }
- ++num_used_entries;
+ }
+ bool att_indices_changed = false;
+ // If there are some unused attribute entries, remap the attribute values
+ // in the attribute buffer.
+ if (num_used_entries < static_cast<int>(att->size())) {
+ att_index_map.resize(att->size());
+ num_used_entries = 0;
+ for (AttributeValueIndex i(0); i < static_cast<uint32_t>(att->size());
+ ++i) {
+ if (is_att_index_used[i]) {
+ att_index_map[i] = num_used_entries;
+ if (i > num_used_entries) {
+ const uint8_t *const src_add = att->GetAddress(i);
+ att->buffer()->Write(
+ att->GetBytePos(AttributeValueIndex(num_used_entries)), src_add,
+ att->byte_stride());
}
+ ++num_used_entries;
}
- // Update the number of unique entries in the vertex buffer.
- att->Resize(num_used_entries);
- att_indices_changed = true;
}
- // If either the points or attribute indices have changed, we need to
- // update the attribute index mapping.
- if (points_changed || att_indices_changed) {
- if (att->is_mapping_identity()) {
- // The mapping was identity. It'll remain identity only if the
- // number of point and attribute indices is still the same.
- if (num_used_entries != static_cast<int>(mesh->num_points())) {
- // We need to create an explicit mapping.
- // First we need to initialize the explicit map to the original
- // number of points to recreate the original identity map.
- att->SetExplicitMapping(num_original_points);
- // Set the entries of the explicit map to identity.
- for (PointIndex::ValueType i = 0; i < num_original_points; ++i) {
- att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i));
- }
+ // Update the number of unique entries in the vertex buffer.
+ att->Resize(num_used_entries);
+ att_indices_changed = true;
+ }
+ // If either the points or attribute indices have changed, we need to
+ // update the attribute index mapping.
+ if (points_changed || att_indices_changed) {
+ if (att->is_mapping_identity()) {
+ // The mapping was identity. It'll remain identity only if the
+ // number of point and attribute indices is still the same.
+ if (num_used_entries != static_cast<int>(mesh->num_points())) {
+ // We need to create an explicit mapping.
+ // First we need to initialize the explicit map to the original
+ // number of points to recreate the original identity map.
+ att->SetExplicitMapping(num_original_points);
+ // Set the entries of the explicit map to identity.
+ for (PointIndex::ValueType i = 0; i < num_original_points; ++i) {
+ att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i));
}
}
- if (!att->is_mapping_identity()) {
- // Explicit mapping between points and local attribute indices.
- for (PointIndex i(0); i < num_original_points; ++i) {
- // The new point id that maps to the currently processed attribute
- // entry.
- const PointIndex new_point_id = point_map[i];
- if (new_point_id == kInvalidPointIndex) {
- continue;
- }
- // Index of the currently processed attribute entry in the original
- // mesh.
- const AttributeValueIndex original_entry_index =
- att->mapped_index(i);
- // New index of the same entry after unused entries were removed.
- const AttributeValueIndex new_entry_index =
- att_index_map[original_entry_index];
- att->SetPointMapEntry(new_point_id, new_entry_index);
+ }
+ if (!att->is_mapping_identity()) {
+ // Explicit mapping between points and local attribute indices.
+ for (PointIndex i(0); i < num_original_points; ++i) {
+ // The new point id that maps to the currently processed attribute
+ // entry.
+ const PointIndex new_point_id = point_map[i];
+ if (new_point_id == kInvalidPointIndex) {
+ continue;
}
- // If the number of points changed, we need to set a new explicit map
- // size.
- att->SetExplicitMapping(mesh->num_points());
+ // Index of the currently processed attribute entry in the original
+ // mesh.
+ const AttributeValueIndex original_entry_index = att->mapped_index(i);
+ // New index of the same entry after unused entries were removed.
+ const AttributeValueIndex new_entry_index =
+ att_indices_changed ? att_index_map[original_entry_index]
+ : original_entry_index;
+
+ // Update the mapping. Note that the new point index is always smaller
+ // than the processed index |i|, making this operation safe.
+ att->SetPointMapEntry(new_point_id, new_entry_index);
}
+ // If the number of points changed, we need to set a new explicit map
+ // size.
+ att->SetExplicitMapping(mesh->num_points());
}
}
}
- return true;
+}
+
+Status MeshCleanup::MakeGeometryManifold(Mesh *mesh) {
+ return Status(Status::DRACO_ERROR, "Unsupported function.");
}
} // namespace draco
diff --git a/extern/draco/draco/src/draco/mesh/mesh_cleanup.h b/extern/draco/draco/src/draco/mesh/mesh_cleanup.h
index b56129dce58..0acdc2ae5b8 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_cleanup.h
+++ b/extern/draco/draco/src/draco/mesh/mesh_cleanup.h
@@ -15,27 +15,44 @@
#ifndef DRACO_MESH_MESH_CLEANUP_H_
#define DRACO_MESH_MESH_CLEANUP_H_
+#include "draco/core/status.h"
#include "draco/mesh/mesh.h"
namespace draco {
// Options used by the MeshCleanup class.
struct MeshCleanupOptions {
- MeshCleanupOptions()
- : remove_degenerated_faces(true), remove_unused_attributes(true) {}
// If true, the cleanup tool removes any face where two or more vertices
// share the same position index.
- bool remove_degenerated_faces;
+ bool remove_degenerated_faces = true;
+
+ // If true, the cleanup tool removes all duplicate faces. A pair of faces is
+ // duplicate if both faces share the same position indices on all vertices
+ // (that is, position values have to be duduplicated). Note that all
+ // non-position properties are currently ignored.
+ bool remove_duplicate_faces = true;
+
// If true, the cleanup tool removes any unused attribute value or unused
// point id. For example, it can be used to remove isolated vertices.
- bool remove_unused_attributes;
+ bool remove_unused_attributes = true;
+
+ // If true, the cleanup tool splits vertices along non-manifold edges and
+ // vertices. This ensures that the connectivity defined by position indices
+ // is manifold.
+ bool make_geometry_manifold = false;
};
// Tool that can be used for removing bad or unused data from draco::Meshes.
class MeshCleanup {
public:
// Performs in-place cleanup of the input mesh according to the input options.
- bool operator()(Mesh *mesh, const MeshCleanupOptions &options);
+ static Status Cleanup(Mesh *mesh, const MeshCleanupOptions &options);
+
+ private:
+ static void RemoveDegeneratedFaces(Mesh *mesh);
+ static void RemoveDuplicateFaces(Mesh *mesh);
+ static void RemoveUnusedAttributes(Mesh *mesh);
+ static Status MakeGeometryManifold(Mesh *mesh);
};
} // namespace draco
diff --git a/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h b/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h
index b450bc80cd8..0a3bcf49782 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h
+++ b/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h
@@ -67,7 +67,6 @@ inline bool IsCornerOppositeToAttributeSeam(CornerIndex ci,
// Interpolates an attribute value on a face using given barycentric
// coordinates. InterpolatedVectorT should be a VectorD that corresponds to the
// values stored in the attribute.
-// TODO(ostava): Find a better place for this.
template <typename InterpolatedVectorT>
InterpolatedVectorT ComputeInterpolatedAttributeValueOnMeshFace(
const Mesh &mesh, const PointAttribute &attribute, FaceIndex fi,
diff --git a/extern/draco/draco/src/draco/mesh/mesh_stripifier.h b/extern/draco/draco/src/draco/mesh/mesh_stripifier.h
index 0c298f48e86..8e8d8d9f21f 100644
--- a/extern/draco/draco/src/draco/mesh/mesh_stripifier.h
+++ b/extern/draco/draco/src/draco/mesh/mesh_stripifier.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#ifndef DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
-#define DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
+#ifndef DRACO_MESH_MESH_STRIPIFIER_H_
+#define DRACO_MESH_MESH_STRIPIFIER_H_
#include "draco/mesh/mesh_misc_functions.h"
@@ -71,8 +71,6 @@ class MeshStripifier {
mesh_ = &mesh;
num_strips_ = 0;
num_encoded_faces_ = 0;
- // TODO(ostava): We may be able to avoid computing the corner table if we
- // already have it stored somewhere.
corner_table_ = CreateCornerTableFromPositionAttribute(mesh_);
if (corner_table_ == nullptr) {
return false;
@@ -257,4 +255,4 @@ bool MeshStripifier::GenerateTriangleStripsWithDegenerateTriangles(
} // namespace draco
-#endif // DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_
+#endif // DRACO_MESH_MESH_STRIPIFIER_H_
diff --git a/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc b/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc
index 60b0c50b8d5..cb767f871a9 100644
--- a/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc
+++ b/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc
@@ -41,8 +41,6 @@ void TriangleSoupMeshBuilder::SetAttributeValuesForFace(
att->SetAttributeValue(AttributeValueIndex(start_index), corner_value_0);
att->SetAttributeValue(AttributeValueIndex(start_index + 1), corner_value_1);
att->SetAttributeValue(AttributeValueIndex(start_index + 2), corner_value_2);
- // TODO(ostava): The below code should be called only for one attribute.
- // It will work OK even for multiple attributes, but it's redundant.
mesh_->SetFace(face_id,
{{PointIndex(start_index), PointIndex(start_index + 1),
PointIndex(start_index + 2)}});
diff --git a/extern/draco/draco/src/draco/metadata/geometry_metadata.cc b/extern/draco/draco/src/draco/metadata/geometry_metadata.cc
index b83898140ae..b6a882c0b1b 100644
--- a/extern/draco/draco/src/draco/metadata/geometry_metadata.cc
+++ b/extern/draco/draco/src/draco/metadata/geometry_metadata.cc
@@ -18,6 +18,19 @@
namespace draco {
+AttributeMetadata::AttributeMetadata(const AttributeMetadata &metadata)
+ : Metadata(metadata) {
+ att_unique_id_ = metadata.att_unique_id_;
+}
+
+GeometryMetadata::GeometryMetadata(const GeometryMetadata &metadata)
+ : Metadata(metadata) {
+ for (size_t i = 0; i < metadata.att_metadatas_.size(); ++i) {
+ att_metadatas_.push_back(std::unique_ptr<AttributeMetadata>(
+ new AttributeMetadata(*metadata.att_metadatas_[i])));
+ }
+}
+
const AttributeMetadata *GeometryMetadata::GetAttributeMetadataByStringEntry(
const std::string &entry_name, const std::string &entry_value) const {
for (auto &&att_metadata : att_metadatas_) {
@@ -35,7 +48,7 @@ const AttributeMetadata *GeometryMetadata::GetAttributeMetadataByStringEntry(
bool GeometryMetadata::AddAttributeMetadata(
std::unique_ptr<AttributeMetadata> att_metadata) {
- if (!att_metadata.get()) {
+ if (!att_metadata) {
return false;
}
att_metadatas_.push_back(std::move(att_metadata));
diff --git a/extern/draco/draco/src/draco/metadata/geometry_metadata.h b/extern/draco/draco/src/draco/metadata/geometry_metadata.h
index ec7ecb9ee68..531bdef2540 100644
--- a/extern/draco/draco/src/draco/metadata/geometry_metadata.h
+++ b/extern/draco/draco/src/draco/metadata/geometry_metadata.h
@@ -25,6 +25,7 @@ namespace draco {
class AttributeMetadata : public Metadata {
public:
AttributeMetadata() : att_unique_id_(0) {}
+ AttributeMetadata(const AttributeMetadata &metadata);
explicit AttributeMetadata(const Metadata &metadata)
: Metadata(metadata), att_unique_id_(0) {}
@@ -57,6 +58,7 @@ struct AttributeMetadataHasher {
class GeometryMetadata : public Metadata {
public:
GeometryMetadata() {}
+ GeometryMetadata(const GeometryMetadata &metadata);
explicit GeometryMetadata(const Metadata &metadata) : Metadata(metadata) {}
const AttributeMetadata *GetAttributeMetadataByStringEntry(
diff --git a/extern/draco/draco/src/draco/metadata/metadata.cc b/extern/draco/draco/src/draco/metadata/metadata.cc
index 9141907ed71..51b4e93a328 100644
--- a/extern/draco/draco/src/draco/metadata/metadata.cc
+++ b/extern/draco/draco/src/draco/metadata/metadata.cc
@@ -122,6 +122,14 @@ const Metadata *Metadata::GetSubMetadata(const std::string &name) const {
return sub_ptr->second.get();
}
+Metadata *Metadata::sub_metadata(const std::string &name) {
+ auto sub_ptr = sub_metadatas_.find(name);
+ if (sub_ptr == sub_metadatas_.end()) {
+ return nullptr;
+ }
+ return sub_ptr->second.get();
+}
+
void Metadata::RemoveEntry(const std::string &name) {
// Actually just remove "name", no need to check if it exists.
auto entry_ptr = entries_.find(name);
diff --git a/extern/draco/draco/src/draco/metadata/metadata.h b/extern/draco/draco/src/draco/metadata/metadata.h
index 56d05e46a3e..12c1ba97439 100644
--- a/extern/draco/draco/src/draco/metadata/metadata.h
+++ b/extern/draco/draco/src/draco/metadata/metadata.h
@@ -147,6 +147,7 @@ class Metadata {
bool AddSubMetadata(const std::string &name,
std::unique_ptr<Metadata> sub_metadata);
const Metadata *GetSubMetadata(const std::string &name) const;
+ Metadata *sub_metadata(const std::string &name);
void RemoveEntry(const std::string &name);
diff --git a/extern/draco/draco/src/draco/metadata/metadata_decoder.cc b/extern/draco/draco/src/draco/metadata/metadata_decoder.cc
index e664e4fa524..a8e66f854cf 100644
--- a/extern/draco/draco/src/draco/metadata/metadata_decoder.cc
+++ b/extern/draco/draco/src/draco/metadata/metadata_decoder.cc
@@ -78,8 +78,10 @@ bool MetadataDecoder::DecodeMetadata(Metadata *metadata) {
std::unique_ptr<Metadata> sub_metadata =
std::unique_ptr<Metadata>(new Metadata());
metadata = sub_metadata.get();
- mp.parent_metadata->AddSubMetadata(sub_metadata_name,
- std::move(sub_metadata));
+ if (!mp.parent_metadata->AddSubMetadata(sub_metadata_name,
+ std::move(sub_metadata))) {
+ return false;
+ }
}
if (metadata == nullptr) {
return false;
@@ -98,6 +100,10 @@ bool MetadataDecoder::DecodeMetadata(Metadata *metadata) {
if (!DecodeVarint(&num_sub_metadata, buffer_)) {
return false;
}
+ if (num_sub_metadata > buffer_->remaining_size()) {
+ // The decoded number of metadata items is unreasonably high.
+ return false;
+ }
for (uint32_t i = 0; i < num_sub_metadata; ++i) {
metadata_stack.push_back({metadata, nullptr});
}
diff --git a/extern/draco/draco/src/draco/point_cloud/point_cloud.cc b/extern/draco/draco/src/draco/point_cloud/point_cloud.cc
index 8eb638f80d4..55ad6670da5 100644
--- a/extern/draco/draco/src/draco/point_cloud/point_cloud.cc
+++ b/extern/draco/draco/src/draco/point_cloud/point_cloud.cc
@@ -241,7 +241,7 @@ void PointCloud::ApplyPointIdDeduplication(
bool PointCloud::DeduplicateAttributeValues() {
// Go over all attributes and create mapping between duplicate entries.
if (num_points() == 0) {
- return false; // Unexpected attribute size.
+ return true; // Nothing to deduplicate.
}
// Deduplicate all attributes.
for (int32_t att_id = 0; att_id < num_attributes(); ++att_id) {
@@ -253,17 +253,11 @@ bool PointCloud::DeduplicateAttributeValues() {
}
#endif
-// TODO(xiaoxumeng): Consider to cash the BBox.
+// TODO(b/199760503): Consider to cache the BBox.
BoundingBox PointCloud::ComputeBoundingBox() const {
- BoundingBox bounding_box =
- BoundingBox(Vector3f(std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max()),
- Vector3f(-std::numeric_limits<float>::max(),
- -std::numeric_limits<float>::max(),
- -std::numeric_limits<float>::max()));
+ BoundingBox bounding_box;
auto pc_att = GetNamedAttribute(GeometryAttribute::POSITION);
- // TODO(xiaoxumeng): Make the BoundingBox a template type, it may not be easy
+ // TODO(b/199760503): Make the BoundingBox a template type, it may not be easy
// because PointCloud is not a template.
// Or simply add some preconditioning here to make sure the position attribute
// is valid, because the current code works only if the position attribute is
@@ -274,7 +268,7 @@ BoundingBox PointCloud::ComputeBoundingBox() const {
for (AttributeValueIndex i(0); i < static_cast<uint32_t>(pc_att->size());
++i) {
pc_att->GetValue(i, &p[0]);
- bounding_box.update_bounding_box(p);
+ bounding_box.Update(p);
}
return bounding_box;
}
diff --git a/extern/draco/patches/blender.patch b/extern/draco/patches/blender.patch
new file mode 100644
index 00000000000..de39260367b
--- /dev/null
+++ b/extern/draco/patches/blender.patch
@@ -0,0 +1,30 @@
+diff --git a/draco/src/draco/attributes/geometry_attribute.h b/draco/src/draco/attributes/geometry_attribute.h
+index fd478a4..c1c0148 100644
+--- a/draco/src/draco/attributes/geometry_attribute.h
++++ b/draco/src/draco/attributes/geometry_attribute.h
+@@ -285,11 +285,25 @@ class GeometryAttribute {
+ // Make sure the in_value fits within the range of values that OutT
+ // is able to represent. Perform the check only for integral types.
+ if (std::is_integral<T>::value && std::is_integral<OutT>::value) {
++#ifdef _MSC_VER
++# pragma warning(push)
++# pragma warning(disable:4804)
++#endif
++#if defined(__GNUC__) && !defined(__clang__)
++# pragma GCC diagnostic push
++# pragma GCC diagnostic ignored "-Wbool-compare"
++#endif
+ static constexpr OutT kOutMin =
+ std::is_signed<T>::value ? std::numeric_limits<OutT>::lowest() : 0;
+ if (in_value < kOutMin || in_value > std::numeric_limits<OutT>::max()) {
+ return false;
+ }
++#ifdef __GNUC__
++# pragma GCC diagnostic pop
++#endif
++#ifdef _MSC_VER
++# pragma warning(pop)
++#endif
+ }
+
+ out_value[i] = static_cast<OutT>(in_value);
diff --git a/extern/draco/src/common.cpp b/extern/draco/src/common.cpp
index 6f98d8db7ef..3a11c126ece 100644
--- a/extern/draco/src/common.cpp
+++ b/extern/draco/src/common.cpp
@@ -54,20 +54,20 @@ size_t getComponentByteLength(size_t componentType)
{
switch (componentType)
{
- case ComponentType::Byte:
- case ComponentType::UnsignedByte:
- return 1;
-
- case ComponentType::Short:
- case ComponentType::UnsignedShort:
- return 2;
-
- case ComponentType::UnsignedInt:
- case ComponentType::Float:
- return 4;
-
- default:
- return 0;
+ case ComponentType::Byte:
+ case ComponentType::UnsignedByte:
+ return 1;
+
+ case ComponentType::Short:
+ case ComponentType::UnsignedShort:
+ return 2;
+
+ case ComponentType::UnsignedInt:
+ case ComponentType::Float:
+ return 4;
+
+ default:
+ return 0;
}
}
diff --git a/extern/draco/src/common.h b/extern/draco/src/common.h
index beaf7d91adb..eef50596350 100644
--- a/extern/draco/src/common.h
+++ b/extern/draco/src/common.h
@@ -33,7 +33,7 @@
#define API(returnType) extern "C" returnType
#endif
-enum ComponentType: size_t
+enum ComponentType : size_t
{
Byte = 5120,
UnsignedByte = 5121,
diff --git a/extern/draco/src/decoder.cpp b/extern/draco/src/decoder.cpp
index 3f3e03bd9f2..e5ec2b65e6c 100644
--- a/extern/draco/src/decoder.cpp
+++ b/extern/draco/src/decoder.cpp
@@ -17,7 +17,6 @@
* @date 2020-11-18
*/
-
#include "decoder.h"
#include <memory>
@@ -30,7 +29,8 @@
#define LOG_PREFIX "DracoDecoder | "
-struct Decoder {
+struct Decoder
+{
std::unique_ptr<draco::Mesh> mesh;
std::vector<uint8_t> indexBuffer;
std::map<uint32_t, std::vector<uint8_t>> buffers;
@@ -54,20 +54,20 @@ bool decoderDecode(Decoder *decoder, void *data, size_t byteLength)
draco::Decoder dracoDecoder;
draco::DecoderBuffer dracoDecoderBuffer;
dracoDecoderBuffer.Init(reinterpret_cast<char *>(data), byteLength);
-
+
auto decoderStatus = dracoDecoder.DecodeMeshFromBuffer(&dracoDecoderBuffer);
if (!decoderStatus.ok())
{
printf(LOG_PREFIX "Error during Draco decoding: %s\n", decoderStatus.status().error_msg());
return false;
}
-
+
decoder->mesh = std::move(decoderStatus).value();
decoder->vertexCount = decoder->mesh->num_points();
decoder->indexCount = decoder->mesh->num_faces() * 3;
-
+
printf(LOG_PREFIX "Decoded %" PRIu32 " vertices, %" PRIu32 " indices\n", decoder->vertexCount, decoder->indexCount);
-
+
return true;
}
@@ -83,32 +83,32 @@ uint32_t decoderGetIndexCount(Decoder *decoder)
bool decoderAttributeIsNormalized(Decoder *decoder, uint32_t id)
{
- const draco::PointAttribute* attribute = decoder->mesh->GetAttributeByUniqueId(id);
+ const draco::PointAttribute *attribute = decoder->mesh->GetAttributeByUniqueId(id);
return attribute != nullptr && attribute->normalized();
}
bool decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType)
{
- const draco::PointAttribute* attribute = decoder->mesh->GetAttributeByUniqueId(id);
-
+ const draco::PointAttribute *attribute = decoder->mesh->GetAttributeByUniqueId(id);
+
if (attribute == nullptr)
{
printf(LOG_PREFIX "Attribute with id=%" PRIu32 " does not exist in Draco data\n", id);
return false;
}
-
+
size_t stride = getAttributeStride(componentType, dataType);
-
+
std::vector<uint8_t> decodedData;
decodedData.resize(stride * decoder->vertexCount);
-
+
for (uint32_t i = 0; i < decoder->vertexCount; ++i)
{
auto index = attribute->mapped_index(draco::PointIndex(i));
uint8_t *value = decodedData.data() + i * stride;
-
+
bool converted = false;
-
+
switch (componentType)
{
case ComponentType::Byte:
@@ -139,7 +139,7 @@ bool decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, c
return false;
}
}
-
+
decoder->buffers[id] = decodedData;
return true;
}
@@ -166,13 +166,13 @@ void decoderCopyAttribute(Decoder *decoder, size_t id, void *output)
}
}
-template<class T>
+template <class T>
void decodeIndices(Decoder *decoder)
{
std::vector<uint8_t> decodedIndices;
decodedIndices.resize(decoder->indexCount * sizeof(T));
T *typedView = reinterpret_cast<T *>(decodedIndices.data());
-
+
for (uint32_t faceIndex = 0; faceIndex < decoder->mesh->num_faces(); ++faceIndex)
{
const draco::Mesh::Face &face = decoder->mesh->face(draco::FaceIndex(faceIndex));
@@ -180,7 +180,7 @@ void decodeIndices(Decoder *decoder)
typedView[faceIndex * 3 + 1] = face[1].value();
typedView[faceIndex * 3 + 2] = face[2].value();
}
-
+
decoder->indexBuffer = decodedIndices;
}
@@ -188,26 +188,26 @@ bool decoderReadIndices(Decoder *decoder, size_t indexComponentType)
{
switch (indexComponentType)
{
- case ComponentType::Byte:
- decodeIndices<int8_t>(decoder);
- break;
- case ComponentType::UnsignedByte:
- decodeIndices<uint8_t>(decoder);
- break;
- case ComponentType::Short:
- decodeIndices<int16_t>(decoder);
- break;
- case ComponentType::UnsignedShort:
- decodeIndices<uint16_t>(decoder);
- break;
- case ComponentType::UnsignedInt:
- decodeIndices<uint32_t>(decoder);
- break;
- default:
- printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
- return false;
+ case ComponentType::Byte:
+ decodeIndices<int8_t>(decoder);
+ break;
+ case ComponentType::UnsignedByte:
+ decodeIndices<uint8_t>(decoder);
+ break;
+ case ComponentType::Short:
+ decodeIndices<int16_t>(decoder);
+ break;
+ case ComponentType::UnsignedShort:
+ decodeIndices<uint16_t>(decoder);
+ break;
+ case ComponentType::UnsignedInt:
+ decodeIndices<uint32_t>(decoder);
+ break;
+ default:
+ printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
+ return false;
}
-
+
return true;
}
diff --git a/extern/draco/src/decoder.h b/extern/draco/src/decoder.h
index 914eb776e8f..c154b426c59 100644
--- a/extern/draco/src/decoder.h
+++ b/extern/draco/src/decoder.h
@@ -28,26 +28,38 @@
struct Decoder;
-API(Decoder *) decoderCreate();
+API(Decoder *)
+decoderCreate();
-API(void) decoderRelease(Decoder *decoder);
+API(void)
+decoderRelease(Decoder *decoder);
-API(bool) decoderDecode(Decoder *decoder, void *data, size_t byteLength);
+API(bool)
+decoderDecode(Decoder *decoder, void *data, size_t byteLength);
-API(uint32_t) decoderGetVertexCount(Decoder *decoder);
+API(uint32_t)
+decoderGetVertexCount(Decoder *decoder);
-API(uint32_t) decoderGetIndexCount(Decoder *decoder);
+API(uint32_t)
+decoderGetIndexCount(Decoder *decoder);
-API(bool) decoderAttributeIsNormalized(Decoder *decoder, uint32_t id);
+API(bool)
+decoderAttributeIsNormalized(Decoder *decoder, uint32_t id);
-API(bool) decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType);
+API(bool)
+decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType);
-API(size_t) decoderGetAttributeByteLength(Decoder *decoder, size_t id);
+API(size_t)
+decoderGetAttributeByteLength(Decoder *decoder, size_t id);
-API(void) decoderCopyAttribute(Decoder *decoder, size_t id, void *output);
+API(void)
+decoderCopyAttribute(Decoder *decoder, size_t id, void *output);
-API(bool) decoderReadIndices(Decoder *decoder, size_t indexComponentType);
+API(bool)
+decoderReadIndices(Decoder *decoder, size_t indexComponentType);
-API(size_t) decoderGetIndicesByteLength(Decoder *decoder);
+API(size_t)
+decoderGetIndicesByteLength(Decoder *decoder);
-API(void) decoderCopyIndices(Decoder *decoder, void *output);
+API(void)
+decoderCopyIndices(Decoder *decoder, void *output);
diff --git a/extern/draco/src/encoder.cpp b/extern/draco/src/encoder.cpp
index ff7570ecfcd..34282ced8c6 100644
--- a/extern/draco/src/encoder.cpp
+++ b/extern/draco/src/encoder.cpp
@@ -59,7 +59,8 @@ void encoderRelease(Encoder *encoder)
delete encoder;
}
-void encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel) {
+void encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel)
+{
encoder->compressionLevel = compressionLevel;
}
@@ -75,7 +76,7 @@ void encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t no
bool encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder)
{
printf(LOG_PREFIX "Preserve triangle order: %s\n", preserveTriangleOrder ? "yes" : "no");
-
+
draco::Encoder dracoEncoder;
int speed = 10 - static_cast<int>(encoder->compressionLevel);
@@ -87,12 +88,12 @@ bool encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder)
dracoEncoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, encoder->quantization.color);
dracoEncoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, encoder->quantization.generic);
dracoEncoder.SetTrackEncodedProperties(true);
-
+
if (preserveTriangleOrder)
{
dracoEncoder.SetEncodingMethod(draco::MESH_SEQUENTIAL_ENCODING);
}
-
+
auto encoderStatus = dracoEncoder.EncodeMeshToBuffer(encoder->mesh, &encoder->encoderBuffer);
if (encoderStatus.ok())
{
@@ -130,20 +131,19 @@ void encoderCopy(Encoder *encoder, uint8_t *data)
memcpy(data, encoder->encoderBuffer.data(), encoder->encoderBuffer.size());
}
-template<class T>
+template <class T>
void encodeIndices(Encoder *encoder, uint32_t indexCount, T *indices)
{
int face_count = indexCount / 3;
encoder->mesh.SetNumFaces(static_cast<size_t>(face_count));
encoder->rawSize += indexCount * sizeof(T);
-
+
for (int i = 0; i < face_count; ++i)
{
draco::Mesh::Face face = {
draco::PointIndex(indices[3 * i + 0]),
draco::PointIndex(indices[3 * i + 1]),
- draco::PointIndex(indices[3 * i + 2])
- };
+ draco::PointIndex(indices[3 * i + 2])};
encoder->mesh.SetFace(draco::FaceIndex(static_cast<uint32_t>(i)), face);
}
}
@@ -152,23 +152,23 @@ void encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t ind
{
switch (indexComponentType)
{
- case ComponentType::Byte:
- encodeIndices(encoder, indexCount, reinterpret_cast<int8_t *>(indices));
- break;
- case ComponentType::UnsignedByte:
- encodeIndices(encoder, indexCount, reinterpret_cast<uint8_t *>(indices));
- break;
- case ComponentType::Short:
- encodeIndices(encoder, indexCount, reinterpret_cast<int16_t *>(indices));
- break;
- case ComponentType::UnsignedShort:
- encodeIndices(encoder, indexCount, reinterpret_cast<uint16_t *>(indices));
- break;
- case ComponentType::UnsignedInt:
- encodeIndices(encoder, indexCount, reinterpret_cast<uint32_t *>(indices));
- break;
- default:
- printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
+ case ComponentType::Byte:
+ encodeIndices(encoder, indexCount, reinterpret_cast<int8_t *>(indices));
+ break;
+ case ComponentType::UnsignedByte:
+ encodeIndices(encoder, indexCount, reinterpret_cast<uint8_t *>(indices));
+ break;
+ case ComponentType::Short:
+ encodeIndices(encoder, indexCount, reinterpret_cast<int16_t *>(indices));
+ break;
+ case ComponentType::UnsignedShort:
+ encodeIndices(encoder, indexCount, reinterpret_cast<uint16_t *>(indices));
+ break;
+ case ComponentType::UnsignedInt:
+ encodeIndices(encoder, indexCount, reinterpret_cast<uint32_t *>(indices));
+ break;
+ default:
+ printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType);
}
}
@@ -190,7 +190,7 @@ draco::GeometryAttribute::Type getAttributeSemantics(char *attribute)
{
return draco::GeometryAttribute::COLOR;
}
-
+
return draco::GeometryAttribute::GENERIC;
}
@@ -198,37 +198,38 @@ draco::DataType getDataType(size_t componentType)
{
switch (componentType)
{
- case ComponentType::Byte:
- return draco::DataType::DT_INT8;
-
- case ComponentType::UnsignedByte:
- return draco::DataType::DT_UINT8;
-
- case ComponentType::Short:
- return draco::DataType::DT_INT16;
-
- case ComponentType::UnsignedShort:
- return draco::DataType::DT_UINT16;
-
- case ComponentType::UnsignedInt:
- return draco::DataType::DT_UINT32;
-
- case ComponentType::Float:
- return draco::DataType::DT_FLOAT32;
-
- default:
- return draco::DataType::DT_INVALID;
+ case ComponentType::Byte:
+ return draco::DataType::DT_INT8;
+
+ case ComponentType::UnsignedByte:
+ return draco::DataType::DT_UINT8;
+
+ case ComponentType::Short:
+ return draco::DataType::DT_INT16;
+
+ case ComponentType::UnsignedShort:
+ return draco::DataType::DT_UINT16;
+
+ case ComponentType::UnsignedInt:
+ return draco::DataType::DT_UINT32;
+
+ case ComponentType::Float:
+ return draco::DataType::DT_FLOAT32;
+
+ default:
+ return draco::DataType::DT_INVALID;
}
}
-API(uint32_t) encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data)
+API(uint32_t)
+encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data)
{
auto buffer = std::make_unique<draco::DataBuffer>();
uint32_t count = encoder->mesh.num_points();
size_t componentCount = getNumberOfComponents(dataType);
size_t stride = getAttributeStride(componentType, dataType);
draco::DataType dracoDataType = getDataType(componentType);
-
+
draco::GeometryAttribute::Type semantics = getAttributeSemantics(attributeName);
draco::GeometryAttribute attribute;
attribute.Init(semantics, &*buffer, componentCount, getDataType(componentType), false, stride, 0);
diff --git a/extern/draco/src/encoder.h b/extern/draco/src/encoder.h
index 2f7f21a469b..c6fdc30295b 100644
--- a/extern/draco/src/encoder.h
+++ b/extern/draco/src/encoder.h
@@ -28,24 +28,35 @@
struct Encoder;
-API(Encoder *) encoderCreate(uint32_t vertexCount);
+API(Encoder *)
+encoderCreate(uint32_t vertexCount);
-API(void) encoderRelease(Encoder *encoder);
+API(void)
+encoderRelease(Encoder *encoder);
-API(void) encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel);
+API(void)
+encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel);
-API(void) encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t normal, uint32_t uv, uint32_t color, uint32_t generic);
+API(void)
+encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t normal, uint32_t uv, uint32_t color, uint32_t generic);
-API(bool) encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder);
+API(bool)
+encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder);
-API(uint64_t) encoderGetByteLength(Encoder *encoder);
+API(uint64_t)
+encoderGetByteLength(Encoder *encoder);
-API(void) encoderCopy(Encoder *encoder, uint8_t *data);
+API(void)
+encoderCopy(Encoder *encoder, uint8_t *data);
-API(void) encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t indexCount, void *indices);
+API(void)
+encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t indexCount, void *indices);
-API(uint32_t) encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data);
+API(uint32_t)
+encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data);
-API(uint32_t) encoderGetEncodedVertexCount(Encoder *encoder);
+API(uint32_t)
+encoderGetEncodedVertexCount(Encoder *encoder);
-API(uint32_t) encoderGetEncodedIndexCount(Encoder *encoder);
+API(uint32_t)
+encoderGetEncodedIndexCount(Encoder *encoder);
diff --git a/extern/mantaflow/README.blender b/extern/mantaflow/README.blender
index bc1e2a164dc..b0b010d54f4 100644
--- a/extern/mantaflow/README.blender
+++ b/extern/mantaflow/README.blender
@@ -2,4 +2,5 @@ Project: Mantaflow
URL: http://mantaflow.com/
License: Apache 2.0
Upstream version: 0.13
-Local modifications: None
+Local modifications:
+* ./patches/local_namespace.diff to support loading MANTA variables into an isolated __main__ name-space.
diff --git a/extern/mantaflow/helper/pwrapper/registry.cpp b/extern/mantaflow/helper/pwrapper/registry.cpp
index 5196c0409f8..b4206a41dea 100644
--- a/extern/mantaflow/helper/pwrapper/registry.cpp
+++ b/extern/mantaflow/helper/pwrapper/registry.cpp
@@ -115,7 +115,7 @@ class WrapperRegistry {
void construct(const std::string &scriptname, const vector<string> &args);
void cleanup();
void renameObjects();
- void runPreInit();
+ void runPreInit(PyObject *name_space);
PyObject *initModule();
ClassData *lookup(const std::string &name);
bool canConvert(ClassData *from, ClassData *to);
@@ -505,7 +505,7 @@ void WrapperRegistry::addConstants(PyObject *module)
}
}
-void WrapperRegistry::runPreInit()
+void WrapperRegistry::runPreInit(PyObject *name_space)
{
// add python directories to path
PyObject *sys_path = PySys_GetObject((char *)"path");
@@ -518,7 +518,15 @@ void WrapperRegistry::runPreInit()
}
if (!mCode.empty()) {
mCode = "from manta import *\n" + mCode;
- PyRun_SimpleString(mCode.c_str());
+ PyObject *return_value = PyRun_String(mCode.c_str(), Py_file_input, name_space, name_space);
+ if (return_value == nullptr) {
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ }
+ }
+ else {
+ Py_DECREF(return_value);
+ }
}
}
@@ -698,16 +706,23 @@ PyObject *WrapperRegistry::initModule()
//******************************************************
// Register members and exposed functions
-void setup(const std::string &filename, const std::vector<std::string> &args)
+void setup(const bool python_lifecycle,
+ const std::string &filename,
+ const std::vector<std::string> &args,
+ PyObject *name_space)
{
WrapperRegistry::instance().construct(filename, args);
- Py_Initialize();
- WrapperRegistry::instance().runPreInit();
+ if (python_lifecycle) {
+ Py_Initialize();
+ }
+ WrapperRegistry::instance().runPreInit(name_space);
}
-void finalize()
+void finalize(const bool python_lifecycle)
{
- Py_Finalize();
+ if (python_lifecycle) {
+ Py_Finalize();
+ }
WrapperRegistry::instance().cleanup();
}
diff --git a/extern/mantaflow/helper/pwrapper/registry.h b/extern/mantaflow/helper/pwrapper/registry.h
index d9d2bbb624b..2273d0b9bb1 100644
--- a/extern/mantaflow/helper/pwrapper/registry.h
+++ b/extern/mantaflow/helper/pwrapper/registry.h
@@ -48,8 +48,11 @@ template<class T> struct Namify {
namespace Pb {
// internal registry access
-void setup(const std::string &filename, const std::vector<std::string> &args);
-void finalize();
+void setup(bool python_lifecycle,
+ const std::string &filename,
+ const std::vector<std::string> &args,
+ PyObject *name_space);
+void finalize(bool python_lifecycle);
bool canConvert(PyObject *obj, const std::string &to);
Manta::PbClass *objFromPy(PyObject *obj);
Manta::PbClass *createPy(const std::string &classname,
diff --git a/extern/mantaflow/patches/local_namespace.diff b/extern/mantaflow/patches/local_namespace.diff
new file mode 100644
index 00000000000..41bc1696772
--- /dev/null
+++ b/extern/mantaflow/patches/local_namespace.diff
@@ -0,0 +1,86 @@
+diff --git a/extern/mantaflow/helper/pwrapper/registry.cpp b/extern/mantaflow/helper/pwrapper/registry.cpp
+index 5196c0409f8..b4206a41dea 100644
+--- a/extern/mantaflow/helper/pwrapper/registry.cpp
++++ b/extern/mantaflow/helper/pwrapper/registry.cpp
+@@ -115,7 +115,7 @@ class WrapperRegistry {
+ void construct(const std::string &scriptname, const vector<string> &args);
+ void cleanup();
+ void renameObjects();
+- void runPreInit();
++ void runPreInit(PyObject *name_space);
+ PyObject *initModule();
+ ClassData *lookup(const std::string &name);
+ bool canConvert(ClassData *from, ClassData *to);
+@@ -505,7 +505,7 @@ void WrapperRegistry::addConstants(PyObject *module)
+ }
+ }
+
+-void WrapperRegistry::runPreInit()
++void WrapperRegistry::runPreInit(PyObject *name_space)
+ {
+ // add python directories to path
+ PyObject *sys_path = PySys_GetObject((char *)"path");
+@@ -518,7 +518,15 @@ void WrapperRegistry::runPreInit()
+ }
+ if (!mCode.empty()) {
+ mCode = "from manta import *\n" + mCode;
+- PyRun_SimpleString(mCode.c_str());
++ PyObject *return_value = PyRun_String(mCode.c_str(), Py_file_input, name_space, name_space);
++ if (return_value == nullptr) {
++ if (PyErr_Occurred()) {
++ PyErr_Print();
++ }
++ }
++ else {
++ Py_DECREF(return_value);
++ }
+ }
+ }
+
+@@ -698,16 +706,23 @@ PyObject *WrapperRegistry::initModule()
+ //******************************************************
+ // Register members and exposed functions
+
+-void setup(const std::string &filename, const std::vector<std::string> &args)
++void setup(const bool python_lifecycle,
++ const std::string &filename,
++ const std::vector<std::string> &args,
++ PyObject *name_space)
+ {
+ WrapperRegistry::instance().construct(filename, args);
+- Py_Initialize();
+- WrapperRegistry::instance().runPreInit();
++ if (python_lifecycle) {
++ Py_Initialize();
++ }
++ WrapperRegistry::instance().runPreInit(name_space);
+ }
+
+-void finalize()
++void finalize(const bool python_lifecycle)
+ {
+- Py_Finalize();
++ if (python_lifecycle) {
++ Py_Finalize();
++ }
+ WrapperRegistry::instance().cleanup();
+ }
+
+diff --git a/extern/mantaflow/helper/pwrapper/registry.h b/extern/mantaflow/helper/pwrapper/registry.h
+index d9d2bbb624b..2273d0b9bb1 100644
+--- a/extern/mantaflow/helper/pwrapper/registry.h
++++ b/extern/mantaflow/helper/pwrapper/registry.h
+@@ -48,8 +48,11 @@ template<class T> struct Namify {
+ namespace Pb {
+
+ // internal registry access
+-void setup(const std::string &filename, const std::vector<std::string> &args);
+-void finalize();
++void setup(bool python_lifecycle,
++ const std::string &filename,
++ const std::vector<std::string> &args,
++ PyObject *name_space);
++void finalize(bool python_lifecycle);
+ bool canConvert(PyObject *obj, const std::string &to);
+ Manta::PbClass *objFromPy(PyObject *obj);
+ Manta::PbClass *createPy(const std::string &classname,
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt
index 2ff2fb39806..6387fd016ba 100644
--- a/intern/CMakeLists.txt
+++ b/intern/CMakeLists.txt
@@ -67,3 +67,10 @@ endif()
if(UNIX AND NOT APPLE)
add_subdirectory(libc_compat)
endif()
+
+if(UNIX AND NOT APPLE)
+ # Important this comes after "ghost" as it uses includes defined by GHOST's CMake.
+ if(WITH_GHOST_WAYLAND AND WITH_GHOST_WAYLAND_DYNLOAD)
+ add_subdirectory(wayland_dynload)
+ endif()
+endif()
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h
index 2bedce1b4f0..65b0c8f9671 100644
--- a/intern/atomic/atomic_ops.h
+++ b/intern/atomic/atomic_ops.h
@@ -124,6 +124,8 @@ ATOMIC_INLINE unsigned int atomic_fetch_and_sub_u(unsigned int *p, unsigned int
ATOMIC_INLINE unsigned int atomic_cas_u(unsigned int *v, unsigned int old, unsigned int _new);
ATOMIC_INLINE void *atomic_cas_ptr(void **v, void *old, void *_new);
+ATOMIC_INLINE void *atomic_load_ptr(void *const *v);
+ATOMIC_INLINE void atomic_store_ptr(void **p, void *v);
ATOMIC_INLINE float atomic_cas_float(float *v, float old, float _new);
diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h
index 6ecc47f18be..b5e1022fb91 100644
--- a/intern/atomic/intern/atomic_ops_ext.h
+++ b/intern/atomic/intern/atomic_ops_ext.h
@@ -205,6 +205,24 @@ ATOMIC_INLINE void *atomic_cas_ptr(void **v, void *old, void *_new)
#endif
}
+ATOMIC_INLINE void *atomic_load_ptr(void *const *v)
+{
+#if (LG_SIZEOF_PTR == 8)
+ return (void *)atomic_load_uint64((const uint64_t *)v);
+#elif (LG_SIZEOF_PTR == 4)
+ return (void *)atomic_load_uint32((const uint32_t *)v);
+#endif
+}
+
+ATOMIC_INLINE void atomic_store_ptr(void **p, void *v)
+{
+#if (LG_SIZEOF_PTR == 8)
+ atomic_store_uint64((uint64_t *)p, (uint64_t)v);
+#elif (LG_SIZEOF_PTR == 4)
+ atomic_store_uint32((uint32_t *)p, (uint32_t)v);
+#endif
+}
+
/******************************************************************************/
/* float operations. */
ATOMIC_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "sizeof(float) != sizeof(uint32_t)");
diff --git a/intern/atomic/tests/atomic_test.cc b/intern/atomic/tests/atomic_test.cc
index ee06085c95d..37a66cf0e9c 100644
--- a/intern/atomic/tests/atomic_test.cc
+++ b/intern/atomic/tests/atomic_test.cc
@@ -1060,6 +1060,25 @@ TEST(atomic, atomic_cas_ptr)
}
}
+TEST(atomic, atomic_load_ptr)
+{
+ {
+ void *value = INT_AS_PTR(0x7f);
+ void *dest = atomic_load_ptr(&value);
+ EXPECT_EQ(dest, INT_AS_PTR(0x7f));
+ }
+}
+
+TEST(atomic, atomic_store_ptr)
+{
+ {
+ void *value = INT_AS_PTR(0x7f);
+ void *dest = nullptr;
+ atomic_store_ptr(&dest, value);
+ EXPECT_EQ(dest, INT_AS_PTR(0x7f));
+ }
+}
+
#undef INT_AS_PTR
/** \} */
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index f5d717e70fc..82fd81be262 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -263,6 +263,10 @@ if(WITH_CYCLES_DEVICE_OPTIX)
endif()
endif()
+if (WITH_CYCLES_DEVICE_ONEAPI)
+ add_definitions(-DWITH_ONEAPI)
+endif()
+
if(WITH_CYCLES_EMBREE)
add_definitions(-DWITH_EMBREE)
include_directories(
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt
index 4919b99cfe0..63d89221d20 100644
--- a/intern/cycles/blender/CMakeLists.txt
+++ b/intern/cycles/blender/CMakeLists.txt
@@ -128,10 +128,6 @@ if(WITH_OPENIMAGEDENOISE)
)
endif()
-if(WITH_EXPERIMENTAL_FEATURES)
- add_definitions(-DWITH_NEW_CURVES_TYPE)
-endif()
-
blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_dependencies(bf_intern_cycles bf_rna)
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 74b28b8ea21..05f27bdbd4d 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
bl_info = {
diff --git a/intern/cycles/blender/addon/camera.py b/intern/cycles/blender/addon/camera.py
index 0e78112699e..3c821c98128 100644
--- a/intern/cycles/blender/addon/camera.py
+++ b/intern/cycles/blender/addon/camera.py
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-# <pep8 compliant>
-
# Fit to match default projective camera with focal_length 50 and sensor_width 36.
default_fisheye_polynomial = [
-1.1735143712967577e-05,
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 724e1b8f727..e211f53cf31 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
diff --git a/intern/cycles/blender/addon/operators.py b/intern/cycles/blender/addon/operators.py
index e5d7f00a381..ab474cda0ab 100644
--- a/intern/cycles/blender/addon/operators.py
+++ b/intern/cycles/blender/addon/operators.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/addon/osl.py b/intern/cycles/blender/addon/osl.py
index 9430dc5d115..1ee7ae421e3 100644
--- a/intern/cycles/blender/addon/osl.py
+++ b/intern/cycles/blender/addon/osl.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py
index 5eaa592a9de..e1f08c07eaf 100644
--- a/intern/cycles/blender/addon/presets.py
+++ b/intern/cycles/blender/addon/presets.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
from bl_operators.presets import AddPresetBase
@@ -86,10 +84,36 @@ class AddPresetViewportSampling(AddPresetBase, Operator):
preset_subdir = "cycles/viewport_sampling"
+class AddPresetPerformance(AddPresetBase, Operator):
+ '''Add an Performance Preset'''
+ bl_idname = "render.cycles_performance_preset_add"
+ bl_label = "Add Performance Preset"
+ preset_menu = "CYCLES_PT_performance_presets"
+
+ preset_defines = [
+ "render = bpy.context.scene.render"
+ "cycles = bpy.context.scene.cycles"
+ ]
+
+ preset_values = [
+ "render.threads_mode",
+ "render.use_persistent_data",
+ "cycles.debug_use_spatial_splits",
+ "cycles.debug_use_compact_bvh",
+ "cycles.debug_use_hair_bvh",
+ "cycles.debug_bvh_time_steps",
+ "cycles.use_auto_tile",
+ "cycles.tile_size",
+ ]
+
+ preset_subdir = "cycles/performance"
+
+
classes = (
AddPresetIntegrator,
AddPresetSampling,
AddPresetViewportSampling,
+ AddPresetPerformance,
)
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 9acc9e99ad0..2c926893f9d 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
@@ -120,7 +118,8 @@ enum_device_type = (
('CUDA', "CUDA", "CUDA", 1),
('OPTIX', "OptiX", "OptiX", 3),
('HIP', "HIP", "HIP", 4),
- ('METAL', "Metal", "Metal", 5)
+ ('METAL', "Metal", "Metal", 5),
+ ('ONEAPI', "oneAPI", "oneAPI", 6)
)
enum_texture_limit = (
@@ -694,7 +693,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
debug_use_compact_bvh: BoolProperty(
name="Use Compact BVH",
description="Use compact BVH structure (uses less ram but renders slower)",
- default=True,
+ default=False,
)
debug_bvh_time_steps: IntProperty(
name="BVH Time Steps",
@@ -1399,7 +1398,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_device_types(self, context):
import _cycles
- has_cuda, has_optix, has_hip, has_metal = _cycles.get_device_types()
+ has_cuda, has_optix, has_hip, has_metal, has_oneapi = _cycles.get_device_types()
+
list = [('NONE', "None", "Don't use compute device", 0)]
if has_cuda:
list.append(('CUDA', "CUDA", "Use CUDA for GPU acceleration", 1))
@@ -1409,6 +1409,8 @@ class CyclesPreferences(bpy.types.AddonPreferences):
list.append(('HIP', "HIP", "Use HIP for GPU acceleration", 4))
if has_metal:
list.append(('METAL', "Metal", "Use Metal for GPU acceleration", 5))
+ if has_oneapi:
+ list.append(('ONEAPI', "oneAPI", "Use oneAPI for GPU acceleration", 6))
return list
@@ -1440,7 +1442,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def update_device_entries(self, device_list):
for device in device_list:
- if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP', 'METAL'}:
+ if not device[1] in {'CUDA', 'OPTIX', 'CPU', 'HIP', 'METAL', 'ONEAPI'}:
continue
# Try to find existing Device entry
entry = self.find_existing_device_entry(device)
@@ -1484,7 +1486,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
import _cycles
# Ensure `self.devices` is not re-allocated when the second call to
# get_devices_for_type is made, freeing items from the first list.
- for device_type in ('CUDA', 'OPTIX', 'HIP', 'METAL'):
+ for device_type in ('CUDA', 'OPTIX', 'HIP', 'METAL', 'ONEAPI'):
self.update_device_entries(_cycles.available_devices(device_type))
# Deprecated: use refresh_devices instead.
@@ -1547,18 +1549,31 @@ class CyclesPreferences(bpy.types.AddonPreferences):
elif device_type == 'HIP':
import sys
if sys.platform[:3] == "win":
- col.label(text="Requires discrete AMD GPU with RDNA architecture", icon='BLANK1')
+ col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
col.label(text="and AMD Radeon Pro 21.Q4 driver or newer", icon='BLANK1')
elif sys.platform.startswith("linux"):
- col.label(text="Requires discrete AMD GPU with RDNA architecture", icon='BLANK1')
+ col.label(text="Requires AMD GPU with Vega or RDNA architecture", icon='BLANK1')
col.label(text="and AMD driver version 22.10 or newer", icon='BLANK1')
+ elif device_type == 'ONEAPI':
+ import sys
+ col.label(text="Requires Intel GPU with Xe-HPG architecture", icon='BLANK1')
+ if sys.platform.startswith("win"):
+ col.label(text="and Windows driver version 101.1660 or newer", icon='BLANK1')
+ elif sys.platform.startswith("linux"):
+ col.label(text="and Linux driver version xx.xx.23570 or newer", icon='BLANK1')
elif device_type == 'METAL':
col.label(text="Requires Apple Silicon with macOS 12.2 or newer", icon='BLANK1')
col.label(text="or AMD with macOS 12.3 or newer", icon='BLANK1')
return
for device in devices:
- box.prop(device, "use", text=device.name)
+ import unicodedata
+ box.prop(
+ device, "use", text=device.name
+ .replace('(TM)', unicodedata.lookup('TRADE MARK SIGN'))
+ .replace('(R)', unicodedata.lookup('REGISTERED SIGN'))
+ .replace('(C)', unicodedata.lookup('COPYRIGHT SIGN'))
+ )
def draw_impl(self, layout, context):
row = layout.row()
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 9d2dbdf6732..0fead409866 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
@@ -45,6 +43,12 @@ class CYCLES_PT_integrator_presets(CyclesPresetPanel):
preset_add_operator = "render.cycles_integrator_preset_add"
+class CYCLES_PT_performance_presets(CyclesPresetPanel):
+ bl_label = "Performance Presets"
+ preset_subdir = "cycles/performance"
+ preset_add_operator = "render.cycles_performance_preset_add"
+
+
class CyclesButtonsPanel:
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
@@ -113,6 +117,12 @@ def use_optix(context):
return (get_device_type(context) == 'OPTIX' and cscene.device == 'GPU')
+def use_oneapi(context):
+ cscene = context.scene.cycles
+
+ return (get_device_type(context) == 'ONEAPI' and cscene.device == 'GPU')
+
+
def use_multi_device(context):
cscene = context.scene.cycles
if cscene.device != 'GPU':
@@ -620,6 +630,9 @@ class CYCLES_RENDER_PT_performance(CyclesButtonsPanel, Panel):
bl_label = "Performance"
bl_options = {'DEFAULT_CLOSED'}
+ def draw_header_preset(self, context):
+ CYCLES_PT_performance_presets.draw_panel_header(self.layout)
+
def draw(self, context):
pass
@@ -756,8 +769,6 @@ class CYCLES_RENDER_PT_filter(CyclesButtonsPanel, Panel):
layout.use_property_split = True
layout.use_property_decorate = False
- with_freestyle = bpy.app.build_options.freestyle
-
scene = context.scene
rd = scene.render
view_layer = context.view_layer
@@ -941,6 +952,8 @@ class CYCLES_CAMERA_PT_dof(CyclesButtonsPanel, Panel):
col = split.column()
col.prop(dof, "focus_object", text="Focus Object")
+ if dof.focus_object and dof.focus_object.type == 'ARMATURE':
+ col.prop_search(dof, "focus_subtarget", dof.focus_object.data, "bones", text="Focus Bone")
sub = col.row()
sub.active = dof.focus_object is None
@@ -1200,7 +1213,7 @@ class CYCLES_OBJECT_PT_lightgroup(CyclesButtonsPanel, Panel):
sub.prop_search(ob, "lightgroup", view_layer, "lightgroups", text="Light Group", results_are_suggestions=True)
sub = row.column(align=True)
- sub.active = bool(ob.lightgroup) and not any(lg.name == ob.lightgroup for lg in view_layer.lightgroups)
+ sub.enabled = bool(ob.lightgroup) and not any(lg.name == ob.lightgroup for lg in view_layer.lightgroups)
sub.operator("scene.view_layer_add_lightgroup", icon='ADD', text="").name = ob.lightgroup
@@ -1638,7 +1651,7 @@ class CYCLES_WORLD_PT_settings_light_group(CyclesButtonsPanel, Panel):
)
sub = row.column(align=True)
- sub.active = bool(world.lightgroup) and not any(lg.name == world.lightgroup for lg in view_layer.lightgroups)
+ sub.enabled = bool(world.lightgroup) and not any(lg.name == world.lightgroup for lg in view_layer.lightgroups)
sub.operator("scene.view_layer_add_lightgroup", icon='ADD', text="").name = world.lightgroup
@@ -2267,6 +2280,7 @@ classes = (
CYCLES_PT_sampling_presets,
CYCLES_PT_viewport_sampling_presets,
CYCLES_PT_integrator_presets,
+ CYCLES_PT_performance_presets,
CYCLES_RENDER_PT_sampling,
CYCLES_RENDER_PT_sampling_viewport,
CYCLES_RENDER_PT_sampling_viewport_denoise,
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 531ecc177da..12880496dfd 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/camera.cpp b/intern/cycles/blender/camera.cpp
index 402fd7c4ec6..6926c833096 100644
--- a/intern/cycles/blender/camera.cpp
+++ b/intern/cycles/blender/camera.cpp
@@ -143,11 +143,20 @@ static float blender_camera_focal_distance(BL::RenderEngine &b_engine,
if (!b_dof_object)
return b_camera.dof().focus_distance();
+ Transform dofmat = get_transform(b_dof_object.matrix_world());
+
+ string focus_subtarget = b_camera.dof().focus_subtarget();
+ if (b_dof_object.pose() && !focus_subtarget.empty()) {
+ BL::PoseBone b_bone = b_dof_object.pose().bones[focus_subtarget];
+ if (b_bone) {
+ dofmat = dofmat * get_transform(b_bone.matrix());
+ }
+ }
+
/* for dof object, return distance along camera Z direction */
BL::Array<float, 16> b_ob_matrix;
b_engine.camera_model_matrix(b_ob, bcam->use_spherical_stereo, b_ob_matrix);
Transform obmat = transform_clear_scale(get_transform(b_ob_matrix));
- Transform dofmat = get_transform(b_dof_object.matrix_world());
float3 view_dir = normalize(transform_get_column(&obmat, 2));
float3 dof_dir = transform_get_column(&obmat, 3) - transform_get_column(&dofmat, 3);
return fabsf(dot(view_dir, dof_dir));
@@ -643,7 +652,7 @@ void BlenderSync::sync_camera_motion(
/* TODO(sergey): De-duplicate calculation with camera sync. */
float fov = 2.0f * atanf((0.5f * sensor_size) / bcam.lens / aspectratio);
if (fov != cam->get_fov()) {
- VLOG(3) << "Camera " << b_ob.name() << " FOV change detected.";
+ VLOG_WORK << "Camera " << b_ob.name() << " FOV change detected.";
if (motion_time == 0.0f) {
cam->set_fov(fov);
}
diff --git a/intern/cycles/blender/curves.cpp b/intern/cycles/blender/curves.cpp
index 4e9f4f62087..c4154bce022 100644
--- a/intern/cycles/blender/curves.cpp
+++ b/intern/cycles/blender/curves.cpp
@@ -341,7 +341,7 @@ static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CDa
/* check allocation */
if ((hair->get_curve_keys().size() != num_keys) || (hair->num_curves() != num_curves)) {
- VLOG(1) << "Hair memory allocation failed, clearing data.";
+ VLOG_WARNING << "Hair memory allocation failed, clearing data.";
hair->clear(true);
}
}
@@ -397,7 +397,7 @@ static void export_hair_motion_validate_attribute(Hair *hair,
if (num_motion_keys != num_keys || !have_motion) {
/* No motion or hair "topology" changed, remove attributes again. */
if (num_motion_keys != num_keys) {
- VLOG(1) << "Hair topology changed, removing motion attribute.";
+ VLOG_WORK << "Hair topology changed, removing motion attribute.";
}
hair->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
}
@@ -613,8 +613,6 @@ void BlenderSync::sync_particle_hair(
}
}
-#ifdef WITH_NEW_CURVES_TYPE
-
static std::optional<BL::FloatAttribute> find_curves_radius_attribute(BL::Curves b_curves)
{
for (BL::Attribute &b_attribute : b_curves.attributes) {
@@ -632,6 +630,25 @@ static std::optional<BL::FloatAttribute> find_curves_radius_attribute(BL::Curves
return std::nullopt;
}
+static BL::FloatVectorAttribute find_curves_position_attribute(BL::Curves b_curves)
+{
+ for (BL::Attribute &b_attribute : b_curves.attributes) {
+ if (b_attribute.name() != "position") {
+ continue;
+ }
+ if (b_attribute.domain() != BL::Attribute::domain_POINT) {
+ continue;
+ }
+ if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
+ continue;
+ }
+ return BL::FloatVectorAttribute{b_attribute};
+ }
+ /* The position attribute must exist. */
+ assert(false);
+ return BL::FloatVectorAttribute{b_curves.attributes[0]};
+}
+
template<typename TypeInCycles, typename GetValueAtIndex>
static void fill_generic_attribute(BL::Curves &b_curves,
TypeInCycles *data,
@@ -795,16 +812,16 @@ static void attr_create_generic(Scene *scene,
}
}
-static float4 hair_point_as_float4(BL::Curves b_curves,
+static float4 hair_point_as_float4(BL::FloatVectorAttribute b_attr_position,
std::optional<BL::FloatAttribute> b_attr_radius,
const int index)
{
- float4 mP = float3_to_float4(get_float3(b_curves.position_data[index].vector()));
+ float4 mP = float3_to_float4(get_float3(b_attr_position.data[index].vector()));
mP.w = b_attr_radius ? b_attr_radius->data[index].value() : 0.0f;
return mP;
}
-static float4 interpolate_hair_points(BL::Curves b_curves,
+static float4 interpolate_hair_points(BL::FloatVectorAttribute b_attr_position,
std::optional<BL::FloatAttribute> b_attr_radius,
const int first_point_index,
const int num_points,
@@ -814,8 +831,8 @@ static float4 interpolate_hair_points(BL::Curves b_curves,
const int point_a = clamp((int)curve_t, 0, num_points - 1);
const int point_b = min(point_a + 1, num_points - 1);
const float t = curve_t - (float)point_a;
- return lerp(hair_point_as_float4(b_curves, b_attr_radius, first_point_index + point_a),
- hair_point_as_float4(b_curves, b_attr_radius, first_point_index + point_b),
+ return lerp(hair_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_a),
+ hair_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_b),
t);
}
@@ -848,6 +865,7 @@ static void export_hair_curves(Scene *scene,
hair->reserve_curves(num_curves, num_keys);
+ BL::FloatVectorAttribute b_attr_position = find_curves_position_attribute(b_curves);
std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_curves);
/* Export curves and points. */
@@ -866,9 +884,9 @@ static void export_hair_curves(Scene *scene,
/* Position and radius. */
for (int i = 0; i < num_points; i++) {
- const float3 co = get_float3(b_curves.position_data[first_point_index + i].vector());
+ const float3 co = get_float3(b_attr_position.data[first_point_index + i].vector());
const float radius = b_attr_radius ? b_attr_radius->data[first_point_index + i].value() :
- 0.0f;
+ 0.005f;
hair->add_curve_key(co, radius);
if (attr_intercept) {
@@ -923,6 +941,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
int num_motion_keys = 0;
int curve_index = 0;
+ BL::FloatVectorAttribute b_attr_position = find_curves_position_attribute(b_curves);
std::optional<BL::FloatAttribute> b_attr_radius = find_curves_radius_attribute(b_curves);
for (int i = 0; i < num_curves; i++) {
@@ -938,7 +957,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
int point_index = first_point_index + i;
if (point_index < num_keys) {
- mP[num_motion_keys] = hair_point_as_float4(b_curves, b_attr_radius, point_index);
+ mP[num_motion_keys] = hair_point_as_float4(b_attr_position, b_attr_radius, point_index);
num_motion_keys++;
if (!have_motion) {
@@ -958,7 +977,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
for (int i = 0; i < curve.num_keys; i++) {
const float step = i * step_size;
mP[num_motion_keys] = interpolate_hair_points(
- b_curves, b_attr_radius, first_point_index, num_points, step);
+ b_attr_position, b_attr_radius, first_point_index, num_points, step);
num_motion_keys++;
}
have_motion = true;
@@ -990,15 +1009,6 @@ void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int
export_hair_curves(scene, hair, b_curves, need_motion, motion_scale);
}
}
-#else
-void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step)
-{
- (void)hair;
- (void)b_ob_info;
- (void)motion;
- (void)motion_step;
-}
-#endif
void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Hair *hair)
{
@@ -1010,14 +1020,11 @@ void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, H
new_hair.set_used_shaders(used_shaders);
if (view_layer.use_hair) {
-#ifdef WITH_NEW_CURVES_TYPE
if (b_ob_info.object_data.is_a(&RNA_Curves)) {
/* Hair object. */
sync_hair(&new_hair, b_ob_info, false);
}
- else
-#endif
- {
+ else {
/* Particle hair. */
bool need_undeformed = new_hair.need_attribute(scene, ATTR_STD_GENERATED);
BL::Mesh b_mesh = object_to_mesh(
@@ -1064,15 +1071,12 @@ void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
/* Export deformed coordinates. */
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
-#ifdef WITH_NEW_CURVES_TYPE
if (b_ob_info.object_data.is_a(&RNA_Curves)) {
/* Hair object. */
sync_hair(hair, b_ob_info, true, motion_step);
return;
}
- else
-#endif
- {
+ else {
/* Particle hair. */
BL::Mesh b_mesh = object_to_mesh(
b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
diff --git a/intern/cycles/blender/device.cpp b/intern/cycles/blender/device.cpp
index 38effa329a5..22beca898f1 100644
--- a/intern/cycles/blender/device.cpp
+++ b/intern/cycles/blender/device.cpp
@@ -15,6 +15,7 @@ enum ComputeDevice {
COMPUTE_DEVICE_OPTIX = 3,
COMPUTE_DEVICE_HIP = 4,
COMPUTE_DEVICE_METAL = 5,
+ COMPUTE_DEVICE_ONEAPI = 6,
COMPUTE_DEVICE_NUM
};
@@ -76,6 +77,9 @@ DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scen
else if (compute_device == COMPUTE_DEVICE_METAL) {
mask |= DEVICE_MASK_METAL;
}
+ else if (compute_device == COMPUTE_DEVICE_ONEAPI) {
+ mask |= DEVICE_MASK_ONEAPI;
+ }
vector<DeviceInfo> devices = Device::available_devices(mask);
/* Match device preferences and available devices. */
diff --git a/intern/cycles/blender/display_driver.cpp b/intern/cycles/blender/display_driver.cpp
index ee67073a9a4..a1bc064be68 100644
--- a/intern/cycles/blender/display_driver.cpp
+++ b/intern/cycles/blender/display_driver.cpp
@@ -982,10 +982,8 @@ void BlenderDisplayDriver::draw(const Params &params)
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
- if (VLOG_IS_ON(5)) {
- VLOG(5) << "Number of textures: " << GLTexture::num_used;
- VLOG(5) << "Number of PBOs: " << GLPixelBufferObject::num_used;
- }
+ VLOG_DEVICE_STATS << "Display driver number of textures: " << GLTexture::num_used;
+ VLOG_DEVICE_STATS << "Display driver number of PBOs: " << GLPixelBufferObject::num_used;
if (use_gl_context_) {
gl_context_mutex_.unlock();
diff --git a/intern/cycles/blender/geometry.cpp b/intern/cycles/blender/geometry.cpp
index 215860f59e6..fc03ca6e489 100644
--- a/intern/cycles/blender/geometry.cpp
+++ b/intern/cycles/blender/geometry.cpp
@@ -18,11 +18,7 @@ CCL_NAMESPACE_BEGIN
static Geometry::Type determine_geom_type(BObjectInfo &b_ob_info, bool use_particle_hair)
{
-#ifdef WITH_NEW_CURVES_TYPE
if (b_ob_info.object_data.is_a(&RNA_Curves) || use_particle_hair) {
-#else
- if (use_particle_hair) {
-#endif
return Geometry::HAIR;
}
@@ -217,11 +213,7 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph,
if (progress.get_cancel())
return;
-#ifdef WITH_NEW_CURVES_TYPE
if (b_ob_info.object_data.is_a(&RNA_Curves) || use_particle_hair) {
-#else
- if (use_particle_hair) {
-#endif
Hair *hair = static_cast<Hair *>(geom);
sync_hair_motion(b_depsgraph, b_ob_info, hair, motion_step);
}
diff --git a/intern/cycles/blender/image.cpp b/intern/cycles/blender/image.cpp
index e01b72c1653..aea79ad60ad 100644
--- a/intern/cycles/blender/image.cpp
+++ b/intern/cycles/blender/image.cpp
@@ -7,6 +7,8 @@
#include "blender/session.h"
#include "blender/util.h"
+#include "util/half.h"
+
CCL_NAMESPACE_BEGIN
/* Packed Images */
@@ -19,17 +21,40 @@ BlenderImageLoader::BlenderImageLoader(BL::Image b_image,
frame(frame),
tile_number(tile_number),
/* Don't free cache for preview render to avoid race condition from T93560, to be fixed
- properly later as we are close to release. */
+ * properly later as we are close to release. */
free_cache(!is_preview_render && !b_image.has_data())
{
}
bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
{
- metadata.width = b_image.size()[0];
- metadata.height = b_image.size()[1];
+ if (b_image.source() != BL::Image::source_TILED) {
+ /* Image sequence might have different dimensions, and hence needs to be handled in a special
+ * manner.
+ * NOTE: Currently the sequences are not handled by this image loader. */
+ assert(b_image.source() != BL::Image::source_SEQUENCE);
+
+ metadata.width = b_image.size()[0];
+ metadata.height = b_image.size()[1];
+ metadata.channels = b_image.channels();
+ }
+ else {
+ /* Different UDIM tiles might have different resolutions, so get resolution from the actual
+ * tile. */
+ BL::UDIMTile b_udim_tile = b_image.tiles.get(tile_number);
+ if (b_udim_tile) {
+ metadata.width = b_udim_tile.size()[0];
+ metadata.height = b_udim_tile.size()[1];
+ metadata.channels = b_udim_tile.channels();
+ }
+ else {
+ metadata.width = 0;
+ metadata.height = 0;
+ metadata.channels = 0;
+ }
+ }
+
metadata.depth = 1;
- metadata.channels = b_image.channels();
if (b_image.is_float()) {
if (metadata.channels == 1) {
@@ -62,80 +87,134 @@ bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaDat
}
bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
+ void *out_pixels,
+ const size_t out_pixels_size,
const bool associate_alpha)
{
const size_t num_pixels = ((size_t)metadata.width) * metadata.height;
const int channels = metadata.channels;
- if (b_image.is_float()) {
- /* image data */
- float *image_pixels;
- image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile_number);
+ if (metadata.type == IMAGE_DATA_TYPE_FLOAT || metadata.type == IMAGE_DATA_TYPE_FLOAT4) {
+ /* Float. */
+ float *in_pixels = image_get_float_pixels_for_frame(b_image, frame, tile_number);
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(float));
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Straight copy pixel data. */
+ memcpy(out_pixels, in_pixels, out_pixels_size * sizeof(float));
}
else {
+ /* Missing or invalid pixel data. */
if (channels == 1) {
- memset(pixels, 0, num_pixels * sizeof(float));
+ memset(out_pixels, 0, num_pixels * sizeof(float));
}
else {
- const size_t num_pixels_safe = pixels_size / channels;
- float *fp = (float *)pixels;
- for (int i = 0; i < num_pixels_safe; i++, fp += channels) {
- fp[0] = 1.0f;
- fp[1] = 0.0f;
- fp[2] = 1.0f;
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ float *out_pixel = (float *)out_pixels;
+ for (int i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = 1.0f;
+ out_pixel[1] = 0.0f;
+ out_pixel[2] = 1.0f;
if (channels == 4) {
- fp[3] = 1.0f;
+ out_pixel[3] = 1.0f;
}
}
}
}
- if (image_pixels) {
- MEM_freeN(image_pixels);
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
}
}
- else {
- unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
+ else if (metadata.type == IMAGE_DATA_TYPE_HALF || metadata.type == IMAGE_DATA_TYPE_HALF4) {
+ /* Half float. Blender does not have a half type, but in some cases
+ * we up-sample byte to half to avoid precision loss for colorspace
+ * conversion. */
+ unsigned char *in_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Convert uchar to half. */
+ const uchar *in_pixel = in_pixels;
+ half *out_pixel = (half *)out_pixels;
+ if (associate_alpha && channels == 4) {
+ for (size_t i = 0; i < num_pixels; i++, in_pixel += 4, out_pixel += 4) {
+ const float alpha = util_image_cast_to_float(in_pixel[3]);
+ out_pixel[0] = float_to_half_image(util_image_cast_to_float(in_pixel[0]) * alpha);
+ out_pixel[1] = float_to_half_image(util_image_cast_to_float(in_pixel[1]) * alpha);
+ out_pixel[2] = float_to_half_image(util_image_cast_to_float(in_pixel[2]) * alpha);
+ out_pixel[3] = float_to_half_image(alpha);
+ }
+ }
+ else {
+ for (size_t i = 0; i < num_pixels; i++) {
+ for (int c = 0; c < channels; c++, in_pixel++, out_pixel++) {
+ *out_pixel = float_to_half_image(util_image_cast_to_float(*in_pixel));
+ }
+ }
+ }
}
else {
+ /* Missing or invalid pixel data. */
if (channels == 1) {
- memset(pixels, 0, pixels_size * sizeof(unsigned char));
+ memset(out_pixels, 0, num_pixels * sizeof(half));
}
else {
- const size_t num_pixels_safe = pixels_size / channels;
- unsigned char *cp = (unsigned char *)pixels;
- for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
- cp[0] = 255;
- cp[1] = 0;
- cp[2] = 255;
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ half *out_pixel = (half *)out_pixels;
+ for (int i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = float_to_half_image(1.0f);
+ out_pixel[1] = float_to_half_image(0.0f);
+ out_pixel[2] = float_to_half_image(1.0f);
if (channels == 4) {
- cp[3] = 255;
+ out_pixel[3] = float_to_half_image(1.0f);
}
}
}
}
- if (image_pixels) {
- MEM_freeN(image_pixels);
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
}
+ }
+ else {
+ /* Byte. */
+ unsigned char *in_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
+
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Straight copy pixel data. */
+ memcpy(out_pixels, in_pixels, out_pixels_size * sizeof(unsigned char));
- if (associate_alpha) {
- /* Premultiply, byte images are always straight for Blender. */
- unsigned char *cp = (unsigned char *)pixels;
- for (size_t i = 0; i < num_pixels; i++, cp += channels) {
- cp[0] = (cp[0] * cp[3]) / 255;
- cp[1] = (cp[1] * cp[3]) / 255;
- cp[2] = (cp[2] * cp[3]) / 255;
+ if (associate_alpha && channels == 4) {
+ /* Premultiply, byte images are always straight for Blender. */
+ unsigned char *out_pixel = (unsigned char *)out_pixels;
+ for (size_t i = 0; i < num_pixels; i++, out_pixel += 4) {
+ out_pixel[0] = (out_pixel[0] * out_pixel[3]) / 255;
+ out_pixel[1] = (out_pixel[1] * out_pixel[3]) / 255;
+ out_pixel[2] = (out_pixel[2] * out_pixel[3]) / 255;
+ }
+ }
+ }
+ else {
+ /* Missing or invalid pixel data. */
+ if (channels == 1) {
+ memset(out_pixels, 0, out_pixels_size * sizeof(unsigned char));
+ }
+ else {
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ unsigned char *out_pixel = (unsigned char *)out_pixels;
+ for (size_t i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = 255;
+ out_pixel[1] = 0;
+ out_pixel[2] = 255;
+ if (channels == 4) {
+ out_pixel[3] = 255;
+ }
+ }
}
}
+
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
+ }
}
/* Free image buffers to save memory during render. */
diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp
index c76ce3801d4..63913b7cd7f 100644
--- a/intern/cycles/blender/mesh.cpp
+++ b/intern/cycles/blender/mesh.cpp
@@ -267,75 +267,62 @@ static void mikk_compute_tangents(
genTangSpaceDefault(&context);
}
-/* Create sculpt vertex color attributes. */
-static void attr_create_sculpt_vertex_color(Scene *scene,
- Mesh *mesh,
- BL::Mesh &b_mesh,
- bool subdivision)
-{
- for (BL::MeshVertColorLayer &l : b_mesh.sculpt_vertex_colors) {
- const bool active_render = l.active_render();
- AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
- ustring vcol_name = ustring(l.name().c_str());
-
- const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
- mesh->need_attribute(scene, vcol_std);
-
- if (!need_vcol) {
- continue;
- }
-
- AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
- Attribute *vcol_attr = attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_VERTEX);
- vcol_attr->std = vcol_std;
-
- float4 *cdata = vcol_attr->data_float4();
- int numverts = b_mesh.vertices.length();
-
- for (int i = 0; i < numverts; i++) {
- *(cdata++) = get_float4(l.data[i].color());
- }
- }
-}
-
template<typename TypeInCycles, typename GetValueAtIndex>
static void fill_generic_attribute(BL::Mesh &b_mesh,
TypeInCycles *data,
const BL::Attribute::domain_enum b_domain,
+ const bool subdivision,
const GetValueAtIndex &get_value_at_index)
{
switch (b_domain) {
case BL::Attribute::domain_CORNER: {
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- const int index = t.index() * 3;
- BL::Array<int, 3> loops = t.loops();
- data[index] = get_value_at_index(loops[0]);
- data[index + 1] = get_value_at_index(loops[1]);
- data[index + 2] = get_value_at_index(loops[2]);
+ if (subdivision) {
+ for (BL::MeshPolygon &p : b_mesh.polygons) {
+ int n = p.loop_total();
+ for (int i = 0; i < n; i++) {
+ *data = get_value_at_index(p.loop_start() + i);
+ data++;
+ }
+ }
+ }
+ else {
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ const int index = t.index() * 3;
+ BL::Array<int, 3> loops = t.loops();
+ data[index] = get_value_at_index(loops[0]);
+ data[index + 1] = get_value_at_index(loops[1]);
+ data[index + 2] = get_value_at_index(loops[2]);
+ }
}
break;
}
case BL::Attribute::domain_EDGE: {
- /* Average edge attributes at vertices. */
- const size_t num_verts = b_mesh.vertices.length();
- vector<int> count(num_verts, 0);
-
- for (BL::MeshEdge &e : b_mesh.edges) {
- BL::Array<int, 2> vertices = e.vertices();
- TypeInCycles value = get_value_at_index(e.index());
-
- data[vertices[0]] += value;
- data[vertices[1]] += value;
- count[vertices[0]]++;
- count[vertices[1]]++;
+ if constexpr (std::is_same_v<TypeInCycles, uchar4>) {
+ /* uchar4 edge attributes do not exist, and averaging in place
+ * would not work. */
+ assert(0);
}
+ else {
+ /* Average edge attributes at vertices. */
+ const size_t num_verts = b_mesh.vertices.length();
+ vector<int> count(num_verts, 0);
+
+ for (BL::MeshEdge &e : b_mesh.edges) {
+ BL::Array<int, 2> vertices = e.vertices();
+ TypeInCycles value = get_value_at_index(e.index());
+
+ data[vertices[0]] += value;
+ data[vertices[1]] += value;
+ count[vertices[0]]++;
+ count[vertices[1]]++;
+ }
- for (size_t i = 0; i < num_verts; i++) {
- if (count[i] > 1) {
- data[i] /= (float)count[i];
+ for (size_t i = 0; i < num_verts; i++) {
+ if (count[i] > 1) {
+ data[i] /= (float)count[i];
+ }
}
}
-
break;
}
case BL::Attribute::domain_POINT: {
@@ -346,8 +333,16 @@ static void fill_generic_attribute(BL::Mesh &b_mesh,
break;
}
case BL::Attribute::domain_FACE: {
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- data[t.index()] = get_value_at_index(t.polygon_index());
+ if (subdivision) {
+ const int num_polygons = b_mesh.polygons.length();
+ for (int i = 0; i < num_polygons; i++) {
+ data[i] = get_value_at_index(i);
+ }
+ }
+ else {
+ for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
+ data[t.index()] = get_value_at_index(t.polygon_index());
+ }
}
break;
}
@@ -395,21 +390,22 @@ static void attr_create_generic(Scene *scene,
const bool need_motion,
const float motion_scale)
{
- if (subdivision) {
- /* TODO: Handle subdivision correctly. */
- return;
- }
- AttributeSet &attributes = mesh->attributes;
+ AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
static const ustring u_velocity("velocity");
+ int attribute_index = 0;
+ int render_color_index = b_mesh.attributes.render_color_index();
+
for (BL::Attribute &b_attribute : b_mesh.attributes) {
const ustring name{b_attribute.name().c_str()};
+ const bool is_render_color = (attribute_index++ == render_color_index);
if (need_motion && name == u_velocity) {
attr_create_motion(mesh, b_attribute, motion_scale);
}
- if (!mesh->need_attribute(scene, name)) {
+ if (!(mesh->need_attribute(scene, name) ||
+ (is_render_color && mesh->need_attribute(scene, ATTR_STD_VERTEX_COLOR)))) {
continue;
}
if (attributes.find(name)) {
@@ -445,15 +441,16 @@ static void attr_create_generic(Scene *scene,
BL::FloatAttribute b_float_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
- fill_generic_attribute(
- b_mesh, data, b_domain, [&](int i) { return b_float_attribute.data[i].value(); });
+ fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
+ return b_float_attribute.data[i].value();
+ });
break;
}
case BL::Attribute::data_type_BOOLEAN: {
BL::BoolAttribute b_bool_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
- fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
+ fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return (float)b_bool_attribute.data[i].value();
});
break;
@@ -462,25 +459,59 @@ static void attr_create_generic(Scene *scene,
BL::IntAttribute b_int_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
- fill_generic_attribute(
- b_mesh, data, b_domain, [&](int i) { return (float)b_int_attribute.data[i].value(); });
+ fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
+ return (float)b_int_attribute.data[i].value();
+ });
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
- fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
+ fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
return make_float3(v[0], v[1], v[2]);
});
break;
}
+ case BL::Attribute::data_type_BYTE_COLOR: {
+ BL::ByteColorAttribute b_color_attribute{b_attribute};
+
+ if (element == ATTR_ELEMENT_CORNER) {
+ element = ATTR_ELEMENT_CORNER_BYTE;
+ }
+ Attribute *attr = attributes.add(name, TypeRGBA, element);
+ if (is_render_color) {
+ attr->std = ATTR_STD_VERTEX_COLOR;
+ }
+
+ if (element == ATTR_ELEMENT_CORNER_BYTE) {
+ uchar4 *data = attr->data_uchar4();
+ fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
+ /* Compress/encode vertex color using the sRGB curve. */
+ const float4 c = get_float4(b_color_attribute.data[i].color());
+ return color_float4_to_uchar4(color_linear_to_srgb_v4(c));
+ });
+ }
+ else {
+ float4 *data = attr->data_float4();
+ fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
+ BL::Array<float, 4> v = b_color_attribute.data[i].color();
+ return make_float4(v[0], v[1], v[2], v[3]);
+ });
+ }
+ break;
+ }
case BL::Attribute::data_type_FLOAT_COLOR: {
BL::FloatColorAttribute b_color_attribute{b_attribute};
+
Attribute *attr = attributes.add(name, TypeRGBA, element);
+ if (is_render_color) {
+ attr->std = ATTR_STD_VERTEX_COLOR;
+ }
+
float4 *data = attr->data_float4();
- fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
+ fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 4> v = b_color_attribute.data[i].color();
return make_float4(v[0], v[1], v[2], v[3]);
});
@@ -490,7 +521,7 @@ static void attr_create_generic(Scene *scene,
BL::Float2Attribute b_float2_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
- fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
+ fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
return make_float2(v[0], v[1]);
});
@@ -503,69 +534,6 @@ static void attr_create_generic(Scene *scene,
}
}
-/* Create vertex color attributes. */
-static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
-{
- for (BL::MeshLoopColorLayer &l : b_mesh.vertex_colors) {
- const bool active_render = l.active_render();
- AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
- ustring vcol_name = ustring(l.name().c_str());
-
- const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
- mesh->need_attribute(scene, vcol_std);
-
- if (!need_vcol) {
- continue;
- }
-
- Attribute *vcol_attr = NULL;
-
- if (subdivision) {
- if (active_render) {
- vcol_attr = mesh->subd_attributes.add(vcol_std, vcol_name);
- }
- else {
- vcol_attr = mesh->subd_attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
- }
-
- uchar4 *cdata = vcol_attr->data_uchar4();
-
- for (BL::MeshPolygon &p : b_mesh.polygons) {
- int n = p.loop_total();
- for (int i = 0; i < n; i++) {
- float4 color = get_float4(l.data[p.loop_start() + i].color());
- /* Compress/encode vertex color using the sRGB curve. */
- *(cdata++) = color_float4_to_uchar4(color);
- }
- }
- }
- else {
- if (active_render) {
- vcol_attr = mesh->attributes.add(vcol_std, vcol_name);
- }
- else {
- vcol_attr = mesh->attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
- }
-
- uchar4 *cdata = vcol_attr->data_uchar4();
-
- for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
- int3 li = get_int3(t.loops());
- float4 c1 = get_float4(l.data[li[0]].color());
- float4 c2 = get_float4(l.data[li[1]].color());
- float4 c3 = get_float4(l.data[li[2]].color());
-
- /* Compress/encode vertex color using the sRGB curve. */
- cdata[0] = color_float4_to_uchar4(c1);
- cdata[1] = color_float4_to_uchar4(c2);
- cdata[2] = color_float4_to_uchar4(c3);
-
- cdata += 3;
- }
- }
- }
-}
-
/* Create uv map attributes. */
static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
{
@@ -1029,8 +997,6 @@ static void create_mesh(Scene *scene,
* The calculate functions will check whether they're needed or not.
*/
attr_create_pointiness(scene, mesh, b_mesh, subdivision);
- attr_create_vertex_color(scene, mesh, b_mesh, subdivision);
- attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision);
attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
@@ -1246,17 +1212,17 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
memcmp(mP, &mesh->get_verts()[0], sizeof(float3) * numverts) == 0) {
/* no motion, remove attributes again */
if (b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, disabling motion blur for object " << ob_name;
+ VLOG_WARNING << "Topology differs, disabling motion blur for object " << ob_name;
}
else {
- VLOG(1) << "No actual deformation motion for object " << ob_name;
+ VLOG_DEBUG << "No actual deformation motion for object " << ob_name;
}
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
if (attr_mN)
mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_NORMAL);
}
else if (motion_step > 0) {
- VLOG(1) << "Filling deformation motion for object " << ob_name;
+ VLOG_DEBUG << "Filling deformation motion for object " << ob_name;
/* motion, fill up previous steps that we might have skipped because
* they had no motion, but we need them anyway now */
float3 *P = &mesh->get_verts()[0];
@@ -1270,8 +1236,8 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
}
else {
if (b_mesh.vertices.length() != numverts) {
- VLOG(1) << "Topology differs, discarding motion blur for object " << ob_name << " at time "
- << motion_step;
+ VLOG_WARNING << "Topology differs, discarding motion blur for object " << ob_name
+ << " at time " << motion_step;
memcpy(mP, &mesh->get_verts()[0], sizeof(float3) * numverts);
if (mN != NULL) {
memcpy(mN, attr_N->data_float3(), sizeof(float3) * numverts);
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index 9b08b564b25..ca1aa6329d9 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -762,7 +762,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
continue;
}
- VLOG(1) << "Synchronizing motion for the relative time " << relative_time << ".";
+ VLOG_WORK << "Synchronizing motion for the relative time " << relative_time << ".";
/* fixed shutter time to get previous and next frame for motion pass */
float shuttertime = scene->motion_shutter_time();
diff --git a/intern/cycles/blender/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp
index 0312ad87a70..b4e90859877 100644
--- a/intern/cycles/blender/pointcloud.cpp
+++ b/intern/cycles/blender/pointcloud.cpp
@@ -1,8 +1,10 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
-#include "scene/pointcloud.h"
+#include <optional>
+
#include "scene/attribute.h"
+#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "blender/sync.h"
@@ -138,6 +140,36 @@ static void copy_attributes(PointCloud *pointcloud,
}
}
+static std::optional<BL::FloatAttribute> find_radius_attribute(BL::PointCloud b_pointcloud)
+{
+ for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
+ if (b_attribute.name() != "radius") {
+ continue;
+ }
+ if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
+ continue;
+ }
+ return BL::FloatAttribute{b_attribute};
+ }
+ return std::nullopt;
+}
+
+static BL::FloatVectorAttribute find_position_attribute(BL::PointCloud b_pointcloud)
+{
+ for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
+ if (b_attribute.name() != "position") {
+ continue;
+ }
+ if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
+ continue;
+ }
+ return BL::FloatVectorAttribute{b_attribute};
+ }
+ /* The position attribute must exist. */
+ assert(false);
+ return BL::FloatVectorAttribute{b_pointcloud.attributes[0]};
+}
+
static void export_pointcloud(Scene *scene,
PointCloud *pointcloud,
BL::PointCloud b_pointcloud,
@@ -156,18 +188,18 @@ static void export_pointcloud(Scene *scene,
const int num_points = b_pointcloud.points.length();
pointcloud->reserve(num_points);
+ BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud);
+ std::optional<BL::FloatAttribute> b_attr_radius = find_radius_attribute(b_pointcloud);
+
/* Export points. */
- BL::PointCloud::points_iterator b_point_iter;
- for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end();
- ++b_point_iter) {
- BL::Point b_point = *b_point_iter;
- const float3 co = get_float3(b_point.co());
- const float radius = b_point.radius();
+ for (int i = 0; i < num_points; i++) {
+ const float3 co = get_float3(b_attr_position.data[i].vector());
+ const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f;
pointcloud->add_point(co, radius);
/* Random number per point. */
if (attr_random != NULL) {
- attr_random->add(hash_uint2_to_float(b_point.index(), 0));
+ attr_random->add(hash_uint2_to_float(i, 0));
}
}
@@ -195,14 +227,15 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
int num_motion_points = 0;
const array<float3> &pointcloud_points = pointcloud->get_points();
- BL::PointCloud::points_iterator b_point_iter;
- for (b_pointcloud.points.begin(b_point_iter); b_point_iter != b_pointcloud.points.end();
- ++b_point_iter) {
- BL::Point b_point = *b_point_iter;
+ BL::FloatVectorAttribute b_attr_position = find_position_attribute(b_pointcloud);
+ std::optional<BL::FloatAttribute> b_attr_radius = find_radius_attribute(b_pointcloud);
+ for (int i = 0; i < num_points; i++) {
if (num_motion_points < num_points) {
- float3 P = get_float3(b_point.co());
- P.w = b_point.radius();
+ const float3 co = get_float3(b_attr_position.data[i].vector());
+ const float radius = b_attr_radius ? b_attr_radius->data[i].value() : 0.0f;
+ float3 P = co;
+ P.w = radius;
mP[num_motion_points] = P;
have_motion = have_motion || (P != pointcloud_points[num_motion_points]);
num_motion_points++;
diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp
index 7bd1ad2cafe..8b2b331f73e 100644
--- a/intern/cycles/blender/python.cpp
+++ b/intern/cycles/blender/python.cpp
@@ -871,18 +871,20 @@ static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*
static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
{
vector<DeviceType> device_types = Device::available_types();
- bool has_cuda = false, has_optix = false, has_hip = false, has_metal = false;
+ bool has_cuda = false, has_optix = false, has_hip = false, has_metal = false, has_oneapi = false;
foreach (DeviceType device_type, device_types) {
has_cuda |= (device_type == DEVICE_CUDA);
has_optix |= (device_type == DEVICE_OPTIX);
has_hip |= (device_type == DEVICE_HIP);
has_metal |= (device_type == DEVICE_METAL);
+ has_oneapi |= (device_type == DEVICE_ONEAPI);
}
- PyObject *list = PyTuple_New(4);
+ PyObject *list = PyTuple_New(5);
PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
PyTuple_SET_ITEM(list, 3, PyBool_FromLong(has_metal));
+ PyTuple_SET_ITEM(list, 4, PyBool_FromLong(has_oneapi));
return list;
}
@@ -914,6 +916,9 @@ static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
else if (override == "METAL") {
BlenderSession::device_override = DEVICE_MASK_METAL;
}
+ else if (override == "ONEAPI") {
+ BlenderSession::device_override = DEVICE_MASK_ONEAPI;
+ }
else {
printf("\nError: %s is not a valid Cycles device.\n", override.c_str());
Py_RETURN_FALSE;
diff --git a/intern/cycles/blender/session.cpp b/intern/cycles/blender/session.cpp
index 87f051ba50b..6d27b8e7d87 100644
--- a/intern/cycles/blender/session.cpp
+++ b/intern/cycles/blender/session.cpp
@@ -458,8 +458,8 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
double total_time, render_time;
session->progress.get_time(total_time, render_time);
- VLOG(1) << "Total render time: " << total_time;
- VLOG(1) << "Render time (without synchronization): " << render_time;
+ VLOG_INFO << "Total render time: " << total_time;
+ VLOG_INFO << "Render time (without synchronization): " << render_time;
}
void BlenderSession::render_frame_finish()
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index 1028c940772..63e9e1e0e68 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -285,7 +285,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render,
free_data_after_sync(b_depsgraph);
- VLOG(1) << "Total time spent synchronizing data: " << timer.get_time();
+ VLOG_INFO << "Total time spent synchronizing data: " << timer.get_time();
has_updates_ = false;
}
@@ -390,7 +390,7 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
}
if (scrambling_distance != 1.0f) {
- VLOG(3) << "Using scrambling distance: " << scrambling_distance;
+ VLOG_INFO << "Using scrambling distance: " << scrambling_distance;
}
integrator->set_scrambling_distance(scrambling_distance);
diff --git a/intern/cycles/blender/volume.cpp b/intern/cycles/blender/volume.cpp
index a9a2c474f40..61b2f9ee276 100644
--- a/intern/cycles/blender/volume.cpp
+++ b/intern/cycles/blender/volume.cpp
@@ -257,6 +257,8 @@ class BlenderVolumeLoader : public VDBImageLoader {
precision = 0;
break;
}
+#else
+ (void)precision_;
#endif
}
diff --git a/intern/cycles/bvh/build.cpp b/intern/cycles/bvh/build.cpp
index 79e9b800690..cf03f05de60 100644
--- a/intern/cycles/bvh/build.cpp
+++ b/intern/cycles/bvh/build.cpp
@@ -529,7 +529,7 @@ BVHNode *BVHBuild::run()
if (progress.get_cancel()) {
rootnode->deleteSubtree();
rootnode = NULL;
- VLOG(1) << "BVH build cancelled.";
+ VLOG_WORK << "BVH build cancelled.";
}
else {
/*rotate(rootnode, 4, 5);*/
@@ -537,26 +537,26 @@ BVHNode *BVHBuild::run()
rootnode->update_time();
}
if (rootnode != NULL) {
- VLOG(1) << "BVH build statistics:\n"
- << " Build time: " << time_dt() - build_start_time << "\n"
- << " Total number of nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT))
- << "\n"
- << " Number of inner nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT))
- << "\n"
- << " Number of leaf nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT))
- << "\n"
- << " Number of unaligned nodes: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT))
- << "\n"
- << " Allocation slop factor: "
- << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() :
- 1.0f)
- << "\n"
- << " Maximum depth: "
- << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n";
+ VLOG_WORK << "BVH build statistics:\n"
+ << " Build time: " << time_dt() - build_start_time << "\n"
+ << " Total number of nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_NODE_COUNT))
+ << "\n"
+ << " Number of inner nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT))
+ << "\n"
+ << " Number of leaf nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT))
+ << "\n"
+ << " Number of unaligned nodes: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT))
+ << "\n"
+ << " Allocation slop factor: "
+ << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() :
+ 1.0f)
+ << "\n"
+ << " Maximum depth: "
+ << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_DEPTH)) << "\n";
}
}
@@ -811,7 +811,7 @@ BVHNode *BVHBuild::build_node(const BVHRange &range,
/* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
params.sah_primitive_cost * unaligned_split.nodeSAH;
- /* TOOD(sergey): Check we can create leaf already. */
+ /* TODO(sergey): Check we can create leaf already. */
/* Check whether unaligned split is better than the regular one. */
if (unalignedSplitSAH < splitSAH) {
do_unalinged_split = true;
diff --git a/intern/cycles/bvh/embree.cpp b/intern/cycles/bvh/embree.cpp
index 0fc71f49ce3..eed7ae19965 100644
--- a/intern/cycles/bvh/embree.cpp
+++ b/intern/cycles/bvh/embree.cpp
@@ -250,7 +250,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
*isect = current_isect;
/* Only primitives from volume object. */
uint tri_object = isect->object;
- int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+ int object_flag = kernel_data_fetch(object_flag, tri_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
--ctx->num_hits;
}
@@ -332,7 +332,7 @@ static bool rtc_memory_monitor_func(void *userPtr, const ssize_t bytes, const bo
static void rtc_error_func(void *, enum RTCError, const char *str)
{
- VLOG(1) << str;
+ VLOG_WARNING << str;
}
static double progress_start_time = 0.0;
@@ -521,8 +521,8 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(int) * 3, num_triangles);
assert(rtc_indices);
if (!rtc_indices) {
- VLOG(1) << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str()
- << ".\n";
+ VLOG_WARNING << "Embree could not create new geometry buffer for mesh " << mesh->name.c_str()
+ << ".\n";
return;
}
for (size_t j = 0; j < num_triangles; ++j) {
diff --git a/intern/cycles/bvh/params.h b/intern/cycles/bvh/params.h
index 41d851ee687..648350d03b0 100644
--- a/intern/cycles/bvh/params.h
+++ b/intern/cycles/bvh/params.h
@@ -129,7 +129,7 @@ class BVHParams {
top_level = false;
bvh_layout = BVH_LAYOUT_BVH2;
- use_compact_structure = true;
+ use_compact_structure = false;
use_unaligned_nodes = false;
num_motion_curve_steps = 0;
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index d2f30fe764b..51830250f2e 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -91,6 +91,8 @@ if(CYCLES_STANDALONE_REPOSITORY)
_set_default(USD_ROOT_DIR "${_cycles_lib_dir}/usd")
_set_default(WEBP_ROOT_DIR "${_cycles_lib_dir}/webp")
_set_default(ZLIB_ROOT "${_cycles_lib_dir}/zlib")
+ _set_default(LEVEL_ZERO_ROOT_DIR "${_cycles_lib_dir}/level-zero")
+ _set_default(SYCL_ROOT_DIR "${_cycles_lib_dir}/dpcpp")
# Ignore system libraries
set(CMAKE_IGNORE_PATH "${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES};${CMAKE_SYSTEM_INCLUDE_PATH};${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES};${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}")
@@ -647,3 +649,22 @@ if(WITH_CYCLES_DEVICE_METAL)
message(STATUS "Found Metal: ${METAL_LIBRARY}")
endif()
endif()
+
+###########################################################################
+# oneAPI
+###########################################################################
+
+if (WITH_CYCLES_DEVICE_ONEAPI)
+ find_package(SYCL)
+ find_package(LevelZero)
+
+ if (SYCL_FOUND AND LEVEL_ZERO_FOUND)
+ message(STATUS "Found oneAPI: ${SYCL_LIBRARY}")
+ message(STATUS "Found Level Zero: ${LEVEL_ZERO_LIBRARY}")
+ else()
+ message(STATUS "oneAPI or Level Zero not found, disabling oneAPI device from Cycles")
+ set(WITH_CYCLES_DEVICE_ONEAPI OFF)
+ endif()
+endif()
+
+unset(_cycles_lib_dir)
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 6205775260a..6418801c572 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -82,6 +82,15 @@ set(SRC_HIP
hip/util.h
)
+set(SRC_ONEAPI
+ oneapi/device_impl.cpp
+ oneapi/device_impl.h
+ oneapi/device.cpp
+ oneapi/device.h
+ oneapi/queue.cpp
+ oneapi/queue.h
+)
+
set(SRC_DUMMY
dummy/device.cpp
dummy/device.h
@@ -134,6 +143,7 @@ set(SRC
${SRC_DUMMY}
${SRC_MULTI}
${SRC_OPTIX}
+ ${SRC_ONEAPI}
${SRC_HEADERS}
)
@@ -181,6 +191,9 @@ if(WITH_CYCLES_DEVICE_METAL)
${SRC_METAL}
)
endif()
+if (WITH_CYCLES_DEVICE_ONEAPI)
+ add_definitions(-DWITH_ONEAPI)
+endif()
if(WITH_OPENIMAGEDENOISE)
list(APPEND LIB
@@ -193,6 +206,11 @@ include_directories(SYSTEM ${INC_SYS})
cycles_add_library(cycles_device "${LIB}" ${SRC})
+if(WITH_CYCLES_DEVICE_ONEAPI)
+ # Need to have proper rebuilding in case of changes in cycles_kernel_oneapi due external project behaviour
+ add_dependencies(cycles_device cycles_kernel_oneapi)
+endif()
+
source_group("cpu" FILES ${SRC_CPU})
source_group("cuda" FILES ${SRC_CUDA})
source_group("dummy" FILES ${SRC_DUMMY})
@@ -200,4 +218,5 @@ source_group("hip" FILES ${SRC_HIP})
source_group("multi" FILES ${SRC_MULTI})
source_group("metal" FILES ${SRC_METAL})
source_group("optix" FILES ${SRC_OPTIX})
+source_group("oneapi" FILES ${SRC_ONEAPI})
source_group("common" FILES ${SRC_BASE} ${SRC_HEADERS})
diff --git a/intern/cycles/device/cpu/device_impl.cpp b/intern/cycles/device/cpu/device_impl.cpp
index 612c391f7d5..1e4b9baa0c0 100644
--- a/intern/cycles/device/cpu/device_impl.cpp
+++ b/intern/cycles/device/cpu/device_impl.cpp
@@ -51,12 +51,12 @@
CCL_NAMESPACE_BEGIN
CPUDevice::CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_)
- : Device(info_, stats_, profiler_), texture_info(this, "__texture_info", MEM_GLOBAL)
+ : Device(info_, stats_, profiler_), texture_info(this, "texture_info", MEM_GLOBAL)
{
/* Pick any kernel, all of them are supposed to have same level of microarchitecture
* optimization. */
- VLOG(1) << "Using " << get_cpu_kernels().integrator_init_from_camera.get_uarch_name()
- << " CPU kernels.";
+ VLOG_INFO << "Using " << get_cpu_kernels().integrator_init_from_camera.get_uarch_name()
+ << " CPU kernels.";
if (info.cpu_threads == 0) {
info.cpu_threads = TaskScheduler::max_concurrency();
@@ -111,9 +111,9 @@ void CPUDevice::mem_alloc(device_memory &mem)
}
else {
if (mem.name) {
- VLOG(1) << "Buffer allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
}
if (mem.type == MEM_DEVICE_ONLY || !mem.host_pointer) {
@@ -192,12 +192,12 @@ device_ptr CPUDevice::mem_alloc_sub_ptr(device_memory &mem, size_t offset, size_
void CPUDevice::const_copy_to(const char *name, void *host, size_t size)
{
#ifdef WITH_EMBREE
- if (strcmp(name, "__data") == 0) {
+ if (strcmp(name, "data") == 0) {
assert(size <= sizeof(KernelData));
// Update scene handle (since it is different for each device on multi devices)
KernelData *const data = (KernelData *)host;
- data->bvh.scene = embree_scene;
+ data->device_bvh = embree_scene;
}
#endif
kernel_const_copy(&kernel_globals, name, host, size);
@@ -205,9 +205,9 @@ void CPUDevice::const_copy_to(const char *name, void *host, size_t size)
void CPUDevice::global_alloc(device_memory &mem)
{
- VLOG(1) << "Global memory allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Global memory allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
kernel_global_memory_copy(&kernel_globals, mem.name, mem.host_pointer, mem.data_size);
@@ -227,9 +227,9 @@ void CPUDevice::global_free(device_memory &mem)
void CPUDevice::tex_alloc(device_texture &mem)
{
- VLOG(1) << "Texture allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Texture allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
mem.device_pointer = (device_ptr)mem.host_pointer;
mem.device_size = mem.memory_size();
diff --git a/intern/cycles/device/cuda/device.cpp b/intern/cycles/device/cuda/device.cpp
index 400490336d6..5a213c45b71 100644
--- a/intern/cycles/device/cuda/device.cpp
+++ b/intern/cycles/device/cuda/device.cpp
@@ -29,24 +29,25 @@ bool device_cuda_init()
initialized = true;
int cuew_result = cuewInit(CUEW_INIT_CUDA);
if (cuew_result == CUEW_SUCCESS) {
- VLOG(1) << "CUEW initialization succeeded";
+ VLOG_INFO << "CUEW initialization succeeded";
if (CUDADevice::have_precompiled_kernels()) {
- VLOG(1) << "Found precompiled kernels";
+ VLOG_INFO << "Found precompiled kernels";
result = true;
}
else if (cuewCompilerPath() != NULL) {
- VLOG(1) << "Found CUDA compiler " << cuewCompilerPath();
+ VLOG_INFO << "Found CUDA compiler " << cuewCompilerPath();
result = true;
}
else {
- VLOG(1) << "Neither precompiled kernels nor CUDA compiler was found,"
- << " unable to use CUDA";
+ VLOG_INFO << "Neither precompiled kernels nor CUDA compiler was found,"
+ << " unable to use CUDA";
}
}
else {
- VLOG(1) << "CUEW initialization failed: "
- << ((cuew_result == CUEW_ERROR_ATEXIT_FAILED) ? "Error setting up atexit() handler" :
- "Error opening the library");
+ VLOG_WARNING << "CUEW initialization failed: "
+ << ((cuew_result == CUEW_ERROR_ATEXIT_FAILED) ?
+ "Error setting up atexit() handler" :
+ "Error opening the library");
}
return result;
@@ -121,7 +122,8 @@ void device_cuda_info(vector<DeviceInfo> &devices)
int major;
cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, num);
if (major < 3) {
- VLOG(1) << "Ignoring device \"" << name << "\", this graphics card is no longer supported.";
+ VLOG_INFO << "Ignoring device \"" << name
+ << "\", this graphics card is no longer supported.";
continue;
}
@@ -166,21 +168,21 @@ void device_cuda_info(vector<DeviceInfo> &devices)
* Windows 10 even when it is, due to an issue in application profiles.
* Detect case where we expect it to be available and override. */
if (preempt_attr == 0 && (major >= 6) && system_windows_version_at_least(10, 17134)) {
- VLOG(1) << "Assuming device has compute preemption on Windows 10.";
+ VLOG_INFO << "Assuming device has compute preemption on Windows 10.";
preempt_attr = 1;
}
if (timeout_attr && !preempt_attr) {
- VLOG(1) << "Device is recognized as display.";
+ VLOG_INFO << "Device is recognized as display.";
info.description += " (Display)";
info.display_device = true;
display_devices.push_back(info);
}
else {
- VLOG(1) << "Device has compute preemption or is not used for display.";
+ VLOG_INFO << "Device has compute preemption or is not used for display.";
devices.push_back(info);
}
- VLOG(1) << "Added device \"" << name << "\" with id \"" << info.id << "\".";
+ VLOG_INFO << "Added device \"" << name << "\" with id \"" << info.id << "\".";
}
if (!display_devices.empty())
diff --git a/intern/cycles/device/cuda/device_impl.cpp b/intern/cycles/device/cuda/device_impl.cpp
index 75177566901..00851a8e91c 100644
--- a/intern/cycles/device/cuda/device_impl.cpp
+++ b/intern/cycles/device/cuda/device_impl.cpp
@@ -23,6 +23,8 @@
# include "util/types.h"
# include "util/windows.h"
+# include "kernel/device/cuda/globals.h"
+
CCL_NAMESPACE_BEGIN
class CUDADevice;
@@ -51,7 +53,7 @@ void CUDADevice::set_error(const string &error)
}
CUDADevice::CUDADevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
- : Device(info, stats, profiler), texture_info(this, "__texture_info", MEM_GLOBAL)
+ : Device(info, stats, profiler), texture_info(this, "texture_info", MEM_GLOBAL)
{
first_error = true;
@@ -244,9 +246,9 @@ string CUDADevice::compile_kernel(const uint kernel_features,
if (!use_adaptive_compilation()) {
if (!force_ptx) {
const string cubin = path_get(string_printf("lib/%s_sm_%d%d.cubin", name, major, minor));
- VLOG(1) << "Testing for pre-compiled kernel " << cubin << ".";
+ VLOG_INFO << "Testing for pre-compiled kernel " << cubin << ".";
if (path_exists(cubin)) {
- VLOG(1) << "Using precompiled kernel.";
+ VLOG_INFO << "Using precompiled kernel.";
return cubin;
}
}
@@ -256,9 +258,9 @@ string CUDADevice::compile_kernel(const uint kernel_features,
while (ptx_major >= 3) {
const string ptx = path_get(
string_printf("lib/%s_compute_%d%d.ptx", name, ptx_major, ptx_minor));
- VLOG(1) << "Testing for pre-compiled kernel " << ptx << ".";
+ VLOG_INFO << "Testing for pre-compiled kernel " << ptx << ".";
if (path_exists(ptx)) {
- VLOG(1) << "Using precompiled kernel.";
+ VLOG_INFO << "Using precompiled kernel.";
return ptx;
}
@@ -287,9 +289,9 @@ string CUDADevice::compile_kernel(const uint kernel_features,
const string cubin_file = string_printf(
"cycles_%s_%s_%d%d_%s.%s", name, kernel_arch, major, minor, kernel_md5.c_str(), kernel_ext);
const string cubin = path_cache_get(path_join("kernels", cubin_file));
- VLOG(1) << "Testing for locally compiled kernel " << cubin << ".";
+ VLOG_INFO << "Testing for locally compiled kernel " << cubin << ".";
if (path_exists(cubin)) {
- VLOG(1) << "Using locally compiled kernel.";
+ VLOG_INFO << "Using locally compiled kernel.";
return cubin;
}
@@ -323,7 +325,7 @@ string CUDADevice::compile_kernel(const uint kernel_features,
}
const int nvcc_cuda_version = cuewCompilerVersion();
- VLOG(1) << "Found nvcc " << nvcc << ", CUDA version " << nvcc_cuda_version << ".";
+ VLOG_INFO << "Found nvcc " << nvcc << ", CUDA version " << nvcc_cuda_version << ".";
if (nvcc_cuda_version < 101) {
printf(
"Unsupported CUDA version %d.%d detected, "
@@ -399,7 +401,8 @@ bool CUDADevice::load_kernels(const uint kernel_features)
*/
if (cuModule) {
if (use_adaptive_compilation()) {
- VLOG(1) << "Skipping CUDA kernel reload for adaptive compilation, not currently supported.";
+ VLOG_INFO
+ << "Skipping CUDA kernel reload for adaptive compilation, not currently supported.";
}
return true;
}
@@ -457,6 +460,8 @@ void CUDADevice::reserve_local_memory(const uint kernel_features)
/* Use the biggest kernel for estimation. */
const DeviceKernel test_kernel = (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) ?
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE :
+ (kernel_features & KERNEL_FEATURE_MNEE) ?
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE :
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE;
/* Launch kernel, using just 1 block appears sufficient to reserve memory for all
@@ -479,8 +484,8 @@ void CUDADevice::reserve_local_memory(const uint kernel_features)
cuMemGetInfo(&free_after, &total);
}
- VLOG(1) << "Local memory reserved " << string_human_readable_number(free_before - free_after)
- << " bytes. (" << string_human_readable_size(free_before - free_after) << ")";
+ VLOG_INFO << "Local memory reserved " << string_human_readable_number(free_before - free_after)
+ << " bytes. (" << string_human_readable_size(free_before - free_after) << ")";
# if 0
/* For testing mapped host memory, fill up device memory. */
@@ -511,7 +516,7 @@ void CUDADevice::init_host_memory()
}
}
else {
- VLOG(1) << "Mapped host memory disabled, failed to get system RAM";
+ VLOG_WARNING << "Mapped host memory disabled, failed to get system RAM";
map_host_limit = 0;
}
@@ -522,8 +527,8 @@ void CUDADevice::init_host_memory()
device_working_headroom = 32 * 1024 * 1024LL; // 32MB
device_texture_headroom = 128 * 1024 * 1024LL; // 128MB
- VLOG(1) << "Mapped host memory limit set to " << string_human_readable_number(map_host_limit)
- << " bytes. (" << string_human_readable_size(map_host_limit) << ")";
+ VLOG_INFO << "Mapped host memory limit set to " << string_human_readable_number(map_host_limit)
+ << " bytes. (" << string_human_readable_size(map_host_limit) << ")";
}
void CUDADevice::load_texture_info()
@@ -591,7 +596,7 @@ void CUDADevice::move_textures_to_host(size_t size, bool for_texture)
* multiple CUDA devices could be moving the memory. The
* first one will do it, and the rest will adopt the pointer. */
if (max_mem) {
- VLOG(1) << "Move memory from device to host: " << max_mem->name;
+ VLOG_WORK << "Move memory from device to host: " << max_mem->name;
static thread_mutex move_mutex;
thread_scoped_lock lock(move_mutex);
@@ -699,9 +704,9 @@ CUDADevice::CUDAMem *CUDADevice::generic_alloc(device_memory &mem, size_t pitch_
}
if (mem.name) {
- VLOG(1) << "Buffer allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")" << status;
+ VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")" << status;
}
mem.device_pointer = (device_ptr)device_pointer;
@@ -897,9 +902,19 @@ void CUDADevice::const_copy_to(const char *name, void *host, size_t size)
CUdeviceptr mem;
size_t bytes;
- cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule, name));
- // assert(bytes == size);
- cuda_assert(cuMemcpyHtoD(mem, host, size));
+ cuda_assert(cuModuleGetGlobal(&mem, &bytes, cuModule, "kernel_params"));
+ assert(bytes == sizeof(KernelParamsCUDA));
+
+ /* Update data storage pointers in launch parameters. */
+# define KERNEL_DATA_ARRAY(data_type, data_name) \
+ if (strcmp(name, #data_name) == 0) { \
+ cuda_assert(cuMemcpyHtoD(mem + offsetof(KernelParamsCUDA, data_name), host, size)); \
+ return; \
+ }
+ KERNEL_DATA_ARRAY(KernelData, data)
+ KERNEL_DATA_ARRAY(IntegratorStateGPU, integrator_state)
+# include "kernel/data_arrays.h"
+# undef KERNEL_DATA_ARRAY
}
void CUDADevice::global_alloc(device_memory &mem)
@@ -923,7 +938,6 @@ void CUDADevice::tex_alloc(device_texture &mem)
{
CUDAContextScope scope(this);
- string bind_name = mem.name;
size_t dsize = datatype_size(mem.data_type);
size_t size = mem.memory_size();
@@ -1006,9 +1020,9 @@ void CUDADevice::tex_alloc(device_texture &mem)
desc.NumChannels = mem.data_elements;
desc.Flags = 0;
- VLOG(1) << "Array 3D allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Array 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
cuda_assert(cuArray3DCreate(&array_3d, &desc));
diff --git a/intern/cycles/device/cuda/queue.cpp b/intern/cycles/device/cuda/queue.cpp
index 38c71866ad0..5912e68a92b 100644
--- a/intern/cycles/device/cuda/queue.cpp
+++ b/intern/cycles/device/cuda/queue.cpp
@@ -39,12 +39,12 @@ int CUDADeviceQueue::num_concurrent_states(const size_t state_size) const
num_states = max((int)(num_states * factor), 1024);
}
else {
- VLOG(3) << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
+ VLOG_DEVICE_STATS << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
}
}
- VLOG(3) << "GPU queue concurrent states: " << num_states << ", using up to "
- << string_human_readable_size(num_states * state_size);
+ VLOG_DEVICE_STATS << "GPU queue concurrent states: " << num_states << ", using up to "
+ << string_human_readable_size(num_states * state_size);
return num_states;
}
diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp
index ea5b3c6dc8c..ace6ed517f5 100644
--- a/intern/cycles/device/device.cpp
+++ b/intern/cycles/device/device.cpp
@@ -16,6 +16,7 @@
#include "device/hip/device.h"
#include "device/metal/device.h"
#include "device/multi/device.h"
+#include "device/oneapi/device.h"
#include "device/optix/device.h"
#include "util/foreach.h"
@@ -39,6 +40,7 @@ vector<DeviceInfo> Device::optix_devices;
vector<DeviceInfo> Device::cpu_devices;
vector<DeviceInfo> Device::hip_devices;
vector<DeviceInfo> Device::metal_devices;
+vector<DeviceInfo> Device::oneapi_devices;
uint Device::devices_initialized_mask = 0;
/* Device */
@@ -101,6 +103,13 @@ Device *Device::create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
device = device_metal_create(info, stats, profiler);
break;
#endif
+
+#ifdef WITH_ONEAPI
+ case DEVICE_ONEAPI:
+ device = device_oneapi_create(info, stats, profiler);
+ break;
+#endif
+
default:
break;
}
@@ -126,6 +135,8 @@ DeviceType Device::type_from_string(const char *name)
return DEVICE_HIP;
else if (strcmp(name, "METAL") == 0)
return DEVICE_METAL;
+ else if (strcmp(name, "ONEAPI") == 0)
+ return DEVICE_ONEAPI;
return DEVICE_NONE;
}
@@ -144,6 +155,8 @@ string Device::string_from_type(DeviceType type)
return "HIP";
else if (type == DEVICE_METAL)
return "METAL";
+ else if (type == DEVICE_ONEAPI)
+ return "ONEAPI";
return "";
}
@@ -164,6 +177,9 @@ vector<DeviceType> Device::available_types()
#ifdef WITH_METAL
types.push_back(DEVICE_METAL);
#endif
+#ifdef WITH_ONEAPI
+ types.push_back(DEVICE_ONEAPI);
+#endif
return types;
}
@@ -219,6 +235,20 @@ vector<DeviceInfo> Device::available_devices(uint mask)
}
#endif
+#ifdef WITH_ONEAPI
+ if (mask & DEVICE_MASK_ONEAPI) {
+ if (!(devices_initialized_mask & DEVICE_MASK_ONEAPI)) {
+ if (device_oneapi_init()) {
+ device_oneapi_info(oneapi_devices);
+ }
+ devices_initialized_mask |= DEVICE_MASK_ONEAPI;
+ }
+ foreach (DeviceInfo &info, oneapi_devices) {
+ devices.push_back(info);
+ }
+ }
+#endif
+
if (mask & DEVICE_MASK_CPU) {
if (!(devices_initialized_mask & DEVICE_MASK_CPU)) {
device_cpu_info(cpu_devices);
@@ -282,6 +312,15 @@ string Device::device_capabilities(uint mask)
}
#endif
+#ifdef WITH_ONEAPI
+ if (mask & DEVICE_MASK_ONEAPI) {
+ if (device_oneapi_init()) {
+ capabilities += "\noneAPI device capabilities:\n";
+ capabilities += device_oneapi_capabilities();
+ }
+ }
+#endif
+
#ifdef WITH_METAL
if (mask & DEVICE_MASK_METAL) {
if (device_metal_init()) {
@@ -325,8 +364,8 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
int orig_cpu_threads = (threads) ? threads : TaskScheduler::max_concurrency();
int cpu_threads = max(orig_cpu_threads - (subdevices.size() - 1), size_t(0));
- VLOG(1) << "CPU render threads reduced from " << orig_cpu_threads << " to " << cpu_threads
- << ", to dedicate to GPU.";
+ VLOG_INFO << "CPU render threads reduced from " << orig_cpu_threads << " to "
+ << cpu_threads << ", to dedicate to GPU.";
if (cpu_threads >= 1) {
DeviceInfo cpu_device = device;
@@ -338,7 +377,7 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices,
}
}
else {
- VLOG(1) << "CPU render threads disabled for interactive render.";
+ VLOG_INFO << "CPU render threads disabled for interactive render.";
continue;
}
}
@@ -380,6 +419,7 @@ void Device::free_memory()
cuda_devices.free_memory();
optix_devices.free_memory();
hip_devices.free_memory();
+ oneapi_devices.free_memory();
cpu_devices.free_memory();
metal_devices.free_memory();
}
diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h
index 927caae600c..cdb13ca0a97 100644
--- a/intern/cycles/device/device.h
+++ b/intern/cycles/device/device.h
@@ -29,6 +29,7 @@ class DeviceQueue;
class Progress;
class CPUKernels;
class CPUKernelThreadGlobals;
+class Scene;
/* Device Types */
@@ -40,6 +41,7 @@ enum DeviceType {
DEVICE_OPTIX,
DEVICE_HIP,
DEVICE_METAL,
+ DEVICE_ONEAPI,
DEVICE_DUMMY,
};
@@ -49,6 +51,7 @@ enum DeviceTypeMask {
DEVICE_MASK_OPTIX = (1 << DEVICE_OPTIX),
DEVICE_MASK_HIP = (1 << DEVICE_HIP),
DEVICE_MASK_METAL = (1 << DEVICE_METAL),
+ DEVICE_MASK_ONEAPI = (1 << DEVICE_ONEAPI),
DEVICE_MASK_ALL = ~0
};
@@ -184,6 +187,11 @@ class Device {
return 0;
}
+ /* Called after kernel texture setup, and prior to integrator state setup. */
+ virtual void optimize_for_scene(Scene * /*scene*/)
+ {
+ }
+
virtual bool is_resident(device_ptr /*key*/, Device *sub_device)
{
/* Memory is always resident if this is not a multi device, regardless of whether the pointer
@@ -273,6 +281,7 @@ class Device {
static vector<DeviceInfo> cpu_devices;
static vector<DeviceInfo> hip_devices;
static vector<DeviceInfo> metal_devices;
+ static vector<DeviceInfo> oneapi_devices;
static uint devices_initialized_mask;
};
diff --git a/intern/cycles/device/hip/device.cpp b/intern/cycles/device/hip/device.cpp
index d6a5ed9c419..3c9c73e7db0 100644
--- a/intern/cycles/device/hip/device.cpp
+++ b/intern/cycles/device/hip/device.cpp
@@ -29,30 +29,31 @@ bool device_hip_init()
initialized = true;
int hipew_result = hipewInit(HIPEW_INIT_HIP);
if (hipew_result == HIPEW_SUCCESS) {
- VLOG(1) << "HIPEW initialization succeeded";
+ VLOG_INFO << "HIPEW initialization succeeded";
if (HIPDevice::have_precompiled_kernels()) {
- VLOG(1) << "Found precompiled kernels";
+ VLOG_INFO << "Found precompiled kernels";
result = true;
}
else if (hipewCompilerPath() != NULL) {
- VLOG(1) << "Found HIPCC " << hipewCompilerPath();
+ VLOG_INFO << "Found HIPCC " << hipewCompilerPath();
result = true;
}
else {
- VLOG(1) << "Neither precompiled kernels nor HIPCC was found,"
- << " unable to use HIP";
+ VLOG_INFO << "Neither precompiled kernels nor HIPCC was found,"
+ << " unable to use HIP";
}
}
else {
if (hipew_result == HIPEW_ERROR_ATEXIT_FAILED) {
- VLOG(1) << "HIPEW initialization failed: Error setting up atexit() handler";
+ VLOG_WARNING << "HIPEW initialization failed: Error setting up atexit() handler";
}
else if (hipew_result == HIPEW_ERROR_OLD_DRIVER) {
- VLOG(1) << "HIPEW initialization failed: Driver version too old, requires AMD Radeon Pro "
- "21.Q4 driver or newer";
+ VLOG_WARNING
+ << "HIPEW initialization failed: Driver version too old, requires AMD Radeon Pro "
+ "21.Q4 driver or newer";
}
else {
- VLOG(1) << "HIPEW initialization failed: Error opening HIP dynamic library";
+ VLOG_WARNING << "HIPEW initialization failed: Error opening HIP dynamic library";
}
}
@@ -165,16 +166,16 @@ void device_hip_info(vector<DeviceInfo> &devices)
hipDeviceGetAttribute(&timeout_attr, hipDeviceAttributeKernelExecTimeout, num);
if (timeout_attr && !preempt_attr) {
- VLOG(1) << "Device is recognized as display.";
+ VLOG_INFO << "Device is recognized as display.";
info.description += " (Display)";
info.display_device = true;
display_devices.push_back(info);
}
else {
- VLOG(1) << "Device has compute preemption or is not used for display.";
+ VLOG_INFO << "Device has compute preemption or is not used for display.";
devices.push_back(info);
}
- VLOG(1) << "Added device \"" << name << "\" with id \"" << info.id << "\".";
+ VLOG_INFO << "Added device \"" << name << "\" with id \"" << info.id << "\".";
}
if (!display_devices.empty())
diff --git a/intern/cycles/device/hip/device_impl.cpp b/intern/cycles/device/hip/device_impl.cpp
index f8fdb86ca29..82db55ea715 100644
--- a/intern/cycles/device/hip/device_impl.cpp
+++ b/intern/cycles/device/hip/device_impl.cpp
@@ -24,6 +24,8 @@
# include "util/types.h"
# include "util/windows.h"
+# include "kernel/device/hip/globals.h"
+
CCL_NAMESPACE_BEGIN
class HIPDevice;
@@ -52,7 +54,7 @@ void HIPDevice::set_error(const string &error)
}
HIPDevice::HIPDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
- : Device(info, stats, profiler), texture_info(this, "__texture_info", MEM_GLOBAL)
+ : Device(info, stats, profiler), texture_info(this, "texture_info", MEM_GLOBAL)
{
first_error = true;
@@ -233,9 +235,9 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c
/* Attempt to use kernel provided with Blender. */
if (!use_adaptive_compilation()) {
const string fatbin = path_get(string_printf("lib/%s_%s.fatbin", name, arch));
- VLOG(1) << "Testing for pre-compiled kernel " << fatbin << ".";
+ VLOG_INFO << "Testing for pre-compiled kernel " << fatbin << ".";
if (path_exists(fatbin)) {
- VLOG(1) << "Using precompiled kernel.";
+ VLOG_INFO << "Using precompiled kernel.";
return fatbin;
}
}
@@ -265,9 +267,9 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c
const string include_path = source_path;
const string fatbin_file = string_printf("cycles_%s_%s_%s", name, arch, kernel_md5.c_str());
const string fatbin = path_cache_get(path_join("kernels", fatbin_file));
- VLOG(1) << "Testing for locally compiled kernel " << fatbin << ".";
+ VLOG_INFO << "Testing for locally compiled kernel " << fatbin << ".";
if (path_exists(fatbin)) {
- VLOG(1) << "Using locally compiled kernel.";
+ VLOG_INFO << "Using locally compiled kernel.";
return fatbin;
}
@@ -301,7 +303,7 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c
}
const int hipcc_hip_version = hipewCompilerVersion();
- VLOG(1) << "Found hipcc " << hipcc << ", HIP version " << hipcc_hip_version << ".";
+ VLOG_INFO << "Found hipcc " << hipcc << ", HIP version " << hipcc_hip_version << ".";
if (hipcc_hip_version < 40) {
printf(
"Unsupported HIP version %d.%d detected, "
@@ -361,7 +363,7 @@ bool HIPDevice::load_kernels(const uint kernel_features)
*/
if (hipModule) {
if (use_adaptive_compilation()) {
- VLOG(1) << "Skipping HIP kernel reload for adaptive compilation, not currently supported.";
+ VLOG_INFO << "Skipping HIP kernel reload for adaptive compilation, not currently supported.";
}
return true;
}
@@ -420,6 +422,8 @@ void HIPDevice::reserve_local_memory(const uint kernel_features)
/* Use the biggest kernel for estimation. */
const DeviceKernel test_kernel = (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) ?
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE :
+ (kernel_features & KERNEL_FEATURE_MNEE) ?
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE :
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE;
/* Launch kernel, using just 1 block appears sufficient to reserve memory for all
@@ -442,8 +446,8 @@ void HIPDevice::reserve_local_memory(const uint kernel_features)
hipMemGetInfo(&free_after, &total);
}
- VLOG(1) << "Local memory reserved " << string_human_readable_number(free_before - free_after)
- << " bytes. (" << string_human_readable_size(free_before - free_after) << ")";
+ VLOG_INFO << "Local memory reserved " << string_human_readable_number(free_before - free_after)
+ << " bytes. (" << string_human_readable_size(free_before - free_after) << ")";
# if 0
/* For testing mapped host memory, fill up device memory. */
@@ -474,7 +478,7 @@ void HIPDevice::init_host_memory()
}
}
else {
- VLOG(1) << "Mapped host memory disabled, failed to get system RAM";
+ VLOG_WARNING << "Mapped host memory disabled, failed to get system RAM";
map_host_limit = 0;
}
@@ -485,8 +489,8 @@ void HIPDevice::init_host_memory()
device_working_headroom = 32 * 1024 * 1024LL; // 32MB
device_texture_headroom = 128 * 1024 * 1024LL; // 128MB
- VLOG(1) << "Mapped host memory limit set to " << string_human_readable_number(map_host_limit)
- << " bytes. (" << string_human_readable_size(map_host_limit) << ")";
+ VLOG_INFO << "Mapped host memory limit set to " << string_human_readable_number(map_host_limit)
+ << " bytes. (" << string_human_readable_size(map_host_limit) << ")";
}
void HIPDevice::load_texture_info()
@@ -554,7 +558,7 @@ void HIPDevice::move_textures_to_host(size_t size, bool for_texture)
* multiple HIP devices could be moving the memory. The
* first one will do it, and the rest will adopt the pointer. */
if (max_mem) {
- VLOG(1) << "Move memory from device to host: " << max_mem->name;
+ VLOG_WORK << "Move memory from device to host: " << max_mem->name;
static thread_mutex move_mutex;
thread_scoped_lock lock(move_mutex);
@@ -656,9 +660,9 @@ HIPDevice::HIPMem *HIPDevice::generic_alloc(device_memory &mem, size_t pitch_pad
}
if (mem.name) {
- VLOG(1) << "Buffer allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")" << status;
+ VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")" << status;
}
mem.device_pointer = (device_ptr)device_pointer;
@@ -854,8 +858,19 @@ void HIPDevice::const_copy_to(const char *name, void *host, size_t size)
hipDeviceptr_t mem;
size_t bytes;
- hip_assert(hipModuleGetGlobal(&mem, &bytes, hipModule, name));
- hip_assert(hipMemcpyHtoD(mem, host, size));
+ hip_assert(hipModuleGetGlobal(&mem, &bytes, hipModule, "kernel_params"));
+ assert(bytes == sizeof(KernelParamsHIP));
+
+ /* Update data storage pointers in launch parameters. */
+# define KERNEL_DATA_ARRAY(data_type, data_name) \
+ if (strcmp(name, #data_name) == 0) { \
+ hip_assert(hipMemcpyHtoD(mem + offsetof(KernelParamsHIP, data_name), host, size)); \
+ return; \
+ }
+ KERNEL_DATA_ARRAY(KernelData, data)
+ KERNEL_DATA_ARRAY(IntegratorStateGPU, integrator_state)
+# include "kernel/data_arrays.h"
+# undef KERNEL_DATA_ARRAY
}
void HIPDevice::global_alloc(device_memory &mem)
@@ -879,7 +894,6 @@ void HIPDevice::tex_alloc(device_texture &mem)
{
HIPContextScope scope(this);
- string bind_name = mem.name;
size_t dsize = datatype_size(mem.data_type);
size_t size = mem.memory_size();
@@ -964,9 +978,9 @@ void HIPDevice::tex_alloc(device_texture &mem)
desc.NumChannels = mem.data_elements;
desc.Flags = 0;
- VLOG(1) << "Array 3D allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Array 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
hip_assert(hipArray3DCreate((hArray *)&array_3d, &desc));
diff --git a/intern/cycles/device/hip/queue.cpp b/intern/cycles/device/hip/queue.cpp
index 6c2c2c29624..8b3d963a32f 100644
--- a/intern/cycles/device/hip/queue.cpp
+++ b/intern/cycles/device/hip/queue.cpp
@@ -39,12 +39,12 @@ int HIPDeviceQueue::num_concurrent_states(const size_t state_size) const
num_states = max((int)(num_states * factor), 1024);
}
else {
- VLOG(3) << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
+ VLOG_DEVICE_STATS << "CYCLES_CONCURRENT_STATES_FACTOR evaluated to 0";
}
}
- VLOG(3) << "GPU queue concurrent states: " << num_states << ", using up to "
- << string_human_readable_size(num_states * state_size);
+ VLOG_DEVICE_STATS << "GPU queue concurrent states: " << num_states << ", using up to "
+ << string_human_readable_size(num_states * state_size);
return num_states;
}
diff --git a/intern/cycles/device/hip/util.h b/intern/cycles/device/hip/util.h
index adb68a2d44c..4e4906171d1 100644
--- a/intern/cycles/device/hip/util.h
+++ b/intern/cycles/device/hip/util.h
@@ -51,7 +51,7 @@ static inline bool hipSupportsDevice(const int hipDevId)
hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
- return (major > 10) || (major == 10 && minor >= 1);
+ return (major >= 9);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/kernel.cpp b/intern/cycles/device/kernel.cpp
index 072731a2af5..96a99cd62cd 100644
--- a/intern/cycles/device/kernel.cpp
+++ b/intern/cycles/device/kernel.cpp
@@ -33,6 +33,8 @@ const char *device_kernel_as_string(DeviceKernel kernel)
return "integrator_shade_surface";
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
return "integrator_shade_surface_raytrace";
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE:
+ return "integrator_shade_surface_mnee";
case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
return "integrator_shade_volume";
case DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL:
diff --git a/intern/cycles/device/memory.h b/intern/cycles/device/memory.h
index 55d6d39cef8..5f44475077e 100644
--- a/intern/cycles/device/memory.h
+++ b/intern/cycles/device/memory.h
@@ -350,7 +350,7 @@ template<typename T> class device_only_memory : public device_memory {
*
* When using memory type MEM_GLOBAL, a pointer to this memory will be
* automatically attached to kernel globals, using the provided name
- * matching an entry in kernel_textures.h. */
+ * matching an entry in kernel/data_arrays.h. */
template<typename T> class device_vector : public device_memory {
public:
diff --git a/intern/cycles/device/metal/bvh.mm b/intern/cycles/device/metal/bvh.mm
index 086fbb093ba..09c4ace081e 100644
--- a/intern/cycles/device/metal/bvh.mm
+++ b/intern/cycles/device/metal/bvh.mm
@@ -11,6 +11,7 @@
# include "util/progress.h"
# include "device/metal/bvh.h"
+# include "device/metal/util.h"
CCL_NAMESPACE_BEGIN
@@ -18,6 +19,7 @@ CCL_NAMESPACE_BEGIN
{ \
string str = string_printf(__VA_ARGS__); \
progress.set_substatus(str); \
+ metal_printf("%s\n", str.c_str()); \
}
BVHMetal::BVHMetal(const BVHParams &params_,
diff --git a/intern/cycles/device/metal/device.mm b/intern/cycles/device/metal/device.mm
index d7f190fc01e..51e3323370a 100644
--- a/intern/cycles/device/metal/device.mm
+++ b/intern/cycles/device/metal/device.mm
@@ -34,7 +34,8 @@ void device_metal_info(vector<DeviceInfo> &devices)
int device_index = 0;
for (id<MTLDevice> &device : usable_devices) {
/* Compute unique ID for persistent user preferences. */
- string device_name = [device.name UTF8String];
+ string device_name = MetalInfo::get_device_name(device);
+
string id = string("METAL_") + device_name;
/* Hardware ID might not be unique, add device number in that case. */
@@ -48,12 +49,6 @@ void device_metal_info(vector<DeviceInfo> &devices)
info.type = DEVICE_METAL;
info.description = string_remove_trademark(string(device_name));
- /* Ensure unique naming on Apple Silicon / SoC devices which return the same string for CPU and
- * GPU */
- if (info.description == system_cpu_brand_string()) {
- info.description += " (GPU)";
- }
-
info.num = device_index;
/* We don't know if it's used for display, but assume it is. */
info.display_device = true;
@@ -69,14 +64,15 @@ string device_metal_capabilities()
{
string result = "";
auto allDevices = MTLCopyAllDevices();
- uint32_t num_devices = allDevices.count;
+ uint32_t num_devices = (uint32_t)allDevices.count;
if (num_devices == 0) {
return "No Metal devices found\n";
}
result += string_printf("Number of devices: %u\n", num_devices);
for (id<MTLDevice> device in allDevices) {
- result += string_printf("\t\tDevice: %s\n", [device.name UTF8String]);
+ string device_name = MetalInfo::get_device_name(device);
+ result += string_printf("\t\tDevice: %s\n", device_name.c_str());
}
return result;
diff --git a/intern/cycles/device/metal/device_impl.h b/intern/cycles/device/metal/device_impl.h
index 7506b9b069f..99e60d3a788 100644
--- a/intern/cycles/device/metal/device_impl.h
+++ b/intern/cycles/device/metal/device_impl.h
@@ -31,6 +31,8 @@ class MetalDevice : public Device {
string source[PSO_NUM];
string source_md5[PSO_NUM];
+ bool capture_enabled = false;
+
KernelParamsMetal launch_params = {0};
/* MetalRT members ----------------------------------*/
@@ -40,7 +42,6 @@ class MetalDevice : public Device {
nil; /* encoder used for fetching device pointers from MTLAccelerationStructure */
/*---------------------------------------------------*/
- string device_name;
MetalGPUVendor device_vendor;
uint kernel_features;
@@ -74,7 +75,8 @@ class MetalDevice : public Device {
std::vector<id<MTLTexture>> texture_slot_map;
bool use_metalrt = false;
- bool use_function_specialisation = false;
+ MetalPipelineType kernel_specialization_level = PSO_GENERIC;
+ std::atomic_bool async_compile_and_load = false;
virtual BVHLayoutMask get_bvh_layout_mask() const override;
@@ -90,9 +92,7 @@ class MetalDevice : public Device {
bool use_adaptive_compilation();
- string get_source(const uint kernel_features);
-
- string compile_kernel(const uint kernel_features, const char *name);
+ void make_source(MetalPipelineType pso_type, const uint kernel_features);
virtual bool load_kernels(const uint kernel_features) override;
@@ -110,7 +110,9 @@ class MetalDevice : public Device {
virtual void build_bvh(BVH *bvh, Progress &progress, bool refit) override;
- id<MTLLibrary> compile(string const &source);
+ virtual void optimize_for_scene(Scene *scene) override;
+
+ bool compile_and_load(MetalPipelineType pso_type);
/* ------------------------------------------------------------------ */
/* low-level memory management */
diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm
index e1438a9d6e2..d1250b83d22 100644
--- a/intern/cycles/device/metal/device_impl.mm
+++ b/intern/cycles/device/metal/device_impl.mm
@@ -6,9 +6,12 @@
# include "device/metal/device_impl.h"
# include "device/metal/device.h"
+# include "scene/scene.h"
+
# include "util/debug.h"
# include "util/md5.h"
# include "util/path.h"
+# include "util/time.h"
CCL_NAMESPACE_BEGIN
@@ -35,7 +38,7 @@ void MetalDevice::set_error(const string &error)
}
MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
- : Device(info, stats, profiler), texture_info(this, "__texture_info", MEM_GLOBAL)
+ : Device(info, stats, profiler), texture_info(this, "texture_info", MEM_GLOBAL)
{
mtlDevId = info.num;
@@ -43,10 +46,9 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
auto usable_devices = MetalInfo::get_usable_devices();
assert(mtlDevId < usable_devices.size());
mtlDevice = usable_devices[mtlDevId];
- device_name = [mtlDevice.name UTF8String];
- device_vendor = MetalInfo::get_vendor_from_device_name(device_name);
+ device_vendor = MetalInfo::get_device_vendor(mtlDevice);
assert(device_vendor != METAL_GPU_UNKNOWN);
- metal_printf("Creating new Cycles device for Metal: %s\n", device_name.c_str());
+ metal_printf("Creating new Cycles device for Metal: %s\n", info.description.c_str());
/* determine default storage mode based on whether UMA is supported */
@@ -78,6 +80,10 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
case METAL_GPU_APPLE: {
max_threads_per_threadgroup = 512;
use_metalrt = info.use_metalrt;
+
+ /* Specialize the intersection kernels on Apple GPUs by default as these can be built very
+ * quickly. */
+ kernel_specialization_level = PSO_SPECIALIZED_INTERSECT;
break;
}
}
@@ -86,6 +92,17 @@ MetalDevice::MetalDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
use_metalrt = (atoi(metalrt) != 0);
}
+ if (getenv("CYCLES_DEBUG_METAL_CAPTURE_KERNEL")) {
+ capture_enabled = true;
+ }
+
+ if (auto envstr = getenv("CYCLES_METAL_SPECIALIZATION_LEVEL")) {
+ kernel_specialization_level = (MetalPipelineType)atoi(envstr);
+ }
+ metal_printf("kernel_specialization_level = %s\n",
+ kernel_type_as_string(
+ (MetalPipelineType)min((int)kernel_specialization_level, (int)PSO_NUM - 1)));
+
MTLArgumentDescriptor *arg_desc_params = [[MTLArgumentDescriptor alloc] init];
arg_desc_params.dataType = MTLDataTypePointer;
arg_desc_params.access = MTLArgumentAccessReadOnly;
@@ -205,61 +222,86 @@ bool MetalDevice::use_adaptive_compilation()
return DebugFlags().metal.adaptive_compile;
}
-string MetalDevice::get_source(const uint kernel_features)
+void MetalDevice::make_source(MetalPipelineType pso_type, const uint kernel_features)
{
- string build_options;
-
+ string global_defines;
if (use_adaptive_compilation()) {
- build_options += " -D__KERNEL_FEATURES__=" + to_string(kernel_features);
+ global_defines += "#define __KERNEL_FEATURES__ " + to_string(kernel_features) + "\n";
}
if (use_metalrt) {
- build_options += "-D__METALRT__ ";
+ global_defines += "#define __METALRT__\n";
if (motion_blur) {
- build_options += "-D__METALRT_MOTION__ ";
+ global_defines += "#define __METALRT_MOTION__\n";
}
}
# ifdef WITH_CYCLES_DEBUG
- build_options += "-D__KERNEL_DEBUG__ ";
+ global_defines += "#define __KERNEL_DEBUG__\n";
# endif
switch (device_vendor) {
default:
break;
case METAL_GPU_INTEL:
- build_options += "-D__KERNEL_METAL_INTEL__ ";
+ global_defines += "#define __KERNEL_METAL_INTEL__\n";
break;
case METAL_GPU_AMD:
- build_options += "-D__KERNEL_METAL_AMD__ ";
+ global_defines += "#define __KERNEL_METAL_AMD__\n";
break;
case METAL_GPU_APPLE:
- build_options += "-D__KERNEL_METAL_APPLE__ ";
+ global_defines += "#define __KERNEL_METAL_APPLE__\n";
break;
}
- /* reformat -D defines list into compilable form */
- vector<string> components;
- string_replace(build_options, "-D", "");
- string_split(components, build_options, " ");
+ string &source = this->source[pso_type];
+ source = "\n#include \"kernel/device/metal/kernel.metal\"\n";
+ source = path_source_replace_includes(source, path_get("source"));
- string globalDefines;
- for (const string &component : components) {
- vector<string> assignments;
- string_split(assignments, component, "=");
- if (assignments.size() == 2)
- globalDefines += string_printf(
- "#define %s %s\n", assignments[0].c_str(), assignments[1].c_str());
- else
- globalDefines += string_printf("#define %s\n", assignments[0].c_str());
+ /* Perform any required specialization on the source.
+ * With Metal function constants we can generate a single variant of the kernel source which can
+ * be repeatedly respecialized.
+ */
+ string baked_constants;
+
+ /* Replace specific KernelData "dot" dereferences with a Metal function_constant identifier of
+ * the same character length. Build a string of all active constant values which is then hashed
+ * in order to identify the PSO.
+ */
+ if (pso_type != PSO_GENERIC) {
+ const double starttime = time_dt();
+
+# define KERNEL_STRUCT_BEGIN(name, parent) \
+ string_replace_same_length(source, "kernel_data." #parent ".", "kernel_data_" #parent "_");
+
+ /* Add constants to md5 so that 'get_best_pipeline' is able to return a suitable match. */
+# define KERNEL_STRUCT_MEMBER(parent, _type, name) \
+ baked_constants += string(#parent "." #name "=") + \
+ to_string(_type(launch_params.data.parent.name)) + "\n";
+
+# include "kernel/data_template.h"
+
+ /* Opt in to all of available specializations. This can be made more granular for the
+ * PSO_SPECIALIZED_INTERSECT case in order to minimize the number of specialization requests,
+ * but the overhead should be negligible as these are very quick to (re)build and aren't
+ * serialized to disk via MTLBinaryArchives.
+ */
+ global_defines += "#define __KERNEL_USE_DATA_CONSTANTS__\n";
+
+ metal_printf("KernelData patching took %.1f ms\n", (time_dt() - starttime) * 1000.0);
}
- string source = globalDefines + "\n#include \"kernel/device/metal/kernel.metal\"\n";
- source = path_source_replace_includes(source, path_get("source"));
-
- metal_printf("Global defines:\n%s\n", globalDefines.c_str());
+ source = global_defines + source;
+ metal_printf("================\n%s================\n\%s================\n",
+ global_defines.c_str(),
+ baked_constants.c_str());
- return source;
+ /* Generate an MD5 from the source and include any baked constants. This is used when caching
+ * PSOs. */
+ MD5Hash md5;
+ md5.append(baked_constants);
+ md5.append(source);
+ source_md5[pso_type] = md5.get_hex();
}
bool MetalDevice::load_kernels(const uint _kernel_features)
@@ -275,24 +317,22 @@ bool MetalDevice::load_kernels(const uint _kernel_features)
* active, but may still need to be rendered without motion blur if that isn't active as well. */
motion_blur = kernel_features & KERNEL_FEATURE_OBJECT_MOTION;
- source[PSO_GENERIC] = get_source(kernel_features);
- mtlLibrary[PSO_GENERIC] = compile(source[PSO_GENERIC]);
-
- MD5Hash md5;
- md5.append(source[PSO_GENERIC]);
- source_md5[PSO_GENERIC] = md5.get_hex();
-
- metal_printf("Front-end compilation finished (generic)\n");
-
- bool result = MetalDeviceKernels::load(this, false);
+ bool result = compile_and_load(PSO_GENERIC);
reserve_local_memory(kernel_features);
-
return result;
}
-id<MTLLibrary> MetalDevice::compile(string const &source)
+bool MetalDevice::compile_and_load(MetalPipelineType pso_type)
{
+ make_source(pso_type, kernel_features);
+
+ if (!MetalDeviceKernels::should_load_kernels(this, pso_type)) {
+ /* We already have a full set of matching pipelines which are cached or queued. */
+ metal_printf("%s kernels already requested\n", kernel_type_as_string(pso_type));
+ return true;
+ }
+
MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
options.fastMathEnabled = YES;
@@ -300,19 +340,30 @@ id<MTLLibrary> MetalDevice::compile(string const &source)
options.languageVersion = MTLLanguageVersion2_4;
}
+ if (getenv("CYCLES_METAL_PROFILING") || getenv("CYCLES_METAL_DEBUG")) {
+ path_write_text(path_cache_get(string_printf("%s.metal", kernel_type_as_string(pso_type))),
+ source[pso_type]);
+ }
+
+ const double starttime = time_dt();
+
NSError *error = NULL;
- id<MTLLibrary> mtlLibrary = [mtlDevice newLibraryWithSource:@(source.c_str())
- options:options
- error:&error];
+ mtlLibrary[pso_type] = [mtlDevice newLibraryWithSource:@(source[pso_type].c_str())
+ options:options
+ error:&error];
- if (!mtlLibrary) {
+ if (!mtlLibrary[pso_type]) {
NSString *err = [error localizedDescription];
set_error(string_printf("Failed to compile library:\n%s", [err UTF8String]));
}
+ metal_printf("Front-end compilation finished in %.1f seconds (%s)\n",
+ time_dt() - starttime,
+ kernel_type_as_string(pso_type));
+
[options release];
- return mtlLibrary;
+ return MetalDeviceKernels::load(this, pso_type);
}
void MetalDevice::reserve_local_memory(const uint kernel_features)
@@ -394,7 +445,7 @@ MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem)
}
if (size > 0) {
- if (mem.type == MEM_DEVICE_ONLY) {
+ if (mem.type == MEM_DEVICE_ONLY && !capture_enabled) {
options = MTLResourceStorageModePrivate;
}
@@ -407,9 +458,9 @@ MetalDevice::MetalMem *MetalDevice::generic_alloc(device_memory &mem)
}
if (mem.name) {
- VLOG(2) << "Buffer allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Buffer allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
}
mem.device_size = metal_buffer.allocatedSize;
@@ -619,11 +670,63 @@ device_ptr MetalDevice::mem_alloc_sub_ptr(device_memory &mem, size_t offset, siz
return 0;
}
+void MetalDevice::optimize_for_scene(Scene *scene)
+{
+ MetalPipelineType specialization_level = kernel_specialization_level;
+
+ if (specialization_level < PSO_SPECIALIZED_INTERSECT) {
+ return;
+ }
+
+ /* PSO_SPECIALIZED_INTERSECT kernels are fast to specialize, so we always load them
+ * synchronously. */
+ compile_and_load(PSO_SPECIALIZED_INTERSECT);
+
+ if (specialization_level < PSO_SPECIALIZED_SHADE) {
+ return;
+ }
+ if (!scene->params.background) {
+ /* Don't load PSO_SPECIALIZED_SHADE kernels during viewport rendering as they are slower to
+ * build. */
+ return;
+ }
+
+ /* PSO_SPECIALIZED_SHADE kernels are slower to specialize, so we load them asynchronously, and
+ * only if there isn't an existing load in flight.
+ */
+ auto specialize_shade_fn = ^() {
+ compile_and_load(PSO_SPECIALIZED_SHADE);
+ async_compile_and_load = false;
+ };
+
+ bool async_specialize_shade = true;
+
+ /* Block if a per-kernel profiling is enabled (ensure steady rendering rate). */
+ if (getenv("CYCLES_METAL_PROFILING") != nullptr) {
+ async_specialize_shade = false;
+ }
+
+ if (async_specialize_shade) {
+ if (!async_compile_and_load) {
+ async_compile_and_load = true;
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+ specialize_shade_fn);
+ }
+ else {
+ metal_printf(
+ "Async PSO_SPECIALIZED_SHADE load request already in progress - dropping request\n");
+ }
+ }
+ else {
+ specialize_shade_fn();
+ }
+}
+
void MetalDevice::const_copy_to(const char *name, void *host, size_t size)
{
- if (strcmp(name, "__data") == 0) {
+ if (strcmp(name, "data") == 0) {
assert(size == sizeof(KernelData));
- memcpy((uint8_t *)&launch_params + offsetof(KernelParamsMetal, data), host, size);
+ memcpy((uint8_t *)&launch_params.data, host, sizeof(KernelData));
return;
}
@@ -642,19 +745,19 @@ void MetalDevice::const_copy_to(const char *name, void *host, size_t size)
};
/* Update data storage pointers in launch parameters. */
- if (strcmp(name, "__integrator_state") == 0) {
+ if (strcmp(name, "integrator_state") == 0) {
/* IntegratorStateGPU is contiguous pointers */
- const size_t pointer_block_size = sizeof(IntegratorStateGPU);
+ const size_t pointer_block_size = offsetof(IntegratorStateGPU, sort_partition_divisor);
update_launch_pointers(
- offsetof(KernelParamsMetal, __integrator_state), host, size, pointer_block_size);
+ offsetof(KernelParamsMetal, integrator_state), host, size, pointer_block_size);
}
-# define KERNEL_TEX(data_type, tex_name) \
+# define KERNEL_DATA_ARRAY(data_type, tex_name) \
else if (strcmp(name, #tex_name) == 0) \
{ \
update_launch_pointers(offsetof(KernelParamsMetal, tex_name), host, size, size); \
}
-# include "kernel/textures.h"
-# undef KERNEL_TEX
+# include "kernel/data_arrays.h"
+# undef KERNEL_DATA_ARRAY
}
void MetalDevice::global_alloc(device_memory &mem)
@@ -697,8 +800,7 @@ void MetalDevice::tex_alloc_as_buffer(device_texture &mem)
void MetalDevice::tex_alloc(device_texture &mem)
{
/* Check that dimensions fit within maximum allowable size.
- See https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
- */
+ * See: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
if (mem.data_width > 16384 || mem.data_height > 16384) {
set_error(string_printf(
"Texture exceeds maximum allowed size of 16384 x 16384 (requested: %zu x %zu)",
@@ -797,9 +899,9 @@ void MetalDevice::tex_alloc(device_texture &mem)
desc.textureType = MTLTextureType3D;
desc.depth = mem.data_depth;
- VLOG(2) << "Texture 3D allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Texture 3D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
assert(mtlTexture);
@@ -831,9 +933,9 @@ void MetalDevice::tex_alloc(device_texture &mem)
desc.storageMode = storage_mode;
desc.usage = MTLTextureUsageShaderRead;
- VLOG(2) << "Texture 2D allocate: " << mem.name << ", "
- << string_human_readable_number(mem.memory_size()) << " bytes. ("
- << string_human_readable_size(mem.memory_size()) << ")";
+ VLOG_WORK << "Texture 2D allocate: " << mem.name << ", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
mtlTexture = [mtlDevice newTextureWithDescriptor:desc];
assert(mtlTexture);
diff --git a/intern/cycles/device/metal/kernel.h b/intern/cycles/device/metal/kernel.h
index 69b2a686ecc..11393f8b7e1 100644
--- a/intern/cycles/device/metal/kernel.h
+++ b/intern/cycles/device/metal/kernel.h
@@ -31,7 +31,7 @@ enum {
enum { METALRT_TABLE_DEFAULT, METALRT_TABLE_SHADOW, METALRT_TABLE_LOCAL, METALRT_TABLE_NUM };
/* Pipeline State Object types */
-enum {
+enum MetalPipelineType {
/* A kernel that can be used with all scenes, supporting all features.
* It is slow to compile, but only needs to be compiled once and is then
* cached for future render sessions. This allows a render to get underway
@@ -39,28 +39,33 @@ enum {
*/
PSO_GENERIC,
- /* A kernel that is relatively quick to compile, but is specialized for the
- * scene being rendered. It only contains the functionality and even baked in
- * constants for values that means it needs to be recompiled whenever a
- * dependent setting is changed. The render performance of this kernel is
- * significantly faster though, and justifies the extra compile time.
+ /* A intersection kernel that is very quick to specialize and results in faster intersection
+ * kernel performance. It uses Metal function constants to replace several KernelData variables
+ * with fixed constants.
+ */
+ PSO_SPECIALIZED_INTERSECT,
+
+ /* A shading kernel that is slow to specialize, but results in faster shading kernel performance
+ * rendered. It uses Metal function constants to replace several KernelData variables with fixed
+ * constants and short-circuit all unused SVM node case handlers.
*/
- /* METAL_WIP: This isn't used and will require more changes to enable. */
- PSO_SPECIALISED,
+ PSO_SPECIALIZED_SHADE,
PSO_NUM
};
-const char *kernel_type_as_string(int kernel_type);
+const char *kernel_type_as_string(MetalPipelineType pso_type);
struct MetalKernelPipeline {
void compile();
id<MTLLibrary> mtlLibrary = nil;
- bool scene_specialized;
+ MetalPipelineType pso_type;
string source_md5;
+ size_t usage_count = 0;
+ KernelData kernel_data_;
bool use_metalrt;
bool metalrt_hair;
bool metalrt_hair_thick;
@@ -75,6 +80,8 @@ struct MetalKernelPipeline {
id<MTLComputePipelineState> pipeline = nil;
int num_threads_per_block = 0;
+ bool should_use_binary_archive() const;
+
string error_str;
API_AVAILABLE(macos(11.0))
@@ -85,7 +92,8 @@ struct MetalKernelPipeline {
/* Cache of Metal kernels for each DeviceKernel. */
namespace MetalDeviceKernels {
-bool load(MetalDevice *device, bool scene_specialized);
+bool should_load_kernels(MetalDevice *device, MetalPipelineType pso_type);
+bool load(MetalDevice *device, MetalPipelineType pso_type);
const MetalKernelPipeline *get_best_pipeline(const MetalDevice *device, DeviceKernel kernel);
} /* namespace MetalDeviceKernels */
diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm
index 304efc813ec..385cb412b06 100644
--- a/intern/cycles/device/metal/kernel.mm
+++ b/intern/cycles/device/metal/kernel.mm
@@ -5,6 +5,7 @@
# include "device/metal/kernel.h"
# include "device/metal/device_impl.h"
+# include "kernel/device/metal/function_constants.h"
# include "util/md5.h"
# include "util/path.h"
# include "util/tbb.h"
@@ -16,13 +17,15 @@ CCL_NAMESPACE_BEGIN
/* limit to 2 MTLCompiler instances */
int max_mtlcompiler_threads = 2;
-const char *kernel_type_as_string(int kernel_type)
+const char *kernel_type_as_string(MetalPipelineType pso_type)
{
- switch (kernel_type) {
+ switch (pso_type) {
case PSO_GENERIC:
return "PSO_GENERIC";
- case PSO_SPECIALISED:
- return "PSO_SPECIALISED";
+ case PSO_SPECIALIZED_INTERSECT:
+ return "PSO_SPECIALIZED_INTERSECT";
+ case PSO_SPECIALIZED_SHADE:
+ return "PSO_SPECIALIZED_SHADE";
default:
assert(0);
}
@@ -35,7 +38,8 @@ bool kernel_has_intersection(DeviceKernel device_kernel)
device_kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW ||
device_kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE ||
device_kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK ||
- device_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE);
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE);
}
struct ShaderCache {
@@ -49,7 +53,11 @@ struct ShaderCache {
/* Non-blocking request for a kernel, optionally specialized to the scene being rendered by
* device. */
- void load_kernel(DeviceKernel kernel, MetalDevice *device, bool scene_specialized);
+ void load_kernel(DeviceKernel kernel, MetalDevice *device, MetalPipelineType pso_type);
+
+ bool should_load_kernel(DeviceKernel device_kernel,
+ MetalDevice *device,
+ MetalPipelineType pso_type);
void wait_for_all();
@@ -138,31 +146,34 @@ void ShaderCache::compile_thread_func(int thread_index)
}
}
-void ShaderCache::load_kernel(DeviceKernel device_kernel,
- MetalDevice *device,
- bool scene_specialized)
+bool ShaderCache::should_load_kernel(DeviceKernel device_kernel,
+ MetalDevice *device,
+ MetalPipelineType pso_type)
{
- {
- /* create compiler threads on first run */
- thread_scoped_lock lock(cache_mutex);
- if (compile_threads.empty()) {
- running = true;
- for (int i = 0; i < max_mtlcompiler_threads; i++) {
- compile_threads.push_back(std::thread([&] { compile_thread_func(i); }));
- }
- }
+ if (device_kernel == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ /* Skip megakernel. */
+ return false;
}
- if (device_kernel == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
- /* skip megakernel */
- return;
+ if (device_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE) {
+ if ((device->kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) == 0) {
+ /* Skip shade_surface_raytrace kernel if the scene doesn't require it. */
+ return false;
+ }
}
- if (scene_specialized) {
+ if (pso_type != PSO_GENERIC) {
/* Only specialize kernels where it can make an impact. */
if (device_kernel < DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
device_kernel > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
- return;
+ return false;
+ }
+
+ /* Only specialize shading / intersection kernels as requested. */
+ bool is_shade_kernel = (device_kernel >= DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ bool is_shade_pso = (pso_type == PSO_SPECIALIZED_SHADE);
+ if (is_shade_pso != is_shade_kernel) {
+ return false;
}
}
@@ -170,35 +181,45 @@ void ShaderCache::load_kernel(DeviceKernel device_kernel,
/* check whether the kernel has already been requested / cached */
thread_scoped_lock lock(cache_mutex);
for (auto &pipeline : pipelines[device_kernel]) {
- if (scene_specialized) {
- if (pipeline->source_md5 == device->source_md5[PSO_SPECIALISED]) {
- /* we already requested a pipeline that is specialized for this kernel data */
- metal_printf("Specialized kernel already requested (%s)\n",
- device_kernel_as_string(device_kernel));
- return;
- }
+ if (pipeline->source_md5 == device->source_md5[pso_type]) {
+ return false;
}
- else {
- if (pipeline->source_md5 == device->source_md5[PSO_GENERIC]) {
- /* we already requested a generic pipeline for this kernel */
- metal_printf("Generic kernel already requested (%s)\n",
- device_kernel_as_string(device_kernel));
- return;
- }
+ }
+ }
+
+ return true;
+}
+
+void ShaderCache::load_kernel(DeviceKernel device_kernel,
+ MetalDevice *device,
+ MetalPipelineType pso_type)
+{
+ {
+ /* create compiler threads on first run */
+ thread_scoped_lock lock(cache_mutex);
+ if (compile_threads.empty()) {
+ running = true;
+ for (int i = 0; i < max_mtlcompiler_threads; i++) {
+ compile_threads.push_back(std::thread([&] { compile_thread_func(i); }));
}
}
}
+ if (!should_load_kernel(device_kernel, device, pso_type)) {
+ return;
+ }
+
incomplete_requests++;
PipelineRequest request;
request.pipeline = new MetalKernelPipeline;
- request.pipeline->scene_specialized = scene_specialized;
+ memcpy(&request.pipeline->kernel_data_,
+ &device->launch_params.data,
+ sizeof(request.pipeline->kernel_data_));
+ request.pipeline->pso_type = pso_type;
request.pipeline->mtlDevice = mtlDevice;
- request.pipeline->source_md5 =
- device->source_md5[scene_specialized ? PSO_SPECIALISED : PSO_GENERIC];
- request.pipeline->mtlLibrary =
- device->mtlLibrary[scene_specialized ? PSO_SPECIALISED : PSO_GENERIC];
+ request.pipeline->source_md5 = device->source_md5[pso_type];
+ request.pipeline->mtlLibrary = device->mtlLibrary[pso_type];
request.pipeline->device_kernel = device_kernel;
request.pipeline->threads_per_threadgroup = device->max_threads_per_threadgroup;
@@ -213,7 +234,24 @@ void ShaderCache::load_kernel(DeviceKernel device_kernel,
{
thread_scoped_lock lock(cache_mutex);
- pipelines[device_kernel].push_back(unique_ptr<MetalKernelPipeline>(request.pipeline));
+ auto &collection = pipelines[device_kernel];
+
+ /* Cache up to 3 kernel variants with the same pso_type, purging oldest first. */
+ int max_entries_of_same_pso_type = 3;
+ for (int i = (int)collection.size() - 1; i >= 0; i--) {
+ if (collection[i]->pso_type == pso_type) {
+ max_entries_of_same_pso_type -= 1;
+ if (max_entries_of_same_pso_type == 0) {
+ metal_printf("Purging oldest %s:%s kernel from ShaderCache\n",
+ kernel_type_as_string(pso_type),
+ device_kernel_as_string(device_kernel));
+ collection.erase(collection.begin() + i);
+ break;
+ }
+ }
+ }
+
+ collection.push_back(unique_ptr<MetalKernelPipeline>(request.pipeline));
request_queue.push_back(request);
}
cond_var.notify_one();
@@ -247,8 +285,9 @@ MetalKernelPipeline *ShaderCache::get_best_pipeline(DeviceKernel kernel, const M
continue;
}
- if (pipeline->scene_specialized) {
- if (pipeline->source_md5 == device->source_md5[PSO_SPECIALISED]) {
+ if (pipeline->pso_type != PSO_GENERIC) {
+ if (pipeline->source_md5 == device->source_md5[PSO_SPECIALIZED_INTERSECT] ||
+ pipeline->source_md5 == device->source_md5[PSO_SPECIALIZED_SHADE]) {
best_pipeline = pipeline.get();
}
}
@@ -257,13 +296,65 @@ MetalKernelPipeline *ShaderCache::get_best_pipeline(DeviceKernel kernel, const M
}
}
+ if (best_pipeline->usage_count == 0 && best_pipeline->pso_type != PSO_GENERIC) {
+ metal_printf("Swapping in %s version of %s\n",
+ kernel_type_as_string(best_pipeline->pso_type),
+ device_kernel_as_string(kernel));
+ }
+ best_pipeline->usage_count += 1;
+
return best_pipeline;
}
-void MetalKernelPipeline::compile()
+bool MetalKernelPipeline::should_use_binary_archive() const
{
- int pso_type = scene_specialized ? PSO_SPECIALISED : PSO_GENERIC;
+ if (auto str = getenv("CYCLES_METAL_DISABLE_BINARY_ARCHIVES")) {
+ if (atoi(str) != 0) {
+ /* Don't archive if we have opted out by env var. */
+ return false;
+ }
+ }
+
+ if (pso_type == PSO_GENERIC) {
+ /* Archive the generic kernels. */
+ return true;
+ }
+
+ if (device_kernel >= DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND &&
+ device_kernel <= DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW) {
+ /* Archive all shade kernels - they take a long time to compile. */
+ return true;
+ }
+
+ /* The remaining kernels are all fast to compile. They may get cached by the system shader cache,
+ * but will be quick to regenerate if not. */
+ return false;
+}
+
+static MTLFunctionConstantValues *GetConstantValues(KernelData const *data = nullptr)
+{
+ MTLFunctionConstantValues *constant_values = [MTLFunctionConstantValues new];
+
+ MTLDataType MTLDataType_int = MTLDataTypeInt;
+ MTLDataType MTLDataType_float = MTLDataTypeFloat;
+ MTLDataType MTLDataType_float4 = MTLDataTypeFloat4;
+ KernelData zero_data = {0};
+ if (!data) {
+ data = &zero_data;
+ }
+# define KERNEL_STRUCT_MEMBER(parent, _type, name) \
+ [constant_values setConstantValue:&data->parent.name \
+ type:MTLDataType_##_type \
+ atIndex:KernelData_##parent##_##name];
+
+# include "kernel/data_template.h"
+
+ return constant_values;
+}
+
+void MetalKernelPipeline::compile()
+{
const std::string function_name = std::string("cycles_metal_") +
device_kernel_as_string(device_kernel);
@@ -280,6 +371,17 @@ void MetalKernelPipeline::compile()
if (@available(macOS 11.0, *)) {
MTLFunctionDescriptor *func_desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
func_desc.name = entryPoint;
+
+ if (pso_type == PSO_SPECIALIZED_SHADE) {
+ func_desc.constantValues = GetConstantValues(&kernel_data_);
+ }
+ else if (pso_type == PSO_SPECIALIZED_INTERSECT) {
+ func_desc.constantValues = GetConstantValues(&kernel_data_);
+ }
+ else {
+ func_desc.constantValues = GetConstantValues();
+ }
+
function = [mtlLibrary newFunctionWithDescriptor:func_desc error:&error];
}
@@ -426,10 +528,7 @@ void MetalKernelPipeline::compile()
MTLPipelineOption pipelineOptions = MTLPipelineOptionNone;
- bool use_binary_archive = true;
- if (auto str = getenv("CYCLES_METAL_DISABLE_BINARY_ARCHIVES")) {
- use_binary_archive = (atoi(str) == 0);
- }
+ bool use_binary_archive = should_use_binary_archive();
id<MTLBinaryArchive> archive = nil;
string metalbin_path;
@@ -607,19 +706,32 @@ void MetalKernelPipeline::compile()
}
}
-bool MetalDeviceKernels::load(MetalDevice *device, bool scene_specialized)
+bool MetalDeviceKernels::load(MetalDevice *device, MetalPipelineType pso_type)
{
+ const double starttime = time_dt();
auto shader_cache = get_shader_cache(device->mtlDevice);
for (int i = 0; i < DEVICE_KERNEL_NUM; i++) {
- shader_cache->load_kernel((DeviceKernel)i, device, scene_specialized);
+ shader_cache->load_kernel((DeviceKernel)i, device, pso_type);
}
- if (!scene_specialized || getenv("CYCLES_METAL_PROFILING")) {
- shader_cache->wait_for_all();
- }
+ shader_cache->wait_for_all();
+ metal_printf("Back-end compilation finished in %.1f seconds (%s)\n",
+ time_dt() - starttime,
+ kernel_type_as_string(pso_type));
return true;
}
+bool MetalDeviceKernels::should_load_kernels(MetalDevice *device, MetalPipelineType pso_type)
+{
+ auto shader_cache = get_shader_cache(device->mtlDevice);
+ for (int i = 0; i < DEVICE_KERNEL_NUM; i++) {
+ if (shader_cache->should_load_kernel((DeviceKernel)i, device, pso_type)) {
+ return true;
+ }
+ }
+ return false;
+}
+
const MetalKernelPipeline *MetalDeviceKernels::get_best_pipeline(const MetalDevice *device,
DeviceKernel kernel)
{
diff --git a/intern/cycles/device/metal/queue.h b/intern/cycles/device/metal/queue.h
index 6cc84a20787..fc32740f3e1 100644
--- a/intern/cycles/device/metal/queue.h
+++ b/intern/cycles/device/metal/queue.h
@@ -12,8 +12,6 @@
# include "device/metal/util.h"
# include "kernel/device/metal/globals.h"
-# define metal_printf VLOG(4) << string_printf
-
CCL_NAMESPACE_BEGIN
class MetalDevice;
@@ -26,6 +24,7 @@ class MetalDeviceQueue : public DeviceQueue {
virtual int num_concurrent_states(const size_t) const override;
virtual int num_concurrent_busy_states() const override;
+ virtual int num_sort_partition_elements() const override;
virtual void init_execution() override;
@@ -40,43 +39,82 @@ class MetalDeviceQueue : public DeviceQueue {
virtual void copy_from_device(device_memory &mem) override;
protected:
+ void setup_capture();
+ void update_capture(DeviceKernel kernel);
+ void begin_capture();
+ void end_capture();
void prepare_resources(DeviceKernel kernel);
id<MTLComputeCommandEncoder> get_compute_encoder(DeviceKernel kernel);
id<MTLBlitCommandEncoder> get_blit_encoder();
- MetalDevice *metal_device;
- MetalBufferPool temp_buffer_pool;
+ MetalDevice *metal_device_;
+ MetalBufferPool temp_buffer_pool_;
API_AVAILABLE(macos(11.0), ios(14.0))
- MTLCommandBufferDescriptor *command_buffer_desc = nullptr;
- id<MTLDevice> mtlDevice = nil;
- id<MTLCommandQueue> mtlCommandQueue = nil;
- id<MTLCommandBuffer> mtlCommandBuffer = nil;
- id<MTLComputeCommandEncoder> mtlComputeEncoder = nil;
- id<MTLBlitCommandEncoder> mtlBlitEncoder = nil;
+ MTLCommandBufferDescriptor *command_buffer_desc_ = nullptr;
+ id<MTLDevice> mtlDevice_ = nil;
+ id<MTLCommandQueue> mtlCommandQueue_ = nil;
+ id<MTLCommandBuffer> mtlCommandBuffer_ = nil;
+ id<MTLComputeCommandEncoder> mtlComputeEncoder_ = nil;
+ id<MTLBlitCommandEncoder> mtlBlitEncoder_ = nil;
API_AVAILABLE(macos(10.14), ios(14.0))
- id<MTLSharedEvent> shared_event = nil;
+ id<MTLSharedEvent> shared_event_ = nil;
API_AVAILABLE(macos(10.14), ios(14.0))
- MTLSharedEventListener *shared_event_listener = nil;
+ MTLSharedEventListener *shared_event_listener_ = nil;
- dispatch_queue_t event_queue;
- dispatch_semaphore_t wait_semaphore;
+ dispatch_queue_t event_queue_;
+ dispatch_semaphore_t wait_semaphore_;
struct CopyBack {
void *host_pointer;
void *gpu_mem;
uint64_t size;
};
- std::vector<CopyBack> copy_back_mem;
+ std::vector<CopyBack> copy_back_mem_;
- uint64_t shared_event_id;
- uint64_t command_buffers_submitted = 0;
- uint64_t command_buffers_completed = 0;
- Stats &stats;
+ uint64_t shared_event_id_;
+ uint64_t command_buffers_submitted_ = 0;
+ uint64_t command_buffers_completed_ = 0;
+ Stats &stats_;
void close_compute_encoder();
void close_blit_encoder();
+
+ bool verbose_tracing_ = false;
+ bool label_command_encoders_ = false;
+
+ /* Per-kernel profiling (see CYCLES_METAL_PROFILING). */
+
+ struct TimingData {
+ DeviceKernel kernel;
+ int work_size;
+ uint64_t timing_id;
+ };
+ std::vector<TimingData> command_encoder_labels_;
+ API_AVAILABLE(macos(10.14), ios(14.0))
+ id<MTLSharedEvent> timing_shared_event_ = nil;
+ uint64_t timing_shared_event_id_;
+ uint64_t command_buffer_start_timing_id_;
+
+ struct TimingStats {
+ double total_time = 0.0;
+ uint64_t total_work_size = 0;
+ uint64_t num_dispatches = 0;
+ };
+ TimingStats timing_stats_[DEVICE_KERNEL_NUM];
+ double last_completion_time_ = 0.0;
+
+ /* .gputrace capture (see CYCLES_DEBUG_METAL_CAPTURE_...). */
+
+ id<MTLCaptureScope> mtlCaptureScope_ = nil;
+ DeviceKernel capture_kernel_;
+ int capture_dispatch_counter_ = 0;
+ bool capture_samples_ = false;
+ int capture_reset_counter_ = 0;
+ bool is_capturing_ = false;
+ bool is_capturing_to_disk_ = false;
+ bool has_captured_to_disk_ = false;
};
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/metal/queue.mm b/intern/cycles/device/metal/queue.mm
index ec10e091b25..5ac63a16c61 100644
--- a/intern/cycles/device/metal/queue.mm
+++ b/intern/cycles/device/metal/queue.mm
@@ -17,46 +17,250 @@ CCL_NAMESPACE_BEGIN
/* MetalDeviceQueue */
MetalDeviceQueue::MetalDeviceQueue(MetalDevice *device)
- : DeviceQueue(device), metal_device(device), stats(device->stats)
+ : DeviceQueue(device), metal_device_(device), stats_(device->stats)
{
if (@available(macos 11.0, *)) {
- command_buffer_desc = [[MTLCommandBufferDescriptor alloc] init];
- command_buffer_desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
+ command_buffer_desc_ = [[MTLCommandBufferDescriptor alloc] init];
+ command_buffer_desc_.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
}
- mtlDevice = device->mtlDevice;
- mtlCommandQueue = [mtlDevice newCommandQueue];
+ mtlDevice_ = device->mtlDevice;
+ mtlCommandQueue_ = [mtlDevice_ newCommandQueue];
if (@available(macos 10.14, *)) {
- shared_event = [mtlDevice newSharedEvent];
- shared_event_id = 1;
+ shared_event_ = [mtlDevice_ newSharedEvent];
+ shared_event_id_ = 1;
/* Shareable event listener */
- event_queue = dispatch_queue_create("com.cycles.metal.event_queue", NULL);
- shared_event_listener = [[MTLSharedEventListener alloc] initWithDispatchQueue:event_queue];
+ event_queue_ = dispatch_queue_create("com.cycles.metal.event_queue", NULL);
+ shared_event_listener_ = [[MTLSharedEventListener alloc] initWithDispatchQueue:event_queue_];
}
- wait_semaphore = dispatch_semaphore_create(0);
+ wait_semaphore_ = dispatch_semaphore_create(0);
+
+ if (@available(macos 10.14, *)) {
+ if (getenv("CYCLES_METAL_PROFILING")) {
+ /* Enable per-kernel timing breakdown (shown at end of render). */
+ timing_shared_event_ = [mtlDevice_ newSharedEvent];
+ label_command_encoders_ = true;
+ }
+ if (getenv("CYCLES_METAL_DEBUG")) {
+ /* Enable very verbose tracing (shows every dispatch). */
+ verbose_tracing_ = true;
+ label_command_encoders_ = true;
+ }
+ timing_shared_event_id_ = 1;
+ }
+
+ setup_capture();
+}
+
+void MetalDeviceQueue::setup_capture()
+{
+ capture_kernel_ = DeviceKernel(-1);
+
+ if (auto capture_kernel_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_KERNEL")) {
+ /* CYCLES_DEBUG_METAL_CAPTURE_KERNEL captures a single dispatch of the specified kernel. */
+ capture_kernel_ = DeviceKernel(atoi(capture_kernel_str));
+ printf("Capture kernel: %d = %s\n", capture_kernel_, device_kernel_as_string(capture_kernel_));
+
+ capture_dispatch_counter_ = 0;
+ if (auto capture_dispatch_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_DISPATCH")) {
+ capture_dispatch_counter_ = atoi(capture_dispatch_str);
+
+ printf("Capture dispatch number %d\n", capture_dispatch_counter_);
+ }
+ }
+ else if (auto capture_samples_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_SAMPLES")) {
+ /* CYCLES_DEBUG_METAL_CAPTURE_SAMPLES captures a block of dispatches from reset#(N) to
+ * reset#(N+1). */
+ capture_samples_ = true;
+ capture_reset_counter_ = atoi(capture_samples_str);
+
+ capture_dispatch_counter_ = INT_MAX;
+ if (auto capture_limit_str = getenv("CYCLES_DEBUG_METAL_CAPTURE_LIMIT")) {
+ /* CYCLES_DEBUG_METAL_CAPTURE_LIMIT sets the maximum number of dispatches to capture. */
+ capture_dispatch_counter_ = atoi(capture_limit_str);
+ }
+
+ printf("Capturing sample block %d (dispatch limit: %d)\n",
+ capture_reset_counter_,
+ capture_dispatch_counter_);
+ }
+ else {
+ /* No capturing requested. */
+ return;
+ }
+
+ /* Enable .gputrace capture for the specified DeviceKernel. */
+ MTLCaptureManager *captureManager = [MTLCaptureManager sharedCaptureManager];
+ mtlCaptureScope_ = [captureManager newCaptureScopeWithDevice:mtlDevice_];
+ mtlCaptureScope_.label = [NSString stringWithFormat:@"Cycles kernel dispatch"];
+ [captureManager setDefaultCaptureScope:mtlCaptureScope_];
+
+ label_command_encoders_ = true;
+
+ if (auto capture_url = getenv("CYCLES_DEBUG_METAL_CAPTURE_URL")) {
+ if (@available(macos 10.15, *)) {
+ if ([captureManager supportsDestination:MTLCaptureDestinationGPUTraceDocument]) {
+
+ MTLCaptureDescriptor *captureDescriptor = [[MTLCaptureDescriptor alloc] init];
+ captureDescriptor.captureObject = mtlCaptureScope_;
+ captureDescriptor.destination = MTLCaptureDestinationGPUTraceDocument;
+ captureDescriptor.outputURL = [NSURL fileURLWithPath:@(capture_url)];
+
+ NSError *error;
+ if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error]) {
+ NSString *err = [error localizedDescription];
+ printf("Start capture failed: %s\n", [err UTF8String]);
+ }
+ else {
+ printf("Capture started (URL: %s)\n", capture_url);
+ is_capturing_to_disk_ = true;
+ }
+ }
+ else {
+ printf("Capture to file is not supported\n");
+ }
+ }
+ }
+}
+
+void MetalDeviceQueue::update_capture(DeviceKernel kernel)
+{
+ /* Handle capture end triggers. */
+ if (is_capturing_) {
+ capture_dispatch_counter_ -= 1;
+ if (capture_dispatch_counter_ <= 0 || kernel == DEVICE_KERNEL_INTEGRATOR_RESET) {
+ /* End capture if we've hit the dispatch limit or we hit a "reset". */
+ end_capture();
+ }
+ return;
+ }
+
+ if (capture_dispatch_counter_ < 0) {
+ /* We finished capturing. */
+ return;
+ }
+
+ /* Handle single-capture start trigger. */
+ if (kernel == capture_kernel_) {
+ /* Start capturing when the we hit the Nth dispatch of the specified kernel. */
+ if (capture_dispatch_counter_ == 0) {
+ begin_capture();
+ }
+ capture_dispatch_counter_ -= 1;
+ return;
+ }
+
+ /* Handle multi-capture start trigger. */
+ if (capture_samples_) {
+ /* Start capturing when the reset countdown is at 0. */
+ if (capture_reset_counter_ == 0) {
+ begin_capture();
+ }
+
+ if (kernel == DEVICE_KERNEL_INTEGRATOR_RESET) {
+ capture_reset_counter_ -= 1;
+ }
+ return;
+ }
+}
+
+void MetalDeviceQueue::begin_capture()
+{
+ /* Start gputrace capture. */
+ if (mtlCommandBuffer_) {
+ synchronize();
+ }
+ [mtlCaptureScope_ beginScope];
+ printf("[mtlCaptureScope_ beginScope]\n");
+ is_capturing_ = true;
+}
+
+void MetalDeviceQueue::end_capture()
+{
+ [mtlCaptureScope_ endScope];
+ is_capturing_ = false;
+ printf("[mtlCaptureScope_ endScope]\n");
+
+ if (is_capturing_to_disk_) {
+ if (@available(macos 10.15, *)) {
+ [[MTLCaptureManager sharedCaptureManager] stopCapture];
+ has_captured_to_disk_ = true;
+ is_capturing_to_disk_ = false;
+ is_capturing_ = false;
+ printf("Capture stopped\n");
+ }
+ }
}
MetalDeviceQueue::~MetalDeviceQueue()
{
/* Tidying up here isn't really practical - we should expect and require the work
* queue to be empty here. */
- assert(mtlCommandBuffer == nil);
- assert(command_buffers_submitted == command_buffers_completed);
+ assert(mtlCommandBuffer_ == nil);
+ assert(command_buffers_submitted_ == command_buffers_completed_);
if (@available(macos 10.14, *)) {
- [shared_event_listener release];
- [shared_event release];
+ [shared_event_listener_ release];
+ [shared_event_ release];
}
if (@available(macos 11.0, *)) {
- [command_buffer_desc release];
- }
- if (mtlCommandQueue) {
- [mtlCommandQueue release];
- mtlCommandQueue = nil;
+ [command_buffer_desc_ release];
+ }
+ if (mtlCommandQueue_) {
+ [mtlCommandQueue_ release];
+ mtlCommandQueue_ = nil;
+ }
+
+ if (mtlCaptureScope_) {
+ [mtlCaptureScope_ release];
+ }
+
+ double total_time = 0.0;
+
+ /* Show per-kernel timings, if gathered (see CYCLES_METAL_PROFILING). */
+ int64_t num_dispatches = 0;
+ for (auto &stat : timing_stats_) {
+ total_time += stat.total_time;
+ num_dispatches += stat.num_dispatches;
+ }
+
+ if (num_dispatches) {
+ printf("\nMetal dispatch stats:\n\n");
+ auto header = string_printf("%-40s %16s %12s %12s %7s %7s",
+ "Kernel name",
+ "Total threads",
+ "Dispatches",
+ "Avg. T/D",
+ "Time",
+ "Time%");
+ auto divider = string(header.length(), '-');
+ printf("%s\n%s\n%s\n", divider.c_str(), header.c_str(), divider.c_str());
+
+ for (size_t i = 0; i < DEVICE_KERNEL_NUM; i++) {
+ auto &stat = timing_stats_[i];
+ if (stat.num_dispatches > 0) {
+ printf("%-40s %16s %12s %12s %6.2fs %6.2f%%\n",
+ device_kernel_as_string(DeviceKernel(i)),
+ string_human_readable_number(stat.total_work_size).c_str(),
+ string_human_readable_number(stat.num_dispatches).c_str(),
+ string_human_readable_number(stat.total_work_size / stat.num_dispatches).c_str(),
+ stat.total_time,
+ stat.total_time * 100.0 / total_time);
+ }
+ }
+ printf("%s\n", divider.c_str());
+ printf("%-40s %16s %12s %12s %6.2fs %6.2f%%\n",
+ "",
+ "",
+ string_human_readable_number(num_dispatches).c_str(),
+ "",
+ total_time,
+ 100.0);
+ printf("%s\n\n", divider.c_str());
}
}
@@ -66,10 +270,10 @@ int MetalDeviceQueue::num_concurrent_states(const size_t /*state_size*/) const
/* TODO: compute automatically. */
/* TODO: must have at least num_threads_per_block. */
int result = 1048576;
- if (metal_device->device_vendor == METAL_GPU_AMD) {
+ if (metal_device_->device_vendor == METAL_GPU_AMD) {
result *= 2;
}
- else if (metal_device->device_vendor == METAL_GPU_APPLE) {
+ else if (metal_device_->device_vendor == METAL_GPU_APPLE) {
result *= 4;
}
return result;
@@ -80,19 +284,24 @@ int MetalDeviceQueue::num_concurrent_busy_states() const
/* METAL_WIP */
/* TODO: compute automatically. */
int result = 65536;
- if (metal_device->device_vendor == METAL_GPU_AMD) {
+ if (metal_device_->device_vendor == METAL_GPU_AMD) {
result *= 2;
}
- else if (metal_device->device_vendor == METAL_GPU_APPLE) {
+ else if (metal_device_->device_vendor == METAL_GPU_APPLE) {
result *= 4;
}
return result;
}
+int MetalDeviceQueue::num_sort_partition_elements() const
+{
+ return MetalInfo::optimal_sort_partition_elements(metal_device_->mtlDevice);
+}
+
void MetalDeviceQueue::init_execution()
{
/* Synchronize all textures and memory copies before executing task. */
- metal_device->load_texture_info();
+ metal_device_->load_texture_info();
synchronize();
}
@@ -101,15 +310,23 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
const int work_size,
DeviceKernelArguments const &args)
{
- if (metal_device->have_error()) {
+ update_capture(kernel);
+
+ if (metal_device_->have_error()) {
return false;
}
- VLOG(3) << "Metal queue launch " << device_kernel_as_string(kernel) << ", work_size "
- << work_size;
+ VLOG_DEVICE_STATS << "Metal queue launch " << device_kernel_as_string(kernel) << ", work_size "
+ << work_size;
id<MTLComputeCommandEncoder> mtlComputeCommandEncoder = get_compute_encoder(kernel);
+ if (@available(macos 10.14, *)) {
+ if (timing_shared_event_) {
+ command_encoder_labels_.push_back({kernel, work_size, timing_shared_event_id_});
+ }
+ }
+
/* Determine size requirement for argument buffer. */
size_t arg_buffer_length = 0;
for (size_t i = 0; i < args.count; i++) {
@@ -126,8 +343,8 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
/* Metal ancillary bindless pointers. */
size_t metal_offsets = arg_buffer_length;
- arg_buffer_length += metal_device->mtlAncillaryArgEncoder.encodedLength;
- arg_buffer_length = round_up(arg_buffer_length, metal_device->mtlAncillaryArgEncoder.alignment);
+ arg_buffer_length += metal_device_->mtlAncillaryArgEncoder.encodedLength;
+ arg_buffer_length = round_up(arg_buffer_length, metal_device_->mtlAncillaryArgEncoder.alignment);
/* Temporary buffer used to prepare arg_buffer */
uint8_t *init_arg_buffer = (uint8_t *)alloca(arg_buffer_length);
@@ -146,23 +363,27 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
/* Prepare any non-pointer (i.e. plain-old-data) KernelParamsMetal data */
/* The plain-old-data is contiguous, continuing to the end of KernelParamsMetal */
- size_t plain_old_launch_data_offset = offsetof(KernelParamsMetal, __integrator_state) +
- sizeof(IntegratorStateGPU);
+ size_t plain_old_launch_data_offset = offsetof(KernelParamsMetal, integrator_state) +
+ offsetof(IntegratorStateGPU, sort_partition_divisor);
size_t plain_old_launch_data_size = sizeof(KernelParamsMetal) - plain_old_launch_data_offset;
memcpy(init_arg_buffer + globals_offsets + plain_old_launch_data_offset,
- (uint8_t *)&metal_device->launch_params + plain_old_launch_data_offset,
+ (uint8_t *)&metal_device_->launch_params + plain_old_launch_data_offset,
plain_old_launch_data_size);
/* Allocate an argument buffer. */
MTLResourceOptions arg_buffer_options = MTLResourceStorageModeManaged;
if (@available(macOS 11.0, *)) {
- if ([mtlDevice hasUnifiedMemory]) {
+ if ([mtlDevice_ hasUnifiedMemory]) {
arg_buffer_options = MTLResourceStorageModeShared;
}
}
- id<MTLBuffer> arg_buffer = temp_buffer_pool.get_buffer(
- mtlDevice, mtlCommandBuffer, arg_buffer_length, arg_buffer_options, init_arg_buffer, stats);
+ id<MTLBuffer> arg_buffer = temp_buffer_pool_.get_buffer(mtlDevice_,
+ mtlCommandBuffer_,
+ arg_buffer_length,
+ arg_buffer_options,
+ init_arg_buffer,
+ stats_);
/* Encode the pointer "enqueue" arguments */
bytes_written = 0;
@@ -170,16 +391,16 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
size_t size_in_bytes = args.sizes[i];
bytes_written = round_up(bytes_written, size_in_bytes);
if (args.types[i] == DeviceKernelArguments::POINTER) {
- [metal_device->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer
- offset:bytes_written];
+ [metal_device_->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer
+ offset:bytes_written];
if (MetalDevice::MetalMem *mmem = *(MetalDevice::MetalMem **)args.values[i]) {
[mtlComputeCommandEncoder useResource:mmem->mtlBuffer
usage:MTLResourceUsageRead | MTLResourceUsageWrite];
- [metal_device->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer offset:0 atIndex:0];
+ [metal_device_->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer offset:0 atIndex:0];
}
else {
if (@available(macos 12.0, *)) {
- [metal_device->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:0];
+ [metal_device_->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:0];
}
}
}
@@ -187,49 +408,58 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
/* Encode KernelParamsMetal buffers */
- [metal_device->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer offset:globals_offsets];
+ [metal_device_->mtlBufferKernelParamsEncoder setArgumentBuffer:arg_buffer
+ offset:globals_offsets];
+
+ if (label_command_encoders_) {
+ /* Add human-readable labels if we're doing any form of debugging / profiling. */
+ mtlComputeCommandEncoder.label = [[NSString alloc]
+ initWithFormat:@"Metal queue launch %s, work_size %d",
+ device_kernel_as_string(kernel),
+ work_size];
+ }
/* this relies on IntegratorStateGPU layout being contiguous device_ptrs */
- const size_t pointer_block_end = offsetof(KernelParamsMetal, __integrator_state) +
- sizeof(IntegratorStateGPU);
+ const size_t pointer_block_end = offsetof(KernelParamsMetal, integrator_state) +
+ offsetof(IntegratorStateGPU, sort_partition_divisor);
for (size_t offset = 0; offset < pointer_block_end; offset += sizeof(device_ptr)) {
- int pointer_index = offset / sizeof(device_ptr);
+ int pointer_index = int(offset / sizeof(device_ptr));
MetalDevice::MetalMem *mmem = *(
- MetalDevice::MetalMem **)((uint8_t *)&metal_device->launch_params + offset);
- if (mmem && (mmem->mtlBuffer || mmem->mtlTexture)) {
- [metal_device->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer
- offset:0
- atIndex:pointer_index];
+ MetalDevice::MetalMem **)((uint8_t *)&metal_device_->launch_params + offset);
+ if (mmem && mmem->mem && (mmem->mtlBuffer || mmem->mtlTexture)) {
+ [metal_device_->mtlBufferKernelParamsEncoder setBuffer:mmem->mtlBuffer
+ offset:0
+ atIndex:pointer_index];
}
else {
if (@available(macos 12.0, *)) {
- [metal_device->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:pointer_index];
+ [metal_device_->mtlBufferKernelParamsEncoder setBuffer:nil offset:0 atIndex:pointer_index];
}
}
}
bytes_written = globals_offsets + sizeof(KernelParamsMetal);
- const MetalKernelPipeline *metal_kernel_pso = MetalDeviceKernels::get_best_pipeline(metal_device,
- kernel);
+ const MetalKernelPipeline *metal_kernel_pso = MetalDeviceKernels::get_best_pipeline(
+ metal_device_, kernel);
if (!metal_kernel_pso) {
- metal_device->set_error(
+ metal_device_->set_error(
string_printf("No MetalKernelPipeline for %s\n", device_kernel_as_string(kernel)));
return false;
}
/* Encode ancillaries */
- [metal_device->mtlAncillaryArgEncoder setArgumentBuffer:arg_buffer offset:metal_offsets];
- [metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_2d
- offset:0
- atIndex:0];
- [metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_3d
- offset:0
- atIndex:1];
+ [metal_device_->mtlAncillaryArgEncoder setArgumentBuffer:arg_buffer offset:metal_offsets];
+ [metal_device_->mtlAncillaryArgEncoder setBuffer:metal_device_->texture_bindings_2d
+ offset:0
+ atIndex:0];
+ [metal_device_->mtlAncillaryArgEncoder setBuffer:metal_device_->texture_bindings_3d
+ offset:0
+ atIndex:1];
if (@available(macos 12.0, *)) {
- if (metal_device->use_metalrt) {
- if (metal_device->bvhMetalRT) {
- id<MTLAccelerationStructure> accel_struct = metal_device->bvhMetalRT->accel_struct;
- [metal_device->mtlAncillaryArgEncoder setAccelerationStructure:accel_struct atIndex:2];
+ if (metal_device_->use_metalrt) {
+ if (metal_device_->bvhMetalRT) {
+ id<MTLAccelerationStructure> accel_struct = metal_device_->bvhMetalRT->accel_struct;
+ [metal_device_->mtlAncillaryArgEncoder setAccelerationStructure:accel_struct atIndex:2];
}
for (int table = 0; table < METALRT_TABLE_NUM; table++) {
@@ -237,19 +467,19 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
[metal_kernel_pso->intersection_func_table[table] setBuffer:arg_buffer
offset:globals_offsets
atIndex:1];
- [metal_device->mtlAncillaryArgEncoder
+ [metal_device_->mtlAncillaryArgEncoder
setIntersectionFunctionTable:metal_kernel_pso->intersection_func_table[table]
atIndex:3 + table];
[mtlComputeCommandEncoder useResource:metal_kernel_pso->intersection_func_table[table]
usage:MTLResourceUsageRead];
}
else {
- [metal_device->mtlAncillaryArgEncoder setIntersectionFunctionTable:nil
- atIndex:3 + table];
+ [metal_device_->mtlAncillaryArgEncoder setIntersectionFunctionTable:nil
+ atIndex:3 + table];
}
}
}
- bytes_written = metal_offsets + metal_device->mtlAncillaryArgEncoder.encodedLength;
+ bytes_written = metal_offsets + metal_device_->mtlAncillaryArgEncoder.encodedLength;
}
if (arg_buffer.storageMode == MTLStorageModeManaged) {
@@ -260,16 +490,17 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
[mtlComputeCommandEncoder setBuffer:arg_buffer offset:globals_offsets atIndex:1];
[mtlComputeCommandEncoder setBuffer:arg_buffer offset:metal_offsets atIndex:2];
- if (metal_device->use_metalrt) {
+ if (metal_device_->use_metalrt) {
if (@available(macos 12.0, *)) {
- auto bvhMetalRT = metal_device->bvhMetalRT;
+ auto bvhMetalRT = metal_device_->bvhMetalRT;
switch (kernel) {
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE:
break;
default:
bvhMetalRT = nil;
@@ -304,7 +535,7 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
/* See parallel_active_index.h for why this amount of shared memory is needed.
* Rounded up to 16 bytes for Metal */
- shared_mem_bytes = round_up((num_threads_per_block + 1) * sizeof(int), 16);
+ shared_mem_bytes = (int)round_up((num_threads_per_block + 1) * sizeof(int), 16);
[mtlComputeCommandEncoder setThreadgroupMemoryLength:shared_mem_bytes atIndex:0];
break;
@@ -318,13 +549,13 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
[mtlComputeCommandEncoder dispatchThreadgroups:size_threadgroups_per_dispatch
threadsPerThreadgroup:size_threads_per_threadgroup];
- [mtlCommandBuffer addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
+ [mtlCommandBuffer_ addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
NSString *kernel_name = metal_kernel_pso->function.label;
/* Enhanced command buffer errors are only available in 11.0+ */
if (@available(macos 11.0, *)) {
if (command_buffer.status == MTLCommandBufferStatusError && command_buffer.error != nil) {
- printf("CommandBuffer Failed: %s\n", [kernel_name UTF8String]);
+ metal_device_->set_error(string("CommandBuffer Failed: ") + [kernel_name UTF8String]);
NSArray<id<MTLCommandBufferEncoderInfo>> *encoderInfos = [command_buffer.error.userInfo
valueForKey:MTLCommandBufferEncoderInfoErrorKey];
if (encoderInfos != nil) {
@@ -338,55 +569,122 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
}
else if (command_buffer.error) {
- printf("CommandBuffer Failed: %s\n", [kernel_name UTF8String]);
+ metal_device_->set_error(string("CommandBuffer Failed: ") + [kernel_name UTF8String]);
}
}
}];
- return !(metal_device->have_error());
+ if (verbose_tracing_ || is_capturing_) {
+ /* Force a sync we've enabled step-by-step verbose tracing or if we're capturing. */
+ synchronize();
+
+ /* Show queue counters and dispatch timing. */
+ if (verbose_tracing_) {
+ if (kernel == DEVICE_KERNEL_INTEGRATOR_RESET) {
+ printf(
+ "_____________________________________.____________________.______________.___________"
+ "______________________________________\n");
+ }
+
+ printf("%-40s| %7d threads |%5.2fms | buckets [",
+ device_kernel_as_string(kernel),
+ work_size,
+ last_completion_time_ * 1000.0);
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
+ for (auto &it : metal_device_->metal_mem_map) {
+ const string c_integrator_queue_counter = "integrator_queue_counter";
+ if (it.first->name == c_integrator_queue_counter) {
+ /* Workaround "device_copy_from" being protected. */
+ struct MyDeviceMemory : device_memory {
+ void device_copy_from__IntegratorQueueCounter()
+ {
+ device_copy_from(0, data_width, 1, sizeof(IntegratorQueueCounter));
+ }
+ };
+ ((MyDeviceMemory *)it.first)->device_copy_from__IntegratorQueueCounter();
+
+ if (IntegratorQueueCounter *queue_counter = (IntegratorQueueCounter *)
+ it.first->host_pointer) {
+ for (int i = 0; i < DEVICE_KERNEL_INTEGRATOR_NUM; i++)
+ printf("%s%d", i == 0 ? "" : ",", int(queue_counter->num_queued[i]));
+ }
+ break;
+ }
+ }
+ printf("]\n");
+ }
+ }
+
+ return !(metal_device_->have_error());
}
bool MetalDeviceQueue::synchronize()
{
- if (metal_device->have_error()) {
+ if (has_captured_to_disk_ || metal_device_->have_error()) {
return false;
}
- if (mtlComputeEncoder) {
+ if (mtlComputeEncoder_) {
close_compute_encoder();
}
close_blit_encoder();
- if (mtlCommandBuffer) {
- uint64_t shared_event_id = this->shared_event_id++;
+ if (mtlCommandBuffer_) {
+ scoped_timer timer;
if (@available(macos 10.14, *)) {
- __block dispatch_semaphore_t block_sema = wait_semaphore;
- [shared_event notifyListener:shared_event_listener
- atValue:shared_event_id
- block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
- dispatch_semaphore_signal(block_sema);
- }];
+ if (timing_shared_event_) {
+ /* For per-kernel timing, add event handlers to measure & accumulate dispatch times. */
+ __block double completion_time = 0;
+ for (uint64_t i = command_buffer_start_timing_id_; i < timing_shared_event_id_; i++) {
+ [timing_shared_event_ notifyListener:shared_event_listener_
+ atValue:i
+ block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
+ completion_time = timer.get_time() - completion_time;
+ last_completion_time_ = completion_time;
+ for (auto label : command_encoder_labels_) {
+ if (label.timing_id == value) {
+ TimingStats &stat = timing_stats_[label.kernel];
+ stat.num_dispatches++;
+ stat.total_time += completion_time;
+ stat.total_work_size += label.work_size;
+ }
+ }
+ }];
+ }
+ }
+ }
- [mtlCommandBuffer encodeSignalEvent:shared_event value:shared_event_id];
- [mtlCommandBuffer commit];
- dispatch_semaphore_wait(wait_semaphore, DISPATCH_TIME_FOREVER);
+ uint64_t shared_event_id_ = this->shared_event_id_++;
+
+ if (@available(macos 10.14, *)) {
+ __block dispatch_semaphore_t block_sema = wait_semaphore_;
+ [shared_event_ notifyListener:shared_event_listener_
+ atValue:shared_event_id_
+ block:^(id<MTLSharedEvent> sharedEvent, uint64_t value) {
+ dispatch_semaphore_signal(block_sema);
+ }];
+
+ [mtlCommandBuffer_ encodeSignalEvent:shared_event_ value:shared_event_id_];
+ [mtlCommandBuffer_ commit];
+ dispatch_semaphore_wait(wait_semaphore_, DISPATCH_TIME_FOREVER);
}
- [mtlCommandBuffer release];
+ [mtlCommandBuffer_ release];
- for (const CopyBack &mmem : copy_back_mem) {
+ for (const CopyBack &mmem : copy_back_mem_) {
memcpy((uchar *)mmem.host_pointer, (uchar *)mmem.gpu_mem, mmem.size);
}
- copy_back_mem.clear();
+ copy_back_mem_.clear();
- temp_buffer_pool.process_command_buffer_completion(mtlCommandBuffer);
- metal_device->flush_delayed_free_list();
+ temp_buffer_pool_.process_command_buffer_completion(mtlCommandBuffer_);
+ metal_device_->flush_delayed_free_list();
- mtlCommandBuffer = nil;
+ mtlCommandBuffer_ = nil;
+ command_encoder_labels_.clear();
}
- return !(metal_device->have_error());
+ return !(metal_device_->have_error());
}
void MetalDeviceQueue::zero_to_device(device_memory &mem)
@@ -399,20 +697,20 @@ void MetalDeviceQueue::zero_to_device(device_memory &mem)
/* Allocate on demand. */
if (mem.device_pointer == 0) {
- metal_device->mem_alloc(mem);
+ metal_device_->mem_alloc(mem);
}
/* Zero memory on device. */
assert(mem.device_pointer != 0);
- std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
- MetalDevice::MetalMem &mmem = *metal_device->metal_mem_map.at(&mem);
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
+ MetalDevice::MetalMem &mmem = *metal_device_->metal_mem_map.at(&mem);
if (mmem.mtlBuffer) {
id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
[blitEncoder fillBuffer:mmem.mtlBuffer range:NSMakeRange(mmem.offset, mmem.size) value:0];
}
else {
- metal_device->mem_zero(mem);
+ metal_device_->mem_zero(mem);
}
}
@@ -424,15 +722,15 @@ void MetalDeviceQueue::copy_to_device(device_memory &mem)
/* Allocate on demand. */
if (mem.device_pointer == 0) {
- metal_device->mem_alloc(mem);
+ metal_device_->mem_alloc(mem);
}
assert(mem.device_pointer != 0);
assert(mem.host_pointer != nullptr);
- std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
- auto result = metal_device->metal_mem_map.find(&mem);
- if (result != metal_device->metal_mem_map.end()) {
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
+ auto result = metal_device_->metal_mem_map.find(&mem);
+ if (result != metal_device_->metal_mem_map.end()) {
if (mem.host_pointer == mem.shared_pointer) {
return;
}
@@ -440,12 +738,12 @@ void MetalDeviceQueue::copy_to_device(device_memory &mem)
MetalDevice::MetalMem &mmem = *result->second;
id<MTLBlitCommandEncoder> blitEncoder = get_blit_encoder();
- id<MTLBuffer> buffer = temp_buffer_pool.get_buffer(mtlDevice,
- mtlCommandBuffer,
- mmem.size,
- MTLResourceStorageModeShared,
- mem.host_pointer,
- stats);
+ id<MTLBuffer> buffer = temp_buffer_pool_.get_buffer(mtlDevice_,
+ mtlCommandBuffer_,
+ mmem.size,
+ MTLResourceStorageModeShared,
+ mem.host_pointer,
+ stats_);
[blitEncoder copyFromBuffer:buffer
sourceOffset:0
@@ -454,7 +752,7 @@ void MetalDeviceQueue::copy_to_device(device_memory &mem)
size:mmem.size];
}
else {
- metal_device->mem_copy_to(mem);
+ metal_device_->mem_copy_to(mem);
}
}
@@ -469,8 +767,8 @@ void MetalDeviceQueue::copy_from_device(device_memory &mem)
assert(mem.device_pointer != 0);
assert(mem.host_pointer != nullptr);
- std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
- MetalDevice::MetalMem &mmem = *metal_device->metal_mem_map.at(&mem);
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
+ MetalDevice::MetalMem &mmem = *metal_device_->metal_mem_map.at(&mem);
if (mmem.mtlBuffer) {
const size_t size = mem.memory_size();
@@ -480,8 +778,8 @@ void MetalDeviceQueue::copy_from_device(device_memory &mem)
[blitEncoder synchronizeResource:mmem.mtlBuffer];
}
if (mem.host_pointer != mmem.hostPtr) {
- if (mtlCommandBuffer) {
- copy_back_mem.push_back({mem.host_pointer, mmem.hostPtr, size});
+ if (mtlCommandBuffer_) {
+ copy_back_mem_.push_back({mem.host_pointer, mmem.hostPtr, size});
}
else {
memcpy((uchar *)mem.host_pointer, (uchar *)mmem.hostPtr, size);
@@ -493,16 +791,16 @@ void MetalDeviceQueue::copy_from_device(device_memory &mem)
}
}
else {
- metal_device->mem_copy_from(mem);
+ metal_device_->mem_copy_from(mem);
}
}
void MetalDeviceQueue::prepare_resources(DeviceKernel kernel)
{
- std::lock_guard<std::recursive_mutex> lock(metal_device->metal_mem_map_mutex);
+ std::lock_guard<std::recursive_mutex> lock(metal_device_->metal_mem_map_mutex);
/* declare resource usage */
- for (auto &it : metal_device->metal_mem_map) {
+ for (auto &it : metal_device_->metal_mem_map) {
device_memory *mem = it.first;
MTLResourceUsage usage = MTLResourceUsageRead;
@@ -512,17 +810,17 @@ void MetalDeviceQueue::prepare_resources(DeviceKernel kernel)
if (it.second->mtlBuffer) {
/* METAL_WIP - use array version (i.e. useResources) */
- [mtlComputeEncoder useResource:it.second->mtlBuffer usage:usage];
+ [mtlComputeEncoder_ useResource:it.second->mtlBuffer usage:usage];
}
else if (it.second->mtlTexture) {
/* METAL_WIP - use array version (i.e. useResources) */
- [mtlComputeEncoder useResource:it.second->mtlTexture usage:usage | MTLResourceUsageSample];
+ [mtlComputeEncoder_ useResource:it.second->mtlTexture usage:usage | MTLResourceUsageSample];
}
}
/* ancillaries */
- [mtlComputeEncoder useResource:metal_device->texture_bindings_2d usage:MTLResourceUsageRead];
- [mtlComputeEncoder useResource:metal_device->texture_bindings_3d usage:MTLResourceUsageRead];
+ [mtlComputeEncoder_ useResource:metal_device_->texture_bindings_2d usage:MTLResourceUsageRead];
+ [mtlComputeEncoder_ useResource:metal_device_->texture_bindings_3d usage:MTLResourceUsageRead];
}
id<MTLComputeCommandEncoder> MetalDeviceQueue::get_compute_encoder(DeviceKernel kernel)
@@ -530,67 +828,81 @@ id<MTLComputeCommandEncoder> MetalDeviceQueue::get_compute_encoder(DeviceKernel
bool concurrent = (kernel < DEVICE_KERNEL_INTEGRATOR_NUM);
if (@available(macos 10.14, *)) {
- if (mtlComputeEncoder) {
- if (mtlComputeEncoder.dispatchType == concurrent ? MTLDispatchTypeConcurrent :
- MTLDispatchTypeSerial) {
+ if (timing_shared_event_) {
+ /* Close the current encoder to ensure we're able to capture per-encoder timing data. */
+ if (mtlComputeEncoder_) {
+ close_compute_encoder();
+ }
+ }
+
+ if (mtlComputeEncoder_) {
+ if (mtlComputeEncoder_.dispatchType == concurrent ? MTLDispatchTypeConcurrent :
+ MTLDispatchTypeSerial) {
/* declare usage of MTLBuffers etc */
prepare_resources(kernel);
- return mtlComputeEncoder;
+ return mtlComputeEncoder_;
}
close_compute_encoder();
}
close_blit_encoder();
- if (!mtlCommandBuffer) {
- mtlCommandBuffer = [mtlCommandQueue commandBuffer];
- [mtlCommandBuffer retain];
+ if (!mtlCommandBuffer_) {
+ mtlCommandBuffer_ = [mtlCommandQueue_ commandBuffer];
+ [mtlCommandBuffer_ retain];
}
- mtlComputeEncoder = [mtlCommandBuffer
+ mtlComputeEncoder_ = [mtlCommandBuffer_
computeCommandEncoderWithDispatchType:concurrent ? MTLDispatchTypeConcurrent :
MTLDispatchTypeSerial];
- [mtlComputeEncoder setLabel:@(device_kernel_as_string(kernel))];
+ [mtlComputeEncoder_ setLabel:@(device_kernel_as_string(kernel))];
/* declare usage of MTLBuffers etc */
prepare_resources(kernel);
}
- return mtlComputeEncoder;
+ return mtlComputeEncoder_;
}
id<MTLBlitCommandEncoder> MetalDeviceQueue::get_blit_encoder()
{
- if (mtlBlitEncoder) {
- return mtlBlitEncoder;
+ if (mtlBlitEncoder_) {
+ return mtlBlitEncoder_;
}
- if (mtlComputeEncoder) {
+ if (mtlComputeEncoder_) {
close_compute_encoder();
}
- if (!mtlCommandBuffer) {
- mtlCommandBuffer = [mtlCommandQueue commandBuffer];
- [mtlCommandBuffer retain];
+ if (!mtlCommandBuffer_) {
+ mtlCommandBuffer_ = [mtlCommandQueue_ commandBuffer];
+ [mtlCommandBuffer_ retain];
+ command_buffer_start_timing_id_ = timing_shared_event_id_;
}
- mtlBlitEncoder = [mtlCommandBuffer blitCommandEncoder];
- return mtlBlitEncoder;
+ mtlBlitEncoder_ = [mtlCommandBuffer_ blitCommandEncoder];
+ return mtlBlitEncoder_;
}
void MetalDeviceQueue::close_compute_encoder()
{
- [mtlComputeEncoder endEncoding];
- mtlComputeEncoder = nil;
+ [mtlComputeEncoder_ endEncoding];
+ mtlComputeEncoder_ = nil;
+
+ if (@available(macos 10.14, *)) {
+ if (timing_shared_event_) {
+ [mtlCommandBuffer_ encodeSignalEvent:timing_shared_event_ value:timing_shared_event_id_++];
+ }
+ }
}
void MetalDeviceQueue::close_blit_encoder()
{
- if (mtlBlitEncoder) {
- [mtlBlitEncoder endEncoding];
- mtlBlitEncoder = nil;
+ if (mtlBlitEncoder_) {
+ [mtlBlitEncoder_ endEncoding];
+ mtlBlitEncoder_ = nil;
}
}
diff --git a/intern/cycles/device/metal/util.h b/intern/cycles/device/metal/util.h
index cc653ab7e12..a988d01d361 100644
--- a/intern/cycles/device/metal/util.h
+++ b/intern/cycles/device/metal/util.h
@@ -14,6 +14,8 @@
# include "util/thread.h"
+# define metal_printf VLOG(4) << string_printf
+
CCL_NAMESPACE_BEGIN
enum MetalGPUVendor {
@@ -23,10 +25,20 @@ enum MetalGPUVendor {
METAL_GPU_INTEL = 3,
};
+enum AppleGPUArchitecture {
+ APPLE_UNKNOWN,
+ APPLE_M1,
+ APPLE_M2,
+};
+
/* Contains static Metal helper functions. */
struct MetalInfo {
static vector<id<MTLDevice>> const &get_usable_devices();
- static MetalGPUVendor get_vendor_from_device_name(string const &device_name);
+ static int get_apple_gpu_core_count(id<MTLDevice> device);
+ static MetalGPUVendor get_device_vendor(id<MTLDevice> device);
+ static AppleGPUArchitecture get_apple_gpu_architecture(id<MTLDevice> device);
+ static int optimal_sort_partition_elements(id<MTLDevice> device);
+ static string get_device_name(id<MTLDevice> device);
};
/* Pool of MTLBuffers whose lifetime is linked to a single MTLCommandBuffer */
diff --git a/intern/cycles/device/metal/util.mm b/intern/cycles/device/metal/util.mm
index a6bd593bcb6..65c67c400fe 100644
--- a/intern/cycles/device/metal/util.mm
+++ b/intern/cycles/device/metal/util.mm
@@ -10,26 +10,83 @@
# include "util/string.h"
# include "util/time.h"
+# include <IOKit/IOKitLib.h>
# include <pwd.h>
# include <sys/shm.h>
# include <time.h>
CCL_NAMESPACE_BEGIN
-MetalGPUVendor MetalInfo::get_vendor_from_device_name(string const &device_name)
+string MetalInfo::get_device_name(id<MTLDevice> device)
{
- if (device_name.find("Intel") != string::npos) {
+ string device_name = [device.name UTF8String];
+ if (get_device_vendor(device) == METAL_GPU_APPLE) {
+ /* Append the GPU core count so we can distinguish between GPU variants in benchmarks. */
+ int gpu_core_count = get_apple_gpu_core_count(device);
+ device_name += string_printf(gpu_core_count ? " (GPU - %d cores)" : " (GPU)", gpu_core_count);
+ }
+ return device_name;
+}
+
+int MetalInfo::get_apple_gpu_core_count(id<MTLDevice> device)
+{
+ int core_count = 0;
+ if (@available(macos 12.0, *)) {
+ io_service_t gpu_service = IOServiceGetMatchingService(
+ kIOMainPortDefault, IORegistryEntryIDMatching(device.registryID));
+ if (CFNumberRef numberRef = (CFNumberRef)IORegistryEntryCreateCFProperty(
+ gpu_service, CFSTR("gpu-core-count"), 0, 0)) {
+ if (CFGetTypeID(numberRef) == CFNumberGetTypeID()) {
+ CFNumberGetValue(numberRef, kCFNumberSInt32Type, &core_count);
+ }
+ CFRelease(numberRef);
+ }
+ }
+ return core_count;
+}
+
+AppleGPUArchitecture MetalInfo::get_apple_gpu_architecture(id<MTLDevice> device)
+{
+ const char *device_name = [device.name UTF8String];
+ if (strstr(device_name, "M1")) {
+ return APPLE_M1;
+ }
+ else if (strstr(device_name, "M2")) {
+ return APPLE_M2;
+ }
+ return APPLE_UNKNOWN;
+}
+
+MetalGPUVendor MetalInfo::get_device_vendor(id<MTLDevice> device)
+{
+ const char *device_name = [device.name UTF8String];
+ if (strstr(device_name, "Intel")) {
return METAL_GPU_INTEL;
}
- else if (device_name.find("AMD") != string::npos) {
+ else if (strstr(device_name, "AMD")) {
return METAL_GPU_AMD;
}
- else if (device_name.find("Apple") != string::npos) {
+ else if (strstr(device_name, "Apple")) {
return METAL_GPU_APPLE;
}
return METAL_GPU_UNKNOWN;
}
+int MetalInfo::optimal_sort_partition_elements(id<MTLDevice> device)
+{
+ if (auto str = getenv("CYCLES_METAL_SORT_PARTITION_ELEMENTS")) {
+ return atoi(str);
+ }
+
+ /* On M1 and M2 GPUs, we see better cache utilization if we partition the active indices before
+ * sorting each partition by material. Partitioning into chunks of 65536 elements results in an
+ * overall render time speedup of up to 15%. */
+ if (get_device_vendor(device) == METAL_GPU_APPLE) {
+ return 65536;
+ }
+ return 0;
+}
+
vector<id<MTLDevice>> const &MetalInfo::get_usable_devices()
{
static vector<id<MTLDevice>> usable_devices;
@@ -41,9 +98,8 @@ vector<id<MTLDevice>> const &MetalInfo::get_usable_devices()
metal_printf("Usable Metal devices:\n");
for (id<MTLDevice> device in MTLCopyAllDevices()) {
- const char *device_name = [device.name UTF8String];
-
- MetalGPUVendor vendor = get_vendor_from_device_name(device_name);
+ string device_name = get_device_name(device);
+ MetalGPUVendor vendor = get_device_vendor(device);
bool usable = false;
if (@available(macos 12.2, *)) {
@@ -55,12 +111,12 @@ vector<id<MTLDevice>> const &MetalInfo::get_usable_devices()
}
if (usable) {
- metal_printf("- %s\n", device_name);
+ metal_printf("- %s\n", device_name.c_str());
[device retain];
usable_devices.push_back(device);
}
else {
- metal_printf(" (skipping \"%s\")\n", device_name);
+ metal_printf(" (skipping \"%s\")\n", device_name.c_str());
}
}
if (usable_devices.empty()) {
diff --git a/intern/cycles/device/oneapi/device.cpp b/intern/cycles/device/oneapi/device.cpp
new file mode 100644
index 00000000000..8056c204188
--- /dev/null
+++ b/intern/cycles/device/oneapi/device.cpp
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#include "device/oneapi/device.h"
+
+#include "util/log.h"
+
+#ifdef WITH_ONEAPI
+# include "device/device.h"
+# include "device/oneapi/device_impl.h"
+
+# include "util/path.h"
+# include "util/string.h"
+
+# ifdef __linux__
+# include <dlfcn.h>
+# endif
+#endif /* WITH_ONEAPI */
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef WITH_ONEAPI
+static OneAPIDLLInterface oneapi_dll;
+#endif
+
+#ifdef _WIN32
+# define LOAD_ONEAPI_SHARED_LIBRARY(path) (void *)(LoadLibrary(path))
+# define FREE_SHARED_LIBRARY(handle) FreeLibrary((HMODULE)handle)
+# define GET_SHARED_LIBRARY_SYMBOL(handle, name) GetProcAddress((HMODULE)handle, name)
+#elif __linux__
+# define LOAD_ONEAPI_SHARED_LIBRARY(path) dlopen(path, RTLD_NOW)
+# define FREE_SHARED_LIBRARY(handle) dlclose(handle)
+# define GET_SHARED_LIBRARY_SYMBOL(handle, name) dlsym(handle, name)
+#endif
+
+bool device_oneapi_init()
+{
+#if !defined(WITH_ONEAPI)
+ return false;
+#else
+
+ string lib_path = path_get("lib");
+# ifdef _WIN32
+ lib_path = path_join(lib_path, "cycles_kernel_oneapi.dll");
+# else
+ lib_path = path_join(lib_path, "cycles_kernel_oneapi.so");
+# endif
+ void *lib_handle = LOAD_ONEAPI_SHARED_LIBRARY(lib_path.c_str());
+
+ /* This shouldn't happen, but it still makes sense to have a branch for this. */
+ if (lib_handle == NULL) {
+ LOG(ERROR) << "oneAPI kernel shared library cannot be loaded for some reason. This should not "
+ "happen, however, it occurs hence oneAPI rendering will be disabled";
+ return false;
+ }
+
+# define DLL_INTERFACE_CALL(function, return_type, ...) \
+ (oneapi_dll.function) = reinterpret_cast<decltype(oneapi_dll.function)>( \
+ GET_SHARED_LIBRARY_SYMBOL(lib_handle, #function)); \
+ if (oneapi_dll.function == NULL) { \
+ LOG(ERROR) << "oneAPI shared library function \"" << #function \
+ << "\" has not been loaded from kernel shared - disable oneAPI " \
+ "library disable oneAPI implementation due to this"; \
+ FREE_SHARED_LIBRARY(lib_handle); \
+ return false; \
+ }
+# include "kernel/device/oneapi/dll_interface_template.h"
+# undef DLL_INTERFACE_CALL
+
+ VLOG_INFO << "oneAPI kernel shared library has been loaded successfully";
+
+ /* We need to have this oneapi kernel shared library during all life-span of the Blender.
+ * So it is not unloaded because of this.
+ * FREE_SHARED_LIBRARY(lib_handle); */
+
+ /* NOTE(@nsirgien): we need to enable JIT cache from here and
+ * right now this cache policy is controlled by env. variables. */
+ /* NOTE(hallade) we also disable use of copy engine as it
+ * improves stability as of intel/LLVM SYCL-nightly/20220529.
+ * All these env variable can be set beforehand by end-users and
+ * will in that case -not- be overwritten. */
+# ifdef _WIN32
+ if (getenv("SYCL_CACHE_PERSISTENT") == nullptr) {
+ _putenv_s("SYCL_CACHE_PERSISTENT", "1");
+ }
+ if (getenv("SYCL_CACHE_TRESHOLD") == nullptr) {
+ _putenv_s("SYCL_CACHE_THRESHOLD", "0");
+ }
+ if (getenv("SYCL_DEVICE_FILTER") == nullptr) {
+ _putenv_s("SYCL_DEVICE_FILTER", "host,level_zero");
+ }
+ if (getenv("SYCL_ENABLE_PCI") == nullptr) {
+ _putenv_s("SYCL_ENABLE_PCI", "1");
+ }
+ if (getenv("SYCL_PI_LEVEL_ZERO_USE_COPY_ENGINE_FOR_IN_ORDER_QUEUE") == nullptr) {
+ _putenv_s("SYCL_PI_LEVEL_ZERO_USE_COPY_ENGINE_FOR_IN_ORDER_QUEUE", "0");
+ }
+# elif __linux__
+ setenv("SYCL_CACHE_PERSISTENT", "1", false);
+ setenv("SYCL_CACHE_THRESHOLD", "0", false);
+ setenv("SYCL_DEVICE_FILTER", "host,level_zero", false);
+ setenv("SYCL_ENABLE_PCI", "1", false);
+ setenv("SYCL_PI_LEVEL_ZERO_USE_COPY_ENGINE_FOR_IN_ORDER_QUEUE", "0", false);
+# endif
+
+ return true;
+#endif
+}
+
+#if defined(_WIN32) || defined(__linux__)
+# undef LOAD_SYCL_SHARED_LIBRARY
+# undef LOAD_ONEAPI_SHARED_LIBRARY
+# undef FREE_SHARED_LIBRARY
+# undef GET_SHARED_LIBRARY_SYMBOL
+#endif
+
+Device *device_oneapi_create(const DeviceInfo &info, Stats &stats, Profiler &profiler)
+{
+#ifdef WITH_ONEAPI
+ return new OneapiDevice(info, oneapi_dll, stats, profiler);
+#else
+ (void)info;
+ (void)stats;
+ (void)profiler;
+
+ LOG(FATAL) << "Requested to create oneAPI device while not enabled for this build.";
+
+ return nullptr;
+#endif
+}
+
+#ifdef WITH_ONEAPI
+static void device_iterator_cb(const char *id, const char *name, int num, void *user_ptr)
+{
+ vector<DeviceInfo> *devices = (vector<DeviceInfo> *)user_ptr;
+
+ DeviceInfo info;
+
+ info.type = DEVICE_ONEAPI;
+ info.description = name;
+ info.num = num;
+
+ /* NOTE(@nsirgien): Should be unique at least on proper oneapi installation. */
+ info.id = id;
+
+ info.has_nanovdb = true;
+ info.denoisers = 0;
+
+ info.has_gpu_queue = true;
+
+ /* NOTE(@nsirgien): oneAPI right now is focused on one device usage. In future it maybe will
+ * change, but right now peer access from one device to another device is not supported. */
+ info.has_peer_memory = false;
+
+ /* NOTE(@nsirgien): Seems not possible to know from SYCL/oneAPI or Level0. */
+ info.display_device = false;
+
+ devices->push_back(info);
+ VLOG_INFO << "Added device \"" << name << "\" with id \"" << info.id << "\".";
+}
+#endif
+
+void device_oneapi_info(vector<DeviceInfo> &devices)
+{
+#ifdef WITH_ONEAPI
+ (oneapi_dll.oneapi_iterate_devices)(device_iterator_cb, &devices);
+#else /* WITH_ONEAPI */
+ (void)devices;
+#endif /* WITH_ONEAPI */
+}
+
+string device_oneapi_capabilities()
+{
+ string capabilities;
+#ifdef WITH_ONEAPI
+ char *c_capabilities = (oneapi_dll.oneapi_device_capabilities)();
+ if (c_capabilities) {
+ capabilities = c_capabilities;
+ (oneapi_dll.oneapi_free)(c_capabilities);
+ }
+#endif
+ return capabilities;
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/oneapi/device.h b/intern/cycles/device/oneapi/device.h
new file mode 100644
index 00000000000..db8c985d4d5
--- /dev/null
+++ b/intern/cycles/device/oneapi/device.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#pragma once
+
+#include "util/string.h"
+#include "util/vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+class Device;
+class DeviceInfo;
+class Profiler;
+class Stats;
+
+bool device_oneapi_init();
+
+Device *device_oneapi_create(const DeviceInfo &info, Stats &stats, Profiler &profiler);
+
+void device_oneapi_info(vector<DeviceInfo> &devices);
+
+string device_oneapi_capabilities();
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp
new file mode 100644
index 00000000000..0c0afd1d2df
--- /dev/null
+++ b/intern/cycles/device/oneapi/device_impl.cpp
@@ -0,0 +1,426 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#ifdef WITH_ONEAPI
+
+# include "device/oneapi/device_impl.h"
+
+# include "util/debug.h"
+# include "util/log.h"
+
+# include "kernel/device/oneapi/kernel.h"
+
+CCL_NAMESPACE_BEGIN
+
+static void queue_error_cb(const char *message, void *user_ptr)
+{
+ if (user_ptr) {
+ *reinterpret_cast<std::string *>(user_ptr) = message;
+ }
+}
+
+OneapiDevice::OneapiDevice(const DeviceInfo &info,
+ OneAPIDLLInterface &oneapi_dll_object,
+ Stats &stats,
+ Profiler &profiler)
+ : Device(info, stats, profiler),
+ device_queue_(nullptr),
+ texture_info_(this, "texture_info", MEM_GLOBAL),
+ kg_memory_(nullptr),
+ kg_memory_device_(nullptr),
+ kg_memory_size_(0),
+ oneapi_dll_(oneapi_dll_object)
+{
+ need_texture_info_ = false;
+
+ oneapi_dll_.oneapi_set_error_cb(queue_error_cb, &oneapi_error_string_);
+
+ /* OneAPI calls should be initialized on this moment. */
+ assert(oneapi_dll_.oneapi_create_queue != nullptr);
+
+ bool is_finished_ok = oneapi_dll_.oneapi_create_queue(device_queue_, info.num);
+ if (is_finished_ok == false) {
+ set_error("oneAPI queue initialization error: got runtime exception \"" +
+ oneapi_error_string_ + "\"");
+ }
+ else {
+ VLOG_DEBUG << "oneAPI queue has been successfully created for the device \""
+ << info.description << "\"";
+ assert(device_queue_);
+ }
+
+ size_t globals_segment_size;
+ is_finished_ok = oneapi_dll_.oneapi_kernel_globals_size(device_queue_, globals_segment_size);
+ if (is_finished_ok == false) {
+ set_error("oneAPI constant memory initialization got runtime exception \"" +
+ oneapi_error_string_ + "\"");
+ }
+ else {
+ VLOG_DEBUG << "Successfully created global/constant memory segment (kernel globals object)";
+ }
+
+ kg_memory_ = oneapi_dll_.oneapi_usm_aligned_alloc_host(device_queue_, globals_segment_size, 16);
+ oneapi_dll_.oneapi_usm_memset(device_queue_, kg_memory_, 0, globals_segment_size);
+
+ kg_memory_device_ = oneapi_dll_.oneapi_usm_alloc_device(device_queue_, globals_segment_size);
+
+ kg_memory_size_ = globals_segment_size;
+}
+
+OneapiDevice::~OneapiDevice()
+{
+ texture_info_.free();
+ oneapi_dll_.oneapi_usm_free(device_queue_, kg_memory_);
+ oneapi_dll_.oneapi_usm_free(device_queue_, kg_memory_device_);
+
+ for (ConstMemMap::iterator mt = const_mem_map_.begin(); mt != const_mem_map_.end(); mt++)
+ delete mt->second;
+
+ if (device_queue_)
+ oneapi_dll_.oneapi_free_queue(device_queue_);
+}
+
+bool OneapiDevice::check_peer_access(Device * /*peer_device*/)
+{
+ return false;
+}
+
+BVHLayoutMask OneapiDevice::get_bvh_layout_mask() const
+{
+ return BVH_LAYOUT_BVH2;
+}
+
+bool OneapiDevice::load_kernels(const uint requested_features)
+{
+ assert(device_queue_);
+ /* NOTE(@nsirgien): oneAPI can support compilation of kernel code with certain feature set
+ * with specialization constants, but it hasn't been implemented yet. */
+ (void)requested_features;
+
+ bool is_finished_ok = oneapi_dll_.oneapi_run_test_kernel(device_queue_);
+ if (is_finished_ok == false) {
+ set_error("oneAPI kernel load: got runtime exception \"" + oneapi_error_string_ + "\"");
+ }
+ else {
+ VLOG_INFO << "Runtime compilation done for \"" << info.description << "\"";
+ assert(device_queue_);
+ }
+ return is_finished_ok;
+}
+
+void OneapiDevice::load_texture_info()
+{
+ if (need_texture_info_) {
+ need_texture_info_ = false;
+ texture_info_.copy_to_device();
+ }
+}
+
+void OneapiDevice::generic_alloc(device_memory &mem)
+{
+ size_t memory_size = mem.memory_size();
+
+ /* TODO(@nsirgien): In future, if scene doesn't fit into device memory, then
+ * we can use USM host memory.
+ * Because of the expected performance impact, implementation of this has had a low priority
+ * and is not implemented yet. */
+
+ assert(device_queue_);
+ /* NOTE(@nsirgien): There are three types of Unified Shared Memory (USM) in oneAPI: host, device
+ * and shared. For new project it maybe more beneficial to use USM shared memory, because it
+ * provides automatic migration mechanism in order to allow to use the same pointer on host and
+ * on device, without need to worry about explicit memory transfer operations. But for
+ * Blender/Cycles this type of memory is not very suitable in current application architecture,
+ * because Cycles already uses two different pointer for host activity and device activity, and
+ * also has to perform all needed memory transfer operations. So, USM device memory
+ * type has been used for oneAPI device in order to better fit in Cycles architecture. */
+ void *device_pointer = oneapi_dll_.oneapi_usm_alloc_device(device_queue_, memory_size);
+ if (device_pointer == nullptr) {
+ size_t max_memory_on_device = oneapi_dll_.oneapi_get_memcapacity(device_queue_);
+ set_error("oneAPI kernel - device memory allocation error for " +
+ string_human_readable_size(mem.memory_size()) +
+ ", possibly caused by lack of available memory space on the device: " +
+ string_human_readable_size(stats.mem_used) + " of " +
+ string_human_readable_size(max_memory_on_device) + " is already allocated");
+ return;
+ }
+ assert(device_pointer);
+
+ mem.device_pointer = reinterpret_cast<ccl::device_ptr>(device_pointer);
+ mem.device_size = memory_size;
+
+ stats.mem_alloc(memory_size);
+}
+
+void OneapiDevice::generic_copy_to(device_memory &mem)
+{
+ size_t memory_size = mem.memory_size();
+
+ /* Copy operation from host shouldn't be requested if there is no memory allocated on host. */
+ assert(mem.host_pointer);
+ assert(device_queue_);
+ oneapi_dll_.oneapi_usm_memcpy(
+ device_queue_, (void *)mem.device_pointer, (void *)mem.host_pointer, memory_size);
+}
+
+/* TODO: Make sycl::queue part of OneapiQueue and avoid using pointers to sycl::queue. */
+SyclQueue *OneapiDevice::sycl_queue()
+{
+ return device_queue_;
+}
+
+string OneapiDevice::oneapi_error_message()
+{
+ return string(oneapi_error_string_);
+}
+
+OneAPIDLLInterface OneapiDevice::oneapi_dll_object()
+{
+ return oneapi_dll_;
+}
+
+void *OneapiDevice::kernel_globals_device_pointer()
+{
+ return kg_memory_device_;
+}
+
+void OneapiDevice::generic_free(device_memory &mem)
+{
+ assert(mem.device_pointer);
+ stats.mem_free(mem.device_size);
+ mem.device_size = 0;
+
+ assert(device_queue_);
+ oneapi_dll_.oneapi_usm_free(device_queue_, (void *)mem.device_pointer);
+ mem.device_pointer = 0;
+}
+
+void OneapiDevice::mem_alloc(device_memory &mem)
+{
+ if (mem.type == MEM_TEXTURE) {
+ assert(!"mem_alloc not supported for textures.");
+ }
+ else if (mem.type == MEM_GLOBAL) {
+ assert(!"mem_alloc not supported for global memory.");
+ }
+ else {
+ if (mem.name) {
+ VLOG_DEBUG << "OneapiDevice::mem_alloc: \"" << mem.name << "\", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+ }
+ generic_alloc(mem);
+ }
+}
+
+void OneapiDevice::mem_copy_to(device_memory &mem)
+{
+ if (mem.name) {
+ VLOG_DEBUG << "OneapiDevice::mem_copy_to: \"" << mem.name << "\", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")";
+ }
+
+ if (mem.type == MEM_GLOBAL) {
+ global_free(mem);
+ global_alloc(mem);
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free((device_texture &)mem);
+ tex_alloc((device_texture &)mem);
+ }
+ else {
+ if (!mem.device_pointer)
+ mem_alloc(mem);
+
+ generic_copy_to(mem);
+ }
+}
+
+void OneapiDevice::mem_copy_from(device_memory &mem, size_t y, size_t w, size_t h, size_t elem)
+{
+ if (mem.type == MEM_TEXTURE || mem.type == MEM_GLOBAL) {
+ assert(!"mem_copy_from not supported for textures.");
+ }
+ else if (mem.host_pointer) {
+ const size_t size = (w > 0 || h > 0 || elem > 0) ? (elem * w * h) : mem.memory_size();
+ const size_t offset = elem * y * w;
+
+ if (mem.name) {
+ VLOG_DEBUG << "OneapiDevice::mem_copy_from: \"" << mem.name << "\" object of "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ") from offset " << offset
+ << " data " << size << " bytes";
+ }
+
+ assert(device_queue_);
+
+ assert(size != 0);
+ assert(mem.device_pointer);
+ char *shifted_host = reinterpret_cast<char *>(mem.host_pointer) + offset;
+ char *shifted_device = reinterpret_cast<char *>(mem.device_pointer) + offset;
+ bool is_finished_ok = oneapi_dll_.oneapi_usm_memcpy(
+ device_queue_, shifted_host, shifted_device, size);
+ if (is_finished_ok == false) {
+ set_error("oneAPI memory operation error: got runtime exception \"" + oneapi_error_string_ +
+ "\"");
+ }
+ }
+}
+
+void OneapiDevice::mem_zero(device_memory &mem)
+{
+ if (mem.name) {
+ VLOG_DEBUG << "OneapiDevice::mem_zero: \"" << mem.name << "\", "
+ << string_human_readable_number(mem.memory_size()) << " bytes. ("
+ << string_human_readable_size(mem.memory_size()) << ")\n";
+ }
+
+ if (!mem.device_pointer) {
+ mem_alloc(mem);
+ }
+ if (!mem.device_pointer) {
+ return;
+ }
+
+ assert(device_queue_);
+ bool is_finished_ok = oneapi_dll_.oneapi_usm_memset(
+ device_queue_, (void *)mem.device_pointer, 0, mem.memory_size());
+ if (is_finished_ok == false) {
+ set_error("oneAPI memory operation error: got runtime exception \"" + oneapi_error_string_ +
+ "\"");
+ }
+}
+
+void OneapiDevice::mem_free(device_memory &mem)
+{
+ if (mem.name) {
+ VLOG_DEBUG << "OneapiDevice::mem_free: \"" << mem.name << "\", "
+ << string_human_readable_number(mem.device_size) << " bytes. ("
+ << string_human_readable_size(mem.device_size) << ")\n";
+ }
+
+ if (mem.type == MEM_GLOBAL) {
+ global_free(mem);
+ }
+ else if (mem.type == MEM_TEXTURE) {
+ tex_free((device_texture &)mem);
+ }
+ else {
+ generic_free(mem);
+ }
+}
+
+device_ptr OneapiDevice::mem_alloc_sub_ptr(device_memory &mem, size_t offset, size_t /*size*/)
+{
+ return reinterpret_cast<device_ptr>(reinterpret_cast<char *>(mem.device_pointer) +
+ mem.memory_elements_size(offset));
+}
+
+void OneapiDevice::const_copy_to(const char *name, void *host, size_t size)
+{
+ assert(name);
+
+ VLOG_DEBUG << "OneapiDevice::const_copy_to \"" << name << "\" object "
+ << string_human_readable_number(size) << " bytes. ("
+ << string_human_readable_size(size) << ")";
+
+ ConstMemMap::iterator i = const_mem_map_.find(name);
+ device_vector<uchar> *data;
+
+ if (i == const_mem_map_.end()) {
+ data = new device_vector<uchar>(this, name, MEM_READ_ONLY);
+ data->alloc(size);
+ const_mem_map_.insert(ConstMemMap::value_type(name, data));
+ }
+ else {
+ data = i->second;
+ }
+
+ assert(data->memory_size() <= size);
+ memcpy(data->data(), host, size);
+ data->copy_to_device();
+
+ oneapi_dll_.oneapi_set_global_memory(
+ device_queue_, kg_memory_, name, (void *)data->device_pointer);
+
+ oneapi_dll_.oneapi_usm_memcpy(device_queue_, kg_memory_device_, kg_memory_, kg_memory_size_);
+}
+
+void OneapiDevice::global_alloc(device_memory &mem)
+{
+ assert(mem.name);
+
+ size_t size = mem.memory_size();
+ VLOG_DEBUG << "OneapiDevice::global_alloc \"" << mem.name << "\" object "
+ << string_human_readable_number(size) << " bytes. ("
+ << string_human_readable_size(size) << ")";
+
+ generic_alloc(mem);
+ generic_copy_to(mem);
+
+ oneapi_dll_.oneapi_set_global_memory(
+ device_queue_, kg_memory_, mem.name, (void *)mem.device_pointer);
+
+ oneapi_dll_.oneapi_usm_memcpy(device_queue_, kg_memory_device_, kg_memory_, kg_memory_size_);
+}
+
+void OneapiDevice::global_free(device_memory &mem)
+{
+ if (mem.device_pointer) {
+ generic_free(mem);
+ }
+}
+
+void OneapiDevice::tex_alloc(device_texture &mem)
+{
+ generic_alloc(mem);
+ generic_copy_to(mem);
+
+ /* Resize if needed. Also, in case of resize - allocate in advance for future allocs. */
+ const uint slot = mem.slot;
+ if (slot >= texture_info_.size()) {
+ texture_info_.resize(slot + 128);
+ }
+
+ texture_info_[slot] = mem.info;
+ need_texture_info_ = true;
+
+ texture_info_[slot].data = (uint64_t)mem.device_pointer;
+}
+
+void OneapiDevice::tex_free(device_texture &mem)
+{
+ /* There is no texture memory in SYCL. */
+ if (mem.device_pointer) {
+ generic_free(mem);
+ }
+}
+
+unique_ptr<DeviceQueue> OneapiDevice::gpu_queue_create()
+{
+ return make_unique<OneapiDeviceQueue>(this);
+}
+
+bool OneapiDevice::should_use_graphics_interop()
+{
+ /* NOTE(@nsirgien): oneAPI doesn't yet support direct writing into graphics API objects, so
+ * return false. */
+ return false;
+}
+
+void *OneapiDevice::usm_aligned_alloc_host(size_t memory_size, size_t alignment)
+{
+ assert(device_queue_);
+ return oneapi_dll_.oneapi_usm_aligned_alloc_host(device_queue_, memory_size, alignment);
+}
+
+void OneapiDevice::usm_free(void *usm_ptr)
+{
+ assert(device_queue_);
+ return oneapi_dll_.oneapi_usm_free(device_queue_, usm_ptr);
+}
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/oneapi/device_impl.h b/intern/cycles/device/oneapi/device_impl.h
new file mode 100644
index 00000000000..f925687ebe9
--- /dev/null
+++ b/intern/cycles/device/oneapi/device_impl.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#ifdef WITH_ONEAPI
+
+# include "device/device.h"
+# include "device/oneapi/device.h"
+# include "device/oneapi/queue.h"
+
+# include "util/map.h"
+
+CCL_NAMESPACE_BEGIN
+
+class DeviceQueue;
+
+class OneapiDevice : public Device {
+ private:
+ SyclQueue *device_queue_;
+
+ using ConstMemMap = map<string, device_vector<uchar> *>;
+ ConstMemMap const_mem_map_;
+ device_vector<TextureInfo> texture_info_;
+ bool need_texture_info_;
+ void *kg_memory_;
+ void *kg_memory_device_;
+ size_t kg_memory_size_ = (size_t)0;
+ OneAPIDLLInterface oneapi_dll_;
+ std::string oneapi_error_string_;
+
+ public:
+ virtual BVHLayoutMask get_bvh_layout_mask() const override;
+
+ OneapiDevice(const DeviceInfo &info,
+ OneAPIDLLInterface &oneapi_dll_object,
+ Stats &stats,
+ Profiler &profiler);
+
+ virtual ~OneapiDevice();
+
+ bool check_peer_access(Device *peer_device) override;
+
+ bool load_kernels(const uint requested_features) override;
+
+ void load_texture_info();
+
+ void generic_alloc(device_memory &mem);
+
+ void generic_copy_to(device_memory &mem);
+
+ void generic_free(device_memory &mem);
+
+ SyclQueue *sycl_queue();
+
+ string oneapi_error_message();
+
+ OneAPIDLLInterface oneapi_dll_object();
+
+ void *kernel_globals_device_pointer();
+
+ void mem_alloc(device_memory &mem) override;
+
+ void mem_copy_to(device_memory &mem) override;
+
+ void mem_copy_from(device_memory &mem, size_t y, size_t w, size_t h, size_t elem) override;
+
+ void mem_copy_from(device_memory &mem)
+ {
+ mem_copy_from(mem, 0, 0, 0, 0);
+ }
+
+ void mem_zero(device_memory &mem) override;
+
+ void mem_free(device_memory &mem) override;
+
+ device_ptr mem_alloc_sub_ptr(device_memory &mem, size_t offset, size_t /*size*/) override;
+
+ virtual void const_copy_to(const char *name, void *host, size_t size) override;
+
+ void global_alloc(device_memory &mem);
+
+ void global_free(device_memory &mem);
+
+ void tex_alloc(device_texture &mem);
+
+ void tex_free(device_texture &mem);
+
+ /* Graphics resources interoperability. */
+ virtual bool should_use_graphics_interop() override;
+
+ virtual unique_ptr<DeviceQueue> gpu_queue_create() override;
+
+ /* NOTE(@nsirgien): Create this methods to avoid some compilation problems on Windows with host
+ * side compilation (MSVC). */
+ void *usm_aligned_alloc_host(size_t memory_size, size_t alignment);
+ void usm_free(void *usm_ptr);
+};
+
+CCL_NAMESPACE_END
+
+#endif
diff --git a/intern/cycles/device/oneapi/dll_interface.h b/intern/cycles/device/oneapi/dll_interface.h
new file mode 100644
index 00000000000..0a888194e98
--- /dev/null
+++ b/intern/cycles/device/oneapi/dll_interface.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#pragma once
+
+/* Include kernel header to get access to SYCL-specific types, like SyclQueue and
+ * OneAPIDeviceIteratorCallback. */
+#include "kernel/device/oneapi/kernel.h"
+
+#ifdef WITH_ONEAPI
+struct OneAPIDLLInterface {
+# define DLL_INTERFACE_CALL(function, return_type, ...) \
+ return_type (*function)(__VA_ARGS__) = nullptr;
+# include "kernel/device/oneapi/dll_interface_template.h"
+# undef DLL_INTERFACE_CALL
+};
+#endif
diff --git a/intern/cycles/device/oneapi/queue.cpp b/intern/cycles/device/oneapi/queue.cpp
new file mode 100644
index 00000000000..42e2408ee7a
--- /dev/null
+++ b/intern/cycles/device/oneapi/queue.cpp
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#ifdef WITH_ONEAPI
+
+# include "device/oneapi/queue.h"
+# include "device/oneapi/device_impl.h"
+# include "util/log.h"
+# include "util/time.h"
+# include <iomanip>
+# include <vector>
+
+# include "kernel/device/oneapi/kernel.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct KernelExecutionInfo {
+ double elapsed_summary = 0.0;
+ int enqueue_count = 0;
+};
+
+/* OneapiDeviceQueue */
+
+OneapiDeviceQueue::OneapiDeviceQueue(OneapiDevice *device)
+ : DeviceQueue(device),
+ oneapi_device_(device),
+ oneapi_dll_(device->oneapi_dll_object()),
+ kernel_context_(nullptr)
+{
+}
+
+OneapiDeviceQueue::~OneapiDeviceQueue()
+{
+ delete kernel_context_;
+}
+
+int OneapiDeviceQueue::num_concurrent_states(const size_t state_size) const
+{
+ int num_states;
+
+ /* TODO: implement and use get_num_multiprocessors and get_max_num_threads_per_multiprocessor. */
+ const size_t compute_units = oneapi_dll_.oneapi_get_compute_units_amount(
+ oneapi_device_->sycl_queue());
+ if (compute_units >= 128) {
+ /* dGPU path, make sense to allocate more states, because it will be dedicated GPU memory. */
+ int base = 1024 * 1024;
+ /* linear dependency (with coefficient less that 1) from amount of compute units. */
+ num_states = (base * (compute_units / 128)) * 3 / 4;
+
+ /* Limit amount of integrator states by one quarter of device memory, because
+ * other allocations will need some space as well
+ * TODO: base this calculation on the how many states what the GPU is actually capable of
+ * running, with some headroom to improve occupancy. If the texture don't fit, offload into
+ * unified memory. */
+ size_t states_memory_size = num_states * state_size;
+ size_t device_memory_amount =
+ (oneapi_dll_.oneapi_get_memcapacity)(oneapi_device_->sycl_queue());
+ if (states_memory_size >= device_memory_amount / 4) {
+ num_states = device_memory_amount / 4 / state_size;
+ }
+ }
+ else {
+ /* iGPU path - no real need to allocate a lot of integrator states because it is shared GPU
+ * memory. */
+ num_states = 1024 * 512;
+ }
+
+ VLOG_DEVICE_STATS << "GPU queue concurrent states: " << num_states << ", using up to "
+ << string_human_readable_size(num_states * state_size);
+
+ return num_states;
+}
+
+int OneapiDeviceQueue::num_concurrent_busy_states() const
+{
+ const size_t compute_units = oneapi_dll_.oneapi_get_compute_units_amount(
+ oneapi_device_->sycl_queue());
+ if (compute_units >= 128) {
+ return 1024 * 1024;
+ }
+ else {
+ return 1024 * 512;
+ }
+}
+
+void OneapiDeviceQueue::init_execution()
+{
+ oneapi_device_->load_texture_info();
+
+ SyclQueue *device_queue = oneapi_device_->sycl_queue();
+ void *kg_dptr = (void *)oneapi_device_->kernel_globals_device_pointer();
+ assert(device_queue);
+ assert(kg_dptr);
+ kernel_context_ = new KernelContext{device_queue, kg_dptr};
+
+ debug_init_execution();
+}
+
+bool OneapiDeviceQueue::enqueue(DeviceKernel kernel,
+ const int signed_kernel_work_size,
+ DeviceKernelArguments const &_args)
+{
+ if (oneapi_device_->have_error()) {
+ return false;
+ }
+
+ void **args = const_cast<void **>(_args.values);
+
+ debug_enqueue(kernel, signed_kernel_work_size);
+ assert(signed_kernel_work_size >= 0);
+ size_t kernel_work_size = (size_t)signed_kernel_work_size;
+
+ size_t kernel_local_size = oneapi_dll_.oneapi_kernel_preferred_local_size(
+ kernel_context_->queue, (::DeviceKernel)kernel, kernel_work_size);
+ size_t uniformed_kernel_work_size = round_up(kernel_work_size, kernel_local_size);
+
+ assert(kernel_context_);
+
+ /* Call the oneAPI kernel DLL to launch the requested kernel. */
+ bool is_finished_ok = oneapi_dll_.oneapi_enqueue_kernel(
+ kernel_context_, kernel, uniformed_kernel_work_size, args);
+
+ if (is_finished_ok == false) {
+ oneapi_device_->set_error("oneAPI kernel \"" + std::string(device_kernel_as_string(kernel)) +
+ "\" execution error: got runtime exception \"" +
+ oneapi_device_->oneapi_error_message() + "\"");
+ }
+
+ return is_finished_ok;
+}
+
+bool OneapiDeviceQueue::synchronize()
+{
+ if (oneapi_device_->have_error()) {
+ return false;
+ }
+
+ bool is_finished_ok = oneapi_dll_.oneapi_queue_synchronize(oneapi_device_->sycl_queue());
+ if (is_finished_ok == false)
+ oneapi_device_->set_error("oneAPI unknown kernel execution error: got runtime exception \"" +
+ oneapi_device_->oneapi_error_message() + "\"");
+
+ debug_synchronize();
+
+ return !(oneapi_device_->have_error());
+}
+
+void OneapiDeviceQueue::zero_to_device(device_memory &mem)
+{
+ oneapi_device_->mem_zero(mem);
+}
+
+void OneapiDeviceQueue::copy_to_device(device_memory &mem)
+{
+ oneapi_device_->mem_copy_to(mem);
+}
+
+void OneapiDeviceQueue::copy_from_device(device_memory &mem)
+{
+ oneapi_device_->mem_copy_from(mem);
+}
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_ONEAPI */
diff --git a/intern/cycles/device/oneapi/queue.h b/intern/cycles/device/oneapi/queue.h
new file mode 100644
index 00000000000..716cbfdc88c
--- /dev/null
+++ b/intern/cycles/device/oneapi/queue.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#pragma once
+
+#ifdef WITH_ONEAPI
+
+# include "device/kernel.h"
+# include "device/memory.h"
+# include "device/queue.h"
+
+# include "device/oneapi/device.h"
+# include "device/oneapi/dll_interface.h"
+
+CCL_NAMESPACE_BEGIN
+
+class OneapiDevice;
+class device_memory;
+
+/* Base class for OneAPI queues. */
+class OneapiDeviceQueue : public DeviceQueue {
+ public:
+ explicit OneapiDeviceQueue(OneapiDevice *device);
+ ~OneapiDeviceQueue();
+
+ virtual int num_concurrent_states(const size_t state_size) const override;
+
+ virtual int num_concurrent_busy_states() const override;
+
+ virtual void init_execution() override;
+
+ virtual bool enqueue(DeviceKernel kernel,
+ const int kernel_work_size,
+ DeviceKernelArguments const &args) override;
+
+ virtual bool synchronize() override;
+
+ virtual void zero_to_device(device_memory &mem) override;
+ virtual void copy_to_device(device_memory &mem) override;
+ virtual void copy_from_device(device_memory &mem) override;
+
+ protected:
+ OneapiDevice *oneapi_device_;
+ OneAPIDLLInterface oneapi_dll_;
+ KernelContext *kernel_context_;
+ bool with_kernel_statistics_;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* WITH_ONEAPI */
diff --git a/intern/cycles/device/optix/device.cpp b/intern/cycles/device/optix/device.cpp
index 70810bae10d..68ca21374fd 100644
--- a/intern/cycles/device/optix/device.cpp
+++ b/intern/cycles/device/optix/device.cpp
@@ -31,12 +31,12 @@ bool device_optix_init()
const OptixResult result = optixInit();
if (result == OPTIX_ERROR_UNSUPPORTED_ABI_VERSION) {
- VLOG(1) << "OptiX initialization failed because the installed NVIDIA driver is too old. "
- "Please update to the latest driver first!";
+ VLOG_WARNING << "OptiX initialization failed because the installed NVIDIA driver is too old. "
+ "Please update to the latest driver first!";
return false;
}
else if (result != OPTIX_SUCCESS) {
- VLOG(1) << "OptiX initialization failed with error code " << (unsigned int)result;
+ VLOG_WARNING << "OptiX initialization failed with error code " << (unsigned int)result;
return false;
}
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index 9fc265bc327..11c0d1bf8a0 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -246,7 +246,7 @@ OptiXDevice::Denoiser::Denoiser(OptiXDevice *device)
OptiXDevice::OptiXDevice(const DeviceInfo &info, Stats &stats, Profiler &profiler)
: CUDADevice(info, stats, profiler),
sbt_data(this, "__sbt", MEM_READ_ONLY),
- launch_params(this, "__params", false),
+ launch_params(this, "kernel_params", false),
denoiser_(this)
{
/* Make the CUDA context current. */
@@ -278,7 +278,7 @@ OptiXDevice::OptiXDevice(const DeviceInfo &info, Stats &stats, Profiler &profile
};
# endif
if (DebugFlags().optix.use_debug) {
- VLOG(1) << "Using OptiX debug mode.";
+ VLOG_INFO << "Using OptiX debug mode.";
options.validationMode = OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL;
}
optix_assert(optixDeviceContextCreate(cuContext, &options, &context));
@@ -421,7 +421,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
pipeline_options.numPayloadValues = 8;
pipeline_options.numAttributeValues = 2; /* u, v */
pipeline_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE;
- pipeline_options.pipelineLaunchParamsVariableName = "__params"; /* See globals.h */
+ pipeline_options.pipelineLaunchParamsVariableName = "kernel_params"; /* See globals.h */
pipeline_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE;
if (kernel_features & KERNEL_FEATURE_HAIR) {
@@ -452,9 +452,10 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
}
{ /* Load and compile PTX module with OptiX kernels. */
- string ptx_data, ptx_filename = path_get((kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) ?
- "lib/kernel_optix_shader_raytrace.ptx" :
- "lib/kernel_optix.ptx");
+ string ptx_data, ptx_filename = path_get(
+ (kernel_features & (KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_MNEE)) ?
+ "lib/kernel_optix_shader_raytrace.ptx" :
+ "lib/kernel_optix.ptx");
if (use_adaptive_compilation() || path_file_size(ptx_filename) == -1) {
if (!getenv("OPTIX_ROOT_DIR")) {
set_error(
@@ -464,7 +465,9 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
}
ptx_filename = compile_kernel(
kernel_features,
- (kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) ? "kernel_shader_raytrace" : "kernel",
+ (kernel_features & (KERNEL_FEATURE_NODE_RAYTRACE | KERNEL_FEATURE_MNEE)) ?
+ "kernel_shader_raytrace" :
+ "kernel",
"optix",
true);
}
@@ -550,7 +553,8 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
OptixBuiltinISOptions builtin_options = {};
# if OPTIX_ABI_VERSION >= 55
builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM;
- builtin_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE;
+ builtin_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE |
+ OPTIX_BUILD_FLAG_ALLOW_COMPACTION;
builtin_options.curveEndcapFlags = OPTIX_CURVE_ENDCAP_DEFAULT; /* Disable end-caps. */
# else
builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
@@ -620,6 +624,14 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
"__direct_callable__svm_node_bevel";
}
+ /* MNEE. */
+ if (kernel_features & KERNEL_FEATURE_MNEE) {
+ group_descs[PG_RGEN_SHADE_SURFACE_MNEE].kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN;
+ group_descs[PG_RGEN_SHADE_SURFACE_MNEE].raygen.module = optix_module;
+ group_descs[PG_RGEN_SHADE_SURFACE_MNEE].raygen.entryFunctionName =
+ "__raygen__kernel_optix_integrator_shade_surface_mnee";
+ }
+
optix_assert(optixProgramGroupCreate(
context, group_descs, NUM_PROGRAM_GROUPS, &group_options, nullptr, 0, groups));
@@ -701,6 +713,46 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
pipelines[PIP_SHADE_RAYTRACE], 0, dss, css, motion_blur ? 3 : 2));
}
+ if (kernel_features & KERNEL_FEATURE_MNEE) {
+ /* Create MNEE pipeline. */
+ vector<OptixProgramGroup> pipeline_groups;
+ pipeline_groups.reserve(NUM_PROGRAM_GROUPS);
+ pipeline_groups.push_back(groups[PG_RGEN_SHADE_SURFACE_MNEE]);
+ pipeline_groups.push_back(groups[PG_MISS]);
+ pipeline_groups.push_back(groups[PG_HITD]);
+ pipeline_groups.push_back(groups[PG_HITS]);
+ pipeline_groups.push_back(groups[PG_HITL]);
+ pipeline_groups.push_back(groups[PG_HITV]);
+ if (motion_blur) {
+ pipeline_groups.push_back(groups[PG_HITD_MOTION]);
+ pipeline_groups.push_back(groups[PG_HITS_MOTION]);
+ }
+ if (kernel_features & KERNEL_FEATURE_POINTCLOUD) {
+ pipeline_groups.push_back(groups[PG_HITD_POINTCLOUD]);
+ pipeline_groups.push_back(groups[PG_HITS_POINTCLOUD]);
+ }
+ pipeline_groups.push_back(groups[PG_CALL_SVM_AO]);
+ pipeline_groups.push_back(groups[PG_CALL_SVM_BEVEL]);
+
+ optix_assert(optixPipelineCreate(context,
+ &pipeline_options,
+ &link_options,
+ pipeline_groups.data(),
+ pipeline_groups.size(),
+ nullptr,
+ 0,
+ &pipelines[PIP_SHADE_MNEE]));
+
+ /* Combine ray generation and trace continuation stack size. */
+ const unsigned int css = stack_size[PG_RGEN_SHADE_SURFACE_MNEE].cssRG +
+ link_options.maxTraceDepth * trace_css;
+ const unsigned int dss = 0;
+
+ /* Set stack size depending on pipeline options. */
+ optix_assert(
+ optixPipelineSetStackSize(pipelines[PIP_SHADE_MNEE], 0, dss, css, motion_blur ? 3 : 2));
+ }
+
{ /* Create intersection-only pipeline. */
vector<OptixProgramGroup> pipeline_groups;
pipeline_groups.reserve(NUM_PROGRAM_GROUPS);
@@ -1186,7 +1238,7 @@ bool OptiXDevice::denoise_configure_if_needed(DenoiseContext &context)
const OptixResult result = optixDenoiserSetup(
denoiser_.optix_denoiser,
0, /* Work around bug in r495 drivers that causes artifacts when denoiser setup is called
- on a stream that is not the default stream */
+ * on a stream that is not the default stream. */
tile_size.x + denoiser_.sizes.overlapWindowSizeInPixels * 2,
tile_size.y + denoiser_.sizes.overlapWindowSizeInPixels * 2,
denoiser_.state.device_pointer,
@@ -1336,12 +1388,15 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
OptixAccelBufferSizes sizes = {};
OptixAccelBuildOptions options = {};
options.operation = operation;
- if (use_fast_trace_bvh) {
- VLOG(2) << "Using fast to trace OptiX BVH";
+ if (use_fast_trace_bvh ||
+ /* The build flags have to match the ones used to query the built-in curve intersection
+ program (see optixBuiltinISModuleGet above) */
+ build_input.type == OPTIX_BUILD_INPUT_TYPE_CURVES) {
+ VLOG_INFO << "Using fast to trace OptiX BVH";
options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE | OPTIX_BUILD_FLAG_ALLOW_COMPACTION;
}
else {
- VLOG(2) << "Using fast to update OptiX BVH";
+ VLOG_INFO << "Using fast to update OptiX BVH";
options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_BUILD | OPTIX_BUILD_FLAG_ALLOW_UPDATE;
}
@@ -1861,7 +1916,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
{
/* Can disable __anyhit__kernel_optix_visibility_test by default (except for thick curves,
* since it needs to filter out end-caps there).
-
+ *
* It is enabled where necessary (visibility mask exceeds 8 bits or the other any-hit
* programs like __anyhit__kernel_optix_shadow_all_hit) via OPTIX_RAY_FLAG_ENFORCE_ANYHIT.
*/
@@ -1987,26 +2042,26 @@ void OptiXDevice::const_copy_to(const char *name, void *host, size_t size)
/* Set constant memory for CUDA module. */
CUDADevice::const_copy_to(name, host, size);
- if (strcmp(name, "__data") == 0) {
+ if (strcmp(name, "data") == 0) {
assert(size <= sizeof(KernelData));
/* Update traversable handle (since it is different for each device on multi devices). */
KernelData *const data = (KernelData *)host;
- *(OptixTraversableHandle *)&data->bvh.scene = tlas_handle;
+ *(OptixTraversableHandle *)&data->device_bvh = tlas_handle;
update_launch_params(offsetof(KernelParamsOptiX, data), host, size);
return;
}
/* Update data storage pointers in launch parameters. */
-# define KERNEL_TEX(data_type, tex_name) \
- if (strcmp(name, #tex_name) == 0) { \
- update_launch_params(offsetof(KernelParamsOptiX, tex_name), host, size); \
+# define KERNEL_DATA_ARRAY(data_type, data_name) \
+ if (strcmp(name, #data_name) == 0) { \
+ update_launch_params(offsetof(KernelParamsOptiX, data_name), host, size); \
return; \
}
- KERNEL_TEX(IntegratorStateGPU, __integrator_state)
-# include "kernel/textures.h"
-# undef KERNEL_TEX
+ KERNEL_DATA_ARRAY(IntegratorStateGPU, integrator_state)
+# include "kernel/data_arrays.h"
+# undef KERNEL_DATA_ARRAY
}
void OptiXDevice::update_launch_params(size_t offset, void *data, size_t data_size)
diff --git a/intern/cycles/device/optix/device_impl.h b/intern/cycles/device/optix/device_impl.h
index 1f53c729c3f..817afdc8384 100644
--- a/intern/cycles/device/optix/device_impl.h
+++ b/intern/cycles/device/optix/device_impl.h
@@ -24,6 +24,7 @@ enum {
PG_RGEN_INTERSECT_SUBSURFACE,
PG_RGEN_INTERSECT_VOLUME_STACK,
PG_RGEN_SHADE_SURFACE_RAYTRACE,
+ PG_RGEN_SHADE_SURFACE_MNEE,
PG_MISS,
PG_HITD, /* Default hit group. */
PG_HITS, /* __SHADOW_RECORD_ALL__ hit group. */
@@ -46,7 +47,7 @@ static const int CALLABLE_PROGRAM_GROUPS_BASE = PG_CALL_SVM_AO;
static const int NUM_CALLABLE_PROGRAM_GROUPS = 2;
/* List of OptiX pipelines. */
-enum { PIP_SHADE_RAYTRACE, PIP_INTERSECT, NUM_PIPELINES };
+enum { PIP_SHADE_RAYTRACE, PIP_SHADE_MNEE, PIP_INTERSECT, NUM_PIPELINES };
/* A single shader binding table entry. */
struct SbtRecord {
diff --git a/intern/cycles/device/optix/queue.cpp b/intern/cycles/device/optix/queue.cpp
index d635512c58a..366bf95269d 100644
--- a/intern/cycles/device/optix/queue.cpp
+++ b/intern/cycles/device/optix/queue.cpp
@@ -28,6 +28,7 @@ void OptiXDeviceQueue::init_execution()
static bool is_optix_specific_kernel(DeviceKernel kernel)
{
return (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE ||
kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW ||
kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE ||
@@ -63,7 +64,8 @@ bool OptiXDeviceQueue::enqueue(DeviceKernel kernel,
cuda_stream_));
if (kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
- kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE) {
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE) {
cuda_device_assert(
cuda_device_,
cuMemcpyHtoDAsync(launch_params_ptr + offsetof(KernelParamsOptiX, render_buffer),
@@ -82,6 +84,10 @@ bool OptiXDeviceQueue::enqueue(DeviceKernel kernel,
pipeline = optix_device->pipelines[PIP_SHADE_RAYTRACE];
sbt_params.raygenRecord = sbt_data_ptr + PG_RGEN_SHADE_SURFACE_RAYTRACE * sizeof(SbtRecord);
break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE:
+ pipeline = optix_device->pipelines[PIP_SHADE_MNEE];
+ sbt_params.raygenRecord = sbt_data_ptr + PG_RGEN_SHADE_SURFACE_MNEE * sizeof(SbtRecord);
+ break;
case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
pipeline = optix_device->pipelines[PIP_INTERSECT];
sbt_params.raygenRecord = sbt_data_ptr + PG_RGEN_INTERSECT_CLOSEST * sizeof(SbtRecord);
diff --git a/intern/cycles/device/queue.cpp b/intern/cycles/device/queue.cpp
index de65047ed6a..cc0cf0ccf84 100644
--- a/intern/cycles/device/queue.cpp
+++ b/intern/cycles/device/queue.cpp
@@ -19,7 +19,7 @@ DeviceQueue::DeviceQueue(Device *device)
DeviceQueue::~DeviceQueue()
{
- if (VLOG_IS_ON(3)) {
+ if (VLOG_DEVICE_STATS_IS_ON) {
/* Print kernel execution times sorted by time. */
vector<pair<DeviceKernelMask, double>> stats_sorted;
for (const auto &stat : stats_kernel_time_) {
@@ -32,17 +32,18 @@ DeviceQueue::~DeviceQueue()
return a.second > b.second;
});
- VLOG(3) << "GPU queue stats:";
+ VLOG_DEVICE_STATS << "GPU queue stats:";
for (const auto &[mask, time] : stats_sorted) {
- VLOG(3) << " " << std::setfill(' ') << std::setw(10) << std::fixed << std::setprecision(5)
- << std::right << time << "s: " << device_kernel_mask_as_string(mask);
+ VLOG_DEVICE_STATS << " " << std::setfill(' ') << std::setw(10) << std::fixed
+ << std::setprecision(5) << std::right << time
+ << "s: " << device_kernel_mask_as_string(mask);
}
}
}
void DeviceQueue::debug_init_execution()
{
- if (VLOG_IS_ON(3)) {
+ if (VLOG_DEVICE_STATS_IS_ON) {
last_sync_time_ = time_dt();
}
@@ -51,9 +52,9 @@ void DeviceQueue::debug_init_execution()
void DeviceQueue::debug_enqueue(DeviceKernel kernel, const int work_size)
{
- if (VLOG_IS_ON(3)) {
- VLOG(4) << "GPU queue launch " << device_kernel_as_string(kernel) << ", work_size "
- << work_size;
+ if (VLOG_DEVICE_STATS_IS_ON) {
+ VLOG_DEVICE_STATS << "GPU queue launch " << device_kernel_as_string(kernel) << ", work_size "
+ << work_size;
}
last_kernels_enqueued_ |= (uint64_t(1) << (uint64_t)kernel);
@@ -61,10 +62,10 @@ void DeviceQueue::debug_enqueue(DeviceKernel kernel, const int work_size)
void DeviceQueue::debug_synchronize()
{
- if (VLOG_IS_ON(3)) {
+ if (VLOG_DEVICE_STATS_IS_ON) {
const double new_time = time_dt();
const double elapsed_time = new_time - last_sync_time_;
- VLOG(4) << "GPU queue synchronize, elapsed " << std::setw(10) << elapsed_time << "s";
+ VLOG_DEVICE_STATS << "GPU queue synchronize, elapsed " << std::setw(10) << elapsed_time << "s";
stats_kernel_time_[last_kernels_enqueued_] += elapsed_time;
diff --git a/intern/cycles/device/queue.h b/intern/cycles/device/queue.h
index 14a5db3a204..808431af401 100644
--- a/intern/cycles/device/queue.h
+++ b/intern/cycles/device/queue.h
@@ -105,6 +105,13 @@ class DeviceQueue {
* value. */
virtual int num_concurrent_busy_states() const = 0;
+ /* Number of elements in a partition of sorted shaders, that improves memory locality of
+ * integrator state fetch at the cost of decreased coherence for shader kernel execution. */
+ virtual int num_sort_partition_elements() const
+ {
+ return 65536;
+ }
+
/* Initialize execution of kernels on this queue.
*
* Will, for example, load all data required by the kernels from Device to global or path state.
diff --git a/intern/cycles/hydra/display_driver.cpp b/intern/cycles/hydra/display_driver.cpp
index a809ace63e2..0c0b577c358 100644
--- a/intern/cycles/hydra/display_driver.cpp
+++ b/intern/cycles/hydra/display_driver.cpp
@@ -23,10 +23,18 @@ HdCyclesDisplayDriver::HdCyclesDisplayDriver(HdCyclesSession *renderParam, Hgi *
HdCyclesDisplayDriver::~HdCyclesDisplayDriver()
{
- deinit();
+ if (texture_) {
+ _hgi->DestroyTexture(&texture_);
+ }
+
+ if (gl_pbo_id_) {
+ glDeleteBuffers(1, &gl_pbo_id_);
+ }
+
+ gl_context_dispose();
}
-void HdCyclesDisplayDriver::init()
+void HdCyclesDisplayDriver::gl_context_create()
{
#ifdef _WIN32
if (!gl_context_) {
@@ -64,16 +72,42 @@ void HdCyclesDisplayDriver::init()
}
}
-void HdCyclesDisplayDriver::deinit()
+bool HdCyclesDisplayDriver::gl_context_enable()
{
- if (texture_) {
- _hgi->DestroyTexture(&texture_);
+#ifdef _WIN32
+ if (!hdc_ || !gl_context_) {
+ return false;
}
- if (gl_pbo_id_) {
- glDeleteBuffers(1, &gl_pbo_id_);
+ mutex_.lock();
+
+ // Do not change context if this is called in the main thread
+ if (wglGetCurrentContext() == nullptr) {
+ if (!TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_))) {
+ mutex_.unlock();
+ return false;
+ }
+ }
+
+ return true;
+#else
+ return false;
+#endif
+}
+
+void HdCyclesDisplayDriver::gl_context_disable()
+{
+#ifdef _WIN32
+ if (wglGetCurrentContext() == gl_context_) {
+ TF_VERIFY(wglMakeCurrent(nullptr, nullptr));
}
+ mutex_.unlock();
+#endif
+}
+
+void HdCyclesDisplayDriver::gl_context_dispose()
+{
#ifdef _WIN32
if (gl_context_) {
TF_VERIFY(wglDeleteContext((HGLRC)gl_context_));
@@ -90,13 +124,9 @@ bool HdCyclesDisplayDriver::update_begin(const Params &params,
int texture_width,
int texture_height)
{
-#ifdef _WIN32
- if (!hdc_ || !gl_context_) {
+ if (!gl_context_enable()) {
return false;
}
-#endif
-
- graphics_interop_activate();
if (gl_render_sync_) {
glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
@@ -121,15 +151,14 @@ bool HdCyclesDisplayDriver::update_begin(const Params &params,
void HdCyclesDisplayDriver::update_end()
{
gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-
glFlush();
- graphics_interop_deactivate();
+ gl_context_disable();
}
void HdCyclesDisplayDriver::flush()
{
- graphics_interop_activate();
+ gl_context_enable();
if (gl_upload_sync_) {
glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
@@ -139,7 +168,7 @@ void HdCyclesDisplayDriver::flush()
glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
}
- graphics_interop_deactivate();
+ gl_context_disable();
}
half4 *HdCyclesDisplayDriver::map_texture_buffer()
@@ -179,25 +208,12 @@ DisplayDriver::GraphicsInterop HdCyclesDisplayDriver::graphics_interop_get()
void HdCyclesDisplayDriver::graphics_interop_activate()
{
- mutex_.lock();
-
-#ifdef _WIN32
- // Do not change context if this is called in the main thread
- if (wglGetCurrentContext() == nullptr) {
- TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_));
- }
-#endif
+ gl_context_enable();
}
void HdCyclesDisplayDriver::graphics_interop_deactivate()
{
-#ifdef _WIN32
- if (wglGetCurrentContext() == gl_context_) {
- TF_VERIFY(wglMakeCurrent(nullptr, nullptr));
- }
-#endif
-
- mutex_.unlock();
+ gl_context_disable();
}
void HdCyclesDisplayDriver::clear()
@@ -214,7 +230,11 @@ void HdCyclesDisplayDriver::draw(const Params &params)
return;
}
- init();
+ if (!renderBuffer->IsResourceUsed()) {
+ return;
+ }
+
+ gl_context_create();
// Cycles 'DisplayDriver' only supports 'half4' format
TF_VERIFY(renderBuffer->GetFormat() == HdFormatFloat16Vec4);
@@ -255,7 +275,6 @@ void HdCyclesDisplayDriver::draw(const Params &params)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-
glFlush();
need_update_ = false;
diff --git a/intern/cycles/hydra/display_driver.h b/intern/cycles/hydra/display_driver.h
index 20086830e6a..2a05397c325 100644
--- a/intern/cycles/hydra/display_driver.h
+++ b/intern/cycles/hydra/display_driver.h
@@ -19,9 +19,6 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver {
~HdCyclesDisplayDriver();
private:
- void init();
- void deinit();
-
void next_tile_begin() override;
bool update_begin(const Params &params, int texture_width, int texture_height) override;
@@ -41,6 +38,11 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver {
void draw(const Params &params) override;
+ void gl_context_create();
+ bool gl_context_enable();
+ void gl_context_disable();
+ void gl_context_dispose();
+
HdCyclesSession *const _renderParam;
Hgi *const _hgi;
@@ -48,7 +50,6 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver {
void *hdc_ = nullptr;
void *gl_context_ = nullptr;
#endif
-
CCL_NS::thread_mutex mutex_;
PXR_NS::HgiTextureHandle texture_;
diff --git a/intern/cycles/hydra/output_driver.cpp b/intern/cycles/hydra/output_driver.cpp
index c5f64ac1c18..f4ea853f243 100644
--- a/intern/cycles/hydra/output_driver.cpp
+++ b/intern/cycles/hydra/output_driver.cpp
@@ -30,11 +30,11 @@ bool HdCyclesOutputDriver::update_render_tile(const Tile &tile)
std::vector<float> pixels;
for (const HdRenderPassAovBinding &aovBinding : _renderParam->GetAovBindings()) {
- if (aovBinding == _renderParam->GetDisplayAovBinding()) {
- continue; // Display AOV binding is already updated by Cycles display driver
- }
-
if (const auto renderBuffer = static_cast<HdCyclesRenderBuffer *>(aovBinding.renderBuffer)) {
+ if (aovBinding == _renderParam->GetDisplayAovBinding() && renderBuffer->IsResourceUsed()) {
+ continue; // Display AOV binding is already updated by Cycles display driver
+ }
+
const HdFormat format = renderBuffer->GetFormat();
if (format == HdFormatInvalid) {
continue; // Skip invalid AOV bindings
diff --git a/intern/cycles/hydra/render_buffer.cpp b/intern/cycles/hydra/render_buffer.cpp
index 4867def0624..4d8b21d1e61 100644
--- a/intern/cycles/hydra/render_buffer.cpp
+++ b/intern/cycles/hydra/render_buffer.cpp
@@ -35,7 +35,7 @@ bool HdCyclesRenderBuffer::Allocate(const GfVec3i &dimensions, HdFormat format,
return false;
}
- const size_t oldSize = _data.size();
+ const size_t oldSize = _dataSize;
const size_t newSize = dimensions[0] * dimensions[1] * HdDataSizeOfFormat(format);
if (oldSize == newSize) {
return true;
@@ -49,8 +49,8 @@ bool HdCyclesRenderBuffer::Allocate(const GfVec3i &dimensions, HdFormat format,
_width = dimensions[0];
_height = dimensions[1];
_format = format;
-
- _data.resize(newSize);
+ _dataSize = newSize;
+ _resourceUsed = false;
return true;
}
@@ -63,6 +63,7 @@ void HdCyclesRenderBuffer::_Deallocate()
_data.clear();
_data.shrink_to_fit();
+ _dataSize = 0;
_resource = VtValue();
}
@@ -74,6 +75,10 @@ void *HdCyclesRenderBuffer::Map()
return nullptr;
}
+ if (_data.size() != _dataSize) {
+ _data.resize(_dataSize);
+ }
+
++_mapped;
return _data.data();
@@ -103,10 +108,17 @@ void HdCyclesRenderBuffer::SetConverged(bool converged)
_converged = converged;
}
+bool HdCyclesRenderBuffer::IsResourceUsed() const
+{
+ return _resourceUsed;
+}
+
VtValue HdCyclesRenderBuffer::GetResource(bool multiSampled) const
{
TF_UNUSED(multiSampled);
+ _resourceUsed = true;
+
return _resource;
}
diff --git a/intern/cycles/hydra/render_buffer.h b/intern/cycles/hydra/render_buffer.h
index 8eb874f0068..90629d4aee0 100644
--- a/intern/cycles/hydra/render_buffer.h
+++ b/intern/cycles/hydra/render_buffer.h
@@ -58,6 +58,8 @@ class HdCyclesRenderBuffer final : public PXR_NS::HdRenderBuffer {
void SetConverged(bool converged);
+ bool IsResourceUsed() const;
+
PXR_NS::VtValue GetResource(bool multiSampled = false) const override;
void SetResource(const PXR_NS::VtValue &resource);
@@ -74,9 +76,11 @@ class HdCyclesRenderBuffer final : public PXR_NS::HdRenderBuffer {
unsigned int _width = 0u;
unsigned int _height = 0u;
PXR_NS::HdFormat _format = PXR_NS::HdFormatInvalid;
+ size_t _dataSize = 0;
std::vector<uint8_t> _data;
PXR_NS::VtValue _resource;
+ mutable std::atomic_bool _resourceUsed = false;
std::atomic_int _mapped = 0;
std::atomic_bool _converged = false;
diff --git a/intern/cycles/integrator/denoiser.cpp b/intern/cycles/integrator/denoiser.cpp
index 23ab825a4d2..94991d63e4c 100644
--- a/intern/cycles/integrator/denoiser.cpp
+++ b/intern/cycles/integrator/denoiser.cpp
@@ -58,8 +58,8 @@ bool Denoiser::load_kernels(Progress *progress)
return false;
}
- VLOG(3) << "Will denoise on " << denoiser_device->info.description << " ("
- << denoiser_device->info.id << ")";
+ VLOG_WORK << "Will denoise on " << denoiser_device->info.description << " ("
+ << denoiser_device->info.id << ")";
return true;
}
diff --git a/intern/cycles/integrator/denoiser_device.cpp b/intern/cycles/integrator/denoiser_device.cpp
index 595397312b3..5414f9dfb1a 100644
--- a/intern/cycles/integrator/denoiser_device.cpp
+++ b/intern/cycles/integrator/denoiser_device.cpp
@@ -48,7 +48,7 @@ bool DeviceDenoiser::denoise_buffer(const BufferParams &buffer_params,
task.render_buffers = render_buffers;
}
else {
- VLOG(3) << "Creating temporary buffer on denoiser device.";
+ VLOG_WORK << "Creating temporary buffer on denoiser device.";
DeviceQueue *queue = denoiser_device->get_denoise_queue();
diff --git a/intern/cycles/integrator/denoiser_oidn.cpp b/intern/cycles/integrator/denoiser_oidn.cpp
index b074408e229..04e659a15e2 100644
--- a/intern/cycles/integrator/denoiser_oidn.cpp
+++ b/intern/cycles/integrator/denoiser_oidn.cpp
@@ -284,8 +284,8 @@ class OIDNDenoiseContext {
/* Read pass pixels using PassAccessor into a temporary buffer which is owned by the pass.. */
void read_pass_pixels_into_buffer(OIDNPass &oidn_pass)
{
- VLOG(3) << "Allocating temporary buffer for pass " << oidn_pass.name << " ("
- << pass_type_as_string(oidn_pass.type) << ")";
+ VLOG_WORK << "Allocating temporary buffer for pass " << oidn_pass.name << " ("
+ << pass_type_as_string(oidn_pass.type) << ")";
const int64_t width = buffer_params_.width;
const int64_t height = buffer_params_.height;
diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp
index 36a0326e405..ed278821b46 100644
--- a/intern/cycles/integrator/path_trace.cpp
+++ b/intern/cycles/integrator/path_trace.cpp
@@ -348,8 +348,8 @@ void PathTrace::path_trace(RenderWork &render_work)
return;
}
- VLOG(3) << "Will path trace " << render_work.path_trace.num_samples
- << " samples at the resolution divider " << render_work.resolution_divider;
+ VLOG_WORK << "Will path trace " << render_work.path_trace.num_samples
+ << " samples at the resolution divider " << render_work.resolution_divider;
const double start_time = time_dt();
@@ -373,9 +373,9 @@ void PathTrace::path_trace(RenderWork &render_work)
work_balance_infos_[i].time_spent += work_time;
work_balance_infos_[i].occupancy = statistics.occupancy;
- VLOG(3) << "Rendered " << num_samples << " samples in " << work_time << " seconds ("
- << work_time / num_samples
- << " seconds per sample), occupancy: " << statistics.occupancy;
+ VLOG_INFO << "Rendered " << num_samples << " samples in " << work_time << " seconds ("
+ << work_time / num_samples
+ << " seconds per sample), occupancy: " << statistics.occupancy;
});
float occupancy_accum = 0.0f;
@@ -398,10 +398,10 @@ void PathTrace::adaptive_sample(RenderWork &render_work)
bool did_reschedule_on_idle = false;
while (true) {
- VLOG(3) << "Will filter adaptive stopping buffer, threshold "
- << render_work.adaptive_sampling.threshold;
+ VLOG_WORK << "Will filter adaptive stopping buffer, threshold "
+ << render_work.adaptive_sampling.threshold;
if (render_work.adaptive_sampling.reset) {
- VLOG(3) << "Will re-calculate convergency flag for currently converged pixels.";
+ VLOG_WORK << "Will re-calculate convergency flag for currently converged pixels.";
}
const double start_time = time_dt();
@@ -420,11 +420,11 @@ void PathTrace::adaptive_sample(RenderWork &render_work)
render_work, time_dt() - start_time, is_cancel_requested());
if (num_active_pixels == 0) {
- VLOG(3) << "All pixels converged.";
+ VLOG_WORK << "All pixels converged.";
if (!render_scheduler_.render_work_reschedule_on_converge(render_work)) {
break;
}
- VLOG(3) << "Continuing with lower threshold.";
+ VLOG_WORK << "Continuing with lower threshold.";
}
else if (did_reschedule_on_idle) {
break;
@@ -436,10 +436,10 @@ void PathTrace::adaptive_sample(RenderWork &render_work)
* A better heuristic is possible here: for example, use maximum of 128^2 and percentage of
* the final resolution. */
if (!render_scheduler_.render_work_reschedule_on_idle(render_work)) {
- VLOG(3) << "Rescheduling is not possible: final threshold is reached.";
+ VLOG_WORK << "Rescheduling is not possible: final threshold is reached.";
break;
}
- VLOG(3) << "Rescheduling lower threshold.";
+ VLOG_WORK << "Rescheduling lower threshold.";
did_reschedule_on_idle = true;
}
else {
@@ -483,7 +483,7 @@ void PathTrace::cryptomatte_postprocess(const RenderWork &render_work)
if (!render_work.cryptomatte.postprocess) {
return;
}
- VLOG(3) << "Perform cryptomatte work.";
+ VLOG_WORK << "Perform cryptomatte work.";
parallel_for_each(path_trace_works_, [&](unique_ptr<PathTraceWork> &path_trace_work) {
path_trace_work->cryptomatte_postproces();
@@ -501,7 +501,7 @@ void PathTrace::denoise(const RenderWork &render_work)
return;
}
- VLOG(3) << "Perform denoising work.";
+ VLOG_WORK << "Perform denoising work.";
const double start_time = time_dt();
@@ -599,26 +599,26 @@ void PathTrace::update_display(const RenderWork &render_work)
}
if (!display_ && !output_driver_) {
- VLOG(3) << "Ignore display update.";
+ VLOG_WORK << "Ignore display update.";
return;
}
if (full_params_.width == 0 || full_params_.height == 0) {
- VLOG(3) << "Skipping PathTraceDisplay update due to 0 size of the render buffer.";
+ VLOG_WORK << "Skipping PathTraceDisplay update due to 0 size of the render buffer.";
return;
}
const double start_time = time_dt();
if (output_driver_) {
- VLOG(3) << "Invoke buffer update callback.";
+ VLOG_WORK << "Invoke buffer update callback.";
PathTraceTile tile(*this);
output_driver_->update_render_tile(tile);
}
if (display_) {
- VLOG(3) << "Perform copy to GPUDisplay work.";
+ VLOG_WORK << "Perform copy to GPUDisplay work.";
const int texture_width = render_state_.effective_big_tile_params.window_width;
const int texture_height = render_state_.effective_big_tile_params.window_height;
@@ -654,33 +654,33 @@ void PathTrace::rebalance(const RenderWork &render_work)
const int num_works = path_trace_works_.size();
if (num_works == 1) {
- VLOG(3) << "Ignoring rebalance work due to single device render.";
+ VLOG_WORK << "Ignoring rebalance work due to single device render.";
return;
}
const double start_time = time_dt();
if (VLOG_IS_ON(3)) {
- VLOG(3) << "Perform rebalance work.";
- VLOG(3) << "Per-device path tracing time (seconds):";
+ VLOG_WORK << "Perform rebalance work.";
+ VLOG_WORK << "Per-device path tracing time (seconds):";
for (int i = 0; i < num_works; ++i) {
- VLOG(3) << path_trace_works_[i]->get_device()->info.description << ": "
- << work_balance_infos_[i].time_spent;
+ VLOG_WORK << path_trace_works_[i]->get_device()->info.description << ": "
+ << work_balance_infos_[i].time_spent;
}
}
const bool did_rebalance = work_balance_do_rebalance(work_balance_infos_);
if (VLOG_IS_ON(3)) {
- VLOG(3) << "Calculated per-device weights for works:";
+ VLOG_WORK << "Calculated per-device weights for works:";
for (int i = 0; i < num_works; ++i) {
- VLOG(3) << path_trace_works_[i]->get_device()->info.description << ": "
- << work_balance_infos_[i].weight;
+ VLOG_WORK << path_trace_works_[i]->get_device()->info.description << ": "
+ << work_balance_infos_[i].weight;
}
}
if (!did_rebalance) {
- VLOG(3) << "Balance in path trace works did not change.";
+ VLOG_WORK << "Balance in path trace works did not change.";
render_scheduler_.report_rebalance_time(render_work, time_dt() - start_time, false);
return;
}
@@ -704,7 +704,7 @@ void PathTrace::write_tile_buffer(const RenderWork &render_work)
return;
}
- VLOG(3) << "Write tile result.";
+ VLOG_WORK << "Write tile result.";
render_state_.tile_written = true;
@@ -718,14 +718,14 @@ void PathTrace::write_tile_buffer(const RenderWork &render_work)
*
* Important thing is: tile should be written to the software via callback only once. */
if (!has_multiple_tiles) {
- VLOG(3) << "Write tile result via buffer write callback.";
+ VLOG_WORK << "Write tile result via buffer write callback.";
tile_buffer_write();
}
/* Write tile to disk, so that the render work's render buffer can be re-used for the next tile.
*/
if (has_multiple_tiles) {
- VLOG(3) << "Write tile result into .";
+ VLOG_WORK << "Write tile result into .";
tile_buffer_write_to_disk();
}
}
@@ -736,10 +736,10 @@ void PathTrace::finalize_full_buffer_on_disk(const RenderWork &render_work)
return;
}
- VLOG(3) << "Handle full-frame render buffer work.";
+ VLOG_WORK << "Handle full-frame render buffer work.";
if (!tile_manager_.has_written_tiles()) {
- VLOG(3) << "No tiles on disk.";
+ VLOG_WORK << "No tiles on disk.";
return;
}
@@ -935,7 +935,7 @@ static string get_layer_view_name(const RenderBuffers &buffers)
void PathTrace::process_full_buffer_from_disk(string_view filename)
{
- VLOG(3) << "Processing full frame buffer file " << filename;
+ VLOG_WORK << "Processing full frame buffer file " << filename;
progress_set_status("Reading full buffer from disk");
@@ -1103,6 +1103,8 @@ static const char *device_type_for_description(const DeviceType type)
return "OptiX";
case DEVICE_HIP:
return "HIP";
+ case DEVICE_ONEAPI:
+ return "oneAPI";
case DEVICE_DUMMY:
return "Dummy";
case DEVICE_MULTI:
diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp
index 8306460d607..fa313f6460a 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_gpu.cpp
@@ -65,6 +65,8 @@ PathTraceWorkGPU::PathTraceWorkGPU(Device *device,
integrator_shader_sort_counter_(device, "integrator_shader_sort_counter", MEM_READ_WRITE),
integrator_shader_raytrace_sort_counter_(
device, "integrator_shader_raytrace_sort_counter", MEM_READ_WRITE),
+ integrator_shader_mnee_sort_counter_(
+ device, "integrator_shader_mnee_sort_counter", MEM_READ_WRITE),
integrator_shader_sort_prefix_sum_(
device, "integrator_shader_sort_prefix_sum", MEM_READ_WRITE),
integrator_next_main_path_index_(device, "integrator_next_main_path_index", MEM_READ_WRITE),
@@ -150,7 +152,7 @@ void PathTraceWorkGPU::alloc_integrator_soa()
total_soa_size += soa_memory->memory_size();
}
- VLOG(3) << "GPU SoA state size: " << string_human_readable_size(total_soa_size);
+ VLOG_DEVICE_STATS << "GPU SoA state size: " << string_human_readable_size(total_soa_size);
}
}
@@ -179,22 +181,45 @@ void PathTraceWorkGPU::alloc_integrator_queue()
void PathTraceWorkGPU::alloc_integrator_sorting()
{
+ /* Compute sort partitions, to balance between memory locality and coherence.
+ * Sort partitioning becomes less effective when more shaders are in the wavefront. In lieu of a
+ * more sophisticated heuristic we simply disable sort partitioning if the shader count is high.
+ */
+ num_sort_partitions_ = 1;
+ if (device_scene_->data.max_shaders < 300) {
+ const int num_elements = queue_->num_sort_partition_elements();
+ if (num_elements) {
+ num_sort_partitions_ = max(max_num_paths_ / num_elements, 1);
+ }
+ }
+
+ integrator_state_gpu_.sort_partition_divisor = (int)divide_up(max_num_paths_,
+ num_sort_partitions_);
+
/* Allocate arrays for shader sorting. */
- const int max_shaders = device_scene_->data.max_shaders;
- if (integrator_shader_sort_counter_.size() < max_shaders) {
- integrator_shader_sort_counter_.alloc(max_shaders);
+ const int sort_buckets = device_scene_->data.max_shaders * num_sort_partitions_;
+ if (integrator_shader_sort_counter_.size() < sort_buckets) {
+ integrator_shader_sort_counter_.alloc(sort_buckets);
integrator_shader_sort_counter_.zero_to_device();
+ integrator_state_gpu_.sort_key_counter[DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE] =
+ (int *)integrator_shader_sort_counter_.device_pointer;
- integrator_shader_raytrace_sort_counter_.alloc(max_shaders);
- integrator_shader_raytrace_sort_counter_.zero_to_device();
+ if (device_scene_->data.kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) {
+ integrator_shader_raytrace_sort_counter_.alloc(sort_buckets);
+ integrator_shader_raytrace_sort_counter_.zero_to_device();
+ integrator_state_gpu_.sort_key_counter[DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE] =
+ (int *)integrator_shader_raytrace_sort_counter_.device_pointer;
+ }
- integrator_shader_sort_prefix_sum_.alloc(max_shaders);
- integrator_shader_sort_prefix_sum_.zero_to_device();
+ if (device_scene_->data.kernel_features & KERNEL_FEATURE_MNEE) {
+ integrator_shader_mnee_sort_counter_.alloc(sort_buckets);
+ integrator_shader_mnee_sort_counter_.zero_to_device();
+ integrator_state_gpu_.sort_key_counter[DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE] =
+ (int *)integrator_shader_mnee_sort_counter_.device_pointer;
+ }
- integrator_state_gpu_.sort_key_counter[DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE] =
- (int *)integrator_shader_sort_counter_.device_pointer;
- integrator_state_gpu_.sort_key_counter[DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE] =
- (int *)integrator_shader_raytrace_sort_counter_.device_pointer;
+ integrator_shader_sort_prefix_sum_.alloc(sort_buckets);
+ integrator_shader_sort_prefix_sum_.zero_to_device();
}
}
@@ -232,7 +257,7 @@ void PathTraceWorkGPU::init_execution()
/* Copy to device side struct in constant memory. */
device_->const_copy_to(
- "__integrator_state", &integrator_state_gpu_, sizeof(integrator_state_gpu_));
+ "integrator_state", &integrator_state_gpu_, sizeof(integrator_state_gpu_));
}
void PathTraceWorkGPU::render_samples(RenderStatistics &statistics,
@@ -326,7 +351,12 @@ void PathTraceWorkGPU::enqueue_reset()
queue_->enqueue(DEVICE_KERNEL_INTEGRATOR_RESET, max_num_paths_, args);
queue_->zero_to_device(integrator_queue_counter_);
queue_->zero_to_device(integrator_shader_sort_counter_);
- queue_->zero_to_device(integrator_shader_raytrace_sort_counter_);
+ if (device_scene_->data.kernel_features & KERNEL_FEATURE_NODE_RAYTRACE) {
+ queue_->zero_to_device(integrator_shader_raytrace_sort_counter_);
+ }
+ if (device_scene_->data.kernel_features & KERNEL_FEATURE_MNEE) {
+ queue_->zero_to_device(integrator_shader_mnee_sort_counter_);
+ }
/* Tiles enqueue need to know number of active paths, which is based on this counter. Zero the
* counter on the host side because `zero_to_device()` is not doing it. */
@@ -450,6 +480,7 @@ void PathTraceWorkGPU::enqueue_path_iteration(DeviceKernel kernel, const int num
case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE:
case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME: {
/* Shading kernels with integrator state and render buffer. */
DeviceKernelArguments args(&d_path_index, &buffers_->buffer.device_pointer, &work_size);
@@ -477,9 +508,9 @@ void PathTraceWorkGPU::compute_sorted_queued_paths(DeviceKernel kernel,
/* Compute prefix sum of number of active paths with each shader. */
{
const int work_size = 1;
- int max_shaders = device_scene_->data.max_shaders;
+ int sort_buckets = device_scene_->data.max_shaders * num_sort_partitions_;
- DeviceKernelArguments args(&d_counter, &d_prefix_sum, &max_shaders);
+ DeviceKernelArguments args(&d_counter, &d_prefix_sum, &sort_buckets);
queue_->enqueue(DEVICE_KERNEL_PREFIX_SUM, work_size, args);
}
@@ -811,10 +842,10 @@ bool PathTraceWorkGPU::should_use_graphics_interop()
interop_use_ = device->should_use_graphics_interop();
if (interop_use_) {
- VLOG(2) << "Using graphics interop GPU display update.";
+ VLOG_INFO << "Using graphics interop GPU display update.";
}
else {
- VLOG(2) << "Using naive GPU display update.";
+ VLOG_INFO << "Using naive GPU display update.";
}
interop_use_checked_ = true;
@@ -1080,13 +1111,15 @@ int PathTraceWorkGPU::shadow_catcher_count_possible_splits()
bool PathTraceWorkGPU::kernel_uses_sorting(DeviceKernel kernel)
{
return (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
- kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE);
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE);
}
bool PathTraceWorkGPU::kernel_creates_shadow_paths(DeviceKernel kernel)
{
return (kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE ||
kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
}
@@ -1094,7 +1127,8 @@ bool PathTraceWorkGPU::kernel_creates_ao_paths(DeviceKernel kernel)
{
return (device_scene_->data.kernel_features & KERNEL_FEATURE_AO) &&
(kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE ||
- kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE);
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
+ kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE);
}
bool PathTraceWorkGPU::kernel_is_shadow_path(DeviceKernel kernel)
diff --git a/intern/cycles/integrator/path_trace_work_gpu.h b/intern/cycles/integrator/path_trace_work_gpu.h
index 90f8b8a4509..a805258d1b5 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.h
+++ b/intern/cycles/integrator/path_trace_work_gpu.h
@@ -133,6 +133,7 @@ class PathTraceWorkGPU : public PathTraceWork {
/* Shader sorting. */
device_vector<int> integrator_shader_sort_counter_;
device_vector<int> integrator_shader_raytrace_sort_counter_;
+ device_vector<int> integrator_shader_mnee_sort_counter_;
device_vector<int> integrator_shader_sort_prefix_sum_;
/* Path split. */
device_vector<int> integrator_next_main_path_index_;
@@ -155,6 +156,9 @@ class PathTraceWorkGPU : public PathTraceWork {
bool interop_use_checked_ = false;
bool interop_use_ = false;
+ /* Number of partitions to sort state indices into prior to material sort. */
+ int num_sort_partitions_;
+
/* Maximum number of concurrent integrator states. */
int max_num_paths_;
diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp
index ebc3170393f..e4676bd059c 100644
--- a/intern/cycles/integrator/render_scheduler.cpp
+++ b/intern/cycles/integrator/render_scheduler.cpp
@@ -225,7 +225,7 @@ bool RenderScheduler::render_work_reschedule_on_idle(RenderWork &render_work)
void RenderScheduler::render_work_reschedule_on_cancel(RenderWork &render_work)
{
- VLOG(3) << "Schedule work for cancel.";
+ VLOG_WORK << "Schedule work for cancel.";
/* Un-schedule samples: they will not be rendered and should not be counted. */
state_.num_rendered_samples -= render_work.path_trace.num_samples;
@@ -475,14 +475,14 @@ void RenderScheduler::report_path_trace_time(const RenderWork &render_work,
path_trace_time_.add_average(final_time_approx, render_work.path_trace.num_samples);
- VLOG(4) << "Average path tracing time: " << path_trace_time_.get_average() << " seconds.";
+ VLOG_WORK << "Average path tracing time: " << path_trace_time_.get_average() << " seconds.";
}
void RenderScheduler::report_path_trace_occupancy(const RenderWork &render_work, float occupancy)
{
state_.occupancy_num_samples = render_work.path_trace.num_samples;
state_.occupancy = occupancy;
- VLOG(4) << "Measured path tracing occupancy: " << occupancy;
+ VLOG_WORK << "Measured path tracing occupancy: " << occupancy;
}
void RenderScheduler::report_adaptive_filter_time(const RenderWork &render_work,
@@ -503,8 +503,8 @@ void RenderScheduler::report_adaptive_filter_time(const RenderWork &render_work,
adaptive_filter_time_.add_average(final_time_approx, render_work.path_trace.num_samples);
- VLOG(4) << "Average adaptive sampling filter time: " << adaptive_filter_time_.get_average()
- << " seconds.";
+ VLOG_WORK << "Average adaptive sampling filter time: " << adaptive_filter_time_.get_average()
+ << " seconds.";
}
void RenderScheduler::report_denoise_time(const RenderWork &render_work, double time)
@@ -523,7 +523,7 @@ void RenderScheduler::report_denoise_time(const RenderWork &render_work, double
denoise_time_.add_average(final_time_approx);
- VLOG(4) << "Average denoising time: " << denoise_time_.get_average() << " seconds.";
+ VLOG_WORK << "Average denoising time: " << denoise_time_.get_average() << " seconds.";
}
void RenderScheduler::report_display_update_time(const RenderWork &render_work, double time)
@@ -542,7 +542,8 @@ void RenderScheduler::report_display_update_time(const RenderWork &render_work,
display_update_time_.add_average(final_time_approx);
- VLOG(4) << "Average display update time: " << display_update_time_.get_average() << " seconds.";
+ VLOG_WORK << "Average display update time: " << display_update_time_.get_average()
+ << " seconds.";
/* Move the display update moment further in time, so that logic which checks when last update
* did happen have more reliable point in time (without path tracing and denoising parts of the
@@ -568,7 +569,7 @@ void RenderScheduler::report_rebalance_time(const RenderWork &render_work,
state_.last_rebalance_changed = balance_changed;
- VLOG(4) << "Average rebalance time: " << rebalance_time_.get_average() << " seconds.";
+ VLOG_WORK << "Average rebalance time: " << rebalance_time_.get_average() << " seconds.";
}
string RenderScheduler::full_report() const
@@ -1063,7 +1064,7 @@ void RenderScheduler::update_start_resolution_divider()
/* Resolution divider has never been calculated before: use default resolution, so that we have
* somewhat good initial behavior, giving a chance to collect real numbers. */
start_resolution_divider_ = default_start_resolution_divider_;
- VLOG(3) << "Initial resolution divider is " << start_resolution_divider_;
+ VLOG_WORK << "Initial resolution divider is " << start_resolution_divider_;
return;
}
@@ -1092,7 +1093,7 @@ void RenderScheduler::update_start_resolution_divider()
* simple and compute device is fast). */
start_resolution_divider_ = max(resolution_divider_for_update, pixel_size_);
- VLOG(3) << "Calculated resolution divider is " << start_resolution_divider_;
+ VLOG_WORK << "Calculated resolution divider is " << start_resolution_divider_;
}
double RenderScheduler::guess_viewport_navigation_update_interval_in_seconds() const
diff --git a/intern/cycles/integrator/shader_eval.cpp b/intern/cycles/integrator/shader_eval.cpp
index 92b9d1c662d..b1450732f5c 100644
--- a/intern/cycles/integrator/shader_eval.cpp
+++ b/intern/cycles/integrator/shader_eval.cpp
@@ -31,8 +31,8 @@ bool ShaderEval::eval(const ShaderEvalType type,
device_->foreach_device([&](Device *device) {
if (!first_device) {
- LOG(ERROR) << "Multi-devices are not yet fully implemented, will evaluate shader on a "
- "single device.";
+ VLOG_WORK << "Multi-devices are not yet fully implemented, will evaluate shader on a "
+ "single device.";
return;
}
first_device = false;
diff --git a/intern/cycles/integrator/work_tile_scheduler.cpp b/intern/cycles/integrator/work_tile_scheduler.cpp
index 6dc511064c9..4bc8c0c4396 100644
--- a/intern/cycles/integrator/work_tile_scheduler.cpp
+++ b/intern/cycles/integrator/work_tile_scheduler.cpp
@@ -55,7 +55,7 @@ void WorkTileScheduler::reset_scheduler_state()
tile_size_ = tile_calculate_best_size(
accelerated_rt_, image_size_px_, samples_num_, max_num_path_states_, scrambling_distance_);
- VLOG(3) << "Will schedule tiles of size " << tile_size_;
+ VLOG_WORK << "Will schedule tiles of size " << tile_size_;
if (VLOG_IS_ON(3)) {
/* The logging is based on multiple tiles scheduled, ignoring overhead of multi-tile scheduling
@@ -63,8 +63,8 @@ void WorkTileScheduler::reset_scheduler_state()
const int num_path_states_in_tile = tile_size_.width * tile_size_.height *
tile_size_.num_samples;
const int num_tiles = max_num_path_states_ / num_path_states_in_tile;
- VLOG(3) << "Number of unused path states: "
- << max_num_path_states_ - num_tiles * num_path_states_in_tile;
+ VLOG_WORK << "Number of unused path states: "
+ << max_num_path_states_ - num_tiles * num_path_states_in_tile;
}
num_tiles_x_ = divide_up(image_size_px_.x, tile_size_.width);
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 473bdb67920..21a78722c0d 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -37,6 +37,10 @@ set(SRC_KERNEL_DEVICE_OPTIX
device/optix/kernel_shader_raytrace.cu
)
+set(SRC_KERNEL_DEVICE_ONEAPI
+ device/oneapi/kernel.cpp
+)
+
set(SRC_KERNEL_DEVICE_CPU_HEADERS
device/cpu/compat.h
device/cpu/image.h
@@ -75,9 +79,20 @@ set(SRC_KERNEL_DEVICE_METAL_HEADERS
device/metal/compat.h
device/metal/context_begin.h
device/metal/context_end.h
+ device/metal/function_constants.h
device/metal/globals.h
)
+set(SRC_KERNEL_DEVICE_ONEAPI_HEADERS
+ device/oneapi/compat.h
+ device/oneapi/context_begin.h
+ device/oneapi/context_end.h
+ device/oneapi/globals.h
+ device/oneapi/image.h
+ device/oneapi/kernel.h
+ device/oneapi/kernel_templates.h
+)
+
set(SRC_KERNEL_CLOSURE_HEADERS
closure/alloc.h
closure/bsdf.h
@@ -140,6 +155,7 @@ set(SRC_KERNEL_SVM_HEADERS
svm/math_util.h
svm/mix.h
svm/musgrave.h
+ svm/node_types_template.h
svm/noise.h
svm/noisetex.h
svm/normal.h
@@ -267,8 +283,9 @@ set(SRC_KERNEL_UTIL_HEADERS
)
set(SRC_KERNEL_TYPES_HEADERS
+ data_arrays.h
+ data_template.h
tables.h
- textures.h
types.h
)
@@ -687,6 +704,209 @@ if(WITH_CYCLES_DEVICE_OPTIX AND WITH_CYCLES_CUDA_BINARIES)
cycles_set_solution_folder(cycles_kernel_optix)
endif()
+if(WITH_CYCLES_DEVICE_ONEAPI)
+ if(WIN32)
+ set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi.dll)
+ else()
+ set(cycles_kernel_oneapi_lib ${CMAKE_CURRENT_BINARY_DIR}/cycles_kernel_oneapi.so)
+ endif()
+
+ set(cycles_oneapi_kernel_sources
+ ${SRC_KERNEL_DEVICE_ONEAPI}
+ ${SRC_KERNEL_HEADERS}
+ ${SRC_KERNEL_DEVICE_GPU_HEADERS}
+ ${SRC_KERNEL_DEVICE_ONEAPI_HEADERS}
+ ${SRC_UTIL_HEADERS}
+ )
+
+ # SYCL_CPP_FLAGS is a variable that the user can set to pass extra compiler options
+ set(sycl_compiler_flags
+ ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_KERNEL_DEVICE_ONEAPI}
+ -fsycl
+ -fsycl-unnamed-lambda
+ -fdelayed-template-parsing
+ -mllvm -inlinedefault-threshold=300
+ -mllvm -inlinehint-threshold=400
+ -shared
+ -DWITH_ONEAPI
+ -ffast-math
+ -DNDEBUG
+ -O2
+ -o ${cycles_kernel_oneapi_lib}
+ -I${CMAKE_CURRENT_SOURCE_DIR}/..
+ ${SYCL_CPP_FLAGS}
+ )
+
+
+ if (WITH_CYCLES_ONEAPI_SYCL_HOST_ENABLED)
+ list(APPEND sycl_compiler_flags -DWITH_ONEAPI_SYCL_HOST_ENABLED)
+ endif()
+
+ # Set defaults for spir64 and spir64_gen options
+ if (NOT DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_spir64)
+ set(CYCLES_ONEAPI_SYCL_OPTIONS_spir64 "-options '-ze-opt-large-register-file -ze-opt-regular-grf-kernel integrator_intersect'")
+ endif()
+ if (NOT DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen)
+ SET (CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "${CYCLES_ONEAPI_SYCL_OPTIONS_spir64}" CACHE STRING "Extra build options for spir64_gen target")
+ endif()
+ # enabling zebin (graphics binary format with improved compatibility) on Windows only while support on Linux isn't available yet
+ if(WIN32)
+ string(PREPEND CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "--format zebin ")
+ endif()
+ string(PREPEND CYCLES_ONEAPI_SYCL_OPTIONS_spir64_gen "-device ${CYCLES_ONEAPI_SPIR64_GEN_DEVICES} ")
+
+ if (WITH_CYCLES_ONEAPI_BINARIES)
+ # Iterate over all targest and their options
+ list (JOIN CYCLES_ONEAPI_SYCL_TARGETS "," targets_string)
+ list (APPEND sycl_compiler_flags -fsycl-targets=${targets_string})
+ foreach(target ${CYCLES_ONEAPI_SYCL_TARGETS})
+ if(DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_${target})
+ list (APPEND sycl_compiler_flags -Xsycl-target-backend=${target} "${CYCLES_ONEAPI_SYCL_OPTIONS_${target}}")
+ endif()
+ endforeach()
+ else()
+ # If AOT is disabled, build for spir64
+ list(APPEND sycl_compiler_flags
+ -fsycl-targets=spir64
+ -Xsycl-target-backend=spir64 "${CYCLES_ONEAPI_SYCL_OPTIONS_spir64}")
+ endif()
+
+ if(WITH_NANOVDB)
+ list(APPEND sycl_compiler_flags
+ -DWITH_NANOVDB
+ -I"${NANOVDB_INCLUDE_DIR}")
+ endif()
+
+ if(WITH_CYCLES_DEBUG)
+ list(APPEND sycl_compiler_flags -DWITH_CYCLES_DEBUG)
+ endif()
+
+ get_filename_component(sycl_compiler_root ${SYCL_COMPILER} DIRECTORY)
+ get_filename_component(sycl_compiler_compiler_name ${SYCL_COMPILER} NAME_WE)
+
+ if(NOT OCLOC_INSTALL_DIR)
+ get_filename_component(OCLOC_INSTALL_DIR "${sycl_compiler_root}/../lib/ocloc" ABSOLUTE)
+ endif()
+ if(WITH_CYCLES_ONEAPI_BINARIES AND NOT EXISTS ${OCLOC_INSTALL_DIR})
+ message(FATAL_ERROR "WITH_CYCLES_ONEAPI_BINARIES requires ocloc but ${OCLOC_INSTALL_DIR} directory doesn't exist."
+ " A different ocloc directory can be set using OCLOC_INSTALL_DIR cmake variable.")
+ endif()
+
+ if(UNIX AND NOT APPLE)
+ if(NOT WITH_CXX11_ABI)
+ check_library_exists(sycl
+ _ZN2cl4sycl7handler22verifyUsedKernelBundleERKSs ${sycl_compiler_root}/../lib SYCL_NO_CXX11_ABI)
+ if(SYCL_NO_CXX11_ABI)
+ list(APPEND sycl_compiler_flags -D_GLIBCXX_USE_CXX11_ABI=0)
+ endif()
+ endif()
+ endif()
+
+ if(WIN32)
+ list(APPEND sycl_compiler_flags
+ -fms-extensions
+ -fms-compatibility
+ -D_WINDLL
+ -D_MBCS
+ -DWIN32
+ -D_WINDOWS
+ -D_CRT_NONSTDC_NO_DEPRECATE
+ -D_CRT_SECURE_NO_DEPRECATE
+ -DONEAPI_EXPORT)
+
+ if(sycl_compiler_compiler_name MATCHES "dpcpp")
+ # The oneAPI distribution calls the compiler "dpcpp" and comes with a script that sets environment variables.
+ add_custom_command(
+ OUTPUT ${cycles_kernel_oneapi_lib}
+ COMMAND "${sycl_compiler_root}/../../env/vars.bat"
+ COMMAND ${SYCL_COMPILER} $<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g> ${sycl_compiler_flags}
+ DEPENDS ${cycles_oneapi_kernel_sources})
+ else()
+ # The open source SYCL compiler just goes by clang++ and does not have such a script.
+ # Set the variables manually.
+ string(REPLACE /Redist/ /Tools/ MSVC_TOOLS_DIR ${MSVC_REDIST_DIR})
+ if(NOT CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION) # case for Ninja on Windows
+ get_filename_component(cmake_mt_dir ${CMAKE_MT} DIRECTORY)
+ string(REPLACE /bin/ /Lib/ WINDOWS_KIT_DIR ${cmake_mt_dir})
+ get_filename_component(WINDOWS_KIT_DIR "${WINDOWS_KIT_DIR}/../" ABSOLUTE)
+ else()
+ set(WINDOWS_KIT_DIR ${WINDOWS_KITS_DIR}/Lib/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION})
+ endif()
+ list(APPEND sycl_compiler_flags
+ -L "${MSVC_TOOLS_DIR}/lib/x64"
+ -L "${WINDOWS_KIT_DIR}/um/x64"
+ -L "${WINDOWS_KIT_DIR}/ucrt/x64")
+ add_custom_command(
+ OUTPUT ${cycles_kernel_oneapi_lib}
+ COMMAND ${CMAKE_COMMAND} -E env
+ "LIB=${sycl_compiler_root}/../lib" # for compiler to find sycl.lib
+ "PATH=${OCLOC_INSTALL_DIR};${sycl_compiler_root}"
+ ${SYCL_COMPILER} $<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g> ${sycl_compiler_flags}
+ DEPENDS ${cycles_oneapi_kernel_sources})
+ endif()
+ else()
+ list(APPEND sycl_compiler_flags -fPIC)
+
+ # We avoid getting __FAST_MATH__ to be defined when building on CentOS 7 until the compilation crash
+ # it triggers at either AoT or JIT stages gets fixed.
+ list(APPEND sycl_compiler_flags -fhonor-nans)
+
+ # add $ORIGIN to cycles_kernel_oneapi.so rpath so libsycl.so and
+ # libpi_level_zero.so can be placed next to it and get found.
+ list(APPEND sycl_compiler_flags -Wl,-rpath,'$$ORIGIN')
+
+ # The oneAPI distribution calls the compiler "dpcpp" and comes with a script that sets environment variables.
+ if(sycl_compiler_compiler_name MATCHES "dpcpp")
+ add_custom_command(
+ OUTPUT ${cycles_kernel_oneapi_lib}
+ COMMAND bash -c \"source ${sycl_compiler_root}/../../env/vars.sh&&${SYCL_COMPILER} $<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g> ${sycl_compiler_flags}\"
+ DEPENDS ${cycles_oneapi_kernel_sources})
+ else()
+ # The open source SYCL compiler just goes by clang++ and does not have such a script.
+ # Set the variables manually.
+ if(NOT IGC_INSTALL_DIR)
+ get_filename_component(IGC_INSTALL_DIR "${sycl_compiler_root}/../lib/igc" ABSOLUTE)
+ endif()
+ add_custom_command(
+ OUTPUT ${cycles_kernel_oneapi_lib}
+ COMMAND ${CMAKE_COMMAND} -E env
+ "LD_LIBRARY_PATH=${sycl_compiler_root}/../lib:${OCLOC_INSTALL_DIR}/lib:${IGC_INSTALL_DIR}/lib"
+ "PATH=${OCLOC_INSTALL_DIR}/bin:${sycl_compiler_root}:$ENV{PATH}" # env PATH is for compiler to find ld
+ ${SYCL_COMPILER} $<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g> ${sycl_compiler_flags}
+ DEPENDS ${cycles_oneapi_kernel_sources})
+ endif()
+ endif()
+
+ # install dynamic libraries required at runtime
+ if(WIN32)
+ set(SYCL_RUNTIME_DEPENDENCIES
+ sycl.dll
+ pi_level_zero.dll
+ )
+ if(NOT WITH_BLENDER)
+ # For the Cycles standalone put libraries next to the Cycles application.
+ delayed_install("${sycl_compiler_root}" "${SYCL_RUNTIME_DEPENDENCIES}" ${CYCLES_INSTALL_PATH})
+ else()
+ # For Blender put the libraries next to the Blender executable.
+ #
+ # Note that the installation path in the delayed_install is relative to the versioned folder,
+ # which means we need to go one level up.
+ delayed_install("${sycl_compiler_root}" "${SYCL_RUNTIME_DEPENDENCIES}" "../")
+ endif()
+ elseif(UNIX AND NOT APPLE)
+ file(GLOB SYCL_RUNTIME_DEPENDENCIES
+ ${sycl_compiler_root}/../lib/libsycl.so
+ ${sycl_compiler_root}/../lib/libsycl.so.[0-9]
+ ${sycl_compiler_root}/../lib/libsycl.so.[0-9].[0-9].[0-9]-[0-9]
+ )
+ list(APPEND SYCL_RUNTIME_DEPENDENCIES ${sycl_compiler_root}/../lib/libpi_level_zero.so)
+ delayed_install("" "${SYCL_RUNTIME_DEPENDENCIES}" ${CYCLES_INSTALL_PATH}/lib)
+ endif()
+
+ delayed_install("${CMAKE_CURRENT_BINARY_DIR}" "${cycles_kernel_oneapi_lib}" ${CYCLES_INSTALL_PATH}/lib)
+ add_custom_target(cycles_kernel_oneapi ALL DEPENDS ${cycles_kernel_oneapi_lib})
+endif()
+
# OSL module
if(WITH_CYCLES_OSL)
@@ -752,6 +972,7 @@ cycles_add_library(cycles_kernel "${LIB}"
${SRC_KERNEL_DEVICE_HIP_HEADERS}
${SRC_KERNEL_DEVICE_OPTIX_HEADERS}
${SRC_KERNEL_DEVICE_METAL_HEADERS}
+ ${SRC_KERNEL_DEVICE_ONEAPI_HEADERS}
)
source_group("bake" FILES ${SRC_KERNEL_BAKE_HEADERS})
@@ -764,6 +985,7 @@ source_group("device\\gpu" FILES ${SRC_KERNEL_DEVICE_GPU_HEADERS})
source_group("device\\hip" FILES ${SRC_KERNEL_DEVICE_HIP} ${SRC_KERNEL_DEVICE_HIP_HEADERS})
source_group("device\\optix" FILES ${SRC_KERNEL_DEVICE_OPTIX} ${SRC_KERNEL_DEVICE_OPTIX_HEADERS})
source_group("device\\metal" FILES ${SRC_KERNEL_DEVICE_METAL} ${SRC_KERNEL_DEVICE_METAL_HEADERS})
+source_group("device\\oneapi" FILES ${SRC_KERNEL_DEVICE_ONEAPI} ${SRC_KERNEL_DEVICE_ONEAPI_HEADERS})
source_group("film" FILES ${SRC_KERNEL_FILM_HEADERS})
source_group("geom" FILES ${SRC_KERNEL_GEOM_HEADERS})
source_group("integrator" FILES ${SRC_KERNEL_INTEGRATOR_HEADERS})
@@ -782,6 +1004,9 @@ endif()
if(WITH_CYCLES_HIP)
add_dependencies(cycles_kernel cycles_kernel_hip)
endif()
+if(WITH_CYCLES_DEVICE_ONEAPI)
+ add_dependencies(cycles_kernel cycles_kernel_oneapi)
+endif()
# Install kernel source for runtime compilation
diff --git a/intern/cycles/kernel/bake/bake.h b/intern/cycles/kernel/bake/bake.h
index 544a8217bef..ec87990b699 100644
--- a/intern/cycles/kernel/bake/bake.h
+++ b/intern/cycles/kernel/bake/bake.h
@@ -29,14 +29,14 @@ ccl_device void kernel_displace_evaluate(KernelGlobals kg,
object_inverse_dir_transform(kg, &sd, &D);
#ifdef __KERNEL_DEBUG_NAN__
- if (!isfinite3_safe(D)) {
+ if (!isfinite_safe(D)) {
kernel_assert(!"Cycles displacement with non-finite value detected");
}
#endif
/* Ensure finite displacement, preventing BVH from becoming degenerate and avoiding possible
* traversal issues caused by non-finite math. */
- D = ensure_finite3(D);
+ D = ensure_finite(D);
/* Write output. */
output[offset * 3 + 0] += D.x;
@@ -68,13 +68,13 @@ ccl_device void kernel_background_evaluate(KernelGlobals kg,
float3 color = shader_background_eval(&sd);
#ifdef __KERNEL_DEBUG_NAN__
- if (!isfinite3_safe(color)) {
+ if (!isfinite_safe(color)) {
kernel_assert(!"Cycles background with non-finite value detected");
}
#endif
/* Ensure finite color, avoiding possible numerical instabilities in the path tracing kernels. */
- color = ensure_finite3(color);
+ color = ensure_finite(color);
/* Write output. */
output[offset * 3 + 0] += color.x;
diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h
index 04ccb7ceff5..9972de86c47 100644
--- a/intern/cycles/kernel/bvh/bvh.h
+++ b/intern/cycles/kernel/bvh/bvh.h
@@ -172,11 +172,11 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
ray_flags |= OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT;
}
- optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
+ optixTrace(scene_intersect_valid(ray) ? kernel_data.device_bvh : 0,
ray->P,
ray->D,
- 0.0f,
- ray->t,
+ ray->tmin,
+ ray->tmax,
ray->time,
ray_mask,
ray_flags,
@@ -203,28 +203,28 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
#elif defined(__METALRT__)
if (!scene_intersect_valid(ray)) {
- isect->t = ray->t;
+ isect->t = ray->tmax;
isect->type = PRIMITIVE_NONE;
return false;
}
# if defined(__KERNEL_DEBUG__)
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
- isect->t = ray->t;
+ isect->t = ray->tmax;
isect->type = PRIMITIVE_NONE;
kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
return false;
}
if (is_null_intersection_function_table(metal_ancillaries->ift_default)) {
- isect->t = ray->t;
+ isect->t = ray->tmax;
isect->type = PRIMITIVE_NONE;
kernel_assert(!"Invalid ift_default");
return false;
}
# endif
- metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
metalrt_intersector_type metalrt_intersect;
if (!kernel_data.bvh.have_curves) {
@@ -263,7 +263,7 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
# endif
if (intersection.type == intersection_type::none) {
- isect->t = ray->t;
+ isect->t = ray->tmax;
isect->type = PRIMITIVE_NONE;
return false;
@@ -295,14 +295,14 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
}
# ifdef __EMBREE__
- if (kernel_data.bvh.scene) {
- isect->t = ray->t;
+ if (kernel_data.device_bvh) {
+ isect->t = ray->tmax;
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR);
IntersectContext rtc_ctx(&ctx);
RTCRayHit ray_hit;
ctx.ray = ray;
kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
- rtcIntersect1(kernel_data.bvh.scene, &rtc_ctx.context, &ray_hit);
+ rtcIntersect1(kernel_data.device_bvh, &rtc_ctx.context, &ray_hit);
if (ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID &&
ray_hit.hit.primID != RTC_INVALID_GEOMETRY_ID) {
kernel_embree_convert_hit(kg, &ray_hit.ray, &ray_hit.hit, isect);
@@ -357,11 +357,11 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
if (local_isect) {
local_isect->num_hits = 0; /* Initialize hit count to zero. */
}
- optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
+ optixTrace(scene_intersect_valid(ray) ? kernel_data.device_bvh : 0,
ray->P,
ray->D,
- 0.0f,
- ray->t,
+ ray->tmin,
+ ray->tmax,
ray->time,
0xFF,
/* Need to always call into __anyhit__kernel_optix_local_hit. */
@@ -405,7 +405,7 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
}
# endif
- metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
metalrt_intersector_type metalrt_intersect;
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
@@ -451,8 +451,8 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
}
# ifdef __EMBREE__
- if (kernel_data.bvh.scene) {
- const bool has_bvh = !(kernel_tex_fetch(__object_flag, local_object) &
+ if (kernel_data.device_bvh) {
+ const bool has_bvh = !(kernel_data_fetch(object_flag, local_object) &
SD_OBJECT_TRANSFORM_APPLIED);
CCLIntersectContext ctx(
kg, has_bvh ? CCLIntersectContext::RAY_SSS : CCLIntersectContext::RAY_LOCAL);
@@ -470,13 +470,13 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
/* If this object has its own BVH, use it. */
if (has_bvh) {
- RTCGeometry geom = rtcGetGeometry(kernel_data.bvh.scene, local_object * 2);
+ RTCGeometry geom = rtcGetGeometry(kernel_data.device_bvh, local_object * 2);
if (geom) {
float3 P = ray->P;
float3 dir = ray->D;
float3 idir = ray->D;
Transform ob_itfm;
- rtc_ray.tfar = ray->t *
+ rtc_ray.tfar = ray->tmax *
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir, &ob_itfm);
/* bvh_instance_motion_push() returns the inverse transform but
* it's not needed here. */
@@ -496,7 +496,7 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
}
}
else {
- rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
+ rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
}
/* rtcOccluded1 sets tfar to -inf if a hit was found. */
@@ -539,11 +539,11 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
ray_mask = 0xFF;
}
- optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
+ optixTrace(scene_intersect_valid(ray) ? kernel_data.device_bvh : 0,
ray->P,
ray->D,
- 0.0f,
- ray->t,
+ ray->tmin,
+ ray->tmax,
ray->time,
ray_mask,
/* Need to always call into __anyhit__kernel_optix_shadow_all_hit. */
@@ -582,7 +582,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
}
# endif
- metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
metalrt_intersector_type metalrt_intersect;
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
@@ -633,7 +633,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
}
# ifdef __EMBREE__
- if (kernel_data.bvh.scene) {
+ if (kernel_data.device_bvh) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL);
Intersection *isect_array = (Intersection *)state->shadow_isect;
ctx.isect_s = isect_array;
@@ -642,7 +642,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
- rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
+ rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
*num_recorded_hits = ctx.num_recorded_hits;
*throughput = ctx.throughput;
@@ -698,11 +698,11 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
ray_mask = 0xFF;
}
- optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0,
+ optixTrace(scene_intersect_valid(ray) ? kernel_data.device_bvh : 0,
ray->P,
ray->D,
- 0.0f,
- ray->t,
+ ray->tmin,
+ ray->tmax,
ray->time,
ray_mask,
/* Need to always call into __anyhit__kernel_optix_volume_test. */
@@ -744,7 +744,7 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
}
# endif
- metal::raytracing::ray r(ray->P, ray->D, 0.0f, ray->t);
+ metal::raytracing::ray r(ray->P, ray->D, ray->tmin, ray->tmax);
metalrt_intersector_type metalrt_intersect;
metalrt_intersect.force_opacity(metal::raytracing::forced_opacity::non_opaque);
@@ -825,7 +825,7 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals kg,
}
# ifdef __EMBREE__
- if (kernel_data.bvh.scene) {
+ if (kernel_data.device_bvh) {
CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_VOLUME_ALL);
ctx.isect_s = isect;
ctx.max_hits = max_hits;
@@ -834,7 +834,7 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals kg,
IntersectContext rtc_ctx(&ctx);
RTCRay rtc_ray;
kernel_embree_setup_ray(*ray, rtc_ray, visibility);
- rtcOccluded1(kernel_data.bvh.scene, &rtc_ctx.context, &rtc_ray);
+ rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
return ctx.num_hits;
}
# endif /* __EMBREE__ */
diff --git a/intern/cycles/kernel/bvh/embree.h b/intern/cycles/kernel/bvh/embree.h
index 4f7e6435daf..fecbccac2f8 100644
--- a/intern/cycles/kernel/bvh/embree.h
+++ b/intern/cycles/kernel/bvh/embree.h
@@ -83,8 +83,8 @@ ccl_device_inline void kernel_embree_setup_ray(const Ray &ray,
rtc_ray.dir_x = ray.D.x;
rtc_ray.dir_y = ray.D.y;
rtc_ray.dir_z = ray.D.z;
- rtc_ray.tnear = 0.0f;
- rtc_ray.tfar = ray.t;
+ rtc_ray.tnear = ray.tmin;
+ rtc_ray.tfar = ray.tmax;
rtc_ray.time = ray.time;
rtc_ray.mask = visibility;
}
@@ -107,7 +107,7 @@ ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg
const int oID = hit->instID[0] / 2;
if ((ray->self.object == oID) || (ray->self.light_object == oID)) {
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0]));
+ rtcGetGeometry(kernel_data.device_bvh, hit->instID[0]));
const int pID = hit->primID +
(intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
status = intersection_skip_self_shadow(ray->self, oID, pID);
@@ -117,7 +117,7 @@ ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg
const int oID = hit->geomID / 2;
if ((ray->self.object == oID) || (ray->self.light_object == oID)) {
const int pID = hit->primID + (intptr_t)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, hit->geomID));
+ rtcGetGeometry(kernel_data.device_bvh, hit->geomID));
status = intersection_skip_self_shadow(ray->self, oID, pID);
}
}
@@ -133,27 +133,27 @@ ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg,
isect->t = ray->tfar;
if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0]));
+ rtcGetGeometry(kernel_data.device_bvh, hit->instID[0]));
isect->prim = hit->primID +
(intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
isect->object = hit->instID[0] / 2;
}
else {
isect->prim = hit->primID + (intptr_t)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, hit->geomID));
+ rtcGetGeometry(kernel_data.device_bvh, hit->geomID));
isect->object = hit->geomID / 2;
}
const bool is_hair = hit->geomID & 1;
if (is_hair) {
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, isect->prim);
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, isect->prim);
isect->type = segment.type;
isect->prim = segment.prim;
isect->u = hit->u;
isect->v = hit->v;
}
else {
- isect->type = kernel_tex_fetch(__objects, isect->object).primitive_type;
+ isect->type = kernel_data_fetch(objects, isect->object).primitive_type;
isect->u = 1.0f - hit->v - hit->u;
isect->v = hit->u;
}
@@ -166,11 +166,11 @@ ccl_device_inline void kernel_embree_convert_sss_hit(
isect->v = hit->u;
isect->t = ray->tfar;
RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
- rtcGetGeometry(kernel_data.bvh.scene, object * 2));
+ rtcGetGeometry(kernel_data.device_bvh, object * 2));
isect->prim = hit->primID +
(intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
isect->object = object;
- isect->type = kernel_tex_fetch(__objects, object).primitive_type;
+ isect->type = kernel_data_fetch(objects, object).primitive_type;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/bvh/local.h b/intern/cycles/kernel/bvh/local.h
index 0d05e09d75f..017a241ef4a 100644
--- a/intern/cycles/kernel/bvh/local.h
+++ b/intern/cycles/kernel/bvh/local.h
@@ -41,28 +41,32 @@ ccl_device_inline
/* traversal variables in registers */
int stack_ptr = 0;
- int node_addr = kernel_tex_fetch(__object_node, local_object);
+ int node_addr = kernel_data_fetch(object_node, local_object);
/* ray parameters in registers */
float3 P = ray->P;
float3 dir = bvh_clamp_direction(ray->D);
float3 idir = bvh_inverse_direction(dir);
+ float tmin = ray->tmin;
int object = OBJECT_NONE;
- float isect_t = ray->t;
+ float isect_t = ray->tmax;
if (local_isect != NULL) {
local_isect->num_hits = 0;
}
kernel_assert((local_isect == NULL) == (max_hits == 0));
- const int object_flag = kernel_tex_fetch(__object_flag, local_object);
+ const int object_flag = kernel_data_fetch(object_flag, local_object);
if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
#if BVH_FEATURE(BVH_MOTION)
Transform ob_itfm;
- isect_t *= bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir, &ob_itfm);
+ const float t_world_to_instance = bvh_instance_motion_push(
+ kg, local_object, ray, &P, &dir, &idir, &ob_itfm);
#else
- isect_t *= bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
+ const float t_world_to_instance = bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
#endif
+ isect_t *= t_world_to_instance;
+ tmin *= t_world_to_instance;
object = local_object;
}
@@ -73,7 +77,7 @@ ccl_device_inline
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
int node_addr_child1, traverse_mask;
float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+ float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
traverse_mask = NODE_INTERSECT(kg,
P,
@@ -81,6 +85,7 @@ ccl_device_inline
dir,
#endif
idir,
+ tmin,
isect_t,
node_addr,
PATH_RAY_ALL_VISIBILITY,
@@ -117,7 +122,7 @@ ccl_device_inline
/* if node is leaf, fetch triangle list */
if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
int prim_addr = __float_as_int(leaf.x);
const int prim_addr2 = __float_as_int(leaf.y);
@@ -132,18 +137,18 @@ ccl_device_inline
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
/* Only intersect with matching object, for instanced objects we
* already know we are only intersecting the right object. */
if (object == OBJECT_NONE) {
- if (kernel_tex_fetch(__prim_object, prim_addr) != local_object) {
+ if (kernel_data_fetch(prim_object, prim_addr) != local_object) {
continue;
}
}
/* Skip self intersection. */
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int prim = kernel_data_fetch(prim_index, prim_addr);
if (intersection_skip_self_local(ray->self, prim)) {
continue;
}
@@ -155,6 +160,7 @@ ccl_device_inline
local_object,
prim,
prim_addr,
+ tmin,
isect_t,
lcg_state,
max_hits)) {
@@ -167,18 +173,18 @@ ccl_device_inline
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
/* Only intersect with matching object, for instanced objects we
* already know we are only intersecting the right object. */
if (object == OBJECT_NONE) {
- if (kernel_tex_fetch(__prim_object, prim_addr) != local_object) {
+ if (kernel_data_fetch(prim_object, prim_addr) != local_object) {
continue;
}
}
/* Skip self intersection. */
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int prim = kernel_data_fetch(prim_index, prim_addr);
if (intersection_skip_self_local(ray->self, prim)) {
continue;
}
@@ -191,6 +197,7 @@ ccl_device_inline
local_object,
prim,
prim_addr,
+ tmin,
isect_t,
lcg_state,
max_hits)) {
diff --git a/intern/cycles/kernel/bvh/nodes.h b/intern/cycles/kernel/bvh/nodes.h
index fd475dcd5e9..e02841fad16 100644
--- a/intern/cycles/kernel/bvh/nodes.h
+++ b/intern/cycles/kernel/bvh/nodes.h
@@ -9,16 +9,17 @@ ccl_device_forceinline Transform bvh_unaligned_node_fetch_space(KernelGlobals kg
{
Transform space;
const int child_addr = node_addr + child * 3;
- space.x = kernel_tex_fetch(__bvh_nodes, child_addr + 1);
- space.y = kernel_tex_fetch(__bvh_nodes, child_addr + 2);
- space.z = kernel_tex_fetch(__bvh_nodes, child_addr + 3);
+ space.x = kernel_data_fetch(bvh_nodes, child_addr + 1);
+ space.y = kernel_data_fetch(bvh_nodes, child_addr + 2);
+ space.z = kernel_data_fetch(bvh_nodes, child_addr + 3);
return space;
}
ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals kg,
const float3 P,
const float3 idir,
- const float t,
+ const float tmin,
+ const float tmax,
const int node_addr,
const uint visibility,
float dist[2])
@@ -26,11 +27,11 @@ ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals kg,
/* fetch node data */
#ifdef __VISIBILITY_FLAG__
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+ float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
#endif
- float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr + 1);
- float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr + 2);
- float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr + 3);
+ float4 node0 = kernel_data_fetch(bvh_nodes, node_addr + 1);
+ float4 node1 = kernel_data_fetch(bvh_nodes, node_addr + 2);
+ float4 node2 = kernel_data_fetch(bvh_nodes, node_addr + 3);
/* intersect ray against child nodes */
float c0lox = (node0.x - P.x) * idir.x;
@@ -39,8 +40,8 @@ ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals kg,
float c0hiy = (node1.z - P.y) * idir.y;
float c0loz = (node2.x - P.z) * idir.z;
float c0hiz = (node2.z - P.z) * idir.z;
- float c0min = max4(0.0f, min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz));
- float c0max = min4(t, max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz));
+ float c0min = max4(tmin, min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz));
+ float c0max = min4(tmax, max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz));
float c1lox = (node0.y - P.x) * idir.x;
float c1hix = (node0.w - P.x) * idir.x;
@@ -48,8 +49,8 @@ ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals kg,
float c1hiy = (node1.w - P.y) * idir.y;
float c1loz = (node2.y - P.z) * idir.z;
float c1hiz = (node2.w - P.z) * idir.z;
- float c1min = max4(0.0f, min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz));
- float c1max = min4(t, max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz));
+ float c1min = max4(tmin, min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz));
+ float c1max = min4(tmax, max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz));
dist[0] = c0min;
dist[1] = c1min;
@@ -66,7 +67,8 @@ ccl_device_forceinline int bvh_aligned_node_intersect(KernelGlobals kg,
ccl_device_forceinline bool bvh_unaligned_node_intersect_child(KernelGlobals kg,
const float3 P,
const float3 dir,
- const float t,
+ const float tmin,
+ const float tmax,
int node_addr,
int child,
float dist[2])
@@ -83,8 +85,8 @@ ccl_device_forceinline bool bvh_unaligned_node_intersect_child(KernelGlobals kg,
const float far_x = max(lower_xyz.x, upper_xyz.x);
const float far_y = max(lower_xyz.y, upper_xyz.y);
const float far_z = max(lower_xyz.z, upper_xyz.z);
- const float tnear = max4(0.0f, near_x, near_y, near_z);
- const float tfar = min4(t, far_x, far_y, far_z);
+ const float tnear = max4(tmin, near_x, near_y, near_z);
+ const float tfar = min4(tmax, far_x, far_y, far_z);
*dist = tnear;
return tnear <= tfar;
}
@@ -93,16 +95,17 @@ ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals kg,
const float3 P,
const float3 dir,
const float3 idir,
- const float t,
+ const float tmin,
+ const float tmax,
const int node_addr,
const uint visibility,
float dist[2])
{
int mask = 0;
#ifdef __VISIBILITY_FLAG__
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+ float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
#endif
- if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, &dist[0])) {
+ if (bvh_unaligned_node_intersect_child(kg, P, dir, tmin, tmax, node_addr, 0, &dist[0])) {
#ifdef __VISIBILITY_FLAG__
if ((__float_as_uint(cnodes.x) & visibility))
#endif
@@ -110,7 +113,7 @@ ccl_device_forceinline int bvh_unaligned_node_intersect(KernelGlobals kg,
mask |= 1;
}
}
- if (bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, &dist[1])) {
+ if (bvh_unaligned_node_intersect_child(kg, P, dir, tmin, tmax, node_addr, 1, &dist[1])) {
#ifdef __VISIBILITY_FLAG__
if ((__float_as_uint(cnodes.y) & visibility))
#endif
@@ -125,16 +128,17 @@ ccl_device_forceinline int bvh_node_intersect(KernelGlobals kg,
const float3 P,
const float3 dir,
const float3 idir,
- const float t,
+ const float tmin,
+ const float tmax,
const int node_addr,
const uint visibility,
float dist[2])
{
- float4 node = kernel_tex_fetch(__bvh_nodes, node_addr);
+ float4 node = kernel_data_fetch(bvh_nodes, node_addr);
if (__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) {
- return bvh_unaligned_node_intersect(kg, P, dir, idir, t, node_addr, visibility, dist);
+ return bvh_unaligned_node_intersect(kg, P, dir, idir, tmin, tmax, node_addr, visibility, dist);
}
else {
- return bvh_aligned_node_intersect(kg, P, idir, t, node_addr, visibility, dist);
+ return bvh_aligned_node_intersect(kg, P, idir, tmin, tmax, node_addr, visibility, dist);
}
}
diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h
index 2f58929c1e5..db3c91569aa 100644
--- a/intern/cycles/kernel/bvh/shadow_all.h
+++ b/intern/cycles/kernel/bvh/shadow_all.h
@@ -49,6 +49,7 @@ ccl_device_inline
float3 P = ray->P;
float3 dir = bvh_clamp_direction(ray->D);
float3 idir = bvh_inverse_direction(dir);
+ float tmin = ray->tmin;
int object = OBJECT_NONE;
uint num_hits = 0;
@@ -59,12 +60,12 @@ ccl_device_inline
/* Max distance in world space. May be dynamically reduced when max number of
* recorded hits is exceeded and we no longer need to find hits beyond the max
* distance found. */
- float t_max_world = ray->t;
+ float t_max_world = ray->tmax;
/* Current maximum distance to the intersection.
* Is calculated as a ray length, transformed to an object space when entering
* instance node. */
- float t_max_current = ray->t;
+ float t_max_current = ray->tmax;
/* Conversion from world to local space for the current instance if any, 1.0
* otherwise. */
@@ -80,7 +81,7 @@ ccl_device_inline
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
int node_addr_child1, traverse_mask;
float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+ float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
traverse_mask = NODE_INTERSECT(kg,
P,
@@ -88,6 +89,7 @@ ccl_device_inline
dir,
#endif
idir,
+ tmin,
t_max_current,
node_addr,
visibility,
@@ -124,7 +126,7 @@ ccl_device_inline
/* if node is leaf, fetch triangle list */
if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
int prim_addr = __float_as_int(leaf.x);
if (prim_addr >= 0) {
@@ -137,7 +139,7 @@ ccl_device_inline
/* primitive intersection */
for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) ==
+ kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
(type & PRIMITIVE_ALL));
bool hit;
@@ -147,17 +149,25 @@ ccl_device_inline
Intersection isect ccl_optional_struct_init;
const int prim_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
+ kernel_data_fetch(prim_object, prim_addr) :
object;
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int prim = kernel_data_fetch(prim_index, prim_addr);
if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
continue;
}
switch (type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
- hit = triangle_intersect(
- kg, &isect, P, dir, t_max_current, visibility, prim_object, prim, prim_addr);
+ hit = triangle_intersect(kg,
+ &isect,
+ P,
+ dir,
+ tmin,
+ t_max_current,
+ visibility,
+ prim_object,
+ prim,
+ prim_addr);
break;
}
#if BVH_FEATURE(BVH_MOTION)
@@ -166,6 +176,7 @@ ccl_device_inline
&isect,
P,
dir,
+ tmin,
t_max_current,
ray->time,
visibility,
@@ -181,16 +192,24 @@ ccl_device_inline
case PRIMITIVE_CURVE_RIBBON:
case PRIMITIVE_MOTION_CURVE_RIBBON: {
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
- const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
if (ray->time < prim_time.x || ray->time > prim_time.y) {
hit = false;
break;
}
}
- const int curve_type = kernel_tex_fetch(__prim_type, prim_addr);
- hit = curve_intersect(
- kg, &isect, P, dir, t_max_current, prim_object, prim, ray->time, curve_type);
+ const int curve_type = kernel_data_fetch(prim_type, prim_addr);
+ hit = curve_intersect(kg,
+ &isect,
+ P,
+ dir,
+ tmin,
+ t_max_current,
+ prim_object,
+ prim,
+ ray->time,
+ curve_type);
break;
}
@@ -199,16 +218,24 @@ ccl_device_inline
case PRIMITIVE_POINT:
case PRIMITIVE_MOTION_POINT: {
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
- const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
if (ray->time < prim_time.x || ray->time > prim_time.y) {
hit = false;
break;
}
}
- const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
- hit = point_intersect(
- kg, &isect, P, dir, t_max_current, prim_object, prim, ray->time, point_type);
+ const int point_type = kernel_data_fetch(prim_type, prim_addr);
+ hit = point_intersect(kg,
+ &isect,
+ P,
+ dir,
+ tmin,
+ t_max_current,
+ prim_object,
+ prim,
+ ray->time,
+ point_type);
break;
}
#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
@@ -291,7 +318,7 @@ ccl_device_inline
}
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
+ object = kernel_data_fetch(prim_object, -prim_addr - 1);
#if BVH_FEATURE(BVH_MOTION)
t_world_to_instance = bvh_instance_motion_push(
@@ -302,12 +329,13 @@ ccl_device_inline
/* Convert intersection to object space. */
t_max_current *= t_world_to_instance;
+ tmin *= t_world_to_instance;
++stack_ptr;
kernel_assert(stack_ptr < BVH_STACK_SIZE);
traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- node_addr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_data_fetch(object_node, object);
}
}
} while (node_addr != ENTRYPOINT_SENTINEL);
@@ -323,7 +351,8 @@ ccl_device_inline
#endif
/* Restore world space ray length. */
- t_max_current = ray->t;
+ tmin = ray->tmin;
+ t_max_current = ray->tmax;
object = OBJECT_NONE;
t_world_to_instance = 1.0f;
diff --git a/intern/cycles/kernel/bvh/traversal.h b/intern/cycles/kernel/bvh/traversal.h
index 1181d4bfdee..0ff38bf02de 100644
--- a/intern/cycles/kernel/bvh/traversal.h
+++ b/intern/cycles/kernel/bvh/traversal.h
@@ -43,13 +43,14 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
float3 P = ray->P;
float3 dir = bvh_clamp_direction(ray->D);
float3 idir = bvh_inverse_direction(dir);
+ float tmin = ray->tmin;
int object = OBJECT_NONE;
#if BVH_FEATURE(BVH_MOTION)
Transform ob_itfm;
#endif
- isect->t = ray->t;
+ isect->t = ray->tmax;
isect->u = 0.0f;
isect->v = 0.0f;
isect->prim = PRIM_NONE;
@@ -62,7 +63,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
int node_addr_child1, traverse_mask;
float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+ float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
{
traverse_mask = NODE_INTERSECT(kg,
@@ -71,6 +72,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
dir,
#endif
idir,
+ tmin,
isect->t,
node_addr,
visibility,
@@ -108,7 +110,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
/* if node is leaf, fetch triangle list */
if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
int prim_addr = __float_as_int(leaf.x);
if (prim_addr >= 0) {
@@ -121,20 +123,28 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
/* primitive intersection */
for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
const int prim_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
+ kernel_data_fetch(prim_object, prim_addr) :
object;
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int prim = kernel_data_fetch(prim_index, prim_addr);
if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
continue;
}
switch (type & PRIMITIVE_ALL) {
case PRIMITIVE_TRIANGLE: {
- if (triangle_intersect(
- kg, isect, P, dir, isect->t, visibility, prim_object, prim, prim_addr)) {
+ if (triangle_intersect(kg,
+ isect,
+ P,
+ dir,
+ tmin,
+ isect->t,
+ visibility,
+ prim_object,
+ prim,
+ prim_addr)) {
/* shadow ray early termination */
if (visibility & PATH_RAY_SHADOW_OPAQUE)
return true;
@@ -147,6 +157,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
isect,
P,
dir,
+ tmin,
isect->t,
ray->time,
visibility,
@@ -166,15 +177,15 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
case PRIMITIVE_CURVE_RIBBON:
case PRIMITIVE_MOTION_CURVE_RIBBON: {
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
- const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
if (ray->time < prim_time.x || ray->time > prim_time.y) {
break;
}
}
- const int curve_type = kernel_tex_fetch(__prim_type, prim_addr);
+ const int curve_type = kernel_data_fetch(prim_type, prim_addr);
const bool hit = curve_intersect(
- kg, isect, P, dir, isect->t, prim_object, prim, ray->time, curve_type);
+ kg, isect, P, dir, tmin, isect->t, prim_object, prim, ray->time, curve_type);
if (hit) {
/* shadow ray early termination */
if (visibility & PATH_RAY_SHADOW_OPAQUE)
@@ -187,15 +198,15 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
case PRIMITIVE_POINT:
case PRIMITIVE_MOTION_POINT: {
if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
- const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
+ const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
if (ray->time < prim_time.x || ray->time > prim_time.y) {
break;
}
}
- const int point_type = kernel_tex_fetch(__prim_type, prim_addr);
+ const int point_type = kernel_data_fetch(prim_type, prim_addr);
const bool hit = point_intersect(
- kg, isect, P, dir, isect->t, prim_object, prim, ray->time, point_type);
+ kg, isect, P, dir, tmin, isect->t, prim_object, prim, ray->time, point_type);
if (hit) {
/* shadow ray early termination */
if (visibility & PATH_RAY_SHADOW_OPAQUE)
@@ -209,19 +220,23 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
}
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
+ object = kernel_data_fetch(prim_object, -prim_addr - 1);
#if BVH_FEATURE(BVH_MOTION)
- isect->t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
+ const float t_world_to_instance = bvh_instance_motion_push(
+ kg, object, ray, &P, &dir, &idir, &ob_itfm);
#else
- isect->t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
+ const float t_world_to_instance = bvh_instance_push(kg, object, ray, &P, &dir, &idir);
#endif
+ isect->t *= t_world_to_instance;
+ tmin *= t_world_to_instance;
+
++stack_ptr;
kernel_assert(stack_ptr < BVH_STACK_SIZE);
traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- node_addr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_data_fetch(object_node, object);
}
}
} while (node_addr != ENTRYPOINT_SENTINEL);
@@ -235,6 +250,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
#else
isect->t = bvh_instance_pop(kg, object, ray, &P, &dir, &idir, isect->t);
#endif
+ tmin = ray->tmin;
object = OBJECT_NONE;
node_addr = traversal_stack[stack_ptr];
diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h
index 71045157372..1795ae4c790 100644
--- a/intern/cycles/kernel/bvh/util.h
+++ b/intern/cycles/kernel/bvh/util.h
@@ -5,6 +5,19 @@
CCL_NAMESPACE_BEGIN
+/* Offset intersection distance by the smallest possible amount, to skip
+ * intersections at this distance. This works in cases where the ray start
+ * position is unchanged and only tmin is updated, since for self
+ * intersection we'll be comparing against the exact same distances. */
+ccl_device_forceinline float intersection_t_offset(const float t)
+{
+ /* This is a simplified version of nextafterf(t, FLT_MAX), only dealing with
+ * non-negative and finite t. */
+ kernel_assert(t >= 0.0f && isfinite_safe(t));
+ const uint32_t bits = (t == 0.0f) ? 1 : __float_as_uint(t) + 1;
+ return __uint_as_float(bits);
+}
+
#if defined(__KERNEL_CPU__)
ccl_device int intersections_compare(const void *a, const void *b)
{
@@ -53,20 +66,20 @@ ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg,
int shader = 0;
if (type & PRIMITIVE_TRIANGLE) {
- shader = kernel_tex_fetch(__tri_shader, prim);
+ shader = kernel_data_fetch(tri_shader, prim);
}
#ifdef __POINTCLOUD__
else if (type & PRIMITIVE_POINT) {
- shader = kernel_tex_fetch(__points_shader, prim);
+ shader = kernel_data_fetch(points_shader, prim);
}
#endif
#ifdef __HAIR__
else if (type & PRIMITIVE_CURVE) {
- shader = kernel_tex_fetch(__curves, prim).shader_id;
+ shader = kernel_data_fetch(curves, prim).shader_id;
}
#endif
- return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).flags;
+ return kernel_data_fetch(shaders, (shader & SHADER_MASK)).flags;
}
ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals kg,
@@ -76,16 +89,16 @@ ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals
int shader = 0;
if (isect_type & PRIMITIVE_TRIANGLE) {
- shader = kernel_tex_fetch(__tri_shader, prim);
+ shader = kernel_data_fetch(tri_shader, prim);
}
#ifdef __POINTCLOUD__
else if (isect_type & PRIMITIVE_POINT) {
- shader = kernel_tex_fetch(__points_shader, prim);
+ shader = kernel_data_fetch(points_shader, prim);
}
#endif
#ifdef __HAIR__
else if (isect_type & PRIMITIVE_CURVE) {
- shader = kernel_tex_fetch(__curves, prim).shader_id;
+ shader = kernel_data_fetch(curves, prim).shader_id;
}
#endif
@@ -101,7 +114,7 @@ ccl_device_forceinline int intersection_get_shader(
ccl_device_forceinline int intersection_get_object_flags(
KernelGlobals kg, ccl_private const Intersection *ccl_restrict isect)
{
- return kernel_tex_fetch(__object_flag, isect->object);
+ return kernel_data_fetch(object_flag, isect->object);
}
/* TODO: find a better (faster) solution for this. Maybe store offset per object for
@@ -110,27 +123,27 @@ ccl_device_inline int intersection_find_attribute(KernelGlobals kg,
const int object,
const uint id)
{
- uint attr_offset = kernel_tex_fetch(__objects, object).attribute_map_offset;
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ uint attr_offset = kernel_data_fetch(objects, object).attribute_map_offset;
+ AttributeMap attr_map = kernel_data_fetch(attributes_map, attr_offset);
- while (attr_map.x != id) {
- if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
- if (UNLIKELY(attr_map.y == 0)) {
+ while (attr_map.id != id) {
+ if (UNLIKELY(attr_map.id == ATTR_STD_NONE)) {
+ if (UNLIKELY(attr_map.element == 0)) {
return (int)ATTR_STD_NOT_FOUND;
}
else {
/* Chain jump to a different part of the table. */
- attr_offset = attr_map.z;
+ attr_offset = attr_map.offset;
}
}
else {
attr_offset += ATTR_PRIM_TYPES;
}
- attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ attr_map = kernel_data_fetch(attributes_map, attr_offset);
}
/* return result */
- return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
+ return (attr_map.element == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.offset;
}
/* Transparent Shadows */
@@ -151,12 +164,12 @@ ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg,
}
/* Interpolate transparency between curve keys. */
- const KernelCurve kcurve = kernel_tex_fetch(__curves, prim);
+ const KernelCurve kcurve = kernel_data_fetch(curves, prim);
const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(kcurve.type);
const int k1 = k0 + 1;
- const float f0 = kernel_tex_fetch(__attributes_float, offset + k0);
- const float f1 = kernel_tex_fetch(__attributes_float, offset + k1);
+ const float f0 = kernel_data_fetch(attributes_float, offset + k0);
+ const float f1 = kernel_data_fetch(attributes_float, offset + k1);
return (1.0f - u) * f0 + u * f1;
}
diff --git a/intern/cycles/kernel/bvh/volume.h b/intern/cycles/kernel/bvh/volume.h
index d711b3abbf4..bd4e508ecac 100644
--- a/intern/cycles/kernel/bvh/volume.h
+++ b/intern/cycles/kernel/bvh/volume.h
@@ -46,13 +46,14 @@ ccl_device_inline
float3 P = ray->P;
float3 dir = bvh_clamp_direction(ray->D);
float3 idir = bvh_inverse_direction(dir);
+ float tmin = ray->tmin;
int object = OBJECT_NONE;
#if BVH_FEATURE(BVH_MOTION)
Transform ob_itfm;
#endif
- isect->t = ray->t;
+ isect->t = ray->tmax;
isect->u = 0.0f;
isect->v = 0.0f;
isect->prim = PRIM_NONE;
@@ -65,7 +66,7 @@ ccl_device_inline
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
int node_addr_child1, traverse_mask;
float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+ float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
traverse_mask = NODE_INTERSECT(kg,
P,
@@ -73,6 +74,7 @@ ccl_device_inline
dir,
#endif
idir,
+ tmin,
isect->t,
node_addr,
visibility,
@@ -109,7 +111,7 @@ ccl_device_inline
/* if node is leaf, fetch triangle list */
if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
int prim_addr = __float_as_int(leaf.x);
if (prim_addr >= 0) {
@@ -125,22 +127,22 @@ ccl_device_inline
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
/* only primitives from volume object */
const int prim_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
+ kernel_data_fetch(prim_object, prim_addr) :
object;
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int prim = kernel_data_fetch(prim_index, prim_addr);
if (intersection_skip_self(ray->self, prim_object, prim)) {
continue;
}
- int object_flag = kernel_tex_fetch(__object_flag, prim_object);
+ int object_flag = kernel_data_fetch(object_flag, prim_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
triangle_intersect(
- kg, isect, P, dir, isect->t, visibility, prim_object, prim, prim_addr);
+ kg, isect, P, dir, tmin, isect->t, visibility, prim_object, prim, prim_addr);
}
break;
}
@@ -148,16 +150,16 @@ ccl_device_inline
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
/* only primitives from volume object */
const int prim_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
+ kernel_data_fetch(prim_object, prim_addr) :
object;
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int prim = kernel_data_fetch(prim_index, prim_addr);
if (intersection_skip_self(ray->self, prim_object, prim)) {
continue;
}
- int object_flag = kernel_tex_fetch(__object_flag, prim_object);
+ int object_flag = kernel_data_fetch(object_flag, prim_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
@@ -165,6 +167,7 @@ ccl_device_inline
isect,
P,
dir,
+ tmin,
isect->t,
ray->time,
visibility,
@@ -182,20 +185,24 @@ ccl_device_inline
}
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
- int object_flag = kernel_tex_fetch(__object_flag, object);
+ object = kernel_data_fetch(prim_object, -prim_addr - 1);
+ int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_HAS_VOLUME) {
#if BVH_FEATURE(BVH_MOTION)
- isect->t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
+ const float t_world_to_instance = bvh_instance_motion_push(
+ kg, object, ray, &P, &dir, &idir, &ob_itfm);
#else
- isect->t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
+ const float t_world_to_instance = bvh_instance_push(kg, object, ray, &P, &dir, &idir);
#endif
+ isect->t *= t_world_to_instance;
+ tmin *= t_world_to_instance;
+
++stack_ptr;
kernel_assert(stack_ptr < BVH_STACK_SIZE);
traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- node_addr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_data_fetch(object_node, object);
}
else {
/* pop */
@@ -217,6 +224,8 @@ ccl_device_inline
isect->t = bvh_instance_pop(kg, object, ray, &P, &dir, &idir, isect->t);
#endif
+ tmin = ray->tmin;
+
object = OBJECT_NONE;
node_addr = traversal_stack[stack_ptr];
--stack_ptr;
diff --git a/intern/cycles/kernel/bvh/volume_all.h b/intern/cycles/kernel/bvh/volume_all.h
index a969bae14a1..c6eeb07a14d 100644
--- a/intern/cycles/kernel/bvh/volume_all.h
+++ b/intern/cycles/kernel/bvh/volume_all.h
@@ -44,12 +44,12 @@ ccl_device_inline
int node_addr = kernel_data.bvh.root;
/* ray parameters in registers */
- const float tmax = ray->t;
float3 P = ray->P;
float3 dir = bvh_clamp_direction(ray->D);
float3 idir = bvh_inverse_direction(dir);
+ float tmin = ray->tmin;
int object = OBJECT_NONE;
- float isect_t = tmax;
+ float isect_t = ray->tmax;
#if BVH_FEATURE(BVH_MOTION)
Transform ob_itfm;
@@ -58,7 +58,7 @@ ccl_device_inline
int num_hits_in_instance = 0;
uint num_hits = 0;
- isect_array->t = tmax;
+ isect_array->t = ray->tmax;
/* traversal loop */
do {
@@ -67,7 +67,7 @@ ccl_device_inline
while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
int node_addr_child1, traverse_mask;
float dist[2];
- float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr + 0);
+ float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
traverse_mask = NODE_INTERSECT(kg,
P,
@@ -75,6 +75,7 @@ ccl_device_inline
dir,
#endif
idir,
+ tmin,
isect_t,
node_addr,
visibility,
@@ -111,7 +112,7 @@ ccl_device_inline
/* if node is leaf, fetch triangle list */
if (node_addr < 0) {
- float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr - 1));
+ float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
int prim_addr = __float_as_int(leaf.x);
if (prim_addr >= 0) {
@@ -128,21 +129,29 @@ ccl_device_inline
case PRIMITIVE_TRIANGLE: {
/* intersect ray against primitive */
for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
/* only primitives from volume object */
const int prim_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
+ kernel_data_fetch(prim_object, prim_addr) :
object;
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int prim = kernel_data_fetch(prim_index, prim_addr);
if (intersection_skip_self(ray->self, prim_object, prim)) {
continue;
}
- int object_flag = kernel_tex_fetch(__object_flag, prim_object);
+ int object_flag = kernel_data_fetch(object_flag, prim_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
- hit = triangle_intersect(
- kg, isect_array, P, dir, isect_t, visibility, prim_object, prim, prim_addr);
+ hit = triangle_intersect(kg,
+ isect_array,
+ P,
+ dir,
+ tmin,
+ isect_t,
+ visibility,
+ prim_object,
+ prim,
+ prim_addr);
if (hit) {
/* Move on to next entry in intersections array. */
isect_array++;
@@ -172,16 +181,16 @@ ccl_device_inline
case PRIMITIVE_MOTION_TRIANGLE: {
/* intersect ray against primitive */
for (; prim_addr < prim_addr2; prim_addr++) {
- kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type);
+ kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
/* only primitives from volume object */
const int prim_object = (object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, prim_addr) :
+ kernel_data_fetch(prim_object, prim_addr) :
object;
- const int prim = kernel_tex_fetch(__prim_index, prim_addr);
+ const int prim = kernel_data_fetch(prim_index, prim_addr);
if (intersection_skip_self(ray->self, prim_object, prim)) {
continue;
}
- int object_flag = kernel_tex_fetch(__object_flag, prim_object);
+ int object_flag = kernel_data_fetch(object_flag, prim_object);
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
continue;
}
@@ -189,6 +198,7 @@ ccl_device_inline
isect_array,
P,
dir,
+ tmin,
isect_t,
ray->time,
visibility,
@@ -228,15 +238,19 @@ ccl_device_inline
}
else {
/* instance push */
- object = kernel_tex_fetch(__prim_object, -prim_addr - 1);
- int object_flag = kernel_tex_fetch(__object_flag, object);
+ object = kernel_data_fetch(prim_object, -prim_addr - 1);
+ int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_HAS_VOLUME) {
#if BVH_FEATURE(BVH_MOTION)
- isect_t *= bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &ob_itfm);
+ const float t_world_to_instance = bvh_instance_motion_push(
+ kg, object, ray, &P, &dir, &idir, &ob_itfm);
#else
- isect_t *= bvh_instance_push(kg, object, ray, &P, &dir, &idir);
+ const float t_world_to_instance = bvh_instance_push(kg, object, ray, &P, &dir, &idir);
#endif
+ isect_t *= t_world_to_instance;
+ tmin *= t_world_to_instance;
+
num_hits_in_instance = 0;
isect_array->t = isect_t;
@@ -244,7 +258,7 @@ ccl_device_inline
kernel_assert(stack_ptr < BVH_STACK_SIZE);
traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL;
- node_addr = kernel_tex_fetch(__object_node, object);
+ node_addr = kernel_data_fetch(object_node, object);
}
else {
/* pop */
@@ -280,7 +294,8 @@ ccl_device_inline
#endif
}
- isect_t = tmax;
+ tmin = ray->tmin;
+ isect_t = ray->tmax;
isect_array->t = isect_t;
object = OBJECT_NONE;
diff --git a/intern/cycles/kernel/camera/camera.h b/intern/cycles/kernel/camera/camera.h
index aad68e527ac..926ccf7b86f 100644
--- a/intern/cycles/kernel/camera/camera.h
+++ b/intern/cycles/kernel/camera/camera.h
@@ -90,7 +90,7 @@ ccl_device void camera_sample_perspective(KernelGlobals kg,
#ifdef __CAMERA_MOTION__
if (kernel_data.cam.num_motion_steps) {
transform_motion_array_interpolate(&cameratoworld,
- kernel_tex_array(__camera_motion),
+ kernel_data_array(camera_motion),
kernel_data.cam.num_motion_steps,
ray->time);
}
@@ -165,9 +165,11 @@ ccl_device void camera_sample_perspective(KernelGlobals kg,
float nearclip = kernel_data.cam.nearclip * z_inv;
ray->P += nearclip * ray->D;
ray->dP += nearclip * ray->dD;
- ray->t = kernel_data.cam.cliplength * z_inv;
+ ray->tmin = 0.0f;
+ ray->tmax = kernel_data.cam.cliplength * z_inv;
#else
- ray->t = FLT_MAX;
+ ray->tmin = 0.0f;
+ ray->tmax = FLT_MAX;
#endif
}
@@ -210,7 +212,7 @@ ccl_device void camera_sample_orthographic(KernelGlobals kg,
#ifdef __CAMERA_MOTION__
if (kernel_data.cam.num_motion_steps) {
transform_motion_array_interpolate(&cameratoworld,
- kernel_tex_array(__camera_motion),
+ kernel_data_array(camera_motion),
kernel_data.cam.num_motion_steps,
ray->time);
}
@@ -231,9 +233,11 @@ ccl_device void camera_sample_orthographic(KernelGlobals kg,
#ifdef __CAMERA_CLIPPING__
/* clipping */
- ray->t = kernel_data.cam.cliplength;
+ ray->tmin = 0.0f;
+ ray->tmax = kernel_data.cam.cliplength;
#else
- ray->t = FLT_MAX;
+ ray->tmin = 0.0f;
+ ray->tmax = FLT_MAX;
#endif
}
@@ -258,7 +262,7 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
/* indicates ray should not receive any light, outside of the lens */
if (is_zero(D)) {
- ray->t = 0.0f;
+ ray->tmax = 0.0f;
return;
}
@@ -349,9 +353,11 @@ ccl_device_inline void camera_sample_panorama(ccl_constant KernelCamera *cam,
float nearclip = cam->nearclip;
ray->P += nearclip * ray->D;
ray->dP += nearclip * ray->dD;
- ray->t = cam->cliplength;
+ ray->tmin = 0.0f;
+ ray->tmax = cam->cliplength;
#else
- ray->t = FLT_MAX;
+ ray->tmin = 0.0f;
+ ray->tmax = FLT_MAX;
#endif
}
@@ -368,7 +374,7 @@ ccl_device_inline void camera_sample(KernelGlobals kg,
ccl_private Ray *ray)
{
/* pixel filter */
- int filter_table_offset = kernel_data.film.filter_table_offset;
+ int filter_table_offset = kernel_data.tables.filter_table_offset;
float raster_x = x + lookup_table_read(kg, filter_u, filter_table_offset, FILTER_TABLE_SIZE);
float raster_y = y + lookup_table_read(kg, filter_v, filter_table_offset, FILTER_TABLE_SIZE);
@@ -421,7 +427,7 @@ ccl_device_inline void camera_sample(KernelGlobals kg,
}
else {
#ifdef __CAMERA_MOTION__
- ccl_global const DecomposedTransform *cam_motion = kernel_tex_array(__camera_motion);
+ ccl_global const DecomposedTransform *cam_motion = kernel_data_array(camera_motion);
camera_sample_panorama(&kernel_data.cam, cam_motion, raster_x, raster_y, lens_u, lens_v, ray);
#else
camera_sample_panorama(&kernel_data.cam, raster_x, raster_y, lens_u, lens_v, ray);
diff --git a/intern/cycles/kernel/closure/alloc.h b/intern/cycles/kernel/closure/alloc.h
index a6975a63d5d..933c07a5102 100644
--- a/intern/cycles/kernel/closure/alloc.h
+++ b/intern/cycles/kernel/closure/alloc.h
@@ -51,7 +51,7 @@ ccl_device_inline ccl_private ShaderClosure *bsdf_alloc(ccl_private ShaderData *
int size,
float3 weight)
{
- kernel_assert(isfinite3_safe(weight));
+ kernel_assert(isfinite_safe(weight));
const float sample_weight = fabsf(average(weight));
@@ -77,7 +77,7 @@ ccl_device_inline ShaderClosure *bsdf_alloc_osl(ShaderData *sd,
float3 weight,
void *data)
{
- kernel_assert(isfinite3_safe(weight));
+ kernel_assert(isfinite_safe(weight));
const float sample_weight = fabsf(average(weight));
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index 011155cdf5f..4feb21c43e3 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -434,12 +434,12 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
else {
/* Shadow terminator offset. */
const float frequency_multiplier =
- kernel_tex_fetch(__objects, sd->object).shadow_terminator_shading_offset;
+ kernel_data_fetch(objects, sd->object).shadow_terminator_shading_offset;
if (frequency_multiplier > 1.0f) {
*eval *= shift_cos_in(dot(*omega_in, sc->N), frequency_multiplier);
}
if (label & LABEL_DIFFUSE) {
- if (!isequal_float3(sc->N, sd->N)) {
+ if (!isequal(sc->N, sd->N)) {
*eval *= bump_shadowing_term((label & LABEL_TRANSMIT) ? -sd->N : sd->N, sc->N, *omega_in);
}
}
@@ -550,13 +550,13 @@ ccl_device_inline
break;
}
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
- if (!isequal_float3(sc->N, sd->N)) {
+ if (!isequal(sc->N, sd->N)) {
eval *= bump_shadowing_term(sd->N, sc->N, omega_in);
}
}
/* Shadow terminator offset. */
const float frequency_multiplier =
- kernel_tex_fetch(__objects, sd->object).shadow_terminator_shading_offset;
+ kernel_data_fetch(objects, sd->object).shadow_terminator_shading_offset;
if (frequency_multiplier > 1.0f) {
eval *= shift_cos_in(dot(omega_in, sc->N), frequency_multiplier);
}
@@ -635,7 +635,7 @@ ccl_device_inline
break;
}
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
- if (!isequal_float3(sc->N, sd->N)) {
+ if (!isequal(sc->N, sd->N)) {
eval *= bump_shadowing_term(-sd->N, sc->N, omega_in);
}
}
diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h
index 33706213403..2cdf6c9f349 100644
--- a/intern/cycles/kernel/closure/bsdf_hair_principled.h
+++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h
@@ -203,7 +203,7 @@ ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd,
float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : dot(cross(sd->Ng, X), Z);
kernel_assert(fabsf(h) < 1.0f + 1e-4f);
- kernel_assert(isfinite3_safe(Y));
+ kernel_assert(isfinite_safe(Y));
kernel_assert(isfinite_safe(h));
bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h);
@@ -272,7 +272,7 @@ ccl_device float3 bsdf_principled_hair_eval(KernelGlobals kg,
const float3 omega_in,
ccl_private float *pdf)
{
- kernel_assert(isfinite3_safe(sd->P) && isfinite_safe(sd->ray_length));
+ kernel_assert(isfinite_safe(sd->P) && isfinite_safe(sd->ray_length));
ccl_private const PrincipledHairBSDF *bsdf = (ccl_private const PrincipledHairBSDF *)sc;
float3 Y = float4_to_float3(bsdf->extra->geom);
@@ -299,7 +299,7 @@ ccl_device float3 bsdf_principled_hair_eval(KernelGlobals kg,
float cos_gamma_t = cos_from_sin(sin_gamma_t);
float gamma_t = safe_asinf(sin_gamma_t);
- float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
+ float3 T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
float4 Ap[4];
hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap);
@@ -319,25 +319,25 @@ ccl_device float3 bsdf_principled_hair_eval(KernelGlobals kg,
Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness);
Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t);
F = Ap[0] * Mp * Np;
- kernel_assert(isfinite3_safe(float4_to_float3(F)));
+ kernel_assert(isfinite_safe(float4_to_float3(F)));
/* Transmission (TT). */
Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f * bsdf->v);
Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t);
F += Ap[1] * Mp * Np;
- kernel_assert(isfinite3_safe(float4_to_float3(F)));
+ kernel_assert(isfinite_safe(float4_to_float3(F)));
/* Secondary specular (TRT). */
Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f * bsdf->v);
Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t);
F += Ap[2] * Mp * Np;
- kernel_assert(isfinite3_safe(float4_to_float3(F)));
+ kernel_assert(isfinite_safe(float4_to_float3(F)));
/* Residual component (TRRT+). */
Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v);
Np = M_1_2PI_F;
F += Ap[3] * Mp * Np;
- kernel_assert(isfinite3_safe(float4_to_float3(F)));
+ kernel_assert(isfinite_safe(float4_to_float3(F)));
*pdf = F.w;
return float4_to_float3(F);
@@ -385,7 +385,7 @@ ccl_device int bsdf_principled_hair_sample(KernelGlobals kg,
float cos_gamma_t = cos_from_sin(sin_gamma_t);
float gamma_t = safe_asinf(sin_gamma_t);
- float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
+ float3 T = exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
float4 Ap[4];
hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap);
@@ -436,25 +436,25 @@ ccl_device int bsdf_principled_hair_sample(KernelGlobals kg,
Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness);
Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t);
F = Ap[0] * Mp * Np;
- kernel_assert(isfinite3_safe(float4_to_float3(F)));
+ kernel_assert(isfinite_safe(float4_to_float3(F)));
/* Transmission (TT). */
Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f * bsdf->v);
Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t);
F += Ap[1] * Mp * Np;
- kernel_assert(isfinite3_safe(float4_to_float3(F)));
+ kernel_assert(isfinite_safe(float4_to_float3(F)));
/* Secondary specular (TRT). */
Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f * bsdf->v);
Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t);
F += Ap[2] * Mp * Np;
- kernel_assert(isfinite3_safe(float4_to_float3(F)));
+ kernel_assert(isfinite_safe(float4_to_float3(F)));
/* Residual component (TRRT+). */
Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v);
Np = M_1_2PI_F;
F += Ap[3] * Mp * Np;
- kernel_assert(isfinite3_safe(float4_to_float3(F)));
+ kernel_assert(isfinite_safe(float4_to_float3(F)));
*eval = float4_to_float3(F);
*pdf = F.w;
@@ -492,13 +492,13 @@ ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(
ccl_device float3 bsdf_principled_hair_albedo(ccl_private const ShaderClosure *sc)
{
ccl_private PrincipledHairBSDF *bsdf = (ccl_private PrincipledHairBSDF *)sc;
- return exp3(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v));
+ return exp(-sqrt(bsdf->sigma) * bsdf_principled_hair_albedo_roughness_scale(bsdf->v));
}
ccl_device_inline float3
bsdf_principled_hair_sigma_from_reflectance(const float3 color, const float azimuthal_roughness)
{
- const float3 sigma = log3(color) /
+ const float3 sigma = log(color) /
bsdf_principled_hair_albedo_roughness_scale(azimuthal_roughness);
return sigma * sigma;
}
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index db50712f9f0..c6cbd1ffae7 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -310,7 +310,7 @@ ccl_device int bsdf_microfacet_ggx_isotropic_setup(ccl_private MicrofacetBsdf *b
ccl_device int bsdf_microfacet_ggx_fresnel_setup(ccl_private MicrofacetBsdf *bsdf,
ccl_private const ShaderData *sd)
{
- bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
+ bsdf->extra->cspec0 = saturate(bsdf->extra->cspec0);
bsdf->alpha_x = saturatef(bsdf->alpha_x);
bsdf->alpha_y = saturatef(bsdf->alpha_y);
@@ -325,7 +325,7 @@ ccl_device int bsdf_microfacet_ggx_fresnel_setup(ccl_private MicrofacetBsdf *bsd
ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *bsdf,
ccl_private const ShaderData *sd)
{
- bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
+ bsdf->extra->cspec0 = saturate(bsdf->extra->cspec0);
bsdf->alpha_x = saturatef(bsdf->alpha_x);
bsdf->alpha_y = bsdf->alpha_x;
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
index 10027ae9f77..b2e068daf17 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -377,8 +377,8 @@ ccl_device int bsdf_microfacet_multi_ggx_common_setup(ccl_private MicrofacetBsdf
{
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f);
- bsdf->extra->color = saturate3(bsdf->extra->color);
- bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
+ bsdf->extra->color = saturate(bsdf->extra->color);
+ bsdf->extra->cspec0 = saturate(bsdf->extra->cspec0);
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG;
}
@@ -565,7 +565,7 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ccl_private MicrofacetBsdf
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->ior = max(0.0f, bsdf->ior);
- bsdf->extra->color = saturate3(bsdf->extra->color);
+ bsdf->extra->color = saturate(bsdf->extra->color);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
@@ -578,8 +578,8 @@ ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(ccl_private Microfa
bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f);
bsdf->alpha_y = bsdf->alpha_x;
bsdf->ior = max(0.0f, bsdf->ior);
- bsdf->extra->color = saturate3(bsdf->extra->color);
- bsdf->extra->cspec0 = saturate3(bsdf->extra->cspec0);
+ bsdf->extra->color = saturate(bsdf->extra->color);
+ bsdf->extra->cspec0 = saturate(bsdf->extra->cspec0);
bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID;
diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h
index 6e24b60af39..ef414c7b821 100644
--- a/intern/cycles/kernel/closure/volume.h
+++ b/intern/cycles/kernel/closure/volume.h
@@ -166,7 +166,7 @@ ccl_device int volume_phase_sample(ccl_private const ShaderData *sd,
ccl_device float3 volume_color_transmittance(float3 sigma, float t)
{
- return exp3(-sigma * t);
+ return exp(-sigma * t);
}
ccl_device float volume_channel_get(float3 value, int channel)
diff --git a/intern/cycles/kernel/data_arrays.h b/intern/cycles/kernel/data_arrays.h
new file mode 100644
index 00000000000..7205f728088
--- /dev/null
+++ b/intern/cycles/kernel/data_arrays.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#ifndef KERNEL_DATA_ARRAY
+# define KERNEL_DATA_ARRAY(type, name)
+#endif
+
+/* BVH2, not used for OptiX or Embree. */
+KERNEL_DATA_ARRAY(float4, bvh_nodes)
+KERNEL_DATA_ARRAY(float4, bvh_leaf_nodes)
+KERNEL_DATA_ARRAY(uint, prim_type)
+KERNEL_DATA_ARRAY(uint, prim_visibility)
+KERNEL_DATA_ARRAY(uint, prim_index)
+KERNEL_DATA_ARRAY(uint, prim_object)
+KERNEL_DATA_ARRAY(uint, object_node)
+KERNEL_DATA_ARRAY(float2, prim_time)
+
+/* objects */
+KERNEL_DATA_ARRAY(KernelObject, objects)
+KERNEL_DATA_ARRAY(Transform, object_motion_pass)
+KERNEL_DATA_ARRAY(DecomposedTransform, object_motion)
+KERNEL_DATA_ARRAY(uint, object_flag)
+KERNEL_DATA_ARRAY(float, object_volume_step)
+KERNEL_DATA_ARRAY(uint, object_prim_offset)
+
+/* cameras */
+KERNEL_DATA_ARRAY(DecomposedTransform, camera_motion)
+
+/* triangles */
+KERNEL_DATA_ARRAY(uint, tri_shader)
+KERNEL_DATA_ARRAY(packed_float3, tri_vnormal)
+KERNEL_DATA_ARRAY(uint4, tri_vindex)
+KERNEL_DATA_ARRAY(uint, tri_patch)
+KERNEL_DATA_ARRAY(float2, tri_patch_uv)
+KERNEL_DATA_ARRAY(packed_float3, tri_verts)
+
+/* curves */
+KERNEL_DATA_ARRAY(KernelCurve, curves)
+KERNEL_DATA_ARRAY(float4, curve_keys)
+KERNEL_DATA_ARRAY(KernelCurveSegment, curve_segments)
+
+/* patches */
+KERNEL_DATA_ARRAY(uint, patches)
+
+/* pointclouds */
+KERNEL_DATA_ARRAY(float4, points)
+KERNEL_DATA_ARRAY(uint, points_shader)
+
+/* attributes */
+KERNEL_DATA_ARRAY(AttributeMap, attributes_map)
+KERNEL_DATA_ARRAY(float, attributes_float)
+KERNEL_DATA_ARRAY(float2, attributes_float2)
+KERNEL_DATA_ARRAY(packed_float3, attributes_float3)
+KERNEL_DATA_ARRAY(float4, attributes_float4)
+KERNEL_DATA_ARRAY(uchar4, attributes_uchar4)
+
+/* lights */
+KERNEL_DATA_ARRAY(KernelLightDistribution, light_distribution)
+KERNEL_DATA_ARRAY(KernelLight, lights)
+KERNEL_DATA_ARRAY(float2, light_background_marginal_cdf)
+KERNEL_DATA_ARRAY(float2, light_background_conditional_cdf)
+
+/* particles */
+KERNEL_DATA_ARRAY(KernelParticle, particles)
+
+/* shaders */
+KERNEL_DATA_ARRAY(uint4, svm_nodes)
+KERNEL_DATA_ARRAY(KernelShader, shaders)
+
+/* lookup tables */
+KERNEL_DATA_ARRAY(float, lookup_table)
+
+/* sobol */
+KERNEL_DATA_ARRAY(float, sample_pattern_lut)
+
+/* image textures */
+KERNEL_DATA_ARRAY(TextureInfo, texture_info)
+
+/* ies lights */
+KERNEL_DATA_ARRAY(float, ies)
+
+#undef KERNEL_DATA_ARRAY
diff --git a/intern/cycles/kernel/data_template.h b/intern/cycles/kernel/data_template.h
new file mode 100644
index 00000000000..b06ac62a5d8
--- /dev/null
+++ b/intern/cycles/kernel/data_template.h
@@ -0,0 +1,206 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#ifndef KERNEL_STRUCT_BEGIN
+# define KERNEL_STRUCT_BEGIN(name, parent)
+#endif
+#ifndef KERNEL_STRUCT_END
+# define KERNEL_STRUCT_END(name)
+#endif
+#ifndef KERNEL_STRUCT_MEMBER
+# define KERNEL_STRUCT_MEMBER(parent, type, name)
+#endif
+
+/* Background. */
+
+KERNEL_STRUCT_BEGIN(KernelBackground, background)
+/* xyz store direction, w the angle. float4 instead of float3 is used
+ * to ensure consistent padding/alignment across devices. */
+KERNEL_STRUCT_MEMBER(background, float4, sun)
+/* Only shader index. */
+KERNEL_STRUCT_MEMBER(background, int, surface_shader)
+KERNEL_STRUCT_MEMBER(background, int, volume_shader)
+KERNEL_STRUCT_MEMBER(background, float, volume_step_size)
+KERNEL_STRUCT_MEMBER(background, int, transparent)
+KERNEL_STRUCT_MEMBER(background, float, transparent_roughness_squared_threshold)
+/* Portal sampling. */
+KERNEL_STRUCT_MEMBER(background, float, portal_weight)
+KERNEL_STRUCT_MEMBER(background, int, num_portals)
+KERNEL_STRUCT_MEMBER(background, int, portal_offset)
+/* Sun sampling. */
+KERNEL_STRUCT_MEMBER(background, float, sun_weight)
+/* Importance map sampling. */
+KERNEL_STRUCT_MEMBER(background, float, map_weight)
+KERNEL_STRUCT_MEMBER(background, int, map_res_x)
+KERNEL_STRUCT_MEMBER(background, int, map_res_y)
+/* Multiple importance sampling. */
+KERNEL_STRUCT_MEMBER(background, int, use_mis)
+/* Lightgroup. */
+KERNEL_STRUCT_MEMBER(background, int, lightgroup)
+/* Padding. */
+KERNEL_STRUCT_MEMBER(background, int, pad1)
+KERNEL_STRUCT_MEMBER(background, int, pad2)
+KERNEL_STRUCT_MEMBER(background, int, pad3)
+KERNEL_STRUCT_END(KernelBackground)
+
+/* BVH: own BVH2 if no native device acceleration struct used. */
+
+KERNEL_STRUCT_BEGIN(KernelBVH, bvh)
+KERNEL_STRUCT_MEMBER(bvh, int, root)
+KERNEL_STRUCT_MEMBER(bvh, int, have_motion)
+KERNEL_STRUCT_MEMBER(bvh, int, have_curves)
+KERNEL_STRUCT_MEMBER(bvh, int, bvh_layout)
+KERNEL_STRUCT_MEMBER(bvh, int, use_bvh_steps)
+KERNEL_STRUCT_MEMBER(bvh, int, curve_subdivisions)
+KERNEL_STRUCT_MEMBER(bvh, int, pad1)
+KERNEL_STRUCT_MEMBER(bvh, int, pad2)
+KERNEL_STRUCT_END(KernelBVH)
+
+/* Film. */
+
+KERNEL_STRUCT_BEGIN(KernelFilm, film)
+/* XYZ to rendering color space transform. float4 instead of float3 to
+ * ensure consistent padding/alignment across devices. */
+KERNEL_STRUCT_MEMBER(film, float4, xyz_to_r)
+KERNEL_STRUCT_MEMBER(film, float4, xyz_to_g)
+KERNEL_STRUCT_MEMBER(film, float4, xyz_to_b)
+KERNEL_STRUCT_MEMBER(film, float4, rgb_to_y)
+/* Rec709 to rendering color space. */
+KERNEL_STRUCT_MEMBER(film, float4, rec709_to_r)
+KERNEL_STRUCT_MEMBER(film, float4, rec709_to_g)
+KERNEL_STRUCT_MEMBER(film, float4, rec709_to_b)
+KERNEL_STRUCT_MEMBER(film, int, is_rec709)
+/* Exposuse. */
+KERNEL_STRUCT_MEMBER(film, float, exposure)
+/* Passed used. */
+KERNEL_STRUCT_MEMBER(film, int, pass_flag)
+KERNEL_STRUCT_MEMBER(film, int, light_pass_flag)
+/* Pass offsets. */
+KERNEL_STRUCT_MEMBER(film, int, pass_stride)
+KERNEL_STRUCT_MEMBER(film, int, pass_combined)
+KERNEL_STRUCT_MEMBER(film, int, pass_depth)
+KERNEL_STRUCT_MEMBER(film, int, pass_position)
+KERNEL_STRUCT_MEMBER(film, int, pass_normal)
+KERNEL_STRUCT_MEMBER(film, int, pass_roughness)
+KERNEL_STRUCT_MEMBER(film, int, pass_motion)
+KERNEL_STRUCT_MEMBER(film, int, pass_motion_weight)
+KERNEL_STRUCT_MEMBER(film, int, pass_uv)
+KERNEL_STRUCT_MEMBER(film, int, pass_object_id)
+KERNEL_STRUCT_MEMBER(film, int, pass_material_id)
+KERNEL_STRUCT_MEMBER(film, int, pass_diffuse_color)
+KERNEL_STRUCT_MEMBER(film, int, pass_glossy_color)
+KERNEL_STRUCT_MEMBER(film, int, pass_transmission_color)
+KERNEL_STRUCT_MEMBER(film, int, pass_diffuse_indirect)
+KERNEL_STRUCT_MEMBER(film, int, pass_glossy_indirect)
+KERNEL_STRUCT_MEMBER(film, int, pass_transmission_indirect)
+KERNEL_STRUCT_MEMBER(film, int, pass_volume_indirect)
+KERNEL_STRUCT_MEMBER(film, int, pass_diffuse_direct)
+KERNEL_STRUCT_MEMBER(film, int, pass_glossy_direct)
+KERNEL_STRUCT_MEMBER(film, int, pass_transmission_direct)
+KERNEL_STRUCT_MEMBER(film, int, pass_volume_direct)
+KERNEL_STRUCT_MEMBER(film, int, pass_emission)
+KERNEL_STRUCT_MEMBER(film, int, pass_background)
+KERNEL_STRUCT_MEMBER(film, int, pass_ao)
+KERNEL_STRUCT_MEMBER(film, float, pass_alpha_threshold)
+KERNEL_STRUCT_MEMBER(film, int, pass_shadow)
+KERNEL_STRUCT_MEMBER(film, float, pass_shadow_scale)
+KERNEL_STRUCT_MEMBER(film, int, pass_shadow_catcher)
+KERNEL_STRUCT_MEMBER(film, int, pass_shadow_catcher_sample_count)
+KERNEL_STRUCT_MEMBER(film, int, pass_shadow_catcher_matte)
+/* Cryptomatte. */
+KERNEL_STRUCT_MEMBER(film, int, cryptomatte_passes)
+KERNEL_STRUCT_MEMBER(film, int, cryptomatte_depth)
+KERNEL_STRUCT_MEMBER(film, int, pass_cryptomatte)
+/* Adaptive sampling. */
+KERNEL_STRUCT_MEMBER(film, int, pass_adaptive_aux_buffer)
+KERNEL_STRUCT_MEMBER(film, int, pass_sample_count)
+/* Mist. */
+KERNEL_STRUCT_MEMBER(film, int, pass_mist)
+KERNEL_STRUCT_MEMBER(film, float, mist_start)
+KERNEL_STRUCT_MEMBER(film, float, mist_inv_depth)
+KERNEL_STRUCT_MEMBER(film, float, mist_falloff)
+/* Denoising. */
+KERNEL_STRUCT_MEMBER(film, int, pass_denoising_normal)
+KERNEL_STRUCT_MEMBER(film, int, pass_denoising_albedo)
+KERNEL_STRUCT_MEMBER(film, int, pass_denoising_depth)
+/* AOVs. */
+KERNEL_STRUCT_MEMBER(film, int, pass_aov_color)
+KERNEL_STRUCT_MEMBER(film, int, pass_aov_value)
+/* Light groups. */
+KERNEL_STRUCT_MEMBER(film, int, pass_lightgroup)
+/* Baking. */
+KERNEL_STRUCT_MEMBER(film, int, pass_bake_primitive)
+KERNEL_STRUCT_MEMBER(film, int, pass_bake_differential)
+/* Shadow catcher. */
+KERNEL_STRUCT_MEMBER(film, int, use_approximate_shadow_catcher)
+/* Padding. */
+KERNEL_STRUCT_MEMBER(film, int, pad1)
+KERNEL_STRUCT_MEMBER(film, int, pad2)
+KERNEL_STRUCT_END(KernelFilm)
+
+/* Integrator. */
+
+KERNEL_STRUCT_BEGIN(KernelIntegrator, integrator)
+/* Emission. */
+KERNEL_STRUCT_MEMBER(integrator, int, use_direct_light)
+KERNEL_STRUCT_MEMBER(integrator, int, num_distribution)
+KERNEL_STRUCT_MEMBER(integrator, int, num_all_lights)
+KERNEL_STRUCT_MEMBER(integrator, float, pdf_triangles)
+KERNEL_STRUCT_MEMBER(integrator, float, pdf_lights)
+KERNEL_STRUCT_MEMBER(integrator, float, light_inv_rr_threshold)
+/* Bounces. */
+KERNEL_STRUCT_MEMBER(integrator, int, min_bounce)
+KERNEL_STRUCT_MEMBER(integrator, int, max_bounce)
+KERNEL_STRUCT_MEMBER(integrator, int, max_diffuse_bounce)
+KERNEL_STRUCT_MEMBER(integrator, int, max_glossy_bounce)
+KERNEL_STRUCT_MEMBER(integrator, int, max_transmission_bounce)
+KERNEL_STRUCT_MEMBER(integrator, int, max_volume_bounce)
+/* AO bounces. */
+KERNEL_STRUCT_MEMBER(integrator, int, ao_bounces)
+KERNEL_STRUCT_MEMBER(integrator, float, ao_bounces_distance)
+KERNEL_STRUCT_MEMBER(integrator, float, ao_bounces_factor)
+KERNEL_STRUCT_MEMBER(integrator, float, ao_additive_factor)
+/* Transparency. */
+KERNEL_STRUCT_MEMBER(integrator, int, transparent_min_bounce)
+KERNEL_STRUCT_MEMBER(integrator, int, transparent_max_bounce)
+KERNEL_STRUCT_MEMBER(integrator, int, transparent_shadows)
+/* Caustics. */
+KERNEL_STRUCT_MEMBER(integrator, int, caustics_reflective)
+KERNEL_STRUCT_MEMBER(integrator, int, caustics_refractive)
+KERNEL_STRUCT_MEMBER(integrator, float, filter_glossy)
+/* Seed. */
+KERNEL_STRUCT_MEMBER(integrator, int, seed)
+/* Clamp. */
+KERNEL_STRUCT_MEMBER(integrator, float, sample_clamp_direct)
+KERNEL_STRUCT_MEMBER(integrator, float, sample_clamp_indirect)
+/* MIS. */
+KERNEL_STRUCT_MEMBER(integrator, int, use_lamp_mis)
+/* Caustics. */
+KERNEL_STRUCT_MEMBER(integrator, int, use_caustics)
+/* Sampling pattern. */
+KERNEL_STRUCT_MEMBER(integrator, int, sampling_pattern)
+KERNEL_STRUCT_MEMBER(integrator, float, scrambling_distance)
+/* Volume render. */
+KERNEL_STRUCT_MEMBER(integrator, int, use_volumes)
+KERNEL_STRUCT_MEMBER(integrator, int, volume_max_steps)
+KERNEL_STRUCT_MEMBER(integrator, float, volume_step_rate)
+/* Shadow catcher. */
+KERNEL_STRUCT_MEMBER(integrator, int, has_shadow_catcher)
+/* Closure filter. */
+KERNEL_STRUCT_MEMBER(integrator, int, filter_closures)
+/* MIS debugging. */
+KERNEL_STRUCT_MEMBER(integrator, int, direct_light_sampling_type)
+/* Padding */
+KERNEL_STRUCT_MEMBER(integrator, int, pad1)
+KERNEL_STRUCT_END(KernelIntegrator)
+
+/* SVM. For shader specialization. */
+
+KERNEL_STRUCT_BEGIN(KernelSVMUsage, svm_usage)
+#define SHADER_NODE_TYPE(type) KERNEL_STRUCT_MEMBER(svm_usage, int, type)
+#include "kernel/svm/node_types_template.h"
+KERNEL_STRUCT_END(KernelSVMUsage)
+
+#undef KERNEL_STRUCT_BEGIN
+#undef KERNEL_STRUCT_MEMBER
+#undef KERNEL_STRUCT_END
diff --git a/intern/cycles/kernel/device/cpu/compat.h b/intern/cycles/kernel/device/cpu/compat.h
index e1c20169582..3bfc37e98ee 100644
--- a/intern/cycles/kernel/device/cpu/compat.h
+++ b/intern/cycles/kernel/device/cpu/compat.h
@@ -35,20 +35,6 @@ CCL_NAMESPACE_BEGIN
#define kernel_assert(cond) assert(cond)
-/* Texture types to be compatible with CUDA textures. These are really just
- * simple arrays and after inlining fetch hopefully revert to being a simple
- * pointer lookup. */
-template<typename T> struct texture {
- ccl_always_inline const T &fetch(int index) const
- {
- kernel_assert(index >= 0 && index < width);
- return data[index];
- }
-
- T *data;
- int width;
-};
-
/* Macros to handle different memory storage on different devices */
#ifdef __KERNEL_SSE2__
diff --git a/intern/cycles/kernel/device/cpu/globals.h b/intern/cycles/kernel/device/cpu/globals.h
index 7e080d428ea..309afae412e 100644
--- a/intern/cycles/kernel/device/cpu/globals.h
+++ b/intern/cycles/kernel/device/cpu/globals.h
@@ -12,7 +12,7 @@
CCL_NAMESPACE_BEGIN
/* On the CPU, we pass along the struct KernelGlobals to nearly everywhere in
- * the kernel, to access constant data. These are all stored as "textures", but
+ * the kernel, to access constant data. These are all stored as flat arrays.
* these are really just standard arrays. We can't use actually globals because
* multiple renders may be running inside the same process. */
@@ -22,11 +22,23 @@ struct OSLThreadData;
struct OSLShadingSystem;
#endif
+/* Array for kernel data, with size to be able to assert on invalid data access. */
+template<typename T> struct kernel_array {
+ ccl_always_inline const T &fetch(int index) const
+ {
+ kernel_assert(index >= 0 && index < width);
+ return data[index];
+ }
+
+ T *data;
+ int width;
+};
+
typedef struct KernelGlobalsCPU {
-#define KERNEL_TEX(type, name) texture<type> name;
-#include "kernel/textures.h"
+#define KERNEL_DATA_ARRAY(type, name) kernel_array<type> name;
+#include "kernel/data_arrays.h"
- KernelData __data;
+ KernelData data;
#ifdef __OSL__
/* On the CPU, we also have the OSL globals here. Most data structures are shared
@@ -44,8 +56,8 @@ typedef struct KernelGlobalsCPU {
typedef const KernelGlobalsCPU *ccl_restrict KernelGlobals;
/* Abstraction macros */
-#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
-#define kernel_tex_array(tex) (kg->tex.data)
-#define kernel_data (kg->__data)
+#define kernel_data_fetch(name, index) (kg->name.fetch(index))
+#define kernel_data_array(name) (kg->name.data)
+#define kernel_data (kg->data)
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/cpu/image.h b/intern/cycles/kernel/device/cpu/image.h
index 7809ec5f4a7..320e6309128 100644
--- a/intern/cycles/kernel/device/cpu/image.h
+++ b/intern/cycles/kernel/device/cpu/image.h
@@ -733,7 +733,7 @@ template<typename TexT, typename OutT = float4> struct NanoVDBInterpolator {
ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, int id, float x, float y)
{
- const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
+ const TextureInfo &info = kernel_data_fetch(texture_info, id);
if (UNLIKELY(!info.data)) {
return zero_float4();
@@ -776,7 +776,7 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
float3 P,
InterpolationType interp)
{
- const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
+ const TextureInfo &info = kernel_data_fetch(texture_info, id);
if (UNLIKELY(!info.data)) {
return zero_float4();
diff --git a/intern/cycles/kernel/device/cpu/kernel.cpp b/intern/cycles/kernel/device/cpu/kernel.cpp
index b12e3089378..01087c96dd6 100644
--- a/intern/cycles/kernel/device/cpu/kernel.cpp
+++ b/intern/cycles/kernel/device/cpu/kernel.cpp
@@ -53,8 +53,8 @@ CCL_NAMESPACE_BEGIN
void kernel_const_copy(KernelGlobalsCPU *kg, const char *name, void *host, size_t)
{
- if (strcmp(name, "__data") == 0) {
- kg->__data = *(KernelData *)host;
+ if (strcmp(name, "data") == 0) {
+ kg->data = *(KernelData *)host;
}
else {
assert(0);
@@ -66,13 +66,13 @@ void kernel_global_memory_copy(KernelGlobalsCPU *kg, const char *name, void *mem
if (0) {
}
-#define KERNEL_TEX(type, tname) \
+#define KERNEL_DATA_ARRAY(type, tname) \
else if (strcmp(name, #tname) == 0) \
{ \
kg->tname.data = (type *)mem; \
kg->tname.width = size; \
}
-#include "kernel/textures.h"
+#include "kernel/data_arrays.h"
else {
assert(0);
}
diff --git a/intern/cycles/kernel/device/cuda/globals.h b/intern/cycles/kernel/device/cuda/globals.h
index e77fcd2b424..f5f7bcf58ee 100644
--- a/intern/cycles/kernel/device/cuda/globals.h
+++ b/intern/cycles/kernel/device/cuda/globals.h
@@ -20,18 +20,24 @@ struct KernelGlobalsGPU {
};
typedef ccl_global const KernelGlobalsGPU *ccl_restrict KernelGlobals;
-/* Global scene data and textures */
-__constant__ KernelData __data;
-#define KERNEL_TEX(type, name) const __constant__ __device__ type *name;
-#include "kernel/textures.h"
+struct KernelParamsCUDA {
+ /* Global scene data and textures */
+ KernelData data;
+#define KERNEL_DATA_ARRAY(type, name) const type *name;
+#include "kernel/data_arrays.h"
+
+ /* Integrator state */
+ IntegratorStateGPU integrator_state;
+};
-/* Integrator state */
-__constant__ IntegratorStateGPU __integrator_state;
+#ifdef __KERNEL_GPU__
+__constant__ KernelParamsCUDA kernel_params;
+#endif
/* Abstraction macros */
-#define kernel_data __data
-#define kernel_tex_fetch(t, index) t[(index)]
-#define kernel_tex_array(t) (t)
-#define kernel_integrator_state __integrator_state
+#define kernel_data kernel_params.data
+#define kernel_data_fetch(name, index) kernel_params.name[(index)]
+#define kernel_data_array(name) (kernel_params.name)
+#define kernel_integrator_state kernel_params.integrator_state
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/gpu/image.h b/intern/cycles/kernel/device/gpu/image.h
index 29d851ae478..a8c72645569 100644
--- a/intern/cycles/kernel/device/gpu/image.h
+++ b/intern/cycles/kernel/device/gpu/image.h
@@ -181,7 +181,7 @@ ccl_device_noinline typename nanovdb::NanoGrid<T>::ValueType kernel_tex_image_in
ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, int id, float x, float y)
{
- ccl_global const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
+ ccl_global const TextureInfo &info = kernel_data_fetch(texture_info, id);
/* float4, byte4, ushort4 and half4 */
const int texture_type = info.data_type;
@@ -216,7 +216,7 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
float3 P,
InterpolationType interp)
{
- ccl_global const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
+ ccl_global const TextureInfo &info = kernel_data_fetch(texture_info, id);
if (info.use_transform_3d) {
P = transform_point(&info.transform_3d, P);
diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h
index 328c58e7905..e1ab802aa80 100644
--- a/intern/cycles/kernel/device/gpu/kernel.h
+++ b/intern/cycles/kernel/device/gpu/kernel.h
@@ -14,6 +14,8 @@
#ifdef __KERNEL_METAL__
# include "kernel/device/metal/context_begin.h"
+#elif defined(__KERNEL_ONEAPI__)
+# include "kernel/device/oneapi/context_begin.h"
#endif
#include "kernel/device/gpu/work_stealing.h"
@@ -40,6 +42,8 @@
#ifdef __KERNEL_METAL__
# include "kernel/device/metal/context_end.h"
+#elif defined(__KERNEL_ONEAPI__)
+# include "kernel/device/oneapi/context_end.h"
#endif
#include "kernel/film/read.h"
@@ -241,8 +245,8 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
}
ccl_gpu_kernel_postfix
-#ifdef __KERNEL_METAL__
-constant int __dummy_constant [[function_constant(0)]];
+#if defined(__KERNEL_METAL_APPLE__) && defined(__METALRT__)
+constant int __dummy_constant [[function_constant(Kernel_DummyConstant)]];
#endif
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
@@ -256,7 +260,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
if (global_index < work_size) {
const int state = (path_index_array) ? path_index_array[global_index] : global_index;
-#ifdef __KERNEL_METAL__
+#if defined(__KERNEL_METAL_APPLE__) && defined(__METALRT__)
KernelGlobals kg = NULL;
/* Workaround Ambient Occlusion and Bevel nodes not working with Metal.
* Dummy offset should not affect result, but somehow fixes bug! */
@@ -270,6 +274,21 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
ccl_gpu_kernel_postfix
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
+ ccl_gpu_kernel_signature(integrator_shade_surface_mnee,
+ ccl_global const int *path_index_array,
+ ccl_global float *render_buffer,
+ const int work_size)
+{
+ const int global_index = ccl_gpu_global_id_x();
+
+ if (global_index < work_size) {
+ const int state = (path_index_array) ? path_index_array[global_index] : global_index;
+ ccl_gpu_kernel_call(integrator_shade_surface_mnee(NULL, state, render_buffer));
+ }
+}
+ccl_gpu_kernel_postfix
+
+ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
ccl_gpu_kernel_signature(integrator_shade_volume,
ccl_global const int *path_index_array,
ccl_global float *render_buffer,
diff --git a/intern/cycles/kernel/device/gpu/parallel_active_index.h b/intern/cycles/kernel/device/gpu/parallel_active_index.h
index 7d7266d5edf..c1df49c4f49 100644
--- a/intern/cycles/kernel/device/gpu/parallel_active_index.h
+++ b/intern/cycles/kernel/device/gpu/parallel_active_index.h
@@ -18,15 +18,68 @@ CCL_NAMESPACE_BEGIN
# define GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE 512
#endif
-#ifndef __KERNEL_METAL__
+/* TODO: abstract more device differences, define ccl_gpu_local_syncthreads,
+ * ccl_gpu_thread_warp, ccl_gpu_warp_index, ccl_gpu_num_warps for all devices
+ * and keep device specific code in compat.h */
+
+#ifdef __KERNEL_ONEAPI__
+# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
+template<typename IsActiveOp>
+void cpu_serial_active_index_array_impl(const uint num_states,
+ ccl_global int *ccl_restrict indices,
+ ccl_global int *ccl_restrict num_indices,
+ IsActiveOp is_active_op)
+{
+ int write_index = 0;
+ for (int state_index = 0; state_index < num_states; state_index++) {
+ if (is_active_op(state_index))
+ indices[write_index++] = state_index;
+ }
+ *num_indices = write_index;
+ return;
+}
+# endif /* WITH_ONEAPI_SYCL_HOST_ENABLED */
+
+template<typename IsActiveOp>
+void gpu_parallel_active_index_array_impl(const uint num_states,
+ ccl_global int *ccl_restrict indices,
+ ccl_global int *ccl_restrict num_indices,
+ IsActiveOp is_active_op)
+{
+ const sycl::nd_item<1> &item_id = sycl::ext::oneapi::experimental::this_nd_item<1>();
+ const uint blocksize = item_id.get_local_range(0);
+
+ sycl::multi_ptr<int[GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE + 1],
+ sycl::access::address_space::local_space>
+ ptr = sycl::ext::oneapi::group_local_memory<
+ int[GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE + 1]>(item_id.get_group());
+ int *warp_offset = *ptr;
+
+ /* NOTE(@nsirgien): Here we calculate the same value as below but
+ * faster for DPC++ : seems CUDA converting "%", "/", "*" based calculations below into
+ * something faster already but DPC++ doesn't, so it's better to use
+ * direct request of needed parameters - switching from this computation to computation below
+ * will cause 2.5x performance slowdown. */
+ const uint thread_index = item_id.get_local_id(0);
+ const uint thread_warp = item_id.get_sub_group().get_local_id();
+
+ const uint warp_index = item_id.get_sub_group().get_group_id();
+ const uint num_warps = item_id.get_sub_group().get_group_range()[0];
+
+ const uint state_index = item_id.get_global_id(0);
+
+ /* Test if state corresponding to this thread is active. */
+ const uint is_active = (state_index < num_states) ? is_active_op(state_index) : 0;
+#else /* !__KERNEL__ONEAPI__ */
+# ifndef __KERNEL_METAL__
template<uint blocksize, typename IsActiveOp>
__device__
-#endif
+# endif
void
gpu_parallel_active_index_array_impl(const uint num_states,
ccl_global int *indices,
ccl_global int *num_indices,
-#ifdef __KERNEL_METAL__
+# ifdef __KERNEL_METAL__
const uint is_active,
const uint blocksize,
const int thread_index,
@@ -37,7 +90,7 @@ __device__
const int num_warps,
threadgroup int *warp_offset)
{
-#else
+# else
IsActiveOp is_active_op)
{
extern ccl_gpu_shared int warp_offset[];
@@ -52,18 +105,33 @@ __device__
/* Test if state corresponding to this thread is active. */
const uint is_active = (state_index < num_states) ? is_active_op(state_index) : 0;
-#endif
-
+# endif
+#endif /* !__KERNEL_ONEAPI__ */
/* For each thread within a warp compute how many other active states precede it. */
+#ifdef __KERNEL_ONEAPI__
+ const uint thread_offset = sycl::exclusive_scan_over_group(
+ item_id.get_sub_group(), is_active, std::plus<>());
+#else
const uint thread_offset = popcount(ccl_gpu_ballot(is_active) &
ccl_gpu_thread_mask(thread_warp));
+#endif
/* Last thread in warp stores number of active states for each warp. */
+#ifdef __KERNEL_ONEAPI__
+ if (thread_warp == item_id.get_sub_group().get_local_range()[0] - 1) {
+#else
if (thread_warp == ccl_gpu_warp_size - 1) {
+#endif
warp_offset[warp_index] = thread_offset + is_active;
}
+#ifdef __KERNEL_ONEAPI__
+ /* NOTE(@nsirgien): For us here only local memory writing (warp_offset) is important,
+ * so faster local barriers can be used. */
+ ccl_gpu_local_syncthreads();
+#else
ccl_gpu_syncthreads();
+#endif
/* Last thread in block converts per-warp sizes to offsets, increments global size of
* index array and gets offset to write to. */
@@ -80,7 +148,13 @@ __device__
warp_offset[num_warps] = atomic_fetch_and_add_uint32(num_indices, block_num_active);
}
+#ifdef __KERNEL_ONEAPI__
+ /* NOTE(@nsirgien): For us here only important local memory writing (warp_offset),
+ * so faster local barriers can be used. */
+ ccl_gpu_local_syncthreads();
+#else
ccl_gpu_syncthreads();
+#endif
/* Write to index array. */
if (is_active) {
@@ -107,7 +181,19 @@ __device__
simd_group_index, \
num_simd_groups, \
simdgroup_offset)
-
+#elif defined(__KERNEL_ONEAPI__)
+# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
+# define gpu_parallel_active_index_array( \
+ blocksize, num_states, indices, num_indices, is_active_op) \
+ if (ccl_gpu_global_size_x() == 1) \
+ cpu_serial_active_index_array_impl(num_states, indices, num_indices, is_active_op); \
+ else \
+ gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op);
+# else
+# define gpu_parallel_active_index_array( \
+ blocksize, num_states, indices, num_indices, is_active_op) \
+ gpu_parallel_active_index_array_impl(num_states, indices, num_indices, is_active_op)
+# endif
#else
# define gpu_parallel_active_index_array( \
diff --git a/intern/cycles/kernel/device/hip/compat.h b/intern/cycles/kernel/device/hip/compat.h
index 667352ed12e..648988c31b6 100644
--- a/intern/cycles/kernel/device/hip/compat.h
+++ b/intern/cycles/kernel/device/hip/compat.h
@@ -62,7 +62,7 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_block_idx_x (blockIdx.x)
#define ccl_gpu_grid_dim_x (gridDim.x)
#define ccl_gpu_warp_size (warpSize)
-#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
+#define ccl_gpu_thread_mask(thread_warp) uint64_t((1ull << thread_warp) - 1)
#define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x)
#define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x)
diff --git a/intern/cycles/kernel/device/hip/globals.h b/intern/cycles/kernel/device/hip/globals.h
index 50f117038a2..3a334b21a9e 100644
--- a/intern/cycles/kernel/device/hip/globals.h
+++ b/intern/cycles/kernel/device/hip/globals.h
@@ -20,18 +20,24 @@ struct KernelGlobalsGPU {
};
typedef ccl_global const KernelGlobalsGPU *ccl_restrict KernelGlobals;
-/* Global scene data and textures */
-__constant__ KernelData __data;
-#define KERNEL_TEX(type, name) __attribute__((used)) const __constant__ __device__ type *name;
-#include "kernel/textures.h"
+struct KernelParamsHIP {
+ /* Global scene data and textures */
+ KernelData data;
+#define KERNEL_DATA_ARRAY(type, name) const type *name;
+#include "kernel/data_arrays.h"
+
+ /* Integrator state */
+ IntegratorStateGPU integrator_state;
+};
-/* Integrator state */
-__constant__ IntegratorStateGPU __integrator_state;
+#ifdef __KERNEL_GPU__
+__constant__ KernelParamsHIP kernel_params;
+#endif
/* Abstraction macros */
-#define kernel_data __data
-#define kernel_tex_fetch(t, index) t[(index)]
-#define kernel_tex_array(t) (t)
-#define kernel_integrator_state __integrator_state
+#define kernel_data kernel_params.data
+#define kernel_data_fetch(name, index) kernel_params.name[(index)]
+#define kernel_data_array(name) (kernel_params.name)
+#define kernel_integrator_state kernel_params.integrator_state
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/metal/context_end.h b/intern/cycles/kernel/device/metal/context_end.h
index b4c8661c401..44ac0478266 100644
--- a/intern/cycles/kernel/device/metal/context_end.h
+++ b/intern/cycles/kernel/device/metal/context_end.h
@@ -7,4 +7,4 @@
/* NOTE: These macros will need maintaining as entry-points change. */
#undef kernel_integrator_state
-#define kernel_integrator_state context.launch_params_metal.__integrator_state
+#define kernel_integrator_state context.launch_params_metal.integrator_state
diff --git a/intern/cycles/kernel/device/metal/function_constants.h b/intern/cycles/kernel/device/metal/function_constants.h
new file mode 100644
index 00000000000..3adf390c7f6
--- /dev/null
+++ b/intern/cycles/kernel/device/metal/function_constants.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Blender Foundation */
+
+enum {
+ Kernel_DummyConstant,
+#define KERNEL_STRUCT_MEMBER(parent, type, name) KernelData_##parent##_##name,
+#include "kernel/data_template.h"
+};
+
+#ifdef __KERNEL_METAL__
+# define KERNEL_STRUCT_MEMBER(parent, type, name) \
+ constant type kernel_data_##parent##_##name \
+ [[function_constant(KernelData_##parent##_##name)]];
+# include "kernel/data_template.h"
+#endif
diff --git a/intern/cycles/kernel/device/metal/globals.h b/intern/cycles/kernel/device/metal/globals.h
index 1c3e775dbae..a336c096440 100644
--- a/intern/cycles/kernel/device/metal/globals.h
+++ b/intern/cycles/kernel/device/metal/globals.h
@@ -12,11 +12,11 @@ CCL_NAMESPACE_BEGIN
typedef struct KernelParamsMetal {
-#define KERNEL_TEX(type, name) ccl_global const type *name;
-#include "kernel/textures.h"
-#undef KERNEL_TEX
+#define KERNEL_DATA_ARRAY(type, name) ccl_global const type *name;
+#include "kernel/data_arrays.h"
+#undef KERNEL_DATA_ARRAY
- const IntegratorStateGPU __integrator_state;
+ const IntegratorStateGPU integrator_state;
const KernelData data;
} KernelParamsMetal;
@@ -27,12 +27,10 @@ typedef struct KernelGlobalsGPU {
typedef ccl_global const KernelGlobalsGPU *ccl_restrict KernelGlobals;
+/* Abstraction macros */
#define kernel_data launch_params_metal.data
-#define kernel_integrator_state launch_params_metal.__integrator_state
-
-/* data lookup defines */
-
-#define kernel_tex_fetch(tex, index) launch_params_metal.tex[index]
-#define kernel_tex_array(tex) launch_params_metal.tex
+#define kernel_data_fetch(name, index) launch_params_metal.name[index]
+#define kernel_data_array(name) launch_params_metal.name
+#define kernel_integrator_state launch_params_metal.integrator_state
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal
index a7252570e64..764c26dbe8f 100644
--- a/intern/cycles/kernel/device/metal/kernel.metal
+++ b/intern/cycles/kernel/device/metal/kernel.metal
@@ -5,6 +5,7 @@
#include "kernel/device/metal/compat.h"
#include "kernel/device/metal/globals.h"
+#include "kernel/device/metal/function_constants.h"
#include "kernel/device/gpu/kernel.h"
/* MetalRT intersection handlers */
@@ -59,7 +60,7 @@ TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal,
TReturn result;
#ifdef __BVH_LOCAL__
- uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
if ((object != payload.local_object) || intersection_skip_self_local(payload.self, prim)) {
/* Only intersect with matching object and skip self-intersecton. */
@@ -113,16 +114,16 @@ TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal,
isect->t = ray_tmax;
isect->prim = prim;
isect->object = object;
- isect->type = kernel_tex_fetch(__objects, object).primitive_type;
+ isect->type = kernel_data_fetch(objects, object).primitive_type;
isect->u = 1.0f - barycentrics.y - barycentrics.x;
isect->v = barycentrics.x;
/* Record geometric normal */
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect->prim).w;
- const float3 tri_a = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0));
- const float3 tri_b = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1));
- const float3 tri_c = float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2));
+ const uint tri_vindex = kernel_data_fetch(tri_vindex, isect->prim).w;
+ const float3 tri_a = float3(kernel_data_fetch(tri_verts, tri_vindex + 0));
+ const float3 tri_b = float3(kernel_data_fetch(tri_verts, tri_vindex + 1));
+ const float3 tri_c = float3(kernel_data_fetch(tri_verts, tri_vindex + 2));
payload.local_isect.Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
/* Continue tracing (without this the trace call would return after the first hit) */
@@ -168,7 +169,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
#ifdef __SHADOW_RECORD_ALL__
# ifdef __VISIBILITY_FLAG__
const uint visibility = payload.visibility;
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
/* continue search */
return true;
}
@@ -184,14 +185,14 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
if (intersection_type == METALRT_HIT_TRIANGLE) {
u = 1.0f - barycentrics.y - barycentrics.x;
v = barycentrics.x;
- type = kernel_tex_fetch(__objects, object).primitive_type;
+ type = kernel_data_fetch(objects, object).primitive_type;
}
# ifdef __HAIR__
else {
u = barycentrics.x;
v = barycentrics.y;
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
type = segment.type;
prim = segment.prim;
@@ -294,7 +295,7 @@ __anyhit__cycles_metalrt_shadow_all_hit_tri(constant KernelParamsMetal &launch_p
float2 barycentrics [[barycentric_coord]],
float ray_tmax [[distance]])
{
- uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
TriangleIntersectionResult result;
result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_TRIANGLE>(
@@ -337,7 +338,7 @@ inline TReturnType metalrt_visibility_test(constant KernelParamsMetal &launch_pa
uint visibility = payload.visibility;
# ifdef __VISIBILITY_FLAG__
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
result.accept = false;
result.continue_search = true;
return result;
@@ -377,12 +378,12 @@ __anyhit__cycles_metalrt_visibility_test_tri(constant KernelParamsMetal &launch_
unsigned int object [[user_instance_id]],
unsigned int primitive_id [[primitive_id]])
{
- uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
+ uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
TriangleIntersectionResult result = metalrt_visibility_test<TriangleIntersectionResult, METALRT_HIT_TRIANGLE>(
launch_params_metal, payload, object, prim, 0.0f);
if (result.accept) {
payload.prim = prim;
- payload.type = kernel_tex_fetch(__objects, object).primitive_type;
+ payload.type = kernel_data_fetch(objects, object).primitive_type;
}
return result;
}
@@ -409,12 +410,13 @@ void metalrt_intersection_curve(constant KernelParamsMetal &launch_params_metal,
const float3 ray_origin,
const float3 ray_direction,
float time,
+ const float ray_tmin,
const float ray_tmax,
thread BoundingBoxIntersectionResult &result)
{
# ifdef __VISIBILITY_FLAG__
const uint visibility = payload.visibility;
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
return;
}
# endif
@@ -433,7 +435,7 @@ void metalrt_intersection_curve(constant KernelParamsMetal &launch_params_metal,
isect.t *= len;
MetalKernelContext context(launch_params_metal);
- if (context.curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ if (context.curve_intersect(NULL, &isect, P, dir, ray_tmin, isect.t, object, prim, time, type)) {
result = metalrt_visibility_test<BoundingBoxIntersectionResult, METALRT_HIT_BOUNDING_BOX>(
launch_params_metal, payload, object, prim, isect.u);
if (result.accept) {
@@ -455,6 +457,7 @@ void metalrt_intersection_curve_shadow(constant KernelParamsMetal &launch_params
const float3 ray_origin,
const float3 ray_direction,
float time,
+ const float ray_tmin,
const float ray_tmax,
thread BoundingBoxIntersectionResult &result)
{
@@ -474,7 +477,7 @@ void metalrt_intersection_curve_shadow(constant KernelParamsMetal &launch_params
isect.t *= len;
MetalKernelContext context(launch_params_metal);
- if (context.curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ if (context.curve_intersect(NULL, &isect, P, dir, ray_tmin, isect.t, object, prim, time, type)) {
result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_BOUNDING_BOX>(
launch_params_metal, payload, object, prim, float2(isect.u, isect.v), ray_tmax);
result.accept = !result.continue_search;
@@ -493,10 +496,11 @@ __intersection__curve_ribbon(constant KernelParamsMetal &launch_params_metal [[b
const uint primitive_id [[primitive_id]],
const float3 ray_origin [[origin]],
const float3 ray_direction [[direction]],
+ const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{
- uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
BoundingBoxIntersectionResult result;
result.accept = false;
@@ -510,7 +514,7 @@ __intersection__curve_ribbon(constant KernelParamsMetal &launch_params_metal [[b
# else
0.0f,
# endif
- ray_tmax, result);
+ ray_tmin, ray_tmax, result);
}
return result;
@@ -524,10 +528,11 @@ __intersection__curve_ribbon_shadow(constant KernelParamsMetal &launch_params_me
const uint primitive_id [[primitive_id]],
const float3 ray_origin [[origin]],
const float3 ray_direction [[direction]],
+ const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{
- uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
BoundingBoxIntersectionResult result;
result.accept = false;
@@ -541,7 +546,7 @@ __intersection__curve_ribbon_shadow(constant KernelParamsMetal &launch_params_me
# else
0.0f,
# endif
- ray_tmax, result);
+ ray_tmin, ray_tmax, result);
}
return result;
@@ -555,10 +560,11 @@ __intersection__curve_all(constant KernelParamsMetal &launch_params_metal [[buff
const uint primitive_id [[primitive_id]],
const float3 ray_origin [[origin]],
const float3 ray_direction [[direction]],
+ const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{
- uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
BoundingBoxIntersectionResult result;
result.accept = false;
@@ -570,7 +576,7 @@ __intersection__curve_all(constant KernelParamsMetal &launch_params_metal [[buff
# else
0.0f,
# endif
- ray_tmax, result);
+ ray_tmin, ray_tmax, result);
return result;
}
@@ -583,10 +589,11 @@ __intersection__curve_all_shadow(constant KernelParamsMetal &launch_params_metal
const uint primitive_id [[primitive_id]],
const float3 ray_origin [[origin]],
const float3 ray_direction [[direction]],
+ const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{
- uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
BoundingBoxIntersectionResult result;
result.accept = false;
@@ -599,7 +606,7 @@ __intersection__curve_all_shadow(constant KernelParamsMetal &launch_params_metal
# else
0.0f,
# endif
- ray_tmax, result);
+ ray_tmin, ray_tmax, result);
return result;
}
@@ -615,12 +622,13 @@ void metalrt_intersection_point(constant KernelParamsMetal &launch_params_metal,
const float3 ray_origin,
const float3 ray_direction,
float time,
+ const float ray_tmin,
const float ray_tmax,
thread BoundingBoxIntersectionResult &result)
{
# ifdef __VISIBILITY_FLAG__
const uint visibility = payload.visibility;
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
return;
}
# endif
@@ -639,7 +647,7 @@ void metalrt_intersection_point(constant KernelParamsMetal &launch_params_metal,
isect.t *= len;
MetalKernelContext context(launch_params_metal);
- if (context.point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ if (context.point_intersect(NULL, &isect, P, dir, ray_tmin, isect.t, object, prim, time, type)) {
result = metalrt_visibility_test<BoundingBoxIntersectionResult, METALRT_HIT_BOUNDING_BOX>(
launch_params_metal, payload, object, prim, isect.u);
if (result.accept) {
@@ -661,6 +669,7 @@ void metalrt_intersection_point_shadow(constant KernelParamsMetal &launch_params
const float3 ray_origin,
const float3 ray_direction,
float time,
+ const float ray_tmin,
const float ray_tmax,
thread BoundingBoxIntersectionResult &result)
{
@@ -680,7 +689,7 @@ void metalrt_intersection_point_shadow(constant KernelParamsMetal &launch_params
isect.t *= len;
MetalKernelContext context(launch_params_metal);
- if (context.point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ if (context.point_intersect(NULL, &isect, P, dir, ray_tmin, isect.t, object, prim, time, type)) {
result.continue_search = metalrt_shadow_all_hit<METALRT_HIT_BOUNDING_BOX>(
launch_params_metal, payload, object, prim, float2(isect.u, isect.v), ray_tmax);
result.accept = !result.continue_search;
@@ -699,10 +708,11 @@ __intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1
const uint primitive_id [[primitive_id]],
const float3 ray_origin [[origin]],
const float3 ray_direction [[direction]],
+ const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{
- const uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
- const int type = kernel_tex_fetch(__objects, object).primitive_type;
+ const uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
+ const int type = kernel_data_fetch(objects, object).primitive_type;
BoundingBoxIntersectionResult result;
result.accept = false;
@@ -715,7 +725,7 @@ __intersection__point(constant KernelParamsMetal &launch_params_metal [[buffer(1
# else
0.0f,
# endif
- ray_tmax, result);
+ ray_tmin, ray_tmax, result);
return result;
}
@@ -728,10 +738,11 @@ __intersection__point_shadow(constant KernelParamsMetal &launch_params_metal [[b
const uint primitive_id [[primitive_id]],
const float3 ray_origin [[origin]],
const float3 ray_direction [[direction]],
+ const float ray_tmin [[min_distance]],
const float ray_tmax [[max_distance]])
{
- const uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object);
- const int type = kernel_tex_fetch(__objects, object).primitive_type;
+ const uint prim = primitive_id + kernel_data_fetch(object_prim_offset, object);
+ const int type = kernel_data_fetch(objects, object).primitive_type;
BoundingBoxIntersectionResult result;
result.accept = false;
@@ -744,7 +755,7 @@ __intersection__point_shadow(constant KernelParamsMetal &launch_params_metal [[b
# else
0.0f,
# endif
- ray_tmax, result);
+ ray_tmin, ray_tmax, result);
return result;
}
diff --git a/intern/cycles/kernel/device/oneapi/compat.h b/intern/cycles/kernel/device/oneapi/compat.h
new file mode 100644
index 00000000000..1b25259bcf5
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/compat.h
@@ -0,0 +1,206 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#pragma once
+
+#define __KERNEL_GPU__
+#define __KERNEL_ONEAPI__
+
+#define CCL_NAMESPACE_BEGIN
+#define CCL_NAMESPACE_END
+
+#include <cstdint>
+
+#ifndef __NODES_MAX_GROUP__
+# define __NODES_MAX_GROUP__ NODE_GROUP_LEVEL_MAX
+#endif
+#ifndef __NODES_FEATURES__
+# define __NODES_FEATURES__ NODE_FEATURE_ALL
+#endif
+
+/* This one does not have an abstraction.
+ * It's used by other devices directly.
+ */
+
+#define __device__
+
+/* Qualifier wrappers for different names on different devices */
+
+#define ccl_device
+#define ccl_global
+#define ccl_always_inline __attribute__((always_inline))
+#define ccl_device_inline inline
+#define ccl_noinline
+#define ccl_inline_constant const constexpr
+#define ccl_static_constant const
+#define ccl_device_forceinline __attribute__((always_inline))
+#define ccl_device_noinline ccl_device ccl_noinline
+#define ccl_device_noinline_cpu ccl_device
+#define ccl_device_inline_method ccl_device
+#define ccl_restrict __restrict__
+#define ccl_loop_no_unroll
+#define ccl_optional_struct_init
+#define ccl_private
+#define ATTR_FALLTHROUGH __attribute__((fallthrough))
+#define ccl_constant const
+#define ccl_try_align(...) __attribute__((aligned(__VA_ARGS__)))
+#define ccl_align(n) __attribute__((aligned(n)))
+#define kernel_assert(cond)
+#define ccl_may_alias
+
+/* clang-format off */
+
+/* kernel.h adapters */
+#define ccl_gpu_kernel(block_num_threads, thread_num_registers)
+#define ccl_gpu_kernel_threads(block_num_threads)
+
+#ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
+# define KG_ND_ITEMS \
+ kg->nd_item_local_id_0 = item.get_local_id(0); \
+ kg->nd_item_local_range_0 = item.get_local_range(0); \
+ kg->nd_item_group_0 = item.get_group(0); \
+ kg->nd_item_group_range_0 = item.get_group_range(0); \
+ kg->nd_item_global_id_0 = item.get_global_id(0); \
+ kg->nd_item_global_range_0 = item.get_global_range(0);
+#else
+# define KG_ND_ITEMS
+#endif
+
+#define ccl_gpu_kernel_signature(name, ...) \
+void oneapi_kernel_##name(KernelGlobalsGPU *ccl_restrict kg, \
+ size_t kernel_global_size, \
+ size_t kernel_local_size, \
+ sycl::handler &cgh, \
+ __VA_ARGS__) { \
+ (kg); \
+ cgh.parallel_for<class kernel_##name>( \
+ sycl::nd_range<1>(kernel_global_size, kernel_local_size), \
+ [=](sycl::nd_item<1> item) { \
+ KG_ND_ITEMS
+
+#define ccl_gpu_kernel_postfix \
+ }); \
+ }
+
+#define ccl_gpu_kernel_call(x) ((ONEAPIKernelContext*)kg)->x
+
+#define ccl_gpu_kernel_lambda(func, ...) \
+ struct KernelLambda \
+ { \
+ KernelLambda(const ONEAPIKernelContext *_kg) : kg(_kg) {} \
+ ccl_private const ONEAPIKernelContext *kg; \
+ __VA_ARGS__; \
+ int operator()(const int state) const { return (func); } \
+ } ccl_gpu_kernel_lambda_pass((ONEAPIKernelContext *)kg)
+
+/* GPU thread, block, grid size and index */
+#ifndef WITH_ONEAPI_SYCL_HOST_ENABLED
+# define ccl_gpu_thread_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_id(0))
+# define ccl_gpu_block_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_local_range(0))
+# define ccl_gpu_block_idx_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group(0))
+# define ccl_gpu_grid_dim_x (sycl::ext::oneapi::experimental::this_nd_item<1>().get_group_range(0))
+# define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0])
+# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
+
+# define ccl_gpu_global_id_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_id(0))
+# define ccl_gpu_global_size_x() (sycl::ext::oneapi::experimental::this_nd_item<1>().get_global_range(0))
+#else
+# define ccl_gpu_thread_idx_x (kg->nd_item_local_id_0)
+# define ccl_gpu_block_dim_x (kg->nd_item_local_range_0)
+# define ccl_gpu_block_idx_x (kg->nd_item_group_0)
+# define ccl_gpu_grid_dim_x (kg->nd_item_group_range_0)
+# define ccl_gpu_warp_size (sycl::ext::oneapi::experimental::this_sub_group().get_local_range()[0])
+# define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
+
+# define ccl_gpu_global_id_x() (kg->nd_item_global_id_0)
+# define ccl_gpu_global_size_x() (kg->nd_item_global_range_0)
+#endif
+
+
+/* GPU warp synchronization */
+
+#define ccl_gpu_syncthreads() sycl::ext::oneapi::experimental::this_nd_item<1>().barrier()
+#define ccl_gpu_local_syncthreads() sycl::ext::oneapi::experimental::this_nd_item<1>().barrier(sycl::access::fence_space::local_space)
+#ifdef __SYCL_DEVICE_ONLY__
+ #define ccl_gpu_ballot(predicate) (sycl::ext::oneapi::group_ballot(sycl::ext::oneapi::experimental::this_sub_group(), predicate).count())
+#else
+ #define ccl_gpu_ballot(predicate) (predicate ? 1 : 0)
+#endif
+
+/* Debug defines */
+#if defined(__SYCL_DEVICE_ONLY__)
+# define CONSTANT __attribute__((opencl_constant))
+#else
+# define CONSTANT
+#endif
+
+#define sycl_printf(format, ...) { \
+ static const CONSTANT char fmt[] = format; \
+ sycl::ext::oneapi::experimental::printf(fmt, __VA_ARGS__ ); \
+ }
+
+#define sycl_printf_(format) { \
+ static const CONSTANT char fmt[] = format; \
+ sycl::ext::oneapi::experimental::printf(fmt); \
+ }
+
+/* GPU texture objects */
+
+/* clang-format on */
+
+/* Types */
+/* It's not possible to use sycl types like sycl::float3, sycl::int3, etc
+ * because these types have different interfaces from blender version */
+
+using uchar = unsigned char;
+using sycl::half;
+
+struct float3 {
+ float x, y, z;
+};
+
+ccl_always_inline float3 make_float3(float x, float y, float z)
+{
+ return {x, y, z};
+}
+ccl_always_inline float3 make_float3(float x)
+{
+ return {x, x, x};
+}
+
+/* math functions */
+#define fabsf(x) sycl::fabs((x))
+#define copysignf(x, y) sycl::copysign((x), (y))
+#define asinf(x) sycl::asin((x))
+#define acosf(x) sycl::acos((x))
+#define atanf(x) sycl::atan((x))
+#define floorf(x) sycl::floor((x))
+#define ceilf(x) sycl::ceil((x))
+#define sinhf(x) sycl::sinh((x))
+#define coshf(x) sycl::cosh((x))
+#define tanhf(x) sycl::tanh((x))
+#define hypotf(x, y) sycl::hypot((x), (y))
+#define atan2f(x, y) sycl::atan2((x), (y))
+#define fmaxf(x, y) sycl::fmax((x), (y))
+#define fminf(x, y) sycl::fmin((x), (y))
+#define fmodf(x, y) sycl::fmod((x), (y))
+#define lgammaf(x) sycl::lgamma((x))
+
+#define __forceinline __attribute__((always_inline))
+
+/* Types */
+#include "util/half.h"
+#include "util/types.h"
+
+/* NOTE(@nsirgien): Declaring these functions after types headers is very important because they
+ * include oneAPI headers, which transitively include math.h headers which will cause redefinitions
+ * of the math defines because math.h also uses them and having them defined before math.h include
+ * is actually UB. */
+/* Use fast math functions - get them from sycl::native namespace for native math function
+ * implementations */
+#define cosf(x) sycl::native::cos(((float)(x)))
+#define sinf(x) sycl::native::sin(((float)(x)))
+#define powf(x, y) sycl::native::powr(((float)(x)), ((float)(y)))
+#define tanf(x) sycl::native::tan(((float)(x)))
+#define logf(x) sycl::native::log(((float)(x)))
+#define expf(x) sycl::native::exp(((float)(x)))
diff --git a/intern/cycles/kernel/device/oneapi/context_begin.h b/intern/cycles/kernel/device/oneapi/context_begin.h
new file mode 100644
index 00000000000..6d6f8cec4ca
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/context_begin.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#ifdef WITH_NANOVDB
+# include <nanovdb/NanoVDB.h>
+# include <nanovdb/util/SampleFromVoxels.h>
+#endif
+
+/* clang-format off */
+struct ONEAPIKernelContext : public KernelGlobalsGPU {
+ public:
+# include "kernel/device/oneapi/image.h"
+ /* clang-format on */
diff --git a/intern/cycles/kernel/device/oneapi/context_end.h b/intern/cycles/kernel/device/oneapi/context_end.h
new file mode 100644
index 00000000000..ddf0d1f1712
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/context_end.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+}
+; /* end of ONEAPIKernelContext class definition */
+
+#undef kernel_integrator_state
+#define kernel_integrator_state (*(kg->integrator_state))
diff --git a/intern/cycles/kernel/device/oneapi/dll_interface_template.h b/intern/cycles/kernel/device/oneapi/dll_interface_template.h
new file mode 100644
index 00000000000..662068c0fed
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/dll_interface_template.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 Intel Corporation */
+
+/* device_capabilities() returns a C string that must be free'd with oneapi_free(). */
+DLL_INTERFACE_CALL(oneapi_device_capabilities, char *)
+DLL_INTERFACE_CALL(oneapi_free, void, void *)
+DLL_INTERFACE_CALL(oneapi_get_memcapacity, size_t, SyclQueue *queue)
+
+DLL_INTERFACE_CALL(oneapi_get_compute_units_amount, size_t, SyclQueue *queue)
+DLL_INTERFACE_CALL(oneapi_iterate_devices, void, OneAPIDeviceIteratorCallback cb, void *user_ptr)
+DLL_INTERFACE_CALL(oneapi_set_error_cb, void, OneAPIErrorCallback, void *user_ptr)
+
+DLL_INTERFACE_CALL(oneapi_create_queue, bool, SyclQueue *&external_queue, int device_index)
+DLL_INTERFACE_CALL(oneapi_free_queue, void, SyclQueue *queue)
+DLL_INTERFACE_CALL(
+ oneapi_usm_aligned_alloc_host, void *, SyclQueue *queue, size_t memory_size, size_t alignment)
+DLL_INTERFACE_CALL(oneapi_usm_alloc_device, void *, SyclQueue *queue, size_t memory_size)
+DLL_INTERFACE_CALL(oneapi_usm_free, void, SyclQueue *queue, void *usm_ptr)
+
+DLL_INTERFACE_CALL(
+ oneapi_usm_memcpy, bool, SyclQueue *queue, void *dest, void *src, size_t num_bytes)
+DLL_INTERFACE_CALL(oneapi_queue_synchronize, bool, SyclQueue *queue)
+DLL_INTERFACE_CALL(oneapi_usm_memset,
+ bool,
+ SyclQueue *queue,
+ void *usm_ptr,
+ unsigned char value,
+ size_t num_bytes)
+
+DLL_INTERFACE_CALL(oneapi_run_test_kernel, bool, SyclQueue *queue)
+
+/* Operation with Kernel globals structure - map of global/constant allocation - filled before
+ * render/kernel execution As we don't know in cycles `sizeof` this - Cycles will manage just as
+ * pointer. */
+DLL_INTERFACE_CALL(oneapi_kernel_globals_size, bool, SyclQueue *queue, size_t &kernel_global_size)
+DLL_INTERFACE_CALL(oneapi_set_global_memory,
+ void,
+ SyclQueue *queue,
+ void *kernel_globals,
+ const char *memory_name,
+ void *memory_device_pointer)
+
+DLL_INTERFACE_CALL(oneapi_kernel_preferred_local_size,
+ size_t,
+ SyclQueue *queue,
+ const DeviceKernel kernel,
+ const size_t kernel_global_size)
+DLL_INTERFACE_CALL(oneapi_enqueue_kernel,
+ bool,
+ KernelContext *context,
+ int kernel,
+ size_t global_size,
+ void **args)
diff --git a/intern/cycles/kernel/device/oneapi/globals.h b/intern/cycles/kernel/device/oneapi/globals.h
new file mode 100644
index 00000000000..d60f4f135ba
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/globals.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#pragma once
+
+#include "kernel/integrator/state.h"
+#include "kernel/types.h"
+#include "kernel/util/profiling.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* NOTE(@nsirgien): With SYCL we can't declare __constant__ global variable, which will be
+ * accessible from device code, like it has been done for Cycles CUDA backend. So, the backend will
+ * allocate this "constant" memory regions and store pointers to them in oneAPI context class */
+
+struct IntegratorStateGPU;
+struct IntegratorQueueCounter;
+
+typedef struct KernelGlobalsGPU {
+
+#define KERNEL_DATA_ARRAY(type, name) const type *__##name = nullptr;
+#include "kernel/data_arrays.h"
+#undef KERNEL_DATA_ARRAY
+ IntegratorStateGPU *integrator_state;
+ const KernelData *__data;
+#ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
+ size_t nd_item_local_id_0;
+ size_t nd_item_local_range_0;
+ size_t nd_item_group_0;
+ size_t nd_item_group_range_0;
+
+ size_t nd_item_global_id_0;
+ size_t nd_item_global_range_0;
+#endif
+} KernelGlobalsGPU;
+
+typedef ccl_global KernelGlobalsGPU *ccl_restrict KernelGlobals;
+
+#define kernel_data (*(__data))
+#define kernel_integrator_state (*(integrator_state))
+
+/* data lookup defines */
+
+#define kernel_data_fetch(name, index) __##name[index]
+#define kernel_data_array(name) __##name
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/oneapi/image.h b/intern/cycles/kernel/device/oneapi/image.h
new file mode 100644
index 00000000000..6681977a675
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/image.h
@@ -0,0 +1,385 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+CCL_NAMESPACE_BEGIN
+
+/* For oneAPI implementation we do manual lookup and interpolation. */
+/* TODO: share implementation with ../cpu/image.h. */
+
+template<typename T> ccl_device_forceinline T tex_fetch(const TextureInfo &info, int index)
+{
+ return reinterpret_cast<ccl_global T *>(info.data)[index];
+}
+
+ccl_device_inline int svm_image_texture_wrap_periodic(int x, int width)
+{
+ x %= width;
+ if (x < 0)
+ x += width;
+ return x;
+}
+
+ccl_device_inline int svm_image_texture_wrap_clamp(int x, int width)
+{
+ return clamp(x, 0, width - 1);
+}
+
+ccl_device_inline float4 svm_image_texture_read(const TextureInfo &info, int x, int y, int z)
+{
+ const int data_offset = x + info.width * y + info.width * info.height * z;
+ const int texture_type = info.data_type;
+
+ /* Float4 */
+ if (texture_type == IMAGE_DATA_TYPE_FLOAT4) {
+ return tex_fetch<float4>(info, data_offset);
+ }
+ /* Byte4 */
+ else if (texture_type == IMAGE_DATA_TYPE_BYTE4) {
+ uchar4 r = tex_fetch<uchar4>(info, data_offset);
+ float f = 1.0f / 255.0f;
+ return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
+ }
+ /* Ushort4 */
+ else if (texture_type == IMAGE_DATA_TYPE_USHORT4) {
+ ushort4 r = tex_fetch<ushort4>(info, data_offset);
+ float f = 1.0f / 65535.f;
+ return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
+ }
+ /* Float */
+ else if (texture_type == IMAGE_DATA_TYPE_FLOAT) {
+ float f = tex_fetch<float>(info, data_offset);
+ return make_float4(f, f, f, 1.0f);
+ }
+ /* UShort */
+ else if (texture_type == IMAGE_DATA_TYPE_USHORT) {
+ ushort r = tex_fetch<ushort>(info, data_offset);
+ float f = r * (1.0f / 65535.0f);
+ return make_float4(f, f, f, 1.0f);
+ }
+ else if (texture_type == IMAGE_DATA_TYPE_HALF) {
+ float f = tex_fetch<half>(info, data_offset);
+ return make_float4(f, f, f, 1.0f);
+ }
+ else if (texture_type == IMAGE_DATA_TYPE_HALF4) {
+ half4 r = tex_fetch<half4>(info, data_offset);
+ return make_float4(r.x, r.y, r.z, r.w);
+ }
+ /* Byte */
+ else {
+ uchar r = tex_fetch<uchar>(info, data_offset);
+ float f = r * (1.0f / 255.0f);
+ return make_float4(f, f, f, 1.0f);
+ }
+}
+
+ccl_device_inline float4 svm_image_texture_read_2d(int id, int x, int y)
+{
+ const TextureInfo &info = kernel_data_fetch(texture_info, id);
+
+ /* Wrap */
+ if (info.extension == EXTENSION_REPEAT) {
+ x = svm_image_texture_wrap_periodic(x, info.width);
+ y = svm_image_texture_wrap_periodic(y, info.height);
+ }
+ else {
+ x = svm_image_texture_wrap_clamp(x, info.width);
+ y = svm_image_texture_wrap_clamp(y, info.height);
+ }
+
+ return svm_image_texture_read(info, x, y, 0);
+}
+
+ccl_device_inline float4 svm_image_texture_read_3d(int id, int x, int y, int z)
+{
+ const TextureInfo &info = kernel_data_fetch(texture_info, id);
+
+ /* Wrap */
+ if (info.extension == EXTENSION_REPEAT) {
+ x = svm_image_texture_wrap_periodic(x, info.width);
+ y = svm_image_texture_wrap_periodic(y, info.height);
+ z = svm_image_texture_wrap_periodic(z, info.depth);
+ }
+ else {
+ x = svm_image_texture_wrap_clamp(x, info.width);
+ y = svm_image_texture_wrap_clamp(y, info.height);
+ z = svm_image_texture_wrap_clamp(z, info.depth);
+ }
+
+ return svm_image_texture_read(info, x, y, z);
+}
+
+static float svm_image_texture_frac(float x, int *ix)
+{
+ int i = float_to_int(x) - ((x < 0.0f) ? 1 : 0);
+ *ix = i;
+ return x - (float)i;
+}
+
+#define SET_CUBIC_SPLINE_WEIGHTS(u, t) \
+ { \
+ u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \
+ u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \
+ u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \
+ u[3] = (1.0f / 6.0f) * t * t * t; \
+ } \
+ (void)0
+
+ccl_device float4 kernel_tex_image_interp(KernelGlobals, int id, float x, float y)
+{
+ const TextureInfo &info = kernel_data_fetch(texture_info, id);
+
+ if (info.extension == EXTENSION_CLIP) {
+ if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if (info.interpolation == INTERPOLATION_CLOSEST) {
+ /* Closest interpolation. */
+ int ix, iy;
+ svm_image_texture_frac(x * info.width, &ix);
+ svm_image_texture_frac(y * info.height, &iy);
+
+ return svm_image_texture_read_2d(id, ix, iy);
+ }
+ else if (info.interpolation == INTERPOLATION_LINEAR) {
+ /* Bilinear interpolation. */
+ int ix, iy;
+ float tx = svm_image_texture_frac(x * info.width - 0.5f, &ix);
+ float ty = svm_image_texture_frac(y * info.height - 0.5f, &iy);
+
+ float4 r;
+ r = (1.0f - ty) * (1.0f - tx) * svm_image_texture_read_2d(id, ix, iy);
+ r += (1.0f - ty) * tx * svm_image_texture_read_2d(id, ix + 1, iy);
+ r += ty * (1.0f - tx) * svm_image_texture_read_2d(id, ix, iy + 1);
+ r += ty * tx * svm_image_texture_read_2d(id, ix + 1, iy + 1);
+ return r;
+ }
+ else {
+ /* Bicubic interpolation. */
+ int ix, iy;
+ float tx = svm_image_texture_frac(x * info.width - 0.5f, &ix);
+ float ty = svm_image_texture_frac(y * info.height - 0.5f, &iy);
+
+ float u[4], v[4];
+ SET_CUBIC_SPLINE_WEIGHTS(u, tx);
+ SET_CUBIC_SPLINE_WEIGHTS(v, ty);
+
+ float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ float weight = u[x] * v[y];
+ r += weight * svm_image_texture_read_2d(id, ix + x - 1, iy + y - 1);
+ }
+ }
+ return r;
+ }
+}
+
+#ifdef WITH_NANOVDB
+template<typename T> struct NanoVDBInterpolator {
+
+ typedef typename nanovdb::NanoGrid<T>::AccessorType AccessorType;
+
+ static ccl_always_inline float4 read(float r)
+ {
+ return make_float4(r, r, r, 1.0f);
+ }
+
+ static ccl_always_inline float4 read(nanovdb::Vec3f r)
+ {
+ return make_float4(r[0], r[1], r[2], 1.0f);
+ }
+
+ static ccl_always_inline float4 interp_3d_closest(const AccessorType &acc,
+ float x,
+ float y,
+ float z)
+ {
+ const nanovdb::Vec3f xyz(x, y, z);
+ return read(nanovdb::SampleFromVoxels<AccessorType, 0, false>(acc)(xyz));
+ }
+
+ static ccl_always_inline float4 interp_3d_linear(const AccessorType &acc,
+ float x,
+ float y,
+ float z)
+ {
+ const nanovdb::Vec3f xyz(x - 0.5f, y - 0.5f, z - 0.5f);
+ return read(nanovdb::SampleFromVoxels<AccessorType, 1, false>(acc)(xyz));
+ }
+
+ static float4 interp_3d_cubic(const AccessorType &acc, float x, float y, float z)
+ {
+ int ix, iy, iz;
+ int nix, niy, niz;
+ int pix, piy, piz;
+ int nnix, nniy, nniz;
+ /* Tri-cubic b-spline interpolation. */
+ const float tx = svm_image_texture_frac(x - 0.5f, &ix);
+ const float ty = svm_image_texture_frac(y - 0.5f, &iy);
+ const float tz = svm_image_texture_frac(z - 0.5f, &iz);
+ pix = ix - 1;
+ piy = iy - 1;
+ piz = iz - 1;
+ nix = ix + 1;
+ niy = iy + 1;
+ niz = iz + 1;
+ nnix = ix + 2;
+ nniy = iy + 2;
+ nniz = iz + 2;
+
+ const int xc[4] = {pix, ix, nix, nnix};
+ const int yc[4] = {piy, iy, niy, nniy};
+ const int zc[4] = {piz, iz, niz, nniz};
+ float u[4], v[4], w[4];
+
+ /* Some helper macro to keep code reasonable size,
+ * let compiler to inline all the matrix multiplications.
+ */
+# define DATA(x, y, z) (read(acc.getValue(nanovdb::Coord(xc[x], yc[y], zc[z]))))
+# define COL_TERM(col, row) \
+ (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \
+ u[3] * DATA(3, col, row)))
+# define ROW_TERM(row) \
+ (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
+
+ SET_CUBIC_SPLINE_WEIGHTS(u, tx);
+ SET_CUBIC_SPLINE_WEIGHTS(v, ty);
+ SET_CUBIC_SPLINE_WEIGHTS(w, tz);
+
+ /* Actual interpolation. */
+ return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
+
+# undef COL_TERM
+# undef ROW_TERM
+# undef DATA
+ }
+
+ static ccl_always_inline float4
+ interp_3d(const TextureInfo &info, float x, float y, float z, int interp)
+ {
+ using namespace nanovdb;
+
+ NanoGrid<T> *const grid = (NanoGrid<T> *)info.data;
+ AccessorType acc = grid->getAccessor();
+
+ switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
+ case INTERPOLATION_CLOSEST:
+ return interp_3d_closest(acc, x, y, z);
+ case INTERPOLATION_LINEAR:
+ return interp_3d_linear(acc, x, y, z);
+ default:
+ return interp_3d_cubic(acc, x, y, z);
+ }
+ }
+};
+#endif /* WITH_NANOVDB */
+
+ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals, int id, float3 P, int interp)
+{
+ const TextureInfo &info = kernel_data_fetch(texture_info, id);
+
+ if (info.use_transform_3d) {
+ Transform tfm = info.transform_3d;
+ P = transform_point(&tfm, P);
+ }
+
+ float x = P.x;
+ float y = P.y;
+ float z = P.z;
+
+ uint interpolation = (interp == INTERPOLATION_NONE) ? info.interpolation : interp;
+
+#ifdef WITH_NANOVDB
+ if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT) {
+ return NanoVDBInterpolator<float>::interp_3d(info, x, y, z, interpolation);
+ }
+ else if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ return NanoVDBInterpolator<nanovdb::Vec3f>::interp_3d(info, x, y, z, interpolation);
+ }
+ else if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FPN) {
+ return NanoVDBInterpolator<nanovdb::FpN>::interp_3d(info, x, y, z, interpolation);
+ }
+ else if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
+ return NanoVDBInterpolator<nanovdb::Fp16>::interp_3d(info, x, y, z, interpolation);
+ }
+#else
+ if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT ||
+ info.data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3 ||
+ info.data_type == IMAGE_DATA_TYPE_NANOVDB_FPN ||
+ info.data_type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
+ return make_float4(
+ TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
+ }
+#endif
+ else {
+ if (info.extension == EXTENSION_CLIP) {
+ if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) {
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+
+ x *= info.width;
+ y *= info.height;
+ z *= info.depth;
+ }
+
+ if (interpolation == INTERPOLATION_CLOSEST) {
+ /* Closest interpolation. */
+ int ix, iy, iz;
+ svm_image_texture_frac(x, &ix);
+ svm_image_texture_frac(y, &iy);
+ svm_image_texture_frac(z, &iz);
+
+ return svm_image_texture_read_3d(id, ix, iy, iz);
+ }
+ else if (interpolation == INTERPOLATION_LINEAR) {
+ /* Trilinear interpolation. */
+ int ix, iy, iz;
+ float tx = svm_image_texture_frac(x - 0.5f, &ix);
+ float ty = svm_image_texture_frac(y - 0.5f, &iy);
+ float tz = svm_image_texture_frac(z - 0.5f, &iz);
+
+ float4 r;
+ r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) * svm_image_texture_read_3d(id, ix, iy, iz);
+ r += (1.0f - tz) * (1.0f - ty) * tx * svm_image_texture_read_3d(id, ix + 1, iy, iz);
+ r += (1.0f - tz) * ty * (1.0f - tx) * svm_image_texture_read_3d(id, ix, iy + 1, iz);
+ r += (1.0f - tz) * ty * tx * svm_image_texture_read_3d(id, ix + 1, iy + 1, iz);
+
+ r += tz * (1.0f - ty) * (1.0f - tx) * svm_image_texture_read_3d(id, ix, iy, iz + 1);
+ r += tz * (1.0f - ty) * tx * svm_image_texture_read_3d(id, ix + 1, iy, iz + 1);
+ r += tz * ty * (1.0f - tx) * svm_image_texture_read_3d(id, ix, iy + 1, iz + 1);
+ r += tz * ty * tx * svm_image_texture_read_3d(id, ix + 1, iy + 1, iz + 1);
+ return r;
+ }
+ else {
+ /* Tri-cubic interpolation. */
+ int ix, iy, iz;
+ float tx = svm_image_texture_frac(x - 0.5f, &ix);
+ float ty = svm_image_texture_frac(y - 0.5f, &iy);
+ float tz = svm_image_texture_frac(z - 0.5f, &iz);
+
+ float u[4], v[4], w[4];
+ SET_CUBIC_SPLINE_WEIGHTS(u, tx);
+ SET_CUBIC_SPLINE_WEIGHTS(v, ty);
+ SET_CUBIC_SPLINE_WEIGHTS(w, tz);
+
+ float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ for (int z = 0; z < 4; z++) {
+ for (int y = 0; y < 4; y++) {
+ for (int x = 0; x < 4; x++) {
+ float weight = u[x] * v[y] * w[z];
+ r += weight * svm_image_texture_read_3d(id, ix + x - 1, iy + y - 1, iz + z - 1);
+ }
+ }
+ }
+ return r;
+ }
+}
+
+#undef SET_CUBIC_SPLINE_WEIGHTS
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/oneapi/kernel.cpp b/intern/cycles/kernel/device/oneapi/kernel.cpp
new file mode 100644
index 00000000000..300e201600c
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/kernel.cpp
@@ -0,0 +1,914 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#ifdef WITH_ONEAPI
+
+/* clang-format off */
+# include "kernel.h"
+# include <iostream>
+# include <map>
+# include <set>
+
+# include <CL/sycl.hpp>
+
+# include "kernel/device/oneapi/compat.h"
+# include "kernel/device/oneapi/globals.h"
+# include "kernel/device/oneapi/kernel_templates.h"
+
+# include "kernel/device/gpu/kernel.h"
+/* clang-format on */
+
+static OneAPIErrorCallback s_error_cb = nullptr;
+static void *s_error_user_ptr = nullptr;
+
+static std::vector<sycl::device> oneapi_available_devices();
+
+void oneapi_set_error_cb(OneAPIErrorCallback cb, void *user_ptr)
+{
+ s_error_cb = cb;
+ s_error_user_ptr = user_ptr;
+}
+
+void oneapi_check_usm(SyclQueue *queue_, const void *usm_ptr, bool allow_host = false)
+{
+# ifdef _DEBUG
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ sycl::info::device_type device_type =
+ queue->get_device().get_info<sycl::info::device::device_type>();
+ sycl::usm::alloc usm_type = get_pointer_type(usm_ptr, queue->get_context());
+ (void)usm_type;
+ assert(usm_type == sycl::usm::alloc::device ||
+ ((device_type == sycl::info::device_type::host ||
+ device_type == sycl::info::device_type::is_cpu || allow_host) &&
+ usm_type == sycl::usm::alloc::host));
+# endif
+}
+
+bool oneapi_create_queue(SyclQueue *&external_queue, int device_index)
+{
+ bool finished_correct = true;
+ try {
+ std::vector<sycl::device> devices = oneapi_available_devices();
+ if (device_index < 0 || device_index >= devices.size()) {
+ return false;
+ }
+ sycl::queue *created_queue = new sycl::queue(devices[device_index],
+ sycl::property::queue::in_order());
+ external_queue = reinterpret_cast<SyclQueue *>(created_queue);
+ }
+ catch (sycl::exception const &e) {
+ finished_correct = false;
+ if (s_error_cb) {
+ s_error_cb(e.what(), s_error_user_ptr);
+ }
+ }
+ return finished_correct;
+}
+
+void oneapi_free_queue(SyclQueue *queue_)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ delete queue;
+}
+
+void *oneapi_usm_aligned_alloc_host(SyclQueue *queue_, size_t memory_size, size_t alignment)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ return sycl::aligned_alloc_host(alignment, memory_size, *queue);
+}
+
+void *oneapi_usm_alloc_device(SyclQueue *queue_, size_t memory_size)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ return sycl::malloc_device(memory_size, *queue);
+}
+
+void oneapi_usm_free(SyclQueue *queue_, void *usm_ptr)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ oneapi_check_usm(queue_, usm_ptr, true);
+ sycl::free(usm_ptr, *queue);
+}
+
+bool oneapi_usm_memcpy(SyclQueue *queue_, void *dest, void *src, size_t num_bytes)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ oneapi_check_usm(queue_, dest, true);
+ oneapi_check_usm(queue_, src, true);
+ sycl::event mem_event = queue->memcpy(dest, src, num_bytes);
+# ifdef WITH_CYCLES_DEBUG
+ try {
+ /* NOTE(@nsirgien) Waiting on memory operation may give more precise error
+ * messages. Due to impact on occupancy, it makes sense to enable it only during Cycles debug.
+ */
+ mem_event.wait_and_throw();
+ return true;
+ }
+ catch (sycl::exception const &e) {
+ if (s_error_cb) {
+ s_error_cb(e.what(), s_error_user_ptr);
+ }
+ return false;
+ }
+# else
+ sycl::usm::alloc dest_type = get_pointer_type(dest, queue->get_context());
+ sycl::usm::alloc src_type = get_pointer_type(src, queue->get_context());
+ bool from_device_to_host = dest_type == sycl::usm::alloc::host &&
+ src_type == sycl::usm::alloc::device;
+ bool host_or_device_memop_with_offset = dest_type == sycl::usm::alloc::unknown ||
+ src_type == sycl::usm::alloc::unknown;
+ /* NOTE(@sirgienko) Host-side blocking wait on this operation is mandatory, otherwise the host
+ * may not wait until the end of the transfer before using the memory.
+ */
+ if (from_device_to_host || host_or_device_memop_with_offset)
+ mem_event.wait();
+ return true;
+# endif
+}
+
+bool oneapi_usm_memset(SyclQueue *queue_, void *usm_ptr, unsigned char value, size_t num_bytes)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ oneapi_check_usm(queue_, usm_ptr, true);
+ sycl::event mem_event = queue->memset(usm_ptr, value, num_bytes);
+# ifdef WITH_CYCLES_DEBUG
+ try {
+ /* NOTE(@nsirgien) Waiting on memory operation may give more precise error
+ * messages. Due to impact on occupancy, it makes sense to enable it only during Cycles debug.
+ */
+ mem_event.wait_and_throw();
+ return true;
+ }
+ catch (sycl::exception const &e) {
+ if (s_error_cb) {
+ s_error_cb(e.what(), s_error_user_ptr);
+ }
+ return false;
+ }
+# else
+ (void)mem_event;
+ return true;
+# endif
+}
+
+bool oneapi_queue_synchronize(SyclQueue *queue_)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ try {
+ queue->wait_and_throw();
+ return true;
+ }
+ catch (sycl::exception const &e) {
+ if (s_error_cb) {
+ s_error_cb(e.what(), s_error_user_ptr);
+ }
+ return false;
+ }
+}
+
+/* NOTE(@nsirgien): Execution of this simple kernel will check basic functionality and
+ * also trigger runtime compilation of all existing oneAPI kernels */
+bool oneapi_run_test_kernel(SyclQueue *queue_)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ size_t N = 8;
+ sycl::buffer<float, 1> A(N);
+ sycl::buffer<float, 1> B(N);
+
+ {
+ sycl::host_accessor A_host_acc(A, sycl::write_only);
+ for (size_t i = (size_t)0; i < N; i++)
+ A_host_acc[i] = rand() % 32;
+ }
+
+ try {
+ queue->submit([&](sycl::handler &cgh) {
+ sycl::accessor A_acc(A, cgh, sycl::read_only);
+ sycl::accessor B_acc(B, cgh, sycl::write_only, sycl::no_init);
+
+ cgh.parallel_for(N, [=](sycl::id<1> idx) { B_acc[idx] = A_acc[idx] + idx.get(0); });
+ });
+ queue->wait_and_throw();
+
+ sycl::host_accessor A_host_acc(A, sycl::read_only);
+ sycl::host_accessor B_host_acc(B, sycl::read_only);
+
+ for (size_t i = (size_t)0; i < N; i++) {
+ float result = A_host_acc[i] + B_host_acc[i];
+ (void)result;
+ }
+ }
+ catch (sycl::exception const &e) {
+ if (s_error_cb) {
+ s_error_cb(e.what(), s_error_user_ptr);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool oneapi_kernel_globals_size(SyclQueue *queue_, size_t &kernel_global_size)
+{
+ kernel_global_size = sizeof(KernelGlobalsGPU);
+
+ return true;
+}
+
+void oneapi_set_global_memory(SyclQueue *queue_,
+ void *kernel_globals,
+ const char *memory_name,
+ void *memory_device_pointer)
+{
+ assert(queue_);
+ assert(kernel_globals);
+ assert(memory_name);
+ assert(memory_device_pointer);
+ KernelGlobalsGPU *globals = (KernelGlobalsGPU *)kernel_globals;
+ oneapi_check_usm(queue_, memory_device_pointer);
+ oneapi_check_usm(queue_, kernel_globals, true);
+
+ std::string matched_name(memory_name);
+
+/* This macro will change global ptr of KernelGlobals via name matching. */
+# define KERNEL_DATA_ARRAY(type, name) \
+ else if (#name == matched_name) \
+ { \
+ globals->__##name = (type *)memory_device_pointer; \
+ return; \
+ }
+ if (false) {
+ }
+ else if ("integrator_state" == matched_name) {
+ globals->integrator_state = (IntegratorStateGPU *)memory_device_pointer;
+ return;
+ }
+ KERNEL_DATA_ARRAY(KernelData, data)
+# include "kernel/data_arrays.h"
+ else
+ {
+ std::cerr << "Can't found global/constant memory with name \"" << matched_name << "\"!"
+ << std::endl;
+ assert(false);
+ }
+# undef KERNEL_DATA_ARRAY
+}
+
+/* TODO: Move device information to OneapiDevice initialized on creation and use it. */
+/* TODO: Move below function to oneapi/queue.cpp. */
+size_t oneapi_kernel_preferred_local_size(SyclQueue *queue_,
+ const DeviceKernel kernel,
+ const size_t kernel_global_size)
+{
+ assert(queue_);
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(queue_);
+ (void)kernel_global_size;
+ const static size_t preferred_work_group_size_intersect_shading = 32;
+ const static size_t preferred_work_group_size_technical = 1024;
+
+ size_t preferred_work_group_size = 0;
+ switch (kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA:
+ case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE:
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME:
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW:
+ preferred_work_group_size = preferred_work_group_size_intersect_shading;
+ break;
+
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES:
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY:
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES:
+ case DEVICE_KERNEL_INTEGRATOR_RESET:
+ case DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS:
+ preferred_work_group_size = preferred_work_group_size_technical;
+ break;
+
+ default:
+ preferred_work_group_size = 512;
+ }
+
+ const size_t limit_work_group_size =
+ queue->get_device().get_info<sycl::info::device::max_work_group_size>();
+ return std::min(limit_work_group_size, preferred_work_group_size);
+}
+
+bool oneapi_enqueue_kernel(KernelContext *kernel_context,
+ int kernel,
+ size_t global_size,
+ void **args)
+{
+ bool success = true;
+ ::DeviceKernel device_kernel = (::DeviceKernel)kernel;
+ KernelGlobalsGPU *kg = (KernelGlobalsGPU *)kernel_context->kernel_globals;
+ sycl::queue *queue = reinterpret_cast<sycl::queue *>(kernel_context->queue);
+ assert(queue);
+ if (!queue) {
+ return false;
+ }
+
+ size_t local_size = oneapi_kernel_preferred_local_size(
+ kernel_context->queue, device_kernel, global_size);
+ assert(global_size % local_size == 0);
+
+ /* Local size for DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY needs to be enforced so we
+ * overwrite it outside of oneapi_kernel_preferred_local_size. */
+ if (device_kernel == DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY) {
+ local_size = GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE;
+ }
+
+ /* Kernels listed below need a specific number of work groups. */
+ if (device_kernel == DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY) {
+ int num_states = *((int *)(args[0]));
+ /* Round up to the next work-group. */
+ size_t groups_count = (num_states + local_size - 1) / local_size;
+ /* NOTE(@nsirgien): As for now non-uniform work-groups don't work on most oneAPI devices,
+ * we extend work size to fit uniformity requirements. */
+ global_size = groups_count * local_size;
+
+# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
+ if (queue->get_device().is_host()) {
+ global_size = 1;
+ local_size = 1;
+ }
+# endif
+ }
+
+ /* Let the compiler throw an error if there are any kernels missing in this implementation. */
+# if defined(_WIN32)
+# pragma warning(error : 4062)
+# elif defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic error "-Wswitch"
+# endif
+
+ try {
+ queue->submit([&](sycl::handler &cgh) {
+ switch (device_kernel) {
+ case DEVICE_KERNEL_INTEGRATOR_RESET: {
+ oneapi_call(kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_reset);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_init_from_camera);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_init_from_bake);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_intersect_closest);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_intersect_shadow);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_intersect_subsurface);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_intersect_volume_stack);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_background);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_light);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_shadow);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_surface);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_shade_surface_raytrace);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_surface_mnee);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_shade_volume);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_PATHS_ARRAY: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_queued_paths_array);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_QUEUED_SHADOW_PATHS_ARRAY: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_queued_shadow_paths_array);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_ACTIVE_PATHS_ARRAY: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_active_paths_array);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_PATHS_ARRAY: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_terminated_paths_array);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_TERMINATED_SHADOW_PATHS_ARRAY: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_terminated_shadow_paths_array);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SORTED_PATHS_ARRAY: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_sorted_paths_array);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_PATHS_ARRAY: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_compact_paths_array);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_PATHS_ARRAY: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_compact_shadow_paths_array);
+ break;
+ }
+ case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_CHECK: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_adaptive_sampling_convergence_check);
+ break;
+ }
+ case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_X: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_adaptive_sampling_filter_x);
+ break;
+ }
+ case DEVICE_KERNEL_ADAPTIVE_SAMPLING_CONVERGENCE_FILTER_Y: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_adaptive_sampling_filter_y);
+ break;
+ }
+ case DEVICE_KERNEL_SHADER_EVAL_DISPLACE: {
+ oneapi_call(kg, cgh, global_size, local_size, args, oneapi_kernel_shader_eval_displace);
+ break;
+ }
+ case DEVICE_KERNEL_SHADER_EVAL_BACKGROUND: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_shader_eval_background);
+ break;
+ }
+ case DEVICE_KERNEL_SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_shader_eval_curve_shadow_transparency);
+ break;
+ }
+ case DEVICE_KERNEL_PREFIX_SUM: {
+ oneapi_call(kg, cgh, global_size, local_size, args, oneapi_kernel_prefix_sum);
+ break;
+ }
+
+ /* clang-format off */
+ # define DEVICE_KERNEL_FILM_CONVERT_PARTIAL(VARIANT, variant) \
+ case DEVICE_KERNEL_FILM_CONVERT_##VARIANT: { \
+ oneapi_call(kg, cgh, \
+ global_size, \
+ local_size, \
+ args, \
+ oneapi_kernel_film_convert_##variant); \
+ break; \
+ }
+
+# define DEVICE_KERNEL_FILM_CONVERT(variant, VARIANT) \
+ DEVICE_KERNEL_FILM_CONVERT_PARTIAL(VARIANT, variant) \
+ DEVICE_KERNEL_FILM_CONVERT_PARTIAL(VARIANT##_HALF_RGBA, variant##_half_rgba)
+
+ DEVICE_KERNEL_FILM_CONVERT(depth, DEPTH);
+ DEVICE_KERNEL_FILM_CONVERT(mist, MIST);
+ DEVICE_KERNEL_FILM_CONVERT(sample_count, SAMPLE_COUNT);
+ DEVICE_KERNEL_FILM_CONVERT(float, FLOAT);
+ DEVICE_KERNEL_FILM_CONVERT(light_path, LIGHT_PATH);
+ DEVICE_KERNEL_FILM_CONVERT(float3, FLOAT3);
+ DEVICE_KERNEL_FILM_CONVERT(motion, MOTION);
+ DEVICE_KERNEL_FILM_CONVERT(cryptomatte, CRYPTOMATTE);
+ DEVICE_KERNEL_FILM_CONVERT(shadow_catcher, SHADOW_CATCHER);
+ DEVICE_KERNEL_FILM_CONVERT(shadow_catcher_matte_with_shadow,
+ SHADOW_CATCHER_MATTE_WITH_SHADOW);
+ DEVICE_KERNEL_FILM_CONVERT(combined, COMBINED);
+ DEVICE_KERNEL_FILM_CONVERT(float4, FLOAT4);
+
+# undef DEVICE_KERNEL_FILM_CONVERT
+# undef DEVICE_KERNEL_FILM_CONVERT_PARTIAL
+ /* clang-format on */
+
+ case DEVICE_KERNEL_FILTER_GUIDING_PREPROCESS: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_filter_guiding_preprocess);
+ break;
+ }
+ case DEVICE_KERNEL_FILTER_GUIDING_SET_FAKE_ALBEDO: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_filter_guiding_set_fake_albedo);
+ break;
+ }
+ case DEVICE_KERNEL_FILTER_COLOR_PREPROCESS: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_filter_color_preprocess);
+ break;
+ }
+ case DEVICE_KERNEL_FILTER_COLOR_POSTPROCESS: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_filter_color_postprocess);
+ break;
+ }
+ case DEVICE_KERNEL_CRYPTOMATTE_POSTPROCESS: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_cryptomatte_postprocess);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_STATES: {
+ oneapi_call(
+ kg, cgh, global_size, local_size, args, oneapi_kernel_integrator_compact_states);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_COMPACT_SHADOW_STATES: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_compact_shadow_states);
+ break;
+ }
+ case DEVICE_KERNEL_INTEGRATOR_SHADOW_CATCHER_COUNT_POSSIBLE_SPLITS: {
+ oneapi_call(kg,
+ cgh,
+ global_size,
+ local_size,
+ args,
+ oneapi_kernel_integrator_shadow_catcher_count_possible_splits);
+ break;
+ }
+ /* Unsupported kernels */
+ case DEVICE_KERNEL_NUM:
+ case DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL:
+ assert(0);
+ return false;
+ }
+
+ /* Unknown kernel. */
+ assert(0);
+ return false;
+ });
+ }
+ catch (sycl::exception const &e) {
+ if (s_error_cb) {
+ s_error_cb(e.what(), s_error_user_ptr);
+ success = false;
+ }
+ }
+
+# if defined(_WIN32)
+# pragma warning(default : 4062)
+# elif defined(__GNUC__)
+# pragma GCC diagnostic pop
+# endif
+ return success;
+}
+
+static const int lowest_supported_driver_version_win = 1011660;
+static const int lowest_supported_driver_version_neo = 23570;
+
+static int parse_driver_build_version(const sycl::device &device)
+{
+ const std::string &driver_version = device.get_info<sycl::info::device::driver_version>();
+ int driver_build_version = 0;
+
+ size_t second_dot_position = driver_version.find('.', driver_version.find('.') + 1);
+ if (second_dot_position == std::string::npos) {
+ std::cerr << "Unable to parse unknown Intel GPU driver version \"" << driver_version
+ << "\" does not match xx.xx.xxxxx (Linux), x.x.xxxx (L0),"
+ << " xx.xx.xxx.xxxx (Windows) for device \""
+ << device.get_info<sycl::info::device::name>() << "\"." << std::endl;
+ }
+ else {
+ try {
+ size_t third_dot_position = driver_version.find('.', second_dot_position + 1);
+ if (third_dot_position != std::string::npos) {
+ const std::string &third_number_substr = driver_version.substr(
+ second_dot_position + 1, third_dot_position - second_dot_position - 1);
+ const std::string &forth_number_substr = driver_version.substr(third_dot_position + 1);
+ if (third_number_substr.length() == 3 && forth_number_substr.length() == 4)
+ driver_build_version = std::stoi(third_number_substr) * 10000 +
+ std::stoi(forth_number_substr);
+ }
+ else {
+ const std::string &third_number_substr = driver_version.substr(second_dot_position + 1);
+ driver_build_version = std::stoi(third_number_substr);
+ }
+ }
+ catch (std::invalid_argument &e) {
+ std::cerr << "Unable to parse unknown Intel GPU driver version \"" << driver_version
+ << "\" does not match xx.xx.xxxxx (Linux), x.x.xxxx (L0),"
+ << " xx.xx.xxx.xxxx (Windows) for device \""
+ << device.get_info<sycl::info::device::name>() << "\"." << std::endl;
+ }
+ }
+
+ return driver_build_version;
+}
+
+static std::vector<sycl::device> oneapi_available_devices()
+{
+ bool allow_all_devices = false;
+ if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr)
+ allow_all_devices = true;
+
+ /* Host device is useful only for debugging at the moment
+ * so we hide this device with default build settings. */
+# ifdef WITH_ONEAPI_SYCL_HOST_ENABLED
+ bool allow_host = true;
+# else
+ bool allow_host = false;
+# endif
+
+ const std::vector<sycl::platform> &oneapi_platforms = sycl::platform::get_platforms();
+
+ std::vector<sycl::device> available_devices;
+ for (const sycl::platform &platform : oneapi_platforms) {
+ /* ignore OpenCL platforms to avoid using the same devices through both Level-Zero and OpenCL.
+ */
+ if (platform.get_backend() == sycl::backend::opencl) {
+ continue;
+ }
+
+ const std::vector<sycl::device> &oneapi_devices =
+ (allow_all_devices || allow_host) ? platform.get_devices(sycl::info::device_type::all) :
+ platform.get_devices(sycl::info::device_type::gpu);
+
+ for (const sycl::device &device : oneapi_devices) {
+ if (allow_all_devices) {
+ /* still filter out host device if build doesn't support it. */
+ if (allow_host || !device.is_host()) {
+ available_devices.push_back(device);
+ }
+ }
+ else {
+ bool filter_out = false;
+
+ /* For now we support all Intel(R) Arc(TM) devices and likely any future GPU,
+ * assuming they have either more than 96 Execution Units or not 7 threads per EU.
+ * Official support can be broaden to older and smaller GPUs once ready. */
+ if (device.is_gpu() && platform.get_backend() == sycl::backend::ext_oneapi_level_zero) {
+ /* Filtered-out defaults in-case these values aren't available through too old L0
+ * runtime. */
+ int number_of_eus = 96;
+ int threads_per_eu = 7;
+ if (device.has(sycl::aspect::ext_intel_gpu_eu_count)) {
+ number_of_eus = device.get_info<sycl::info::device::ext_intel_gpu_eu_count>();
+ }
+ if (device.has(sycl::aspect::ext_intel_gpu_hw_threads_per_eu)) {
+ threads_per_eu =
+ device.get_info<sycl::info::device::ext_intel_gpu_hw_threads_per_eu>();
+ }
+ /* This filters out all Level-Zero supported GPUs from older generation than Arc. */
+ if (number_of_eus <= 96 && threads_per_eu == 7) {
+ filter_out = true;
+ }
+ /* if not already filtered out, check driver version. */
+ if (!filter_out) {
+ int driver_build_version = parse_driver_build_version(device);
+ if ((driver_build_version > 100000 &&
+ driver_build_version < lowest_supported_driver_version_win) ||
+ (driver_build_version > 0 &&
+ driver_build_version < lowest_supported_driver_version_neo)) {
+ filter_out = true;
+ }
+ }
+ }
+ else if (!allow_host && device.is_host()) {
+ filter_out = true;
+ }
+ else if (!allow_all_devices) {
+ filter_out = true;
+ }
+
+ if (!filter_out) {
+ available_devices.push_back(device);
+ }
+ }
+ }
+ }
+
+ return available_devices;
+}
+
+char *oneapi_device_capabilities()
+{
+ std::stringstream capabilities;
+
+ const std::vector<sycl::device> &oneapi_devices = oneapi_available_devices();
+ for (const sycl::device &device : oneapi_devices) {
+ const std::string &name = device.get_info<sycl::info::device::name>();
+
+ capabilities << std::string("\t") << name << "\n";
+# define WRITE_ATTR(attribute_name, attribute_variable) \
+ capabilities << "\t\tsycl::info::device::" #attribute_name "\t\t\t" << attribute_variable \
+ << "\n";
+# define GET_NUM_ATTR(attribute) \
+ { \
+ size_t attribute = (size_t)device.get_info<sycl::info::device ::attribute>(); \
+ capabilities << "\t\tsycl::info::device::" #attribute "\t\t\t" << attribute << "\n"; \
+ }
+
+ GET_NUM_ATTR(vendor_id)
+ GET_NUM_ATTR(max_compute_units)
+ GET_NUM_ATTR(max_work_item_dimensions)
+
+ sycl::id<3> max_work_item_sizes = device.get_info<sycl::info::device::max_work_item_sizes>();
+ WRITE_ATTR("max_work_item_sizes_dim0", ((size_t)max_work_item_sizes.get(0)))
+ WRITE_ATTR("max_work_item_sizes_dim1", ((size_t)max_work_item_sizes.get(1)))
+ WRITE_ATTR("max_work_item_sizes_dim2", ((size_t)max_work_item_sizes.get(2)))
+
+ GET_NUM_ATTR(max_work_group_size)
+ GET_NUM_ATTR(max_num_sub_groups)
+ GET_NUM_ATTR(sub_group_independent_forward_progress)
+
+ GET_NUM_ATTR(preferred_vector_width_char)
+ GET_NUM_ATTR(preferred_vector_width_short)
+ GET_NUM_ATTR(preferred_vector_width_int)
+ GET_NUM_ATTR(preferred_vector_width_long)
+ GET_NUM_ATTR(preferred_vector_width_float)
+ GET_NUM_ATTR(preferred_vector_width_double)
+ GET_NUM_ATTR(preferred_vector_width_half)
+
+ GET_NUM_ATTR(native_vector_width_char)
+ GET_NUM_ATTR(native_vector_width_short)
+ GET_NUM_ATTR(native_vector_width_int)
+ GET_NUM_ATTR(native_vector_width_long)
+ GET_NUM_ATTR(native_vector_width_float)
+ GET_NUM_ATTR(native_vector_width_double)
+ GET_NUM_ATTR(native_vector_width_half)
+
+ size_t max_clock_frequency =
+ (size_t)(device.is_host() ? (size_t)0 :
+ device.get_info<sycl::info::device::max_clock_frequency>());
+ WRITE_ATTR("max_clock_frequency", max_clock_frequency)
+
+ GET_NUM_ATTR(address_bits)
+ GET_NUM_ATTR(max_mem_alloc_size)
+
+ /* NOTE(@nsirgien): Implementation doesn't use image support as bindless images aren't
+ * supported so we always return false, even if device supports HW texture usage acceleration.
+ */
+ bool image_support = false;
+ WRITE_ATTR("image_support", (size_t)image_support)
+
+ GET_NUM_ATTR(max_parameter_size)
+ GET_NUM_ATTR(mem_base_addr_align)
+ GET_NUM_ATTR(global_mem_size)
+ GET_NUM_ATTR(local_mem_size)
+ GET_NUM_ATTR(error_correction_support)
+ GET_NUM_ATTR(profiling_timer_resolution)
+ GET_NUM_ATTR(is_available)
+
+# undef GET_NUM_ATTR
+# undef WRITE_ATTR
+ capabilities << "\n";
+ }
+
+ return ::strdup(capabilities.str().c_str());
+}
+
+void oneapi_free(void *p)
+{
+ if (p) {
+ ::free(p);
+ }
+}
+
+void oneapi_iterate_devices(OneAPIDeviceIteratorCallback cb, void *user_ptr)
+{
+ int num = 0;
+ std::vector<sycl::device> devices = oneapi_available_devices();
+ for (sycl::device &device : devices) {
+ const std::string &platform_name =
+ device.get_platform().get_info<sycl::info::platform::name>();
+ std::string name = device.get_info<sycl::info::device::name>();
+ std::string id = "ONEAPI_" + platform_name + "_" + name;
+ if (device.has(sycl::aspect::ext_intel_pci_address)) {
+ id.append("_" + device.get_info<sycl::info::device::ext_intel_pci_address>());
+ }
+ (cb)(id.c_str(), name.c_str(), num, user_ptr);
+ num++;
+ }
+}
+
+size_t oneapi_get_memcapacity(SyclQueue *queue)
+{
+ return reinterpret_cast<sycl::queue *>(queue)
+ ->get_device()
+ .get_info<sycl::info::device::global_mem_size>();
+}
+
+size_t oneapi_get_compute_units_amount(SyclQueue *queue)
+{
+ return reinterpret_cast<sycl::queue *>(queue)
+ ->get_device()
+ .get_info<sycl::info::device::max_compute_units>();
+}
+
+#endif /* WITH_ONEAPI */
diff --git a/intern/cycles/kernel/device/oneapi/kernel.h b/intern/cycles/kernel/device/oneapi/kernel.h
new file mode 100644
index 00000000000..c5f853742ed
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/kernel.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#pragma once
+
+#ifdef WITH_ONEAPI
+
+# include <stddef.h>
+
+/* NOTE(@nsirgien): Should match underlying type in the declaration inside "kernel/types.h"
+ * TODO: use kernel/types.h directly. */
+enum DeviceKernel : int;
+
+# ifndef CYCLES_KERNEL_ONEAPI_EXPORT
+# ifdef _WIN32
+# if defined(ONEAPI_EXPORT)
+# define CYCLES_KERNEL_ONEAPI_EXPORT extern __declspec(dllexport)
+# else
+# define CYCLES_KERNEL_ONEAPI_EXPORT extern __declspec(dllimport)
+# endif
+# else
+# define CYCLES_KERNEL_ONEAPI_EXPORT
+# endif
+# endif
+
+class SyclQueue;
+
+typedef void (*OneAPIDeviceIteratorCallback)(const char *id,
+ const char *name,
+ int num,
+ void *user_ptr);
+
+typedef void (*OneAPIErrorCallback)(const char *error, void *user_ptr);
+
+struct KernelContext {
+ /* Queue, associated with selected device */
+ SyclQueue *queue;
+ /* Pointer to USM device memory with all global/constant allocation on this device */
+ void *kernel_globals;
+};
+
+/* Use extern C linking so that the symbols can be easily load from the dynamic library at runtime.
+ */
+# ifdef __cplusplus
+extern "C" {
+# endif
+
+# define DLL_INTERFACE_CALL(function, return_type, ...) \
+ CYCLES_KERNEL_ONEAPI_EXPORT return_type function(__VA_ARGS__);
+# include "kernel/device/oneapi/dll_interface_template.h"
+# undef DLL_INTERFACE_CALL
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* WITH_ONEAPI */
diff --git a/intern/cycles/kernel/device/oneapi/kernel_templates.h b/intern/cycles/kernel/device/oneapi/kernel_templates.h
new file mode 100644
index 00000000000..d8964d9b672
--- /dev/null
+++ b/intern/cycles/kernel/device/oneapi/kernel_templates.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2021-2022 Intel Corporation */
+
+#pragma once
+
+/* Some macro magic to generate templates for kernel arguments.
+ * The resulting oneapi_call() template allows to call a SYCL/C++ kernel
+ * with typed arguments by only giving it a void `**args` as given by Cycles.
+ * The template will automatically cast from void* to the expected type. */
+
+/* When expanded by the preprocessor, the generated templates will look like this example: */
+#if 0
+template<typename T0, typename T1, typename T2>
+void oneapi_call(
+ KernelGlobalsGPU *kg,
+ sycl::handler &cgh,
+ size_t global_size,
+ size_t local_size,
+ void **args,
+ void (*func)(const KernelGlobalsGPU *, size_t, size_t, sycl::handler &, T0, T1, T2))
+{
+ func(kg, global_size, local_size, cgh, *(T0 *)(args[0]), *(T1 *)(args[1]), *(T2 *)(args[2]));
+}
+#endif
+
+/* clang-format off */
+#define ONEAPI_TYP(x) typename T##x
+#define ONEAPI_CAST(x) *(T##x *)(args[x])
+#define ONEAPI_T(x) T##x
+
+#define ONEAPI_GET_NTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, N, ...) N
+#define ONEAPI_0(_call, ...)
+#define ONEAPI_1(_call, x) _call(x)
+#define ONEAPI_2(_call, x, ...) _call(x), ONEAPI_1(_call, __VA_ARGS__)
+#define ONEAPI_3(_call, x, ...) _call(x), ONEAPI_2(_call, __VA_ARGS__)
+#define ONEAPI_4(_call, x, ...) _call(x), ONEAPI_3(_call, __VA_ARGS__)
+#define ONEAPI_5(_call, x, ...) _call(x), ONEAPI_4(_call, __VA_ARGS__)
+#define ONEAPI_6(_call, x, ...) _call(x), ONEAPI_5(_call, __VA_ARGS__)
+#define ONEAPI_7(_call, x, ...) _call(x), ONEAPI_6(_call, __VA_ARGS__)
+#define ONEAPI_8(_call, x, ...) _call(x), ONEAPI_7(_call, __VA_ARGS__)
+#define ONEAPI_9(_call, x, ...) _call(x), ONEAPI_8(_call, __VA_ARGS__)
+#define ONEAPI_10(_call, x, ...) _call(x), ONEAPI_9(_call, __VA_ARGS__)
+#define ONEAPI_11(_call, x, ...) _call(x), ONEAPI_10(_call, __VA_ARGS__)
+#define ONEAPI_12(_call, x, ...) _call(x), ONEAPI_11(_call, __VA_ARGS__)
+#define ONEAPI_13(_call, x, ...) _call(x), ONEAPI_12(_call, __VA_ARGS__)
+#define ONEAPI_14(_call, x, ...) _call(x), ONEAPI_13(_call, __VA_ARGS__)
+#define ONEAPI_15(_call, x, ...) _call(x), ONEAPI_14(_call, __VA_ARGS__)
+#define ONEAPI_16(_call, x, ...) _call(x), ONEAPI_15(_call, __VA_ARGS__)
+#define ONEAPI_17(_call, x, ...) _call(x), ONEAPI_16(_call, __VA_ARGS__)
+#define ONEAPI_18(_call, x, ...) _call(x), ONEAPI_17(_call, __VA_ARGS__)
+#define ONEAPI_19(_call, x, ...) _call(x), ONEAPI_18(_call, __VA_ARGS__)
+#define ONEAPI_20(_call, x, ...) _call(x), ONEAPI_19(_call, __VA_ARGS__)
+#define ONEAPI_21(_call, x, ...) _call(x), ONEAPI_20(_call, __VA_ARGS__)
+
+#define ONEAPI_CALL_FOR(x, ...) \
+ ONEAPI_GET_NTH_ARG("ignored", \
+ ##__VA_ARGS__, \
+ ONEAPI_21, \
+ ONEAPI_20, \
+ ONEAPI_19, \
+ ONEAPI_18, \
+ ONEAPI_17, \
+ ONEAPI_16, \
+ ONEAPI_15, \
+ ONEAPI_14, \
+ ONEAPI_13, \
+ ONEAPI_12, \
+ ONEAPI_11, \
+ ONEAPI_10, \
+ ONEAPI_9, \
+ ONEAPI_8, \
+ ONEAPI_7, \
+ ONEAPI_6, \
+ ONEAPI_5, \
+ ONEAPI_4, \
+ ONEAPI_3, \
+ ONEAPI_2, \
+ ONEAPI_1, \
+ ONEAPI_0) \
+ (x, ##__VA_ARGS__)
+
+/* This template automatically casts entries in the void **args array to the types requested by the kernel func.
+ Since kernel parameters are passed as void ** to the device, this is the closest that we have to type safety. */
+#define oneapi_template(...) \
+ template<ONEAPI_CALL_FOR(ONEAPI_TYP, __VA_ARGS__)> \
+ void oneapi_call( \
+ KernelGlobalsGPU *kg, \
+ sycl::handler &cgh, \
+ size_t global_size, \
+ size_t local_size, \
+ void **args, \
+ void (*func)(KernelGlobalsGPU*, size_t, size_t, sycl::handler &, ONEAPI_CALL_FOR(ONEAPI_T, __VA_ARGS__))) \
+ { \
+ func(kg, \
+ global_size, \
+ local_size, \
+ cgh, \
+ ONEAPI_CALL_FOR(ONEAPI_CAST, __VA_ARGS__)); \
+ }
+
+oneapi_template(0)
+oneapi_template(0, 1)
+oneapi_template(0, 1, 2)
+oneapi_template(0, 1, 2, 3)
+oneapi_template(0, 1, 2, 3, 4)
+oneapi_template(0, 1, 2, 3, 4, 5)
+oneapi_template(0, 1, 2, 3, 4, 5, 6)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
+oneapi_template(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
+
+ /* clang-format on */
diff --git a/intern/cycles/kernel/device/optix/globals.h b/intern/cycles/kernel/device/optix/globals.h
index bb752c531f0..7af2e421378 100644
--- a/intern/cycles/kernel/device/optix/globals.h
+++ b/intern/cycles/kernel/device/optix/globals.h
@@ -28,21 +28,21 @@ struct KernelParamsOptiX {
/* Global scene data and textures */
KernelData data;
-#define KERNEL_TEX(type, name) const type *name;
-#include "kernel/textures.h"
+#define KERNEL_DATA_ARRAY(type, name) const type *name;
+#include "kernel/data_arrays.h"
/* Integrator state */
- IntegratorStateGPU __integrator_state;
+ IntegratorStateGPU integrator_state;
};
#ifdef __NVCC__
-extern "C" static __constant__ KernelParamsOptiX __params;
+extern "C" static __constant__ KernelParamsOptiX kernel_params;
#endif
/* Abstraction macros */
-#define kernel_data __params.data
-#define kernel_tex_array(t) __params.t
-#define kernel_tex_fetch(t, index) __params.t[(index)]
-#define kernel_integrator_state __params.__integrator_state
+#define kernel_data kernel_params.data
+#define kernel_data_array(name) kernel_params.name
+#define kernel_data_fetch(name, index) kernel_params.name[(index)]
+#define kernel_integrator_state kernel_params.integrator_state
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/optix/kernel.cu b/intern/cycles/kernel/device/optix/kernel.cu
index 9843b2e99be..510f7cca5d6 100644
--- a/intern/cycles/kernel/device/optix/kernel.cu
+++ b/intern/cycles/kernel/device/optix/kernel.cu
@@ -51,32 +51,36 @@ ccl_device_forceinline int get_object_id()
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_closest()
{
const int global_index = optixGetLaunchIndex().x;
- const int path_index = (__params.path_index_array) ? __params.path_index_array[global_index] :
- global_index;
- integrator_intersect_closest(nullptr, path_index, __params.render_buffer);
+ const int path_index = (kernel_params.path_index_array) ?
+ kernel_params.path_index_array[global_index] :
+ global_index;
+ integrator_intersect_closest(nullptr, path_index, kernel_params.render_buffer);
}
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_shadow()
{
const int global_index = optixGetLaunchIndex().x;
- const int path_index = (__params.path_index_array) ? __params.path_index_array[global_index] :
- global_index;
+ const int path_index = (kernel_params.path_index_array) ?
+ kernel_params.path_index_array[global_index] :
+ global_index;
integrator_intersect_shadow(nullptr, path_index);
}
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_subsurface()
{
const int global_index = optixGetLaunchIndex().x;
- const int path_index = (__params.path_index_array) ? __params.path_index_array[global_index] :
- global_index;
+ const int path_index = (kernel_params.path_index_array) ?
+ kernel_params.path_index_array[global_index] :
+ global_index;
integrator_intersect_subsurface(nullptr, path_index);
}
extern "C" __global__ void __raygen__kernel_optix_integrator_intersect_volume_stack()
{
const int global_index = optixGetLaunchIndex().x;
- const int path_index = (__params.path_index_array) ? __params.path_index_array[global_index] :
- global_index;
+ const int path_index = (kernel_params.path_index_array) ?
+ kernel_params.path_index_array[global_index] :
+ global_index;
integrator_intersect_volume_stack(nullptr, path_index);
}
@@ -151,17 +155,17 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit()
isect->t = optixGetRayTmax();
isect->prim = prim;
isect->object = get_object_id();
- isect->type = kernel_tex_fetch(__objects, isect->object).primitive_type;
+ isect->type = kernel_data_fetch(objects, isect->object).primitive_type;
const float2 barycentrics = optixGetTriangleBarycentrics();
isect->u = 1.0f - barycentrics.y - barycentrics.x;
isect->v = barycentrics.x;
/* Record geometric normal. */
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
- const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0);
- const float3 tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1);
- const float3 tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
+ const uint tri_vindex = kernel_data_fetch(tri_vindex, prim).w;
+ const float3 tri_a = kernel_data_fetch(tri_verts, tri_vindex + 0);
+ const float3 tri_b = kernel_data_fetch(tri_verts, tri_vindex + 1);
+ const float3 tri_c = kernel_data_fetch(tri_verts, tri_vindex + 2);
local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a));
/* Continue tracing (without this the trace call would return after the first hit). */
@@ -176,7 +180,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
const uint object = get_object_id();
# ifdef __VISIBILITY_FLAG__
const uint visibility = optixGetPayload_4();
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
return optixIgnoreIntersection();
}
# endif
@@ -192,14 +196,14 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
const float2 barycentrics = optixGetTriangleBarycentrics();
u = 1.0f - barycentrics.y - barycentrics.x;
v = barycentrics.x;
- type = kernel_tex_fetch(__objects, object).primitive_type;
+ type = kernel_data_fetch(objects, object).primitive_type;
}
# ifdef __HAIR__
else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
u = __uint_as_float(optixGetAttribute_0());
v = __uint_as_float(optixGetAttribute_1());
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
type = segment.type;
prim = segment.prim;
@@ -212,7 +216,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
}
# endif
else {
- type = kernel_tex_fetch(__objects, object).primitive_type;
+ type = kernel_data_fetch(objects, object).primitive_type;
u = 0.0f;
v = 0.0f;
}
@@ -307,12 +311,12 @@ extern "C" __global__ void __anyhit__kernel_optix_volume_test()
const uint object = get_object_id();
#ifdef __VISIBILITY_FLAG__
const uint visibility = optixGetPayload_4();
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
return optixIgnoreIntersection();
}
#endif
- if ((kernel_tex_fetch(__object_flag, object) & SD_OBJECT_HAS_VOLUME) == 0) {
+ if ((kernel_data_fetch(object_flag, object) & SD_OBJECT_HAS_VOLUME) == 0) {
return optixIgnoreIntersection();
}
@@ -340,7 +344,7 @@ extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
const uint object = get_object_id();
const uint visibility = optixGetPayload_4();
#ifdef __VISIBILITY_FLAG__
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
return optixIgnoreIntersection();
}
#endif
@@ -377,10 +381,10 @@ extern "C" __global__ void __closesthit__kernel_optix_hit()
optixSetPayload_1(__float_as_uint(1.0f - barycentrics.y - barycentrics.x));
optixSetPayload_2(__float_as_uint(barycentrics.x));
optixSetPayload_3(prim);
- optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
+ optixSetPayload_5(kernel_data_fetch(objects, object).primitive_type);
}
else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, prim);
optixSetPayload_1(optixGetAttribute_0()); /* Same as 'optixGetCurveParameter()' */
optixSetPayload_2(optixGetAttribute_1());
optixSetPayload_3(segment.prim);
@@ -390,7 +394,7 @@ extern "C" __global__ void __closesthit__kernel_optix_hit()
optixSetPayload_1(0);
optixSetPayload_2(0);
optixSetPayload_3(prim);
- optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
+ optixSetPayload_5(kernel_data_fetch(objects, object).primitive_type);
}
}
@@ -401,13 +405,14 @@ ccl_device_inline void optix_intersection_curve(const int prim, const int type)
# ifdef __VISIBILITY_FLAG__
const uint visibility = optixGetPayload_4();
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
return;
}
# endif
float3 P = optixGetObjectRayOrigin();
float3 dir = optixGetObjectRayDirection();
+ float tmin = optixGetRayTmin();
/* The direction is not normalized by default, but the curve intersection routine expects that */
float len;
@@ -425,7 +430,7 @@ ccl_device_inline void optix_intersection_curve(const int prim, const int type)
if (isect.t != FLT_MAX)
isect.t *= len;
- if (curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ if (curve_intersect(NULL, &isect, P, dir, tmin, isect.t, object, prim, time, type)) {
static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
optixReportIntersection(isect.t / len,
type & PRIMITIVE_ALL,
@@ -436,7 +441,7 @@ ccl_device_inline void optix_intersection_curve(const int prim, const int type)
extern "C" __global__ void __intersection__curve_ribbon()
{
- const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, optixGetPrimitiveIndex());
+ const KernelCurveSegment segment = kernel_data_fetch(curve_segments, optixGetPrimitiveIndex());
const int prim = segment.prim;
const int type = segment.type;
if (type & PRIMITIVE_CURVE_RIBBON) {
@@ -451,17 +456,18 @@ extern "C" __global__ void __intersection__point()
{
const int prim = optixGetPrimitiveIndex();
const int object = get_object_id();
- const int type = kernel_tex_fetch(__objects, object).primitive_type;
+ const int type = kernel_data_fetch(objects, object).primitive_type;
# ifdef __VISIBILITY_FLAG__
const uint visibility = optixGetPayload_4();
- if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) {
+ if ((kernel_data_fetch(objects, object).visibility & visibility) == 0) {
return;
}
# endif
float3 P = optixGetObjectRayOrigin();
float3 dir = optixGetObjectRayDirection();
+ float tmin = optixGetRayTmin();
/* The direction is not normalized by default, the point intersection routine expects that. */
float len;
@@ -480,7 +486,7 @@ extern "C" __global__ void __intersection__point()
isect.t *= len;
}
- if (point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ if (point_intersect(NULL, &isect, P, dir, tmin, isect.t, object, prim, time, type)) {
static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
optixReportIntersection(isect.t / len, type & PRIMITIVE_ALL);
}
diff --git a/intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu b/intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu
index e2c5d2ff024..41e6224f6da 100644
--- a/intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu
+++ b/intern/cycles/kernel/device/optix/kernel_shader_raytrace.cu
@@ -11,7 +11,15 @@
extern "C" __global__ void __raygen__kernel_optix_integrator_shade_surface_raytrace()
{
const int global_index = optixGetLaunchIndex().x;
- const int path_index = (__params.path_index_array) ? __params.path_index_array[global_index] :
+ const int path_index = (kernel_params.path_index_array) ? kernel_params.path_index_array[global_index] :
global_index;
- integrator_shade_surface_raytrace(nullptr, path_index, __params.render_buffer);
+ integrator_shade_surface_raytrace(nullptr, path_index, kernel_params.render_buffer);
+}
+
+extern "C" __global__ void __raygen__kernel_optix_integrator_shade_surface_mnee()
+{
+ const int global_index = optixGetLaunchIndex().x;
+ const int path_index = (kernel_params.path_index_array) ? kernel_params.path_index_array[global_index] :
+ global_index;
+ integrator_shade_surface_mnee(nullptr, path_index, kernel_params.render_buffer);
}
diff --git a/intern/cycles/kernel/film/accumulate.h b/intern/cycles/kernel/film/accumulate.h
index e10acfd7eb5..33c35a68ad0 100644
--- a/intern/cycles/kernel/film/accumulate.h
+++ b/intern/cycles/kernel/film/accumulate.h
@@ -62,7 +62,7 @@ ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, float value)
eval->sum *= value;
}
-ccl_device_inline void bsdf_eval_mul3(ccl_private BsdfEval *eval, float3 value)
+ccl_device_inline void bsdf_eval_mul(ccl_private BsdfEval *eval, float3 value)
{
eval->diffuse *= value;
eval->glossy *= value;
@@ -78,14 +78,14 @@ ccl_device_inline float3 bsdf_eval_pass_diffuse_weight(ccl_private const BsdfEva
{
/* Ratio of diffuse weight to recover proportions for writing to render pass.
* We assume reflection, transmission and volume scatter to be exclusive. */
- return safe_divide_float3_float3(eval->diffuse, eval->sum);
+ return safe_divide(eval->diffuse, eval->sum);
}
ccl_device_inline float3 bsdf_eval_pass_glossy_weight(ccl_private const BsdfEval *eval)
{
/* Ratio of glossy weight to recover proportions for writing to render pass.
* We assume reflection, transmission and volume scatter to be exclusive. */
- return safe_divide_float3_float3(eval->glossy, eval->sum);
+ return safe_divide(eval->glossy, eval->sum);
}
/* --------------------------------------------------------------------
@@ -98,14 +98,14 @@ ccl_device_inline float3 bsdf_eval_pass_glossy_weight(ccl_private const BsdfEval
ccl_device_forceinline void kernel_accum_clamp(KernelGlobals kg, ccl_private float3 *L, int bounce)
{
#ifdef __KERNEL_DEBUG_NAN__
- if (!isfinite3_safe(*L)) {
+ if (!isfinite_safe(*L)) {
kernel_assert(!"Cycles sample with non-finite value detected");
}
#endif
/* Make sure all components are finite, allowing the contribution to be usable by adaptive
* sampling convergence check, but also to make it so render result never causes issues with
* post-processing. */
- *L = ensure_finite3(*L);
+ *L = ensure_finite(*L);
#ifdef __CLAMP_SAMPLE__
float limit = (bounce > 0) ? kernel_data.integrator.sample_clamp_indirect :
@@ -518,7 +518,7 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg,
const float3 unshadowed_throughput = INTEGRATOR_STATE(
state, shadow_path, unshadowed_throughput);
const float3 shadowed_throughput = INTEGRATOR_STATE(state, shadow_path, throughput);
- const float3 shadow = safe_divide_float3_float3(shadowed_throughput, unshadowed_throughput) *
+ const float3 shadow = safe_divide(shadowed_throughput, unshadowed_throughput) *
kernel_data.film.pass_shadow_scale;
kernel_write_pass_float3(buffer + kernel_data.film.pass_shadow, shadow);
}
diff --git a/intern/cycles/kernel/film/passes.h b/intern/cycles/kernel/film/passes.h
index 773f5726850..1f5cf2048f1 100644
--- a/intern/cycles/kernel/film/passes.h
+++ b/intern/cycles/kernel/film/passes.h
@@ -108,15 +108,14 @@ ccl_device_forceinline void kernel_write_denoising_features_surface(
const Transform worldtocamera = kernel_data.cam.worldtocamera;
normal = transform_direction(&worldtocamera, normal);
- const float3 denoising_normal = ensure_finite3(normal);
+ const float3 denoising_normal = ensure_finite(normal);
kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal);
}
if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) {
const float3 denoising_feature_throughput = INTEGRATOR_STATE(
state, path, denoising_feature_throughput);
- const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput *
- diffuse_albedo);
+ const float3 denoising_albedo = ensure_finite(denoising_feature_throughput * diffuse_albedo);
kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo);
}
@@ -149,7 +148,7 @@ ccl_device_forceinline void kernel_write_denoising_features_volume(KernelGlobals
if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) {
/* Write albedo. */
- const float3 denoising_albedo = ensure_finite3(denoising_feature_throughput * albedo);
+ const float3 denoising_albedo = ensure_finite(denoising_feature_throughput * albedo);
kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo);
}
}
diff --git a/intern/cycles/kernel/geom/attribute.h b/intern/cycles/kernel/geom/attribute.h
index da620f69e2d..31a9e39d528 100644
--- a/intern/cycles/kernel/geom/attribute.h
+++ b/intern/cycles/kernel/geom/attribute.h
@@ -18,7 +18,7 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const ShaderData *sd)
{
- return (sd->prim != PRIM_NONE) ? kernel_tex_fetch(__tri_patch, sd->prim) : ~0;
+ return (sd->prim != PRIM_NONE) ? kernel_data_fetch(tri_patch, sd->prim) : ~0;
}
ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, ccl_private const ShaderData *sd)
@@ -42,7 +42,7 @@ ccl_device_inline AttributeDescriptor attribute_not_found()
ccl_device_inline uint object_attribute_map_offset(KernelGlobals kg, int object)
{
- return kernel_tex_fetch(__objects, object).attribute_map_offset;
+ return kernel_data_fetch(objects, object).attribute_map_offset;
}
ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
@@ -56,26 +56,26 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
/* for SVM, find attribute by unique id */
uint attr_offset = object_attribute_map_offset(kg, sd->object);
attr_offset += attribute_primitive_type(kg, sd);
- uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ AttributeMap attr_map = kernel_data_fetch(attributes_map, attr_offset);
- while (attr_map.x != id) {
- if (UNLIKELY(attr_map.x == ATTR_STD_NONE)) {
- if (UNLIKELY(attr_map.y == 0)) {
+ while (attr_map.id != id) {
+ if (UNLIKELY(attr_map.id == ATTR_STD_NONE)) {
+ if (UNLIKELY(attr_map.element == 0)) {
return attribute_not_found();
}
else {
/* Chain jump to a different part of the table. */
- attr_offset = attr_map.z;
+ attr_offset = attr_map.offset;
}
}
else {
attr_offset += ATTR_PRIM_TYPES;
}
- attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+ attr_map = kernel_data_fetch(attributes_map, attr_offset);
}
AttributeDescriptor desc;
- desc.element = (AttributeElement)attr_map.y;
+ desc.element = (AttributeElement)attr_map.element;
if (sd->prim == PRIM_NONE && desc.element != ATTR_ELEMENT_MESH &&
desc.element != ATTR_ELEMENT_VOXEL && desc.element != ATTR_ELEMENT_OBJECT) {
@@ -83,9 +83,10 @@ ccl_device_inline AttributeDescriptor find_attribute(KernelGlobals kg,
}
/* return result */
- desc.offset = (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
- desc.type = (NodeAttributeType)(attr_map.w & 0xff);
- desc.flags = (AttributeFlag)(attr_map.w >> 8);
+ desc.offset = (attr_map.element == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND :
+ (int)attr_map.offset;
+ desc.type = (NodeAttributeType)attr_map.type;
+ desc.flags = (AttributeFlag)attr_map.flags;
return desc;
}
@@ -98,9 +99,9 @@ ccl_device Transform primitive_attribute_matrix(KernelGlobals kg,
{
Transform tfm;
- tfm.x = kernel_tex_fetch(__attributes_float4, desc.offset + 0);
- tfm.y = kernel_tex_fetch(__attributes_float4, desc.offset + 1);
- tfm.z = kernel_tex_fetch(__attributes_float4, desc.offset + 2);
+ tfm.x = kernel_data_fetch(attributes_float4, desc.offset + 0);
+ tfm.y = kernel_data_fetch(attributes_float4, desc.offset + 1);
+ tfm.z = kernel_data_fetch(attributes_float4, desc.offset + 2);
return tfm;
}
diff --git a/intern/cycles/kernel/geom/curve.h b/intern/cycles/kernel/geom/curve.h
index 4dbc6d4f6db..e243adfde21 100644
--- a/intern/cycles/kernel/geom/curve.h
+++ b/intern/cycles/kernel/geom/curve.h
@@ -23,12 +23,12 @@ ccl_device float curve_attribute_float(KernelGlobals kg,
ccl_private float *dy)
{
if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
- KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ KernelCurve curve = kernel_data_fetch(curves, sd->prim);
int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
- float f0 = kernel_tex_fetch(__attributes_float, desc.offset + k0);
- float f1 = kernel_tex_fetch(__attributes_float, desc.offset + k1);
+ float f0 = kernel_data_fetch(attributes_float, desc.offset + k0);
+ float f1 = kernel_data_fetch(attributes_float, desc.offset + k1);
# ifdef __RAY_DIFFERENTIALS__
if (dx)
@@ -50,7 +50,7 @@ ccl_device float curve_attribute_float(KernelGlobals kg,
if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
desc.offset;
- return kernel_tex_fetch(__attributes_float, offset);
+ return kernel_data_fetch(attributes_float, offset);
}
else {
return 0.0f;
@@ -65,12 +65,12 @@ ccl_device float2 curve_attribute_float2(KernelGlobals kg,
ccl_private float2 *dy)
{
if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
- KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ KernelCurve curve = kernel_data_fetch(curves, sd->prim);
int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
- float2 f0 = kernel_tex_fetch(__attributes_float2, desc.offset + k0);
- float2 f1 = kernel_tex_fetch(__attributes_float2, desc.offset + k1);
+ float2 f0 = kernel_data_fetch(attributes_float2, desc.offset + k0);
+ float2 f1 = kernel_data_fetch(attributes_float2, desc.offset + k1);
# ifdef __RAY_DIFFERENTIALS__
if (dx)
@@ -96,7 +96,7 @@ ccl_device float2 curve_attribute_float2(KernelGlobals kg,
if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
desc.offset;
- return kernel_tex_fetch(__attributes_float2, offset);
+ return kernel_data_fetch(attributes_float2, offset);
}
else {
return make_float2(0.0f, 0.0f);
@@ -111,12 +111,12 @@ ccl_device float3 curve_attribute_float3(KernelGlobals kg,
ccl_private float3 *dy)
{
if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
- KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ KernelCurve curve = kernel_data_fetch(curves, sd->prim);
int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
- float3 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + k0);
- float3 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + k1);
+ float3 f0 = kernel_data_fetch(attributes_float3, desc.offset + k0);
+ float3 f1 = kernel_data_fetch(attributes_float3, desc.offset + k1);
# ifdef __RAY_DIFFERENTIALS__
if (dx)
@@ -138,7 +138,7 @@ ccl_device float3 curve_attribute_float3(KernelGlobals kg,
if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
desc.offset;
- return kernel_tex_fetch(__attributes_float3, offset);
+ return kernel_data_fetch(attributes_float3, offset);
}
else {
return make_float3(0.0f, 0.0f, 0.0f);
@@ -153,12 +153,12 @@ ccl_device float4 curve_attribute_float4(KernelGlobals kg,
ccl_private float4 *dy)
{
if (desc.element & (ATTR_ELEMENT_CURVE_KEY | ATTR_ELEMENT_CURVE_KEY_MOTION)) {
- KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ KernelCurve curve = kernel_data_fetch(curves, sd->prim);
int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
- float4 f0 = kernel_tex_fetch(__attributes_float4, desc.offset + k0);
- float4 f1 = kernel_tex_fetch(__attributes_float4, desc.offset + k1);
+ float4 f0 = kernel_data_fetch(attributes_float4, desc.offset + k0);
+ float4 f1 = kernel_data_fetch(attributes_float4, desc.offset + k1);
# ifdef __RAY_DIFFERENTIALS__
if (dx)
@@ -180,7 +180,7 @@ ccl_device float4 curve_attribute_float4(KernelGlobals kg,
if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim :
desc.offset;
- return kernel_tex_fetch(__attributes_float4, offset);
+ return kernel_data_fetch(attributes_float4, offset);
}
else {
return zero_float4();
@@ -195,15 +195,15 @@ ccl_device float curve_thickness(KernelGlobals kg, ccl_private const ShaderData
float r = 0.0f;
if (sd->type & PRIMITIVE_CURVE) {
- KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ KernelCurve curve = kernel_data_fetch(curves, sd->prim);
int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
float4 P_curve[2];
if (!(sd->type & PRIMITIVE_MOTION)) {
- P_curve[0] = kernel_tex_fetch(__curve_keys, k0);
- P_curve[1] = kernel_tex_fetch(__curve_keys, k1);
+ P_curve[0] = kernel_data_fetch(curve_keys, k0);
+ P_curve[1] = kernel_data_fetch(curve_keys, k1);
}
else {
motion_curve_keys_linear(kg, sd->object, sd->prim, sd->time, k0, k1, P_curve);
@@ -232,14 +232,14 @@ ccl_device float curve_random(KernelGlobals kg, ccl_private const ShaderData *sd
ccl_device float3 curve_motion_center_location(KernelGlobals kg, ccl_private const ShaderData *sd)
{
- KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
+ KernelCurve curve = kernel_data_fetch(curves, sd->prim);
int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
float4 P_curve[2];
- P_curve[0] = kernel_tex_fetch(__curve_keys, k0);
- P_curve[1] = kernel_tex_fetch(__curve_keys, k1);
+ P_curve[0] = kernel_data_fetch(curve_keys, k0);
+ P_curve[1] = kernel_data_fetch(curve_keys, k1);
return float4_to_float3(P_curve[1]) * sd->u + float4_to_float3(P_curve[0]) * (1.0f - sd->u);
}
diff --git a/intern/cycles/kernel/geom/curve_intersect.h b/intern/cycles/kernel/geom/curve_intersect.h
index e1a1f9c02c5..9770105dd81 100644
--- a/intern/cycles/kernel/geom/curve_intersect.h
+++ b/intern/cycles/kernel/geom/curve_intersect.h
@@ -156,7 +156,8 @@ ccl_device_inline float2 half_plane_intersect(const float3 P, const float3 N, co
}
ccl_device bool curve_intersect_iterative(const float3 ray_dir,
- ccl_private float *ray_tfar,
+ const float ray_tmin,
+ ccl_private float *ray_tmax,
const float dt,
const float4 curve[4],
float u,
@@ -220,7 +221,7 @@ ccl_device bool curve_intersect_iterative(const float3 ray_dir,
if (fabsf(f) < f_err && fabsf(g) < g_err) {
t += dt;
- if (!(0.0f <= t && t <= *ray_tfar)) {
+ if (!(t >= ray_tmin && t <= *ray_tmax)) {
return false; /* Rejects NaNs */
}
if (!(u >= 0.0f && u <= 1.0f)) {
@@ -237,7 +238,7 @@ ccl_device bool curve_intersect_iterative(const float3 ray_dir,
}
/* Record intersection. */
- *ray_tfar = t;
+ *ray_tmax = t;
isect->t = t;
isect->u = u;
isect->v = 0.0f;
@@ -250,7 +251,8 @@ ccl_device bool curve_intersect_iterative(const float3 ray_dir,
ccl_device bool curve_intersect_recursive(const float3 ray_orig,
const float3 ray_dir,
- float ray_tfar,
+ const float ray_tmin,
+ float ray_tmax,
float4 curve[4],
ccl_private Intersection *isect)
{
@@ -331,7 +333,7 @@ ccl_device bool curve_intersect_recursive(const float3 ray_orig,
}
/* Intersect with cap-planes. */
- float2 tp = make_float2(-dt, ray_tfar - dt);
+ float2 tp = make_float2(ray_tmin - dt, ray_tmax - dt);
tp = make_float2(max(tp.x, tc_outer.x), min(tp.y, tc_outer.y));
const float2 h0 = half_plane_intersect(
float4_to_float3(P0), float4_to_float3(dP0du), ray_dir);
@@ -394,19 +396,20 @@ ccl_device bool curve_intersect_recursive(const float3 ray_orig,
CURVE_NUM_BEZIER_SUBDIVISIONS;
if (depth >= termDepth) {
found |= curve_intersect_iterative(
- ray_dir, &ray_tfar, dt, curve, u_outer0, tp0.x, use_backfacing, isect);
+ ray_dir, ray_tmin, &ray_tmax, dt, curve, u_outer0, tp0.x, use_backfacing, isect);
}
else {
recurse = true;
}
}
- if (valid1 && (tp1.x + dt <= ray_tfar)) {
+ const float t1 = tp1.x + dt;
+ if (valid1 && (t1 >= ray_tmin && t1 <= ray_tmax)) {
const int termDepth = unstable1 ? CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE :
CURVE_NUM_BEZIER_SUBDIVISIONS;
if (depth >= termDepth) {
found |= curve_intersect_iterative(
- ray_dir, &ray_tfar, dt, curve, u_outer1, tp1.y, use_backfacing, isect);
+ ray_dir, ray_tmin, &ray_tmax, dt, curve, u_outer1, tp1.y, use_backfacing, isect);
}
else {
recurse = true;
@@ -456,7 +459,8 @@ ccl_device_inline bool cylinder_culling_test(const float2 p1, const float2 p2, c
* v0,v1,v3 and v2,v3,v1. The edge v1,v2 decides which of the two
* triangles gets intersected.
*/
-ccl_device_inline bool ribbon_intersect_quad(const float ray_tfar,
+ccl_device_inline bool ribbon_intersect_quad(const float ray_tmin,
+ const float ray_tmax,
const float3 quad_v0,
const float3 quad_v1,
const float3 quad_v2,
@@ -497,7 +501,7 @@ ccl_device_inline bool ribbon_intersect_quad(const float ray_tfar,
/* Perform depth test? */
const float t = rcpDen * dot(v0, Ng);
- if (!(0.0f <= t && t <= ray_tfar)) {
+ if (!(t >= ray_tmin && t <= ray_tmax)) {
return false;
}
@@ -534,7 +538,8 @@ ccl_device_inline float4 ribbon_to_ray_space(const float3 ray_space[3],
ccl_device_inline bool ribbon_intersect(const float3 ray_org,
const float3 ray_dir,
- float ray_tfar,
+ const float ray_tmin,
+ float ray_tmax,
const int N,
float4 curve[4],
ccl_private Intersection *isect)
@@ -555,7 +560,7 @@ ccl_device_inline bool ribbon_intersect(const float3 ray_org,
/* Evaluate first point and radius scaled normal direction. */
float4 p0 = catmull_rom_basis_eval(curve, 0.0f);
float3 dp0dt = float4_to_float3(catmull_rom_basis_derivative(curve, 0.0f));
- if (max3(fabs(dp0dt)) < eps) {
+ if (reduce_max(fabs(dp0dt)) < eps) {
const float4 p1 = catmull_rom_basis_eval(curve, step_size);
dp0dt = float4_to_float3(p1 - p0);
}
@@ -570,7 +575,7 @@ ccl_device_inline bool ribbon_intersect(const float3 ray_org,
/* Evaluate next point. */
float3 dp1dt = float4_to_float3(catmull_rom_basis_derivative(curve, u + step_size));
- dp1dt = (max3(fabs(dp1dt)) < eps) ? float4_to_float3(p1 - p0) : dp1dt;
+ dp1dt = (reduce_max(fabs(dp1dt)) < eps) ? float4_to_float3(p1 - p0) : dp1dt;
const float3 wn1 = normalize(make_float3(dp1dt.y, -dp1dt.x, 0.0f)) * p1.w;
if (valid) {
@@ -582,7 +587,7 @@ ccl_device_inline bool ribbon_intersect(const float3 ray_org,
/* Intersect quad. */
float vu, vv, vt;
- bool valid0 = ribbon_intersect_quad(ray_tfar, lp0, lp1, up1, up0, &vu, &vv, &vt);
+ bool valid0 = ribbon_intersect_quad(ray_tmin, ray_tmax, lp0, lp1, up1, up0, &vu, &vv, &vt);
if (valid0) {
/* ignore self intersections */
@@ -596,7 +601,7 @@ ccl_device_inline bool ribbon_intersect(const float3 ray_org,
vv = 2.0f * vv - 1.0f;
/* Record intersection. */
- ray_tfar = vt;
+ ray_tmax = vt;
isect->t = vt;
isect->u = u + vu * step_size;
isect->v = vv;
@@ -616,6 +621,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
ccl_private Intersection *isect,
const float3 P,
const float3 dir,
+ const float tmin,
const float tmax,
int object,
int prim,
@@ -624,7 +630,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
{
const bool is_motion = (type & PRIMITIVE_MOTION);
- KernelCurve kcurve = kernel_tex_fetch(__curves, prim);
+ KernelCurve kcurve = kernel_data_fetch(curves, prim);
int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type);
int k1 = k0 + 1;
@@ -633,10 +639,10 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
float4 curve[4];
if (!is_motion) {
- curve[0] = kernel_tex_fetch(__curve_keys, ka);
- curve[1] = kernel_tex_fetch(__curve_keys, k0);
- curve[2] = kernel_tex_fetch(__curve_keys, k1);
- curve[3] = kernel_tex_fetch(__curve_keys, kb);
+ curve[0] = kernel_data_fetch(curve_keys, ka);
+ curve[1] = kernel_data_fetch(curve_keys, k0);
+ curve[2] = kernel_data_fetch(curve_keys, k1);
+ curve[3] = kernel_data_fetch(curve_keys, kb);
}
else {
motion_curve_keys(kg, object, prim, time, ka, k0, k1, kb, curve);
@@ -645,7 +651,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
if (type & PRIMITIVE_CURVE_RIBBON) {
/* todo: adaptive number of subdivisions could help performance here. */
const int subdivisions = kernel_data.bvh.curve_subdivisions;
- if (ribbon_intersect(P, dir, tmax, subdivisions, curve, isect)) {
+ if (ribbon_intersect(P, dir, tmin, tmax, subdivisions, curve, isect)) {
isect->prim = prim;
isect->object = object;
isect->type = type;
@@ -655,7 +661,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
return false;
}
else {
- if (curve_intersect_recursive(P, dir, tmax, curve, isect)) {
+ if (curve_intersect_recursive(P, dir, tmin, tmax, curve, isect)) {
isect->prim = prim;
isect->object = object;
isect->type = type;
@@ -682,7 +688,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
D = safe_normalize_len(D, &t);
}
- KernelCurve kcurve = kernel_tex_fetch(__curves, isect_prim);
+ KernelCurve kcurve = kernel_data_fetch(curves, isect_prim);
int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
@@ -692,10 +698,10 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
float4 P_curve[4];
if (!(sd->type & PRIMITIVE_MOTION)) {
- P_curve[0] = kernel_tex_fetch(__curve_keys, ka);
- P_curve[1] = kernel_tex_fetch(__curve_keys, k0);
- P_curve[2] = kernel_tex_fetch(__curve_keys, k1);
- P_curve[3] = kernel_tex_fetch(__curve_keys, kb);
+ P_curve[0] = kernel_data_fetch(curve_keys, ka);
+ P_curve[1] = kernel_data_fetch(curve_keys, k0);
+ P_curve[2] = kernel_data_fetch(curve_keys, k1);
+ P_curve[3] = kernel_data_fetch(curve_keys, kb);
}
else {
motion_curve_keys(kg, sd->object, sd->prim, sd->time, ka, k0, k1, kb, P_curve);
@@ -729,7 +735,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
/* NOTE: It is possible that P will be the same as P_inside (precision issues, or very small
* radius). In this case use the view direction to approximate the normal. */
const float3 P_inside = float4_to_float3(catmull_rom_basis_eval(P_curve, sd->u));
- const float3 N = (!isequal_float3(P, P_inside)) ? normalize(P - P_inside) : -sd->I;
+ const float3 N = (!isequal(P, P_inside)) ? normalize(P - P_inside) : -sd->I;
sd->N = N;
sd->v = 0.0f;
@@ -750,7 +756,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
sd->P = P;
sd->Ng = (sd->type & PRIMITIVE_CURVE_RIBBON) ? sd->I : sd->N;
sd->dPdv = cross(sd->dPdu, sd->Ng);
- sd->shader = kernel_tex_fetch(__curves, sd->prim).shader_id;
+ sd->shader = kernel_data_fetch(curves, sd->prim).shader_id;
}
#endif
diff --git a/intern/cycles/kernel/geom/motion_curve.h b/intern/cycles/kernel/geom/motion_curve.h
index b5289b6dda1..448e4b95e0b 100644
--- a/intern/cycles/kernel/geom/motion_curve.h
+++ b/intern/cycles/kernel/geom/motion_curve.h
@@ -27,8 +27,8 @@ ccl_device_inline void motion_curve_keys_for_step_linear(KernelGlobals kg,
{
if (step == numsteps) {
/* center step: regular key location */
- keys[0] = kernel_tex_fetch(__curve_keys, k0);
- keys[1] = kernel_tex_fetch(__curve_keys, k1);
+ keys[0] = kernel_data_fetch(curve_keys, k0);
+ keys[1] = kernel_data_fetch(curve_keys, k1);
}
else {
/* center step is not stored in this array */
@@ -37,8 +37,8 @@ ccl_device_inline void motion_curve_keys_for_step_linear(KernelGlobals kg,
offset += step * numkeys;
- keys[0] = kernel_tex_fetch(__attributes_float4, offset + k0);
- keys[1] = kernel_tex_fetch(__attributes_float4, offset + k1);
+ keys[0] = kernel_data_fetch(attributes_float4, offset + k0);
+ keys[1] = kernel_data_fetch(attributes_float4, offset + k1);
}
}
@@ -83,10 +83,10 @@ ccl_device_inline void motion_curve_keys_for_step(KernelGlobals kg,
{
if (step == numsteps) {
/* center step: regular key location */
- keys[0] = kernel_tex_fetch(__curve_keys, k0);
- keys[1] = kernel_tex_fetch(__curve_keys, k1);
- keys[2] = kernel_tex_fetch(__curve_keys, k2);
- keys[3] = kernel_tex_fetch(__curve_keys, k3);
+ keys[0] = kernel_data_fetch(curve_keys, k0);
+ keys[1] = kernel_data_fetch(curve_keys, k1);
+ keys[2] = kernel_data_fetch(curve_keys, k2);
+ keys[3] = kernel_data_fetch(curve_keys, k3);
}
else {
/* center step is not stored in this array */
@@ -95,10 +95,10 @@ ccl_device_inline void motion_curve_keys_for_step(KernelGlobals kg,
offset += step * numkeys;
- keys[0] = kernel_tex_fetch(__attributes_float4, offset + k0);
- keys[1] = kernel_tex_fetch(__attributes_float4, offset + k1);
- keys[2] = kernel_tex_fetch(__attributes_float4, offset + k2);
- keys[3] = kernel_tex_fetch(__attributes_float4, offset + k3);
+ keys[0] = kernel_data_fetch(attributes_float4, offset + k0);
+ keys[1] = kernel_data_fetch(attributes_float4, offset + k1);
+ keys[2] = kernel_data_fetch(attributes_float4, offset + k2);
+ keys[3] = kernel_data_fetch(attributes_float4, offset + k3);
}
}
diff --git a/intern/cycles/kernel/geom/motion_point.h b/intern/cycles/kernel/geom/motion_point.h
index c1952ab090a..4916ae702ff 100644
--- a/intern/cycles/kernel/geom/motion_point.h
+++ b/intern/cycles/kernel/geom/motion_point.h
@@ -19,7 +19,7 @@ motion_point_for_step(KernelGlobals kg, int offset, int numkeys, int numsteps, i
{
if (step == numsteps) {
/* center step: regular key location */
- return kernel_tex_fetch(__points, prim);
+ return kernel_data_fetch(points, prim);
}
else {
/* center step is not stored in this array */
@@ -28,7 +28,7 @@ motion_point_for_step(KernelGlobals kg, int offset, int numkeys, int numsteps, i
offset += step * numkeys;
- return kernel_tex_fetch(__attributes_float4, offset + prim);
+ return kernel_data_fetch(attributes_float4, offset + prim);
}
}
diff --git a/intern/cycles/kernel/geom/motion_triangle.h b/intern/cycles/kernel/geom/motion_triangle.h
index a87eb11f4f4..06308071700 100644
--- a/intern/cycles/kernel/geom/motion_triangle.h
+++ b/intern/cycles/kernel/geom/motion_triangle.h
@@ -30,9 +30,9 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals kg,
{
if (step == numsteps) {
/* center step: regular vertex location */
- verts[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
- verts[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
- verts[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+ verts[0] = kernel_data_fetch(tri_verts, tri_vindex.w + 0);
+ verts[1] = kernel_data_fetch(tri_verts, tri_vindex.w + 1);
+ verts[2] = kernel_data_fetch(tri_verts, tri_vindex.w + 2);
}
else {
/* center step not store in this array */
@@ -41,9 +41,9 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals kg,
offset += step * numverts;
- verts[0] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x);
- verts[1] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y);
- verts[2] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z);
+ verts[0] = kernel_data_fetch(attributes_float3, offset + tri_vindex.x);
+ verts[1] = kernel_data_fetch(attributes_float3, offset + tri_vindex.y);
+ verts[2] = kernel_data_fetch(attributes_float3, offset + tri_vindex.z);
}
}
@@ -57,9 +57,9 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
{
if (step == numsteps) {
/* center step: regular vertex location */
- normals[0] = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
- normals[1] = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
- normals[2] = kernel_tex_fetch(__tri_vnormal, tri_vindex.z);
+ normals[0] = kernel_data_fetch(tri_vnormal, tri_vindex.x);
+ normals[1] = kernel_data_fetch(tri_vnormal, tri_vindex.y);
+ normals[2] = kernel_data_fetch(tri_vnormal, tri_vindex.z);
}
else {
/* center step is not stored in this array */
@@ -68,9 +68,9 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg,
offset += step * numverts;
- normals[0] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x);
- normals[1] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y);
- normals[2] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z);
+ normals[0] = kernel_data_fetch(attributes_float3, offset + tri_vindex.x);
+ normals[1] = kernel_data_fetch(attributes_float3, offset + tri_vindex.y);
+ normals[2] = kernel_data_fetch(attributes_float3, offset + tri_vindex.z);
}
}
@@ -92,7 +92,7 @@ ccl_device_inline void motion_triangle_vertices(
/* fetch vertex coordinates */
float3 next_verts[3];
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
@@ -121,7 +121,7 @@ ccl_device_inline void motion_triangle_vertices_and_normals(
/* Fetch vertex coordinates. */
float3 next_verts[3];
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
@@ -167,7 +167,7 @@ ccl_device_inline float3 motion_triangle_smooth_normal(
/* fetch normals */
float3 normals[3], next_normals[3];
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
+ uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals);
motion_triangle_normals_for_step(
diff --git a/intern/cycles/kernel/geom/motion_triangle_intersect.h b/intern/cycles/kernel/geom/motion_triangle_intersect.h
index fb951fa151d..b59c5c43c20 100644
--- a/intern/cycles/kernel/geom/motion_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/motion_triangle_intersect.h
@@ -46,6 +46,7 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg,
ccl_private Intersection *isect,
float3 P,
float3 dir,
+ float tmin,
float tmax,
float time,
uint visibility,
@@ -58,12 +59,12 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg,
motion_triangle_vertices(kg, object, prim, time, verts);
/* Ray-triangle intersection, unoptimized. */
float t, u, v;
- if (ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) {
+ if (ray_triangle_intersect(P, dir, tmin, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) {
#ifdef __VISIBILITY_FLAG__
/* Visibility flag test. we do it here under the assumption
* that most triangles are culled by node flags.
*/
- if (kernel_tex_fetch(__prim_visibility, prim_addr) & visibility)
+ if (kernel_data_fetch(prim_visibility, prim_addr) & visibility)
#endif
{
isect->t = t;
@@ -92,6 +93,7 @@ ccl_device_inline bool motion_triangle_intersect_local(KernelGlobals kg,
int object,
int prim,
int prim_addr,
+ float tmin,
float tmax,
ccl_private uint *lcg_state,
int max_hits)
@@ -101,7 +103,7 @@ ccl_device_inline bool motion_triangle_intersect_local(KernelGlobals kg,
motion_triangle_vertices(kg, object, prim, time, verts);
/* Ray-triangle intersection, unoptimized. */
float t, u, v;
- if (!ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) {
+ if (!ray_triangle_intersect(P, dir, tmin, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) {
return false;
}
diff --git a/intern/cycles/kernel/geom/motion_triangle_shader.h b/intern/cycles/kernel/geom/motion_triangle_shader.h
index 2b2bb858816..236e737b785 100644
--- a/intern/cycles/kernel/geom/motion_triangle_shader.h
+++ b/intern/cycles/kernel/geom/motion_triangle_shader.h
@@ -31,7 +31,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
bool is_local)
{
/* Get shader. */
- sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
+ sd->shader = kernel_data_fetch(tri_shader, sd->prim);
/* Get motion info. */
/* TODO(sergey): This logic is really similar to motion_triangle_vertices(),
* can we de-duplicate something here?
@@ -47,7 +47,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals kg,
kernel_assert(offset != ATTR_STD_NOT_FOUND);
/* Fetch vertex coordinates. */
float3 verts[3], next_verts[3];
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ uint4 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts);
motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step + 1, next_verts);
/* Interpolate between steps. */
diff --git a/intern/cycles/kernel/geom/object.h b/intern/cycles/kernel/geom/object.h
index 3faab7fa905..b15f6b5dda5 100644
--- a/intern/cycles/kernel/geom/object.h
+++ b/intern/cycles/kernel/geom/object.h
@@ -31,10 +31,10 @@ ccl_device_inline Transform object_fetch_transform(KernelGlobals kg,
enum ObjectTransform type)
{
if (type == OBJECT_INVERSE_TRANSFORM) {
- return kernel_tex_fetch(__objects, object).itfm;
+ return kernel_data_fetch(objects, object).itfm;
}
else {
- return kernel_tex_fetch(__objects, object).tfm;
+ return kernel_data_fetch(objects, object).tfm;
}
}
@@ -43,10 +43,10 @@ ccl_device_inline Transform object_fetch_transform(KernelGlobals kg,
ccl_device_inline Transform lamp_fetch_transform(KernelGlobals kg, int lamp, bool inverse)
{
if (inverse) {
- return kernel_tex_fetch(__lights, lamp).itfm;
+ return kernel_data_fetch(lights, lamp).itfm;
}
else {
- return kernel_tex_fetch(__lights, lamp).tfm;
+ return kernel_data_fetch(lights, lamp).tfm;
}
}
@@ -57,7 +57,7 @@ ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals kg,
enum ObjectVectorTransform type)
{
int offset = object * OBJECT_MOTION_PASS_SIZE + (int)type;
- return kernel_tex_fetch(__object_motion_pass, offset);
+ return kernel_data_fetch(object_motion_pass, offset);
}
/* Motion blurred object transformations */
@@ -65,9 +65,9 @@ ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals kg,
#ifdef __OBJECT_MOTION__
ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals kg, int object, float time)
{
- const uint motion_offset = kernel_tex_fetch(__objects, object).motion_offset;
- ccl_global const DecomposedTransform *motion = &kernel_tex_fetch(__object_motion, motion_offset);
- const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
+ const uint motion_offset = kernel_data_fetch(objects, object).motion_offset;
+ ccl_global const DecomposedTransform *motion = &kernel_data_fetch(object_motion, motion_offset);
+ const uint num_steps = kernel_data_fetch(objects, object).numsteps * 2 + 1;
Transform tfm;
transform_motion_array_interpolate(&tfm, motion, num_steps, time);
@@ -80,7 +80,7 @@ ccl_device_inline Transform object_fetch_transform_motion_test(KernelGlobals kg,
float time,
ccl_private Transform *itfm)
{
- int object_flag = kernel_tex_fetch(__object_flag, object);
+ int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_MOTION) {
/* if we do motion blur */
Transform tfm = object_fetch_transform_motion(kg, object, time);
@@ -259,7 +259,7 @@ ccl_device_inline float3 object_color(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return make_float3(0.0f, 0.0f, 0.0f);
- ccl_global const KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ ccl_global const KernelObject *kobject = &kernel_data_fetch(objects, object);
return make_float3(kobject->color[0], kobject->color[1], kobject->color[2]);
}
@@ -270,7 +270,7 @@ ccl_device_inline float object_alpha(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return 0.0f;
- return kernel_tex_fetch(__objects, object).alpha;
+ return kernel_data_fetch(objects, object).alpha;
}
/* Pass ID number of object */
@@ -280,7 +280,7 @@ ccl_device_inline float object_pass_id(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return 0.0f;
- return kernel_tex_fetch(__objects, object).pass_id;
+ return kernel_data_fetch(objects, object).pass_id;
}
/* Lightgroup of lamp */
@@ -290,7 +290,7 @@ ccl_device_inline int lamp_lightgroup(KernelGlobals kg, int lamp)
if (lamp == LAMP_NONE)
return LIGHTGROUP_NONE;
- return kernel_tex_fetch(__lights, lamp).lightgroup;
+ return kernel_data_fetch(lights, lamp).lightgroup;
}
/* Lightgroup of object */
@@ -300,7 +300,7 @@ ccl_device_inline int object_lightgroup(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return LIGHTGROUP_NONE;
- return kernel_tex_fetch(__objects, object).lightgroup;
+ return kernel_data_fetch(objects, object).lightgroup;
}
/* Per lamp random number for shader variation */
@@ -310,7 +310,7 @@ ccl_device_inline float lamp_random_number(KernelGlobals kg, int lamp)
if (lamp == LAMP_NONE)
return 0.0f;
- return kernel_tex_fetch(__lights, lamp).random;
+ return kernel_data_fetch(lights, lamp).random;
}
/* Per object random number for shader variation */
@@ -320,7 +320,7 @@ ccl_device_inline float object_random_number(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return 0.0f;
- return kernel_tex_fetch(__objects, object).random_number;
+ return kernel_data_fetch(objects, object).random_number;
}
/* Particle ID from which this object was generated */
@@ -330,7 +330,7 @@ ccl_device_inline int object_particle_id(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return 0;
- return kernel_tex_fetch(__objects, object).particle_index;
+ return kernel_data_fetch(objects, object).particle_index;
}
/* Generated texture coordinate on surface from where object was instanced */
@@ -340,7 +340,7 @@ ccl_device_inline float3 object_dupli_generated(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return make_float3(0.0f, 0.0f, 0.0f);
- ccl_global const KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ ccl_global const KernelObject *kobject = &kernel_data_fetch(objects, object);
return make_float3(
kobject->dupli_generated[0], kobject->dupli_generated[1], kobject->dupli_generated[2]);
}
@@ -352,7 +352,7 @@ ccl_device_inline float3 object_dupli_uv(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return make_float3(0.0f, 0.0f, 0.0f);
- ccl_global const KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ ccl_global const KernelObject *kobject = &kernel_data_fetch(objects, object);
return make_float3(kobject->dupli_uv[0], kobject->dupli_uv[1], 0.0f);
}
@@ -365,13 +365,13 @@ ccl_device_inline void object_motion_info(KernelGlobals kg,
ccl_private int *numkeys)
{
if (numkeys) {
- *numkeys = kernel_tex_fetch(__objects, object).numkeys;
+ *numkeys = kernel_data_fetch(objects, object).numkeys;
}
if (numsteps)
- *numsteps = kernel_tex_fetch(__objects, object).numsteps;
+ *numsteps = kernel_data_fetch(objects, object).numsteps;
if (numverts)
- *numverts = kernel_tex_fetch(__objects, object).numverts;
+ *numverts = kernel_data_fetch(objects, object).numverts;
}
/* Offset to an objects patch map */
@@ -381,7 +381,7 @@ ccl_device_inline uint object_patch_map_offset(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return 0;
- return kernel_tex_fetch(__objects, object).patch_map_offset;
+ return kernel_data_fetch(objects, object).patch_map_offset;
}
/* Volume step size */
@@ -392,7 +392,7 @@ ccl_device_inline float object_volume_density(KernelGlobals kg, int object)
return 1.0f;
}
- return kernel_tex_fetch(__objects, object).volume_density;
+ return kernel_data_fetch(objects, object).volume_density;
}
ccl_device_inline float object_volume_step_size(KernelGlobals kg, int object)
@@ -401,14 +401,14 @@ ccl_device_inline float object_volume_step_size(KernelGlobals kg, int object)
return kernel_data.background.volume_step_size;
}
- return kernel_tex_fetch(__object_volume_step, object);
+ return kernel_data_fetch(object_volume_step, object);
}
/* Pass ID for shader */
ccl_device int shader_pass_id(KernelGlobals kg, ccl_private const ShaderData *sd)
{
- return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
+ return kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).pass_id;
}
/* Cryptomatte ID */
@@ -418,7 +418,7 @@ ccl_device_inline float object_cryptomatte_id(KernelGlobals kg, int object)
if (object == OBJECT_NONE)
return 0.0f;
- return kernel_tex_fetch(__objects, object).cryptomatte_object;
+ return kernel_data_fetch(objects, object).cryptomatte_object;
}
ccl_device_inline float object_cryptomatte_asset_id(KernelGlobals kg, int object)
@@ -426,49 +426,49 @@ ccl_device_inline float object_cryptomatte_asset_id(KernelGlobals kg, int object
if (object == OBJECT_NONE)
return 0;
- return kernel_tex_fetch(__objects, object).cryptomatte_asset;
+ return kernel_data_fetch(objects, object).cryptomatte_asset;
}
/* Particle data from which object was instanced */
ccl_device_inline uint particle_index(KernelGlobals kg, int particle)
{
- return kernel_tex_fetch(__particles, particle).index;
+ return kernel_data_fetch(particles, particle).index;
}
ccl_device float particle_age(KernelGlobals kg, int particle)
{
- return kernel_tex_fetch(__particles, particle).age;
+ return kernel_data_fetch(particles, particle).age;
}
ccl_device float particle_lifetime(KernelGlobals kg, int particle)
{
- return kernel_tex_fetch(__particles, particle).lifetime;
+ return kernel_data_fetch(particles, particle).lifetime;
}
ccl_device float particle_size(KernelGlobals kg, int particle)
{
- return kernel_tex_fetch(__particles, particle).size;
+ return kernel_data_fetch(particles, particle).size;
}
ccl_device float4 particle_rotation(KernelGlobals kg, int particle)
{
- return kernel_tex_fetch(__particles, particle).rotation;
+ return kernel_data_fetch(particles, particle).rotation;
}
ccl_device float3 particle_location(KernelGlobals kg, int particle)
{
- return float4_to_float3(kernel_tex_fetch(__particles, particle).location);
+ return float4_to_float3(kernel_data_fetch(particles, particle).location);
}
ccl_device float3 particle_velocity(KernelGlobals kg, int particle)
{
- return float4_to_float3(kernel_tex_fetch(__particles, particle).velocity);
+ return float4_to_float3(kernel_data_fetch(particles, particle).velocity);
}
ccl_device float3 particle_angular_velocity(KernelGlobals kg, int particle)
{
- return float4_to_float3(kernel_tex_fetch(__particles, particle).angular_velocity);
+ return float4_to_float3(kernel_data_fetch(particles, particle).angular_velocity);
}
/* Object intersection in BVH */
diff --git a/intern/cycles/kernel/geom/patch.h b/intern/cycles/kernel/geom/patch.h
index 1c63a00e30d..ec98ddf51f0 100644
--- a/intern/cycles/kernel/geom/patch.h
+++ b/intern/cycles/kernel/geom/patch.h
@@ -62,7 +62,7 @@ patch_map_find_patch(KernelGlobals kg, int object, int patch, float u, float v)
int quadrant = patch_map_resolve_quadrant(median, &u, &v);
kernel_assert(quadrant >= 0);
- uint child = kernel_tex_fetch(__patches, node + quadrant);
+ uint child = kernel_data_fetch(patches, node + quadrant);
/* is the quadrant a hole? */
if (!(child & PATCH_MAP_NODE_IS_SET)) {
@@ -73,9 +73,9 @@ patch_map_find_patch(KernelGlobals kg, int object, int patch, float u, float v)
uint index = child & PATCH_MAP_NODE_INDEX_MASK;
if (child & PATCH_MAP_NODE_IS_LEAF) {
- handle.array_index = kernel_tex_fetch(__patches, index + 0);
- handle.patch_index = kernel_tex_fetch(__patches, index + 1);
- handle.vert_index = kernel_tex_fetch(__patches, index + 2);
+ handle.array_index = kernel_data_fetch(patches, index + 0);
+ handle.patch_index = kernel_data_fetch(patches, index + 1);
+ handle.vert_index = kernel_data_fetch(patches, index + 2);
return handle;
}
@@ -189,11 +189,11 @@ ccl_device_inline int patch_eval_indices(KernelGlobals kg,
int channel,
int indices[PATCH_MAX_CONTROL_VERTS])
{
- int index_base = kernel_tex_fetch(__patches, handle->array_index + 2) + handle->vert_index;
+ int index_base = kernel_data_fetch(patches, handle->array_index + 2) + handle->vert_index;
/* XXX: regular patches only */
for (int i = 0; i < 16; i++) {
- indices[i] = kernel_tex_fetch(__patches, index_base + i);
+ indices[i] = kernel_data_fetch(patches, index_base + i);
}
return 16;
@@ -209,7 +209,7 @@ ccl_device_inline void patch_eval_basis(KernelGlobals kg,
float weights_du[PATCH_MAX_CONTROL_VERTS],
float weights_dv[PATCH_MAX_CONTROL_VERTS])
{
- uint patch_bits = kernel_tex_fetch(__patches, handle->patch_index + 1); /* read patch param */
+ uint patch_bits = kernel_data_fetch(patches, handle->patch_index + 1); /* read patch param */
float d_scale = 1 << patch_eval_depth(patch_bits);
bool non_quad_root = (patch_bits >> 4) & 0x1;
@@ -287,7 +287,7 @@ ccl_device float patch_eval_float(KernelGlobals kg,
*dv = 0.0f;
for (int i = 0; i < num_control; i++) {
- float v = kernel_tex_fetch(__attributes_float, offset + indices[i]);
+ float v = kernel_data_fetch(attributes_float, offset + indices[i]);
val += v * weights[i];
if (du)
@@ -324,7 +324,7 @@ ccl_device float2 patch_eval_float2(KernelGlobals kg,
*dv = make_float2(0.0f, 0.0f);
for (int i = 0; i < num_control; i++) {
- float2 v = kernel_tex_fetch(__attributes_float2, offset + indices[i]);
+ float2 v = kernel_data_fetch(attributes_float2, offset + indices[i]);
val += v * weights[i];
if (du)
@@ -361,7 +361,7 @@ ccl_device float3 patch_eval_float3(KernelGlobals kg,
*dv = make_float3(0.0f, 0.0f, 0.0f);
for (int i = 0; i < num_control; i++) {
- float3 v = kernel_tex_fetch(__attributes_float3, offset + indices[i]);
+ float3 v = kernel_data_fetch(attributes_float3, offset + indices[i]);
val += v * weights[i];
if (du)
@@ -398,7 +398,7 @@ ccl_device float4 patch_eval_float4(KernelGlobals kg,
*dv = zero_float4();
for (int i = 0; i < num_control; i++) {
- float4 v = kernel_tex_fetch(__attributes_float4, offset + indices[i]);
+ float4 v = kernel_data_fetch(attributes_float4, offset + indices[i]);
val += v * weights[i];
if (du)
@@ -436,7 +436,7 @@ ccl_device float4 patch_eval_uchar4(KernelGlobals kg,
for (int i = 0; i < num_control; i++) {
float4 v = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, offset + indices[i])));
+ color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, offset + indices[i])));
val += v * weights[i];
if (du)
diff --git a/intern/cycles/kernel/geom/point.h b/intern/cycles/kernel/geom/point.h
index ee7eca9e0c6..726d829c329 100644
--- a/intern/cycles/kernel/geom/point.h
+++ b/intern/cycles/kernel/geom/point.h
@@ -26,7 +26,7 @@ ccl_device float point_attribute_float(KernelGlobals kg,
# endif
if (desc.element == ATTR_ELEMENT_VERTEX) {
- return kernel_tex_fetch(__attributes_float, desc.offset + sd->prim);
+ return kernel_data_fetch(attributes_float, desc.offset + sd->prim);
}
else {
return 0.0f;
@@ -47,7 +47,7 @@ ccl_device float2 point_attribute_float2(KernelGlobals kg,
# endif
if (desc.element == ATTR_ELEMENT_VERTEX) {
- return kernel_tex_fetch(__attributes_float2, desc.offset + sd->prim);
+ return kernel_data_fetch(attributes_float2, desc.offset + sd->prim);
}
else {
return make_float2(0.0f, 0.0f);
@@ -68,7 +68,7 @@ ccl_device float3 point_attribute_float3(KernelGlobals kg,
# endif
if (desc.element == ATTR_ELEMENT_VERTEX) {
- return kernel_tex_fetch(__attributes_float3, desc.offset + sd->prim);
+ return kernel_data_fetch(attributes_float3, desc.offset + sd->prim);
}
else {
return make_float3(0.0f, 0.0f, 0.0f);
@@ -89,7 +89,7 @@ ccl_device float4 point_attribute_float4(KernelGlobals kg,
# endif
if (desc.element == ATTR_ELEMENT_VERTEX) {
- return kernel_tex_fetch(__attributes_float4, desc.offset + sd->prim);
+ return kernel_data_fetch(attributes_float4, desc.offset + sd->prim);
}
else {
return zero_float4();
@@ -104,7 +104,7 @@ ccl_device float3 point_position(KernelGlobals kg, ccl_private const ShaderData
/* World space center. */
float3 P = (sd->type & PRIMITIVE_MOTION) ?
float4_to_float3(motion_point(kg, sd->object, sd->prim, sd->time)) :
- float4_to_float3(kernel_tex_fetch(__points, sd->prim));
+ float4_to_float3(kernel_data_fetch(points, sd->prim));
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &P);
@@ -122,7 +122,7 @@ ccl_device float point_radius(KernelGlobals kg, ccl_private const ShaderData *sd
{
if (sd->type & PRIMITIVE_POINT) {
/* World space radius. */
- const float r = kernel_tex_fetch(__points, sd->prim).w;
+ const float r = kernel_data_fetch(points, sd->prim).w;
if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
return r;
@@ -155,7 +155,7 @@ ccl_device float point_random(KernelGlobals kg, ccl_private const ShaderData *sd
ccl_device float3 point_motion_center_location(KernelGlobals kg, ccl_private const ShaderData *sd)
{
- return float4_to_float3(kernel_tex_fetch(__points, sd->prim));
+ return float4_to_float3(kernel_data_fetch(points, sd->prim));
}
#endif /* __POINTCLOUD__ */
diff --git a/intern/cycles/kernel/geom/point_intersect.h b/intern/cycles/kernel/geom/point_intersect.h
index c7ae72bb488..ee5a564947b 100644
--- a/intern/cycles/kernel/geom/point_intersect.h
+++ b/intern/cycles/kernel/geom/point_intersect.h
@@ -9,8 +9,12 @@ CCL_NAMESPACE_BEGIN
#ifdef __POINTCLOUD__
-ccl_device_forceinline bool point_intersect_test(
- const float4 point, const float3 P, const float3 dir, const float tmax, ccl_private float *t)
+ccl_device_forceinline bool point_intersect_test(const float4 point,
+ const float3 P,
+ const float3 dir,
+ const float tmin,
+ const float tmax,
+ ccl_private float *t)
{
const float3 center = float4_to_float3(point);
const float radius = point.w;
@@ -28,12 +32,12 @@ ccl_device_forceinline bool point_intersect_test(
const float td = sqrt((r2 - l2) * rd2);
const float t_front = projC0 - td;
- const bool valid_front = (0.0f <= t_front) & (t_front <= tmax);
+ const bool valid_front = (tmin <= t_front) & (t_front <= tmax);
/* Always back-face culling for now. */
# if 0
const float t_back = projC0 + td;
- const bool valid_back = (0.0f <= t_back) & (t_back <= tmax);
+ const bool valid_back = (tmin <= t_back) & (t_back <= tmax);
/* check if there is a first hit */
const bool valid_first = valid_front | valid_back;
@@ -56,6 +60,7 @@ ccl_device_forceinline bool point_intersect(KernelGlobals kg,
ccl_private Intersection *isect,
const float3 P,
const float3 dir,
+ const float tmin,
const float tmax,
const int object,
const int prim,
@@ -63,9 +68,9 @@ ccl_device_forceinline bool point_intersect(KernelGlobals kg,
const int type)
{
const float4 point = (type & PRIMITIVE_MOTION) ? motion_point(kg, object, prim, time) :
- kernel_tex_fetch(__points, prim);
+ kernel_data_fetch(points, prim);
- if (!point_intersect_test(point, P, dir, tmax, &isect->t)) {
+ if (!point_intersect_test(point, P, dir, tmin, tmax, &isect->t)) {
return false;
}
@@ -82,7 +87,7 @@ ccl_device_inline void point_shader_setup(KernelGlobals kg,
ccl_private const Intersection *isect,
ccl_private const Ray *ray)
{
- sd->shader = kernel_tex_fetch(__points_shader, isect->prim);
+ sd->shader = kernel_data_fetch(points_shader, isect->prim);
sd->P = ray->P + ray->D * isect->t;
/* Texture coordinates, zero for now. */
@@ -94,7 +99,7 @@ ccl_device_inline void point_shader_setup(KernelGlobals kg,
/* Compute point center for normal. */
float3 center = float4_to_float3((isect->type & PRIMITIVE_MOTION) ?
motion_point(kg, sd->object, sd->prim, sd->time) :
- kernel_tex_fetch(__points, sd->prim));
+ kernel_data_fetch(points, sd->prim));
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
object_position_transform_auto(kg, sd, &center);
}
diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h
index 9b4b61fbd84..0f1a3fc11bc 100644
--- a/intern/cycles/kernel/geom/primitive.h
+++ b/intern/cycles/kernel/geom/primitive.h
@@ -18,11 +18,11 @@ CCL_NAMESPACE_BEGIN
* attributes for performance, mainly for GPU performance to avoid bringing in
* heavy volume interpolation code. */
-ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc,
- ccl_private float *dx,
- ccl_private float *dy)
+ccl_device_forceinline float primitive_surface_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float *dx,
+ ccl_private float *dy)
{
if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
@@ -49,11 +49,11 @@ ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg,
}
}
-ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc,
- ccl_private float2 *dx,
- ccl_private float2 *dy)
+ccl_device_forceinline float2 primitive_surface_attribute_float2(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float2 *dx,
+ ccl_private float2 *dy)
{
if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
@@ -80,11 +80,11 @@ ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg,
}
}
-ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc,
- ccl_private float3 *dx,
- ccl_private float3 *dy)
+ccl_device_forceinline float3 primitive_surface_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float3 *dx,
+ ccl_private float3 *dy)
{
if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
@@ -149,15 +149,15 @@ ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals k
* attributes for performance, mainly for GPU performance to avoid bringing in
* heavy volume interpolation code. */
-ccl_device_inline bool primitive_is_volume_attribute(ccl_private const ShaderData *sd,
- const AttributeDescriptor desc)
+ccl_device_forceinline bool primitive_is_volume_attribute(ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
{
return sd->type == PRIMITIVE_VOLUME;
}
-ccl_device_inline float primitive_volume_attribute_float(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc)
+ccl_device_forceinline float primitive_volume_attribute_float(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
{
if (primitive_is_volume_attribute(sd, desc)) {
return volume_attribute_value_to_float(volume_attribute_float4(kg, sd, desc));
@@ -167,9 +167,9 @@ ccl_device_inline float primitive_volume_attribute_float(KernelGlobals kg,
}
}
-ccl_device_inline float3 primitive_volume_attribute_float3(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc)
+ccl_device_forceinline float3 primitive_volume_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
{
if (primitive_is_volume_attribute(sd, desc)) {
return volume_attribute_value_to_float3(volume_attribute_float4(kg, sd, desc));
@@ -179,9 +179,9 @@ ccl_device_inline float3 primitive_volume_attribute_float3(KernelGlobals kg,
}
}
-ccl_device_inline float4 primitive_volume_attribute_float4(KernelGlobals kg,
- ccl_private const ShaderData *sd,
- const AttributeDescriptor desc)
+ccl_device_forceinline float4 primitive_volume_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc)
{
if (primitive_is_volume_attribute(sd, desc)) {
return volume_attribute_float4(kg, sd, desc);
@@ -194,7 +194,7 @@ ccl_device_inline float4 primitive_volume_attribute_float4(KernelGlobals kg,
/* Default UV coordinate */
-ccl_device_inline float3 primitive_uv(KernelGlobals kg, ccl_private const ShaderData *sd)
+ccl_device_forceinline float3 primitive_uv(KernelGlobals kg, ccl_private const ShaderData *sd)
{
const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_UV);
@@ -262,8 +262,8 @@ ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd
/* Motion vector for motion pass */
-ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
- ccl_private const ShaderData *sd)
+ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg,
+ ccl_private const ShaderData *sd)
{
/* center position */
float3 center;
diff --git a/intern/cycles/kernel/geom/shader_data.h b/intern/cycles/kernel/geom/shader_data.h
index 7a439da427a..99b9289cb4a 100644
--- a/intern/cycles/kernel/geom/shader_data.h
+++ b/intern/cycles/kernel/geom/shader_data.h
@@ -40,7 +40,7 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
sd->ray_length = isect->t;
sd->type = isect->type;
sd->object = isect->object;
- sd->object_flag = kernel_tex_fetch(__object_flag, sd->object);
+ sd->object_flag = kernel_data_fetch(object_flag, sd->object);
sd->prim = isect->prim;
sd->lamp = LAMP_NONE;
sd->flag = 0;
@@ -73,7 +73,7 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
if (sd->type == PRIMITIVE_TRIANGLE) {
/* static triangle */
float3 Ng = triangle_normal(kg, sd);
- sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
+ sd->shader = kernel_data_fetch(tri_shader, sd->prim);
/* vectors */
sd->P = triangle_point_from_uv(kg, sd, isect->object, isect->prim, isect->u, isect->v);
@@ -106,7 +106,7 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
}
}
- sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ sd->flag = kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).flags;
/* backfacing test */
bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
@@ -169,10 +169,10 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
sd->time = time;
sd->ray_length = t;
- sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ sd->flag = kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag = 0;
if (sd->object != OBJECT_NONE) {
- sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object);
+ sd->object_flag |= kernel_data_fetch(object_flag, sd->object);
#ifdef __OBJECT_MOTION__
shader_setup_object_transforms(kg, sd, time);
@@ -264,21 +264,20 @@ ccl_device void shader_setup_from_displace(KernelGlobals kg,
/* force smooth shading for displacement */
shader |= SHADER_SMOOTH_NORMAL;
- shader_setup_from_sample(
- kg,
- sd,
- P,
- Ng,
- I,
- shader,
- object,
- prim,
- u,
- v,
- 0.0f,
- 0.5f,
- !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
- LAMP_NONE);
+ shader_setup_from_sample(kg,
+ sd,
+ P,
+ Ng,
+ I,
+ shader,
+ object,
+ prim,
+ u,
+ v,
+ 0.0f,
+ 0.5f,
+ !(kernel_data_fetch(object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED),
+ LAMP_NONE);
}
/* ShaderData setup for point on curve. */
@@ -300,18 +299,18 @@ ccl_device void shader_setup_from_curve(KernelGlobals kg,
sd->ray_length = 0.0f;
/* Shader */
- sd->shader = kernel_tex_fetch(__curves, prim).shader_id;
- sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ sd->shader = kernel_data_fetch(curves, prim).shader_id;
+ sd->flag = kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).flags;
/* Object */
sd->object = object;
- sd->object_flag = kernel_tex_fetch(__object_flag, sd->object);
+ sd->object_flag = kernel_data_fetch(object_flag, sd->object);
#ifdef __OBJECT_MOTION__
shader_setup_object_transforms(kg, sd, sd->time);
#endif
/* Get control points. */
- KernelCurve kcurve = kernel_tex_fetch(__curves, prim);
+ KernelCurve kcurve = kernel_data_fetch(curves, prim);
int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
@@ -320,10 +319,10 @@ ccl_device void shader_setup_from_curve(KernelGlobals kg,
float4 P_curve[4];
- P_curve[0] = kernel_tex_fetch(__curve_keys, ka);
- P_curve[1] = kernel_tex_fetch(__curve_keys, k0);
- P_curve[2] = kernel_tex_fetch(__curve_keys, k1);
- P_curve[3] = kernel_tex_fetch(__curve_keys, kb);
+ P_curve[0] = kernel_data_fetch(curve_keys, ka);
+ P_curve[1] = kernel_data_fetch(curve_keys, k0);
+ P_curve[2] = kernel_data_fetch(curve_keys, k1);
+ P_curve[3] = kernel_data_fetch(curve_keys, kb);
/* Interpolate position and tangent. */
sd->P = float4_to_float3(catmull_rom_basis_derivative(P_curve, sd->u));
@@ -373,7 +372,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals kg,
sd->Ng = -ray_D;
sd->I = -ray_D;
sd->shader = kernel_data.background.surface_shader;
- sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ sd->flag = kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag = 0;
sd->time = ray_time;
sd->ray_length = 0.0f;
@@ -408,7 +407,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals kg,
{
/* vectors */
- sd->P = ray->P;
+ sd->P = ray->P + ray->D * ray->tmin;
sd->N = -ray->D;
sd->Ng = -ray->D;
sd->I = -ray->D;
@@ -442,7 +441,6 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals kg,
/* for NDC coordinates */
sd->ray_P = ray->P;
- sd->ray_dP = ray->dP;
}
#endif /* __VOLUME__ */
diff --git a/intern/cycles/kernel/geom/subd_triangle.h b/intern/cycles/kernel/geom/subd_triangle.h
index 24e1e454b8c..8b73b342e16 100644
--- a/intern/cycles/kernel/geom/subd_triangle.h
+++ b/intern/cycles/kernel/geom/subd_triangle.h
@@ -13,11 +13,11 @@ ccl_device_inline void subd_triangle_patch_uv(KernelGlobals kg,
ccl_private const ShaderData *sd,
float2 uv[3])
{
- uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
+ uint4 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
- uv[0] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.x);
- uv[1] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.y);
- uv[2] = kernel_tex_fetch(__tri_patch_uv, tri_vindex.z);
+ uv[0] = kernel_data_fetch(tri_patch_uv, tri_vindex.x);
+ uv[1] = kernel_data_fetch(tri_patch_uv, tri_vindex.y);
+ uv[2] = kernel_data_fetch(tri_patch_uv, tri_vindex.z);
}
/* Vertex indices of patch */
@@ -26,10 +26,10 @@ ccl_device_inline uint4 subd_triangle_patch_indices(KernelGlobals kg, int patch)
{
uint4 indices;
- indices.x = kernel_tex_fetch(__patches, patch + 0);
- indices.y = kernel_tex_fetch(__patches, patch + 1);
- indices.z = kernel_tex_fetch(__patches, patch + 2);
- indices.w = kernel_tex_fetch(__patches, patch + 3);
+ indices.x = kernel_data_fetch(patches, patch + 0);
+ indices.y = kernel_data_fetch(patches, patch + 1);
+ indices.z = kernel_data_fetch(patches, patch + 2);
+ indices.w = kernel_data_fetch(patches, patch + 3);
return indices;
}
@@ -38,14 +38,14 @@ ccl_device_inline uint4 subd_triangle_patch_indices(KernelGlobals kg, int patch)
ccl_device_inline uint subd_triangle_patch_face(KernelGlobals kg, int patch)
{
- return kernel_tex_fetch(__patches, patch + 4);
+ return kernel_data_fetch(patches, patch + 4);
}
/* Number of corners on originating face */
ccl_device_inline uint subd_triangle_patch_num_corners(KernelGlobals kg, int patch)
{
- return kernel_tex_fetch(__patches, patch + 5) & 0xffff;
+ return kernel_data_fetch(patches, patch + 5) & 0xffff;
}
/* Indices of the four corners that are used by the patch */
@@ -54,10 +54,10 @@ ccl_device_inline void subd_triangle_patch_corners(KernelGlobals kg, int patch,
{
uint4 data;
- data.x = kernel_tex_fetch(__patches, patch + 4);
- data.y = kernel_tex_fetch(__patches, patch + 5);
- data.z = kernel_tex_fetch(__patches, patch + 6);
- data.w = kernel_tex_fetch(__patches, patch + 7);
+ data.x = kernel_data_fetch(patches, patch + 4);
+ data.y = kernel_data_fetch(patches, patch + 5);
+ data.z = kernel_data_fetch(patches, patch + 6);
+ data.w = kernel_data_fetch(patches, patch + 7);
int num_corners = data.y & 0xffff;
@@ -141,7 +141,7 @@ ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg,
if (dy)
*dy = 0.0f;
- return kernel_tex_fetch(__attributes_float, desc.offset + subd_triangle_patch_face(kg, patch));
+ return kernel_data_fetch(attributes_float, desc.offset + subd_triangle_patch_face(kg, patch));
}
else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
float2 uv[3];
@@ -149,10 +149,10 @@ ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg,
uint4 v = subd_triangle_patch_indices(kg, patch);
- float f0 = kernel_tex_fetch(__attributes_float, desc.offset + v.x);
- float f1 = kernel_tex_fetch(__attributes_float, desc.offset + v.y);
- float f2 = kernel_tex_fetch(__attributes_float, desc.offset + v.z);
- float f3 = kernel_tex_fetch(__attributes_float, desc.offset + v.w);
+ float f0 = kernel_data_fetch(attributes_float, desc.offset + v.x);
+ float f1 = kernel_data_fetch(attributes_float, desc.offset + v.y);
+ float f2 = kernel_data_fetch(attributes_float, desc.offset + v.z);
+ float f3 = kernel_data_fetch(attributes_float, desc.offset + v.w);
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -179,10 +179,10 @@ ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg,
int corners[4];
subd_triangle_patch_corners(kg, patch, corners);
- float f0 = kernel_tex_fetch(__attributes_float, corners[0] + desc.offset);
- float f1 = kernel_tex_fetch(__attributes_float, corners[1] + desc.offset);
- float f2 = kernel_tex_fetch(__attributes_float, corners[2] + desc.offset);
- float f3 = kernel_tex_fetch(__attributes_float, corners[3] + desc.offset);
+ float f0 = kernel_data_fetch(attributes_float, corners[0] + desc.offset);
+ float f1 = kernel_data_fetch(attributes_float, corners[1] + desc.offset);
+ float f2 = kernel_data_fetch(attributes_float, corners[2] + desc.offset);
+ float f3 = kernel_data_fetch(attributes_float, corners[3] + desc.offset);
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -208,7 +208,7 @@ ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg,
if (dy)
*dy = 0.0f;
- return kernel_tex_fetch(__attributes_float, desc.offset);
+ return kernel_data_fetch(attributes_float, desc.offset);
}
else {
if (dx)
@@ -281,8 +281,7 @@ ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg,
if (dy)
*dy = make_float2(0.0f, 0.0f);
- return kernel_tex_fetch(__attributes_float2,
- desc.offset + subd_triangle_patch_face(kg, patch));
+ return kernel_data_fetch(attributes_float2, desc.offset + subd_triangle_patch_face(kg, patch));
}
else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
float2 uv[3];
@@ -290,10 +289,10 @@ ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg,
uint4 v = subd_triangle_patch_indices(kg, patch);
- float2 f0 = kernel_tex_fetch(__attributes_float2, desc.offset + v.x);
- float2 f1 = kernel_tex_fetch(__attributes_float2, desc.offset + v.y);
- float2 f2 = kernel_tex_fetch(__attributes_float2, desc.offset + v.z);
- float2 f3 = kernel_tex_fetch(__attributes_float2, desc.offset + v.w);
+ float2 f0 = kernel_data_fetch(attributes_float2, desc.offset + v.x);
+ float2 f1 = kernel_data_fetch(attributes_float2, desc.offset + v.y);
+ float2 f2 = kernel_data_fetch(attributes_float2, desc.offset + v.z);
+ float2 f3 = kernel_data_fetch(attributes_float2, desc.offset + v.w);
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -322,10 +321,10 @@ ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg,
float2 f0, f1, f2, f3;
- f0 = kernel_tex_fetch(__attributes_float2, corners[0] + desc.offset);
- f1 = kernel_tex_fetch(__attributes_float2, corners[1] + desc.offset);
- f2 = kernel_tex_fetch(__attributes_float2, corners[2] + desc.offset);
- f3 = kernel_tex_fetch(__attributes_float2, corners[3] + desc.offset);
+ f0 = kernel_data_fetch(attributes_float2, corners[0] + desc.offset);
+ f1 = kernel_data_fetch(attributes_float2, corners[1] + desc.offset);
+ f2 = kernel_data_fetch(attributes_float2, corners[2] + desc.offset);
+ f3 = kernel_data_fetch(attributes_float2, corners[3] + desc.offset);
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -351,7 +350,7 @@ ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg,
if (dy)
*dy = make_float2(0.0f, 0.0f);
- return kernel_tex_fetch(__attributes_float2, desc.offset);
+ return kernel_data_fetch(attributes_float2, desc.offset);
}
else {
if (dx)
@@ -423,8 +422,7 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg,
if (dy)
*dy = make_float3(0.0f, 0.0f, 0.0f);
- return kernel_tex_fetch(__attributes_float3,
- desc.offset + subd_triangle_patch_face(kg, patch));
+ return kernel_data_fetch(attributes_float3, desc.offset + subd_triangle_patch_face(kg, patch));
}
else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
float2 uv[3];
@@ -432,10 +430,10 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg,
uint4 v = subd_triangle_patch_indices(kg, patch);
- float3 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + v.x);
- float3 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + v.y);
- float3 f2 = kernel_tex_fetch(__attributes_float3, desc.offset + v.z);
- float3 f3 = kernel_tex_fetch(__attributes_float3, desc.offset + v.w);
+ float3 f0 = kernel_data_fetch(attributes_float3, desc.offset + v.x);
+ float3 f1 = kernel_data_fetch(attributes_float3, desc.offset + v.y);
+ float3 f2 = kernel_data_fetch(attributes_float3, desc.offset + v.z);
+ float3 f3 = kernel_data_fetch(attributes_float3, desc.offset + v.w);
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -464,10 +462,10 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg,
float3 f0, f1, f2, f3;
- f0 = kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset);
- f1 = kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset);
- f2 = kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset);
- f3 = kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset);
+ f0 = kernel_data_fetch(attributes_float3, corners[0] + desc.offset);
+ f1 = kernel_data_fetch(attributes_float3, corners[1] + desc.offset);
+ f2 = kernel_data_fetch(attributes_float3, corners[2] + desc.offset);
+ f3 = kernel_data_fetch(attributes_float3, corners[3] + desc.offset);
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -493,7 +491,7 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg,
if (dy)
*dy = make_float3(0.0f, 0.0f, 0.0f);
- return kernel_tex_fetch(__attributes_float3, desc.offset);
+ return kernel_data_fetch(attributes_float3, desc.offset);
}
else {
if (dx)
@@ -570,8 +568,7 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
if (dy)
*dy = zero_float4();
- return kernel_tex_fetch(__attributes_float4,
- desc.offset + subd_triangle_patch_face(kg, patch));
+ return kernel_data_fetch(attributes_float4, desc.offset + subd_triangle_patch_face(kg, patch));
}
else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
float2 uv[3];
@@ -579,10 +576,10 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
uint4 v = subd_triangle_patch_indices(kg, patch);
- float4 f0 = kernel_tex_fetch(__attributes_float4, desc.offset + v.x);
- float4 f1 = kernel_tex_fetch(__attributes_float4, desc.offset + v.y);
- float4 f2 = kernel_tex_fetch(__attributes_float4, desc.offset + v.z);
- float4 f3 = kernel_tex_fetch(__attributes_float4, desc.offset + v.w);
+ float4 f0 = kernel_data_fetch(attributes_float4, desc.offset + v.x);
+ float4 f1 = kernel_data_fetch(attributes_float4, desc.offset + v.y);
+ float4 f2 = kernel_data_fetch(attributes_float4, desc.offset + v.z);
+ float4 f3 = kernel_data_fetch(attributes_float4, desc.offset + v.w);
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -613,19 +610,19 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
f0 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset)));
+ color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, corners[0] + desc.offset)));
f1 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset)));
+ color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, corners[1] + desc.offset)));
f2 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset)));
+ color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, corners[2] + desc.offset)));
f3 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset)));
+ color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, corners[3] + desc.offset)));
}
else {
- f0 = kernel_tex_fetch(__attributes_float4, corners[0] + desc.offset);
- f1 = kernel_tex_fetch(__attributes_float4, corners[1] + desc.offset);
- f2 = kernel_tex_fetch(__attributes_float4, corners[2] + desc.offset);
- f3 = kernel_tex_fetch(__attributes_float4, corners[3] + desc.offset);
+ f0 = kernel_data_fetch(attributes_float4, corners[0] + desc.offset);
+ f1 = kernel_data_fetch(attributes_float4, corners[1] + desc.offset);
+ f2 = kernel_data_fetch(attributes_float4, corners[2] + desc.offset);
+ f3 = kernel_data_fetch(attributes_float4, corners[3] + desc.offset);
}
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
@@ -652,7 +649,7 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
if (dy)
*dy = zero_float4();
- return kernel_tex_fetch(__attributes_float4, desc.offset);
+ return kernel_data_fetch(attributes_float4, desc.offset);
}
else {
if (dx)
diff --git a/intern/cycles/kernel/geom/triangle.h b/intern/cycles/kernel/geom/triangle.h
index 8ac7e67ff05..788bfaca7cf 100644
--- a/intern/cycles/kernel/geom/triangle.h
+++ b/intern/cycles/kernel/geom/triangle.h
@@ -15,10 +15,10 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float3 triangle_normal(KernelGlobals kg, ccl_private ShaderData *sd)
{
/* load triangle vertices */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- const float3 v0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
- const float3 v1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
- const float3 v2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
+ const float3 v0 = kernel_data_fetch(tri_verts, tri_vindex.w + 0);
+ const float3 v1 = kernel_data_fetch(tri_verts, tri_vindex.w + 1);
+ const float3 v2 = kernel_data_fetch(tri_verts, tri_vindex.w + 2);
/* return normal */
if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
@@ -40,15 +40,15 @@ ccl_device_inline void triangle_point_normal(KernelGlobals kg,
ccl_private int *shader)
{
/* load triangle vertices */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- float3 v0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
- float3 v1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
- float3 v2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
+ float3 v0 = kernel_data_fetch(tri_verts, tri_vindex.w + 0);
+ float3 v1 = kernel_data_fetch(tri_verts, tri_vindex.w + 1);
+ float3 v2 = kernel_data_fetch(tri_verts, tri_vindex.w + 2);
/* compute point */
float t = 1.0f - u - v;
*P = (u * v0 + v * v1 + t * v2);
/* get object flags */
- int object_flag = kernel_tex_fetch(__object_flag, object);
+ int object_flag = kernel_data_fetch(object_flag, object);
/* compute normal */
if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
*Ng = normalize(cross(v2 - v0, v1 - v0));
@@ -57,17 +57,17 @@ ccl_device_inline void triangle_point_normal(KernelGlobals kg,
*Ng = normalize(cross(v1 - v0, v2 - v0));
}
/* shader`*/
- *shader = kernel_tex_fetch(__tri_shader, prim);
+ *shader = kernel_data_fetch(tri_shader, prim);
}
/* Triangle vertex locations */
ccl_device_inline void triangle_vertices(KernelGlobals kg, int prim, float3 P[3])
{
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- P[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
- P[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
- P[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
+ P[0] = kernel_data_fetch(tri_verts, tri_vindex.w + 0);
+ P[1] = kernel_data_fetch(tri_verts, tri_vindex.w + 1);
+ P[2] = kernel_data_fetch(tri_verts, tri_vindex.w + 2);
}
/* Triangle vertex locations and vertex normals */
@@ -77,13 +77,13 @@ ccl_device_inline void triangle_vertices_and_normals(KernelGlobals kg,
float3 P[3],
float3 N[3])
{
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- P[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
- P[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
- P[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
- N[0] = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
- N[1] = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
- N[2] = kernel_tex_fetch(__tri_vnormal, tri_vindex.z);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
+ P[0] = kernel_data_fetch(tri_verts, tri_vindex.w + 0);
+ P[1] = kernel_data_fetch(tri_verts, tri_vindex.w + 1);
+ P[2] = kernel_data_fetch(tri_verts, tri_vindex.w + 2);
+ N[0] = kernel_data_fetch(tri_vnormal, tri_vindex.x);
+ N[1] = kernel_data_fetch(tri_vnormal, tri_vindex.y);
+ N[2] = kernel_data_fetch(tri_vnormal, tri_vindex.z);
}
/* Interpolate smooth vertex normal from vertices */
@@ -92,10 +92,10 @@ ccl_device_inline float3
triangle_smooth_normal(KernelGlobals kg, float3 Ng, int prim, float u, float v)
{
/* load triangle vertices */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- float3 n0 = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
- float3 n1 = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
- float3 n2 = kernel_tex_fetch(__tri_vnormal, tri_vindex.z);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
+ float3 n0 = kernel_data_fetch(tri_vnormal, tri_vindex.x);
+ float3 n1 = kernel_data_fetch(tri_vnormal, tri_vindex.y);
+ float3 n2 = kernel_data_fetch(tri_vnormal, tri_vindex.z);
float3 N = safe_normalize((1.0f - u - v) * n2 + u * n0 + v * n1);
@@ -106,10 +106,10 @@ ccl_device_inline float3 triangle_smooth_normal_unnormalized(
KernelGlobals kg, ccl_private const ShaderData *sd, float3 Ng, int prim, float u, float v)
{
/* load triangle vertices */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- float3 n0 = kernel_tex_fetch(__tri_vnormal, tri_vindex.x);
- float3 n1 = kernel_tex_fetch(__tri_vnormal, tri_vindex.y);
- float3 n2 = kernel_tex_fetch(__tri_vnormal, tri_vindex.z);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
+ float3 n0 = kernel_data_fetch(tri_vnormal, tri_vindex.x);
+ float3 n1 = kernel_data_fetch(tri_vnormal, tri_vindex.y);
+ float3 n2 = kernel_data_fetch(tri_vnormal, tri_vindex.z);
/* ensure that the normals are in object space */
if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
@@ -131,10 +131,10 @@ ccl_device_inline void triangle_dPdudv(KernelGlobals kg,
ccl_private float3 *dPdv)
{
/* fetch triangle vertex coordinates */
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
- const float3 p0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0);
- const float3 p1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1);
- const float3 p2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, prim);
+ const float3 p0 = kernel_data_fetch(tri_verts, tri_vindex.w + 0);
+ const float3 p1 = kernel_data_fetch(tri_verts, tri_vindex.w + 1);
+ const float3 p2 = kernel_data_fetch(tri_verts, tri_vindex.w + 2);
/* compute derivatives of P w.r.t. uv */
*dPdu = (p0 - p2);
@@ -153,16 +153,16 @@ ccl_device float triangle_attribute_float(KernelGlobals kg,
float f0, f1, f2;
if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- f0 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.x);
- f1 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.y);
- f2 = kernel_tex_fetch(__attributes_float, desc.offset + tri_vindex.z);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
+ f0 = kernel_data_fetch(attributes_float, desc.offset + tri_vindex.x);
+ f1 = kernel_data_fetch(attributes_float, desc.offset + tri_vindex.y);
+ f2 = kernel_data_fetch(attributes_float, desc.offset + tri_vindex.z);
}
else {
const int tri = desc.offset + sd->prim * 3;
- f0 = kernel_tex_fetch(__attributes_float, tri + 0);
- f1 = kernel_tex_fetch(__attributes_float, tri + 1);
- f2 = kernel_tex_fetch(__attributes_float, tri + 2);
+ f0 = kernel_data_fetch(attributes_float, tri + 0);
+ f1 = kernel_data_fetch(attributes_float, tri + 1);
+ f2 = kernel_data_fetch(attributes_float, tri + 2);
}
#ifdef __RAY_DIFFERENTIALS__
@@ -185,7 +185,7 @@ ccl_device float triangle_attribute_float(KernelGlobals kg,
if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
desc.offset;
- return kernel_tex_fetch(__attributes_float, offset);
+ return kernel_data_fetch(attributes_float, offset);
}
else {
return 0.0f;
@@ -203,16 +203,16 @@ ccl_device float2 triangle_attribute_float2(KernelGlobals kg,
float2 f0, f1, f2;
if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- f0 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.x);
- f1 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.y);
- f2 = kernel_tex_fetch(__attributes_float2, desc.offset + tri_vindex.z);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
+ f0 = kernel_data_fetch(attributes_float2, desc.offset + tri_vindex.x);
+ f1 = kernel_data_fetch(attributes_float2, desc.offset + tri_vindex.y);
+ f2 = kernel_data_fetch(attributes_float2, desc.offset + tri_vindex.z);
}
else {
const int tri = desc.offset + sd->prim * 3;
- f0 = kernel_tex_fetch(__attributes_float2, tri + 0);
- f1 = kernel_tex_fetch(__attributes_float2, tri + 1);
- f2 = kernel_tex_fetch(__attributes_float2, tri + 2);
+ f0 = kernel_data_fetch(attributes_float2, tri + 0);
+ f1 = kernel_data_fetch(attributes_float2, tri + 1);
+ f2 = kernel_data_fetch(attributes_float2, tri + 2);
}
#ifdef __RAY_DIFFERENTIALS__
@@ -235,7 +235,7 @@ ccl_device float2 triangle_attribute_float2(KernelGlobals kg,
if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
desc.offset;
- return kernel_tex_fetch(__attributes_float2, offset);
+ return kernel_data_fetch(attributes_float2, offset);
}
else {
return make_float2(0.0f, 0.0f);
@@ -253,16 +253,16 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals kg,
float3 f0, f1, f2;
if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- f0 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x);
- f1 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y);
- f2 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
+ f0 = kernel_data_fetch(attributes_float3, desc.offset + tri_vindex.x);
+ f1 = kernel_data_fetch(attributes_float3, desc.offset + tri_vindex.y);
+ f2 = kernel_data_fetch(attributes_float3, desc.offset + tri_vindex.z);
}
else {
const int tri = desc.offset + sd->prim * 3;
- f0 = kernel_tex_fetch(__attributes_float3, tri + 0);
- f1 = kernel_tex_fetch(__attributes_float3, tri + 1);
- f2 = kernel_tex_fetch(__attributes_float3, tri + 2);
+ f0 = kernel_data_fetch(attributes_float3, tri + 0);
+ f1 = kernel_data_fetch(attributes_float3, tri + 1);
+ f2 = kernel_data_fetch(attributes_float3, tri + 2);
}
#ifdef __RAY_DIFFERENTIALS__
@@ -285,7 +285,7 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals kg,
if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
desc.offset;
- return kernel_tex_fetch(__attributes_float3, offset);
+ return kernel_data_fetch(attributes_float3, offset);
}
else {
return make_float3(0.0f, 0.0f, 0.0f);
@@ -304,25 +304,25 @@ ccl_device float4 triangle_attribute_float4(KernelGlobals kg,
float4 f0, f1, f2;
if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) {
- const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim);
- f0 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.x);
- f1 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.y);
- f2 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.z);
+ const uint4 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
+ f0 = kernel_data_fetch(attributes_float4, desc.offset + tri_vindex.x);
+ f1 = kernel_data_fetch(attributes_float4, desc.offset + tri_vindex.y);
+ f2 = kernel_data_fetch(attributes_float4, desc.offset + tri_vindex.z);
}
else {
const int tri = desc.offset + sd->prim * 3;
if (desc.element == ATTR_ELEMENT_CORNER) {
- f0 = kernel_tex_fetch(__attributes_float4, tri + 0);
- f1 = kernel_tex_fetch(__attributes_float4, tri + 1);
- f2 = kernel_tex_fetch(__attributes_float4, tri + 2);
+ f0 = kernel_data_fetch(attributes_float4, tri + 0);
+ f1 = kernel_data_fetch(attributes_float4, tri + 1);
+ f2 = kernel_data_fetch(attributes_float4, tri + 2);
}
else {
f0 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 0)));
+ color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, tri + 0)));
f1 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 1)));
+ color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, tri + 1)));
f2 = color_srgb_to_linear_v4(
- color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 2)));
+ color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, tri + 2)));
}
}
@@ -346,7 +346,7 @@ ccl_device float4 triangle_attribute_float4(KernelGlobals kg,
if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim :
desc.offset;
- return kernel_tex_fetch(__attributes_float4, offset);
+ return kernel_data_fetch(attributes_float4, offset);
}
else {
return zero_float4();
diff --git a/intern/cycles/kernel/geom/triangle_intersect.h b/intern/cycles/kernel/geom/triangle_intersect.h
index fe531e6868a..f968e537cfa 100644
--- a/intern/cycles/kernel/geom/triangle_intersect.h
+++ b/intern/cycles/kernel/geom/triangle_intersect.h
@@ -17,23 +17,24 @@ ccl_device_inline bool triangle_intersect(KernelGlobals kg,
ccl_private Intersection *isect,
float3 P,
float3 dir,
+ float tmin,
float tmax,
uint visibility,
int object,
int prim,
int prim_addr)
{
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
- const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
+ const uint tri_vindex = kernel_data_fetch(tri_vindex, prim).w;
+ const float3 tri_a = kernel_data_fetch(tri_verts, tri_vindex + 0),
+ tri_b = kernel_data_fetch(tri_verts, tri_vindex + 1),
+ tri_c = kernel_data_fetch(tri_verts, tri_vindex + 2);
float t, u, v;
- if (ray_triangle_intersect(P, dir, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) {
+ if (ray_triangle_intersect(P, dir, tmin, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) {
#ifdef __VISIBILITY_FLAG__
/* Visibility flag test. we do it here under the assumption
* that most triangles are culled by node flags.
*/
- if (kernel_tex_fetch(__prim_visibility, prim_addr) & visibility)
+ if (kernel_data_fetch(prim_visibility, prim_addr) & visibility)
#endif
{
isect->object = object;
@@ -62,16 +63,17 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg,
int object,
int prim,
int prim_addr,
+ float tmin,
float tmax,
ccl_private uint *lcg_state,
int max_hits)
{
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w;
- const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
+ const uint tri_vindex = kernel_data_fetch(tri_vindex, prim).w;
+ const float3 tri_a = kernel_data_fetch(tri_verts, tri_vindex + 0),
+ tri_b = kernel_data_fetch(tri_verts, tri_vindex + 1),
+ tri_c = kernel_data_fetch(tri_verts, tri_vindex + 2);
float t, u, v;
- if (!ray_triangle_intersect(P, dir, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) {
+ if (!ray_triangle_intersect(P, dir, tmin, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) {
return false;
}
@@ -139,10 +141,10 @@ ccl_device_inline float3 triangle_point_from_uv(KernelGlobals kg,
const float u,
const float v)
{
- const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w;
- const packed_float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0),
- tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1),
- tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2);
+ const uint tri_vindex = kernel_data_fetch(tri_vindex, isect_prim).w;
+ const packed_float3 tri_a = kernel_data_fetch(tri_verts, tri_vindex + 0),
+ tri_b = kernel_data_fetch(tri_verts, tri_vindex + 1),
+ tri_c = kernel_data_fetch(tri_verts, tri_vindex + 2);
float w = 1.0f - u - v;
float3 P = u * tri_a + v * tri_b + w * tri_c;
diff --git a/intern/cycles/kernel/geom/volume.h b/intern/cycles/kernel/geom/volume.h
index 22715dee5bf..3510a905def 100644
--- a/intern/cycles/kernel/geom/volume.h
+++ b/intern/cycles/kernel/geom/volume.h
@@ -62,7 +62,7 @@ ccl_device float4 volume_attribute_float4(KernelGlobals kg,
const AttributeDescriptor desc)
{
if (desc.element & (ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
- return kernel_tex_fetch(__attributes_float4, desc.offset);
+ return kernel_data_fetch(attributes_float4, desc.offset);
}
else if (desc.element == ATTR_ELEMENT_VOXEL) {
/* todo: optimize this so we don't have to transform both here and in
diff --git a/intern/cycles/kernel/integrator/init_from_bake.h b/intern/cycles/kernel/integrator/init_from_bake.h
index 293c1d243f8..bf3f41b52b9 100644
--- a/intern/cycles/kernel/integrator/init_from_bake.h
+++ b/intern/cycles/kernel/integrator/init_from_bake.h
@@ -49,7 +49,8 @@ ccl_device const float2 bake_offset_towards_center(KernelGlobals kg,
const float3 to_center = center - P;
const float3 offset_P = P + normalize(to_center) *
- min(len(to_center), max(max3(fabs(P)), 1.0f) * position_offset);
+ min(len(to_center),
+ max(reduce_max(fabs(P)), 1.0f) * position_offset);
/* Compute barycentric coordinates at new position. */
const float3 v1 = tri_verts[1] - tri_verts[0];
@@ -160,7 +161,7 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
int shader;
triangle_point_normal(kg, object, prim, u, v, &P, &Ng, &shader);
- const int object_flag = kernel_tex_fetch(__object_flag, object);
+ const int object_flag = kernel_data_fetch(object_flag, object);
if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
P = transform_point_auto(&tfm, P);
@@ -173,14 +174,15 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
Ray ray ccl_optional_struct_init;
ray.P = zero_float3();
ray.D = normalize(P);
- ray.t = FLT_MAX;
+ ray.tmin = 0.0f;
+ ray.tmax = FLT_MAX;
ray.time = 0.5f;
ray.dP = differential_zero_compact();
ray.dD = differential_zero_compact();
integrator_state_write_ray(kg, state, &ray);
/* Setup next kernel to execute. */
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ integrator_path_init(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
}
else {
/* Surface baking. */
@@ -193,7 +195,7 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
}
const int shader_index = shader & SHADER_MASK;
- const int shader_flags = kernel_tex_fetch(__shaders, shader_index).flags;
+ const int shader_flags = kernel_data_fetch(shaders, shader_index).flags;
/* Fast path for position and normal passes not affected by shaders. */
if (kernel_data.film.pass_position != PASS_UNUSED) {
@@ -209,7 +211,8 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
Ray ray ccl_optional_struct_init;
ray.P = P + N;
ray.D = -N;
- ray.t = FLT_MAX;
+ ray.tmin = 0.0f;
+ ray.tmax = FLT_MAX;
ray.time = 0.5f;
/* Setup differentials. */
@@ -243,13 +246,18 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg,
/* Setup next kernel to execute. */
const bool use_caustics = kernel_data.integrator.use_caustics &&
(object_flag & SD_OBJECT_CAUSTICS);
- const bool use_raytrace_kernel = (shader_flags & SD_HAS_RAYTRACE) || use_caustics;
+ const bool use_raytrace_kernel = (shader_flags & SD_HAS_RAYTRACE);
- if (use_raytrace_kernel) {
- INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader_index);
+ if (use_caustics) {
+ integrator_path_init_sorted(
+ kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE, shader_index);
+ }
+ else if (use_raytrace_kernel) {
+ integrator_path_init_sorted(
+ kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader_index);
}
else {
- INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader_index);
+ integrator_path_init_sorted(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader_index);
}
}
diff --git a/intern/cycles/kernel/integrator/init_from_camera.h b/intern/cycles/kernel/integrator/init_from_camera.h
index 9fe27cdda9a..e89ab3991c7 100644
--- a/intern/cycles/kernel/integrator/init_from_camera.h
+++ b/intern/cycles/kernel/integrator/init_from_camera.h
@@ -86,7 +86,7 @@ ccl_device bool integrator_init_from_camera(KernelGlobals kg,
/* Generate camera ray. */
Ray ray;
integrate_camera_sample(kg, sample, x, y, rng_hash, &ray);
- if (ray.t == 0.0f) {
+ if (ray.tmax == 0.0f) {
return true;
}
@@ -100,10 +100,10 @@ ccl_device bool integrator_init_from_camera(KernelGlobals kg,
/* Continue with intersect_closest kernel, optionally initializing volume
* stack before that if the camera may be inside a volume. */
if (kernel_data.cam.is_inside_volume) {
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
+ integrator_path_init(kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
}
else {
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+ integrator_path_init(kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
}
return true;
diff --git a/intern/cycles/kernel/integrator/intersect_closest.h b/intern/cycles/kernel/integrator/intersect_closest.h
index b8ce625c11b..60299f2cb2f 100644
--- a/intern/cycles/kernel/integrator/intersect_closest.h
+++ b/intern/cycles/kernel/integrator/intersect_closest.h
@@ -109,34 +109,38 @@ ccl_device_forceinline void integrator_split_shadow_catcher(
/* If using background pass, schedule background shading kernel so that we have a background
* to alpha-over on. The background kernel will then continue the path afterwards. */
INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SHADOW_CATCHER_BACKGROUND;
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ integrator_path_init(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
return;
}
if (!integrator_state_volume_stack_is_empty(kg, state)) {
/* Volume stack is not empty. Re-init the volume stack to exclude any non-shadow catcher
* objects from it, and then continue shading volume and shadow catcher surface after. */
- INTEGRATOR_PATH_INIT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
+ integrator_path_init(kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
return;
}
/* Continue with shading shadow catcher surface. */
const int shader = intersection_get_shader(kg, isect);
- const int flags = kernel_tex_fetch(__shaders, shader).flags;
+ const int flags = kernel_data_fetch(shaders, shader).flags;
const bool use_caustics = kernel_data.integrator.use_caustics &&
(object_flags & SD_OBJECT_CAUSTICS);
- const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE) || use_caustics;
+ const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
- if (use_raytrace_kernel) {
- INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
+ if (use_caustics) {
+ integrator_path_init_sorted(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE, shader);
+ }
+ else if (use_raytrace_kernel) {
+ integrator_path_init_sorted(
+ kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
}
else {
- INTEGRATOR_PATH_INIT_SORTED(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
+ integrator_path_init_sorted(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
}
}
/* Schedule next kernel to be executed after updating volume stack for shadow catcher. */
-template<uint32_t current_kernel>
+template<DeviceKernel current_kernel>
ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catcher_volume(
KernelGlobals kg, IntegratorState state)
{
@@ -146,23 +150,28 @@ ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catche
integrator_state_read_isect(kg, state, &isect);
const int shader = intersection_get_shader(kg, &isect);
- const int flags = kernel_tex_fetch(__shaders, shader).flags;
+ const int flags = kernel_data_fetch(shaders, shader).flags;
const int object_flags = intersection_get_object_flags(kg, &isect);
const bool use_caustics = kernel_data.integrator.use_caustics &&
(object_flags & SD_OBJECT_CAUSTICS);
- const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE) || use_caustics;
+ const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
- if (use_raytrace_kernel) {
- INTEGRATOR_PATH_NEXT_SORTED(
- current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
+ if (use_caustics) {
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE, shader);
+ }
+ else if (use_raytrace_kernel) {
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
}
else {
- INTEGRATOR_PATH_NEXT_SORTED(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
}
}
/* Schedule next kernel to be executed after executing background shader for shadow catcher. */
-template<uint32_t current_kernel>
+template<DeviceKernel current_kernel>
ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catcher_background(
KernelGlobals kg, IntegratorState state)
{
@@ -170,7 +179,8 @@ ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catche
if (!integrator_state_volume_stack_is_empty(kg, state)) {
/* Volume stack is not empty. Re-init the volume stack to exclude any non-shadow catcher
* objects from it, and then continue shading volume and shadow catcher surface after. */
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
+ integrator_path_next(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK);
return;
}
@@ -183,7 +193,7 @@ ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catche
*
* Note that current_kernel is a template value since making this a variable
* leads to poor performance with CUDA atomics. */
-template<uint32_t current_kernel>
+template<DeviceKernel current_kernel>
ccl_device_forceinline void integrator_intersect_next_kernel(
KernelGlobals kg,
IntegratorState state,
@@ -196,13 +206,13 @@ ccl_device_forceinline void integrator_intersect_next_kernel(
if (!integrator_state_volume_stack_is_empty(kg, state)) {
const bool hit_surface = hit && !(isect->type & PRIMITIVE_LAMP);
const int shader = (hit_surface) ? intersection_get_shader(kg, isect) : SHADER_NONE;
- const int flags = (hit_surface) ? kernel_tex_fetch(__shaders, shader).flags : 0;
+ const int flags = (hit_surface) ? kernel_data_fetch(shaders, shader).flags : 0;
if (!integrator_intersect_terminate(kg, state, flags)) {
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
+ integrator_path_next(kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
}
else {
- INTEGRATOR_PATH_TERMINATE(current_kernel);
+ integrator_path_terminate(kg, state, current_kernel);
}
return;
}
@@ -211,25 +221,29 @@ ccl_device_forceinline void integrator_intersect_next_kernel(
if (hit) {
/* Hit a surface, continue with light or surface kernel. */
if (isect->type & PRIMITIVE_LAMP) {
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
+ integrator_path_next(kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
}
else {
/* Hit a surface, continue with surface kernel unless terminated. */
const int shader = intersection_get_shader(kg, isect);
- const int flags = kernel_tex_fetch(__shaders, shader).flags;
+ const int flags = kernel_data_fetch(shaders, shader).flags;
if (!integrator_intersect_terminate(kg, state, flags)) {
const int object_flags = intersection_get_object_flags(kg, isect);
const bool use_caustics = kernel_data.integrator.use_caustics &&
(object_flags & SD_OBJECT_CAUSTICS);
- const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE) || use_caustics;
- if (use_raytrace_kernel) {
- INTEGRATOR_PATH_NEXT_SORTED(
- current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
+ const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
+ if (use_caustics) {
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE, shader);
+ }
+ else if (use_raytrace_kernel) {
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
}
else {
- INTEGRATOR_PATH_NEXT_SORTED(
- current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
}
#ifdef __SHADOW_CATCHER__
@@ -238,13 +252,13 @@ ccl_device_forceinline void integrator_intersect_next_kernel(
#endif
}
else {
- INTEGRATOR_PATH_TERMINATE(current_kernel);
+ integrator_path_terminate(kg, state, current_kernel);
}
}
}
else {
/* Nothing hit, continue with background kernel. */
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ integrator_path_next(kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
}
}
@@ -252,7 +266,7 @@ ccl_device_forceinline void integrator_intersect_next_kernel(
*
* The logic here matches integrator_intersect_next_kernel, except that
* volume shading and termination testing have already been done. */
-template<uint32_t current_kernel>
+template<DeviceKernel current_kernel>
ccl_device_forceinline void integrator_intersect_next_kernel_after_volume(
KernelGlobals kg,
IntegratorState state,
@@ -262,25 +276,29 @@ ccl_device_forceinline void integrator_intersect_next_kernel_after_volume(
if (isect->prim != PRIM_NONE) {
/* Hit a surface, continue with light or surface kernel. */
if (isect->type & PRIMITIVE_LAMP) {
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
+ integrator_path_next(kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
return;
}
else {
/* Hit a surface, continue with surface kernel unless terminated. */
const int shader = intersection_get_shader(kg, isect);
- const int flags = kernel_tex_fetch(__shaders, shader).flags;
+ const int flags = kernel_data_fetch(shaders, shader).flags;
const int object_flags = intersection_get_object_flags(kg, isect);
const bool use_caustics = kernel_data.integrator.use_caustics &&
(object_flags & SD_OBJECT_CAUSTICS);
- const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE) || use_caustics;
+ const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
- if (use_raytrace_kernel) {
- INTEGRATOR_PATH_NEXT_SORTED(
- current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
+ if (use_caustics) {
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE, shader);
+ }
+ else if (use_raytrace_kernel) {
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
}
else {
- INTEGRATOR_PATH_NEXT_SORTED(
- current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
+ integrator_path_next_sorted(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
}
#ifdef __SHADOW_CATCHER__
@@ -292,7 +310,7 @@ ccl_device_forceinline void integrator_intersect_next_kernel_after_volume(
}
else {
/* Nothing hit, continue with background kernel. */
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ integrator_path_next(kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
return;
}
}
@@ -306,7 +324,7 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg,
/* Read ray from integrator state into local memory. */
Ray ray ccl_optional_struct_init;
integrator_state_read_ray(kg, state, &ray);
- kernel_assert(ray.t != 0.0f);
+ kernel_assert(ray.tmax != 0.0f);
const uint visibility = path_state_ray_visibility(state);
const int last_isect_prim = INTEGRATOR_STATE(state, isect, prim);
@@ -314,12 +332,12 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg,
/* Trick to use short AO rays to approximate indirect light at the end of the path. */
if (path_state_ao_bounce(kg, state)) {
- ray.t = kernel_data.integrator.ao_bounces_distance;
+ ray.tmax = kernel_data.integrator.ao_bounces_distance;
if (last_isect_object != OBJECT_NONE) {
- const float object_ao_distance = kernel_tex_fetch(__objects, last_isect_object).ao_distance;
+ const float object_ao_distance = kernel_data_fetch(objects, last_isect_object).ao_distance;
if (object_ao_distance != 0.0f) {
- ray.t = object_ao_distance;
+ ray.tmax = object_ao_distance;
}
}
}
@@ -351,7 +369,7 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg,
bool from_caustic_caster = false;
bool from_caustic_receiver = false;
if (!(path_flag & PATH_RAY_CAMERA) && last_isect_object != OBJECT_NONE) {
- const int object_flags = kernel_tex_fetch(__object_flag, last_isect_object);
+ const int object_flags = kernel_data_fetch(object_flag, last_isect_object);
from_caustic_receiver = (object_flags & SD_OBJECT_CAUSTICS_RECEIVER);
from_caustic_caster = (object_flags & SD_OBJECT_CAUSTICS_CASTER);
}
diff --git a/intern/cycles/kernel/integrator/intersect_shadow.h b/intern/cycles/kernel/integrator/intersect_shadow.h
index 3e746998225..1b48b360858 100644
--- a/intern/cycles/kernel/integrator/intersect_shadow.h
+++ b/intern/cycles/kernel/integrator/intersect_shadow.h
@@ -162,7 +162,7 @@ ccl_device void integrator_intersect_shadow(KernelGlobals kg, IntegratorShadowSt
if (opaque_hit) {
/* Hit an opaque surface, shadow path ends here. */
- INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
+ integrator_shadow_path_terminate(kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
return;
}
else {
@@ -171,7 +171,9 @@ ccl_device void integrator_intersect_shadow(KernelGlobals kg, IntegratorShadowSt
*
* TODO: could also write to render buffer directly if no transparent shadows?
* Could save a kernel execution for the common case. */
- INTEGRATOR_SHADOW_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW,
+ integrator_shadow_path_next(kg,
+ state,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW,
DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
return;
}
diff --git a/intern/cycles/kernel/integrator/intersect_subsurface.h b/intern/cycles/kernel/integrator/intersect_subsurface.h
index 0a2c4ad680d..f439d6905a0 100644
--- a/intern/cycles/kernel/integrator/intersect_subsurface.h
+++ b/intern/cycles/kernel/integrator/intersect_subsurface.h
@@ -17,7 +17,7 @@ ccl_device void integrator_intersect_subsurface(KernelGlobals kg, IntegratorStat
}
#endif
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
+ integrator_path_terminate(kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/intersect_volume_stack.h b/intern/cycles/kernel/integrator/intersect_volume_stack.h
index 49ef01dc870..9ba4a0a3964 100644
--- a/intern/cycles/kernel/integrator/intersect_volume_stack.h
+++ b/intern/cycles/kernel/integrator/intersect_volume_stack.h
@@ -24,7 +24,8 @@ ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg,
Ray volume_ray ccl_optional_struct_init;
volume_ray.P = from_P;
- volume_ray.D = normalize_len(to_P - from_P, &volume_ray.t);
+ volume_ray.D = normalize_len(to_P - from_P, &volume_ray.tmax);
+ volume_ray.tmin = 0.0f;
volume_ray.self.object = INTEGRATOR_STATE(state, isect, object);
volume_ray.self.prim = INTEGRATOR_STATE(state, isect, prim);
volume_ray.self.light_object = OBJECT_NONE;
@@ -58,12 +59,9 @@ ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg,
volume_stack_enter_exit(kg, state, stack_sd);
/* Move ray forward. */
- volume_ray.P = stack_sd->P;
+ volume_ray.tmin = intersection_t_offset(isect.t);
volume_ray.self.object = isect.object;
volume_ray.self.prim = isect.prim;
- if (volume_ray.t != FLT_MAX) {
- volume_ray.D = normalize_len(to_P - volume_ray.P, &volume_ray.t);
- }
++step;
}
#endif
@@ -82,7 +80,8 @@ ccl_device void integrator_volume_stack_init(KernelGlobals kg, IntegratorState s
/* Trace ray in random direction. Any direction works, Z up is a guess to get the
* fewest hits. */
volume_ray.D = make_float3(0.0f, 0.0f, 1.0f);
- volume_ray.t = FLT_MAX;
+ volume_ray.tmin = 0.0f;
+ volume_ray.tmax = FLT_MAX;
volume_ray.self.object = OBJECT_NONE;
volume_ray.self.prim = PRIM_NONE;
volume_ray.self.light_object = OBJECT_NONE;
@@ -199,7 +198,7 @@ ccl_device void integrator_volume_stack_init(KernelGlobals kg, IntegratorState s
}
/* Move ray forward. */
- volume_ray.P = stack_sd->P;
+ volume_ray.tmin = intersection_t_offset(isect.t);
volume_ray.self.object = isect.object;
volume_ray.self.prim = isect.prim;
++step;
@@ -222,7 +221,9 @@ ccl_device void integrator_intersect_volume_stack(KernelGlobals kg, IntegratorSt
}
else {
/* Volume stack init for camera rays, continue with intersection of camera ray. */
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK,
+ integrator_path_next(kg,
+ state,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK,
DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
}
}
diff --git a/intern/cycles/kernel/integrator/megakernel.h b/intern/cycles/kernel/integrator/megakernel.h
index a0c15794470..17ae13ad23f 100644
--- a/intern/cycles/kernel/integrator/megakernel.h
+++ b/intern/cycles/kernel/integrator/megakernel.h
@@ -77,6 +77,9 @@ ccl_device void integrator_megakernel(KernelGlobals kg,
case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE:
integrator_shade_surface_raytrace(kg, state, render_buffer);
break;
+ case DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE:
+ integrator_shade_surface_mnee(kg, state, render_buffer);
+ break;
case DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT:
integrator_shade_light(kg, state, render_buffer);
break;
diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h
index ad83f82d091..7a6f866b1a0 100644
--- a/intern/cycles/kernel/integrator/mnee.h
+++ b/intern/cycles/kernel/integrator/mnee.h
@@ -115,7 +115,7 @@ ccl_device_forceinline void mnee_update_light_sample(KernelGlobals kg,
{
/* correct light sample position/direction and pdf
* NOTE: preserve pdf in area measure */
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, ls->lamp);
+ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
if (ls->type == LIGHT_POINT || ls->type == LIGHT_SPOT) {
ls->D = normalize_len(ls->P - P, &ls->t);
@@ -137,8 +137,14 @@ ccl_device_forceinline void mnee_update_light_sample(KernelGlobals kg,
}
}
else if (ls->type == LIGHT_AREA) {
+ float invarea = fabsf(klight->area.invarea);
ls->D = normalize_len(ls->P - P, &ls->t);
- ls->pdf = fabsf(klight->area.invarea);
+ ls->pdf = invarea;
+ if (klight->area.tan_spread > 0.f) {
+ ls->eval_fac = 0.25f * invarea;
+ ls->eval_fac *= light_spread_attenuation(
+ ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread);
+ }
}
ls->pdf *= kernel_data.integrator.pdf_lights;
@@ -154,12 +160,12 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
ccl_private const Intersection *isect,
ccl_private ShaderData *sd_vtx)
{
- sd_vtx->object = (isect->object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, isect->prim) :
+ sd_vtx->object = (isect->object == OBJECT_NONE) ? kernel_data_fetch(prim_object, isect->prim) :
isect->object;
sd_vtx->type = isect->type;
sd_vtx->flag = 0;
- sd_vtx->object_flag = kernel_tex_fetch(__object_flag, sd_vtx->object);
+ sd_vtx->object_flag = kernel_data_fetch(object_flag, sd_vtx->object);
/* Matrices and time. */
shader_setup_object_transforms(kg, sd_vtx, ray->time);
@@ -171,7 +177,7 @@ ccl_device_forceinline void mnee_setup_manifold_vertex(KernelGlobals kg,
sd_vtx->u = isect->u;
sd_vtx->v = isect->v;
- sd_vtx->shader = kernel_tex_fetch(__tri_shader, sd_vtx->prim);
+ sd_vtx->shader = kernel_data_fetch(tri_shader, sd_vtx->prim);
float3 verts[3];
float3 normals[3];
@@ -436,6 +442,7 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg,
projection_ray.self.light_prim = PRIM_NONE;
projection_ray.dP = differential_make_compact(sd->dP);
projection_ray.dD = differential_zero_compact();
+ projection_ray.tmin = 0.0f;
projection_ray.time = sd->time;
Intersection projection_isect;
@@ -499,8 +506,8 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg,
projection_ray.self.prim = pv.prim;
projection_ray.P = pv.p;
}
- projection_ray.D = normalize_len(tentative_p - projection_ray.P, &projection_ray.t);
- projection_ray.t *= MNEE_PROJECTION_DISTANCE_MULTIPLIER;
+ projection_ray.D = normalize_len(tentative_p - projection_ray.P, &projection_ray.tmax);
+ projection_ray.tmax *= MNEE_PROJECTION_DISTANCE_MULTIPLIER;
bool projection_success = false;
for (int isect_count = 0; isect_count < MNEE_MAX_INTERSECTION_COUNT; isect_count++) {
@@ -509,7 +516,7 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg,
break;
int hit_object = (projection_isect.object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, projection_isect.prim) :
+ kernel_data_fetch(prim_object, projection_isect.prim) :
projection_isect.object;
if (hit_object == mv.object) {
@@ -519,8 +526,7 @@ ccl_device_forceinline bool mnee_newton_solver(KernelGlobals kg,
projection_ray.self.object = projection_isect.object;
projection_ray.self.prim = projection_isect.prim;
- projection_ray.P += projection_isect.t * projection_ray.D;
- projection_ray.t -= projection_isect.t;
+ projection_ray.tmin = intersection_t_offset(projection_isect.t);
}
if (!projection_success) {
reduce_stepsize = true;
@@ -830,7 +836,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
INTEGRATOR_STATE_WRITE(state, path, bounce) = bounce + vertex_count;
float3 light_eval = light_sample_shader_eval(kg, state, sd_mnee, ls, sd->time);
- bsdf_eval_mul3(throughput, light_eval / ls->pdf);
+ bsdf_eval_mul(throughput, light_eval / ls->pdf);
/* Generalized geometry term. */
@@ -852,6 +858,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
Ray probe_ray;
probe_ray.self.light_object = ls->object;
probe_ray.self.light_prim = ls->prim;
+ probe_ray.tmin = 0.0f;
probe_ray.dP = differential_make_compact(sd->dP);
probe_ray.dD = differential_zero_compact();
probe_ray.time = sd->time;
@@ -867,13 +874,13 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
ccl_private const ManifoldVertex &v = vertices[vi];
/* Check visibility. */
- probe_ray.D = normalize_len(v.p - probe_ray.P, &probe_ray.t);
+ probe_ray.D = normalize_len(v.p - probe_ray.P, &probe_ray.tmax);
if (scene_intersect(kg, &probe_ray, PATH_RAY_TRANSMIT, &probe_isect)) {
int hit_object = (probe_isect.object == OBJECT_NONE) ?
- kernel_tex_fetch(__prim_object, probe_isect.prim) :
+ kernel_data_fetch(prim_object, probe_isect.prim) :
probe_isect.object;
/* Test whether the ray hit the appropriate object at its intended location. */
- if (hit_object != v.object || fabsf(probe_ray.t - probe_isect.t) > MNEE_MIN_DISTANCE)
+ if (hit_object != v.object || fabsf(probe_ray.tmax - probe_isect.t) > MNEE_MIN_DISTANCE)
return false;
}
probe_ray.self.object = v.object;
@@ -918,7 +925,7 @@ ccl_device_forceinline bool mnee_path_contribution(KernelGlobals kg,
* divided by corresponding sampled pdf:
* fr(vi)_do / pdf_dh(vi) x |do/dh| x |n.wo / n.h| */
float3 bsdf_contribution = mnee_eval_bsdf_contribution(v.bsdf, wi, wo);
- bsdf_eval_mul3(throughput, bsdf_contribution);
+ bsdf_eval_mul(throughput, bsdf_contribution);
}
/* Restore original state path bounce info. */
@@ -952,15 +959,16 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
probe_ray.self.light_object = ls->object;
probe_ray.self.light_prim = ls->prim;
probe_ray.P = sd->P;
+ probe_ray.tmin = 0.0f;
if (ls->t == FLT_MAX) {
/* Distant / env light. */
probe_ray.D = ls->D;
- probe_ray.t = ls->t;
+ probe_ray.tmax = ls->t;
}
else {
/* Other lights, avoid self-intersection. */
probe_ray.D = ls->P - probe_ray.P;
- probe_ray.D = normalize_len(probe_ray.D, &probe_ray.t);
+ probe_ray.D = normalize_len(probe_ray.D, &probe_ray.tmax);
}
probe_ray.dP = differential_make_compact(sd->dP);
probe_ray.dD = differential_zero_compact();
@@ -1042,9 +1050,7 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
probe_ray.self.object = probe_isect.object;
probe_ray.self.prim = probe_isect.prim;
- probe_ray.P += probe_isect.t * probe_ray.D;
- if (ls->t != FLT_MAX)
- probe_ray.t -= probe_isect.t;
+ probe_ray.tmin = intersection_t_offset(probe_isect.t);
};
/* Mark the manifold walk invalid to keep mollification on by default. */
diff --git a/intern/cycles/kernel/integrator/path_state.h b/intern/cycles/kernel/integrator/path_state.h
index ec93ac6d46f..912c380cdb6 100644
--- a/intern/cycles/kernel/integrator/path_state.h
+++ b/intern/cycles/kernel/integrator/path_state.h
@@ -52,7 +52,6 @@ ccl_device_inline void path_state_init_integrator(KernelGlobals kg,
INTEGRATOR_STATE_WRITE(state, path, flag) = PATH_RAY_CAMERA | PATH_RAY_MIS_SKIP |
PATH_RAY_TRANSPARENT_BACKGROUND;
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = 0.0f;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = FLT_MAX;
INTEGRATOR_STATE_WRITE(state, path, continuation_probability) = 1.0f;
INTEGRATOR_STATE_WRITE(state, path, throughput) = make_float3(1.0f, 1.0f, 1.0f);
@@ -250,7 +249,7 @@ ccl_device_inline float path_state_continuation_probability(KernelGlobals kg,
/* Probabilistic termination: use sqrt() to roughly match typical view
* transform and do path termination a bit later on average. */
- return min(sqrtf(max3(fabs(INTEGRATOR_STATE(state, path, throughput)))), 1.0f);
+ return min(sqrtf(reduce_max(fabs(INTEGRATOR_STATE(state, path, throughput)))), 1.0f);
}
ccl_device_inline bool path_state_ao_bounce(KernelGlobals kg, ConstIntegratorState state)
diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h
index 62b3ce1c15c..a7edfffd175 100644
--- a/intern/cycles/kernel/integrator/shade_background.h
+++ b/intern/cycles/kernel/integrator/shade_background.h
@@ -48,7 +48,7 @@ ccl_device float3 integrator_eval_background_shader(KernelGlobals kg,
PROFILING_SHADER(emission_sd->object, emission_sd->shader);
PROFILING_EVENT(PROFILING_SHADE_LIGHT_EVAL);
- shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT>(
+ shader_eval_surface<KERNEL_FEATURE_NODE_MASK_SURFACE_BACKGROUND>(
kg, state, emission_sd, render_buffer, path_flag | PATH_RAY_EMISSION);
L = shader_background_eval(emission_sd);
@@ -62,11 +62,10 @@ ccl_device float3 integrator_eval_background_shader(KernelGlobals kg,
const float3 ray_P = INTEGRATOR_STATE(state, ray, P);
const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
- const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
/* multiple importance sampling, get background light pdf for ray
* direction, and compute weight with respect to BSDF pdf */
- const float pdf = background_light_pdf(kg, ray_P - ray_D * mis_ray_t, ray_D);
+ const float pdf = background_light_pdf(kg, ray_P, ray_D);
const float mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, pdf);
L *= mis_weight;
}
@@ -107,7 +106,7 @@ ccl_device_inline void integrate_background(KernelGlobals kg,
for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
/* This path should have been resolved with mnee, it will
* generate a firefly for small lights since it is improbable. */
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
if (klight->type == LIGHT_BACKGROUND && klight->use_caustics) {
eval_background = false;
break;
@@ -160,7 +159,7 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg,
if (INTEGRATOR_STATE(state, path, mnee) & PATH_MNEE_CULL_LIGHT_CONNECTION) {
/* This path should have been resolved with mnee, it will
* generate a firefly for small lights since it is improbable. */
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
if (klight->use_caustics)
return;
}
@@ -213,7 +212,7 @@ ccl_device void integrator_shade_background(KernelGlobals kg,
}
#endif
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
+ integrator_path_terminate(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shade_light.h b/intern/cycles/kernel/integrator/shade_light.h
index be926c78439..910e3383f51 100644
--- a/intern/cycles/kernel/integrator/shade_light.h
+++ b/intern/cycles/kernel/integrator/shade_light.h
@@ -22,19 +22,8 @@ ccl_device_inline void integrate_light(KernelGlobals kg,
const float3 ray_D = INTEGRATOR_STATE(state, ray, D);
const float ray_time = INTEGRATOR_STATE(state, ray, time);
- /* Advance ray beyond light. */
- /* TODO: can we make this more numerically robust to avoid reintersecting the
- * same light in some cases? Ray should not intersect surface anymore as the
- * object and prim ids will prevent self intersection. */
- const float3 new_ray_P = ray_P + ray_D * isect.t;
- INTEGRATOR_STATE_WRITE(state, ray, P) = new_ray_P;
- INTEGRATOR_STATE_WRITE(state, ray, t) -= isect.t;
-
- /* Set position to where the BSDF was sampled, for correct MIS PDF. */
- const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
- ray_P -= ray_D * mis_ray_t;
- isect.t += mis_ray_t;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = isect.t;
+ /* Advance ray to new start distance. */
+ INTEGRATOR_STATE_WRITE(state, ray, tmin) = intersection_t_offset(isect.t);
LightSample ls ccl_optional_struct_init;
const bool use_light_sample = light_sample_from_intersection(kg, &isect, ray_P, ray_D, &ls);
@@ -99,11 +88,13 @@ ccl_device void integrator_shade_light(KernelGlobals kg,
INTEGRATOR_STATE_WRITE(state, path, transparent_bounce) = transparent_bounce;
if (transparent_bounce >= kernel_data.integrator.transparent_max_bounce) {
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
+ integrator_path_terminate(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT);
return;
}
else {
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT,
+ integrator_path_next(kg,
+ state,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT,
DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
return;
}
diff --git a/intern/cycles/kernel/integrator/shade_shadow.h b/intern/cycles/kernel/integrator/shade_shadow.h
index 2b929b7b62e..4b002a47bee 100644
--- a/intern/cycles/kernel/integrator/shade_shadow.h
+++ b/intern/cycles/kernel/integrator/shade_shadow.h
@@ -75,13 +75,9 @@ ccl_device_inline void integrate_transparent_volume_shadow(KernelGlobals kg,
ray.self.light_object = OBJECT_NONE;
ray.self.light_prim = PRIM_NONE;
/* Modify ray position and length to match current segment. */
- const float start_t = (hit == 0) ? 0.0f :
- INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit - 1, t);
- const float end_t = (hit < num_recorded_hits) ?
- INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit, t) :
- ray.t;
- ray.P += start_t * ray.D;
- ray.t = end_t - start_t;
+ ray.tmin = (hit == 0) ? ray.tmin : INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit - 1, t);
+ ray.tmax = (hit < num_recorded_hits) ? INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit, t) :
+ ray.tmax;
shader_setup_from_volume(kg, shadow_sd, &ray);
@@ -137,10 +133,7 @@ ccl_device_inline bool integrate_transparent_shadow(KernelGlobals kg,
/* There are more hits that we could not recorded due to memory usage,
* adjust ray to intersect again from the last hit. */
const float last_hit_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, num_recorded_hits - 1, t);
- const float3 ray_P = INTEGRATOR_STATE(state, shadow_ray, P);
- const float3 ray_D = INTEGRATOR_STATE(state, shadow_ray, D);
- INTEGRATOR_STATE_WRITE(state, shadow_ray, P) = ray_P + last_hit_t * ray_D;
- INTEGRATOR_STATE_WRITE(state, shadow_ray, t) -= last_hit_t;
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, tmin) = intersection_t_offset(last_hit_t);
}
return false;
@@ -158,20 +151,22 @@ ccl_device void integrator_shade_shadow(KernelGlobals kg,
/* Evaluate transparent shadows. */
const bool opaque = integrate_transparent_shadow(kg, state, num_hits);
if (opaque) {
- INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
+ integrator_shadow_path_terminate(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
return;
}
#endif
if (shadow_intersections_has_remaining(num_hits)) {
/* More intersections to find, continue shadow ray. */
- INTEGRATOR_SHADOW_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW,
+ integrator_shadow_path_next(kg,
+ state,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW,
DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW);
return;
}
else {
kernel_accum_light(kg, state, render_buffer);
- INTEGRATOR_SHADOW_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
+ integrator_shadow_path_terminate(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW);
return;
}
}
diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h
index 896e81b80ff..1514b3956ad 100644
--- a/intern/cycles/kernel/integrator/shade_surface.h
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -48,7 +48,7 @@ ccl_device_forceinline bool integrate_surface_holdout(KernelGlobals kg,
const float transparent = average(holdout_weight * throughput);
kernel_accum_holdout(kg, state, path_flag, transparent, render_buffer);
}
- if (isequal_float3(holdout_weight, one_float3())) {
+ if (isequal(holdout_weight, one_float3())) {
return false;
}
}
@@ -77,7 +77,7 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
# endif
{
const float bsdf_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf);
- const float t = sd->ray_length + INTEGRATOR_STATE(state, path, mis_ray_t);
+ const float t = sd->ray_length;
/* Multiple importance sampling, get triangle light pdf,
* and compute weight with respect to BSDF pdf. */
@@ -137,11 +137,11 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
# ifdef __MNEE__
int mnee_vertex_count = 0;
- IF_KERNEL_NODES_FEATURE(RAYTRACE)
+ IF_KERNEL_FEATURE(MNEE)
{
if (ls.lamp != LAMP_NONE) {
/* Is this a caustic light? */
- const bool use_caustics = kernel_tex_fetch(__lights, ls.lamp).use_caustics;
+ const bool use_caustics = kernel_data_fetch(lights, ls.lamp).use_caustics;
if (use_caustics) {
/* Are we on a caustic caster? */
if (is_transmission && (sd->object_flag & SD_OBJECT_CAUSTICS_CASTER))
@@ -170,7 +170,7 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
/* Evaluate BSDF. */
const float bsdf_pdf = shader_bsdf_eval(kg, sd, ls.D, is_transmission, &bsdf_eval, ls.shader);
- bsdf_eval_mul3(&bsdf_eval, light_eval / ls.pdf);
+ bsdf_eval_mul(&bsdf_eval, light_eval / ls.pdf);
if (ls.shader & SHADER_USE_MIS) {
const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, bsdf_pdf);
@@ -190,8 +190,8 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg,
const bool is_light = light_sample_is_light(&ls);
/* Branch off shadow kernel. */
- INTEGRATOR_SHADOW_PATH_INIT(
- shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, shadow);
+ IntegratorShadowState shadow_state = integrator_shadow_path_init(
+ kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, false);
/* Copy volume stack and enter/exit volume. */
integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
@@ -323,16 +323,21 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
return LABEL_NONE;
}
- /* Setup ray. Note that clipping works through transparent bounces. */
- INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
- INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(bsdf_omega_in);
- INTEGRATOR_STATE_WRITE(state, ray, t) = (label & LABEL_TRANSPARENT) ?
- INTEGRATOR_STATE(state, ray, t) - sd->ray_length :
- FLT_MAX;
+ if (label & LABEL_TRANSPARENT) {
+ /* Only need to modify start distance for transparent. */
+ INTEGRATOR_STATE_WRITE(state, ray, tmin) = intersection_t_offset(sd->ray_length);
+ }
+ else {
+ /* Setup ray with changed origin and direction. */
+ INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
+ INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(bsdf_omega_in);
+ INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
+ INTEGRATOR_STATE_WRITE(state, ray, tmax) = FLT_MAX;
#ifdef __RAY_DIFFERENTIALS__
- INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
- INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(bsdf_domega_in);
+ INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
+ INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(bsdf_domega_in);
#endif
+ }
/* Update throughput. */
float3 throughput = INTEGRATOR_STATE(state, path, throughput);
@@ -349,12 +354,8 @@ ccl_device_forceinline int integrate_surface_bsdf_bssrdf_bounce(
}
/* Update path state */
- if (label & LABEL_TRANSPARENT) {
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) += sd->ray_length;
- }
- else {
+ if (!(label & LABEL_TRANSPARENT)) {
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = bsdf_pdf;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
bsdf_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
}
@@ -371,17 +372,8 @@ ccl_device_forceinline int integrate_surface_volume_only_bounce(IntegratorState
return LABEL_NONE;
}
- /* Setup ray position, direction stays unchanged. */
- INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
-
- /* Clipping works through transparent. */
- INTEGRATOR_STATE_WRITE(state, ray, t) -= sd->ray_length;
-
-# ifdef __RAY_DIFFERENTIALS__
- INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
-# endif
-
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) += sd->ray_length;
+ /* Only modify start distance. */
+ INTEGRATOR_STATE_WRITE(state, ray, tmin) = intersection_t_offset(sd->ray_length);
return LABEL_TRANSMIT | LABEL_TRANSPARENT;
}
@@ -432,7 +424,8 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
Ray ray ccl_optional_struct_init;
ray.P = shadow_ray_offset(kg, sd, ao_D, &skip_self);
ray.D = ao_D;
- ray.t = kernel_data.integrator.ao_bounces_distance;
+ ray.tmin = 0.0f;
+ ray.tmax = kernel_data.integrator.ao_bounces_distance;
ray.time = sd->time;
ray.self.object = (skip_self) ? sd->object : OBJECT_NONE;
ray.self.prim = (skip_self) ? sd->prim : PRIM_NONE;
@@ -442,7 +435,8 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
ray.dD = differential_zero_compact();
/* Branch off shadow kernel. */
- INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, ao);
+ IntegratorShadowState shadow_state = integrator_shadow_path_init(
+ kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, true);
/* Copy volume stack and enter/exit volume. */
integrator_state_copy_volume_stack_to_shadow(kg, shadow_state, state);
@@ -604,22 +598,23 @@ ccl_device bool integrate_surface(KernelGlobals kg,
}
template<uint node_feature_mask = KERNEL_FEATURE_NODE_MASK_SURFACE & ~KERNEL_FEATURE_NODE_RAYTRACE,
- int current_kernel = DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE>
+ DeviceKernel current_kernel = DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE>
ccl_device_forceinline void integrator_shade_surface(KernelGlobals kg,
IntegratorState state,
ccl_global float *ccl_restrict render_buffer)
{
if (integrate_surface<node_feature_mask>(kg, state, render_buffer)) {
if (INTEGRATOR_STATE(state, path, flag) & PATH_RAY_SUBSURFACE) {
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
+ integrator_path_next(
+ kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE);
}
else {
- kernel_assert(INTEGRATOR_STATE(state, ray, t) != 0.0f);
- INTEGRATOR_PATH_NEXT(current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
+ kernel_assert(INTEGRATOR_STATE(state, ray, tmax) != 0.0f);
+ integrator_path_next(kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
}
}
else {
- INTEGRATOR_PATH_TERMINATE(current_kernel);
+ integrator_path_terminate(kg, state, current_kernel);
}
}
@@ -631,4 +626,12 @@ ccl_device_forceinline void integrator_shade_surface_raytrace(
kg, state, render_buffer);
}
+ccl_device_forceinline void integrator_shade_surface_mnee(
+ KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
+{
+ integrator_shade_surface<(KERNEL_FEATURE_NODE_MASK_SURFACE & ~KERNEL_FEATURE_NODE_RAYTRACE) |
+ KERNEL_FEATURE_MNEE,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE>(kg, state, render_buffer);
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h
index 4a5015946aa..4aab097a7d8 100644
--- a/intern/cycles/kernel/integrator/shade_volume.h
+++ b/intern/cycles/kernel/integrator/shade_volume.h
@@ -114,7 +114,8 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals kg,
ccl_device_forceinline void volume_step_init(KernelGlobals kg,
ccl_private const RNGState *rng_state,
const float object_step_size,
- float t,
+ const float tmin,
+ const float tmax,
ccl_private float *step_size,
ccl_private float *step_shade_offset,
ccl_private float *steps_offset,
@@ -122,7 +123,7 @@ ccl_device_forceinline void volume_step_init(KernelGlobals kg,
{
if (object_step_size == FLT_MAX) {
/* Homogeneous volume. */
- *step_size = t;
+ *step_size = tmax - tmin;
*step_shade_offset = 0.0f;
*steps_offset = 1.0f;
*max_steps = 1;
@@ -130,6 +131,7 @@ ccl_device_forceinline void volume_step_init(KernelGlobals kg,
else {
/* Heterogeneous volume. */
*max_steps = kernel_data.integrator.volume_max_steps;
+ const float t = tmax - tmin;
float step = min(object_step_size, t);
/* compute exact steps in advance for malloc */
@@ -165,7 +167,7 @@ ccl_device void volume_shadow_homogeneous(KernelGlobals kg, IntegratorState stat
float3 sigma_t = zero_float3();
if (shadow_volume_shader_sample(kg, state, sd, &sigma_t)) {
- *throughput *= volume_color_transmittance(sigma_t, ray->t);
+ *throughput *= volume_color_transmittance(sigma_t, ray->tmax - ray->tmin);
}
}
# endif
@@ -194,7 +196,8 @@ ccl_device void volume_shadow_heterogeneous(KernelGlobals kg,
volume_step_init(kg,
&rng_state,
object_step_size,
- ray->t,
+ ray->tmin,
+ ray->tmax,
&step_size,
&step_shade_offset,
&unused,
@@ -202,13 +205,13 @@ ccl_device void volume_shadow_heterogeneous(KernelGlobals kg,
const float steps_offset = 1.0f;
/* compute extinction at the start */
- float t = 0.0f;
+ float t = ray->tmin;
float3 sum = zero_float3();
for (int i = 0; i < max_steps; i++) {
/* advance to new position */
- float new_t = min(ray->t, (i + steps_offset) * step_size);
+ float new_t = min(ray->tmax, ray->tmin + (i + steps_offset) * step_size);
float dt = new_t - t;
float3 new_P = ray->P + ray->D * (t + dt * step_shade_offset);
@@ -222,7 +225,7 @@ ccl_device void volume_shadow_heterogeneous(KernelGlobals kg,
* check then. */
sum += (-sigma_t * dt);
if ((i & 0x07) == 0) { /* TODO: Other interval? */
- tp = *throughput * exp3(sum);
+ tp = *throughput * exp(sum);
/* stop if nearly all light is blocked */
if (tp.x < VOLUME_THROUGHPUT_EPSILON && tp.y < VOLUME_THROUGHPUT_EPSILON &&
@@ -233,9 +236,9 @@ ccl_device void volume_shadow_heterogeneous(KernelGlobals kg,
/* stop if at the end of the volume */
t = new_t;
- if (t == ray->t) {
+ if (t == ray->tmax) {
/* Update throughput in case we haven't done it above */
- tp = *throughput * exp3(sum);
+ tp = *throughput * exp(sum);
break;
}
}
@@ -257,15 +260,16 @@ ccl_device float volume_equiangular_sample(ccl_private const Ray *ccl_restrict r
const float xi,
ccl_private float *pdf)
{
- const float t = ray->t;
+ const float tmin = ray->tmin;
+ const float tmax = ray->tmax;
const float delta = dot((light_P - ray->P), ray->D);
const float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta);
if (UNLIKELY(D == 0.0f)) {
*pdf = 0.0f;
return 0.0f;
}
- const float theta_a = -atan2f(delta, D);
- const float theta_b = atan2f(t - delta, D);
+ const float theta_a = atan2f(tmin - delta, D);
+ const float theta_b = atan2f(tmax - delta, D);
const float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a);
if (UNLIKELY(theta_b == theta_a)) {
*pdf = 0.0f;
@@ -273,7 +277,7 @@ ccl_device float volume_equiangular_sample(ccl_private const Ray *ccl_restrict r
}
*pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_));
- return min(t, delta + t_); /* min is only for float precision errors */
+ return clamp(delta + t_, tmin, tmax); /* clamp is only for float precision errors */
}
ccl_device float volume_equiangular_pdf(ccl_private const Ray *ccl_restrict ray,
@@ -286,11 +290,12 @@ ccl_device float volume_equiangular_pdf(ccl_private const Ray *ccl_restrict ray,
return 0.0f;
}
- const float t = ray->t;
+ const float tmin = ray->tmin;
+ const float tmax = ray->tmax;
const float t_ = sample_t - delta;
- const float theta_a = -atan2f(delta, D);
- const float theta_b = atan2f(t - delta, D);
+ const float theta_a = atan2f(tmin - delta, D);
+ const float theta_b = atan2f(tmax - delta, D);
if (UNLIKELY(theta_b == theta_a)) {
return 0.0f;
}
@@ -310,11 +315,12 @@ ccl_device float volume_equiangular_cdf(ccl_private const Ray *ccl_restrict ray,
return 0.0f;
}
- const float t = ray->t;
+ const float tmin = ray->tmin;
+ const float tmax = ray->tmax;
const float t_ = sample_t - delta;
- const float theta_a = -atan2f(delta, D);
- const float theta_b = atan2f(t - delta, D);
+ const float theta_a = atan2f(tmin - delta, D);
+ const float theta_b = atan2f(tmax - delta, D);
if (UNLIKELY(theta_b == theta_a)) {
return 0.0f;
}
@@ -390,8 +396,8 @@ ccl_device float3 volume_emission_integrate(ccl_private VolumeShaderCoefficients
typedef struct VolumeIntegrateState {
/* Volume segment extents. */
- float start_t;
- float end_t;
+ float tmin;
+ float tmax;
/* If volume is absorption-only up to this point, and no probabilistic
* scattering or termination has been used yet. */
@@ -426,9 +432,9 @@ ccl_device_forceinline void volume_integrate_step_scattering(
/* Equiangular sampling for direct lighting. */
if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !result.direct_scatter) {
- if (result.direct_t >= vstate.start_t && result.direct_t <= vstate.end_t &&
+ if (result.direct_t >= vstate.tmin && result.direct_t <= vstate.tmax &&
vstate.equiangular_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
- const float new_dt = result.direct_t - vstate.start_t;
+ const float new_dt = result.direct_t - vstate.tmin;
const float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
result.direct_scatter = true;
@@ -458,7 +464,7 @@ ccl_device_forceinline void volume_integrate_step_scattering(
/* compute sampling distance */
const float sample_sigma_t = volume_channel_get(coeff.sigma_t, channel);
const float new_dt = -logf(1.0f - vstate.rscatter) / sample_sigma_t;
- const float new_t = vstate.start_t + new_dt;
+ const float new_t = vstate.tmin + new_dt;
/* transmittance and pdf */
const float3 new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
@@ -528,7 +534,8 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
volume_step_init(kg,
rng_state,
object_step_size,
- ray->t,
+ ray->tmin,
+ ray->tmax,
&step_size,
&step_shade_offset,
&steps_offset,
@@ -536,8 +543,8 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
/* Initialize volume integration state. */
VolumeIntegrateState vstate ccl_optional_struct_init;
- vstate.start_t = 0.0f;
- vstate.end_t = 0.0f;
+ vstate.tmin = ray->tmin;
+ vstate.tmax = ray->tmin;
vstate.absorption_only = true;
vstate.rscatter = path_state_rng_1D(kg, rng_state, PRNG_SCATTER_DISTANCE);
vstate.rphase = path_state_rng_1D(kg, rng_state, PRNG_PHASE_CHANNEL);
@@ -578,8 +585,8 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
for (int i = 0; i < max_steps; i++) {
/* Advance to new position */
- vstate.end_t = min(ray->t, (i + steps_offset) * step_size);
- const float shade_t = vstate.start_t + (vstate.end_t - vstate.start_t) * step_shade_offset;
+ vstate.tmax = min(ray->tmax, ray->tmin + (i + steps_offset) * step_size);
+ const float shade_t = vstate.tmin + (vstate.tmax - vstate.tmin) * step_shade_offset;
sd->P = ray->P + ray->D * shade_t;
/* compute segment */
@@ -588,7 +595,7 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
const int closure_flag = sd->flag;
/* Evaluate transmittance over segment. */
- const float dt = (vstate.end_t - vstate.start_t);
+ const float dt = (vstate.tmax - vstate.tmin);
const float3 transmittance = (closure_flag & SD_EXTINCTION) ?
volume_color_transmittance(coeff.sigma_t, dt) :
one_float3();
@@ -626,13 +633,13 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
/* Stop if nearly all light blocked. */
if (!result.indirect_scatter) {
- if (max3(result.indirect_throughput) < VOLUME_THROUGHPUT_EPSILON) {
+ if (reduce_max(result.indirect_throughput) < VOLUME_THROUGHPUT_EPSILON) {
result.indirect_throughput = zero_float3();
break;
}
}
else if (!result.direct_scatter) {
- if (max3(result.direct_throughput) < VOLUME_THROUGHPUT_EPSILON) {
+ if (reduce_max(result.direct_throughput) < VOLUME_THROUGHPUT_EPSILON) {
break;
}
}
@@ -645,8 +652,8 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
}
/* Stop if at the end of the volume. */
- vstate.start_t = vstate.end_t;
- if (vstate.start_t == ray->t) {
+ vstate.tmin = vstate.tmax;
+ if (vstate.tmin == ray->tmax) {
break;
}
}
@@ -760,7 +767,7 @@ ccl_device_forceinline void integrate_volume_direct_light(
bsdf_eval_mul(&phase_eval, mis_weight);
}
- bsdf_eval_mul3(&phase_eval, light_eval / ls->pdf);
+ bsdf_eval_mul(&phase_eval, light_eval / ls->pdf);
/* Path termination. */
const float terminate = path_state_rng_light_termination(kg, rng_state);
@@ -774,8 +781,8 @@ ccl_device_forceinline void integrate_volume_direct_light(
const bool is_light = light_sample_is_light(ls);
/* Branch off shadow kernel. */
- INTEGRATOR_SHADOW_PATH_INIT(
- shadow_state, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, shadow);
+ IntegratorShadowState shadow_state = integrator_shadow_path_init(
+ kg, state, DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW, false);
/* Write shadow ray and associated state to global memory. */
integrator_state_write_shadow_ray(kg, shadow_state, &ray);
@@ -880,7 +887,8 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
/* Setup ray. */
INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
INTEGRATOR_STATE_WRITE(state, ray, D) = normalize(phase_omega_in);
- INTEGRATOR_STATE_WRITE(state, ray, t) = FLT_MAX;
+ INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
+ INTEGRATOR_STATE_WRITE(state, ray, tmax) = FLT_MAX;
# ifdef __RAY_DIFFERENTIALS__
INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(phase_domega_in);
@@ -901,7 +909,6 @@ ccl_device_forceinline bool integrate_volume_phase_scatter(
/* Update path state */
INTEGRATOR_STATE_WRITE(state, path, mis_ray_pdf) = phase_pdf;
- INTEGRATOR_STATE_WRITE(state, path, mis_ray_t) = 0.0f;
INTEGRATOR_STATE_WRITE(state, path, min_ray_pdf) = fminf(
phase_pdf, INTEGRATOR_STATE(state, path, min_ray_pdf));
@@ -1021,7 +1028,7 @@ ccl_device void integrator_shade_volume(KernelGlobals kg,
integrator_state_read_isect(kg, state, &isect);
/* Set ray length to current segment. */
- ray.t = (isect.prim != PRIM_NONE) ? isect.t : FLT_MAX;
+ ray.tmax = (isect.prim != PRIM_NONE) ? isect.t : FLT_MAX;
/* Clean volume stack for background rays. */
if (isect.prim == PRIM_NONE) {
@@ -1032,13 +1039,15 @@ ccl_device void integrator_shade_volume(KernelGlobals kg,
if (event == VOLUME_PATH_SCATTERED) {
/* Queue intersect_closest kernel. */
- INTEGRATOR_PATH_NEXT(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
+ integrator_path_next(kg,
+ state,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST);
return;
}
else if (event == VOLUME_PATH_MISSED) {
/* End path. */
- INTEGRATOR_PATH_TERMINATE(DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
+ integrator_path_terminate(kg, state, DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME);
return;
}
else {
diff --git a/intern/cycles/kernel/integrator/shader_eval.h b/intern/cycles/kernel/integrator/shader_eval.h
index 4da92929366..ed4d973e864 100644
--- a/intern/cycles/kernel/integrator/shader_eval.h
+++ b/intern/cycles/kernel/integrator/shader_eval.h
@@ -528,12 +528,12 @@ ccl_device bool shader_constant_emission_eval(KernelGlobals kg,
ccl_private float3 *eval)
{
int shader_index = shader & SHADER_MASK;
- int shader_flag = kernel_tex_fetch(__shaders, shader_index).flags;
+ int shader_flag = kernel_data_fetch(shaders, shader_index).flags;
if (shader_flag & SD_HAS_CONSTANT_EMISSION) {
- *eval = make_float3(kernel_tex_fetch(__shaders, shader_index).constant_emission[0],
- kernel_tex_fetch(__shaders, shader_index).constant_emission[1],
- kernel_tex_fetch(__shaders, shader_index).constant_emission[2]);
+ *eval = make_float3(kernel_data_fetch(shaders, shader_index).constant_emission[0],
+ kernel_data_fetch(shaders, shader_index).constant_emission[1],
+ kernel_data_fetch(shaders, shader_index).constant_emission[2]);
return true;
}
@@ -821,11 +821,11 @@ ccl_device_inline void shader_eval_volume(KernelGlobals kg,
sd->shader = entry.shader;
sd->flag &= ~SD_SHADER_FLAGS;
- sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ sd->flag |= kernel_data_fetch(shaders, (sd->shader & SHADER_MASK)).flags;
sd->object_flag &= ~SD_OBJECT_FLAGS;
if (sd->object != OBJECT_NONE) {
- sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object);
+ sd->object_flag |= kernel_data_fetch(object_flag, sd->object);
# ifdef __OBJECT_MOTION__
/* todo: this is inefficient for motion blur, we should be
@@ -837,7 +837,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals kg,
kernel_assert(v_desc.offset != ATTR_STD_NOT_FOUND);
const float3 P = sd->P;
- const float velocity_scale = kernel_tex_fetch(__objects, sd->object).velocity_scale;
+ const float velocity_scale = kernel_data_fetch(objects, sd->object).velocity_scale;
const float time_offset = kernel_data.cam.motion_position == MOTION_POSITION_CENTER ?
0.5f :
0.0f;
@@ -946,7 +946,7 @@ ccl_device void shader_eval_displacement(KernelGlobals kg,
ccl_device float shader_cryptomatte_id(KernelGlobals kg, int shader)
{
- return kernel_tex_fetch(__shaders, (shader & SHADER_MASK)).cryptomatte_id;
+ return kernel_data_fetch(shaders, (shader & SHADER_MASK)).cryptomatte_id;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/integrator/shadow_catcher.h b/intern/cycles/kernel/integrator/shadow_catcher.h
index 42d44580f80..ff63625aceb 100644
--- a/intern/cycles/kernel/integrator/shadow_catcher.h
+++ b/intern/cycles/kernel/integrator/shadow_catcher.h
@@ -50,7 +50,7 @@ ccl_device_inline bool kernel_shadow_catcher_is_path_split_bounce(KernelGlobals
ccl_device_inline bool kernel_shadow_catcher_path_can_split(KernelGlobals kg,
ConstIntegratorState state)
{
- if (INTEGRATOR_PATH_IS_TERMINATED) {
+ if (integrator_path_is_terminated(state)) {
return false;
}
diff --git a/intern/cycles/kernel/integrator/shadow_state_template.h b/intern/cycles/kernel/integrator/shadow_state_template.h
index eaee65ada40..c340467606d 100644
--- a/intern/cycles/kernel/integrator/shadow_state_template.h
+++ b/intern/cycles/kernel/integrator/shadow_state_template.h
@@ -47,7 +47,8 @@ KERNEL_STRUCT_END(shadow_path)
KERNEL_STRUCT_BEGIN(shadow_ray)
KERNEL_STRUCT_MEMBER(shadow_ray, packed_float3, P, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(shadow_ray, packed_float3, D, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(shadow_ray, float, t, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(shadow_ray, float, tmin, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(shadow_ray, float, tmax, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(shadow_ray, float, time, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(shadow_ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(shadow_ray, int, object, KERNEL_FEATURE_PATH_TRACING)
diff --git a/intern/cycles/kernel/integrator/state.h b/intern/cycles/kernel/integrator/state.h
index d6fef27f344..d10d31e930e 100644
--- a/intern/cycles/kernel/integrator/state.h
+++ b/intern/cycles/kernel/integrator/state.h
@@ -127,6 +127,9 @@ typedef struct IntegratorStateGPU {
/* Index of main path which will be used by a next shadow catcher split. */
ccl_global int *next_main_path_index;
+
+ /* Divisor used to partition active indices by locality when sorting by material. */
+ uint sort_partition_divisor;
} IntegratorStateGPU;
/* Abstraction
diff --git a/intern/cycles/kernel/integrator/state_flow.h b/intern/cycles/kernel/integrator/state_flow.h
index fed74d49434..4b03c665e17 100644
--- a/intern/cycles/kernel/integrator/state_flow.h
+++ b/intern/cycles/kernel/integrator/state_flow.h
@@ -10,125 +10,196 @@ CCL_NAMESPACE_BEGIN
/* Control Flow
*
- * Utilities for control flow between kernels. The implementation may differ per device
- * or even be handled on the host side. To abstract such differences, experiment with
- * different implementations and for debugging, this is abstracted using macros.
+ * Utilities for control flow between kernels. The implementation is different between CPU and
+ * GPU devices. For the latter part of the logic is handled on the host side with wavefronts.
*
* There is a main path for regular path tracing camera for path tracing. Shadows for next
* event estimation branch off from this into their own path, that may be computed in
- * parallel while the main path continues.
+ * parallel while the main path continues. Additionally, shading kernels are sorted using
+ * a key for coherence.
*
* Each kernel on the main path must call one of these functions. These may not be called
* multiple times from the same kernel.
*
- * INTEGRATOR_PATH_INIT(next_kernel)
- * INTEGRATOR_PATH_NEXT(current_kernel, next_kernel)
- * INTEGRATOR_PATH_TERMINATE(current_kernel)
+ * integrator_path_init(kg, state, next_kernel)
+ * integrator_path_next(kg, state, current_kernel, next_kernel)
+ * integrator_path_terminate(kg, state, current_kernel)
*
* For the shadow path similar functions are used, and again each shadow kernel must call
* one of them, and only once.
*/
-#define INTEGRATOR_PATH_IS_TERMINATED (INTEGRATOR_STATE(state, path, queued_kernel) == 0)
-#define INTEGRATOR_SHADOW_PATH_IS_TERMINATED \
- (INTEGRATOR_STATE(state, shadow_path, queued_kernel) == 0)
+ccl_device_forceinline bool integrator_path_is_terminated(ConstIntegratorState state)
+{
+ return INTEGRATOR_STATE(state, path, queued_kernel) == 0;
+}
+
+ccl_device_forceinline bool integrator_shadow_path_is_terminated(ConstIntegratorShadowState state)
+{
+ return INTEGRATOR_STATE(state, shadow_path, queued_kernel) == 0;
+}
#ifdef __KERNEL_GPU__
-# define INTEGRATOR_PATH_INIT(next_kernel) \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
-# define INTEGRATOR_PATH_NEXT(current_kernel, next_kernel) \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
-# define INTEGRATOR_PATH_TERMINATE(current_kernel) \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
-
-# define INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, next_kernel, shadow_type) \
- IntegratorShadowState shadow_state = atomic_fetch_and_add_uint32( \
- &kernel_integrator_state.next_shadow_path_index[0], 1); \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
-# define INTEGRATOR_SHADOW_PATH_NEXT(current_kernel, next_kernel) \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], \
- 1); \
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = next_kernel;
-# define INTEGRATOR_SHADOW_PATH_TERMINATE(current_kernel) \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0;
-
-# define INTEGRATOR_PATH_INIT_SORTED(next_kernel, key) \
- { \
- const int key_ = key; \
- atomic_fetch_and_add_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[next_kernel], 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- INTEGRATOR_STATE_WRITE(state, path, shader_sort_key) = key_; \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.sort_key_counter[next_kernel][key_], \
- 1); \
- }
-# define INTEGRATOR_PATH_NEXT_SORTED(current_kernel, next_kernel, key) \
- { \
- const int key_ = key; \
- atomic_fetch_and_sub_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[current_kernel], 1); \
- atomic_fetch_and_add_uint32( \
- &kernel_integrator_state.queue_counter->num_queued[next_kernel], 1); \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- INTEGRATOR_STATE_WRITE(state, path, shader_sort_key) = key_; \
- atomic_fetch_and_add_uint32(&kernel_integrator_state.sort_key_counter[next_kernel][key_], \
- 1); \
- }
+ccl_device_forceinline void integrator_path_init(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel next_kernel)
+{
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], 1);
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+}
+
+ccl_device_forceinline void integrator_path_next(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel current_kernel,
+ const DeviceKernel next_kernel)
+{
+ atomic_fetch_and_sub_uint32(&kernel_integrator_state.queue_counter->num_queued[current_kernel],
+ 1);
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], 1);
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+}
+
+ccl_device_forceinline void integrator_path_terminate(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel current_kernel)
+{
+ atomic_fetch_and_sub_uint32(&kernel_integrator_state.queue_counter->num_queued[current_kernel],
+ 1);
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
+}
+
+ccl_device_forceinline IntegratorShadowState integrator_shadow_path_init(
+ KernelGlobals kg, IntegratorState state, const DeviceKernel next_kernel, const bool is_ao)
+{
+ IntegratorShadowState shadow_state = atomic_fetch_and_add_uint32(
+ &kernel_integrator_state.next_shadow_path_index[0], 1);
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], 1);
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
+ return shadow_state;
+}
+
+ccl_device_forceinline void integrator_shadow_path_next(KernelGlobals kg,
+ IntegratorShadowState state,
+ const DeviceKernel current_kernel,
+ const DeviceKernel next_kernel)
+{
+ atomic_fetch_and_sub_uint32(&kernel_integrator_state.queue_counter->num_queued[current_kernel],
+ 1);
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], 1);
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = next_kernel;
+}
+
+ccl_device_forceinline void integrator_shadow_path_terminate(KernelGlobals kg,
+ IntegratorShadowState state,
+ const DeviceKernel current_kernel)
+{
+ atomic_fetch_and_sub_uint32(&kernel_integrator_state.queue_counter->num_queued[current_kernel],
+ 1);
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0;
+}
+
+/* Sort first by truncated state index (for good locality), then by key (for good coherence). */
+# define INTEGRATOR_SORT_KEY(key, state) \
+ (key + kernel_data.max_shaders * (state / kernel_integrator_state.sort_partition_divisor))
+
+ccl_device_forceinline void integrator_path_init_sorted(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel next_kernel,
+ const uint32_t key)
+{
+ const int key_ = INTEGRATOR_SORT_KEY(key, state);
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], 1);
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+ INTEGRATOR_STATE_WRITE(state, path, shader_sort_key) = key_;
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.sort_key_counter[next_kernel][key_], 1);
+}
+
+ccl_device_forceinline void integrator_path_next_sorted(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel current_kernel,
+ const DeviceKernel next_kernel,
+ const uint32_t key)
+{
+ const int key_ = INTEGRATOR_SORT_KEY(key, state);
+ atomic_fetch_and_sub_uint32(&kernel_integrator_state.queue_counter->num_queued[current_kernel],
+ 1);
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.queue_counter->num_queued[next_kernel], 1);
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+ INTEGRATOR_STATE_WRITE(state, path, shader_sort_key) = key_;
+ atomic_fetch_and_add_uint32(&kernel_integrator_state.sort_key_counter[next_kernel][key_], 1);
+}
#else
-# define INTEGRATOR_PATH_INIT(next_kernel) \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
-# define INTEGRATOR_PATH_INIT_SORTED(next_kernel, key) \
- { \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- (void)key; \
- }
-# define INTEGRATOR_PATH_NEXT(current_kernel, next_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_PATH_TERMINATE(current_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_PATH_NEXT_SORTED(current_kernel, next_kernel, key) \
- { \
- INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel; \
- (void)key; \
- (void)current_kernel; \
- }
-
-# define INTEGRATOR_SHADOW_PATH_INIT(shadow_state, state, next_kernel, shadow_type) \
- IntegratorShadowState shadow_state = &state->shadow_type; \
- INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
-# define INTEGRATOR_SHADOW_PATH_NEXT(current_kernel, next_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = next_kernel; \
- (void)current_kernel; \
- }
-# define INTEGRATOR_SHADOW_PATH_TERMINATE(current_kernel) \
- { \
- INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0; \
- (void)current_kernel; \
- }
+ccl_device_forceinline void integrator_path_init(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel next_kernel)
+{
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+}
+
+ccl_device_forceinline void integrator_path_init_sorted(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel next_kernel,
+ const uint32_t key)
+{
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+ (void)key;
+}
+
+ccl_device_forceinline void integrator_path_next(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel current_kernel,
+ const DeviceKernel next_kernel)
+{
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+ (void)current_kernel;
+}
+
+ccl_device_forceinline void integrator_path_terminate(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel current_kernel)
+{
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = 0;
+ (void)current_kernel;
+}
+
+ccl_device_forceinline void integrator_path_next_sorted(KernelGlobals kg,
+ IntegratorState state,
+ const DeviceKernel current_kernel,
+ const DeviceKernel next_kernel,
+ const uint32_t key)
+{
+ INTEGRATOR_STATE_WRITE(state, path, queued_kernel) = next_kernel;
+ (void)key;
+ (void)current_kernel;
+}
+
+ccl_device_forceinline IntegratorShadowState integrator_shadow_path_init(
+ KernelGlobals kg, IntegratorState state, const DeviceKernel next_kernel, const bool is_ao)
+{
+ IntegratorShadowState shadow_state = (is_ao) ? &state->ao : &state->shadow;
+ INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, queued_kernel) = next_kernel;
+ return shadow_state;
+}
+
+ccl_device_forceinline void integrator_shadow_path_next(KernelGlobals kg,
+ IntegratorShadowState state,
+ const DeviceKernel current_kernel,
+ const DeviceKernel next_kernel)
+{
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = next_kernel;
+ (void)current_kernel;
+}
+
+ccl_device_forceinline void integrator_shadow_path_terminate(KernelGlobals kg,
+ IntegratorShadowState state,
+ const DeviceKernel current_kernel)
+{
+ INTEGRATOR_STATE_WRITE(state, shadow_path, queued_kernel) = 0;
+ (void)current_kernel;
+}
#endif
diff --git a/intern/cycles/kernel/integrator/state_template.h b/intern/cycles/kernel/integrator/state_template.h
index e7e6db037b0..5c2af131945 100644
--- a/intern/cycles/kernel/integrator/state_template.h
+++ b/intern/cycles/kernel/integrator/state_template.h
@@ -37,11 +37,10 @@ KERNEL_STRUCT_MEMBER(path, uint32_t, flag, KERNEL_FEATURE_PATH_TRACING)
/* enum PathRayMNEE */
KERNEL_STRUCT_MEMBER(path, uint8_t, mnee, KERNEL_FEATURE_PATH_TRACING)
/* Multiple importance sampling
- * The PDF of BSDF sampling at the last scatter point, and distance to the
- * last scatter point minus the last ray segment. This distance lets us
- * compute the complete distance through transparent surfaces and volumes. */
+ * The PDF of BSDF sampling at the last scatter point, which is at ray distance
+ * zero and distance. Note that transparency and volume attenuation increase
+ * the ray tmin but keep P unmodified so that this works. */
KERNEL_STRUCT_MEMBER(path, float, mis_ray_pdf, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(path, float, mis_ray_t, KERNEL_FEATURE_PATH_TRACING)
/* Filter glossy. */
KERNEL_STRUCT_MEMBER(path, float, min_ray_pdf, KERNEL_FEATURE_PATH_TRACING)
/* Continuation probability for path termination. */
@@ -63,7 +62,8 @@ KERNEL_STRUCT_END(path)
KERNEL_STRUCT_BEGIN(ray)
KERNEL_STRUCT_MEMBER(ray, packed_float3, P, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, packed_float3, D, KERNEL_FEATURE_PATH_TRACING)
-KERNEL_STRUCT_MEMBER(ray, float, t, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(ray, float, tmin, KERNEL_FEATURE_PATH_TRACING)
+KERNEL_STRUCT_MEMBER(ray, float, tmax, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, time, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING)
KERNEL_STRUCT_MEMBER(ray, float, dD, KERNEL_FEATURE_PATH_TRACING)
diff --git a/intern/cycles/kernel/integrator/state_util.h b/intern/cycles/kernel/integrator/state_util.h
index 280db2d1aac..8dd58ad6bcd 100644
--- a/intern/cycles/kernel/integrator/state_util.h
+++ b/intern/cycles/kernel/integrator/state_util.h
@@ -17,7 +17,8 @@ ccl_device_forceinline void integrator_state_write_ray(KernelGlobals kg,
{
INTEGRATOR_STATE_WRITE(state, ray, P) = ray->P;
INTEGRATOR_STATE_WRITE(state, ray, D) = ray->D;
- INTEGRATOR_STATE_WRITE(state, ray, t) = ray->t;
+ INTEGRATOR_STATE_WRITE(state, ray, tmin) = ray->tmin;
+ INTEGRATOR_STATE_WRITE(state, ray, tmax) = ray->tmax;
INTEGRATOR_STATE_WRITE(state, ray, time) = ray->time;
INTEGRATOR_STATE_WRITE(state, ray, dP) = ray->dP;
INTEGRATOR_STATE_WRITE(state, ray, dD) = ray->dD;
@@ -29,7 +30,8 @@ ccl_device_forceinline void integrator_state_read_ray(KernelGlobals kg,
{
ray->P = INTEGRATOR_STATE(state, ray, P);
ray->D = INTEGRATOR_STATE(state, ray, D);
- ray->t = INTEGRATOR_STATE(state, ray, t);
+ ray->tmin = INTEGRATOR_STATE(state, ray, tmin);
+ ray->tmax = INTEGRATOR_STATE(state, ray, tmax);
ray->time = INTEGRATOR_STATE(state, ray, time);
ray->dP = INTEGRATOR_STATE(state, ray, dP);
ray->dD = INTEGRATOR_STATE(state, ray, dD);
@@ -42,7 +44,8 @@ ccl_device_forceinline void integrator_state_write_shadow_ray(
{
INTEGRATOR_STATE_WRITE(state, shadow_ray, P) = ray->P;
INTEGRATOR_STATE_WRITE(state, shadow_ray, D) = ray->D;
- INTEGRATOR_STATE_WRITE(state, shadow_ray, t) = ray->t;
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, tmin) = ray->tmin;
+ INTEGRATOR_STATE_WRITE(state, shadow_ray, tmax) = ray->tmax;
INTEGRATOR_STATE_WRITE(state, shadow_ray, time) = ray->time;
INTEGRATOR_STATE_WRITE(state, shadow_ray, dP) = ray->dP;
}
@@ -53,7 +56,8 @@ ccl_device_forceinline void integrator_state_read_shadow_ray(KernelGlobals kg,
{
ray->P = INTEGRATOR_STATE(state, shadow_ray, P);
ray->D = INTEGRATOR_STATE(state, shadow_ray, D);
- ray->t = INTEGRATOR_STATE(state, shadow_ray, t);
+ ray->tmin = INTEGRATOR_STATE(state, shadow_ray, tmin);
+ ray->tmax = INTEGRATOR_STATE(state, shadow_ray, tmax);
ray->time = INTEGRATOR_STATE(state, shadow_ray, time);
ray->dP = INTEGRATOR_STATE(state, shadow_ray, dP);
ray->dD = differential_zero_compact();
diff --git a/intern/cycles/kernel/integrator/subsurface.h b/intern/cycles/kernel/integrator/subsurface.h
index 2391cc2356d..2f96f215d8a 100644
--- a/intern/cycles/kernel/integrator/subsurface.h
+++ b/intern/cycles/kernel/integrator/subsurface.h
@@ -38,7 +38,8 @@ ccl_device int subsurface_bounce(KernelGlobals kg,
/* Setup ray into surface. */
INTEGRATOR_STATE_WRITE(state, ray, P) = sd->P;
INTEGRATOR_STATE_WRITE(state, ray, D) = bssrdf->N;
- INTEGRATOR_STATE_WRITE(state, ray, t) = FLT_MAX;
+ INTEGRATOR_STATE_WRITE(state, ray, tmin) = 0.0f;
+ INTEGRATOR_STATE_WRITE(state, ray, tmax) = FLT_MAX;
INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP);
INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_zero_compact();
@@ -147,7 +148,7 @@ ccl_device_inline bool subsurface_scatter(KernelGlobals kg, IntegratorState stat
/* Update volume stack if needed. */
if (kernel_data.integrator.use_volumes) {
const int object = ss_isect.hits[0].object;
- const int object_flag = kernel_tex_fetch(__object_flag, object);
+ const int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_INTERSECTS_VOLUME) {
float3 P = INTEGRATOR_STATE(state, ray, P);
@@ -160,7 +161,7 @@ ccl_device_inline bool subsurface_scatter(KernelGlobals kg, IntegratorState stat
/* Pretend ray is coming from the outside towards the exit point. This ensures
* correct front/back facing normals.
* TODO: find a more elegant solution? */
- ray.P += ray.D * ray.t * 2.0f;
+ ray.P += ray.D * ray.tmax * 2.0f;
ray.D = -ray.D;
integrator_state_write_isect(kg, state, &ss_isect.hits[0]);
@@ -170,19 +171,30 @@ ccl_device_inline bool subsurface_scatter(KernelGlobals kg, IntegratorState stat
INTEGRATOR_STATE_WRITE(state, path, rng_offset) += PRNG_BOUNCE_NUM;
const int shader = intersection_get_shader(kg, &ss_isect.hits[0]);
- const int shader_flags = kernel_tex_fetch(__shaders, shader).flags;
+ const int shader_flags = kernel_data_fetch(shaders, shader).flags;
const int object_flags = intersection_get_object_flags(kg, &ss_isect.hits[0]);
const bool use_caustics = kernel_data.integrator.use_caustics &&
(object_flags & SD_OBJECT_CAUSTICS);
- const bool use_raytrace_kernel = (shader_flags & SD_HAS_RAYTRACE) || use_caustics;
+ const bool use_raytrace_kernel = (shader_flags & SD_HAS_RAYTRACE);
- if (use_raytrace_kernel) {
- INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
+ if (use_caustics) {
+ integrator_path_next_sorted(kg,
+ state,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE,
+ shader);
+ }
+ else if (use_raytrace_kernel) {
+ integrator_path_next_sorted(kg,
+ state,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE,
shader);
}
else {
- INTEGRATOR_PATH_NEXT_SORTED(DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
+ integrator_path_next_sorted(kg,
+ state,
+ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE,
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE,
shader);
}
diff --git a/intern/cycles/kernel/integrator/subsurface_disk.h b/intern/cycles/kernel/integrator/subsurface_disk.h
index 34330671748..2836934f6dd 100644
--- a/intern/cycles/kernel/integrator/subsurface_disk.h
+++ b/intern/cycles/kernel/integrator/subsurface_disk.h
@@ -82,7 +82,8 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg,
/* Create ray. */
ray.P = P + disk_N * disk_height + disk_P;
ray.D = -disk_N;
- ray.t = 2.0f * disk_height;
+ ray.tmin = 0.0f;
+ ray.tmax = 2.0f * disk_height;
ray.dP = ray_dP;
ray.dD = differential_zero_compact();
ray.time = time;
@@ -113,7 +114,7 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg,
for (int hit = 0; hit < num_eval_hits; hit++) {
/* Get geometric normal. */
const int object = ss_isect.hits[hit].object;
- const int object_flag = kernel_tex_fetch(__object_flag, object);
+ const int object_flag = kernel_data_fetch(object_flag, object);
float3 hit_Ng = ss_isect.Ng[hit];
if (path_flag & PATH_RAY_SUBSURFACE_BACKFACING) {
hit_Ng = -hit_Ng;
@@ -188,7 +189,8 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg,
ray.P = ray.P + ray.D * ss_isect.hits[hit].t;
ray.D = ss_isect.Ng[hit];
- ray.t = 1.0f;
+ ray.tmin = 0.0f;
+ ray.tmax = 1.0f;
return true;
}
diff --git a/intern/cycles/kernel/integrator/subsurface_random_walk.h b/intern/cycles/kernel/integrator/subsurface_random_walk.h
index b6cd4aae195..c1691030817 100644
--- a/intern/cycles/kernel/integrator/subsurface_random_walk.h
+++ b/intern/cycles/kernel/integrator/subsurface_random_walk.h
@@ -195,7 +195,8 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
/* Setup ray. */
ray.P = P;
ray.D = D;
- ray.t = FLT_MAX;
+ ray.tmin = 0.0f;
+ ray.tmax = FLT_MAX;
ray.time = time;
ray.dP = ray_dP;
ray.dD = differential_zero_compact();
@@ -229,7 +230,7 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
* Since the strength of the guided sampling increases as alpha gets lower, using a value that
* is too low results in fireflies while one that's too high just gives a bit more noise.
* Therefore, the code here uses the highest of the three albedos to be safe. */
- const float diffusion_length = diffusion_length_dwivedi(max3(alpha));
+ const float diffusion_length = diffusion_length_dwivedi(reduce_max(alpha));
if (diffusion_length == 1.0f) {
/* With specific values of alpha the length might become 1, which in asymptotic makes phase to
@@ -370,10 +371,10 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
* chance of connecting to it.
* TODO: Maybe use less than 10 times the mean free path? */
if (bounce == 0) {
- ray.t = max(t, 10.0f / (min3(sigma_t)));
+ ray.tmax = max(t, 10.0f / (reduce_min(sigma_t)));
}
else {
- ray.t = t;
+ ray.tmax = t;
/* After the first bounce the object can intersect the same surface again */
ray.self.object = OBJECT_NONE;
ray.self.prim = PRIM_NONE;
@@ -384,12 +385,12 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
if (hit) {
#ifdef __KERNEL_GPU_RAYTRACING__
/* t is always in world space with OptiX and MetalRT. */
- ray.t = ss_isect.hits[0].t;
+ ray.tmax = ss_isect.hits[0].t;
#else
/* Compute world space distance to surface hit. */
float3 D = transform_direction(&ob_itfm, ray.D);
D = normalize(D) * ss_isect.hits[0].t;
- ray.t = len(transform_direction(&ob_tfm, D));
+ ray.tmax = len(transform_direction(&ob_tfm, D));
#endif
}
@@ -397,16 +398,16 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
/* Check if we hit the opposite side. */
if (hit) {
have_opposite_interface = true;
- opposite_distance = dot(ray.P + ray.t * ray.D - P, -N);
+ opposite_distance = dot(ray.P + ray.tmax * ray.D - P, -N);
}
/* Apart from the opposite side check, we were supposed to only trace up to distance t,
* so check if there would have been a hit in that case. */
- hit = ray.t < t;
+ hit = ray.tmax < t;
}
/* Use the distance to the exit point for the throughput update if we found one. */
if (hit) {
- t = ray.t;
+ t = ray.tmax;
}
/* Advance to new scatter location. */
@@ -452,7 +453,7 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg,
}
if (hit) {
- kernel_assert(isfinite3_safe(throughput));
+ kernel_assert(isfinite_safe(throughput));
INTEGRATOR_STATE_WRITE(state, path, throughput) = throughput;
}
diff --git a/intern/cycles/kernel/integrator/volume_stack.h b/intern/cycles/kernel/integrator/volume_stack.h
index 5256349a0cc..97a0f0f386c 100644
--- a/intern/cycles/kernel/integrator/volume_stack.h
+++ b/intern/cycles/kernel/integrator/volume_stack.h
@@ -133,7 +133,7 @@ ccl_device float volume_stack_step_size(KernelGlobals kg, StackReadOp stack_read
break;
}
- int shader_flag = kernel_tex_fetch(__shaders, (entry.shader & SHADER_MASK)).flags;
+ int shader_flag = kernel_data_fetch(shaders, (entry.shader & SHADER_MASK)).flags;
bool heterogeneous = false;
@@ -146,7 +146,7 @@ ccl_device float volume_stack_step_size(KernelGlobals kg, StackReadOp stack_read
* heterogeneous volume objects may be using the same shader. */
int object = entry.object;
if (object != OBJECT_NONE) {
- int object_flag = kernel_tex_fetch(__object_flag, object);
+ int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_HAS_VOLUME_ATTRIBUTES) {
heterogeneous = true;
}
@@ -180,7 +180,7 @@ ccl_device VolumeSampleMethod volume_stack_sample_method(KernelGlobals kg, Integ
break;
}
- int shader_flag = kernel_tex_fetch(__shaders, (entry.shader & SHADER_MASK)).flags;
+ int shader_flag = kernel_data_fetch(shaders, (entry.shader & SHADER_MASK)).flags;
if (shader_flag & SD_VOLUME_MIS) {
/* Multiple importance sampling. */
diff --git a/intern/cycles/kernel/light/background.h b/intern/cycles/kernel/light/background.h
index 0cbf7fb76fe..2a97d43c9ce 100644
--- a/intern/cycles/kernel/light/background.h
+++ b/intern/cycles/kernel/light/background.h
@@ -31,7 +31,7 @@ ccl_device float3 background_map_sample(KernelGlobals kg,
int step = count >> 1;
int middle = first + step;
- if (kernel_tex_fetch(__light_background_marginal_cdf, middle).y < randv) {
+ if (kernel_data_fetch(light_background_marginal_cdf, middle).y < randv) {
first = middle + 1;
count -= step + 1;
}
@@ -42,9 +42,9 @@ ccl_device float3 background_map_sample(KernelGlobals kg,
int index_v = max(0, first - 1);
kernel_assert(index_v >= 0 && index_v < res_y);
- float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
- float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1);
- float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y);
+ float2 cdf_v = kernel_data_fetch(light_background_marginal_cdf, index_v);
+ float2 cdf_next_v = kernel_data_fetch(light_background_marginal_cdf, index_v + 1);
+ float2 cdf_last_v = kernel_data_fetch(light_background_marginal_cdf, res_y);
/* importance-sampled V direction */
float dv = inverse_lerp(cdf_v.y, cdf_next_v.y, randv);
@@ -57,7 +57,7 @@ ccl_device float3 background_map_sample(KernelGlobals kg,
int step = count >> 1;
int middle = first + step;
- if (kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + middle).y <
+ if (kernel_data_fetch(light_background_conditional_cdf, index_v * cdf_width + middle).y <
randu) {
first = middle + 1;
count -= step + 1;
@@ -69,12 +69,12 @@ ccl_device float3 background_map_sample(KernelGlobals kg,
int index_u = max(0, first - 1);
kernel_assert(index_u >= 0 && index_u < res_x);
- float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + index_u);
- float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + index_u + 1);
- float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + res_x);
+ float2 cdf_u = kernel_data_fetch(light_background_conditional_cdf,
+ index_v * cdf_width + index_u);
+ float2 cdf_next_u = kernel_data_fetch(light_background_conditional_cdf,
+ index_v * cdf_width + index_u + 1);
+ float2 cdf_last_u = kernel_data_fetch(light_background_conditional_cdf,
+ index_v * cdf_width + res_x);
/* importance-sampled U direction */
float du = inverse_lerp(cdf_u.y, cdf_next_u.y, randu);
@@ -112,9 +112,9 @@ ccl_device float background_map_pdf(KernelGlobals kg, float3 direction)
int index_v = clamp(float_to_int(uv.y * res_y), 0, res_y - 1);
/* pdfs in V direction */
- float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + res_x);
- float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y);
+ float2 cdf_last_u = kernel_data_fetch(light_background_conditional_cdf,
+ index_v * cdf_width + res_x);
+ float2 cdf_last_v = kernel_data_fetch(light_background_marginal_cdf, res_y);
float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x;
@@ -122,9 +122,9 @@ ccl_device float background_map_pdf(KernelGlobals kg, float3 direction)
return 0.0f;
/* pdfs in U direction */
- float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf,
- index_v * cdf_width + index_u);
- float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
+ float2 cdf_u = kernel_data_fetch(light_background_conditional_cdf,
+ index_v * cdf_width + index_u);
+ float2 cdf_v = kernel_data_fetch(light_background_marginal_cdf, index_v);
return (cdf_u.x * cdf_v.x) / denom;
}
@@ -133,7 +133,7 @@ ccl_device_inline bool background_portal_data_fetch_and_check_side(
KernelGlobals kg, float3 P, int index, ccl_private float3 *lightpos, ccl_private float3 *dir)
{
int portal = kernel_data.background.portal_offset + index;
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal);
*lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]);
*dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]);
@@ -166,7 +166,7 @@ ccl_device_inline float background_portal_pdf(
num_possible++;
int portal = kernel_data.background.portal_offset + p;
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal);
float3 axisu = make_float3(
klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(
@@ -242,7 +242,7 @@ ccl_device float3 background_portal_sample(KernelGlobals kg,
if (portal == 0) {
/* p is the portal to be sampled. */
int portal = kernel_data.background.portal_offset + p;
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, portal);
+ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal);
float3 axisu = make_float3(
klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]);
float3 axisv = make_float3(
diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h
index 1df1615ed99..b939489bb18 100644
--- a/intern/cycles/kernel/light/light.h
+++ b/intern/cycles/kernel/light/light.h
@@ -38,7 +38,7 @@ ccl_device_inline bool light_sample(KernelGlobals kg,
const uint32_t path_flag,
ccl_private LightSample *ls)
{
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) {
return false;
@@ -237,7 +237,7 @@ ccl_device bool lights_intersect(KernelGlobals kg,
const uint32_t path_flag)
{
for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) {
- const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
if (path_flag & PATH_RAY_CAMERA) {
if (klight->shader_id & SHADER_EXCLUDE_CAMERA) {
@@ -270,31 +270,26 @@ ccl_device bool lights_intersect(KernelGlobals kg,
if (type == LIGHT_SPOT) {
/* Spot/Disk light. */
- const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
- const float3 ray_P = ray->P - ray->D * mis_ray_t;
-
const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
const float radius = klight->spot.radius;
if (radius == 0.0f) {
continue;
}
/* disk oriented normal */
- const float3 lightN = normalize(ray_P - lightP);
+ const float3 lightN = normalize(ray->P - lightP);
/* One sided. */
if (dot(ray->D, lightN) >= 0.0f) {
continue;
}
float3 P;
- if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lightN, radius, &P, &t)) {
+ if (!ray_disk_intersect(
+ ray->P, ray->D, ray->tmin, ray->tmax, lightP, lightN, radius, &P, &t)) {
continue;
}
}
else if (type == LIGHT_POINT) {
/* Sphere light (aka, aligned disk light). */
- const float mis_ray_t = INTEGRATOR_STATE(state, path, mis_ray_t);
- const float3 ray_P = ray->P - ray->D * mis_ray_t;
-
const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]);
const float radius = klight->spot.radius;
if (radius == 0.0f) {
@@ -302,9 +297,10 @@ ccl_device bool lights_intersect(KernelGlobals kg,
}
/* disk oriented normal */
- const float3 lightN = normalize(ray_P - lightP);
+ const float3 lightN = normalize(ray->P - lightP);
float3 P;
- if (!ray_disk_intersect(ray->P, ray->D, ray->t, lightP, lightN, radius, &P, &t)) {
+ if (!ray_disk_intersect(
+ ray->P, ray->D, ray->tmin, ray->tmax, lightP, lightN, radius, &P, &t)) {
continue;
}
}
@@ -330,8 +326,19 @@ ccl_device bool lights_intersect(KernelGlobals kg,
const float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]);
float3 P;
- if (!ray_quad_intersect(
- ray->P, ray->D, 0.0f, ray->t, light_P, axisu, axisv, Ng, &P, &t, &u, &v, is_round)) {
+ if (!ray_quad_intersect(ray->P,
+ ray->D,
+ ray->tmin,
+ ray->tmax,
+ light_P,
+ axisu,
+ axisv,
+ Ng,
+ &P,
+ &t,
+ &u,
+ &v,
+ is_round)) {
continue;
}
}
@@ -358,7 +365,7 @@ ccl_device bool light_sample_from_distant_ray(KernelGlobals kg,
const int lamp,
ccl_private LightSample *ccl_restrict ls)
{
- ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ ccl_global const KernelLight *klight = &kernel_data_fetch(lights, lamp);
const int shader = klight->shader_id;
const float radius = klight->distant.radius;
const LightType type = (LightType)klight->type;
@@ -433,7 +440,7 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg,
ccl_private LightSample *ccl_restrict ls)
{
const int lamp = isect->prim;
- ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp);
+ ccl_global const KernelLight *klight = &kernel_data_fetch(lights, lamp);
LightType type = (LightType)klight->type;
ls->type = type;
ls->shader = klight->shader_id;
@@ -562,7 +569,7 @@ ccl_device_inline bool triangle_world_space_vertices(
KernelGlobals kg, int object, int prim, float time, float3 V[3])
{
bool has_motion = false;
- const int object_flag = kernel_tex_fetch(__object_flag, object);
+ const int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) {
motion_triangle_vertices(kg, object, prim, time, V);
@@ -699,12 +706,12 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals kg,
float area = 0.5f * Nl;
/* flip normal if necessary */
- const int object_flag = kernel_tex_fetch(__object_flag, object);
+ const int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
ls->Ng = -ls->Ng;
}
ls->eval_fac = 1.0f;
- ls->shader = kernel_tex_fetch(__tri_shader, prim);
+ ls->shader = kernel_data_fetch(tri_shader, prim);
ls->object = object;
ls->prim = prim;
ls->lamp = LAMP_NONE;
@@ -775,7 +782,8 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals kg,
ls->D = z * B + safe_sqrtf(1.0f - z * z) * safe_normalize(C_ - dot(C_, B) * B);
/* calculate intersection with the planar triangle */
- if (!ray_triangle_intersect(P, ls->D, FLT_MAX, V[0], V[1], V[2], &ls->u, &ls->v, &ls->t)) {
+ if (!ray_triangle_intersect(
+ P, ls->D, 0.0f, FLT_MAX, V[0], V[1], V[2], &ls->u, &ls->v, &ls->t)) {
ls->pdf = 0.0f;
return;
}
@@ -845,7 +853,7 @@ ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *ra
int half_len = len >> 1;
int middle = first + half_len;
- if (r < kernel_tex_fetch(__light_distribution, middle).totarea) {
+ if (r < kernel_data_fetch(light_distribution, middle).totarea) {
len = half_len;
}
else {
@@ -860,8 +868,8 @@ ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *ra
/* Rescale to reuse random number. this helps the 2D samples within
* each area light be stratified as well. */
- float distr_min = kernel_tex_fetch(__light_distribution, index).totarea;
- float distr_max = kernel_tex_fetch(__light_distribution, index + 1).totarea;
+ float distr_min = kernel_data_fetch(light_distribution, index).totarea;
+ float distr_max = kernel_data_fetch(light_distribution, index + 1).totarea;
*randu = (r - distr_min) / (distr_max - distr_min);
return index;
@@ -871,7 +879,7 @@ ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *ra
ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce)
{
- return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
+ return (bounce > kernel_data_fetch(lights, index).max_bounces);
}
template<bool in_volume_segment>
@@ -886,8 +894,8 @@ ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
{
/* Sample light index from distribution. */
const int index = light_distribution_sample(kg, &randu);
- ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution,
- index);
+ ccl_global const KernelLightDistribution *kdistribution = &kernel_data_fetch(light_distribution,
+ index);
const int prim = kdistribution->prim;
if (prim >= 0) {
@@ -896,7 +904,7 @@ ccl_device_noinline bool light_distribution_sample(KernelGlobals kg,
/* Exclude synthetic meshes from shadow catcher pass. */
if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
- !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
+ !(kernel_data_fetch(object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) {
return false;
}
diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h
index 9bbbd5b0d10..210bb1b35c2 100644
--- a/intern/cycles/kernel/light/sample.h
+++ b/intern/cycles/kernel/light/sample.h
@@ -81,7 +81,7 @@ light_sample_shader_eval(KernelGlobals kg,
eval *= ls->eval_fac;
if (ls->lamp != LAMP_NONE) {
- ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, ls->lamp);
+ ccl_global const KernelLight *klight = &kernel_data_fetch(lights, ls->lamp);
eval *= make_float3(klight->strength[0], klight->strength[1], klight->strength[2]);
}
@@ -106,7 +106,7 @@ ccl_device_inline bool light_sample_terminate(KernelGlobals kg,
}
if (kernel_data.integrator.light_inv_rr_threshold > 0.0f) {
- float probability = max3(fabs(bsdf_eval_sum(eval))) *
+ float probability = reduce_max(fabs(bsdf_eval_sum(eval))) *
kernel_data.integrator.light_inv_rr_threshold;
if (probability < 1.0f) {
if (rand_terminate >= probability) {
@@ -187,7 +187,7 @@ ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
if ((sd->type & PRIMITIVE_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
const float offset_cutoff =
- kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset;
+ kernel_data_fetch(objects, sd->object).shadow_terminator_geometry_offset;
/* Do ray offset (heavy stuff) only for close to be terminated triangles:
* offset_cutoff = 0.1f means that 10-20% of rays will be affected. Also
* make a smooth transition near the threshold. */
@@ -227,23 +227,24 @@ ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restri
if (ls->shader & SHADER_CAST_SHADOW) {
/* setup ray */
ray->P = P;
+ ray->tmin = 0.0f;
if (ls->t == FLT_MAX) {
/* distant light */
ray->D = ls->D;
- ray->t = ls->t;
+ ray->tmax = ls->t;
}
else {
/* other lights, avoid self-intersection */
ray->D = ls->P - P;
- ray->D = normalize_len(ray->D, &ray->t);
+ ray->D = normalize_len(ray->D, &ray->tmax);
}
}
else {
/* signal to not cast shadow ray */
ray->P = zero_float3();
ray->D = zero_float3();
- ray->t = 0.0f;
+ ray->tmax = 0.0f;
}
ray->dP = differential_make_compact(sd->dP);
diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp
index e2e10b5b83f..6b7981b7f3a 100644
--- a/intern/cycles/kernel/osl/services.cpp
+++ b/intern/cycles/kernel/osl/services.cpp
@@ -132,7 +132,7 @@ OSLRenderServices::OSLRenderServices(OSL::TextureSystem *texture_system)
OSLRenderServices::~OSLRenderServices()
{
if (texture_system) {
- VLOG(2) << "OSL texture system stats:\n" << texture_system->getstats();
+ VLOG_INFO << "OSL texture system stats:\n" << texture_system->getstats();
}
}
@@ -1094,10 +1094,8 @@ bool OSLRenderServices::get_background_attribute(const KernelGlobalsCPU *kg,
ndc[0] = camera_world_to_ndc(kg, sd, sd->ray_P);
if (derivatives) {
- ndc[1] = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(sd->ray_dP, 0.0f, 0.0f)) -
- ndc[0];
- ndc[2] = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(0.0f, sd->ray_dP, 0.0f)) -
- ndc[0];
+ ndc[1] = zero_float3();
+ ndc[2] = zero_float3();
}
}
else {
@@ -1671,7 +1669,8 @@ bool OSLRenderServices::trace(TraceOpt &options,
ray.P = TO_FLOAT3(P);
ray.D = TO_FLOAT3(R);
- ray.t = (options.maxdist == 1.0e30f) ? FLT_MAX : options.maxdist - options.mindist;
+ ray.tmin = 0.0f;
+ ray.tmax = (options.maxdist == 1.0e30f) ? FLT_MAX : options.maxdist - options.mindist;
ray.time = sd->time;
ray.self.object = OBJECT_NONE;
ray.self.prim = PRIM_NONE;
@@ -1710,12 +1709,12 @@ bool OSLRenderServices::trace(TraceOpt &options,
const KernelGlobalsCPU *kg = sd->osl_globals;
- /* Can't raytrace from shaders like displacement, before BVH exists. */
+ /* Can't ray-trace from shaders like displacement, before BVH exists. */
if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
return false;
}
- /* Raytrace, leaving out shadow opaque to avoid early exit. */
+ /* Ray-trace, leaving out shadow opaque to avoid early exit. */
uint visibility = PATH_RAY_ALL_VISIBILITY - PATH_RAY_SHADOW_OPAQUE;
tracedata->hit = scene_intersect(kg, &ray, visibility, &tracedata->isect);
return tracedata->hit;
diff --git a/intern/cycles/kernel/sample/jitter.h b/intern/cycles/kernel/sample/jitter.h
index b8da94248a4..b5cfa624406 100644
--- a/intern/cycles/kernel/sample/jitter.h
+++ b/intern/cycles/kernel/sample/jitter.h
@@ -97,7 +97,7 @@ ccl_device float pmj_sample_1D(KernelGlobals kg, uint sample, uint rng_hash, uin
* the x part is used for even dims and the y for odd. */
int index = 2 * ((dim >> 1) * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES)) + (dim & 1);
- float fx = kernel_tex_fetch(__sample_pattern_lut, index);
+ float fx = kernel_data_fetch(sample_pattern_lut, index);
#ifndef _NO_CRANLEY_PATTERSON_ROTATION_
/* Use Cranley-Patterson rotation to displace the sample pattern. */
@@ -154,8 +154,8 @@ ccl_device void pmj_sample_2D(KernelGlobals kg,
uint dim = d % NUM_PMJ_PATTERNS;
int index = 2 * (dim * NUM_PMJ_SAMPLES + (s % NUM_PMJ_SAMPLES));
- float fx = kernel_tex_fetch(__sample_pattern_lut, index);
- float fy = kernel_tex_fetch(__sample_pattern_lut, index + 1);
+ float fx = kernel_data_fetch(sample_pattern_lut, index);
+ float fy = kernel_data_fetch(sample_pattern_lut, index + 1);
#ifndef _NO_CRANLEY_PATTERSON_ROTATION_
/* Use Cranley-Patterson rotation to displace the sample pattern. */
diff --git a/intern/cycles/kernel/sample/pattern.h b/intern/cycles/kernel/sample/pattern.h
index 1e66f39ede2..89500d51872 100644
--- a/intern/cycles/kernel/sample/pattern.h
+++ b/intern/cycles/kernel/sample/pattern.h
@@ -32,7 +32,7 @@ ccl_device uint sobol_dimension(KernelGlobals kg, int index, int dimension)
uint i = index + SOBOL_SKIP;
for (int j = 0, x; (x = find_first_set(i)); i >>= x) {
j += x;
- result ^= __float_as_uint(kernel_tex_fetch(__sample_pattern_lut, 32 * dimension + j - 1));
+ result ^= __float_as_uint(kernel_data_fetch(sample_pattern_lut, 32 * dimension + j - 1));
}
return result;
}
diff --git a/intern/cycles/kernel/svm/ao.h b/intern/cycles/kernel/svm/ao.h
index b477855dca3..c57c68d6230 100644
--- a/intern/cycles/kernel/svm/ao.h
+++ b/intern/cycles/kernel/svm/ao.h
@@ -31,7 +31,7 @@ ccl_device float svm_ao(
return 1.0f;
}
- /* Can't raytrace from shaders like displacement, before BVH exists. */
+ /* Can't ray-trace from shaders like displacement, before BVH exists. */
if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
return 1.0f;
}
@@ -59,7 +59,8 @@ ccl_device float svm_ao(
Ray ray;
ray.P = sd->P;
ray.D = D.x * T + D.y * B + D.z * N;
- ray.t = max_dist;
+ ray.tmin = 0.0f;
+ ray.tmax = max_dist;
ray.time = sd->time;
ray.self.object = sd->object;
ray.self.prim = sd->prim;
diff --git a/intern/cycles/kernel/svm/bevel.h b/intern/cycles/kernel/svm/bevel.h
index 5abffe1c771..4617a056a52 100644
--- a/intern/cycles/kernel/svm/bevel.h
+++ b/intern/cycles/kernel/svm/bevel.h
@@ -103,7 +103,7 @@ ccl_device float3 svm_bevel(
return sd->N;
}
- /* Can't raytrace from shaders like displacement, before BVH exists. */
+ /* Can't ray-trace from shaders like displacement, before BVH exists. */
if (kernel_data.bvh.bvh_layout == BVH_LAYOUT_NONE) {
return sd->N;
}
@@ -179,7 +179,8 @@ ccl_device float3 svm_bevel(
Ray ray ccl_optional_struct_init;
ray.P = sd->P + disk_N * disk_height + disk_P;
ray.D = -disk_N;
- ray.t = 2.0f * disk_height;
+ ray.tmin = 0.0f;
+ ray.tmax = 2.0f * disk_height;
ray.dP = differential_zero_compact();
ray.dD = differential_zero_compact();
ray.time = sd->time;
@@ -222,7 +223,7 @@ ccl_device float3 svm_bevel(
/* Get geometric normal. */
float3 hit_Ng = isect.Ng[hit];
int object = isect.hits[hit].object;
- int object_flag = kernel_tex_fetch(__object_flag, object);
+ int object_flag = kernel_data_fetch(object_flag, object);
if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) {
hit_Ng = -hit_Ng;
}
@@ -230,7 +231,7 @@ ccl_device float3 svm_bevel(
/* Compute smooth normal. */
float3 N = hit_Ng;
int prim = isect.hits[hit].prim;
- int shader = kernel_tex_fetch(__tri_shader, prim);
+ int shader = kernel_data_fetch(tri_shader, prim);
if (shader & SHADER_SMOOTH_NORMAL) {
float u = isect.hits[hit].u;
diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h
index 305bd404d27..99a8fdd3be9 100644
--- a/intern/cycles/kernel/svm/closure.h
+++ b/intern/cycles/kernel/svm/closure.h
@@ -395,7 +395,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0)
# endif
{
- /* This is to prevent mnee from receiving a null bsdf. */
+ /* This is to prevent MNEE from receiving a null BSDF. */
float refraction_fresnel = fmaxf(0.0001f, 1.0f - fresnel);
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), base_color * glass_weight * refraction_fresnel);
@@ -676,7 +676,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0)
#endif
{
- /* This is to prevent mnee from receiving a null bsdf. */
+ /* This is to prevent MNEE from receiving a null BSDF. */
float refraction_fresnel = fmaxf(0.0001f, 1.0f - fresnel);
ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc(
sd, sizeof(MicrofacetBsdf), weight * refraction_fresnel);
diff --git a/intern/cycles/kernel/svm/color_util.h b/intern/cycles/kernel/svm/color_util.h
index fa22d4bc8c2..41f44378ff0 100644
--- a/intern/cycles/kernel/svm/color_util.h
+++ b/intern/cycles/kernel/svm/color_util.h
@@ -244,7 +244,7 @@ ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2)
ccl_device float3 svm_mix_clamp(float3 col)
{
- return saturate3(col);
+ return saturate(col);
}
ccl_device_noinline_cpu float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
diff --git a/intern/cycles/kernel/svm/ies.h b/intern/cycles/kernel/svm/ies.h
index 201d88101cd..3648cb580d5 100644
--- a/intern/cycles/kernel/svm/ies.h
+++ b/intern/cycles/kernel/svm/ies.h
@@ -17,7 +17,7 @@ ccl_device_inline float interpolate_ies_vertical(
* Therefore, the assumption is made that the light is going to be symmetrical, which means that
* we can just take the corresponding value at the current horizontal coordinate. */
-#define IES_LOOKUP(v) kernel_tex_fetch(__ies, ofs + h * v_num + (v))
+#define IES_LOOKUP(v) kernel_data_fetch(ies, ofs + h * v_num + (v))
/* If v is zero, assume symmetry and read at v=1 instead of v=-1. */
float a = IES_LOOKUP((v == 0) ? 1 : v - 1);
float b = IES_LOOKUP(v);
@@ -31,16 +31,16 @@ ccl_device_inline float interpolate_ies_vertical(
ccl_device_inline float kernel_ies_interp(KernelGlobals kg, int slot, float h_angle, float v_angle)
{
/* Find offset of the IES data in the table. */
- int ofs = __float_as_int(kernel_tex_fetch(__ies, slot));
+ int ofs = __float_as_int(kernel_data_fetch(ies, slot));
if (ofs == -1) {
return 100.0f;
}
- int h_num = __float_as_int(kernel_tex_fetch(__ies, ofs++));
- int v_num = __float_as_int(kernel_tex_fetch(__ies, ofs++));
+ int h_num = __float_as_int(kernel_data_fetch(ies, ofs++));
+ int v_num = __float_as_int(kernel_data_fetch(ies, ofs++));
-#define IES_LOOKUP_ANGLE_H(h) kernel_tex_fetch(__ies, ofs + (h))
-#define IES_LOOKUP_ANGLE_V(v) kernel_tex_fetch(__ies, ofs + h_num + (v))
+#define IES_LOOKUP_ANGLE_H(h) kernel_data_fetch(ies, ofs + (h))
+#define IES_LOOKUP_ANGLE_V(v) kernel_data_fetch(ies, ofs + h_num + (v))
/* Check whether the angle is within the bounds of the IES texture. */
if (v_angle >= IES_LOOKUP_ANGLE_V(v_num - 1)) {
diff --git a/intern/cycles/kernel/svm/map_range.h b/intern/cycles/kernel/svm/map_range.h
index ff0e462041c..ea85bc43b74 100644
--- a/intern/cycles/kernel/svm/map_range.h
+++ b/intern/cycles/kernel/svm/map_range.h
@@ -112,10 +112,10 @@ ccl_device_noinline int svm_node_vector_map_range(KernelGlobals kg,
switch (range_type_stack_offset) {
default:
case NODE_MAP_RANGE_LINEAR:
- factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = safe_divide((value - from_min), (from_max - from_min));
break;
case NODE_MAP_RANGE_STEPPED: {
- factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = safe_divide((value - from_min), (from_max - from_min));
factor = make_float3((steps.x > 0.0f) ? floorf(factor.x * (steps.x + 1.0f)) / steps.x : 0.0f,
(steps.y > 0.0f) ? floorf(factor.y * (steps.y + 1.0f)) / steps.y : 0.0f,
(steps.z > 0.0f) ? floorf(factor.z * (steps.z + 1.0f)) / steps.z :
@@ -123,13 +123,13 @@ ccl_device_noinline int svm_node_vector_map_range(KernelGlobals kg,
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
- factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = safe_divide((value - from_min), (from_max - from_min));
factor = clamp(factor, zero_float3(), one_float3());
factor = (make_float3(3.0f, 3.0f, 3.0f) - 2.0f * factor) * (factor * factor);
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
- factor = safe_divide_float3_float3((value - from_min), (from_max - from_min));
+ factor = safe_divide((value - from_min), (from_max - from_min));
factor = clamp(factor, zero_float3(), one_float3());
factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f);
break;
diff --git a/intern/cycles/kernel/svm/mapping_util.h b/intern/cycles/kernel/svm/mapping_util.h
index c616d4018c4..13257c762e7 100644
--- a/intern/cycles/kernel/svm/mapping_util.h
+++ b/intern/cycles/kernel/svm/mapping_util.h
@@ -13,13 +13,12 @@ svm_mapping(NodeMappingType type, float3 vector, float3 location, float3 rotatio
case NODE_MAPPING_TYPE_POINT:
return transform_direction(&rotationTransform, (vector * scale)) + location;
case NODE_MAPPING_TYPE_TEXTURE:
- return safe_divide_float3_float3(
- transform_direction_transposed(&rotationTransform, (vector - location)), scale);
+ return safe_divide(transform_direction_transposed(&rotationTransform, (vector - location)),
+ scale);
case NODE_MAPPING_TYPE_VECTOR:
return transform_direction(&rotationTransform, (vector * scale));
case NODE_MAPPING_TYPE_NORMAL:
- return safe_normalize(
- transform_direction(&rotationTransform, safe_divide_float3_float3(vector, scale)));
+ return safe_normalize(transform_direction(&rotationTransform, safe_divide(vector, scale)));
default:
return make_float3(0.0f, 0.0f, 0.0f);
}
diff --git a/intern/cycles/kernel/svm/math_util.h b/intern/cycles/kernel/svm/math_util.h
index 89bd4a501a7..d90d4f0f794 100644
--- a/intern/cycles/kernel/svm/math_util.h
+++ b/intern/cycles/kernel/svm/math_util.h
@@ -24,7 +24,7 @@ ccl_device void svm_vector_math(ccl_private float *value,
*vector = a * b;
break;
case NODE_VECTOR_MATH_DIVIDE:
- *vector = safe_divide_float3_float3(a, b);
+ *vector = safe_divide(a, b);
break;
case NODE_VECTOR_MATH_CROSS_PRODUCT:
*vector = cross(a, b);
@@ -60,7 +60,7 @@ ccl_device void svm_vector_math(ccl_private float *value,
*vector = safe_normalize(a);
break;
case NODE_VECTOR_MATH_SNAP:
- *vector = floor(safe_divide_float3_float3(a, b)) * b;
+ *vector = floor(safe_divide(a, b)) * b;
break;
case NODE_VECTOR_MATH_FLOOR:
*vector = floor(a);
diff --git a/intern/cycles/kernel/svm/node_types_template.h b/intern/cycles/kernel/svm/node_types_template.h
new file mode 100644
index 00000000000..39d279be4cb
--- /dev/null
+++ b/intern/cycles/kernel/svm/node_types_template.h
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#ifndef SHADER_NODE_TYPE
+# define SHADER_NODE_TYPE(name)
+#endif
+
+/* NOTE: for best OpenCL performance, item definition in the enum must
+ * match the switch case order in `svm.h`. */
+
+SHADER_NODE_TYPE(NODE_END)
+SHADER_NODE_TYPE(NODE_SHADER_JUMP)
+SHADER_NODE_TYPE(NODE_CLOSURE_BSDF)
+SHADER_NODE_TYPE(NODE_CLOSURE_EMISSION)
+SHADER_NODE_TYPE(NODE_CLOSURE_BACKGROUND)
+SHADER_NODE_TYPE(NODE_CLOSURE_SET_WEIGHT)
+SHADER_NODE_TYPE(NODE_CLOSURE_WEIGHT)
+SHADER_NODE_TYPE(NODE_EMISSION_WEIGHT)
+SHADER_NODE_TYPE(NODE_MIX_CLOSURE)
+SHADER_NODE_TYPE(NODE_JUMP_IF_ZERO)
+SHADER_NODE_TYPE(NODE_JUMP_IF_ONE)
+SHADER_NODE_TYPE(NODE_GEOMETRY)
+SHADER_NODE_TYPE(NODE_CONVERT)
+SHADER_NODE_TYPE(NODE_TEX_COORD)
+SHADER_NODE_TYPE(NODE_VALUE_F)
+SHADER_NODE_TYPE(NODE_VALUE_V)
+SHADER_NODE_TYPE(NODE_ATTR)
+SHADER_NODE_TYPE(NODE_VERTEX_COLOR)
+SHADER_NODE_TYPE(NODE_GEOMETRY_BUMP_DX)
+SHADER_NODE_TYPE(NODE_GEOMETRY_BUMP_DY)
+SHADER_NODE_TYPE(NODE_SET_DISPLACEMENT)
+SHADER_NODE_TYPE(NODE_DISPLACEMENT)
+SHADER_NODE_TYPE(NODE_VECTOR_DISPLACEMENT)
+SHADER_NODE_TYPE(NODE_TEX_IMAGE)
+SHADER_NODE_TYPE(NODE_TEX_IMAGE_BOX)
+SHADER_NODE_TYPE(NODE_TEX_NOISE)
+SHADER_NODE_TYPE(NODE_SET_BUMP)
+SHADER_NODE_TYPE(NODE_ATTR_BUMP_DX)
+SHADER_NODE_TYPE(NODE_ATTR_BUMP_DY)
+SHADER_NODE_TYPE(NODE_VERTEX_COLOR_BUMP_DX)
+SHADER_NODE_TYPE(NODE_VERTEX_COLOR_BUMP_DY)
+SHADER_NODE_TYPE(NODE_TEX_COORD_BUMP_DX)
+SHADER_NODE_TYPE(NODE_TEX_COORD_BUMP_DY)
+SHADER_NODE_TYPE(NODE_CLOSURE_SET_NORMAL)
+SHADER_NODE_TYPE(NODE_ENTER_BUMP_EVAL)
+SHADER_NODE_TYPE(NODE_LEAVE_BUMP_EVAL)
+SHADER_NODE_TYPE(NODE_HSV)
+SHADER_NODE_TYPE(NODE_CLOSURE_HOLDOUT)
+SHADER_NODE_TYPE(NODE_FRESNEL)
+SHADER_NODE_TYPE(NODE_LAYER_WEIGHT)
+SHADER_NODE_TYPE(NODE_CLOSURE_VOLUME)
+SHADER_NODE_TYPE(NODE_PRINCIPLED_VOLUME)
+SHADER_NODE_TYPE(NODE_MATH)
+SHADER_NODE_TYPE(NODE_VECTOR_MATH)
+SHADER_NODE_TYPE(NODE_RGB_RAMP)
+SHADER_NODE_TYPE(NODE_GAMMA)
+SHADER_NODE_TYPE(NODE_BRIGHTCONTRAST)
+SHADER_NODE_TYPE(NODE_LIGHT_PATH)
+SHADER_NODE_TYPE(NODE_OBJECT_INFO)
+SHADER_NODE_TYPE(NODE_PARTICLE_INFO)
+SHADER_NODE_TYPE(NODE_HAIR_INFO)
+SHADER_NODE_TYPE(NODE_POINT_INFO)
+SHADER_NODE_TYPE(NODE_TEXTURE_MAPPING)
+SHADER_NODE_TYPE(NODE_MAPPING)
+SHADER_NODE_TYPE(NODE_MIN_MAX)
+SHADER_NODE_TYPE(NODE_CAMERA)
+SHADER_NODE_TYPE(NODE_TEX_ENVIRONMENT)
+SHADER_NODE_TYPE(NODE_TEX_SKY)
+SHADER_NODE_TYPE(NODE_TEX_GRADIENT)
+SHADER_NODE_TYPE(NODE_TEX_VORONOI)
+SHADER_NODE_TYPE(NODE_TEX_MUSGRAVE)
+SHADER_NODE_TYPE(NODE_TEX_WAVE)
+SHADER_NODE_TYPE(NODE_TEX_MAGIC)
+SHADER_NODE_TYPE(NODE_TEX_CHECKER)
+SHADER_NODE_TYPE(NODE_TEX_BRICK)
+SHADER_NODE_TYPE(NODE_TEX_WHITE_NOISE)
+SHADER_NODE_TYPE(NODE_NORMAL)
+SHADER_NODE_TYPE(NODE_LIGHT_FALLOFF)
+SHADER_NODE_TYPE(NODE_IES)
+SHADER_NODE_TYPE(NODE_CURVES)
+SHADER_NODE_TYPE(NODE_TANGENT)
+SHADER_NODE_TYPE(NODE_NORMAL_MAP)
+SHADER_NODE_TYPE(NODE_INVERT)
+SHADER_NODE_TYPE(NODE_MIX)
+SHADER_NODE_TYPE(NODE_SEPARATE_COLOR)
+SHADER_NODE_TYPE(NODE_COMBINE_COLOR)
+SHADER_NODE_TYPE(NODE_SEPARATE_VECTOR)
+SHADER_NODE_TYPE(NODE_COMBINE_VECTOR)
+SHADER_NODE_TYPE(NODE_SEPARATE_HSV)
+SHADER_NODE_TYPE(NODE_COMBINE_HSV)
+SHADER_NODE_TYPE(NODE_VECTOR_ROTATE)
+SHADER_NODE_TYPE(NODE_VECTOR_TRANSFORM)
+SHADER_NODE_TYPE(NODE_WIREFRAME)
+SHADER_NODE_TYPE(NODE_WAVELENGTH)
+SHADER_NODE_TYPE(NODE_BLACKBODY)
+SHADER_NODE_TYPE(NODE_MAP_RANGE)
+SHADER_NODE_TYPE(NODE_VECTOR_MAP_RANGE)
+SHADER_NODE_TYPE(NODE_CLAMP)
+SHADER_NODE_TYPE(NODE_BEVEL)
+SHADER_NODE_TYPE(NODE_AMBIENT_OCCLUSION)
+SHADER_NODE_TYPE(NODE_TEX_VOXEL)
+SHADER_NODE_TYPE(NODE_AOV_START)
+SHADER_NODE_TYPE(NODE_AOV_COLOR)
+SHADER_NODE_TYPE(NODE_AOV_VALUE)
+SHADER_NODE_TYPE(NODE_FLOAT_CURVE)
+
+/* Padding for struct alignment. */
+SHADER_NODE_TYPE(NODE_PAD1)
+
+#undef SHADER_NODE_TYPE
diff --git a/intern/cycles/kernel/svm/ramp.h b/intern/cycles/kernel/svm/ramp.h
index 342b15da9ed..0df9268bd9c 100644
--- a/intern/cycles/kernel/svm/ramp.h
+++ b/intern/cycles/kernel/svm/ramp.h
@@ -9,7 +9,7 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float fetch_float(KernelGlobals kg, int offset)
{
- uint4 node = kernel_tex_fetch(__svm_nodes, offset);
+ uint4 node = kernel_data_fetch(svm_nodes, offset);
return __uint_as_float(node.x);
}
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 5def943c87f..9d6d3e9222c 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -95,14 +95,14 @@ ccl_device_inline bool stack_valid(uint a)
ccl_device_inline uint4 read_node(KernelGlobals kg, ccl_private int *offset)
{
- uint4 node = kernel_tex_fetch(__svm_nodes, *offset);
+ uint4 node = kernel_data_fetch(svm_nodes, *offset);
(*offset)++;
return node;
}
ccl_device_inline float4 read_node_float(KernelGlobals kg, ccl_private int *offset)
{
- uint4 node = kernel_tex_fetch(__svm_nodes, *offset);
+ uint4 node = kernel_data_fetch(svm_nodes, *offset);
float4 f = make_float4(__uint_as_float(node.x),
__uint_as_float(node.y),
__uint_as_float(node.z),
@@ -113,7 +113,7 @@ ccl_device_inline float4 read_node_float(KernelGlobals kg, ccl_private int *offs
ccl_device_inline float4 fetch_node_float(KernelGlobals kg, int offset)
{
- uint4 node = kernel_tex_fetch(__svm_nodes, offset);
+ uint4 node = kernel_data_fetch(svm_nodes, offset);
return make_float4(__uint_as_float(node.x),
__uint_as_float(node.y),
__uint_as_float(node.z),
@@ -204,6 +204,15 @@ CCL_NAMESPACE_END
CCL_NAMESPACE_BEGIN
+#ifdef __KERNEL_USE_DATA_CONSTANTS__
+# define SVM_CASE(node) \
+ case node: \
+ if (!kernel_data_svm_usage_##node) \
+ break;
+#else
+# define SVM_CASE(node) case node:
+#endif
+
/* Main Interpreter Loop */
template<uint node_feature_mask, ShaderType type, typename ConstIntegratorGenericState>
ccl_device void svm_eval_nodes(KernelGlobals kg,
@@ -219,9 +228,10 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
uint4 node = read_node(kg, &offset);
switch (node.x) {
- case NODE_END:
- return;
- case NODE_SHADER_JUMP: {
+ SVM_CASE(NODE_END)
+ return;
+ SVM_CASE(NODE_SHADER_JUMP)
+ {
if (type == SHADER_TYPE_SURFACE)
offset = node.y;
else if (type == SHADER_TYPE_VOLUME)
@@ -232,351 +242,349 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
return;
break;
}
- case NODE_CLOSURE_BSDF:
- offset = svm_node_closure_bsdf<node_feature_mask, type>(
- kg, sd, stack, node, path_flag, offset);
- break;
- case NODE_CLOSURE_EMISSION:
- IF_KERNEL_NODES_FEATURE(EMISSION)
- {
- svm_node_closure_emission(sd, stack, node);
- }
- break;
- case NODE_CLOSURE_BACKGROUND:
- IF_KERNEL_NODES_FEATURE(EMISSION)
- {
- svm_node_closure_background(sd, stack, node);
- }
- break;
- case NODE_CLOSURE_SET_WEIGHT:
- svm_node_closure_set_weight(sd, node.y, node.z, node.w);
- break;
- case NODE_CLOSURE_WEIGHT:
- svm_node_closure_weight(sd, stack, node.y);
- break;
- case NODE_EMISSION_WEIGHT:
- IF_KERNEL_NODES_FEATURE(EMISSION)
- {
- svm_node_emission_weight(kg, sd, stack, node);
- }
- break;
- case NODE_MIX_CLOSURE:
- svm_node_mix_closure(sd, stack, node);
- break;
- case NODE_JUMP_IF_ZERO:
- if (stack_load_float(stack, node.z) == 0.0f)
- offset += node.y;
- break;
- case NODE_JUMP_IF_ONE:
- if (stack_load_float(stack, node.z) == 1.0f)
- offset += node.y;
- break;
- case NODE_GEOMETRY:
- svm_node_geometry(kg, sd, stack, node.y, node.z);
- break;
- case NODE_CONVERT:
- svm_node_convert(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_TEX_COORD:
- offset = svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
- break;
- case NODE_VALUE_F:
- svm_node_value_f(kg, sd, stack, node.y, node.z);
- break;
- case NODE_VALUE_V:
- offset = svm_node_value_v(kg, sd, stack, node.y, offset);
- break;
- case NODE_ATTR:
- svm_node_attr<node_feature_mask>(kg, sd, stack, node);
- break;
- case NODE_VERTEX_COLOR:
- svm_node_vertex_color(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_GEOMETRY_BUMP_DX:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z);
- }
- break;
- case NODE_GEOMETRY_BUMP_DY:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z);
- }
- break;
- case NODE_SET_DISPLACEMENT:
- svm_node_set_displacement<node_feature_mask>(kg, sd, stack, node.y);
- break;
- case NODE_DISPLACEMENT:
- svm_node_displacement<node_feature_mask>(kg, sd, stack, node);
- break;
- case NODE_VECTOR_DISPLACEMENT:
- offset = svm_node_vector_displacement<node_feature_mask>(kg, sd, stack, node, offset);
- break;
- case NODE_TEX_IMAGE:
- offset = svm_node_tex_image(kg, sd, stack, node, offset);
- break;
- case NODE_TEX_IMAGE_BOX:
- svm_node_tex_image_box(kg, sd, stack, node);
- break;
- case NODE_TEX_NOISE:
- offset = svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_SET_BUMP:
- svm_node_set_bump<node_feature_mask>(kg, sd, stack, node);
- break;
- case NODE_ATTR_BUMP_DX:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- svm_node_attr_bump_dx(kg, sd, stack, node);
- }
- break;
- case NODE_ATTR_BUMP_DY:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- svm_node_attr_bump_dy(kg, sd, stack, node);
- }
- break;
- case NODE_VERTEX_COLOR_BUMP_DX:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- svm_node_vertex_color_bump_dx(kg, sd, stack, node.y, node.z, node.w);
- }
- break;
- case NODE_VERTEX_COLOR_BUMP_DY:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- svm_node_vertex_color_bump_dy(kg, sd, stack, node.y, node.z, node.w);
- }
- break;
- case NODE_TEX_COORD_BUMP_DX:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- offset = svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, offset);
- }
- break;
- case NODE_TEX_COORD_BUMP_DY:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- offset = svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, offset);
- }
- break;
- case NODE_CLOSURE_SET_NORMAL:
- IF_KERNEL_NODES_FEATURE(BUMP)
- {
- svm_node_set_normal(kg, sd, stack, node.y, node.z);
- }
- break;
- case NODE_ENTER_BUMP_EVAL:
- IF_KERNEL_NODES_FEATURE(BUMP_STATE)
- {
- svm_node_enter_bump_eval(kg, sd, stack, node.y);
- }
- break;
- case NODE_LEAVE_BUMP_EVAL:
- IF_KERNEL_NODES_FEATURE(BUMP_STATE)
- {
- svm_node_leave_bump_eval(kg, sd, stack, node.y);
- }
- break;
- case NODE_HSV:
- svm_node_hsv(kg, sd, stack, node);
- break;
-
- case NODE_CLOSURE_HOLDOUT:
- svm_node_closure_holdout(sd, stack, node);
- break;
- case NODE_FRESNEL:
- svm_node_fresnel(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_LAYER_WEIGHT:
- svm_node_layer_weight(sd, stack, node);
- break;
- case NODE_CLOSURE_VOLUME:
- IF_KERNEL_NODES_FEATURE(VOLUME)
- {
- svm_node_closure_volume<type>(kg, sd, stack, node);
- }
- break;
- case NODE_PRINCIPLED_VOLUME:
- IF_KERNEL_NODES_FEATURE(VOLUME)
- {
- offset = svm_node_principled_volume<type>(kg, sd, stack, node, path_flag, offset);
- }
- break;
- case NODE_MATH:
- svm_node_math(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_VECTOR_MATH:
- offset = svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_RGB_RAMP:
- offset = svm_node_rgb_ramp(kg, sd, stack, node, offset);
- break;
- case NODE_GAMMA:
- svm_node_gamma(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_BRIGHTCONTRAST:
- svm_node_brightness(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_LIGHT_PATH:
- svm_node_light_path<node_feature_mask>(kg, state, sd, stack, node.y, node.z, path_flag);
- break;
- case NODE_OBJECT_INFO:
- svm_node_object_info(kg, sd, stack, node.y, node.z);
- break;
- case NODE_PARTICLE_INFO:
- svm_node_particle_info(kg, sd, stack, node.y, node.z);
- break;
+ SVM_CASE(NODE_CLOSURE_BSDF)
+ offset = svm_node_closure_bsdf<node_feature_mask, type>(
+ kg, sd, stack, node, path_flag, offset);
+ break;
+ SVM_CASE(NODE_CLOSURE_EMISSION)
+ IF_KERNEL_NODES_FEATURE(EMISSION)
+ {
+ svm_node_closure_emission(sd, stack, node);
+ }
+ break;
+ SVM_CASE(NODE_CLOSURE_BACKGROUND)
+ IF_KERNEL_NODES_FEATURE(EMISSION)
+ {
+ svm_node_closure_background(sd, stack, node);
+ }
+ break;
+ SVM_CASE(NODE_CLOSURE_SET_WEIGHT)
+ svm_node_closure_set_weight(sd, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_CLOSURE_WEIGHT)
+ svm_node_closure_weight(sd, stack, node.y);
+ break;
+ SVM_CASE(NODE_EMISSION_WEIGHT)
+ IF_KERNEL_NODES_FEATURE(EMISSION)
+ {
+ svm_node_emission_weight(kg, sd, stack, node);
+ }
+ break;
+ SVM_CASE(NODE_MIX_CLOSURE)
+ svm_node_mix_closure(sd, stack, node);
+ break;
+ SVM_CASE(NODE_JUMP_IF_ZERO)
+ if (stack_load_float(stack, node.z) <= 0.0f)
+ offset += node.y;
+ break;
+ SVM_CASE(NODE_JUMP_IF_ONE)
+ if (stack_load_float(stack, node.z) >= 1.0f)
+ offset += node.y;
+ break;
+ SVM_CASE(NODE_GEOMETRY)
+ svm_node_geometry(kg, sd, stack, node.y, node.z);
+ break;
+ SVM_CASE(NODE_CONVERT)
+ svm_node_convert(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_TEX_COORD)
+ offset = svm_node_tex_coord(kg, sd, path_flag, stack, node, offset);
+ break;
+ SVM_CASE(NODE_VALUE_F)
+ svm_node_value_f(kg, sd, stack, node.y, node.z);
+ break;
+ SVM_CASE(NODE_VALUE_V)
+ offset = svm_node_value_v(kg, sd, stack, node.y, offset);
+ break;
+ SVM_CASE(NODE_ATTR)
+ svm_node_attr<node_feature_mask>(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_VERTEX_COLOR)
+ svm_node_vertex_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_GEOMETRY_BUMP_DX)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z);
+ }
+ break;
+ SVM_CASE(NODE_GEOMETRY_BUMP_DY)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ svm_node_geometry_bump_dy(kg, sd, stack, node.y, node.z);
+ }
+ break;
+ SVM_CASE(NODE_SET_DISPLACEMENT)
+ svm_node_set_displacement<node_feature_mask>(kg, sd, stack, node.y);
+ break;
+ SVM_CASE(NODE_DISPLACEMENT)
+ svm_node_displacement<node_feature_mask>(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_VECTOR_DISPLACEMENT)
+ offset = svm_node_vector_displacement<node_feature_mask>(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_TEX_IMAGE)
+ offset = svm_node_tex_image(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_TEX_IMAGE_BOX)
+ svm_node_tex_image_box(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_TEX_NOISE)
+ offset = svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_SET_BUMP)
+ svm_node_set_bump<node_feature_mask>(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_ATTR_BUMP_DX)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ svm_node_attr_bump_dx(kg, sd, stack, node);
+ }
+ break;
+ SVM_CASE(NODE_ATTR_BUMP_DY)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ svm_node_attr_bump_dy(kg, sd, stack, node);
+ }
+ break;
+ SVM_CASE(NODE_VERTEX_COLOR_BUMP_DX)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ svm_node_vertex_color_bump_dx(kg, sd, stack, node.y, node.z, node.w);
+ }
+ break;
+ SVM_CASE(NODE_VERTEX_COLOR_BUMP_DY)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ svm_node_vertex_color_bump_dy(kg, sd, stack, node.y, node.z, node.w);
+ }
+ break;
+ SVM_CASE(NODE_TEX_COORD_BUMP_DX)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ offset = svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, offset);
+ }
+ break;
+ SVM_CASE(NODE_TEX_COORD_BUMP_DY)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ offset = svm_node_tex_coord_bump_dy(kg, sd, path_flag, stack, node, offset);
+ }
+ break;
+ SVM_CASE(NODE_CLOSURE_SET_NORMAL)
+ IF_KERNEL_NODES_FEATURE(BUMP)
+ {
+ svm_node_set_normal(kg, sd, stack, node.y, node.z);
+ }
+ break;
+ SVM_CASE(NODE_ENTER_BUMP_EVAL)
+ IF_KERNEL_NODES_FEATURE(BUMP_STATE)
+ {
+ svm_node_enter_bump_eval(kg, sd, stack, node.y);
+ }
+ break;
+ SVM_CASE(NODE_LEAVE_BUMP_EVAL)
+ IF_KERNEL_NODES_FEATURE(BUMP_STATE)
+ {
+ svm_node_leave_bump_eval(kg, sd, stack, node.y);
+ }
+ break;
+ SVM_CASE(NODE_HSV)
+ svm_node_hsv(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_CLOSURE_HOLDOUT)
+ svm_node_closure_holdout(sd, stack, node);
+ break;
+ SVM_CASE(NODE_FRESNEL)
+ svm_node_fresnel(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_LAYER_WEIGHT)
+ svm_node_layer_weight(sd, stack, node);
+ break;
+ SVM_CASE(NODE_CLOSURE_VOLUME)
+ IF_KERNEL_NODES_FEATURE(VOLUME)
+ {
+ svm_node_closure_volume<type>(kg, sd, stack, node);
+ }
+ break;
+ SVM_CASE(NODE_PRINCIPLED_VOLUME)
+ IF_KERNEL_NODES_FEATURE(VOLUME)
+ {
+ offset = svm_node_principled_volume<type>(kg, sd, stack, node, path_flag, offset);
+ }
+ break;
+ SVM_CASE(NODE_MATH)
+ svm_node_math(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_VECTOR_MATH)
+ offset = svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_RGB_RAMP)
+ offset = svm_node_rgb_ramp(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_GAMMA)
+ svm_node_gamma(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_BRIGHTCONTRAST)
+ svm_node_brightness(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_LIGHT_PATH)
+ svm_node_light_path<node_feature_mask>(kg, state, sd, stack, node.y, node.z, path_flag);
+ break;
+ SVM_CASE(NODE_OBJECT_INFO)
+ svm_node_object_info(kg, sd, stack, node.y, node.z);
+ break;
+ SVM_CASE(NODE_PARTICLE_INFO)
+ svm_node_particle_info(kg, sd, stack, node.y, node.z);
+ break;
#if defined(__HAIR__)
- case NODE_HAIR_INFO:
- svm_node_hair_info(kg, sd, stack, node.y, node.z);
- break;
+ SVM_CASE(NODE_HAIR_INFO)
+ svm_node_hair_info(kg, sd, stack, node.y, node.z);
+ break;
#endif
#if defined(__POINTCLOUD__)
- case NODE_POINT_INFO:
- svm_node_point_info(kg, sd, stack, node.y, node.z);
- break;
+ SVM_CASE(NODE_POINT_INFO)
+ svm_node_point_info(kg, sd, stack, node.y, node.z);
+ break;
#endif
- case NODE_TEXTURE_MAPPING:
- offset = svm_node_texture_mapping(kg, sd, stack, node.y, node.z, offset);
- break;
- case NODE_MAPPING:
- svm_node_mapping(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_MIN_MAX:
- offset = svm_node_min_max(kg, sd, stack, node.y, node.z, offset);
- break;
- case NODE_CAMERA:
- svm_node_camera(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_TEX_ENVIRONMENT:
- svm_node_tex_environment(kg, sd, stack, node);
- break;
- case NODE_TEX_SKY:
- offset = svm_node_tex_sky(kg, sd, stack, node, offset);
- break;
- case NODE_TEX_GRADIENT:
- svm_node_tex_gradient(sd, stack, node);
- break;
- case NODE_TEX_VORONOI:
- offset = svm_node_tex_voronoi<node_feature_mask>(
- kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_TEX_MUSGRAVE:
- offset = svm_node_tex_musgrave(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_TEX_WAVE:
- offset = svm_node_tex_wave(kg, sd, stack, node, offset);
- break;
- case NODE_TEX_MAGIC:
- offset = svm_node_tex_magic(kg, sd, stack, node, offset);
- break;
- case NODE_TEX_CHECKER:
- svm_node_tex_checker(kg, sd, stack, node);
- break;
- case NODE_TEX_BRICK:
- offset = svm_node_tex_brick(kg, sd, stack, node, offset);
- break;
- case NODE_TEX_WHITE_NOISE:
- svm_node_tex_white_noise(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_NORMAL:
- offset = svm_node_normal(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_LIGHT_FALLOFF:
- svm_node_light_falloff(sd, stack, node);
- break;
- case NODE_IES:
- svm_node_ies(kg, sd, stack, node);
- break;
- case NODE_RGB_CURVES:
- case NODE_VECTOR_CURVES:
- offset = svm_node_curves(kg, sd, stack, node, offset);
- break;
- case NODE_FLOAT_CURVE:
- offset = svm_node_curve(kg, sd, stack, node, offset);
- break;
- case NODE_TANGENT:
- svm_node_tangent(kg, sd, stack, node);
- break;
- case NODE_NORMAL_MAP:
- svm_node_normal_map(kg, sd, stack, node);
- break;
- case NODE_INVERT:
- svm_node_invert(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_MIX:
- offset = svm_node_mix(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_SEPARATE_COLOR:
- svm_node_separate_color(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_COMBINE_COLOR:
- svm_node_combine_color(kg, sd, stack, node.y, node.z, node.w);
- break;
- case NODE_SEPARATE_VECTOR:
- svm_node_separate_vector(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_COMBINE_VECTOR:
- svm_node_combine_vector(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_SEPARATE_HSV:
- offset = svm_node_separate_hsv(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_COMBINE_HSV:
- offset = svm_node_combine_hsv(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_VECTOR_ROTATE:
- svm_node_vector_rotate(sd, stack, node.y, node.z, node.w);
- break;
- case NODE_VECTOR_TRANSFORM:
- svm_node_vector_transform(kg, sd, stack, node);
- break;
- case NODE_WIREFRAME:
- svm_node_wireframe(kg, sd, stack, node);
- break;
- case NODE_WAVELENGTH:
- svm_node_wavelength(kg, sd, stack, node.y, node.z);
- break;
- case NODE_BLACKBODY:
- svm_node_blackbody(kg, sd, stack, node.y, node.z);
- break;
- case NODE_MAP_RANGE:
- offset = svm_node_map_range(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_VECTOR_MAP_RANGE:
- offset = svm_node_vector_map_range(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
- case NODE_CLAMP:
- offset = svm_node_clamp(kg, sd, stack, node.y, node.z, node.w, offset);
- break;
+ SVM_CASE(NODE_TEXTURE_MAPPING)
+ offset = svm_node_texture_mapping(kg, sd, stack, node.y, node.z, offset);
+ break;
+ SVM_CASE(NODE_MAPPING)
+ svm_node_mapping(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_MIN_MAX)
+ offset = svm_node_min_max(kg, sd, stack, node.y, node.z, offset);
+ break;
+ SVM_CASE(NODE_CAMERA)
+ svm_node_camera(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_TEX_ENVIRONMENT)
+ svm_node_tex_environment(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_TEX_SKY)
+ offset = svm_node_tex_sky(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_TEX_GRADIENT)
+ svm_node_tex_gradient(sd, stack, node);
+ break;
+ SVM_CASE(NODE_TEX_VORONOI)
+ offset = svm_node_tex_voronoi<node_feature_mask>(
+ kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_TEX_MUSGRAVE)
+ offset = svm_node_tex_musgrave(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_TEX_WAVE)
+ offset = svm_node_tex_wave(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_TEX_MAGIC)
+ offset = svm_node_tex_magic(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_TEX_CHECKER)
+ svm_node_tex_checker(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_TEX_BRICK)
+ offset = svm_node_tex_brick(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_TEX_WHITE_NOISE)
+ svm_node_tex_white_noise(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_NORMAL)
+ offset = svm_node_normal(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_LIGHT_FALLOFF)
+ svm_node_light_falloff(sd, stack, node);
+ break;
+ SVM_CASE(NODE_IES)
+ svm_node_ies(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_CURVES)
+ offset = svm_node_curves(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_FLOAT_CURVE)
+ offset = svm_node_curve(kg, sd, stack, node, offset);
+ break;
+ SVM_CASE(NODE_TANGENT)
+ svm_node_tangent(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_NORMAL_MAP)
+ svm_node_normal_map(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_INVERT)
+ svm_node_invert(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_MIX)
+ offset = svm_node_mix(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_SEPARATE_COLOR)
+ svm_node_separate_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_COMBINE_COLOR)
+ svm_node_combine_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_SEPARATE_VECTOR)
+ svm_node_separate_vector(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_COMBINE_VECTOR)
+ svm_node_combine_vector(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_SEPARATE_HSV)
+ offset = svm_node_separate_hsv(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_COMBINE_HSV)
+ offset = svm_node_combine_hsv(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_VECTOR_ROTATE)
+ svm_node_vector_rotate(sd, stack, node.y, node.z, node.w);
+ break;
+ SVM_CASE(NODE_VECTOR_TRANSFORM)
+ svm_node_vector_transform(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_WIREFRAME)
+ svm_node_wireframe(kg, sd, stack, node);
+ break;
+ SVM_CASE(NODE_WAVELENGTH)
+ svm_node_wavelength(kg, sd, stack, node.y, node.z);
+ break;
+ SVM_CASE(NODE_BLACKBODY)
+ svm_node_blackbody(kg, sd, stack, node.y, node.z);
+ break;
+ SVM_CASE(NODE_MAP_RANGE)
+ offset = svm_node_map_range(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_VECTOR_MAP_RANGE)
+ offset = svm_node_vector_map_range(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
+ SVM_CASE(NODE_CLAMP)
+ offset = svm_node_clamp(kg, sd, stack, node.y, node.z, node.w, offset);
+ break;
#ifdef __SHADER_RAYTRACE__
- case NODE_BEVEL:
- svm_node_bevel<node_feature_mask>(kg, state, sd, stack, node);
- break;
- case NODE_AMBIENT_OCCLUSION:
- svm_node_ao<node_feature_mask>(kg, state, sd, stack, node);
- break;
+ SVM_CASE(NODE_BEVEL)
+ svm_node_bevel<node_feature_mask>(kg, state, sd, stack, node);
+ break;
+ SVM_CASE(NODE_AMBIENT_OCCLUSION)
+ svm_node_ao<node_feature_mask>(kg, state, sd, stack, node);
+ break;
#endif
- case NODE_TEX_VOXEL:
- IF_KERNEL_NODES_FEATURE(VOLUME)
- {
- offset = svm_node_tex_voxel(kg, sd, stack, node, offset);
- }
- break;
- case NODE_AOV_START:
- if (!svm_node_aov_check(path_flag, render_buffer)) {
- return;
- }
- break;
- case NODE_AOV_COLOR:
- svm_node_aov_color<node_feature_mask>(kg, state, sd, stack, node, render_buffer);
- break;
- case NODE_AOV_VALUE:
- svm_node_aov_value<node_feature_mask>(kg, state, sd, stack, node, render_buffer);
- break;
+ SVM_CASE(NODE_TEX_VOXEL)
+ IF_KERNEL_NODES_FEATURE(VOLUME)
+ {
+ offset = svm_node_tex_voxel(kg, sd, stack, node, offset);
+ }
+ break;
+ SVM_CASE(NODE_AOV_START)
+ if (!svm_node_aov_check(path_flag, render_buffer)) {
+ return;
+ }
+ break;
+ SVM_CASE(NODE_AOV_COLOR)
+ svm_node_aov_color<node_feature_mask>(kg, state, sd, stack, node, render_buffer);
+ break;
+ SVM_CASE(NODE_AOV_VALUE)
+ svm_node_aov_value<node_feature_mask>(kg, state, sd, stack, node, render_buffer);
+ break;
default:
kernel_assert(!"Unknown node type was passed to the SVM machine");
return;
diff --git a/intern/cycles/kernel/svm/tex_coord.h b/intern/cycles/kernel/svm/tex_coord.h
index d9138796c45..2a0130e11d4 100644
--- a/intern/cycles/kernel/svm/tex_coord.h
+++ b/intern/cycles/kernel/svm/tex_coord.h
@@ -138,7 +138,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dx(KernelGlobals kg,
case NODE_TEXCO_WINDOW: {
if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
- data = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(sd->ray_dP, 0.0f, 0.0f));
+ data = camera_world_to_ndc(kg, sd, sd->ray_P);
else
data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx);
data.z = 0.0f;
@@ -223,7 +223,7 @@ ccl_device_noinline int svm_node_tex_coord_bump_dy(KernelGlobals kg,
case NODE_TEXCO_WINDOW: {
if ((path_flag & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE &&
kernel_data.cam.type == CAMERA_ORTHOGRAPHIC)
- data = camera_world_to_ndc(kg, sd, sd->ray_P + make_float3(0.0f, sd->ray_dP, 0.0f));
+ data = camera_world_to_ndc(kg, sd, sd->ray_P);
else
data = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy);
data.z = 0.0f;
diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h
index 82109ec4c4f..12d0ec141e6 100644
--- a/intern/cycles/kernel/svm/types.h
+++ b/intern/cycles/kernel/svm/types.h
@@ -17,104 +17,9 @@ CCL_NAMESPACE_BEGIN
/* Nodes */
typedef enum ShaderNodeType {
- NODE_END = 0,
- NODE_SHADER_JUMP,
- NODE_CLOSURE_BSDF,
- NODE_CLOSURE_EMISSION,
- NODE_CLOSURE_BACKGROUND,
- NODE_CLOSURE_SET_WEIGHT,
- NODE_CLOSURE_WEIGHT,
- NODE_EMISSION_WEIGHT,
- NODE_MIX_CLOSURE,
- NODE_JUMP_IF_ZERO,
- NODE_JUMP_IF_ONE,
- NODE_GEOMETRY,
- NODE_CONVERT,
- NODE_TEX_COORD,
- NODE_VALUE_F,
- NODE_VALUE_V,
- NODE_ATTR,
- NODE_VERTEX_COLOR,
- NODE_GEOMETRY_BUMP_DX,
- NODE_GEOMETRY_BUMP_DY,
- NODE_SET_DISPLACEMENT,
- NODE_DISPLACEMENT,
- NODE_VECTOR_DISPLACEMENT,
- NODE_TEX_IMAGE,
- NODE_TEX_IMAGE_BOX,
- NODE_TEX_NOISE,
- NODE_SET_BUMP,
- NODE_ATTR_BUMP_DX,
- NODE_ATTR_BUMP_DY,
- NODE_VERTEX_COLOR_BUMP_DX,
- NODE_VERTEX_COLOR_BUMP_DY,
- NODE_TEX_COORD_BUMP_DX,
- NODE_TEX_COORD_BUMP_DY,
- NODE_CLOSURE_SET_NORMAL,
- NODE_ENTER_BUMP_EVAL,
- NODE_LEAVE_BUMP_EVAL,
- NODE_HSV,
- NODE_CLOSURE_HOLDOUT,
- NODE_FRESNEL,
- NODE_LAYER_WEIGHT,
- NODE_CLOSURE_VOLUME,
- NODE_PRINCIPLED_VOLUME,
- NODE_MATH,
- NODE_VECTOR_MATH,
- NODE_RGB_RAMP,
- NODE_GAMMA,
- NODE_BRIGHTCONTRAST,
- NODE_LIGHT_PATH,
- NODE_OBJECT_INFO,
- NODE_PARTICLE_INFO,
- NODE_HAIR_INFO,
- NODE_POINT_INFO,
- NODE_TEXTURE_MAPPING,
- NODE_MAPPING,
- NODE_MIN_MAX,
- NODE_CAMERA,
- NODE_TEX_ENVIRONMENT,
- NODE_TEX_SKY,
- NODE_TEX_GRADIENT,
- NODE_TEX_VORONOI,
- NODE_TEX_MUSGRAVE,
- NODE_TEX_WAVE,
- NODE_TEX_MAGIC,
- NODE_TEX_CHECKER,
- NODE_TEX_BRICK,
- NODE_TEX_WHITE_NOISE,
- NODE_NORMAL,
- NODE_LIGHT_FALLOFF,
- NODE_IES,
- NODE_RGB_CURVES,
- NODE_VECTOR_CURVES,
- NODE_TANGENT,
- NODE_NORMAL_MAP,
- NODE_INVERT,
- NODE_MIX,
- NODE_SEPARATE_COLOR,
- NODE_COMBINE_COLOR,
- NODE_SEPARATE_VECTOR,
- NODE_COMBINE_VECTOR,
- NODE_SEPARATE_HSV,
- NODE_COMBINE_HSV,
- NODE_VECTOR_ROTATE,
- NODE_VECTOR_TRANSFORM,
- NODE_WIREFRAME,
- NODE_WAVELENGTH,
- NODE_BLACKBODY,
- NODE_MAP_RANGE,
- NODE_VECTOR_MAP_RANGE,
- NODE_CLAMP,
- NODE_BEVEL,
- NODE_AMBIENT_OCCLUSION,
- NODE_TEX_VOXEL,
- NODE_AOV_START,
- NODE_AOV_COLOR,
- NODE_AOV_VALUE,
- NODE_FLOAT_CURVE,
- /* NOTE: for best OpenCL performance, item definition in the enum must
- * match the switch case order in `svm.h`. */
+#define SHADER_NODE_TYPE(name) name,
+#include "node_types_template.h"
+ NODE_NUM
} ShaderNodeType;
typedef enum NodeAttributeOutputType {
diff --git a/intern/cycles/kernel/svm/voronoi.h b/intern/cycles/kernel/svm/voronoi.h
index 4ff1047aab7..53c1bda0904 100644
--- a/intern/cycles/kernel/svm/voronoi.h
+++ b/intern/cycles/kernel/svm/voronoi.h
@@ -1079,7 +1079,7 @@ ccl_device_noinline int svm_node_tex_voronoi(KernelGlobals kg,
default:
kernel_assert(0);
}
- position_out = safe_divide_float3_float(position_out, scale);
+ position_out = safe_divide(position_out, scale);
break;
}
@@ -1126,7 +1126,7 @@ ccl_device_noinline int svm_node_tex_voronoi(KernelGlobals kg,
default:
kernel_assert(0);
}
- position_out_4d = safe_divide_float4_float(position_out_4d, scale);
+ position_out_4d = safe_divide(position_out_4d, scale);
position_out = make_float3(position_out_4d.x, position_out_4d.y, position_out_4d.z);
w_out = position_out_4d.w;
}
diff --git a/intern/cycles/kernel/textures.h b/intern/cycles/kernel/textures.h
deleted file mode 100644
index 7deb589a0a9..00000000000
--- a/intern/cycles/kernel/textures.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* SPDX-License-Identifier: Apache-2.0
- * Copyright 2011-2022 Blender Foundation */
-
-#ifndef KERNEL_TEX
-# define KERNEL_TEX(type, name)
-#endif
-
-/* BVH2, not used for OptiX or Embree. */
-KERNEL_TEX(float4, __bvh_nodes)
-KERNEL_TEX(float4, __bvh_leaf_nodes)
-KERNEL_TEX(uint, __prim_type)
-KERNEL_TEX(uint, __prim_visibility)
-KERNEL_TEX(uint, __prim_index)
-KERNEL_TEX(uint, __prim_object)
-KERNEL_TEX(uint, __object_node)
-KERNEL_TEX(float2, __prim_time)
-
-/* objects */
-KERNEL_TEX(KernelObject, __objects)
-KERNEL_TEX(Transform, __object_motion_pass)
-KERNEL_TEX(DecomposedTransform, __object_motion)
-KERNEL_TEX(uint, __object_flag)
-KERNEL_TEX(float, __object_volume_step)
-KERNEL_TEX(uint, __object_prim_offset)
-
-/* cameras */
-KERNEL_TEX(DecomposedTransform, __camera_motion)
-
-/* triangles */
-KERNEL_TEX(uint, __tri_shader)
-KERNEL_TEX(packed_float3, __tri_vnormal)
-KERNEL_TEX(uint4, __tri_vindex)
-KERNEL_TEX(uint, __tri_patch)
-KERNEL_TEX(float2, __tri_patch_uv)
-KERNEL_TEX(packed_float3, __tri_verts)
-
-/* curves */
-KERNEL_TEX(KernelCurve, __curves)
-KERNEL_TEX(float4, __curve_keys)
-KERNEL_TEX(KernelCurveSegment, __curve_segments)
-
-/* patches */
-KERNEL_TEX(uint, __patches)
-
-/* pointclouds */
-KERNEL_TEX(float4, __points)
-KERNEL_TEX(uint, __points_shader)
-
-/* attributes */
-KERNEL_TEX(uint4, __attributes_map)
-KERNEL_TEX(float, __attributes_float)
-KERNEL_TEX(float2, __attributes_float2)
-KERNEL_TEX(packed_float3, __attributes_float3)
-KERNEL_TEX(float4, __attributes_float4)
-KERNEL_TEX(uchar4, __attributes_uchar4)
-
-/* lights */
-KERNEL_TEX(KernelLightDistribution, __light_distribution)
-KERNEL_TEX(KernelLight, __lights)
-KERNEL_TEX(float2, __light_background_marginal_cdf)
-KERNEL_TEX(float2, __light_background_conditional_cdf)
-
-/* particles */
-KERNEL_TEX(KernelParticle, __particles)
-
-/* shaders */
-KERNEL_TEX(uint4, __svm_nodes)
-KERNEL_TEX(KernelShader, __shaders)
-
-/* lookup tables */
-KERNEL_TEX(float, __lookup_table)
-
-/* sobol */
-KERNEL_TEX(float, __sample_pattern_lut)
-
-/* image textures */
-KERNEL_TEX(TextureInfo, __texture_info)
-
-/* ies lights */
-KERNEL_TEX(float, __ies)
-
-#undef KERNEL_TEX
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 01df7948241..05320deed19 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -535,7 +535,8 @@ typedef struct RaySelfPrimitives {
typedef struct Ray {
float3 P; /* origin */
float3 D; /* direction */
- float t; /* length of the ray */
+ float tmin; /* start distance */
+ float tmax; /* end distance */
float time; /* time (for motion blur) */
RaySelfPrimitives self;
@@ -670,6 +671,16 @@ typedef struct AttributeDescriptor {
int offset;
} AttributeDescriptor;
+/* For looking up attributes on objects and geometry. */
+typedef struct AttributeMap {
+ uint id; /* Global unique identifier. */
+ uint element; /* AttributeElement. */
+ int offset; /* Offset into __attributes global arrays. */
+ uint8_t type; /* NodeAttributeType. */
+ uint8_t flags; /* AttributeFlag. */
+ uint8_t pad[2];
+} AttributeMap;
+
/* Closure data */
#ifndef __MAX_CLOSURE__
@@ -1062,94 +1073,6 @@ typedef struct KernelCamera {
} KernelCamera;
static_assert_align(KernelCamera, 16);
-typedef struct KernelFilm {
- float exposure;
- int pass_flag;
-
- int light_pass_flag;
- int pass_stride;
-
- int pass_combined;
- int pass_depth;
- int pass_position;
- int pass_normal;
- int pass_roughness;
- int pass_motion;
-
- int pass_motion_weight;
- int pass_uv;
- int pass_object_id;
- int pass_material_id;
-
- int pass_diffuse_color;
- int pass_glossy_color;
- int pass_transmission_color;
-
- int pass_diffuse_indirect;
- int pass_glossy_indirect;
- int pass_transmission_indirect;
- int pass_volume_indirect;
-
- int pass_diffuse_direct;
- int pass_glossy_direct;
- int pass_transmission_direct;
- int pass_volume_direct;
-
- int pass_emission;
- int pass_background;
- int pass_ao;
- float pass_alpha_threshold;
-
- int pass_shadow;
- float pass_shadow_scale;
-
- int pass_shadow_catcher;
- int pass_shadow_catcher_sample_count;
- int pass_shadow_catcher_matte;
-
- int filter_table_offset;
-
- int cryptomatte_passes;
- int cryptomatte_depth;
- int pass_cryptomatte;
-
- int pass_adaptive_aux_buffer;
- int pass_sample_count;
-
- int pass_mist;
- float mist_start;
- float mist_inv_depth;
- float mist_falloff;
-
- int pass_denoising_normal;
- int pass_denoising_albedo;
- int pass_denoising_depth;
-
- int pass_aov_color;
- int pass_aov_value;
- int pass_lightgroup;
-
- /* XYZ to rendering color space transform. float4 instead of float3 to
- * ensure consistent padding/alignment across devices. */
- float4 xyz_to_r;
- float4 xyz_to_g;
- float4 xyz_to_b;
- float4 rgb_to_y;
- /* Rec709 to rendering color space. */
- float4 rec709_to_r;
- float4 rec709_to_g;
- float4 rec709_to_b;
- int is_rec709;
-
- int pass_bake_primitive;
- int pass_bake_differential;
-
- int use_approximate_shadow_catcher;
-
- int pad1;
-} KernelFilm;
-static_assert_align(KernelFilm, 16);
-
typedef struct KernelFilmConvert {
int pass_offset;
int pass_stride;
@@ -1191,108 +1114,6 @@ typedef struct KernelFilmConvert {
} KernelFilmConvert;
static_assert_align(KernelFilmConvert, 16);
-typedef struct KernelBackground {
- /* only shader index */
- int surface_shader;
- int volume_shader;
- float volume_step_size;
- int transparent;
- float transparent_roughness_squared_threshold;
-
- /* portal sampling */
- float portal_weight;
- int num_portals;
- int portal_offset;
-
- /* sun sampling */
- float sun_weight;
- /* xyz store direction, w the angle. float4 instead of float3 is used
- * to ensure consistent padding/alignment across devices. */
- float4 sun;
-
- /* map sampling */
- float map_weight;
- int map_res_x;
- int map_res_y;
-
- int use_mis;
-
- int lightgroup;
-
- /* Padding */
- int pad1, pad2;
-} KernelBackground;
-static_assert_align(KernelBackground, 16);
-
-typedef struct KernelIntegrator {
- /* emission */
- int use_direct_light;
- int num_distribution;
- int num_all_lights;
- float pdf_triangles;
- float pdf_lights;
- float light_inv_rr_threshold;
-
- /* bounces */
- int min_bounce;
- int max_bounce;
-
- int max_diffuse_bounce;
- int max_glossy_bounce;
- int max_transmission_bounce;
- int max_volume_bounce;
-
- /* AO bounces */
- int ao_bounces;
- float ao_bounces_distance;
- float ao_bounces_factor;
- float ao_additive_factor;
-
- /* transparent */
- int transparent_min_bounce;
- int transparent_max_bounce;
- int transparent_shadows;
-
- /* caustics */
- int caustics_reflective;
- int caustics_refractive;
- float filter_glossy;
-
- /* seed */
- int seed;
-
- /* clamp */
- float sample_clamp_direct;
- float sample_clamp_indirect;
-
- /* mis */
- int use_lamp_mis;
-
- /* caustics */
- int use_caustics;
-
- /* sampler */
- int sampling_pattern;
-
- /* volume render */
- int use_volumes;
- int volume_max_steps;
- float volume_step_rate;
-
- int has_shadow_catcher;
- float scrambling_distance;
-
- /* Closure filter. */
- int filter_closures;
-
- /* MIS debugging. */
- int direct_light_sampling_type;
-
- /* padding */
- int pad1;
-} KernelIntegrator;
-static_assert_align(KernelIntegrator, 16);
-
typedef enum KernelBVHLayout {
BVH_LAYOUT_NONE = 0,
@@ -1310,36 +1131,25 @@ typedef enum KernelBVHLayout {
BVH_LAYOUT_ALL = BVH_LAYOUT_BVH2 | BVH_LAYOUT_EMBREE | BVH_LAYOUT_OPTIX | BVH_LAYOUT_METAL,
} KernelBVHLayout;
-typedef struct KernelBVH {
- /* Own BVH */
- int root;
- int have_motion;
- int have_curves;
- int bvh_layout;
- int use_bvh_steps;
- int curve_subdivisions;
+/* Specialized struct that can become constants in dynamic compilation. */
+#define KERNEL_STRUCT_BEGIN(name, parent) struct name {
+#define KERNEL_STRUCT_END(name) \
+ } \
+ ; \
+ static_assert_align(name, 16);
- /* Custom BVH */
-#ifdef __KERNEL_OPTIX__
- OptixTraversableHandle scene;
-#elif defined __METALRT__
- metalrt_as_type scene;
+#ifdef __KERNEL_USE_DATA_CONSTANTS__
+# define KERNEL_STRUCT_MEMBER(parent, type, name) type __unused_##name;
#else
-# ifdef __EMBREE__
- RTCScene scene;
-# ifndef __KERNEL_64_BIT__
- int pad2;
-# endif
-# else
- int scene, pad2;
-# endif
+# define KERNEL_STRUCT_MEMBER(parent, type, name) type name;
#endif
-} KernelBVH;
-static_assert_align(KernelBVH, 16);
+
+#include "kernel/data_template.h"
typedef struct KernelTables {
int beckmann_offset;
- int pad1, pad2, pad3;
+ int filter_table_offset;
+ int pad1, pad2;
} KernelTables;
static_assert_align(KernelTables, 16);
@@ -1352,18 +1162,37 @@ typedef struct KernelBake {
static_assert_align(KernelBake, 16);
typedef struct KernelData {
+ /* Features and limits. */
uint kernel_features;
uint max_closures;
uint max_shaders;
uint volume_stack_size;
+ /* Always dynamic data mambers. */
KernelCamera cam;
- KernelFilm film;
- KernelBackground background;
- KernelIntegrator integrator;
- KernelBVH bvh;
- KernelTables tables;
KernelBake bake;
+ KernelTables tables;
+
+ /* Potentially specialized data members. */
+#define KERNEL_STRUCT_BEGIN(name, parent) name parent;
+#include "kernel/data_template.h"
+
+ /* Device specific BVH. */
+#ifdef __KERNEL_OPTIX__
+ OptixTraversableHandle device_bvh;
+#elif defined __METALRT__
+ metalrt_as_type device_bvh;
+#else
+# ifdef __EMBREE__
+ RTCScene device_bvh;
+# ifndef __KERNEL_64_BIT__
+ int pad1;
+# endif
+# else
+ int device_bvh, pad1;
+# endif
+#endif
+ int pad2, pad3;
} KernelData;
static_assert_align(KernelData, 16);
@@ -1561,7 +1390,7 @@ static_assert_align(KernelShaderEvalInput, 16);
* If the kernel uses shared CUDA memory, `CUDADeviceQueue::enqueue` is to be modified.
* The path iteration kernels are handled in `PathTraceWorkGPU::enqueue_path_iteration`. */
-typedef enum DeviceKernel {
+typedef enum DeviceKernel : int {
DEVICE_KERNEL_INTEGRATOR_INIT_FROM_CAMERA = 0,
DEVICE_KERNEL_INTEGRATOR_INIT_FROM_BAKE,
DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST,
@@ -1572,6 +1401,7 @@ typedef enum DeviceKernel {
DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT,
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE,
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE,
+ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE,
DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME,
DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW,
DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL,
@@ -1689,6 +1519,9 @@ enum KernelFeatureFlag : uint32_t {
KERNEL_FEATURE_AO_PASS = (1U << 25U),
KERNEL_FEATURE_AO_ADDITIVE = (1U << 26U),
KERNEL_FEATURE_AO = (KERNEL_FEATURE_AO_PASS | KERNEL_FEATURE_AO_ADDITIVE),
+
+ /* MNEE. */
+ KERNEL_FEATURE_MNEE = (1U << 27U),
};
/* Shader node feature mask, to specialize shader evaluation for kernels. */
@@ -1696,6 +1529,8 @@ enum KernelFeatureFlag : uint32_t {
#define KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT \
(KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VORONOI_EXTRA | \
KERNEL_FEATURE_NODE_LIGHT_PATH)
+#define KERNEL_FEATURE_NODE_MASK_SURFACE_BACKGROUND \
+ (KERNEL_FEATURE_NODE_MASK_SURFACE_LIGHT | KERNEL_FEATURE_NODE_AOV)
#define KERNEL_FEATURE_NODE_MASK_SURFACE_SHADOW \
(KERNEL_FEATURE_NODE_BSDF | KERNEL_FEATURE_NODE_EMISSION | KERNEL_FEATURE_NODE_VOLUME | \
KERNEL_FEATURE_NODE_BUMP | KERNEL_FEATURE_NODE_BUMP_STATE | \
@@ -1714,9 +1549,12 @@ enum KernelFeatureFlag : uint32_t {
* are different depending on the main, shadow or null path. For GPU we don't have
* C++17 everywhere so can't use it. */
#ifdef __KERNEL_CPU__
+# define IF_KERNEL_FEATURE(feature) \
+ if constexpr ((node_feature_mask & (KERNEL_FEATURE_##feature)) != 0U)
# define IF_KERNEL_NODES_FEATURE(feature) \
if constexpr ((node_feature_mask & (KERNEL_FEATURE_NODE_##feature)) != 0U)
#else
+# define IF_KERNEL_FEATURE(feature) if ((node_feature_mask & (KERNEL_FEATURE_##feature)) != 0U)
# define IF_KERNEL_NODES_FEATURE(feature) \
if ((node_feature_mask & (KERNEL_FEATURE_NODE_##feature)) != 0U)
#endif
diff --git a/intern/cycles/kernel/util/lookup_table.h b/intern/cycles/kernel/util/lookup_table.h
index e19e2ce5bd1..4db4dadab0e 100644
--- a/intern/cycles/kernel/util/lookup_table.h
+++ b/intern/cycles/kernel/util/lookup_table.h
@@ -15,11 +15,11 @@ ccl_device float lookup_table_read(KernelGlobals kg, float x, int offset, int si
int nindex = min(index + 1, size - 1);
float t = x - index;
- float data0 = kernel_tex_fetch(__lookup_table, index + offset);
+ float data0 = kernel_data_fetch(lookup_table, index + offset);
if (t == 0.0f)
return data0;
- float data1 = kernel_tex_fetch(__lookup_table, nindex + offset);
+ float data1 = kernel_data_fetch(lookup_table, nindex + offset);
return (1.0f - t) * data0 + t * data1;
}
diff --git a/intern/cycles/scene/alembic.cpp b/intern/cycles/scene/alembic.cpp
index c1e2d306fcc..e6f39bf8625 100644
--- a/intern/cycles/scene/alembic.cpp
+++ b/intern/cycles/scene/alembic.cpp
@@ -1514,7 +1514,7 @@ void AlembicProcedural::build_caches(Progress &progress)
}
}
- VLOG(1) << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used);
+ VLOG_WORK << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp
index df01189a54b..d6b4c0240f6 100644
--- a/intern/cycles/scene/attribute.cpp
+++ b/intern/cycles/scene/attribute.cpp
@@ -661,6 +661,26 @@ Attribute *AttributeSet::find(AttributeStandard std) const
return NULL;
}
+Attribute *AttributeSet::find_matching(const Attribute &other)
+{
+ for (Attribute &attr : attributes) {
+ if (attr.name != other.name) {
+ continue;
+ }
+ if (attr.std != other.std) {
+ continue;
+ }
+ if (attr.type != other.type) {
+ continue;
+ }
+ if (attr.element != other.element) {
+ continue;
+ }
+ return &attr;
+ }
+ return nullptr;
+}
+
void AttributeSet::remove(AttributeStandard std)
{
Attribute *attr = find(std);
@@ -729,32 +749,24 @@ void AttributeSet::clear(bool preserve_voxel_data)
void AttributeSet::update(AttributeSet &&new_attributes)
{
- /* add or update old_attributes based on the new_attributes */
- foreach (Attribute &attr, new_attributes.attributes) {
- Attribute *nattr = add(attr.name, attr.type, attr.element);
- nattr->std = attr.std;
- nattr->set_data_from(std::move(attr));
- }
-
- /* remove any attributes not on new_attributes */
+ /* Remove any attributes not on new_attributes. */
list<Attribute>::iterator it;
for (it = attributes.begin(); it != attributes.end();) {
- if (it->std != ATTR_STD_NONE) {
- if (new_attributes.find(it->std) == nullptr) {
- remove(it++);
- continue;
- }
- }
- else if (it->name != "") {
- if (new_attributes.find(it->name) == nullptr) {
- remove(it++);
- continue;
- }
+ const Attribute &old_attr = *it;
+ if (new_attributes.find_matching(old_attr) == nullptr) {
+ remove(it++);
+ continue;
}
-
it++;
}
+ /* Add or update old_attributes based on the new_attributes. */
+ foreach (Attribute &attr, new_attributes.attributes) {
+ Attribute *nattr = add(attr.name, attr.type, attr.element);
+ nattr->std = attr.std;
+ nattr->set_data_from(std::move(attr));
+ }
+
/* If all attributes were replaced, transform is no longer applied. */
geometry->transform_applied = false;
}
diff --git a/intern/cycles/scene/attribute.h b/intern/cycles/scene/attribute.h
index fd13b8ff6de..7f8cbf32049 100644
--- a/intern/cycles/scene/attribute.h
+++ b/intern/cycles/scene/attribute.h
@@ -194,6 +194,7 @@ class AttributeSet {
void remove(AttributeStandard std);
Attribute *find(AttributeRequest &req);
+ Attribute *find_matching(const Attribute &other);
void remove(Attribute *attribute);
diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp
index 710f1c5ee90..eec269ab542 100644
--- a/intern/cycles/scene/camera.cpp
+++ b/intern/cycles/scene/camera.cpp
@@ -530,7 +530,7 @@ void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scen
if (object->get_geometry()->has_volume &&
viewplane_boundbox.intersects(object->bounds)) {
/* TODO(sergey): Consider adding more grained check. */
- VLOG(1) << "Detected camera inside volume.";
+ VLOG_INFO << "Detected camera inside volume.";
kcam->is_inside_volume = 1;
parallel_for_cancel();
break;
@@ -539,7 +539,7 @@ void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scen
});
if (!kcam->is_inside_volume) {
- VLOG(1) << "Camera is outside of the volume.";
+ VLOG_INFO << "Camera is outside of the volume.";
}
}
diff --git a/intern/cycles/scene/colorspace.cpp b/intern/cycles/scene/colorspace.cpp
index f87b4c62ab2..189e3bc752d 100644
--- a/intern/cycles/scene/colorspace.cpp
+++ b/intern/cycles/scene/colorspace.cpp
@@ -55,8 +55,8 @@ ColorSpaceProcessor *ColorSpaceManager::get_processor(ustring colorspace)
}
catch (OCIO::Exception &exception) {
cached_processors[colorspace] = OCIO::ConstProcessorRcPtr();
- VLOG(1) << "Colorspace " << colorspace.c_str()
- << " can't be converted to scene_linear: " << exception.what();
+ VLOG_WARNING << "Colorspace " << colorspace.c_str()
+ << " can't be converted to scene_linear: " << exception.what();
}
}
@@ -132,12 +132,12 @@ ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace,
thread_scoped_lock cache_lock(cache_colorspaces_mutex);
if (is_scene_linear) {
- VLOG(1) << "Colorspace " << colorspace.string() << " is no-op";
+ VLOG_INFO << "Colorspace " << colorspace.string() << " is no-op";
cached_colorspaces[colorspace] = u_colorspace_raw;
return u_colorspace_raw;
}
else if (is_srgb) {
- VLOG(1) << "Colorspace " << colorspace.string() << " is sRGB";
+ VLOG_INFO << "Colorspace " << colorspace.string() << " is sRGB";
cached_colorspaces[colorspace] = u_colorspace_srgb;
return u_colorspace_srgb;
}
@@ -146,22 +146,23 @@ ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace,
if (!get_processor(colorspace)) {
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
if (!config || !config->getColorSpace(colorspace.c_str())) {
- VLOG(1) << "Colorspace " << colorspace.c_str() << " not found, using raw instead";
+ VLOG_WARNING << "Colorspace " << colorspace.c_str() << " not found, using raw instead";
}
else {
- VLOG(1) << "Colorspace " << colorspace.c_str()
- << " can't be converted to scene_linear, using raw instead";
+ VLOG_WARNING << "Colorspace " << colorspace.c_str()
+ << " can't be converted to scene_linear, using raw instead";
}
cached_colorspaces[colorspace] = u_colorspace_raw;
return u_colorspace_raw;
}
/* Convert to/from colorspace with OpenColorIO. */
- VLOG(1) << "Colorspace " << colorspace.string() << " handled through OpenColorIO";
+ VLOG_INFO << "Colorspace " << colorspace.string() << " handled through OpenColorIO";
cached_colorspaces[colorspace] = colorspace;
return colorspace;
#else
- VLOG(1) << "Colorspace " << colorspace.c_str() << " not available, built without OpenColorIO";
+ VLOG_WARNING << "Colorspace " << colorspace.c_str()
+ << " not available, built without OpenColorIO";
return u_colorspace_raw;
#endif
}
diff --git a/intern/cycles/scene/constant_fold.cpp b/intern/cycles/scene/constant_fold.cpp
index 46ffbe9043a..4bce5661f9b 100644
--- a/intern/cycles/scene/constant_fold.cpp
+++ b/intern/cycles/scene/constant_fold.cpp
@@ -30,8 +30,8 @@ bool ConstantFolder::all_inputs_constant() const
void ConstantFolder::make_constant(float value) const
{
- VLOG(3) << "Folding " << node->name << "::" << output->name() << " to constant (" << value
- << ").";
+ VLOG_DEBUG << "Folding " << node->name << "::" << output->name() << " to constant (" << value
+ << ").";
foreach (ShaderInput *sock, output->links) {
sock->set(value);
@@ -43,7 +43,8 @@ void ConstantFolder::make_constant(float value) const
void ConstantFolder::make_constant(float3 value) const
{
- VLOG(3) << "Folding " << node->name << "::" << output->name() << " to constant " << value << ".";
+ VLOG_DEBUG << "Folding " << node->name << "::" << output->name() << " to constant " << value
+ << ".";
foreach (ShaderInput *sock, output->links) {
sock->set(value);
@@ -99,8 +100,8 @@ void ConstantFolder::bypass(ShaderOutput *new_output) const
{
assert(new_output);
- VLOG(3) << "Folding " << node->name << "::" << output->name() << " to socket "
- << new_output->parent->name << "::" << new_output->name() << ".";
+ VLOG_DEBUG << "Folding " << node->name << "::" << output->name() << " to socket "
+ << new_output->parent->name << "::" << new_output->name() << ".";
/* Remove all outgoing links from socket and connect them to new_output instead.
* The graph->relink method affects node inputs, so it's not safe to use in constant
@@ -118,7 +119,7 @@ void ConstantFolder::discard() const
{
assert(output->type() == SocketType::CLOSURE);
- VLOG(3) << "Discarding closure " << node->name << ".";
+ VLOG_DEBUG << "Discarding closure " << node->name << ".";
graph->disconnect(output);
}
diff --git a/intern/cycles/scene/film.cpp b/intern/cycles/scene/film.cpp
index 7f69df7b321..a6a8f90a449 100644
--- a/intern/cycles/scene/film.cpp
+++ b/intern/cycles/scene/film.cpp
@@ -152,7 +152,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
KernelFilm *kfilm = &dscene->data.film;
- /* update __data */
+ /* update data */
kfilm->exposure = exposure;
kfilm->pass_alpha_threshold = pass_alpha_threshold;
kfilm->pass_flag = 0;
@@ -394,7 +394,7 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene)
vector<float> table = filter_table(filter_type, filter_width);
scene->lookup_tables->remove_table(&filter_table_offset_);
filter_table_offset_ = scene->lookup_tables->add_table(dscene, table);
- kfilm->filter_table_offset = (int)filter_table_offset_;
+ dscene->data.tables.filter_table_offset = (int)filter_table_offset_;
/* mist pass parameters */
kfilm->mist_start = mist_start;
@@ -580,10 +580,10 @@ void Film::update_passes(Scene *scene, bool add_sample_count_pass)
tag_modified();
/* Debug logging. */
- if (VLOG_IS_ON(2)) {
- VLOG(2) << "Effective scene passes:";
+ if (VLOG_INFO_IS_ON) {
+ VLOG_INFO << "Effective scene passes:";
for (const Pass *pass : scene->passes) {
- VLOG(2) << "- " << *pass;
+ VLOG_INFO << "- " << *pass;
}
}
}
diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp
index 9152abacbdb..67ff118692e 100644
--- a/intern/cycles/scene/geometry.cpp
+++ b/intern/cycles/scene/geometry.cpp
@@ -407,43 +407,47 @@ void GeometryManager::update_osl_attributes(Device *device,
/* Generate a normal attribute map entry from an attribute descriptor. */
static void emit_attribute_map_entry(
- uint4 *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc)
+ AttributeMap *attr_map, int index, uint id, TypeDesc type, const AttributeDescriptor &desc)
{
- attr_map[index].x = id;
- attr_map[index].y = desc.element;
- attr_map[index].z = as_uint(desc.offset);
+ attr_map[index].id = id;
+ attr_map[index].element = desc.element;
+ attr_map[index].offset = as_uint(desc.offset);
if (type == TypeDesc::TypeFloat)
- attr_map[index].w = NODE_ATTR_FLOAT;
+ attr_map[index].type = NODE_ATTR_FLOAT;
else if (type == TypeDesc::TypeMatrix)
- attr_map[index].w = NODE_ATTR_MATRIX;
+ attr_map[index].type = NODE_ATTR_MATRIX;
else if (type == TypeFloat2)
- attr_map[index].w = NODE_ATTR_FLOAT2;
+ attr_map[index].type = NODE_ATTR_FLOAT2;
else if (type == TypeFloat4)
- attr_map[index].w = NODE_ATTR_FLOAT4;
+ attr_map[index].type = NODE_ATTR_FLOAT4;
else if (type == TypeRGBA)
- attr_map[index].w = NODE_ATTR_RGBA;
+ attr_map[index].type = NODE_ATTR_RGBA;
else
- attr_map[index].w = NODE_ATTR_FLOAT3;
+ attr_map[index].type = NODE_ATTR_FLOAT3;
- attr_map[index].w |= desc.flags << 8;
+ attr_map[index].flags = desc.flags;
}
/* Generate an attribute map end marker, optionally including a link to another map.
* Links are used to connect object attribute maps to mesh attribute maps. */
-static void emit_attribute_map_terminator(uint4 *attr_map, int index, bool chain, uint chain_link)
+static void emit_attribute_map_terminator(AttributeMap *attr_map,
+ int index,
+ bool chain,
+ uint chain_link)
{
for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
- attr_map[index + j].x = ATTR_STD_NONE;
- attr_map[index + j].y = chain; /* link is valid flag */
- attr_map[index + j].z = chain ? chain_link + j : 0; /* link to the correct sub-entry */
- attr_map[index + j].w = 0;
+ attr_map[index + j].id = ATTR_STD_NONE;
+ attr_map[index + j].element = chain; /* link is valid flag */
+ attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */
+ attr_map[index + j].type = 0;
+ attr_map[index + j].flags = 0;
}
}
/* Generate all necessary attribute map entries from the attribute request. */
static void emit_attribute_mapping(
- uint4 *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom)
+ AttributeMap *attr_map, int index, Scene *scene, AttributeRequest &req, Geometry *geom)
{
uint id;
@@ -501,8 +505,8 @@ void GeometryManager::update_svm_attributes(Device *,
}
/* create attribute map */
- uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size);
- memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint));
+ AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size);
+ memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map));
for (size_t i = 0; i < scene->geometry.size(); i++) {
Geometry *geom = scene->geometry[i];
@@ -1288,7 +1292,7 @@ void GeometryManager::device_update_bvh(Device *device,
bparams.bvh_type = scene->params.bvh_type;
bparams.curve_subdivisions = scene->params.curve_subdivisions();
- VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
+ VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
const bool can_refit = scene->bvh != nullptr &&
(bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX ||
@@ -1358,7 +1362,7 @@ void GeometryManager::device_update_bvh(Device *device,
dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions();
/* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */
- dscene->data.bvh.scene = 0;
+ dscene->data.device_bvh = 0;
}
/* Set of flags used to help determining what data has been modified or needs reallocation, so we
@@ -1799,7 +1803,7 @@ void GeometryManager::device_update(Device *device,
if (!need_update())
return;
- VLOG(1) << "Total " << scene->geometry.size() << " meshes.";
+ VLOG_INFO << "Total " << scene->geometry.size() << " meshes.";
bool true_displacement_used = false;
bool curve_shadow_transparency_used = false;
@@ -1953,7 +1957,7 @@ void GeometryManager::device_update(Device *device,
{
/* Copy constant data needed by shader evaluation. */
- device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
+ device->const_copy_to("data", &dscene->data, sizeof(dscene->data));
scoped_callback_timer timer([scene](double time) {
if (scene->update_stats) {
@@ -2038,7 +2042,7 @@ void GeometryManager::device_update(Device *device,
TaskPool::Summary summary;
pool.wait_work(&summary);
- VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report();
+ VLOG_WORK << "Objects BVH build pool statistics:\n" << summary.full_report();
}
foreach (Shader *shader, scene->shaders) {
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
index 2aa9a6bc1a1..0352ed3e66c 100644
--- a/intern/cycles/scene/image.cpp
+++ b/intern/cycles/scene/image.cpp
@@ -272,17 +272,12 @@ void ImageMetaData::detect_colorspace()
compress_as_srgb = true;
}
else {
- /* Always compress non-raw 8bit images as scene linear + sRGB, as a
- * heuristic to keep memory usage the same without too much data loss
- * due to quantization in common cases. */
- compress_as_srgb = (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_BYTE4);
-
/* If colorspace conversion needed, use half instead of short so we can
* represent HDR values that might result from conversion. */
- if (type == IMAGE_DATA_TYPE_USHORT) {
+ if (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_USHORT) {
type = IMAGE_DATA_TYPE_HALF;
}
- else if (type == IMAGE_DATA_TYPE_USHORT4) {
+ else if (type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4) {
type = IMAGE_DATA_TYPE_HALF4;
}
}
@@ -658,8 +653,8 @@ bool ImageManager::file_load_image(Image *img, int texture_limit)
while (max_size * scale_factor > texture_limit) {
scale_factor *= 0.5f;
}
- VLOG(1) << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor
- << ".";
+ VLOG_WORK << "Scaling image " << img->loader->name() << " by a factor of " << scale_factor
+ << ".";
vector<StorageType> scaled_pixels;
size_t scaled_width, scaled_height, scaled_depth;
util_image_resize_pixels(pixels_storage,
@@ -702,7 +697,7 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
ImageDataType type = img->metadata.type;
/* Name for debugging. */
- img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type), slot);
+ img->mem_name = string_printf("tex_image_%s_%03d", name_from_type(type), slot);
/* Free previous texture in slot. */
if (img->mem) {
diff --git a/intern/cycles/scene/image_oiio.cpp b/intern/cycles/scene/image_oiio.cpp
index 1b7f8f49696..500e53ed763 100644
--- a/intern/cycles/scene/image_oiio.cpp
+++ b/intern/cycles/scene/image_oiio.cpp
@@ -22,11 +22,11 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures & /*features*/,
{
/* Perform preliminary checks, with meaningful logging. */
if (!path_exists(filepath.string())) {
- VLOG(1) << "File '" << filepath.string() << "' does not exist.";
+ VLOG_WARNING << "File '" << filepath.string() << "' does not exist.";
return false;
}
if (path_is_directory(filepath.string())) {
- VLOG(1) << "File '" << filepath.string() << "' is a directory, can't use as image.";
+ VLOG_WARNING << "File '" << filepath.string() << "' is a directory, can't use as image.";
return false;
}
@@ -94,10 +94,11 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures & /*features*/,
template<TypeDesc::BASETYPE FileFormat, typename StorageType>
static void oiio_load_pixels(const ImageMetaData &metadata,
const unique_ptr<ImageInput> &in,
+ const bool associate_alpha,
StorageType *pixels)
{
- const int width = metadata.width;
- const int height = metadata.height;
+ const size_t width = metadata.width;
+ const size_t height = metadata.height;
const int depth = metadata.depth;
const int components = metadata.channels;
@@ -105,12 +106,12 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
StorageType *readpixels = pixels;
vector<StorageType> tmppixels;
if (components > 4) {
- tmppixels.resize(((size_t)width) * height * components);
+ tmppixels.resize(width * height * components);
readpixels = &tmppixels[0];
}
if (depth <= 1) {
- size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
+ size_t scanlinesize = width * components * sizeof(StorageType);
in->read_image(FileFormat,
(uchar *)readpixels + (height - 1) * scanlinesize,
AutoStride,
@@ -122,7 +123,7 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
}
if (components > 4) {
- size_t dimensions = ((size_t)width) * height;
+ size_t dimensions = width * height;
for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
pixels[i * 4 + 3] = tmppixels[i * components + 3];
pixels[i * 4 + 2] = tmppixels[i * components + 2];
@@ -137,7 +138,7 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
if (cmyk) {
const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
- const size_t num_pixels = ((size_t)width) * height * depth;
+ const size_t num_pixels = width * height * depth;
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
float c = util_image_cast_to_float(pixels[i * 4 + 0]);
float m = util_image_cast_to_float(pixels[i * 4 + 1]);
@@ -149,6 +150,16 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
pixels[i * 4 + 3] = one;
}
}
+
+ if (components == 4 && associate_alpha) {
+ size_t dimensions = width * height;
+ for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
+ const StorageType alpha = pixels[i * 4 + 3];
+ pixels[i * 4 + 0] = util_image_multiply_native(pixels[i * 4 + 0], alpha);
+ pixels[i * 4 + 1] = util_image_multiply_native(pixels[i * 4 + 1], alpha);
+ pixels[i * 4 + 2] = util_image_multiply_native(pixels[i * 4 + 2], alpha);
+ }
+ }
}
bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
@@ -172,30 +183,36 @@ bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
ImageSpec spec = ImageSpec();
ImageSpec config = ImageSpec();
- if (!associate_alpha) {
- config.attribute("oiio:UnassociatedAlpha", 1);
- }
+ /* Load without automatic OIIO alpha conversion, we do it ourselves. OIIO
+ * will associate alpha in the the 8bit buffer for PNGs, which leads to too
+ * much precision loss when we load it as half float to do a colorspace
+ * transform. */
+ config.attribute("oiio:UnassociatedAlpha", 1);
if (!in->open(filepath.string(), spec, config)) {
return false;
}
+ const bool do_associate_alpha = associate_alpha &&
+ spec.get_int_attribute("oiio:UnassociatedAlpha", 0);
+
switch (metadata.type) {
case IMAGE_DATA_TYPE_BYTE:
case IMAGE_DATA_TYPE_BYTE4:
- oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, (uchar *)pixels);
+ oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, do_associate_alpha, (uchar *)pixels);
break;
case IMAGE_DATA_TYPE_USHORT:
case IMAGE_DATA_TYPE_USHORT4:
- oiio_load_pixels<TypeDesc::USHORT, uint16_t>(metadata, in, (uint16_t *)pixels);
+ oiio_load_pixels<TypeDesc::USHORT, uint16_t>(
+ metadata, in, do_associate_alpha, (uint16_t *)pixels);
break;
case IMAGE_DATA_TYPE_HALF:
case IMAGE_DATA_TYPE_HALF4:
- oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, (half *)pixels);
+ oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, do_associate_alpha, (half *)pixels);
break;
case IMAGE_DATA_TYPE_FLOAT:
case IMAGE_DATA_TYPE_FLOAT4:
- oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, (float *)pixels);
+ oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, do_associate_alpha, (float *)pixels);
break;
case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
diff --git a/intern/cycles/scene/image_vdb.cpp b/intern/cycles/scene/image_vdb.cpp
index d0b41a239df..059eb09fef4 100644
--- a/intern/cycles/scene/image_vdb.cpp
+++ b/intern/cycles/scene/image_vdb.cpp
@@ -70,7 +70,7 @@ struct ToNanoOp {
nanogrid = nanovdb::openToNanoVDB(floatgrid);
}
catch (const std::exception &e) {
- VLOG(1) << "Error converting OpenVDB to NanoVDB grid: " << e.what();
+ VLOG_WARNING << "Error converting OpenVDB to NanoVDB grid: " << e.what();
}
return true;
}
@@ -114,9 +114,11 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
/* NanoVDB expects no inactive leaf nodes. */
- /*openvdb::FloatGrid &pruned_grid = *openvdb::gridPtrCast<openvdb::FloatGrid>(grid);
+# if 0
+ openvdb::FloatGrid &pruned_grid = *openvdb::gridPtrCast<openvdb::FloatGrid>(grid);
openvdb::tools::pruneInactive(pruned_grid.tree());
- nanogrid = nanovdb::openToNanoVDB(pruned_grid);*/
+ nanogrid = nanovdb::openToNanoVDB(pruned_grid);
+# endif
ToNanoOp op;
op.precision = precision;
if (!openvdb::grid_type_operation(grid, op)) {
diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp
index fda6ecc8d14..aa11004fb48 100644
--- a/intern/cycles/scene/integrator.cpp
+++ b/intern/cycles/scene/integrator.cpp
@@ -338,7 +338,7 @@ AdaptiveSampling Integrator::get_adaptive_sampling() const
if (aa_samples > 0 && adaptive_threshold == 0.0f) {
adaptive_sampling.threshold = max(0.001f, 1.0f / (float)aa_samples);
- VLOG(1) << "Cycles adaptive sampling: automatic threshold = " << adaptive_sampling.threshold;
+ VLOG_INFO << "Cycles adaptive sampling: automatic threshold = " << adaptive_sampling.threshold;
}
else {
adaptive_sampling.threshold = adaptive_threshold;
@@ -350,8 +350,8 @@ AdaptiveSampling Integrator::get_adaptive_sampling() const
* in various test scenes. */
const int min_samples = (int)ceilf(16.0f / powf(adaptive_sampling.threshold, 0.3f));
adaptive_sampling.min_samples = max(4, min_samples);
- VLOG(1) << "Cycles adaptive sampling: automatic min samples = "
- << adaptive_sampling.min_samples;
+ VLOG_INFO << "Cycles adaptive sampling: automatic min samples = "
+ << adaptive_sampling.min_samples;
}
else {
adaptive_sampling.min_samples = max(4, adaptive_min_samples);
diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp
index 5e311d3051f..ea1f45793fa 100644
--- a/intern/cycles/scene/light.cpp
+++ b/intern/cycles/scene/light.cpp
@@ -34,7 +34,7 @@ static void shade_background_pixels(Device *device,
Progress &progress)
{
/* Needs to be up to data for attribute access. */
- device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
+ device->const_copy_to("data", &dscene->data, sizeof(dscene->data));
const int size = width * height;
const int num_channels = 3;
@@ -215,7 +215,9 @@ void LightManager::test_enabled_lights(Scene *scene)
*/
Shader *shader = scene->background->get_shader(scene);
const bool disable_mis = !(has_portal || shader->has_surface_spatial_varying);
- VLOG_IF(1, disable_mis) << "Background MIS has been disabled.\n";
+ if (disable_mis) {
+ VLOG_INFO << "Background MIS has been disabled.\n";
+ }
foreach (Light *light, scene->lights) {
if (light->light_type == LIGHT_BACKGROUND) {
light->is_enabled = !disable_mis;
@@ -309,7 +311,7 @@ void LightManager::device_update_distribution(Device *,
}
size_t num_distribution = num_triangles + num_lights;
- VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
+ VLOG_INFO << "Total " << num_distribution << " of light distribution primitives.";
/* emission area */
KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
@@ -655,13 +657,14 @@ void LightManager::device_update_background(Device *device,
if (res.x == 0) {
res = environment_res;
if (res.x > 0 && res.y > 0) {
- VLOG(2) << "Automatically set World MIS resolution to " << res.x << " by " << res.y << "\n";
+ VLOG_INFO << "Automatically set World MIS resolution to " << res.x << " by " << res.y
+ << "\n";
}
}
/* If it's still unknown, just use the default. */
if (res.x == 0 || res.y == 0) {
res = make_int2(1024, 512);
- VLOG(2) << "Setting World MIS resolution to default\n";
+ VLOG_INFO << "Setting World MIS resolution to default\n";
}
kbackground->map_res_x = res.x;
kbackground->map_res_y = res.y;
@@ -704,7 +707,7 @@ void LightManager::device_update_background(Device *device,
marg_cdf[res.y].y = 1.0f;
- VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n";
+ VLOG_WORK << "Background MIS build time " << time_dt() - time_start << "\n";
/* update device */
dscene->light_background_marginal_cdf.copy_to_device();
@@ -725,7 +728,7 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
KernelLight *klights = dscene->lights.alloc(num_lights);
if (num_lights == 0) {
- VLOG(1) << "No effective light, ignoring points update.";
+ VLOG_WORK << "No effective light, ignoring points update.";
return;
}
@@ -955,9 +958,9 @@ void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *sc
light_index++;
}
- VLOG(1) << "Number of lights sent to the device: " << light_index;
+ VLOG_INFO << "Number of lights sent to the device: " << light_index;
- VLOG(1) << "Number of lights without contribution: " << num_scene_lights - light_index;
+ VLOG_INFO << "Number of lights without contribution: " << num_scene_lights - light_index;
dscene->lights.copy_to_device();
}
@@ -976,7 +979,7 @@ void LightManager::device_update(Device *device,
}
});
- VLOG(1) << "Total " << scene->lights.size() << " lights.";
+ VLOG_INFO << "Total " << scene->lights.size() << " lights.";
/* Detect which lights are enabled, also determines if we need to update the background. */
test_enabled_lights(scene);
diff --git a/intern/cycles/scene/mesh.cpp b/intern/cycles/scene/mesh.cpp
index b5c0d9d92fb..110cb439f58 100644
--- a/intern/cycles/scene/mesh.cpp
+++ b/intern/cycles/scene/mesh.cpp
@@ -94,7 +94,7 @@ float3 Mesh::Triangle::compute_normal(const float3 *verts) const
bool Mesh::Triangle::valid(const float3 *verts) const
{
- return isfinite3_safe(verts[v[0]]) && isfinite3_safe(verts[v[1]]) && isfinite3_safe(verts[v[2]]);
+ return isfinite_safe(verts[v[0]]) && isfinite_safe(verts[v[1]]) && isfinite_safe(verts[v[2]]);
}
/* SubdFace */
diff --git a/intern/cycles/scene/mesh_displace.cpp b/intern/cycles/scene/mesh_displace.cpp
index 6b109bbb818..e180145daac 100644
--- a/intern/cycles/scene/mesh_displace.cpp
+++ b/intern/cycles/scene/mesh_displace.cpp
@@ -137,7 +137,7 @@ static void read_shader_output(const Scene *scene,
d_output_index += 3;
/* Avoid illegal vertex coordinates. */
- off = ensure_finite3(off);
+ off = ensure_finite(off);
mesh_verts[t.v[j]] += off;
if (attr_mP != NULL) {
for (int step = 0; step < num_motion_steps - 1; step++) {
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index ddd89a16640..2126b23d82e 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -340,12 +340,12 @@ float Object::compute_volume_step_size() const
if (metadata.use_transform_3d) {
voxel_tfm = tfm * transform_inverse(metadata.transform_3d);
}
- voxel_step_size = min3(fabs(transform_direction(&voxel_tfm, size)));
+ voxel_step_size = reduce_min(fabs(transform_direction(&voxel_tfm, size)));
}
else if (volume->get_object_space()) {
/* User specified step size in object space. */
float3 size = make_float3(voxel_step_size, voxel_step_size, voxel_step_size);
- voxel_step_size = min3(fabs(transform_direction(&tfm, size)));
+ voxel_step_size = reduce_min(fabs(transform_direction(&tfm, size)));
}
if (voxel_step_size > 0.0f) {
@@ -688,7 +688,7 @@ void ObjectManager::device_update(Device *device,
dscene->objects.tag_modified();
}
- VLOG(1) << "Total " << scene->objects.size() << " objects.";
+ VLOG_INFO << "Total " << scene->objects.size() << " objects.";
device_free(device, dscene, false);
diff --git a/intern/cycles/scene/osl.cpp b/intern/cycles/scene/osl.cpp
index 6698e6e2cce..f5ee0c0f1d3 100644
--- a/intern/cycles/scene/osl.cpp
+++ b/intern/cycles/scene/osl.cpp
@@ -92,7 +92,7 @@ void OSLShaderManager::device_update_specific(Device *device,
}
});
- VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
+ VLOG_INFO << "Total " << scene->shaders.size() << " shaders.";
device_free(device, dscene, scene);
@@ -240,7 +240,7 @@ void OSLShaderManager::shading_system_init()
ss_shared->attribute("searchpath:shader", shader_path);
ss_shared->attribute("greedyjit", 1);
- VLOG(1) << "Using shader search path: " << shader_path;
+ VLOG_INFO << "Using shader search path: " << shader_path;
/* our own ray types */
static const char *raytypes[] = {
diff --git a/intern/cycles/scene/particles.cpp b/intern/cycles/scene/particles.cpp
index a05acf17ccf..b527dd0ebe8 100644
--- a/intern/cycles/scene/particles.cpp
+++ b/intern/cycles/scene/particles.cpp
@@ -105,7 +105,7 @@ void ParticleSystemManager::device_update(Device *device,
}
});
- VLOG(1) << "Total " << scene->particle_systems.size() << " particle systems.";
+ VLOG_INFO << "Total " << scene->particle_systems.size() << " particle systems.";
device_free(device, dscene);
diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp
index b35242139ea..18cd665ac74 100644
--- a/intern/cycles/scene/scene.cpp
+++ b/intern/cycles/scene/scene.cpp
@@ -34,49 +34,49 @@
CCL_NAMESPACE_BEGIN
DeviceScene::DeviceScene(Device *device)
- : bvh_nodes(device, "__bvh_nodes", MEM_GLOBAL),
- bvh_leaf_nodes(device, "__bvh_leaf_nodes", MEM_GLOBAL),
- object_node(device, "__object_node", MEM_GLOBAL),
- prim_type(device, "__prim_type", MEM_GLOBAL),
- prim_visibility(device, "__prim_visibility", MEM_GLOBAL),
- prim_index(device, "__prim_index", MEM_GLOBAL),
- prim_object(device, "__prim_object", MEM_GLOBAL),
- prim_time(device, "__prim_time", MEM_GLOBAL),
- tri_verts(device, "__tri_verts", MEM_GLOBAL),
- tri_shader(device, "__tri_shader", MEM_GLOBAL),
- tri_vnormal(device, "__tri_vnormal", MEM_GLOBAL),
- tri_vindex(device, "__tri_vindex", MEM_GLOBAL),
- tri_patch(device, "__tri_patch", MEM_GLOBAL),
- tri_patch_uv(device, "__tri_patch_uv", MEM_GLOBAL),
- curves(device, "__curves", MEM_GLOBAL),
- curve_keys(device, "__curve_keys", MEM_GLOBAL),
- curve_segments(device, "__curve_segments", MEM_GLOBAL),
- patches(device, "__patches", MEM_GLOBAL),
- points(device, "__points", MEM_GLOBAL),
- points_shader(device, "__points_shader", MEM_GLOBAL),
- objects(device, "__objects", MEM_GLOBAL),
- object_motion_pass(device, "__object_motion_pass", MEM_GLOBAL),
- object_motion(device, "__object_motion", MEM_GLOBAL),
- object_flag(device, "__object_flag", MEM_GLOBAL),
- object_volume_step(device, "__object_volume_step", MEM_GLOBAL),
- object_prim_offset(device, "__object_prim_offset", MEM_GLOBAL),
- camera_motion(device, "__camera_motion", MEM_GLOBAL),
- attributes_map(device, "__attributes_map", MEM_GLOBAL),
- attributes_float(device, "__attributes_float", MEM_GLOBAL),
- attributes_float2(device, "__attributes_float2", MEM_GLOBAL),
- attributes_float3(device, "__attributes_float3", MEM_GLOBAL),
- attributes_float4(device, "__attributes_float4", MEM_GLOBAL),
- attributes_uchar4(device, "__attributes_uchar4", MEM_GLOBAL),
- light_distribution(device, "__light_distribution", MEM_GLOBAL),
- lights(device, "__lights", MEM_GLOBAL),
- light_background_marginal_cdf(device, "__light_background_marginal_cdf", MEM_GLOBAL),
- light_background_conditional_cdf(device, "__light_background_conditional_cdf", MEM_GLOBAL),
- particles(device, "__particles", MEM_GLOBAL),
- svm_nodes(device, "__svm_nodes", MEM_GLOBAL),
- shaders(device, "__shaders", MEM_GLOBAL),
- lookup_table(device, "__lookup_table", MEM_GLOBAL),
- sample_pattern_lut(device, "__sample_pattern_lut", MEM_GLOBAL),
- ies_lights(device, "__ies", MEM_GLOBAL)
+ : bvh_nodes(device, "bvh_nodes", MEM_GLOBAL),
+ bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL),
+ object_node(device, "object_node", MEM_GLOBAL),
+ prim_type(device, "prim_type", MEM_GLOBAL),
+ prim_visibility(device, "prim_visibility", MEM_GLOBAL),
+ prim_index(device, "prim_index", MEM_GLOBAL),
+ prim_object(device, "prim_object", MEM_GLOBAL),
+ prim_time(device, "prim_time", MEM_GLOBAL),
+ tri_verts(device, "tri_verts", MEM_GLOBAL),
+ tri_shader(device, "tri_shader", MEM_GLOBAL),
+ tri_vnormal(device, "tri_vnormal", MEM_GLOBAL),
+ tri_vindex(device, "tri_vindex", MEM_GLOBAL),
+ tri_patch(device, "tri_patch", MEM_GLOBAL),
+ tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL),
+ curves(device, "curves", MEM_GLOBAL),
+ curve_keys(device, "curve_keys", MEM_GLOBAL),
+ curve_segments(device, "curve_segments", MEM_GLOBAL),
+ patches(device, "patches", MEM_GLOBAL),
+ points(device, "points", MEM_GLOBAL),
+ points_shader(device, "points_shader", MEM_GLOBAL),
+ objects(device, "objects", MEM_GLOBAL),
+ object_motion_pass(device, "object_motion_pass", MEM_GLOBAL),
+ object_motion(device, "object_motion", MEM_GLOBAL),
+ object_flag(device, "object_flag", MEM_GLOBAL),
+ object_volume_step(device, "object_volume_step", MEM_GLOBAL),
+ object_prim_offset(device, "object_prim_offset", MEM_GLOBAL),
+ camera_motion(device, "camera_motion", MEM_GLOBAL),
+ attributes_map(device, "attributes_map", MEM_GLOBAL),
+ attributes_float(device, "attributes_float", MEM_GLOBAL),
+ attributes_float2(device, "attributes_float2", MEM_GLOBAL),
+ attributes_float3(device, "attributes_float3", MEM_GLOBAL),
+ attributes_float4(device, "attributes_float4", MEM_GLOBAL),
+ attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL),
+ light_distribution(device, "light_distribution", MEM_GLOBAL),
+ lights(device, "lights", MEM_GLOBAL),
+ light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL),
+ light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL),
+ particles(device, "particles", MEM_GLOBAL),
+ svm_nodes(device, "svm_nodes", MEM_GLOBAL),
+ shaders(device, "shaders", MEM_GLOBAL),
+ lookup_table(device, "lookup_table", MEM_GLOBAL),
+ sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL),
+ ies_lights(device, "ies", MEM_GLOBAL)
{
memset((void *)&data, 0, sizeof(data));
}
@@ -366,18 +366,20 @@ void Scene::device_update(Device *device_, Progress &progress)
dscene.data.volume_stack_size = get_volume_stack_size();
progress.set_status("Updating Device", "Writing constant memory");
- device->const_copy_to("__data", &dscene.data, sizeof(dscene.data));
+ device->const_copy_to("data", &dscene.data, sizeof(dscene.data));
}
+ device->optimize_for_scene(this);
+
if (print_stats) {
size_t mem_used = util_guarded_get_mem_used();
size_t mem_peak = util_guarded_get_mem_peak();
- VLOG(1) << "System memory statistics after full device sync:\n"
- << " Usage: " << string_human_readable_number(mem_used) << " ("
- << string_human_readable_size(mem_used) << ")\n"
- << " Peak: " << string_human_readable_number(mem_peak) << " ("
- << string_human_readable_size(mem_peak) << ")";
+ VLOG_INFO << "System memory statistics after full device sync:\n"
+ << " Usage: " << string_human_readable_number(mem_used) << " ("
+ << string_human_readable_size(mem_used) << ")\n"
+ << " Peak: " << string_human_readable_number(mem_peak) << " ("
+ << string_human_readable_size(mem_peak) << ")";
}
}
@@ -499,9 +501,9 @@ void Scene::update_kernel_features()
kernel_features |= KERNEL_FEATURE_CAMERA_MOTION;
}
- /* Figure out whether the scene will use shader raytrace we need at least
+ /* Figure out whether the scene will use shader ray-trace we need at least
* one caustic light, one caustic caster and one caustic receiver to use
- * and enable the mnee code path. */
+ * and enable the MNEE code path. */
bool has_caustics_receiver = false;
bool has_caustics_caster = false;
bool has_caustics_light = false;
@@ -550,7 +552,7 @@ void Scene::update_kernel_features()
dscene.data.integrator.use_caustics = false;
if (has_caustics_caster && has_caustics_receiver && has_caustics_light) {
dscene.data.integrator.use_caustics = true;
- kernel_features |= KERNEL_FEATURE_NODE_RAYTRACE;
+ kernel_features |= KERNEL_FEATURE_MNEE;
}
if (bake_manager->get_baking()) {
@@ -586,34 +588,38 @@ bool Scene::update(Progress &progress)
static void log_kernel_features(const uint features)
{
- VLOG(2) << "Requested features:\n";
- VLOG(2) << "Use BSDF " << string_from_bool(features & KERNEL_FEATURE_NODE_BSDF) << "\n";
- VLOG(2) << "Use Principled BSDF " << string_from_bool(features & KERNEL_FEATURE_PRINCIPLED)
- << "\n";
- VLOG(2) << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION) << "\n";
- VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n";
- VLOG(2) << "Use Bump " << string_from_bool(features & KERNEL_FEATURE_NODE_BUMP) << "\n";
- VLOG(2) << "Use Voronoi " << string_from_bool(features & KERNEL_FEATURE_NODE_VORONOI_EXTRA)
- << "\n";
- VLOG(2) << "Use Shader Raytrace " << string_from_bool(features & KERNEL_FEATURE_NODE_RAYTRACE)
- << "\n";
- VLOG(2) << "Use Transparent " << string_from_bool(features & KERNEL_FEATURE_TRANSPARENT) << "\n";
- VLOG(2) << "Use Denoising " << string_from_bool(features & KERNEL_FEATURE_DENOISING) << "\n";
- VLOG(2) << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING)
- << "\n";
- VLOG(2) << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n";
- VLOG(2) << "Use Pointclouds " << string_from_bool(features & KERNEL_FEATURE_POINTCLOUD) << "\n";
- VLOG(2) << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION)
- << "\n";
- VLOG(2) << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION)
- << "\n";
- VLOG(2) << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n";
- VLOG(2) << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n";
- VLOG(2) << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n";
- VLOG(2) << "Use Patch Evaluation "
- << string_from_bool(features & KERNEL_FEATURE_PATCH_EVALUATION) << "\n";
- VLOG(2) << "Use Shadow Catcher " << string_from_bool(features & KERNEL_FEATURE_SHADOW_CATCHER)
- << "\n";
+ VLOG_INFO << "Requested features:\n";
+ VLOG_INFO << "Use BSDF " << string_from_bool(features & KERNEL_FEATURE_NODE_BSDF) << "\n";
+ VLOG_INFO << "Use Principled BSDF " << string_from_bool(features & KERNEL_FEATURE_PRINCIPLED)
+ << "\n";
+ VLOG_INFO << "Use Emission " << string_from_bool(features & KERNEL_FEATURE_NODE_EMISSION)
+ << "\n";
+ VLOG_INFO << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_NODE_VOLUME) << "\n";
+ VLOG_INFO << "Use Bump " << string_from_bool(features & KERNEL_FEATURE_NODE_BUMP) << "\n";
+ VLOG_INFO << "Use Voronoi " << string_from_bool(features & KERNEL_FEATURE_NODE_VORONOI_EXTRA)
+ << "\n";
+ VLOG_INFO << "Use Shader Raytrace " << string_from_bool(features & KERNEL_FEATURE_NODE_RAYTRACE)
+ << "\n";
+ VLOG_INFO << "Use MNEE" << string_from_bool(features & KERNEL_FEATURE_MNEE) << "\n";
+ VLOG_INFO << "Use Transparent " << string_from_bool(features & KERNEL_FEATURE_TRANSPARENT)
+ << "\n";
+ VLOG_INFO << "Use Denoising " << string_from_bool(features & KERNEL_FEATURE_DENOISING) << "\n";
+ VLOG_INFO << "Use Path Tracing " << string_from_bool(features & KERNEL_FEATURE_PATH_TRACING)
+ << "\n";
+ VLOG_INFO << "Use Hair " << string_from_bool(features & KERNEL_FEATURE_HAIR) << "\n";
+ VLOG_INFO << "Use Pointclouds " << string_from_bool(features & KERNEL_FEATURE_POINTCLOUD)
+ << "\n";
+ VLOG_INFO << "Use Object Motion " << string_from_bool(features & KERNEL_FEATURE_OBJECT_MOTION)
+ << "\n";
+ VLOG_INFO << "Use Camera Motion " << string_from_bool(features & KERNEL_FEATURE_CAMERA_MOTION)
+ << "\n";
+ VLOG_INFO << "Use Baking " << string_from_bool(features & KERNEL_FEATURE_BAKING) << "\n";
+ VLOG_INFO << "Use Subsurface " << string_from_bool(features & KERNEL_FEATURE_SUBSURFACE) << "\n";
+ VLOG_INFO << "Use Volume " << string_from_bool(features & KERNEL_FEATURE_VOLUME) << "\n";
+ VLOG_INFO << "Use Patch Evaluation "
+ << string_from_bool(features & KERNEL_FEATURE_PATCH_EVALUATION) << "\n";
+ VLOG_INFO << "Use Shadow Catcher " << string_from_bool(features & KERNEL_FEATURE_SHADOW_CATCHER)
+ << "\n";
}
bool Scene::load_kernels(Progress &progress, bool lock_scene)
@@ -674,8 +680,8 @@ int Scene::get_max_closure_count()
* closures discarded due to mixing or low weights. We need to limit
* to MAX_CLOSURE as this is hardcoded in CPU/mega kernels, and it
* avoids excessive memory usage for split kernels. */
- VLOG(2) << "Maximum number of closures exceeded: " << max_closure_global << " > "
- << MAX_CLOSURE;
+ VLOG_WARNING << "Maximum number of closures exceeded: " << max_closure_global << " > "
+ << MAX_CLOSURE;
max_closure_global = MAX_CLOSURE;
}
@@ -722,7 +728,7 @@ int Scene::get_volume_stack_size() const
volume_stack_size = min(volume_stack_size, MAX_VOLUME_STACK_SIZE);
- VLOG(3) << "Detected required volume stack size " << volume_stack_size;
+ VLOG_WORK << "Detected required volume stack size " << volume_stack_size;
return volume_stack_size;
}
diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h
index a0d2f4a6c06..d1004bb7b66 100644
--- a/intern/cycles/scene/scene.h
+++ b/intern/cycles/scene/scene.h
@@ -82,7 +82,7 @@ class DeviceScene {
device_vector<uint> patches;
- /* pointcloud */
+ /* point-cloud */
device_vector<float4> points;
device_vector<uint> points_shader;
@@ -98,7 +98,7 @@ class DeviceScene {
device_vector<DecomposedTransform> camera_motion;
/* attributes */
- device_vector<uint4> attributes_map;
+ device_vector<AttributeMap> attributes_map;
device_vector<float> attributes_float;
device_vector<float2> attributes_float2;
device_vector<packed_float3> attributes_float3;
@@ -124,7 +124,7 @@ class DeviceScene {
/* integrator */
device_vector<float> sample_pattern_lut;
- /* ies lights */
+ /* IES lights */
device_vector<float> ies_lights;
KernelData data;
diff --git a/intern/cycles/scene/shader_graph.cpp b/intern/cycles/scene/shader_graph.cpp
index d44e12f5fab..ef3f142ed4e 100644
--- a/intern/cycles/scene/shader_graph.cpp
+++ b/intern/cycles/scene/shader_graph.cpp
@@ -659,7 +659,7 @@ void ShaderGraph::deduplicate_nodes()
}
if (num_deduplicated > 0) {
- VLOG(1) << "Deduplicated " << num_deduplicated << " nodes.";
+ VLOG_DEBUG << "Deduplicated " << num_deduplicated << " nodes.";
}
}
@@ -700,7 +700,7 @@ void ShaderGraph::verify_volume_output()
}
}
if (!has_valid_volume) {
- VLOG(1) << "Disconnect meaningless volume output.";
+ VLOG_DEBUG << "Disconnect meaningless volume output.";
disconnect(volume_in->link);
}
}
@@ -888,7 +888,7 @@ void ShaderGraph::default_inputs(bool do_osl)
void ShaderGraph::refine_bump_nodes()
{
- /* we transverse the node graph looking for bump nodes, when we find them,
+ /* We transverse the node graph looking for bump nodes, when we find them,
* like in bump_from_displacement(), we copy the sub-graph defined from "bump"
* input to the inputs "center","dx" and "dy" What is in "bump" input is moved
* to "center" input. */
@@ -898,18 +898,18 @@ void ShaderGraph::refine_bump_nodes()
ShaderInput *bump_input = node->input("Height");
ShaderNodeSet nodes_bump;
- /* make 2 extra copies of the subgraph defined in Bump input */
+ /* Make 2 extra copies of the subgraph defined in Bump input. */
ShaderNodeMap nodes_dx;
ShaderNodeMap nodes_dy;
- /* find dependencies for the given input */
+ /* Find dependencies for the given input. */
find_dependencies(nodes_bump, bump_input);
copy_nodes(nodes_bump, nodes_dx);
copy_nodes(nodes_bump, nodes_dy);
- /* mark nodes to indicate they are use for bump computation, so
- that any texture coordinates are shifted by dx/dy when sampling */
+ /* Mark nodes to indicate they are use for bump computation, so
+ * that any texture coordinates are shifted by dx/dy when sampling. */
foreach (ShaderNode *node, nodes_bump)
node->bump = SHADER_BUMP_CENTER;
foreach (NodePair &pair, nodes_dx)
@@ -924,7 +924,7 @@ void ShaderGraph::refine_bump_nodes()
connect(out_dx, node->input("SampleX"));
connect(out_dy, node->input("SampleY"));
- /* add generated nodes */
+ /* Add generated nodes. */
foreach (NodePair &pair, nodes_dx)
add(pair.second);
foreach (NodePair &pair, nodes_dy)
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index 3b58556f601..bedb0fe2902 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -2391,7 +2391,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(3) << "Using sharp glossy BSDF.";
+ VLOG_DEBUG << "Using sharp glossy BSDF.";
distribution = CLOSURE_BSDF_REFLECTION_ID;
}
}
@@ -2400,7 +2400,7 @@ void GlossyBsdfNode::simplify_settings(Scene *scene)
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFLECTION_ID) {
- VLOG(3) << "Using GGX glossy with filter glossy.";
+ VLOG_DEBUG << "Using GGX glossy with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
roughness = 0.0f;
}
@@ -2484,7 +2484,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(3) << "Using sharp glass BSDF.";
+ VLOG_DEBUG << "Using sharp glass BSDF.";
distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
}
}
@@ -2493,7 +2493,7 @@ void GlassBsdfNode::simplify_settings(Scene *scene)
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_SHARP_GLASS_ID) {
- VLOG(3) << "Using GGX glass with filter glossy.";
+ VLOG_DEBUG << "Using GGX glass with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
roughness = 0.0f;
}
@@ -2577,7 +2577,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
* NOTE: Keep the epsilon in sync with kernel!
*/
if (!roughness_input->link && roughness <= 1e-4f) {
- VLOG(3) << "Using sharp refraction BSDF.";
+ VLOG_DEBUG << "Using sharp refraction BSDF.";
distribution = CLOSURE_BSDF_REFRACTION_ID;
}
}
@@ -2586,7 +2586,7 @@ void RefractionBsdfNode::simplify_settings(Scene *scene)
* benefit from closure blur to remove unwanted noise.
*/
if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFRACTION_ID) {
- VLOG(3) << "Using GGX refraction with filter glossy.";
+ VLOG_DEBUG << "Using GGX refraction with filter glossy.";
distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
roughness = 0.0f;
}
@@ -6671,7 +6671,7 @@ void CurvesNode::compile(SVMCompiler &compiler,
ShaderInput *fac_in = input("Fac");
- compiler.add_node(type,
+ compiler.add_node(ShaderNodeType(type),
compiler.encode_uchar4(compiler.stack_assign(fac_in),
compiler.stack_assign(value_in),
compiler.stack_assign(value_out),
@@ -6736,7 +6736,7 @@ void RGBCurvesNode::constant_fold(const ConstantFolder &folder)
void RGBCurvesNode::compile(SVMCompiler &compiler)
{
- CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color"));
+ CurvesNode::compile(compiler, NODE_CURVES, input("Color"), output("Color"));
}
void RGBCurvesNode::compile(OSLCompiler &compiler)
@@ -6774,7 +6774,7 @@ void VectorCurvesNode::constant_fold(const ConstantFolder &folder)
void VectorCurvesNode::compile(SVMCompiler &compiler)
{
- CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector"));
+ CurvesNode::compile(compiler, NODE_CURVES, input("Vector"), output("Vector"));
}
void VectorCurvesNode::compile(OSLCompiler &compiler)
diff --git a/intern/cycles/scene/svm.cpp b/intern/cycles/scene/svm.cpp
index 484a7d6de72..ede3f87e7e3 100644
--- a/intern/cycles/scene/svm.cpp
+++ b/intern/cycles/scene/svm.cpp
@@ -44,16 +44,14 @@ void SVMShaderManager::device_update_shader(Scene *scene,
}
assert(shader->graph);
- svm_nodes->push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
-
SVMCompiler::Summary summary;
SVMCompiler compiler(scene);
compiler.background = (shader == scene->background->get_shader(scene));
compiler.compile(shader, *svm_nodes, 0, &summary);
- VLOG(3) << "Compilation summary:\n"
- << "Shader name: " << shader->name << "\n"
- << summary.full_report();
+ VLOG_WORK << "Compilation summary:\n"
+ << "Shader name: " << shader->name << "\n"
+ << summary.full_report();
}
void SVMShaderManager::device_update_specific(Device *device,
@@ -72,7 +70,7 @@ void SVMShaderManager::device_update_specific(Device *device,
const int num_shaders = scene->shaders.size();
- VLOG(1) << "Total " << num_shaders << " shaders.";
+ VLOG_INFO << "Total " << num_shaders << " shaders.";
double start_time = time_dt();
@@ -148,8 +146,8 @@ void SVMShaderManager::device_update_specific(Device *device,
update_flags = UPDATE_NONE;
- VLOG(1) << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
- << " seconds.";
+ VLOG_INFO << "Shader manager updated " << num_shaders << " shaders in " << time_dt() - start_time
+ << " seconds.";
}
void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
@@ -170,6 +168,9 @@ SVMCompiler::SVMCompiler(Scene *scene) : scene(scene)
background = false;
mix_weight_offset = SVM_STACK_INVALID;
compile_failed = false;
+
+ /* This struct has one entry for every node, in order of ShaderNodeType definition. */
+ svm_node_types_used = (std::atomic_int *)&scene->dscene.data.svm_usage;
}
int SVMCompiler::stack_size(SocketType::Type type)
@@ -378,11 +379,13 @@ void SVMCompiler::add_node(int a, int b, int c, int d)
void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c)
{
+ svm_node_types_used[type] = true;
current_svm_nodes.push_back_slow(make_int4(type, a, b, c));
}
void SVMCompiler::add_node(ShaderNodeType type, const float3 &f)
{
+ svm_node_types_used[type] = true;
current_svm_nodes.push_back_slow(
make_int4(type, __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z)));
}
@@ -663,6 +666,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
/* Add instruction to skip closure and its dependencies if mix
* weight is zero.
*/
+ svm_node_types_used[NODE_JUMP_IF_ONE] = true;
current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ONE, 0, stack_assign(facin), 0));
int node_jump_skip_index = current_svm_nodes.size() - 1;
@@ -678,6 +682,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *root_node,
/* Add instruction to skip closure and its dependencies if mix
* weight is zero.
*/
+ svm_node_types_used[NODE_JUMP_IF_ZERO] = true;
current_svm_nodes.push_back_slow(make_int4(NODE_JUMP_IF_ZERO, 0, stack_assign(facin), 0));
int node_jump_skip_index = current_svm_nodes.size() - 1;
@@ -844,6 +849,9 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
void SVMCompiler::compile(Shader *shader, array<int4> &svm_nodes, int index, Summary *summary)
{
+ svm_node_types_used[NODE_SHADER_JUMP] = true;
+ svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
+
/* copy graph for shader with bump mapping */
ShaderNode *output = shader->graph->output();
int start_num_svm_nodes = svm_nodes.size();
diff --git a/intern/cycles/scene/svm.h b/intern/cycles/scene/svm.h
index 19746616207..f72375e7f87 100644
--- a/intern/cycles/scene/svm.h
+++ b/intern/cycles/scene/svm.h
@@ -211,6 +211,7 @@ class SVMCompiler {
/* compile */
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
+ std::atomic_int *svm_node_types_used;
array<int4> current_svm_nodes;
ShaderType current_type;
Shader *current_shader;
diff --git a/intern/cycles/scene/tables.cpp b/intern/cycles/scene/tables.cpp
index bb35880d37e..3e57b535f35 100644
--- a/intern/cycles/scene/tables.cpp
+++ b/intern/cycles/scene/tables.cpp
@@ -34,7 +34,7 @@ void LookupTables::device_update(Device *, DeviceScene *dscene, Scene *scene)
}
});
- VLOG(1) << "Total " << lookup_tables.size() << " lookup tables.";
+ VLOG_INFO << "Total " << lookup_tables.size() << " lookup tables.";
if (lookup_tables.size() > 0)
dscene->lookup_table.copy_to_device();
diff --git a/intern/cycles/scene/volume.cpp b/intern/cycles/scene/volume.cpp
index 39e9b0bbbf4..77955350305 100644
--- a/intern/cycles/scene/volume.cpp
+++ b/intern/cycles/scene/volume.cpp
@@ -754,11 +754,11 @@ void GeometryManager::create_volume_mesh(const Scene *scene, Volume *volume, Pro
}
/* Print stats. */
- VLOG(1) << "Memory usage volume mesh: "
- << ((vertices.size() + face_normals.size()) * sizeof(float3) +
- indices.size() * sizeof(int)) /
- (1024.0 * 1024.0)
- << "Mb.";
+ VLOG_WORK << "Memory usage volume mesh: "
+ << ((vertices.size() + face_normals.size()) * sizeof(float3) +
+ indices.size() * sizeof(int)) /
+ (1024.0 * 1024.0)
+ << "Mb.";
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/session/denoising.cpp b/intern/cycles/session/denoising.cpp
index ff9ca1b4345..a9377d412e8 100644
--- a/intern/cycles/session/denoising.cpp
+++ b/intern/cycles/session/denoising.cpp
@@ -90,7 +90,7 @@ static vector<ChannelMapping> output_channels()
return map;
}
-/* Renderlayer Handling */
+/* Render-layer Handling. */
bool DenoiseImageLayer::detect_denoising_channels()
{
diff --git a/intern/cycles/session/session.cpp b/intern/cycles/session/session.cpp
index ef177636046..e7de82a6e1b 100644
--- a/intern/cycles/session/session.cpp
+++ b/intern/cycles/session/session.cpp
@@ -146,11 +146,11 @@ void Session::run_main_render_loop()
RenderWork render_work = run_update_for_next_iteration();
if (!render_work) {
- if (VLOG_IS_ON(2)) {
+ if (VLOG_INFO_IS_ON) {
double total_time, render_time;
progress.get_time(total_time, render_time);
- VLOG(2) << "Rendering in main loop is done in " << render_time << " seconds.";
- VLOG(2) << path_trace_->full_report();
+ VLOG_INFO << "Rendering in main loop is done in " << render_time << " seconds.";
+ VLOG_INFO << path_trace_->full_report();
}
if (params.background) {
diff --git a/intern/cycles/session/tile.cpp b/intern/cycles/session/tile.cpp
index 82272a7dbf5..f4930cbb945 100644
--- a/intern/cycles/session/tile.cpp
+++ b/intern/cycles/session/tile.cpp
@@ -335,7 +335,7 @@ int TileManager::compute_render_tile_size(const int suggested_tile_size) const
void TileManager::reset_scheduling(const BufferParams &params, int2 tile_size)
{
- VLOG(3) << "Using tile size of " << tile_size;
+ VLOG_WORK << "Using tile size of " << tile_size;
close_tile_output();
@@ -466,7 +466,7 @@ bool TileManager::open_tile_output()
write_state_.num_tiles_written = 0;
- VLOG(3) << "Opened tile file " << write_state_.filename;
+ VLOG_WORK << "Opened tile file " << write_state_.filename;
return true;
}
@@ -485,7 +485,7 @@ bool TileManager::close_tile_output()
return false;
}
- VLOG(3) << "Tile output is closed.";
+ VLOG_WORK << "Tile output is closed.";
return true;
}
@@ -536,7 +536,7 @@ bool TileManager::write_tile(const RenderBuffers &tile_buffers)
pixels = pixel_storage.data();
}
- VLOG(3) << "Write tile at " << tile_x << ", " << tile_y;
+ VLOG_WORK << "Write tile at " << tile_x << ", " << tile_y;
/* The image tile sizes in the OpenEXR file are different from the size of our big tiles. The
* write_tiles() method expects a contiguous image region that will be split into tiles
@@ -567,7 +567,7 @@ bool TileManager::write_tile(const RenderBuffers &tile_buffers)
++write_state_.num_tiles_written;
- VLOG(3) << "Tile written in " << time_dt() - time_start << " seconds.";
+ VLOG_WORK << "Tile written in " << time_dt() - time_start << " seconds.";
return true;
}
@@ -591,7 +591,7 @@ void TileManager::finish_write_tiles()
const int tile_x = tile.x + tile.window_x;
const int tile_y = tile.y + tile.window_y;
- VLOG(3) << "Write dummy tile at " << tile_x << ", " << tile_y;
+ VLOG_WORK << "Write dummy tile at " << tile_x << ", " << tile_y;
write_state_.tile_out->write_tiles(tile_x,
tile_x + tile.window_width,
@@ -610,8 +610,8 @@ void TileManager::finish_write_tiles()
full_buffer_written_cb(write_state_.filename);
}
- VLOG(3) << "Tile file size is "
- << string_human_readable_number(path_file_size(write_state_.filename)) << " bytes.";
+ VLOG_WORK << "Tile file size is "
+ << string_human_readable_number(path_file_size(write_state_.filename)) << " bytes.";
/* Advance the counter upon explicit finish of the file.
* Makes it possible to re-use tile manager for another scene, and avoids unnecessary increments
diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp
index dac36ab0135..2dc13f0eccb 100644
--- a/intern/cycles/test/render_graph_finalize_test.cpp
+++ b/intern/cycles/test/render_graph_finalize_test.cpp
@@ -166,7 +166,7 @@ class RenderGraph : public testing::Test {
virtual void SetUp()
{
util_logging_start();
- util_logging_verbosity_set(3);
+ util_logging_verbosity_set(5);
device_cpu = Device::create(device_info, stats, profiler);
scene = new Scene(scene_params, device_cpu);
diff --git a/intern/cycles/util/atomic.h b/intern/cycles/util/atomic.h
index f89eb28b0b7..1ebf085ae13 100644
--- a/intern/cycles/util/atomic.h
+++ b/intern/cycles/util/atomic.h
@@ -106,6 +106,116 @@ ccl_device_inline float atomic_compare_and_swap_float(volatile ccl_global float
# endif /* __KERNEL_METAL__ */
+# ifdef __KERNEL_ONEAPI__
+
+ccl_device_inline float atomic_add_and_fetch_float(ccl_global float *p, float x)
+{
+ sycl::atomic_ref<float,
+ sycl::memory_order::relaxed,
+ sycl::memory_scope::device,
+ sycl::access::address_space::ext_intel_global_device_space>
+ atomic(*p);
+ return atomic.fetch_add(x);
+}
+
+ccl_device_inline float atomic_compare_and_swap_float(ccl_global float *source,
+ float old_val,
+ float new_val)
+{
+ sycl::atomic_ref<float,
+ sycl::memory_order::relaxed,
+ sycl::memory_scope::device,
+ sycl::access::address_space::ext_intel_global_device_space>
+ atomic(*source);
+ atomic.compare_exchange_weak(old_val, new_val);
+ return old_val;
+}
+
+ccl_device_inline unsigned int atomic_fetch_and_add_uint32(ccl_global unsigned int *p,
+ unsigned int x)
+{
+ sycl::atomic_ref<unsigned int,
+ sycl::memory_order::relaxed,
+ sycl::memory_scope::device,
+ sycl::access::address_space::ext_intel_global_device_space>
+ atomic(*p);
+ return atomic.fetch_add(x);
+}
+
+ccl_device_inline int atomic_fetch_and_add_uint32(ccl_global int *p, int x)
+{
+ sycl::atomic_ref<int,
+ sycl::memory_order::relaxed,
+ sycl::memory_scope::device,
+ sycl::access::address_space::ext_intel_global_device_space>
+ atomic(*p);
+ return atomic.fetch_add(x);
+}
+
+ccl_device_inline unsigned int atomic_fetch_and_sub_uint32(ccl_global unsigned int *p,
+ unsigned int x)
+{
+ sycl::atomic_ref<unsigned int,
+ sycl::memory_order::relaxed,
+ sycl::memory_scope::device,
+ sycl::access::address_space::ext_intel_global_device_space>
+ atomic(*p);
+ return atomic.fetch_sub(x);
+}
+
+ccl_device_inline int atomic_fetch_and_sub_uint32(ccl_global int *p, int x)
+{
+ sycl::atomic_ref<int,
+ sycl::memory_order::relaxed,
+ sycl::memory_scope::device,
+ sycl::access::address_space::ext_intel_global_device_space>
+ atomic(*p);
+ return atomic.fetch_sub(x);
+}
+
+ccl_device_inline unsigned int atomic_fetch_and_inc_uint32(ccl_global unsigned int *p)
+{
+ return atomic_fetch_and_add_uint32(p, 1);
+}
+
+ccl_device_inline int atomic_fetch_and_inc_uint32(ccl_global int *p)
+{
+ return atomic_fetch_and_add_uint32(p, 1);
+}
+
+ccl_device_inline unsigned int atomic_fetch_and_dec_uint32(ccl_global unsigned int *p)
+{
+ return atomic_fetch_and_sub_uint32(p, 1);
+}
+
+ccl_device_inline int atomic_fetch_and_dec_uint32(ccl_global int *p)
+{
+ return atomic_fetch_and_sub_uint32(p, 1);
+}
+
+ccl_device_inline unsigned int atomic_fetch_and_or_uint32(ccl_global unsigned int *p,
+ unsigned int x)
+{
+ sycl::atomic_ref<unsigned int,
+ sycl::memory_order::relaxed,
+ sycl::memory_scope::device,
+ sycl::access::address_space::ext_intel_global_device_space>
+ atomic(*p);
+ return atomic.fetch_or(x);
+}
+
+ccl_device_inline int atomic_fetch_and_or_uint32(ccl_global int *p, int x)
+{
+ sycl::atomic_ref<int,
+ sycl::memory_order::relaxed,
+ sycl::memory_scope::device,
+ sycl::access::address_space::ext_intel_global_device_space>
+ atomic(*p);
+ return atomic.fetch_or(x);
+}
+
+# endif /* __KERNEL_ONEAPI__ */
+
#endif /* __KERNEL_GPU__ */
#endif /* __UTIL_ATOMIC_H__ */
diff --git a/intern/cycles/util/color.h b/intern/cycles/util/color.h
index 795c3754976..537f8ab6771 100644
--- a/intern/cycles/util/color.h
+++ b/intern/cycles/util/color.h
@@ -318,14 +318,14 @@ ccl_device float3 color_highlight_compress(float3 color, ccl_private float3 *var
{
color += one_float3();
if (variance) {
- *variance *= sqr3(one_float3() / color);
+ *variance *= sqr(one_float3() / color);
}
- return log3(color);
+ return log(color);
}
ccl_device float3 color_highlight_uncompress(float3 color)
{
- return exp3(color) - one_float3();
+ return exp(color) - one_float3();
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/debug.cpp b/intern/cycles/util/debug.cpp
index 65d108bb9d1..faa54a92c24 100644
--- a/intern/cycles/util/debug.cpp
+++ b/intern/cycles/util/debug.cpp
@@ -25,7 +25,7 @@ void DebugFlags::CPU::reset()
do { \
flag = (getenv(env) == NULL); \
if (!flag) { \
- VLOG(1) << "Disabling " << STRINGIFY(flag) << " instruction set."; \
+ VLOG_INFO << "Disabling " << STRINGIFY(flag) << " instruction set."; \
} \
} while (0)
diff --git a/intern/cycles/util/half.h b/intern/cycles/util/half.h
index 59ed652b346..c668638eb02 100644
--- a/intern/cycles/util/half.h
+++ b/intern/cycles/util/half.h
@@ -35,7 +35,7 @@ ccl_device_inline float half_to_float(half h_in)
#else
/* CUDA has its own half data type, no need to define then */
-# if !defined(__KERNEL_CUDA__) && !defined(__KERNEL_HIP__)
+# if !defined(__KERNEL_CUDA__) && !defined(__KERNEL_HIP__) && !defined(__KERNEL_ONEAPI__)
/* Implementing this as a class rather than a typedef so that the compiler can tell it apart from
* unsigned shorts. */
class half {
@@ -73,10 +73,10 @@ struct half4 {
ccl_device_inline half float_to_half_image(float f)
{
-#if defined(__KERNEL_METAL__)
- return half(f);
+#if defined(__KERNEL_METAL__) || defined(__KERNEL_ONEAPI__)
+ return half(min(f, 65504.0f));
#elif defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
- return __float2half(f);
+ return __float2half(min(f, 65504.0f));
#else
const uint u = __float_as_uint(f);
/* Sign bit, shifted to its position. */
@@ -103,6 +103,8 @@ ccl_device_inline float half_to_float_image(half h)
{
#if defined(__KERNEL_METAL__)
return half_to_float(h);
+#elif defined(__KERNEL_ONEAPI__)
+ return float(h);
#elif defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
return __half2float(h);
#else
@@ -136,10 +138,10 @@ ccl_device_inline float4 half4_to_float4_image(const half4 h)
ccl_device_inline half float_to_half_display(const float f)
{
-#if defined(__KERNEL_METAL__)
- return half(f);
+#if defined(__KERNEL_METAL__) || defined(__KERNEL_ONEAPI__)
+ return half(min(f, 65504.0f));
#elif defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__)
- return __float2half(f);
+ return __float2half(min(f, 65504.0f));
#else
const int x = __float_as_int((f > 0.0f) ? ((f < 65504.0f) ? f : 65504.0f) : 0.0f);
const int absolute = x & 0x7FFFFFFF;
diff --git a/intern/cycles/util/image.h b/intern/cycles/util/image.h
index 9348125d072..17446a83e59 100644
--- a/intern/cycles/util/image.h
+++ b/intern/cycles/util/image.h
@@ -78,6 +78,26 @@ template<> inline half util_image_cast_from_float(float value)
return float_to_half_image(value);
}
+/* Multiply image pixels in native data format. */
+template<typename T> inline T util_image_multiply_native(T a, T b);
+
+template<> inline float util_image_multiply_native(float a, float b)
+{
+ return a * b;
+}
+template<> inline uchar util_image_multiply_native(uchar a, uchar b)
+{
+ return ((uint32_t)a * (uint32_t)b) / 255;
+}
+template<> inline uint16_t util_image_multiply_native(uint16_t a, uint16_t b)
+{
+ return ((uint32_t)a * (uint32_t)b) / 65535;
+}
+template<> inline half util_image_multiply_native(half a, half b)
+{
+ return float_to_half_image(half_to_float_image(a) * half_to_float_image(b));
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_IMAGE_H__ */
diff --git a/intern/cycles/util/log.h b/intern/cycles/util/log.h
index b33c826d6f5..3780d03c0d1 100644
--- a/intern/cycles/util/log.h
+++ b/intern/cycles/util/log.h
@@ -69,9 +69,22 @@ class LogMessageVoidify {
# define LOG_ASSERT(expression) LOG_SUPPRESS()
#endif
-#define VLOG_ONCE(level, flag) \
- if (!flag) \
- flag = true, VLOG(level)
+/* Verbose logging categories. */
+
+/* Warnings. */
+#define VLOG_WARNING VLOG(1)
+/* Info about devices, scene contents and features used. */
+#define VLOG_INFO VLOG(2)
+#define VLOG_INFO_IS_ON VLOG_IS_ON(2)
+/* Work being performed and timing/memory stats about that work. */
+#define VLOG_WORK VLOG(3)
+#define VLOG_WORK_IS_ON VLOG_IS_ON(3)
+/* Detailed device timing stats. */
+#define VLOG_DEVICE_STATS VLOG(4)
+#define VLOG_DEVICE_STATS_IS_ON VLOG_IS_ON(4)
+/* Verbose debug messages. */
+#define VLOG_DEBUG VLOG(5)
+#define VLOG_DEBUG_IS_ON VLOG_IS_ON(5)
struct int2;
struct float3;
diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h
index 555a5304764..af2f1ea092d 100644
--- a/intern/cycles/util/math.h
+++ b/intern/cycles/util/math.h
@@ -79,7 +79,7 @@ CCL_NAMESPACE_BEGIN
/* Scalar */
-#ifndef __HIP__
+#if !defined(__HIP__) && !defined(__KERNEL_ONEAPI__)
# ifdef _WIN32
ccl_device_inline float fmaxf(float a, float b)
{
@@ -92,12 +92,18 @@ ccl_device_inline float fminf(float a, float b)
}
# endif /* _WIN32 */
-#endif /* __HIP__ */
+#endif /* __HIP__, __KERNEL_ONEAPI__ */
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
+# ifndef __KERNEL_ONEAPI__
using std::isfinite;
using std::isnan;
using std::sqrt;
+# else
+using sycl::sqrt;
+# define isfinite(x) sycl::isfinite((x))
+# define isnan(x) sycl::isnan((x))
+# endif
ccl_device_inline int abs(int x)
{
@@ -297,8 +303,15 @@ ccl_device_inline float4 __int4_as_float4(int4 i)
#endif /* !defined(__KERNEL_METAL__) */
#if defined(__KERNEL_METAL__)
-# define isnan_safe(v) isnan(v)
-# define isfinite_safe(v) isfinite(v)
+ccl_device_forceinline bool isnan_safe(float f)
+{
+ return isnan(f);
+}
+
+ccl_device_forceinline bool isfinite_safe(float f)
+{
+ return isfinite(f);
+}
#else
template<typename T> ccl_device_inline uint pointer_pack_to_uint_0(T *ptr)
{
@@ -786,6 +799,11 @@ ccl_device_inline uint popcount(uint x)
return i & 1;
}
# endif
+#elif defined(__KERNEL_ONEAPI__)
+# define popcount(x) sycl::popcount(x)
+#elif defined(__KERNEL_HIP__)
+/* Use popcll to support 64-bit wave for pre-RDNA AMD GPUs */
+# define popcount(x) __popcll(x)
#elif !defined(__KERNEL_METAL__)
# define popcount(x) __popc(x)
#endif
@@ -796,6 +814,8 @@ ccl_device_inline uint count_leading_zeros(uint x)
return __clz(x);
#elif defined(__KERNEL_METAL__)
return clz(x);
+#elif defined(__KERNEL_ONEAPI__)
+ return sycl::clz(x);
#else
assert(x != 0);
# ifdef _MSC_VER
@@ -814,6 +834,8 @@ ccl_device_inline uint count_trailing_zeros(uint x)
return (__ffs(x) - 1);
#elif defined(__KERNEL_METAL__)
return ctz(x);
+#elif defined(__KERNEL_ONEAPI__)
+ return sycl::ctz(x);
#else
assert(x != 0);
# ifdef _MSC_VER
diff --git a/intern/cycles/util/math_float3.h b/intern/cycles/util/math_float3.h
index 365c322dd7e..c02b4cdbf0d 100644
--- a/intern/cycles/util/math_float3.h
+++ b/intern/cycles/util/math_float3.h
@@ -53,26 +53,25 @@ ccl_device_inline float3 ceil(const float3 &a);
ccl_device_inline float3 reflect(const float3 incident, const float3 normal);
#endif /* !defined(__KERNEL_METAL__) */
-ccl_device_inline float min3(float3 a);
-ccl_device_inline float max3(float3 a);
+ccl_device_inline float reduce_min(float3 a);
+ccl_device_inline float reduce_max(float3 a);
ccl_device_inline float len(const float3 a);
ccl_device_inline float len_squared(const float3 a);
ccl_device_inline float3 project(const float3 v, const float3 v_proj);
-ccl_device_inline float3 saturate3(float3 a);
ccl_device_inline float3 safe_normalize(const float3 a);
ccl_device_inline float3 normalize_len(const float3 a, ccl_private float *t);
ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t);
-ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b);
-ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b);
+ccl_device_inline float3 safe_divide(const float3 a, const float3 b);
+ccl_device_inline float3 safe_divide(const float3 a, const float b);
ccl_device_inline float3 interp(float3 a, float3 b, float t);
-ccl_device_inline float3 sqr3(float3 a);
+ccl_device_inline float3 sqr(float3 a);
ccl_device_inline bool is_zero(const float3 a);
ccl_device_inline float reduce_add(const float3 a);
ccl_device_inline float average(const float3 a);
-ccl_device_inline bool isequal_float3(const float3 a, const float3 b);
+ccl_device_inline bool isequal(const float3 a, const float3 b);
/*******************************************************************************
* Definition.
@@ -377,14 +376,30 @@ ccl_device_inline float3 rcp(const float3 &a)
return make_float3(1.0f / a.x, 1.0f / a.y, 1.0f / a.z);
# endif
}
+
+ccl_device_inline float3 saturate(float3 a)
+{
+ return make_float3(saturatef(a.x), saturatef(a.y), saturatef(a.z));
+}
+
+ccl_device_inline float3 exp(float3 v)
+{
+ return make_float3(expf(v.x), expf(v.y), expf(v.z));
+}
+
+ccl_device_inline float3 log(float3 v)
+{
+ return make_float3(logf(v.x), logf(v.y), logf(v.z));
+}
+
#endif /* !__KERNEL_METAL__ */
-ccl_device_inline float min3(float3 a)
+ccl_device_inline float reduce_min(float3 a)
{
return min(min(a.x, a.y), a.z);
}
-ccl_device_inline float max3(float3 a)
+ccl_device_inline float reduce_max(float3 a)
{
return max(max(a.x, a.y), a.z);
}
@@ -433,11 +448,6 @@ ccl_device_inline float3 project(const float3 v, const float3 v_proj)
return (len_squared != 0.0f) ? (dot(v, v_proj) / len_squared) * v_proj : zero_float3();
}
-ccl_device_inline float3 saturate3(float3 a)
-{
- return make_float3(saturatef(a.x), saturatef(a.y), saturatef(a.z));
-}
-
ccl_device_inline float3 normalize_len(const float3 a, ccl_private float *t)
{
*t = len(a);
@@ -457,14 +467,14 @@ ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t
return (*t != 0.0f) ? a / (*t) : a;
}
-ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b)
+ccl_device_inline float3 safe_divide(const float3 a, const float3 b)
{
return make_float3((b.x != 0.0f) ? a.x / b.x : 0.0f,
(b.y != 0.0f) ? a.y / b.y : 0.0f,
(b.z != 0.0f) ? a.z / b.z : 0.0f);
}
-ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b)
+ccl_device_inline float3 safe_divide(const float3 a, const float b)
{
return (b != 0.0f) ? a / b : zero_float3();
}
@@ -474,7 +484,7 @@ ccl_device_inline float3 interp(float3 a, float3 b, float t)
return a + t * (b - a);
}
-ccl_device_inline float3 sqr3(float3 a)
+ccl_device_inline float3 sqr(float3 a)
{
return a * a;
}
@@ -504,7 +514,7 @@ ccl_device_inline float average(const float3 a)
return reduce_add(a) * (1.0f / 3.0f);
}
-ccl_device_inline bool isequal_float3(const float3 a, const float3 b)
+ccl_device_inline bool isequal(const float3 a, const float3 b)
{
#if defined(__KERNEL_METAL__)
return all(a == b);
@@ -513,21 +523,11 @@ ccl_device_inline bool isequal_float3(const float3 a, const float3 b)
#endif
}
-ccl_device_inline float3 pow3(float3 v, float e)
+ccl_device_inline float3 pow(float3 v, float e)
{
return make_float3(powf(v.x, e), powf(v.y, e), powf(v.z, e));
}
-ccl_device_inline float3 exp3(float3 v)
-{
- return make_float3(expf(v.x), expf(v.y), expf(v.z));
-}
-
-ccl_device_inline float3 log3(float3 v)
-{
- return make_float3(logf(v.x), logf(v.y), logf(v.z));
-}
-
ccl_device_inline int3 quick_floor_to_int3(const float3 a)
{
#ifdef __KERNEL_SSE__
@@ -540,12 +540,12 @@ ccl_device_inline int3 quick_floor_to_int3(const float3 a)
#endif
}
-ccl_device_inline bool isfinite3_safe(float3 v)
+ccl_device_inline bool isfinite_safe(float3 v)
{
return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z);
}
-ccl_device_inline float3 ensure_finite3(float3 v)
+ccl_device_inline float3 ensure_finite(float3 v)
{
if (!isfinite_safe(v.x))
v.x = 0.0f;
diff --git a/intern/cycles/util/math_float4.h b/intern/cycles/util/math_float4.h
index ae9dfe75a9c..c2721873037 100644
--- a/intern/cycles/util/math_float4.h
+++ b/intern/cycles/util/math_float4.h
@@ -55,7 +55,8 @@ ccl_device_inline float4 floor(const float4 &a);
ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t);
#endif /* !__KERNEL_METAL__*/
-ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b);
+ccl_device_inline float4 safe_divide(const float4 a, const float4 b);
+ccl_device_inline float4 safe_divide(const float4 a, const float b);
#ifdef __KERNEL_SSE__
template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
@@ -74,11 +75,14 @@ template<> __forceinline const float4 shuffle<1, 1, 3, 3>(const float4 &b);
# endif
#endif /* __KERNEL_SSE__ */
+ccl_device_inline float reduce_min(const float4 a);
+ccl_device_inline float reduce_max(const float4 a);
+ccl_device_inline float reduce_add(const float4 a);
+
+ccl_device_inline bool isequal(const float4 a, const float4 b);
+
#ifndef __KERNEL_GPU__
ccl_device_inline float4 select(const int4 &mask, const float4 &a, const float4 &b);
-ccl_device_inline float4 reduce_min(const float4 &a);
-ccl_device_inline float4 reduce_max(const float4 &a);
-ccl_device_inline float4 reduce_add(const float4 &a);
#endif /* !__KERNEL_GPU__ */
/*******************************************************************************
@@ -303,27 +307,9 @@ ccl_device_inline bool is_zero(const float4 &a)
# endif
}
-ccl_device_inline float4 reduce_add(const float4 &a)
-{
-# if defined(__KERNEL_SSE__)
-# if defined(__KERNEL_NEON__)
- return float4(vdupq_n_f32(vaddvq_f32(a)));
-# elif defined(__KERNEL_SSE3__)
- float4 h(_mm_hadd_ps(a.m128, a.m128));
- return float4(_mm_hadd_ps(h.m128, h.m128));
-# else
- float4 h(shuffle<1, 0, 3, 2>(a) + a);
- return shuffle<2, 3, 0, 1>(h) + h;
-# endif
-# else
- float sum = (a.x + a.y) + (a.z + a.w);
- return make_float4(sum, sum, sum, sum);
-# endif
-}
-
ccl_device_inline float average(const float4 &a)
{
- return reduce_add(a).x * 0.25f;
+ return reduce_add(a) * 0.25f;
}
ccl_device_inline float len(const float4 &a)
@@ -392,8 +378,77 @@ ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t)
return a + t * (b - a);
}
+ccl_device_inline float4 saturate(const float4 &a)
+{
+ return make_float4(saturatef(a.x), saturatef(a.y), saturatef(a.z), saturatef(a.w));
+}
+
+ccl_device_inline float4 exp(float4 v)
+{
+ return make_float4(expf(v.x), expf(v.y), expf(v.z), expf(v.z));
+}
+
+ccl_device_inline float4 log(float4 v)
+{
+ return make_float4(logf(v.x), logf(v.y), logf(v.z), logf(v.z));
+}
+
#endif /* !__KERNEL_METAL__*/
+ccl_device_inline float reduce_add(const float4 a)
+{
+#if defined(__KERNEL_SSE__)
+# if defined(__KERNEL_NEON__)
+ return vaddvq_f32(a);
+# elif defined(__KERNEL_SSE3__)
+ float4 h(_mm_hadd_ps(a.m128, a.m128));
+ return _mm_cvtss_f32(_mm_hadd_ps(h.m128, h.m128));
+# else
+ float4 h(shuffle<1, 0, 3, 2>(a) + a);
+ return _mm_cvtss_f32(shuffle<2, 3, 0, 1>(h) + h);
+# endif
+#else
+ return a.x + a.y + a.z + a.w;
+#endif
+}
+
+ccl_device_inline float reduce_min(const float4 a)
+{
+#if defined(__KERNEL_SSE__)
+# if defined(__KERNEL_NEON__)
+ return vminvq_f32(a);
+# else
+ float4 h = min(shuffle<1, 0, 3, 2>(a), a);
+ return _mm_cvtss_f32(min(shuffle<2, 3, 0, 1>(h), h));
+# endif
+#else
+ return min(min(a.x, a.y), min(a.z, a.w));
+#endif
+}
+
+ccl_device_inline float reduce_max(const float4 a)
+{
+#if defined(__KERNEL_SSE__)
+# if defined(__KERNEL_NEON__)
+ return vmaxvq_f32(a);
+# else
+ float4 h = max(shuffle<1, 0, 3, 2>(a), a);
+ return _mm_cvtss_f32(max(shuffle<2, 3, 0, 1>(h), h));
+# endif
+#else
+ return max(max(a.x, a.y), max(a.z, a.w));
+#endif
+}
+
+ccl_device_inline bool isequal(const float4 a, const float4 b)
+{
+#if defined(__KERNEL_METAL__)
+ return all(a == b);
+#else
+ return a == b;
+#endif
+}
+
#ifdef __KERNEL_SSE__
template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
__forceinline const float4 shuffle(const float4 &b)
@@ -461,34 +516,6 @@ ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
return select(mask, a, zero_float4());
}
-ccl_device_inline float4 reduce_min(const float4 &a)
-{
-# if defined(__KERNEL_SSE__)
-# if defined(__KERNEL_NEON__)
- return float4(vdupq_n_f32(vminvq_f32(a)));
-# else
- float4 h = min(shuffle<1, 0, 3, 2>(a), a);
- return min(shuffle<2, 3, 0, 1>(h), h);
-# endif
-# else
- return make_float4(min(min(a.x, a.y), min(a.z, a.w)));
-# endif
-}
-
-ccl_device_inline float4 reduce_max(const float4 &a)
-{
-# if defined(__KERNEL_SSE__)
-# if defined(__KERNEL_NEON__)
- return float4(vdupq_n_f32(vmaxvq_f32(a)));
-# else
- float4 h = max(shuffle<1, 0, 3, 2>(a), a);
- return max(shuffle<2, 3, 0, 1>(h), h);
-# endif
-# else
- return make_float4(max(max(a.x, a.y), max(a.z, a.w)));
-# endif
-}
-
ccl_device_inline float4 load_float4(ccl_private const float *v)
{
# ifdef __KERNEL_SSE__
@@ -500,17 +527,25 @@ ccl_device_inline float4 load_float4(ccl_private const float *v)
#endif /* !__KERNEL_GPU__ */
-ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b)
+ccl_device_inline float4 safe_divide(const float4 a, const float b)
{
return (b != 0.0f) ? a / b : zero_float4();
}
-ccl_device_inline bool isfinite4_safe(float4 v)
+ccl_device_inline float4 safe_divide(const float4 a, const float4 b)
+{
+ return make_float4((b.x != 0.0f) ? a.x / b.x : 0.0f,
+ (b.y != 0.0f) ? a.y / b.y : 0.0f,
+ (b.z != 0.0f) ? a.z / b.z : 0.0f,
+ (b.w != 0.0f) ? a.w / b.w : 0.0f);
+}
+
+ccl_device_inline bool isfinite_safe(float4 v)
{
return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z) && isfinite_safe(v.w);
}
-ccl_device_inline float4 ensure_finite4(float4 v)
+ccl_device_inline float4 ensure_finite(float4 v)
{
if (!isfinite_safe(v.x))
v.x = 0.0f;
@@ -523,6 +558,11 @@ ccl_device_inline float4 ensure_finite4(float4 v)
return v;
}
+ccl_device_inline float4 pow(float4 v, float e)
+{
+ return make_float4(powf(v.x, e), powf(v.y, e), powf(v.z, e), powf(v.z, e));
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_FLOAT4_H__ */
diff --git a/intern/cycles/util/math_intersect.h b/intern/cycles/util/math_intersect.h
index b0de0b25a45..c5b1cd51030 100644
--- a/intern/cycles/util/math_intersect.h
+++ b/intern/cycles/util/math_intersect.h
@@ -10,7 +10,8 @@ CCL_NAMESPACE_BEGIN
ccl_device bool ray_sphere_intersect(float3 ray_P,
float3 ray_D,
- float ray_t,
+ float ray_tmin,
+ float ray_tmax,
float3 sphere_P,
float sphere_radius,
ccl_private float3 *isect_P,
@@ -33,7 +34,7 @@ ccl_device bool ray_sphere_intersect(float3 ray_P,
return false;
}
const float t = tp - sqrtf(radiussq - dsq); /* pythagoras */
- if (t < ray_t) {
+ if (t > ray_tmin && t < ray_tmax) {
*isect_t = t;
*isect_P = ray_P + ray_D * t;
return true;
@@ -44,7 +45,8 @@ ccl_device bool ray_sphere_intersect(float3 ray_P,
ccl_device bool ray_aligned_disk_intersect(float3 ray_P,
float3 ray_D,
- float ray_t,
+ float ray_tmin,
+ float ray_tmax,
float3 disk_P,
float disk_radius,
ccl_private float3 *isect_P,
@@ -59,7 +61,7 @@ ccl_device bool ray_aligned_disk_intersect(float3 ray_P,
}
/* Compute t to intersection point. */
const float t = -disk_t / div;
- if (t < 0.0f || t > ray_t) {
+ if (!(t > ray_tmin && t < ray_tmax)) {
return false;
}
/* Test if within radius. */
@@ -74,7 +76,8 @@ ccl_device bool ray_aligned_disk_intersect(float3 ray_P,
ccl_device bool ray_disk_intersect(float3 ray_P,
float3 ray_D,
- float ray_t,
+ float ray_tmin,
+ float ray_tmax,
float3 disk_P,
float3 disk_N,
float disk_radius,
@@ -92,7 +95,8 @@ ccl_device bool ray_disk_intersect(float3 ray_P,
}
float3 P = ray_P + t * ray_D;
float3 T = P - disk_P;
- if (dot(T, T) < sqr(disk_radius) /*&& t > 0.f*/ && t <= ray_t) {
+
+ if (dot(T, T) < sqr(disk_radius) && (t > ray_tmin && t < ray_tmax)) {
*isect_P = ray_P + t * ray_D;
*isect_t = t;
return true;
@@ -103,7 +107,8 @@ ccl_device bool ray_disk_intersect(float3 ray_P,
ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
float3 ray_dir,
- float ray_t,
+ float ray_tmin,
+ float ray_tmax,
const float3 tri_a,
const float3 tri_b,
const float3 tri_c,
@@ -149,16 +154,14 @@ ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
/* Perform depth test. */
const float T = dot3(v0, Ng);
- const int sign_den = (__float_as_int(den) & 0x80000000);
- const float sign_T = xor_signmask(T, sign_den);
- if ((sign_T < 0.0f) || (sign_T > ray_t * xor_signmask(den, sign_den))) {
+ const float t = T / den;
+ if (!(t >= ray_tmin && t <= ray_tmax)) {
return false;
}
- const float inv_den = 1.0f / den;
- *isect_u = U * inv_den;
- *isect_v = V * inv_den;
- *isect_t = T * inv_den;
+ *isect_u = U / den;
+ *isect_v = V / den;
+ *isect_t = t;
return true;
#undef dot3
@@ -171,8 +174,8 @@ ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P,
*/
ccl_device bool ray_quad_intersect(float3 ray_P,
float3 ray_D,
- float ray_mint,
- float ray_maxt,
+ float ray_tmin,
+ float ray_tmax,
float3 quad_P,
float3 quad_u,
float3 quad_v,
@@ -185,7 +188,7 @@ ccl_device bool ray_quad_intersect(float3 ray_P,
{
/* Perform intersection test. */
float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
- if (t < ray_mint || t > ray_maxt) {
+ if (!(t > ray_tmin && t < ray_tmax)) {
return false;
}
const float3 hit = ray_P + t * ray_D;
diff --git a/intern/cycles/util/string.cpp b/intern/cycles/util/string.cpp
index 66ff866ee10..0c318cea44a 100644
--- a/intern/cycles/util/string.cpp
+++ b/intern/cycles/util/string.cpp
@@ -136,6 +136,19 @@ void string_replace(string &haystack, const string &needle, const string &other)
}
}
+void string_replace_same_length(string &haystack, const string &needle, const string &other)
+{
+ assert(needle.size() == other.size());
+ size_t pos = 0;
+ while (pos != string::npos) {
+ pos = haystack.find(needle, pos);
+ if (pos != string::npos) {
+ memcpy(haystack.data() + pos, other.data(), other.size());
+ pos += other.size();
+ }
+ }
+}
+
string string_remove_trademark(const string &s)
{
string result = s;
@@ -164,6 +177,11 @@ string to_string(const char *str)
return string(str);
}
+string to_string(const float4 &v)
+{
+ return string_printf("%f,%f,%f,%f", v.x, v.y, v.z, v.w);
+}
+
string string_to_lower(const string &s)
{
string r = s;
diff --git a/intern/cycles/util/string.h b/intern/cycles/util/string.h
index a74feee1750..ecbe9e106c6 100644
--- a/intern/cycles/util/string.h
+++ b/intern/cycles/util/string.h
@@ -38,12 +38,14 @@ void string_split(vector<string> &tokens,
const string &separators = "\t ",
bool skip_empty_tokens = true);
void string_replace(string &haystack, const string &needle, const string &other);
+void string_replace_same_length(string &haystack, const string &needle, const string &other);
bool string_startswith(string_view s, string_view start);
bool string_endswith(string_view s, string_view end);
string string_strip(const string &s);
string string_remove_trademark(const string &s);
string string_from_bool(const bool var);
string to_string(const char *str);
+string to_string(const float4 &v);
string string_to_lower(const string &s);
/* Wide char strings are only used on Windows to deal with non-ASCII
diff --git a/intern/cycles/util/task.cpp b/intern/cycles/util/task.cpp
index 2edc82eb7c3..12f661f752d 100644
--- a/intern/cycles/util/task.cpp
+++ b/intern/cycles/util/task.cpp
@@ -70,7 +70,7 @@ void TaskScheduler::init(int num_threads)
}
if (num_threads > 0) {
/* Automatic number of threads. */
- VLOG(1) << "Overriding number of TBB threads to " << num_threads << ".";
+ VLOG_INFO << "Overriding number of TBB threads to " << num_threads << ".";
global_control = new tbb::global_control(tbb::global_control::max_allowed_parallelism,
num_threads);
active_num_threads = num_threads;
diff --git a/intern/cycles/util/time.cpp b/intern/cycles/util/time.cpp
index d27a0415106..0295a071f39 100644
--- a/intern/cycles/util/time.cpp
+++ b/intern/cycles/util/time.cpp
@@ -102,7 +102,7 @@ double time_human_readable_to_seconds(const string &time_string)
}
else if (fraction_tokens.size() == 2) {
result = atof(fraction_tokens[1].c_str());
- result *= pow(0.1, fraction_tokens[1].length());
+ result *= ::pow(0.1, fraction_tokens[1].length());
}
else {
/* This is not a valid string, the result can not be reliable. */
diff --git a/intern/cycles/util/transform.cpp b/intern/cycles/util/transform.cpp
index fa50e1db063..0bf5de57a20 100644
--- a/intern/cycles/util/transform.cpp
+++ b/intern/cycles/util/transform.cpp
@@ -229,17 +229,17 @@ static void transform_decompose(DecomposedTransform *decomp, const Transform *tf
/* extract scale and shear first */
float3 scale, shear;
scale.x = len(colx);
- colx = safe_divide_float3_float(colx, scale.x);
+ colx = safe_divide(colx, scale.x);
shear.z = dot(colx, coly);
coly -= shear.z * colx;
scale.y = len(coly);
- coly = safe_divide_float3_float(coly, scale.y);
+ coly = safe_divide(coly, scale.y);
shear.y = dot(colx, colz);
colz -= shear.y * colx;
shear.x = dot(coly, colz);
colz -= shear.x * coly;
scale.z = len(colz);
- colz = safe_divide_float3_float(colz, scale.z);
+ colz = safe_divide(colz, scale.z);
transform_set_column(&M, 0, colx);
transform_set_column(&M, 1, coly);
diff --git a/intern/cycles/util/transform.h b/intern/cycles/util/transform.h
index 477272f0ba6..a460581d1f3 100644
--- a/intern/cycles/util/transform.h
+++ b/intern/cycles/util/transform.h
@@ -493,13 +493,13 @@ ccl_device void transform_motion_array_interpolate(ccl_private Transform *tfm,
ccl_device_inline bool transform_isfinite_safe(ccl_private Transform *tfm)
{
- return isfinite4_safe(tfm->x) && isfinite4_safe(tfm->y) && isfinite4_safe(tfm->z);
+ return isfinite_safe(tfm->x) && isfinite_safe(tfm->y) && isfinite_safe(tfm->z);
}
ccl_device_inline bool transform_decomposed_isfinite_safe(ccl_private DecomposedTransform *decomp)
{
- return isfinite4_safe(decomp->x) && isfinite4_safe(decomp->y) && isfinite4_safe(decomp->z) &&
- isfinite4_safe(decomp->w);
+ return isfinite_safe(decomp->x) && isfinite_safe(decomp->y) && isfinite_safe(decomp->z) &&
+ isfinite_safe(decomp->w);
}
#ifndef __KERNEL_GPU__
diff --git a/intern/cycles/util/types_float2.h b/intern/cycles/util/types_float2.h
index d8b2efb7b4b..07b9ec0986b 100644
--- a/intern/cycles/util/types_float2.h
+++ b/intern/cycles/util/types_float2.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct float2 {
float x, y;
@@ -20,7 +20,7 @@ struct float2 {
ccl_device_inline float2 make_float2(float x, float y);
ccl_device_inline void print_float2(const char *label, const float2 &a);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_float2_impl.h b/intern/cycles/util/types_float2_impl.h
index d67ec946b79..45fc90c52bd 100644
--- a/intern/cycles/util/types_float2_impl.h
+++ b/intern/cycles/util/types_float2_impl.h
@@ -14,7 +14,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
__forceinline float float2::operator[](int i) const
{
util_assert(i >= 0);
@@ -39,7 +39,7 @@ ccl_device_inline void print_float2(const char *label, const float2 &a)
{
printf("%s: %.8f %.8f\n", label, (double)a.x, (double)a.y);
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_float3.h b/intern/cycles/util/types_float3.h
index 060c2ac4152..c7900acaa69 100644
--- a/intern/cycles/util/types_float3.h
+++ b/intern/cycles/util/types_float3.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__)
struct ccl_try_align(16) float3
{
# ifdef __KERNEL_SSE__
@@ -40,7 +40,7 @@ struct ccl_try_align(16) float3
ccl_device_inline float3 make_float3(float f);
ccl_device_inline float3 make_float3(float x, float y, float z);
ccl_device_inline void print_float3(const char *label, const float3 &a);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) */
/* Smaller float3 for storage. For math operations this must be converted to float3, so that on the
* CPU SIMD instructions can be used. */
diff --git a/intern/cycles/util/types_float3_impl.h b/intern/cycles/util/types_float3_impl.h
index f5ffc48c1be..2e6e864c8ea 100644
--- a/intern/cycles/util/types_float3_impl.h
+++ b/intern/cycles/util/types_float3_impl.h
@@ -14,7 +14,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__)
# ifdef __KERNEL_SSE__
__forceinline float3::float3()
{
@@ -83,7 +83,7 @@ ccl_device_inline void print_float3(const char *label, const float3 &a)
{
printf("%s: %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z);
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_float4.h b/intern/cycles/util/types_float4.h
index 68ba787dac0..27453bf39e4 100644
--- a/intern/cycles/util/types_float4.h
+++ b/intern/cycles/util/types_float4.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct int4;
struct ccl_try_align(16) float4
@@ -43,7 +43,7 @@ ccl_device_inline float4 make_float4(float f);
ccl_device_inline float4 make_float4(float x, float y, float z, float w);
ccl_device_inline float4 make_float4(const int4 &i);
ccl_device_inline void print_float4(const char *label, const float4 &a);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_float4_impl.h b/intern/cycles/util/types_float4_impl.h
index de2e7cb7061..d7858f744e3 100644
--- a/intern/cycles/util/types_float4_impl.h
+++ b/intern/cycles/util/types_float4_impl.h
@@ -14,7 +14,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
# ifdef __KERNEL_SSE__
__forceinline float4::float4()
{
@@ -89,7 +89,7 @@ ccl_device_inline void print_float4(const char *label, const float4 &a)
{
printf("%s: %.8f %.8f %.8f %.8f\n", label, (double)a.x, (double)a.y, (double)a.z, (double)a.w);
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_float8.h b/intern/cycles/util/types_float8.h
index 99f9ec9b867..d71149946f7 100644
--- a/intern/cycles/util/types_float8.h
+++ b/intern/cycles/util/types_float8.h
@@ -11,7 +11,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct ccl_try_align(32) float8
{
@@ -43,7 +43,7 @@ struct ccl_try_align(32) float8
ccl_device_inline float8 make_float8(float f);
ccl_device_inline float8
make_float8(float a, float b, float c, float d, float e, float f, float g, float h);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_float8_impl.h b/intern/cycles/util/types_float8_impl.h
index 19818976b50..0694f5205a5 100644
--- a/intern/cycles/util/types_float8_impl.h
+++ b/intern/cycles/util/types_float8_impl.h
@@ -15,7 +15,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
# ifdef __KERNEL_AVX2__
__forceinline float8::float8()
{
@@ -81,7 +81,7 @@ make_float8(float a, float b, float c, float d, float e, float f, float g, float
return r;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_int2.h b/intern/cycles/util/types_int2.h
index 4daf387d9cf..bf69cddc653 100644
--- a/intern/cycles/util/types_int2.h
+++ b/intern/cycles/util/types_int2.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct int2 {
int x, y;
@@ -19,7 +19,7 @@ struct int2 {
};
ccl_device_inline int2 make_int2(int x, int y);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_int2_impl.h b/intern/cycles/util/types_int2_impl.h
index 7989c4d5506..7bdc77369ee 100644
--- a/intern/cycles/util/types_int2_impl.h
+++ b/intern/cycles/util/types_int2_impl.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
int int2::operator[](int i) const
{
util_assert(i >= 0);
@@ -30,7 +30,7 @@ ccl_device_inline int2 make_int2(int x, int y)
int2 a = {x, y};
return a;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_int3.h b/intern/cycles/util/types_int3.h
index ad9bcb39bbe..f88ff22ac35 100644
--- a/intern/cycles/util/types_int3.h
+++ b/intern/cycles/util/types_int3.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct ccl_try_align(16) int3
{
# ifdef __KERNEL_SSE__
@@ -40,7 +40,7 @@ struct ccl_try_align(16) int3
ccl_device_inline int3 make_int3(int i);
ccl_device_inline int3 make_int3(int x, int y, int z);
ccl_device_inline void print_int3(const char *label, const int3 &a);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_int3_impl.h b/intern/cycles/util/types_int3_impl.h
index 4cfc1cf2987..1c49e97ad32 100644
--- a/intern/cycles/util/types_int3_impl.h
+++ b/intern/cycles/util/types_int3_impl.h
@@ -14,7 +14,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
# ifdef __KERNEL_SSE__
__forceinline int3::int3()
{
@@ -84,7 +84,7 @@ ccl_device_inline void print_int3(const char *label, const int3 &a)
{
printf("%s: %d %d %d\n", label, a.x, a.y, a.z);
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_int4.h b/intern/cycles/util/types_int4.h
index f35632fb52f..9d557c01344 100644
--- a/intern/cycles/util/types_int4.h
+++ b/intern/cycles/util/types_int4.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct float3;
struct float4;
@@ -46,7 +46,7 @@ ccl_device_inline int4 make_int4(int x, int y, int z, int w);
ccl_device_inline int4 make_int4(const float3 &f);
ccl_device_inline int4 make_int4(const float4 &f);
ccl_device_inline void print_int4(const char *label, const int4 &a);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_int4_impl.h b/intern/cycles/util/types_int4_impl.h
index adb4a4cebac..11e1ede6705 100644
--- a/intern/cycles/util/types_int4_impl.h
+++ b/intern/cycles/util/types_int4_impl.h
@@ -14,7 +14,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
# ifdef __KERNEL_SSE__
__forceinline int4::int4()
{
@@ -83,6 +83,8 @@ ccl_device_inline int4 make_int4(const float3 &f)
{
# ifdef __KERNEL_SSE__
int4 a(_mm_cvtps_epi32(f.m128));
+# elif defined(__KERNEL_ONEAPI__)
+ int4 a = {(int)f.x, (int)f.y, (int)f.z, 0};
# else
int4 a = {(int)f.x, (int)f.y, (int)f.z, (int)f.w};
# endif
@@ -103,7 +105,7 @@ ccl_device_inline void print_int4(const char *label, const int4 &a)
{
printf("%s: %d %d %d %d\n", label, a.x, a.y, a.z, a.w);
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar2.h b/intern/cycles/util/types_uchar2.h
index 445fa8dd703..0b3c9bd0331 100644
--- a/intern/cycles/util/types_uchar2.h
+++ b/intern/cycles/util/types_uchar2.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct uchar2 {
uchar x, y;
@@ -19,7 +19,7 @@ struct uchar2 {
};
ccl_device_inline uchar2 make_uchar2(uchar x, uchar y);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar2_impl.h b/intern/cycles/util/types_uchar2_impl.h
index cec1c679050..a7254d5eaf2 100644
--- a/intern/cycles/util/types_uchar2_impl.h
+++ b/intern/cycles/util/types_uchar2_impl.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
uchar uchar2::operator[](int i) const
{
util_assert(i >= 0);
@@ -30,7 +30,7 @@ ccl_device_inline uchar2 make_uchar2(uchar x, uchar y)
uchar2 a = {x, y};
return a;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar3.h b/intern/cycles/util/types_uchar3.h
index 1ebd86441c3..fc213502ada 100644
--- a/intern/cycles/util/types_uchar3.h
+++ b/intern/cycles/util/types_uchar3.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct uchar3 {
uchar x, y, z;
@@ -19,7 +19,7 @@ struct uchar3 {
};
ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar3_impl.h b/intern/cycles/util/types_uchar3_impl.h
index 0656baa3da4..0c24ffb488a 100644
--- a/intern/cycles/util/types_uchar3_impl.h
+++ b/intern/cycles/util/types_uchar3_impl.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
uchar uchar3::operator[](int i) const
{
util_assert(i >= 0);
@@ -30,7 +30,7 @@ ccl_device_inline uchar3 make_uchar3(uchar x, uchar y, uchar z)
uchar3 a = {x, y, z};
return a;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar4.h b/intern/cycles/util/types_uchar4.h
index 2ac4fb56cbb..a2a2c945aaa 100644
--- a/intern/cycles/util/types_uchar4.h
+++ b/intern/cycles/util/types_uchar4.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct uchar4 {
uchar x, y, z, w;
@@ -19,7 +19,7 @@ struct uchar4 {
};
ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uchar4_impl.h b/intern/cycles/util/types_uchar4_impl.h
index b3e8abfe873..8ec6213a37d 100644
--- a/intern/cycles/util/types_uchar4_impl.h
+++ b/intern/cycles/util/types_uchar4_impl.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
uchar uchar4::operator[](int i) const
{
util_assert(i >= 0);
@@ -30,7 +30,7 @@ ccl_device_inline uchar4 make_uchar4(uchar x, uchar y, uchar z, uchar w)
uchar4 a = {x, y, z, w};
return a;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uint2.h b/intern/cycles/util/types_uint2.h
index e3254b9f0e1..faa0955f903 100644
--- a/intern/cycles/util/types_uint2.h
+++ b/intern/cycles/util/types_uint2.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct uint2 {
uint x, y;
@@ -19,7 +19,7 @@ struct uint2 {
};
ccl_device_inline uint2 make_uint2(uint x, uint y);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uint2_impl.h b/intern/cycles/util/types_uint2_impl.h
index e67134a011e..cac0ba6b531 100644
--- a/intern/cycles/util/types_uint2_impl.h
+++ b/intern/cycles/util/types_uint2_impl.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
__forceinline uint uint2::operator[](uint i) const
{
util_assert(i < 2);
@@ -28,7 +28,7 @@ ccl_device_inline uint2 make_uint2(uint x, uint y)
uint2 a = {x, y};
return a;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uint3.h b/intern/cycles/util/types_uint3.h
index 885a8fb84ce..3ff87bfc791 100644
--- a/intern/cycles/util/types_uint3.h
+++ b/intern/cycles/util/types_uint3.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct uint3 {
uint x, y, z;
@@ -19,7 +19,7 @@ struct uint3 {
};
ccl_device_inline uint3 make_uint3(uint x, uint y, uint z);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uint3_impl.h b/intern/cycles/util/types_uint3_impl.h
index f4d3d72469c..221883a1adb 100644
--- a/intern/cycles/util/types_uint3_impl.h
+++ b/intern/cycles/util/types_uint3_impl.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
__forceinline uint uint3::operator[](uint i) const
{
util_assert(i < 3);
@@ -28,7 +28,7 @@ ccl_device_inline uint3 make_uint3(uint x, uint y, uint z)
uint3 a = {x, y, z};
return a;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uint4.h b/intern/cycles/util/types_uint4.h
index d582b91d2a0..504095b2383 100644
--- a/intern/cycles/util/types_uint4.h
+++ b/intern/cycles/util/types_uint4.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct uint4 {
uint x, y, z, w;
@@ -19,7 +19,7 @@ struct uint4 {
};
ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w);
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_uint4_impl.h b/intern/cycles/util/types_uint4_impl.h
index 98a4c5e9fe9..d78db944a1f 100644
--- a/intern/cycles/util/types_uint4_impl.h
+++ b/intern/cycles/util/types_uint4_impl.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
__forceinline uint uint4::operator[](uint i) const
{
util_assert(i < 3);
@@ -28,7 +28,7 @@ ccl_device_inline uint4 make_uint4(uint x, uint y, uint z, uint w)
uint4 a = {x, y, z, w};
return a;
}
-#endif /* __KERNEL_GPU__ */
+#endif /* !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__) */
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/types_ushort4.h b/intern/cycles/util/types_ushort4.h
index 1766c6bf734..9a6e12095ba 100644
--- a/intern/cycles/util/types_ushort4.h
+++ b/intern/cycles/util/types_ushort4.h
@@ -10,7 +10,7 @@
CCL_NAMESPACE_BEGIN
-#ifndef __KERNEL_GPU__
+#if !defined(__KERNEL_GPU__) || defined(__KERNEL_ONEAPI__)
struct ushort4 {
uint16_t x, y, z, w;
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index dceb9ced803..c681dc368bb 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -3,6 +3,7 @@
set(INC
.
+ ../clog
../glew-mx
../../source/blender/imbuf
../../source/blender/makesdna
@@ -65,6 +66,8 @@ set(SRC
intern/GHOST_Util.h
intern/GHOST_Window.h
intern/GHOST_WindowManager.h
+ intern/GHOST_utildefines.h
+ intern/GHOST_utildefines_variadic.h
)
set(LIB
@@ -268,9 +271,30 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
${wayland-egl_INCLUDE_DIRS}
${xkbcommon_INCLUDE_DIRS}
${wayland-cursor_INCLUDE_DIRS}
- ${dbus_INCLUDE_DIRS}
)
+ if(WITH_GHOST_WAYLAND_DYNLOAD)
+ list(APPEND INC_SYS
+ ../../intern/wayland_dynload/extern
+ )
+ list(APPEND LIB
+ bf_intern_wayland_dynload
+ )
+ add_definitions(-DWITH_GHOST_WAYLAND_DYNLOAD)
+ endif()
+
+ if(WITH_GHOST_WAYLAND_DBUS)
+ list(APPEND INC_SYS
+ ${dbus_INCLUDE_DIRS}
+ )
+ endif()
+
+ if(WITH_GHOST_WAYLAND_LIBDECOR)
+ list(APPEND INC_SYS
+ ${libdecor_INCLUDE_DIRS}
+ )
+ endif()
+
include(CheckSymbolExists)
set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
@@ -303,49 +327,66 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
message(FATAL_ERROR "path to wayland-protocols not found")
endif()
+ set(INC_DST ${CMAKE_CURRENT_BINARY_DIR}/libwayland)
+
# Generate protocols bindings.
- macro(generate_protocol_bindings NAME PROT_DEF)
+ macro(generate_protocol_bindings PROT_DEF)
+ # File name without directory or extension (use for header name).
+ get_filename_component(_name ${PROT_DEF} NAME_WLE)
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.h
- COMMAND ${WAYLAND_SCANNER} client-header ${PROT_DEF} ${NAME}-client-protocol.h
+ OUTPUT ${INC_DST}/${_name}-client-protocol.h
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${INC_DST}
+ COMMAND ${WAYLAND_SCANNER} client-header ${PROT_DEF} ${INC_DST}/${_name}-client-protocol.h
)
add_custom_command(
- OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.c
- COMMAND ${WAYLAND_SCANNER} private-code ${PROT_DEF} ${NAME}-client-protocol.c
- DEPENDS ${NAME}-client-protocol.h
+ OUTPUT ${INC_DST}/${_name}-client-protocol.c
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${INC_DST}
+ COMMAND ${WAYLAND_SCANNER} private-code ${PROT_DEF} ${INC_DST}/${_name}-client-protocol.c
+ DEPENDS ${INC_DST}/${_name}-client-protocol.h
)
list(APPEND SRC
- ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.c
- ${CMAKE_CURRENT_BINARY_DIR}/${NAME}-client-protocol.h
+ ${INC_DST}/${_name}-client-protocol.c
+ ${INC_DST}/${_name}-client-protocol.h
)
+ unset(_name)
endmacro()
+
list(APPEND INC_SYS
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${INC_DST}
)
- # xdg-shell.
- generate_protocol_bindings(
- xdg-shell
- "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml"
- )
- # xdg-decoration.
+ if(NOT WITH_GHOST_WAYLAND_LIBDECOR)
+ # `xdg-shell`.
+ generate_protocol_bindings(
+ "${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml"
+ )
+ # `xdg-decoration`.
+ generate_protocol_bindings(
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
+ )
+ endif()
+
+ # `xdg-output`.
generate_protocol_bindings(
- xdg-decoration
- "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-output/xdg-output-unstable-v1.xml"
)
# Pointer-constraints.
generate_protocol_bindings(
- pointer-constraints
"${WAYLAND_PROTOCOLS_DIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
)
# Relative-pointer.
generate_protocol_bindings(
- relative-pointer
"${WAYLAND_PROTOCOLS_DIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
)
+ # Tablet.
+ generate_protocol_bindings(
+ "${WAYLAND_PROTOCOLS_DIR}/unstable/tablet/tablet-unstable-v2.xml"
+ )
add_definitions(-DWITH_GHOST_WAYLAND)
+
+ unset(INC_DST)
endif()
if(WITH_INPUT_NDOF)
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index ec641938f1f..4cbc0d65b11 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -20,7 +20,7 @@ extern "C" {
* \param event: The event received.
* \param userdata: The callback's user data, supplied to #GHOST_CreateSystem.
*/
-typedef int (*GHOST_EventCallbackProcPtr)(GHOST_EventHandle event, GHOST_TUserDataPtr userdata);
+typedef bool (*GHOST_EventCallbackProcPtr)(GHOST_EventHandle event, GHOST_TUserDataPtr userdata);
/**
* Creates the one and only system.
@@ -206,7 +206,7 @@ extern GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandl
*/
extern void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr userdata);
-extern int GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle);
+extern bool GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle);
/**
* Dispose a window.
@@ -223,7 +223,7 @@ extern GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
* \param windowhandle: Handle to the window to be checked.
* \return Indication of validity.
*/
-extern int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle);
+extern bool GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle);
/**
* Begins full screen mode.
@@ -235,7 +235,7 @@ extern int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle
*/
extern GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle,
GHOST_DisplaySetting *setting,
- const int stereoVisual);
+ const bool stereoVisual);
/**
* Ends full screen mode.
@@ -249,7 +249,7 @@ extern GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle);
* \param systemhandle: The handle to the system.
* \return The current status.
*/
-extern int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle);
+extern bool GHOST_GetFullScreen(GHOST_SystemHandle systemhandle);
/**
* Get the Window under the cursor.
@@ -364,12 +364,15 @@ extern GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle
int hotY,
bool canInvertColor);
+extern GHOST_TSuccess GHOST_GetCursorBitmap(GHOST_WindowHandle windowhandle,
+ GHOST_CursorBitmapRef *bitmap);
+
/**
* Returns the visibility state of the cursor.
* \param windowhandle: The handle to the window.
* \return The visibility state of the cursor.
*/
-extern int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle);
+extern bool GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle);
/**
* Shows or hides the cursor.
@@ -377,30 +380,37 @@ extern int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle);
* \param visible: The new visibility state of the cursor.
* \return Indication of success.
*/
-extern GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, int visible);
+extern GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, bool visible);
/**
- * Returns the current location of the cursor (location in screen coordinates)
+ * Returns the current location of the cursor (location in client relative coordinates)
* \param systemhandle: The handle to the system.
* \param x: The x-coordinate of the cursor.
* \param y: The y-coordinate of the cursor.
* \return Indication of success.
*/
-extern GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle,
- int32_t *x,
- int32_t *y);
-
+GHOST_TSuccess GHOST_GetCursorPosition(const GHOST_SystemHandle systemhandle,
+ const GHOST_WindowHandle windowhandle,
+ int32_t *x,
+ int32_t *y);
/**
- * Updates the location of the cursor (location in screen coordinates).
+ * Updates the location of the cursor (location in client relative coordinates).
* Not all operating systems allow the cursor to be moved (without the input device being moved).
* \param systemhandle: The handle to the system.
* \param x: The x-coordinate of the cursor.
* \param y: The y-coordinate of the cursor.
* \return Indication of success.
*/
-extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
- int32_t x,
- int32_t y);
+GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
+ GHOST_WindowHandle windowhandle,
+ int32_t x,
+ int32_t y);
+
+void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
+ GHOST_TGrabCursorMode *r_mode,
+ GHOST_TAxisFlag *r_axis_flag,
+ int r_bounds[4],
+ bool *r_use_software_cursor);
/**
* Grabs the cursor for a modal operation, to keep receiving
@@ -414,7 +424,7 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
*/
extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
GHOST_TGrabCursorMode mode,
- GHOST_TAxisFlag warp_axis,
+ GHOST_TAxisFlag wrap_axis,
int bounds[4],
const int mouse_ungrab_xy[2]);
@@ -430,8 +440,8 @@ extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
* \return Indication of success.
*/
extern GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
- GHOST_TModifierKeyMask mask,
- int *isDown);
+ GHOST_TModifierKey mask,
+ bool *r_is_down);
/**
* Returns the state of a mouse button (outside the message queue).
@@ -441,8 +451,8 @@ extern GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
* \return Indication of success.
*/
extern GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
- GHOST_TButtonMask mask,
- int *isDown);
+ GHOST_TButton mask,
+ bool *r_is_down);
#ifdef WITH_INPUT_NDOF
/***************************************************************************************
@@ -463,7 +473,7 @@ extern void GHOST_setNDOFDeadZone(float deadzone);
/**
* Tells if the ongoing drag'n'drop object can be accepted upon mouse drop
*/
-extern void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, bool canAccept);
+extern void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, bool can_accept);
/**
* Returns the event type.
@@ -529,7 +539,7 @@ extern void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle,
* \param windowhandle: The handle to the window.
* \return The validity of the window.
*/
-extern int GHOST_GetValid(GHOST_WindowHandle windowhandle);
+extern bool GHOST_GetValid(GHOST_WindowHandle windowhandle);
/**
* Returns the type of drawing context used in this window.
@@ -727,7 +737,7 @@ extern unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle
/**
* Get the OpenGL frame-buffer handle that serves as a default frame-buffer.
*/
-extern unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windwHandle);
+extern unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle);
/**
* Set which tablet API to use. Only affects Windows, other platforms have a single API.
@@ -889,17 +899,32 @@ extern void GHOST_putClipboard(const char *buffer, bool selection);
* \param action: console state
* \return current status (1 -visible, 0 - hidden)
*/
-extern int setConsoleWindowState(GHOST_TConsoleWindowState action);
+extern bool GHOST_setConsoleWindowState(GHOST_TConsoleWindowState action);
/**
* Use native pixel size (MacBook pro 'retina'), if supported.
*/
-extern int GHOST_UseNativePixels(void);
+extern bool GHOST_UseNativePixels(void);
+
+/**
+ * Warp the cursor, if supported.
+ */
+extern bool GHOST_SupportsCursorWarp(void);
+
+/**
+ * Support positioning windows (when false `wmWindow.x,y` are meaningless).
+ */
+extern bool GHOST_SupportsWindowPosition(void);
+
+/**
+ * Assign the callback which generates a back-trace (may be NULL).
+ */
+extern void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn);
/**
* Focus window after opening, or put them in the background.
*/
-extern void GHOST_UseWindowFocus(int use_focus);
+extern void GHOST_UseWindowFocus(bool use_focus);
/**
* If window was opened using native pixel size, it returns scaling factor.
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index bb91abbadec..91cf1c4c558 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -133,6 +133,9 @@ class GHOST_ISystem {
*/
static GHOST_ISystem *getSystem();
+ static GHOST_TBacktraceFn getBacktraceFn();
+ static void setBacktraceFn(GHOST_TBacktraceFn backtrace_fn);
+
protected:
/**
* Constructor.
@@ -305,6 +308,16 @@ class GHOST_ISystem {
virtual bool useNativePixel(void) = 0;
/**
+ * Return true when warping the cursor is supported.
+ */
+ virtual bool supportsCursorWarp() = 0;
+
+ /**
+ * Return true getting/setting the window position is supported.
+ */
+ virtual bool supportsWindowPosition() = 0;
+
+ /**
* Focus window after opening, or put them in the background.
*/
virtual void useWindowFocus(const bool use_focus) = 0;
@@ -352,6 +365,25 @@ class GHOST_ISystem {
***************************************************************************************/
/**
+ * Returns the current location of the cursor (location in window coordinates)
+ * \param x: The x-coordinate of the cursor.
+ * \param y: The y-coordinate of the cursor.
+ * \return Indication of success.
+ */
+ virtual GHOST_TSuccess getCursorPositionClientRelative(const GHOST_IWindow *window,
+ int32_t &x,
+ int32_t &y) const = 0;
+ /**
+ * Updates the location of the cursor (location in window coordinates).
+ * \param x: The x-coordinate of the cursor.
+ * \param y: The y-coordinate of the cursor.
+ * \return Indication of success.
+ */
+ virtual GHOST_TSuccess setCursorPositionClientRelative(GHOST_IWindow *window,
+ int32_t x,
+ int32_t y) = 0;
+
+ /**
* Returns the current location of the cursor (location in screen coordinates)
* \param x: The x-coordinate of the cursor.
* \param y: The y-coordinate of the cursor.
@@ -378,7 +410,7 @@ class GHOST_ISystem {
* \param isDown: The state of a modifier key (true == pressed).
* \return Indication of success.
*/
- virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const = 0;
+ virtual GHOST_TSuccess getModifierKeyState(GHOST_TModifierKey mask, bool &isDown) const = 0;
/**
* Returns the state of a mouse button (outside the message queue).
@@ -386,7 +418,7 @@ class GHOST_ISystem {
* \param isDown: Button state.
* \return Indication of success.
*/
- virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool &isDown) const = 0;
+ virtual GHOST_TSuccess getButtonState(GHOST_TButton mask, bool &isDown) const = 0;
/**
* Set which tablet API to use. Only affects Windows, other platforms have a single API.
@@ -477,6 +509,9 @@ class GHOST_ISystem {
/** The one and only system */
static GHOST_ISystem *m_system;
+ /** Function to call that sets the back-trace. */
+ static GHOST_TBacktraceFn m_backtrace_fn;
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_ISystem")
#endif
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 183e97a4b55..f712d9bd9f0 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -254,6 +254,15 @@ class GHOST_IWindow {
*/
virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0;
+ virtual GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) = 0;
+
+ virtual void getCursorGrabState(GHOST_TGrabCursorMode &mode,
+ GHOST_TAxisFlag &axis_flag,
+ GHOST_Rect &bounds,
+ bool &use_software_cursor) = 0;
+
+ virtual bool getCursorGrabUseSoftwareDisplay() = 0;
+
/**
* Test if the standard cursor shape is supported by current platform.
* \return Indication of success.
@@ -276,6 +285,8 @@ class GHOST_IWindow {
int hotY,
bool canInvertColor) = 0;
+ virtual GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) = 0;
+
/**
* Returns the visibility state of the cursor.
* \return The visibility state of the cursor.
diff --git a/intern/ghost/GHOST_Rect.h b/intern/ghost/GHOST_Rect.h
index 0a5561b7d68..15fa546fb07 100644
--- a/intern/ghost/GHOST_Rect.h
+++ b/intern/ghost/GHOST_Rect.h
@@ -101,6 +101,12 @@ class GHOST_Rect {
* \param y: The y-coordinate of the point.
*/
virtual inline void wrapPoint(int32_t &x, int32_t &y, int32_t ofs, GHOST_TAxisFlag axis);
+ /**
+ * Confine x & y within the rectangle (inclusive).
+ * \param x: The x-coordinate of the point.
+ * \param y: The y-coordinate of the point.
+ */
+ virtual inline void clampPoint(int32_t &x, int32_t &y);
/**
* Returns whether the point is inside this rectangle.
@@ -190,26 +196,34 @@ inline bool GHOST_Rect::isValid() const
inline void GHOST_Rect::unionRect(const GHOST_Rect &r)
{
- if (r.m_l < m_l)
+ if (r.m_l < m_l) {
m_l = r.m_l;
- if (r.m_r > m_r)
+ }
+ if (r.m_r > m_r) {
m_r = r.m_r;
- if (r.m_t < m_t)
+ }
+ if (r.m_t < m_t) {
m_t = r.m_t;
- if (r.m_b > m_b)
+ }
+ if (r.m_b > m_b) {
m_b = r.m_b;
+ }
}
inline void GHOST_Rect::unionPoint(int32_t x, int32_t y)
{
- if (x < m_l)
+ if (x < m_l) {
m_l = x;
- if (x > m_r)
+ }
+ if (x > m_r) {
m_r = x;
- if (y < m_t)
+ }
+ if (y < m_t) {
m_t = y;
- if (y > m_b)
+ }
+ if (y > m_b) {
m_b = y;
+ }
}
inline void GHOST_Rect::wrapPoint(int32_t &x, int32_t &y, int32_t ofs, GHOST_TAxisFlag axis)
@@ -223,16 +237,37 @@ inline void GHOST_Rect::wrapPoint(int32_t &x, int32_t &y, int32_t ofs, GHOST_TAx
}
if (axis & GHOST_kAxisX) {
- while (x - ofs < m_l)
+ while (x - ofs < m_l) {
x += w - (ofs * 2);
- while (x + ofs > m_r)
+ }
+ while (x + ofs > m_r) {
x -= w - (ofs * 2);
+ }
}
- if (axis & GHOST_kGrabAxisY) {
- while (y - ofs < m_t)
+ if (axis & GHOST_kAxisY) {
+ while (y - ofs < m_t) {
y += h - (ofs * 2);
- while (y + ofs > m_b)
+ }
+ while (y + ofs > m_b) {
y -= h - (ofs * 2);
+ }
+ }
+}
+
+inline void GHOST_Rect::clampPoint(int32_t &x, int32_t &y)
+{
+ if (x < m_l) {
+ x = m_l;
+ }
+ else if (x > m_r) {
+ x = m_r;
+ }
+
+ if (y < m_t) {
+ y = m_t;
+ }
+ else if (y > m_b) {
+ y = m_b;
}
}
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 85913fbd10c..495fb739978 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -42,6 +42,18 @@ GHOST_DECLARE_HANDLE(GHOST_EventConsumerHandle);
GHOST_DECLARE_HANDLE(GHOST_ContextHandle);
GHOST_DECLARE_HANDLE(GHOST_XrContextHandle);
+typedef void (*GHOST_TBacktraceFn)(void *file_handle);
+
+/**
+ * A reference to cursor bitmap data.
+ */
+typedef struct {
+ /** `RGBA` bytes. */
+ const uint8_t *data;
+ int data_size[2];
+ int hot_spot[2];
+} GHOST_CursorBitmapRef;
+
typedef struct {
int flags;
} GHOST_GLSettings;
@@ -111,8 +123,8 @@ typedef enum {
GHOST_kModifierKeyLeftControl,
GHOST_kModifierKeyRightControl,
GHOST_kModifierKeyOS,
- GHOST_kModifierKeyNumMasks
-} GHOST_TModifierKeyMask;
+ GHOST_kModifierKeyNum
+} GHOST_TModifierKey;
typedef enum {
GHOST_kWindowStateNormal = 0,
@@ -151,8 +163,8 @@ typedef enum {
/* Trackballs and programmable buttons. */
GHOST_kButtonMaskButton6,
GHOST_kButtonMaskButton7,
- GHOST_kButtonNumMasks
-} GHOST_TButtonMask;
+ GHOST_kButtonNum
+} GHOST_TButton;
typedef enum {
GHOST_kEventUnknown = 0,
@@ -403,11 +415,13 @@ typedef enum {
GHOST_kGrabHide,
} GHOST_TGrabCursorMode;
+#define GHOST_GRAB_NEEDS_SOFTWARE_CURSOR_FOR_WARP(grab) ((grab) == GHOST_kGrabWrap)
+
typedef enum {
/** Axis that cursor grab will wrap. */
- GHOST_kGrabAxisNone = 0,
+ GHOST_kAxisNone = 0,
GHOST_kAxisX = (1 << 0),
- GHOST_kGrabAxisY = (1 << 1),
+ GHOST_kAxisY = (1 << 1),
} GHOST_TAxisFlag;
typedef void *GHOST_TEventDataPtr;
@@ -423,7 +437,7 @@ typedef struct {
typedef struct {
/** The mask of the mouse button. */
- GHOST_TButtonMask button;
+ GHOST_TButton button;
/** Associated tablet data. */
GHOST_TabletData tablet;
} GHOST_TEventButtonData;
@@ -521,7 +535,7 @@ typedef struct {
} GHOST_TEventNDOFMotionData;
typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
-/* Good for mouse or other buttons too, hmmm? */
+/* Good for mouse or other buttons too? */
typedef struct {
GHOST_TButtonAction action;
@@ -533,21 +547,15 @@ typedef struct {
/** The key code. */
GHOST_TKey key;
- /* ascii / utf8: both should always be set when possible,
- * - ascii may be '\0' however if the user presses a non ascii key
- * - unicode may not be set if the system has no unicode support
- *
- * These values are intended to be used as follows.
- * For text input use unicode when available, fallback to ascii.
- * For areas where unicode is not needed, number input for example, always
- * use ascii, unicode is ignored - campbell.
- */
- /** The ascii code for the key event ('\0' if none). */
- char ascii;
/** The unicode character. if the length is 6, not NULL terminated if all 6 are set. */
char utf8_buf[6];
- /** Generated by auto-repeat. */
+ /**
+ * Enabled when the key is held (auto-repeat).
+ * In this case press events are sent without a corresponding release/up event.
+ *
+ * All back-ends must set this variable for correct behavior regarding repeatable keys.
+ */
char is_repeat;
} GHOST_TEventKeyData;
@@ -596,7 +604,7 @@ typedef int GHOST_TEmbedderWindowID;
/**
* A timer task callback routine.
* \param task: The timer task object.
- * \param time: The current time.
+ * \param time: Time since this timer started (in milliseconds).
*/
#ifdef __cplusplus
class GHOST_ITimerTask;
diff --git a/intern/ghost/intern/GHOST_Buttons.cpp b/intern/ghost/intern/GHOST_Buttons.cpp
index 3367d256325..6382729c579 100644
--- a/intern/ghost/intern/GHOST_Buttons.cpp
+++ b/intern/ghost/intern/GHOST_Buttons.cpp
@@ -12,7 +12,7 @@ GHOST_Buttons::GHOST_Buttons()
clear();
}
-bool GHOST_Buttons::get(GHOST_TButtonMask mask) const
+bool GHOST_Buttons::get(GHOST_TButton mask) const
{
switch (mask) {
case GHOST_kButtonMaskLeft:
@@ -34,7 +34,7 @@ bool GHOST_Buttons::get(GHOST_TButtonMask mask) const
}
}
-void GHOST_Buttons::set(GHOST_TButtonMask mask, bool down)
+void GHOST_Buttons::set(GHOST_TButton mask, bool down)
{
switch (mask) {
case GHOST_kButtonMaskLeft:
diff --git a/intern/ghost/intern/GHOST_Buttons.h b/intern/ghost/intern/GHOST_Buttons.h
index 72cb17a3322..e42376b1c76 100644
--- a/intern/ghost/intern/GHOST_Buttons.h
+++ b/intern/ghost/intern/GHOST_Buttons.h
@@ -27,14 +27,14 @@ struct GHOST_Buttons {
* \param mask: Key button to return.
* \return The state of the button (pressed == true).
*/
- bool get(GHOST_TButtonMask mask) const;
+ bool get(GHOST_TButton mask) const;
/**
* Updates the state of a single button.
* \param mask: Button state to update.
* \param down: The new state of the button.
*/
- void set(GHOST_TButtonMask mask, bool down);
+ void set(GHOST_TButton mask, bool down);
/**
* Sets the state of all buttons to up.
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 93e94893162..65e7de707ec 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -7,8 +7,8 @@
* C Api for GHOST
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "GHOST_C-api.h"
#include "GHOST_IEvent.h"
@@ -177,11 +177,11 @@ void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr
window->setUserData(userdata);
}
-int GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle)
+bool GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return (int)window->isDialog();
+ return window->isDialog();
}
GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
@@ -193,26 +193,28 @@ GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle,
return system->disposeWindow(window);
}
-int GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle)
+bool GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return (int)system->validWindow(window);
+ return system->validWindow(window);
}
GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle,
GHOST_DisplaySetting *setting,
- const int stereoVisual)
+ const bool stereoVisual)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
- GHOST_IWindow *window = NULL;
+ GHOST_IWindow *window = nullptr;
bool bstereoVisual;
- if (stereoVisual)
+ if (stereoVisual) {
bstereoVisual = true;
- else
+ }
+ else {
bstereoVisual = false;
+ }
system->beginFullScreen(*setting, &window, bstereoVisual);
@@ -226,11 +228,11 @@ GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle)
return system->endFullScreen();
}
-int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle)
+bool GHOST_GetFullScreen(GHOST_SystemHandle systemhandle)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
- return (int)system->getFullScreen();
+ return system->getFullScreen();
}
GHOST_WindowHandle GHOST_GetWindowUnderCursor(GHOST_SystemHandle systemhandle,
@@ -324,33 +326,71 @@ GHOST_TSuccess GHOST_SetCustomCursorShape(GHOST_WindowHandle windowhandle,
return window->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
}
-int GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle)
+GHOST_TSuccess GHOST_GetCursorBitmap(GHOST_WindowHandle windowhandle,
+ GHOST_CursorBitmapRef *bitmap)
+{
+ GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+
+ return window->getCursorBitmap(bitmap);
+}
+
+bool GHOST_GetCursorVisibility(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return (int)window->getCursorVisibility();
+ return window->getCursorVisibility();
}
-GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, int visible)
+GHOST_TSuccess GHOST_SetCursorVisibility(GHOST_WindowHandle windowhandle, bool visible)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return window->setCursorVisibility(visible ? true : false);
+ return window->setCursorVisibility(visible);
}
-GHOST_TSuccess GHOST_GetCursorPosition(GHOST_SystemHandle systemhandle, int32_t *x, int32_t *y)
+/* Unused, can expose again if needed although WAYLAND
+ * can only properly use client relative coordinates, so leave disabled if possible. */
+#if 0
+GHOST_TSuccess GHOST_GetCursorPositionScreenCoords(GHOST_SystemHandle systemhandle,
+ int32_t *x,
+ int32_t *y)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
return system->getCursorPosition(*x, *y);
}
-GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, int32_t x, int32_t y)
+GHOST_TSuccess GHOST_SetCursorPositionScreenCoords(GHOST_SystemHandle systemhandle,
+ int32_t x,
+ int32_t y)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
return system->setCursorPosition(x, y);
}
+#endif
+
+GHOST_TSuccess GHOST_GetCursorPosition(const GHOST_SystemHandle systemhandle,
+ const GHOST_WindowHandle windowhandle,
+ int32_t *x,
+ int32_t *y)
+{
+ const GHOST_ISystem *system = (const GHOST_ISystem *)systemhandle;
+ const GHOST_IWindow *window = (const GHOST_IWindow *)windowhandle;
+
+ return system->getCursorPositionClientRelative(window, *x, *y);
+}
+
+GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
+ GHOST_WindowHandle windowhandle,
+ int32_t x,
+ int32_t y)
+{
+ GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
+ GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+
+ return system->setCursorPositionClientRelative(window, x, y);
+}
GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
GHOST_TGrabCursorMode mode,
@@ -371,33 +411,50 @@ GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
}
return window->setCursorGrab(
- mode, wrap_axis, bounds ? &bounds_rect : NULL, mouse_ungrab_xy ? mouse_xy : NULL);
+ mode, wrap_axis, bounds ? &bounds_rect : nullptr, mouse_ungrab_xy ? mouse_xy : nullptr);
+}
+
+void GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
+ GHOST_TGrabCursorMode *r_mode,
+ GHOST_TAxisFlag *r_axis_flag,
+ int r_bounds[4],
+ bool *r_use_software_cursor)
+{
+ GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+ GHOST_Rect bounds_rect;
+ bool use_software_cursor;
+ window->getCursorGrabState(*r_mode, *r_axis_flag, bounds_rect, use_software_cursor);
+ r_bounds[0] = bounds_rect.m_l;
+ r_bounds[1] = bounds_rect.m_t;
+ r_bounds[2] = bounds_rect.m_r;
+ r_bounds[3] = bounds_rect.m_b;
+ *r_use_software_cursor = use_software_cursor;
}
GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
- GHOST_TModifierKeyMask mask,
- int *isDown)
+ GHOST_TModifierKey mask,
+ bool *r_is_down)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
GHOST_TSuccess result;
- bool isdown = false;
+ bool is_down = false;
- result = system->getModifierKeyState(mask, isdown);
- *isDown = (int)isdown;
+ result = system->getModifierKeyState(mask, is_down);
+ *r_is_down = is_down;
return result;
}
GHOST_TSuccess GHOST_GetButtonState(GHOST_SystemHandle systemhandle,
- GHOST_TButtonMask mask,
- int *isDown)
+ GHOST_TButton mask,
+ bool *r_is_down)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
GHOST_TSuccess result;
- bool isdown = false;
+ bool is_down = false;
- result = system->getButtonState(mask, isdown);
- *isDown = (int)isdown;
+ result = system->getButtonState(mask, is_down);
+ *r_is_down = is_down;
return result;
}
@@ -410,11 +467,11 @@ void GHOST_setNDOFDeadZone(float deadzone)
}
#endif
-void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, bool canAccept)
+void GHOST_setAcceptDragOperation(GHOST_WindowHandle windowhandle, bool can_accept)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- window->setAcceptDragOperation(canAccept);
+ window->setAcceptDragOperation(can_accept);
}
GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle)
@@ -473,11 +530,11 @@ void GHOST_SetTimerTaskUserData(GHOST_TimerTaskHandle timertaskhandle, GHOST_TUs
timertask->setUserData(userdata);
}
-int GHOST_GetValid(GHOST_WindowHandle windowhandle)
+bool GHOST_GetValid(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- return (int)window->getValid();
+ return window->getValid();
}
GHOST_TDrawingContextType GHOST_GetDrawingContextType(GHOST_WindowHandle windowhandle)
@@ -509,8 +566,8 @@ char *GHOST_GetTitle(GHOST_WindowHandle windowhandle)
char *ctitle = (char *)malloc(title.size() + 1);
- if (ctitle == NULL) {
- return NULL;
+ if (ctitle == nullptr) {
+ return nullptr;
}
strcpy(ctitle, title.c_str());
@@ -521,7 +578,7 @@ char *GHOST_GetTitle(GHOST_WindowHandle windowhandle)
GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- GHOST_Rect *rectangle = NULL;
+ GHOST_Rect *rectangle = nullptr;
rectangle = new GHOST_Rect();
window->getWindowBounds(*rectangle);
@@ -532,7 +589,7 @@ GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- GHOST_Rect *rectangle = NULL;
+ GHOST_Rect *rectangle = nullptr;
rectangle = new GHOST_Rect();
window->getClientBounds(*rectangle);
@@ -646,10 +703,8 @@ GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
if (context) {
return context->activateDrawingContext();
}
- else {
- GHOST_PRINTF("%s: Context not valid\n", __func__);
- return GHOST_kFailure;
- }
+ GHOST_PRINTF("%s: Context not valid\n", __func__);
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
@@ -717,9 +772,9 @@ GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle)
{
GHOST_TSuccess result = GHOST_kFailure;
- if (((GHOST_Rect *)rectanglehandle)->isEmpty())
+ if (((GHOST_Rect *)rectanglehandle)->isEmpty()) {
result = GHOST_kSuccess;
-
+ }
return result;
}
@@ -727,9 +782,9 @@ GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle)
{
GHOST_TSuccess result = GHOST_kFailure;
- if (((GHOST_Rect *)rectanglehandle)->isValid())
+ if (((GHOST_Rect *)rectanglehandle)->isValid()) {
result = GHOST_kSuccess;
-
+ }
return result;
}
@@ -753,9 +808,9 @@ GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle, in
{
GHOST_TSuccess result = GHOST_kFailure;
- if (((GHOST_Rect *)rectanglehandle)->isInside(x, y))
+ if (((GHOST_Rect *)rectanglehandle)->isInside(x, y)) {
result = GHOST_kSuccess;
-
+ }
return result;
}
@@ -785,9 +840,9 @@ GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle,
{
GHOST_TSuccess result = GHOST_kFailure;
- if (((GHOST_Rect *)rectanglehandle)->clip(*(GHOST_Rect *)anotherrectanglehandle))
+ if (((GHOST_Rect *)rectanglehandle)->clip(*(GHOST_Rect *)anotherrectanglehandle)) {
result = GHOST_kSuccess;
-
+ }
return result;
}
@@ -803,19 +858,37 @@ void GHOST_putClipboard(const char *buffer, bool selection)
system->putClipboard(buffer, selection);
}
-int setConsoleWindowState(GHOST_TConsoleWindowState action)
+bool GHOST_setConsoleWindowState(GHOST_TConsoleWindowState action)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
- return system->setConsoleWindowState(action);
+ /* FIXME: use `bool` instead of int for this value. */
+ return (bool)system->setConsoleWindowState(action);
}
-int GHOST_UseNativePixels(void)
+bool GHOST_UseNativePixels(void)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return system->useNativePixel();
}
-void GHOST_UseWindowFocus(int use_focus)
+bool GHOST_SupportsCursorWarp(void)
+{
+ GHOST_ISystem *system = GHOST_ISystem::getSystem();
+ return system->supportsCursorWarp();
+}
+
+bool GHOST_SupportsWindowPosition(void)
+{
+ GHOST_ISystem *system = GHOST_ISystem::getSystem();
+ return system->supportsWindowPosition();
+}
+
+void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn)
+{
+ GHOST_ISystem::setBacktraceFn(backtrace_fn);
+}
+
+void GHOST_UseWindowFocus(bool use_focus)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
return system->useWindowFocus(use_focus);
@@ -824,8 +897,9 @@ void GHOST_UseWindowFocus(int use_focus)
float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- if (window)
+ if (window) {
return window->getNativePixelSize();
+ }
return 1.0f;
}
diff --git a/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp
index 72aeebdc876..9f14d56cd9a 100644
--- a/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp
+++ b/intern/ghost/intern/GHOST_CallbackEventConsumer.cpp
@@ -22,5 +22,5 @@ GHOST_CallbackEventConsumer::GHOST_CallbackEventConsumer(GHOST_EventCallbackProc
bool GHOST_CallbackEventConsumer::processEvent(GHOST_IEvent *event)
{
- return m_eventCallback((GHOST_EventHandle)event, m_userData) != 0;
+ return m_eventCallback((GHOST_EventHandle)event, m_userData);
}
diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h
index d9c2cdce258..e707f1c3475 100644
--- a/intern/ghost/intern/GHOST_Context.h
+++ b/intern/ghost/intern/GHOST_Context.h
@@ -93,6 +93,22 @@ class GHOST_Context : public GHOST_IContext {
}
/**
+ * Get user data.
+ */
+ void *getUserData()
+ {
+ return m_user_data;
+ }
+
+ /**
+ * Set user data (intended for the caller to use as needed).
+ */
+ void setUserData(void *user_data)
+ {
+ m_user_data = user_data;
+ }
+
+ /**
* Stereo visual created. Only necessary for 'real' stereo support,
* ie quad buffered stereo. This is not always possible, depends on
* the graphics h/w
@@ -124,6 +140,9 @@ class GHOST_Context : public GHOST_IContext {
bool m_stereoVisual;
+ /** Caller specified, not for internal use. */
+ void *m_user_data = nullptr;
+
static void initClearGL();
#ifdef WITH_CXX_GUARDEDALLOC
diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp
index a2b58106f0d..8c44dfe0158 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextEGL.cpp
@@ -40,7 +40,7 @@ static const char *get_egl_error_enum_string(EGLint error)
CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_WINDOW)
CASE_CODE_RETURN_STR(EGL_CONTEXT_LOST)
default:
- return NULL;
+ return nullptr;
}
}
@@ -106,11 +106,14 @@ static const char *get_egl_error_message_string(EGLint error)
"and objects to continue rendering.");
default:
- return NULL;
+ return nullptr;
}
}
-static bool egl_chk(bool result, const char *file = NULL, int line = 0, const char *text = NULL)
+static bool egl_chk(bool result,
+ const char *file = nullptr,
+ int line = 0,
+ const char *text = nullptr)
{
if (!result) {
const EGLint error = eglGetError();
@@ -158,7 +161,7 @@ static inline bool bindAPI(EGLenum api)
}
#ifdef WITH_GL_ANGLE
-HMODULE GHOST_ContextEGL::s_d3dcompiler = NULL;
+HMODULE GHOST_ContextEGL::s_d3dcompiler = nullptr;
#endif
EGLContext GHOST_ContextEGL::s_gl_sharedContext = EGL_NO_CONTEXT;
@@ -170,7 +173,9 @@ EGLint GHOST_ContextEGL::s_gles_sharedCount = 0;
EGLContext GHOST_ContextEGL::s_vg_sharedContext = EGL_NO_CONTEXT;
EGLint GHOST_ContextEGL::s_vg_sharedCount = 0;
-#pragma warning(disable : 4715)
+#ifdef _MSC_VER
+# pragma warning(disable : 4715)
+#endif
template<typename T> T &choose_api(EGLenum api, T &a, T &b, T &c)
{
@@ -223,23 +228,24 @@ GHOST_ContextEGL::~GHOST_ContextEGL()
bindAPI(m_api);
if (m_context != EGL_NO_CONTEXT) {
- if (m_context == ::eglGetCurrentContext())
+ if (m_context == ::eglGetCurrentContext()) {
EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
-
+ }
if (m_context != m_sharedContext || m_sharedCount == 1) {
assert(m_sharedCount > 0);
m_sharedCount--;
- if (m_sharedCount == 0)
+ if (m_sharedCount == 0) {
m_sharedContext = EGL_NO_CONTEXT;
-
+ }
EGL_CHK(::eglDestroyContext(m_display, m_context));
}
}
- if (m_surface != EGL_NO_SURFACE)
+ if (m_surface != EGL_NO_SURFACE) {
EGL_CHK(::eglDestroySurface(m_display, m_surface));
+ }
}
}
@@ -256,13 +262,9 @@ GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval)
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
- }
- else {
return GHOST_kFailure;
}
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut)
@@ -293,13 +295,10 @@ GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext()
{
if (m_display) {
bindAPI(m_api);
-
return EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)) ? GHOST_kSuccess :
GHOST_kFailure;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext()
@@ -311,9 +310,7 @@ GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext()
GHOST_kSuccess :
GHOST_kFailure;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
bool GHOST_ContextEGL::initContextEGLEW()
@@ -322,7 +319,7 @@ bool GHOST_ContextEGL::initContextEGLEW()
* it requires a display argument. glewInit() does the same, but we only want
* to initialize EGLEW here. */
eglGetDisplay = (PFNEGLGETDISPLAYPROC)eglGetProcAddress("eglGetDisplay");
- if (eglGetDisplay == NULL) {
+ if (eglGetDisplay == nullptr) {
return false;
}
@@ -353,9 +350,9 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
std::vector<EGLint> attrib_list;
EGLint num_config = 0;
- if (m_stereoVisual)
+ if (m_stereoVisual) {
fprintf(stderr, "Warning! Stereo OpenGL ES contexts are not supported.\n");
-
+ }
m_stereoVisual = false; /* It doesn't matter what the Window wants. */
if (!initContextEGLEW()) {
@@ -364,12 +361,12 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
#ifdef WITH_GL_ANGLE
/* `d3dcompiler_XX.dll` needs to be loaded before ANGLE will work. */
- if (s_d3dcompiler == NULL) {
+ if (s_d3dcompiler == nullptr) {
s_d3dcompiler = LoadLibrary(D3DCOMPILER);
- WIN32_CHK(s_d3dcompiler != NULL);
+ WIN32_CHK(s_d3dcompiler != nullptr);
- if (s_d3dcompiler == NULL) {
+ if (s_d3dcompiler == nullptr) {
fprintf(stderr, "LoadLibrary(\"" D3DCOMPILER "\") failed!\n");
return GHOST_kFailure;
}
@@ -383,18 +380,19 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
EGLint egl_major, egl_minor;
- if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor)))
+ if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) {
goto error;
-
+ }
#ifdef WITH_GHOST_DEBUG
fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor);
#endif
- if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)))
+ if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))) {
goto error;
-
- if (!bindAPI(m_api))
+ }
+ if (!bindAPI(m_api)) {
goto error;
+ }
/* Build attribute list. */
@@ -462,15 +460,17 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
attrib_list.push_back(EGL_NONE);
- if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &m_config, 1, &num_config)))
+ if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &m_config, 1, &num_config))) {
goto error;
+ }
/* A common error is to assume that ChooseConfig worked because it returned EGL_TRUE. */
- if (num_config != 1) /* `num_config` should be exactly 1. */
+ if (num_config != 1) { /* `num_config` should be exactly 1. */
goto error;
+ }
if (m_nativeWindow != 0) {
- m_surface = ::eglCreateWindowSurface(m_display, m_config, m_nativeWindow, NULL);
+ m_surface = ::eglCreateWindowSurface(m_display, m_config, m_nativeWindow, nullptr);
}
else {
static const EGLint pb_attrib_list[] = {
@@ -483,9 +483,9 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
m_surface = ::eglCreatePbufferSurface(m_display, m_config, pb_attrib_list);
}
- if (!EGL_CHK(m_surface != EGL_NO_SURFACE))
+ if (!EGL_CHK(m_surface != EGL_NO_SURFACE)) {
goto error;
-
+ }
attrib_list.clear();
if (EGLEW_VERSION_1_5 || EGLEW_KHR_create_context) {
@@ -524,9 +524,10 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
}
}
else {
- if (m_contextProfileMask != 0)
+ if (m_contextProfileMask != 0) {
fprintf(
stderr, "Warning! Cannot select profile for %s contexts.", api_string(m_api).c_str());
+ }
}
if (m_api == EGL_OPENGL_API || EGLEW_VERSION_1_5) {
@@ -583,16 +584,19 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
m_context = ::eglCreateContext(m_display, m_config, m_sharedContext, &(attrib_list[0]));
- if (!EGL_CHK(m_context != EGL_NO_CONTEXT))
+ if (!EGL_CHK(m_context != EGL_NO_CONTEXT)) {
goto error;
+ }
- if (m_sharedContext == EGL_NO_CONTEXT)
+ if (m_sharedContext == EGL_NO_CONTEXT) {
m_sharedContext = m_context;
+ }
m_sharedCount++;
- if (!EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)))
+ if (!EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context))) {
goto error;
+ }
initContextGLEW();
@@ -602,16 +606,16 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
return GHOST_kSuccess;
error:
- if (prev_display != EGL_NO_DISPLAY)
+ if (prev_display != EGL_NO_DISPLAY) {
EGL_CHK(eglMakeCurrent(prev_display, prev_draw, prev_read, prev_context));
-
+ }
return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextEGL::releaseNativeHandles()
{
m_nativeWindow = 0;
- m_nativeDisplay = NULL;
+ m_nativeDisplay = nullptr;
return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index b7d613645dc..b4a076e4598 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -47,23 +47,24 @@ GHOST_ContextGLX::GHOST_ContextGLX(bool stereoVisual,
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
m_context(None)
{
- assert(m_display != NULL);
+ assert(m_display != nullptr);
}
GHOST_ContextGLX::~GHOST_ContextGLX()
{
- if (m_display != NULL) {
+ if (m_display != nullptr) {
if (m_context != None) {
- if (m_window != 0 && m_context == ::glXGetCurrentContext())
- ::glXMakeCurrent(m_display, None, NULL);
-
+ if (m_window != 0 && m_context == ::glXGetCurrentContext()) {
+ ::glXMakeCurrent(m_display, None, nullptr);
+ }
if (m_context != s_sharedContext || s_sharedCount == 1) {
assert(s_sharedCount > 0);
s_sharedCount--;
- if (s_sharedCount == 0)
- s_sharedContext = NULL;
+ if (s_sharedCount == 0) {
+ s_sharedContext = nullptr;
+ }
::glXDestroyContext(m_display, m_context);
}
@@ -80,22 +81,18 @@ GHOST_TSuccess GHOST_ContextGLX::swapBuffers()
GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext()
{
- if (m_display) {
- return ::glXMakeCurrent(m_display, m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
- }
- else {
+ if (m_display == nullptr) {
return GHOST_kFailure;
}
+ return ::glXMakeCurrent(m_display, m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextGLX::releaseDrawingContext()
{
- if (m_display) {
- return ::glXMakeCurrent(m_display, None, NULL) ? GHOST_kSuccess : GHOST_kFailure;
- }
- else {
+ if (m_display == nullptr) {
return GHOST_kFailure;
}
+ return ::glXMakeCurrent(m_display, None, nullptr) ? GHOST_kSuccess : GHOST_kFailure;
}
void GHOST_ContextGLX::initContextGLXEW()
@@ -108,20 +105,20 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
/* -------------------------------------------------------------------- */
- /* Begin Inline Glew */
+ /* Begin Inline GLEW. */
#ifdef USE_GLXEW_INIT_WORKAROUND
const GLubyte *extStart = (GLubyte *)"";
const GLubyte *extEnd;
- if (glXQueryExtension(m_display, NULL, NULL)) {
+ if (glXQueryExtension(m_display, nullptr, nullptr)) {
extStart = (const GLubyte *)glXGetClientString(m_display, GLX_EXTENSIONS);
- if ((extStart == NULL) ||
+ if ((extStart == nullptr) ||
(glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXChooseFBConfig")) == NULL ||
+ (const GLubyte *)"glXChooseFBConfig")) == nullptr ||
(glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXCreateContextAttribsARB")) == NULL ||
+ (const GLubyte *)"glXCreateContextAttribsARB")) == nullptr ||
(glXCreatePbuffer = (PFNGLXCREATEPBUFFERPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXCreatePbuffer")) == NULL) {
+ (const GLubyte *)"glXCreatePbuffer")) == nullptr) {
extStart = (GLubyte *)"";
}
}
@@ -145,11 +142,11 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
"GLX_EXT_create_context_es2_profile", extStart, extEnd);
# endif /* WITH_GLEW_ES */
- /* End Inline Glew */
+ /* End Inline GLEW. */
/* -------------------------------------------------------------------- */
#else
- /* important to initialize only glxew (_not_ glew),
- * since this breaks w/ Mesa's `swrast`, see: T46431 */
+ /* Important to initialize only glxew (_not_ GLEW),
+ * since this breaks w/ Mesa's `swrast`, see: T46431. */
glxewInit();
#endif /* USE_GLXEW_INIT_WORKAROUND */
@@ -161,11 +158,12 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
int profileBitES = m_contextProfileMask & GLX_CONTEXT_ES_PROFILE_BIT_EXT;
#endif
- if (!GLXEW_ARB_create_context_profile && profileBitCore)
+ if (!GLXEW_ARB_create_context_profile && profileBitCore) {
fprintf(stderr, "Warning! OpenGL core profile not available.\n");
-
- if (!GLXEW_ARB_create_context_profile && profileBitCompat)
+ }
+ if (!GLXEW_ARB_create_context_profile && profileBitCompat) {
fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n");
+ }
#ifdef WITH_GLEW_ES
if (!GLXEW_EXT_create_context_es_profile && profileBitES && m_contextMajorVersion == 1)
@@ -177,20 +175,21 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
int profileMask = 0;
- if (GLXEW_ARB_create_context_profile && profileBitCore)
+ if (GLXEW_ARB_create_context_profile && profileBitCore) {
profileMask |= profileBitCore;
-
- if (GLXEW_ARB_create_context_profile && profileBitCompat)
+ }
+ if (GLXEW_ARB_create_context_profile && profileBitCompat) {
profileMask |= profileBitCompat;
+ }
#ifdef WITH_GLEW_ES
if (GLXEW_EXT_create_context_es_profile && profileBitES)
profileMask |= profileBitES;
#endif
- if (profileMask != m_contextProfileMask)
+ if (profileMask != m_contextProfileMask) {
fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits.");
-
+ }
/* max 10 attributes plus terminator */
int attribs[11];
int i = 0;
@@ -238,7 +237,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
}
}
else {
- GLXFBConfig *framebuffer_config = NULL;
+ GLXFBConfig *framebuffer_config = nullptr;
{
int glx_attribs[64];
int fbcount = 0;
@@ -269,12 +268,12 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
GHOST_TSuccess success;
- if (m_context != NULL) {
+ if (m_context != nullptr) {
const unsigned char *version;
- if (!s_sharedContext)
+ if (!s_sharedContext) {
s_sharedContext = m_context;
-
+ }
s_sharedCount++;
glXMakeCurrent(m_display, m_window, m_context);
@@ -319,14 +318,11 @@ GHOST_TSuccess GHOST_ContextGLX::releaseNativeHandles()
GHOST_TSuccess GHOST_ContextGLX::setSwapInterval(int interval)
{
- if (GLXEW_EXT_swap_control) {
+ if (!GLXEW_EXT_swap_control) {
::glXSwapIntervalEXT(m_display, m_window, interval);
-
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut)
@@ -340,9 +336,7 @@ GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut)
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
/**
@@ -401,35 +395,41 @@ int GHOST_X11_GL_GetAttributes(
return i;
}
-/* excuse inlining part of glew */
+/* Excuse inlining part of GLEW. */
#ifdef USE_GLXEW_INIT_WORKAROUND
static GLuint _glewStrLen(const GLubyte *s)
{
GLuint i = 0;
- if (s == NULL)
+ if (s == nullptr) {
return 0;
- while (s[i] != '\0')
+ }
+ while (s[i] != '\0') {
i++;
+ }
return i;
}
static GLuint _glewStrCLen(const GLubyte *s, GLubyte c)
{
GLuint i = 0;
- if (s == NULL)
+ if (s == nullptr) {
return 0;
- while (s[i] != '\0' && s[i] != c)
+ }
+ while (s[i] != '\0' && s[i] != c) {
i++;
+ }
return (s[i] == '\0' || s[i] == c) ? i : 0;
}
static GLboolean _glewStrSame(const GLubyte *a, const GLubyte *b, GLuint n)
{
GLuint i = 0;
- if (a == NULL || b == NULL)
- return (a == NULL && b == NULL && n == 0) ? GL_TRUE : GL_FALSE;
- while (i < n && a[i] != '\0' && b[i] != '\0' && a[i] == b[i])
+ if (a == nullptr || b == nullptr) {
+ return (a == nullptr && b == nullptr && n == 0) ? GL_TRUE : GL_FALSE;
+ }
+ while (i < n && a[i] != '\0' && b[i] != '\0' && a[i] == b[i]) {
i++;
+ }
return i == n ? GL_TRUE : GL_FALSE;
}
@@ -440,8 +440,9 @@ static GLboolean _glewSearchExtension(const char *name, const GLubyte *start, co
p = start;
while (p < end) {
GLuint n = _glewStrCLen(p, ' ');
- if (len == n && _glewStrSame((const GLubyte *)name, p, n))
+ if (len == n && _glewStrSame((const GLubyte *)name, p, n)) {
return GL_TRUE;
+ }
p += n + 1;
}
return GL_FALSE;
diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp
index 050f8e43aab..5b02fe1c1e6 100644
--- a/intern/ghost/intern/GHOST_ContextSDL.cpp
+++ b/intern/ghost/intern/GHOST_ContextSDL.cpp
@@ -15,7 +15,7 @@
#include <cstdio>
#include <cstring>
-SDL_GLContext GHOST_ContextSDL::s_sharedContext = NULL;
+SDL_GLContext GHOST_ContextSDL::s_sharedContext = nullptr;
int GHOST_ContextSDL::s_sharedCount = 0;
GHOST_ContextSDL::GHOST_ContextSDL(bool stereoVisual,
@@ -27,36 +27,39 @@ GHOST_ContextSDL::GHOST_ContextSDL(bool stereoVisual,
int contextResetNotificationStrategy)
: GHOST_Context(stereoVisual),
m_window(window),
- m_hidden_window(NULL),
+ m_hidden_window(nullptr),
m_contextProfileMask(contextProfileMask),
m_contextMajorVersion(contextMajorVersion),
m_contextMinorVersion(contextMinorVersion),
m_contextFlags(contextFlags),
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
- m_context(NULL)
+ m_context(nullptr)
{
- // assert(m_window != NULL);
+ // assert(m_window != nullptr);
}
GHOST_ContextSDL::~GHOST_ContextSDL()
{
- if (m_context != NULL) {
- if (m_window != NULL && m_context == SDL_GL_GetCurrentContext())
- SDL_GL_MakeCurrent(m_window, NULL);
-
- if (m_context != s_sharedContext || s_sharedCount == 1) {
- assert(s_sharedCount > 0);
+ if (m_context == nullptr) {
+ return;
+ }
- s_sharedCount--;
+ if (m_window != nullptr && m_context == SDL_GL_GetCurrentContext()) {
+ SDL_GL_MakeCurrent(m_window, nullptr);
+ }
+ if (m_context != s_sharedContext || s_sharedCount == 1) {
+ assert(s_sharedCount > 0);
- if (s_sharedCount == 0)
- s_sharedContext = NULL;
+ s_sharedCount--;
- SDL_GL_DeleteContext(m_context);
+ if (s_sharedCount == 0) {
+ s_sharedContext = nullptr;
}
+ SDL_GL_DeleteContext(m_context);
+ }
- if (m_hidden_window != NULL)
- SDL_DestroyWindow(m_hidden_window);
+ if (m_hidden_window != nullptr) {
+ SDL_DestroyWindow(m_hidden_window);
}
}
@@ -69,23 +72,19 @@ GHOST_TSuccess GHOST_ContextSDL::swapBuffers()
GHOST_TSuccess GHOST_ContextSDL::activateDrawingContext()
{
- if (m_context) {
- return SDL_GL_MakeCurrent(m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
- }
- else {
+ if (m_context == nullptr) {
return GHOST_kFailure;
}
+ return SDL_GL_MakeCurrent(m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextSDL::releaseDrawingContext()
{
- if (m_context) {
- /* Untested, may not work */
- return SDL_GL_MakeCurrent(NULL, NULL) ? GHOST_kSuccess : GHOST_kFailure;
- }
- else {
+ if (m_context == nullptr) {
return GHOST_kFailure;
}
+ /* Untested, may not work. */
+ return SDL_GL_MakeCurrent(nullptr, nullptr) ? GHOST_kSuccess : GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
@@ -115,7 +114,7 @@ GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
SDL_GL_SetAttribute(SDL_GL_STEREO, 1);
}
- if (m_window == NULL) {
+ if (m_window == nullptr) {
m_hidden_window = SDL_CreateWindow("Offscreen Context Windows",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
@@ -131,10 +130,10 @@ GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
GHOST_TSuccess success;
- if (m_context != NULL) {
- if (!s_sharedContext)
+ if (m_context != nullptr) {
+ if (!s_sharedContext) {
s_sharedContext = m_context;
-
+ }
s_sharedCount++;
success = (SDL_GL_MakeCurrent(m_window, m_context) < 0) ? GHOST_kFailure : GHOST_kSuccess;
@@ -155,19 +154,17 @@ GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
GHOST_TSuccess GHOST_ContextSDL::releaseNativeHandles()
{
- m_window = NULL;
+ m_window = nullptr;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextSDL::setSwapInterval(int interval)
{
- if (SDL_GL_SetSwapInterval(interval) != -1) {
- return GHOST_kSuccess;
- }
- else {
+ if (SDL_GL_SetSwapInterval(interval) == -1) {
return GHOST_kFailure;
}
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextSDL::getSwapInterval(int &intervalOut)
diff --git a/intern/ghost/intern/GHOST_Debug.h b/intern/ghost/intern/GHOST_Debug.h
index e6bdf974d59..ec1a0b34be6 100644
--- a/intern/ghost/intern/GHOST_Debug.h
+++ b/intern/ghost/intern/GHOST_Debug.h
@@ -15,12 +15,12 @@
# endif
#endif
-#ifdef WITH_GHOST_DEBUG
+#if defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))
# include <iostream>
# include <stdio.h> //for printf()
#endif // WITH_GHOST_DEBUG
-#ifdef WITH_GHOST_DEBUG
+#if defined(WITH_GHOST_DEBUG)
# define GHOST_PRINT(x) \
{ \
std::cout << x; \
@@ -31,10 +31,10 @@
printf(x, __VA_ARGS__); \
} \
(void)0
-#else // WITH_GHOST_DEBUG
+#else
# define GHOST_PRINT(x)
# define GHOST_PRINTF(x, ...)
-#endif // WITH_GHOST_DEBUG
+#endif /* `!defined(WITH_GHOST_DEBUG)` */
#ifdef WITH_ASSERT_ABORT
# include <stdio.h> //for fprintf()
@@ -49,7 +49,8 @@
} \
} \
(void)0
-#elif defined(WITH_GHOST_DEBUG)
+/* Assert in non-release builds too. */
+#elif defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))
# define GHOST_ASSERT(x, info) \
{ \
if (!(x)) { \
@@ -59,6 +60,6 @@
} \
} \
(void)0
-#else // WITH_GHOST_DEBUG
+#else /* `defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))` */
# define GHOST_ASSERT(x, info) ((void)0)
-#endif // WITH_GHOST_DEBUG
+#endif /* `defined(WITH_GHOST_DEBUG) || (!defined(NDEBUG))` */
diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp
index 18de4ab6c8f..fa15d05232d 100644
--- a/intern/ghost/intern/GHOST_DisplayManager.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManager.cpp
@@ -12,15 +12,15 @@
#include "GHOST_DisplayManager.h"
#include "GHOST_Debug.h"
-GHOST_DisplayManager::GHOST_DisplayManager(void) : m_settingsInitialized(false)
+GHOST_DisplayManager::GHOST_DisplayManager() : m_settingsInitialized(false)
{
}
-GHOST_DisplayManager::~GHOST_DisplayManager(void)
+GHOST_DisplayManager::~GHOST_DisplayManager()
{
}
-GHOST_TSuccess GHOST_DisplayManager::initialize(void)
+GHOST_TSuccess GHOST_DisplayManager::initialize()
{
GHOST_TSuccess success;
if (!m_settingsInitialized) {
@@ -139,7 +139,7 @@ GHOST_TSuccess GHOST_DisplayManager::findMatch(uint8_t display,
return success;
}
-GHOST_TSuccess GHOST_DisplayManager::initializeSettings(void)
+GHOST_TSuccess GHOST_DisplayManager::initializeSettings()
{
uint8_t numDisplays;
GHOST_TSuccess success = getNumDisplays(numDisplays);
diff --git a/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp b/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
index 740fcc2ef1d..a2fe6a41fb4 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
@@ -109,7 +109,7 @@ GHOST_TSuccess GHOST_DisplayManagerSDL::setCurrentDisplaySetting(
SDL_GetDisplayMode(display, i, &mode);
- if (setting.xPixels > mode.w || setting.yPixels > mode.h) {
+ if ((int)setting.xPixels > mode.w || (int)setting.yPixels > mode.h) {
continue;
}
@@ -122,9 +122,9 @@ GHOST_TSuccess GHOST_DisplayManagerSDL::setCurrentDisplaySetting(
}
}
- if (best_fit == -1)
+ if (best_fit == -1) {
return GHOST_kFailure;
-
+ }
SDL_GetDisplayMode(display, best_fit, &mode);
}
@@ -142,12 +142,10 @@ GHOST_TSuccess GHOST_DisplayManagerSDL::setCurrentDisplaySetting(
return GHOST_kSuccess;
}
- else {
- /* this is a problem for the BGE player :S, perhaps SDL2 will resolve at some point.
- * we really need SDL_SetDisplayModeForDisplay() to become an API func! - campbell */
- printf("no windows available, can't fullscreen\n");
+ /* This is a problem for the BGE player :S, perhaps SDL2 will resolve at some point.
+ * we really need SDL_SetDisplayModeForDisplay() to become an API func! - campbell. */
+ printf("no windows available, can't fullscreen\n");
- /* do not fail, we will try again later when the window is created - wander */
- return GHOST_kSuccess;
- }
+ /* do not fail, we will try again later when the window is created - wander */
+ return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
index 843f22df1c3..ab4a77cd660 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
@@ -39,8 +39,9 @@ GHOST_TSuccess GHOST_DisplayManagerX11::getNumDisplaySettings(uint8_t display,
GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
- if (dpy == NULL)
+ if (dpy == nullptr) {
return GHOST_kFailure;
+ }
majorVersion = minorVersion = 0;
if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
@@ -77,8 +78,9 @@ GHOST_TSuccess GHOST_DisplayManagerX11::getDisplaySetting(uint8_t display,
{
Display *dpy = m_system->getXDisplay();
- if (dpy == NULL)
+ if (dpy == nullptr) {
return GHOST_kFailure;
+ }
(void)display;
@@ -143,8 +145,9 @@ GHOST_TSuccess GHOST_DisplayManagerX11::setCurrentDisplaySetting(
Display *dpy = m_system->getXDisplay();
int scrnum, num_vidmodes;
- if (dpy == NULL)
+ if (dpy == nullptr) {
return GHOST_kFailure;
+ }
scrnum = DefaultScreen(dpy);
diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cpp b/intern/ghost/intern/GHOST_DropTargetX11.cpp
index 0212a71d2ff..252a8bfd095 100644
--- a/intern/ghost/intern/GHOST_DropTargetX11.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetX11.cpp
@@ -7,16 +7,17 @@
#include "GHOST_DropTargetX11.h"
#include "GHOST_Debug.h"
+#include "GHOST_utildefines.h"
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstring>
bool GHOST_DropTargetX11::m_xdndInitialized = false;
DndClass GHOST_DropTargetX11::m_dndClass;
-Atom *GHOST_DropTargetX11::m_dndTypes = NULL;
-Atom *GHOST_DropTargetX11::m_dndActions = NULL;
+Atom *GHOST_DropTargetX11::m_dndTypes = nullptr;
+Atom *GHOST_DropTargetX11::m_dndActions = nullptr;
const char *GHOST_DropTargetX11::m_dndMimeTypes[] = {
"url/url", "text/uri-list", "text/plain", "application/octet-stream"};
int GHOST_DropTargetX11::m_refCounter = 0;
@@ -31,10 +32,10 @@ int GHOST_DropTargetX11::m_refCounter = 0;
#define dndTypePlainText m_dndTypes[dndTypePlainTextID]
#define dndTypeOctetStream m_dndTypes[dndTypeOctetStreamID]
-void GHOST_DropTargetX11::Initialize(void)
+void GHOST_DropTargetX11::Initialize()
{
Display *display = m_system->getXDisplay();
- int dndTypesCount = sizeof(m_dndMimeTypes) / sizeof(char *);
+ int dndTypesCount = ARRAY_SIZE(m_dndMimeTypes);
int counter;
xdnd_init(&m_dndClass, display);
@@ -60,7 +61,7 @@ void GHOST_DropTargetX11::Initialize(void)
m_dndActions[counter++] = 0;
}
-void GHOST_DropTargetX11::Uninitialize(void)
+void GHOST_DropTargetX11::Uninitialize()
{
xdnd_shut(&m_dndClass);
@@ -98,12 +99,12 @@ GHOST_DropTargetX11::~GHOST_DropTargetX11()
/* Based on: https://stackoverflow.com/a/2766963/432509 */
-typedef enum DecodeState_e {
+using DecodeState_e = enum DecodeState_e {
/** Searching for an ampersand to convert. */
STATE_SEARCH = 0,
/** Convert the two proceeding characters from hex. */
STATE_CONVERTING
-} DecodeState_e;
+};
void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char *encodedIn)
{
@@ -122,7 +123,7 @@ void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char
case STATE_SEARCH:
if (encodedIn[i] != '%') {
strncat(decodedOut, &encodedIn[i], 1);
- assert(strlen(decodedOut) < bufferSize);
+ assert((int)strlen(decodedOut) < bufferSize);
break;
}
@@ -145,18 +146,19 @@ void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char
/* Ensure both characters are hexadecimal */
for (j = 0; j < 2; ++j) {
- if (!isxdigit(tempNumBuf[j]))
+ if (!isxdigit(tempNumBuf[j])) {
bothDigits = false;
+ }
}
- if (!bothDigits)
+ if (!bothDigits) {
break;
-
+ }
/* Convert two hexadecimal characters into one character */
sscanf(tempNumBuf, "%x", &asciiCharacter);
/* Ensure we aren't going to overflow */
- assert(strlen(decodedOut) < bufferSize);
+ assert((int)strlen(decodedOut) < bufferSize);
/* Concatenate this character onto the output */
strncat(decodedOut, (char *)&asciiCharacter, 1);
@@ -180,12 +182,12 @@ char *GHOST_DropTargetX11::FileUrlDecode(char *fileUrl)
return decodedPath;
}
- return NULL;
+ return nullptr;
}
void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dropBufferSize)
{
- GHOST_TStringArray *strArray = NULL;
+ GHOST_TStringArray *strArray = nullptr;
int totPaths = 0, curLength = 0;
/* Count total number of file paths in buffer. */
@@ -196,8 +198,9 @@ void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dr
curLength = 0;
}
}
- else
+ else {
curLength++;
+ }
}
strArray = (GHOST_TStringArray *)malloc(sizeof(GHOST_TStringArray));
@@ -224,8 +227,9 @@ void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dr
curLength = 0;
}
}
- else
+ else {
curLength++;
+ }
}
return strArray;
@@ -235,11 +239,11 @@ void *GHOST_DropTargetX11::getGhostData(Atom dropType,
unsigned char *dropBuffer,
int dropBufferSize)
{
- void *data = NULL;
+ void *data = nullptr;
unsigned char *tmpBuffer = (unsigned char *)malloc(dropBufferSize + 1);
bool needsFree = true;
- /* ensure NULL-terminator */
+ /* Ensure nil-terminator. */
memcpy(tmpBuffer, dropBuffer, dropBufferSize);
tmpBuffer[dropBufferSize] = 0;
@@ -265,8 +269,9 @@ void *GHOST_DropTargetX11::getGhostData(Atom dropType,
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
}
- if (needsFree)
+ if (needsFree) {
free(tmpBuffer);
+ }
return data;
}
@@ -288,9 +293,10 @@ bool GHOST_DropTargetX11::GHOST_HandleClientMessage(XEvent *event)
&dropY)) {
void *data = getGhostData(dropType, dropBuffer, dropBufferSize);
- if (data)
+ if (data) {
m_system->pushDragDropEvent(
GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, dropX, dropY, data);
+ }
free(dropBuffer);
diff --git a/intern/ghost/intern/GHOST_EventButton.h b/intern/ghost/intern/GHOST_EventButton.h
index d68e401ffc4..f42805e2c6b 100644
--- a/intern/ghost/intern/GHOST_EventButton.h
+++ b/intern/ghost/intern/GHOST_EventButton.h
@@ -27,7 +27,7 @@ class GHOST_EventButton : public GHOST_Event {
GHOST_EventButton(uint64_t time,
GHOST_TEventType type,
GHOST_IWindow *window,
- GHOST_TButtonMask button,
+ GHOST_TButton button,
const GHOST_TabletData &tablet)
: GHOST_Event(time, type, window), m_buttonEventData({button, tablet})
{
diff --git a/intern/ghost/intern/GHOST_EventKey.h b/intern/ghost/intern/GHOST_EventKey.h
index 1c3156c27d2..f85a674be9f 100644
--- a/intern/ghost/intern/GHOST_EventKey.h
+++ b/intern/ghost/intern/GHOST_EventKey.h
@@ -22,13 +22,13 @@ class GHOST_EventKey : public GHOST_Event {
* \param msec: The time this event was generated.
* \param type: The type of key event.
* \param key: The key code of the key.
+ * \param is_repeat: Enabled for key repeat events (only for press events).
*/
GHOST_EventKey(
uint64_t msec, GHOST_TEventType type, GHOST_IWindow *window, GHOST_TKey key, bool is_repeat)
: GHOST_Event(msec, type, window)
{
m_keyEventData.key = key;
- m_keyEventData.ascii = '\0';
m_keyEventData.utf8_buf[0] = '\0';
m_keyEventData.is_repeat = is_repeat;
m_data = &m_keyEventData;
@@ -39,23 +39,24 @@ class GHOST_EventKey : public GHOST_Event {
* \param msec: The time this event was generated.
* \param type: The type of key event.
* \param key: The key code of the key.
- * \param ascii: The ascii code for the key event.
+ * \param is_repeat: Enabled for key repeat events (only for press events).
+ * \param utf8_buf: The text associated with this key event (only for press events).
*/
GHOST_EventKey(uint64_t msec,
GHOST_TEventType type,
GHOST_IWindow *window,
GHOST_TKey key,
- char ascii,
- const char utf8_buf[6],
- bool is_repeat)
+ bool is_repeat,
+ const char utf8_buf[6])
: GHOST_Event(msec, type, window)
{
m_keyEventData.key = key;
- m_keyEventData.ascii = ascii;
- if (utf8_buf)
+ if (utf8_buf) {
memcpy(m_keyEventData.utf8_buf, utf8_buf, sizeof(m_keyEventData.utf8_buf));
- else
+ }
+ else {
m_keyEventData.utf8_buf[0] = '\0';
+ }
m_keyEventData.is_repeat = is_repeat;
m_data = &m_keyEventData;
}
diff --git a/intern/ghost/intern/GHOST_EventPrinter.cpp b/intern/ghost/intern/GHOST_EventPrinter.cpp
index 758938e879e..2620bcc075d 100644
--- a/intern/ghost/intern/GHOST_EventPrinter.cpp
+++ b/intern/ghost/intern/GHOST_EventPrinter.cpp
@@ -12,7 +12,7 @@
#include "GHOST_EventKey.h"
#include <iostream>
-#include <stdio.h>
+#include <cstdio>
bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
{
@@ -20,9 +20,9 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
GHOST_ASSERT(event, "event==0");
- if (event->getType() == GHOST_kEventWindowUpdate)
+ if (event->getType() == GHOST_kEventWindowUpdate) {
return false;
-
+ }
std::cout << "GHOST_EventPrinter::processEvent, time: " << (int32_t)event->getTime()
<< ", type: ";
switch (event->getType()) {
@@ -106,8 +106,9 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
std::cout << " type : GHOST_kDragnDropTypeFilenames,";
std::cout << "\n Received " << strArray->count << " filename"
<< (strArray->count > 1 ? "s:" : ":");
- for (i = 0; i < strArray->count; i++)
+ for (i = 0; i < strArray->count; i++) {
std::cout << "\n File[" << i << "] : " << strArray->strings[i];
+ }
} break;
default:
break;
@@ -117,10 +118,12 @@ bool GHOST_EventPrinter::processEvent(GHOST_IEvent *event)
case GHOST_kEventOpenMainFile: {
GHOST_TEventDataPtr eventData = ((GHOST_IEvent *)event)->getData();
- if (eventData)
+ if (eventData) {
std::cout << "GHOST_kEventOpenMainFile for path : " << (char *)eventData;
- else
+ }
+ else {
std::cout << "GHOST_kEventOpenMainFile with no path specified!!";
+ }
} break;
case GHOST_kEventQuitRequest:
@@ -167,7 +170,7 @@ void GHOST_EventPrinter::getKeyString(GHOST_TKey key, char str[32]) const
sprintf(str, "F%d", key - GHOST_kKeyF1 + 1);
}
else {
- const char *tstr = NULL;
+ const char *tstr = nullptr;
switch (key) {
case GHOST_kKeyBackSpace:
tstr = "BackSpace";
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index 7906002b2b5..4f6a9531077 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -29,18 +29,31 @@
# include "GHOST_SystemCocoa.h"
#endif
-GHOST_ISystem *GHOST_ISystem::m_system = NULL;
+GHOST_ISystem *GHOST_ISystem::m_system = nullptr;
+
+GHOST_TBacktraceFn GHOST_ISystem::m_backtrace_fn = nullptr;
GHOST_TSuccess GHOST_ISystem::createSystem()
{
GHOST_TSuccess success;
if (!m_system) {
+
+#if defined(WITH_HEADLESS)
+ /* Pass. */
+#elif defined(WITH_GHOST_WAYLAND)
+# if defined(WITH_GHOST_WAYLAND_DYNLOAD)
+ const bool has_wayland_libraries = ghost_wl_dynload_libraries();
+# else
+ const bool has_wayland_libraries = true;
+# endif
+#endif
+
#if defined(WITH_HEADLESS)
m_system = new GHOST_SystemNULL();
#elif defined(WITH_GHOST_X11) && defined(WITH_GHOST_WAYLAND)
/* Special case, try Wayland, fall back to X11. */
try {
- m_system = new GHOST_SystemWayland();
+ m_system = has_wayland_libraries ? new GHOST_SystemWayland() : nullptr;
}
catch (const std::runtime_error &) {
/* fallback to X11. */
@@ -53,7 +66,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
#elif defined(WITH_GHOST_X11)
m_system = new GHOST_SystemX11();
#elif defined(WITH_GHOST_WAYLAND)
- m_system = new GHOST_SystemWayland();
+ m_system = has_wayland_libraries ? new GHOST_SystemWayland() : nullptr;
#elif defined(WITH_GHOST_SDL)
m_system = new GHOST_SystemSDL();
#elif defined(WIN32)
@@ -61,7 +74,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
#elif defined(__APPLE__)
m_system = new GHOST_SystemCocoa();
#endif
- success = m_system != NULL ? GHOST_kSuccess : GHOST_kFailure;
+ success = m_system != nullptr ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
@@ -77,7 +90,7 @@ GHOST_TSuccess GHOST_ISystem::disposeSystem()
GHOST_TSuccess success = GHOST_kSuccess;
if (m_system) {
delete m_system;
- m_system = NULL;
+ m_system = nullptr;
}
else {
success = GHOST_kFailure;
@@ -89,3 +102,13 @@ GHOST_ISystem *GHOST_ISystem::getSystem()
{
return m_system;
}
+
+GHOST_TBacktraceFn GHOST_ISystem::getBacktraceFn()
+{
+ return GHOST_ISystem::m_backtrace_fn;
+}
+
+void GHOST_ISystem::setBacktraceFn(GHOST_TBacktraceFn backtrace_fn)
+{
+ GHOST_ISystem::m_backtrace_fn = backtrace_fn;
+}
diff --git a/intern/ghost/intern/GHOST_ISystemPaths.cpp b/intern/ghost/intern/GHOST_ISystemPaths.cpp
index dacb5421da0..599a9fec681 100644
--- a/intern/ghost/intern/GHOST_ISystemPaths.cpp
+++ b/intern/ghost/intern/GHOST_ISystemPaths.cpp
@@ -9,8 +9,6 @@
* Copyright (C) 2001 NaN Technologies B.V.
*/
-#include <stdio.h> /* just for NULL */
-
#include "GHOST_ISystemPaths.h"
#ifdef WIN32
@@ -23,7 +21,7 @@
# endif
#endif
-GHOST_ISystemPaths *GHOST_ISystemPaths::m_systemPaths = NULL;
+GHOST_ISystemPaths *GHOST_ISystemPaths::m_systemPaths = nullptr;
GHOST_TSuccess GHOST_ISystemPaths::create()
{
@@ -38,7 +36,7 @@ GHOST_TSuccess GHOST_ISystemPaths::create()
m_systemPaths = new GHOST_SystemPathsUnix();
# endif
#endif
- success = m_systemPaths != NULL ? GHOST_kSuccess : GHOST_kFailure;
+ success = m_systemPaths != nullptr ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
@@ -51,7 +49,7 @@ GHOST_TSuccess GHOST_ISystemPaths::dispose()
GHOST_TSuccess success = GHOST_kSuccess;
if (m_systemPaths) {
delete m_systemPaths;
- m_systemPaths = NULL;
+ m_systemPaths = nullptr;
}
else {
success = GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_ModifierKeys.cpp b/intern/ghost/intern/GHOST_ModifierKeys.cpp
index e6e433ba332..d31dc8f0770 100644
--- a/intern/ghost/intern/GHOST_ModifierKeys.cpp
+++ b/intern/ghost/intern/GHOST_ModifierKeys.cpp
@@ -20,7 +20,7 @@ GHOST_ModifierKeys::~GHOST_ModifierKeys()
{
}
-GHOST_TKey GHOST_ModifierKeys::getModifierKeyCode(GHOST_TModifierKeyMask mask)
+GHOST_TKey GHOST_ModifierKeys::getModifierKeyCode(GHOST_TModifierKey mask)
{
GHOST_TKey key;
switch (mask) {
@@ -53,7 +53,7 @@ GHOST_TKey GHOST_ModifierKeys::getModifierKeyCode(GHOST_TModifierKeyMask mask)
return key;
}
-bool GHOST_ModifierKeys::get(GHOST_TModifierKeyMask mask) const
+bool GHOST_ModifierKeys::get(GHOST_TModifierKey mask) const
{
switch (mask) {
case GHOST_kModifierKeyLeftShift:
@@ -75,7 +75,7 @@ bool GHOST_ModifierKeys::get(GHOST_TModifierKeyMask mask) const
}
}
-void GHOST_ModifierKeys::set(GHOST_TModifierKeyMask mask, bool down)
+void GHOST_ModifierKeys::set(GHOST_TModifierKey mask, bool down)
{
switch (mask) {
case GHOST_kModifierKeyLeftShift:
diff --git a/intern/ghost/intern/GHOST_ModifierKeys.h b/intern/ghost/intern/GHOST_ModifierKeys.h
index ca76ba6c704..ce1bf3df2ae 100644
--- a/intern/ghost/intern/GHOST_ModifierKeys.h
+++ b/intern/ghost/intern/GHOST_ModifierKeys.h
@@ -27,21 +27,21 @@ struct GHOST_ModifierKeys {
* \param mask: The mask of the modifier key.
* \return The modifier key's key code.
*/
- static GHOST_TKey getModifierKeyCode(GHOST_TModifierKeyMask mask);
+ static GHOST_TKey getModifierKeyCode(GHOST_TModifierKey mask);
/**
* Returns the state of a single modifier key.
* \param mask: Key state to return.
* \return The state of the key (pressed == true).
*/
- bool get(GHOST_TModifierKeyMask mask) const;
+ bool get(GHOST_TModifierKey mask) const;
/**
* Updates the state of a single modifier key.
* \param mask: Key state to update.
* \param down: The new state of the key.
*/
- void set(GHOST_TModifierKeyMask mask, bool down);
+ void set(GHOST_TModifierKey mask, bool down);
/**
* Sets the state of all modifier keys to up.
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index 7f6b5f53316..d58fb90f63e 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -5,11 +5,12 @@
#include "GHOST_EventKey.h"
#include "GHOST_EventNDOF.h"
#include "GHOST_WindowManager.h"
+#include "GHOST_utildefines.h"
-#include <limits.h>
-#include <math.h>
-#include <stdio.h> /* For error/info reporting. */
-#include <string.h> /* For memory functions. */
+#include <climits>
+#include <cmath>
+#include <cstdio> /* For error/info reporting. */
+#include <cstring> /* For memory functions. */
#ifdef DEBUG_NDOF_MOTION
/* Printable version of each GHOST_TProgress value. */
@@ -128,7 +129,7 @@ static const NDOF_ButtonT Generic_HID_map[] = {
NDOF_BUTTON_C,
};
-static const int genericButtonCount = sizeof(Generic_HID_map) / sizeof(NDOF_ButtonT);
+static const int genericButtonCount = ARRAY_SIZE(Generic_HID_map);
GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System &sys)
: m_system(sys),
@@ -255,8 +256,9 @@ bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id);
}
- if (m_buttonMask == 0)
+ if (m_buttonMask == 0) {
m_buttonMask = (int)~(UINT_MAX << m_buttonCount);
+ }
#ifdef DEBUG_NDOF_BUTTONS
printf("ndof: %d buttons -> hex:%X\n", m_buttonCount, m_buttonMask);
diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
index 7e53ce45f70..7770f5f39ce 100644
--- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp
@@ -32,10 +32,11 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys)
char line[MAX_LINE_LENGTH] = {0};
while (fgets(line, MAX_LINE_LENGTH, command_output)) {
unsigned short vendor_id = 0, product_id = 0;
- if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2)
+ if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2) {
if (setDevice(vendor_id, product_id)) {
break; /* stop looking once the first 3D mouse is found */
}
+ }
}
pclose(command_output);
}
@@ -44,8 +45,9 @@ GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys)
GHOST_NDOFManagerUnix::~GHOST_NDOFManagerUnix()
{
- if (m_available)
+ if (m_available) {
spnav_close();
+ }
}
bool GHOST_NDOFManagerUnix::available()
diff --git a/intern/ghost/intern/GHOST_Path-api.cpp b/intern/ghost/intern/GHOST_Path-api.cpp
index c57af8a1a21..1b1c72d8a4b 100644
--- a/intern/ghost/intern/GHOST_Path-api.cpp
+++ b/intern/ghost/intern/GHOST_Path-api.cpp
@@ -25,25 +25,28 @@ GHOST_TSuccess GHOST_DisposeSystemPaths(void)
const char *GHOST_getSystemDir(int version, const char *versionstr)
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
- return systemPaths ? systemPaths->getSystemDir(version, versionstr) : NULL;
+ return systemPaths ? systemPaths->getSystemDir(version, versionstr) : nullptr;
}
const char *GHOST_getUserDir(int version, const char *versionstr)
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
- return systemPaths ? systemPaths->getUserDir(version, versionstr) : NULL; /* shouldn't be NULL */
+ /* Shouldn't be `nullptr`. */
+ return systemPaths ? systemPaths->getUserDir(version, versionstr) : nullptr;
}
const char *GHOST_getUserSpecialDir(GHOST_TUserSpecialDirTypes type)
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
- return systemPaths ? systemPaths->getUserSpecialDir(type) : NULL; /* shouldn't be NULL */
+ /* Shouldn't be `nullptr`. */
+ return systemPaths ? systemPaths->getUserSpecialDir(type) : nullptr;
}
const char *GHOST_getBinaryDir()
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
- return systemPaths ? systemPaths->getBinaryDir() : NULL; /* shouldn't be NULL */
+ /* Shouldn't be `nullptr`. */
+ return systemPaths ? systemPaths->getBinaryDir() : nullptr;
}
void GHOST_addToSystemRecentFiles(const char *filename)
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 0d0d41972fd..cf04287af9f 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -8,7 +8,7 @@
#include "GHOST_System.h"
#include <chrono>
-#include <stdio.h> /* just for printf */
+#include <cstdio> /* just for printf */
#include "GHOST_DisplayManager.h"
#include "GHOST_EventManager.h"
@@ -23,10 +23,10 @@
GHOST_System::GHOST_System()
: m_nativePixel(false),
m_windowFocus(true),
- m_displayManager(NULL),
- m_timerManager(NULL),
- m_windowManager(NULL),
- m_eventManager(NULL),
+ m_displayManager(nullptr),
+ m_timerManager(nullptr),
+ m_windowManager(nullptr),
+ m_eventManager(nullptr),
#ifdef WITH_INPUT_NDOF
m_ndofManager(0),
#endif
@@ -61,7 +61,7 @@ GHOST_ITimerTask *GHOST_System::installTimer(uint64_t delay,
}
else {
delete timer;
- timer = NULL;
+ timer = nullptr;
}
}
return timer;
@@ -158,7 +158,7 @@ GHOST_TSuccess GHOST_System::updateFullScreen(const GHOST_DisplaySetting &settin
return success;
}
-GHOST_TSuccess GHOST_System::endFullScreen(void)
+GHOST_TSuccess GHOST_System::endFullScreen()
{
GHOST_TSuccess success = GHOST_kFailure;
GHOST_ASSERT(m_windowManager, "GHOST_System::endFullScreen(): invalid window manager");
@@ -177,7 +177,7 @@ GHOST_TSuccess GHOST_System::endFullScreen(void)
return success;
}
-bool GHOST_System::getFullScreen(void)
+bool GHOST_System::getFullScreen()
{
bool fullScreen;
if (m_windowManager) {
@@ -205,7 +205,7 @@ GHOST_IWindow *GHOST_System::getWindowUnderCursor(int32_t x, int32_t y)
}
}
- return NULL;
+ return nullptr;
}
void GHOST_System::dispatchEvents()
@@ -260,7 +260,30 @@ GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent *event)
return success;
}
-GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const
+GHOST_TSuccess GHOST_System::getCursorPositionClientRelative(const GHOST_IWindow *window,
+ int32_t &x,
+ int32_t &y) const
+{
+ /* Sub-classes that can implement this directly should do so. */
+ int32_t screen_x, screen_y;
+ GHOST_TSuccess success = getCursorPosition(screen_x, screen_y);
+ if (success == GHOST_kSuccess) {
+ window->screenToClient(screen_x, screen_y, x, y);
+ }
+ return success;
+}
+
+GHOST_TSuccess GHOST_System::setCursorPositionClientRelative(GHOST_IWindow *window,
+ int32_t x,
+ int32_t y)
+{
+ /* Sub-classes that can implement this directly should do so. */
+ int32_t screen_x, screen_y;
+ window->clientToScreen(x, y, screen_x, screen_y);
+ return setCursorPosition(screen_x, screen_y);
+}
+
+GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKey mask, bool &isDown) const
{
GHOST_ModifierKeys keys;
/* Get the state of all modifier keys. */
@@ -272,7 +295,7 @@ GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bo
return success;
}
-GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool &isDown) const
+GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButton mask, bool &isDown) const
{
GHOST_Buttons buttons;
/* Get the state of all mouse buttons. */
@@ -289,7 +312,7 @@ void GHOST_System::setTabletAPI(GHOST_TTabletAPI api)
m_tabletAPI = api;
}
-GHOST_TTabletAPI GHOST_System::getTabletAPI(void)
+GHOST_TTabletAPI GHOST_System::getTabletAPI()
{
return m_tabletAPI;
}
@@ -319,9 +342,7 @@ GHOST_TSuccess GHOST_System::init()
if (m_timerManager && m_windowManager && m_eventManager) {
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_System::exit()
@@ -331,20 +352,20 @@ GHOST_TSuccess GHOST_System::exit()
}
delete m_displayManager;
- m_displayManager = NULL;
+ m_displayManager = nullptr;
delete m_windowManager;
- m_windowManager = NULL;
+ m_windowManager = nullptr;
delete m_timerManager;
- m_timerManager = NULL;
+ m_timerManager = nullptr;
delete m_eventManager;
- m_eventManager = NULL;
+ m_eventManager = nullptr;
#ifdef WITH_INPUT_NDOF
delete m_ndofManager;
- m_ndofManager = NULL;
+ m_ndofManager = nullptr;
#endif
return GHOST_kSuccess;
@@ -357,10 +378,12 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
{
GHOST_GLSettings glSettings = {0};
- if (stereoVisual)
+ if (stereoVisual) {
glSettings.flags |= GHOST_glStereoVisual;
- if (alphaBackground)
+ }
+ if (alphaBackground) {
glSettings.flags |= GHOST_glAlphaBackground;
+ }
/* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may
* be zoomed in and the desktop may be bigger than the viewport. */
@@ -376,13 +399,13 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
GHOST_kDrawingContextTypeOpenGL,
glSettings,
true /* exclusive */);
- return (*window == NULL) ? GHOST_kFailure : GHOST_kSuccess;
+ return (*window == nullptr) ? GHOST_kFailure : GHOST_kSuccess;
}
-bool GHOST_System::useNativePixel(void)
+bool GHOST_System::useNativePixel()
{
m_nativePixel = true;
- return 1;
+ return true;
}
void GHOST_System::useWindowFocus(const bool use_focus)
@@ -390,6 +413,16 @@ void GHOST_System::useWindowFocus(const bool use_focus)
m_windowFocus = use_focus;
}
+bool GHOST_System::supportsCursorWarp()
+{
+ return true;
+}
+
+bool GHOST_System::supportsWindowPosition()
+{
+ return true;
+}
+
void GHOST_System::initDebug(GHOST_Debug debug)
{
m_is_debug_enabled = debug.flags & GHOST_kDebugDefault;
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 4a3cded1fbd..d5558be3444 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -151,10 +151,14 @@ class GHOST_System : public GHOST_ISystem {
bool useNativePixel(void);
bool m_nativePixel;
+ bool supportsCursorWarp(void);
+ bool supportsWindowPosition(void);
+
/**
* Focus window after opening, or put them in the background.
*/
void useWindowFocus(const bool use_focus);
+
bool m_windowFocus;
/**
@@ -199,6 +203,15 @@ class GHOST_System : public GHOST_ISystem {
* Cursor management functionality
***************************************************************************************/
+ /* Client relative functions use a default implementation
+ * that converts from screen-coordinates to client coordinates.
+ * Implementations may override. */
+
+ GHOST_TSuccess getCursorPositionClientRelative(const GHOST_IWindow *window,
+ int32_t &x,
+ int32_t &y) const;
+ GHOST_TSuccess setCursorPositionClientRelative(GHOST_IWindow *window, int32_t x, int32_t y);
+
/**
* Inherited from GHOST_ISystem but left pure virtual
* <pre>
@@ -217,7 +230,7 @@ class GHOST_System : public GHOST_ISystem {
* \param isDown: The state of a modifier key (true == pressed).
* \return Indication of success.
*/
- GHOST_TSuccess getModifierKeyState(GHOST_TModifierKeyMask mask, bool &isDown) const;
+ GHOST_TSuccess getModifierKeyState(GHOST_TModifierKey mask, bool &isDown) const;
/**
* Returns the state of a mouse button (outside the message queue).
@@ -225,7 +238,7 @@ class GHOST_System : public GHOST_ISystem {
* \param isDown: Button state.
* \return Indication of success.
*/
- GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool &isDown) const;
+ GHOST_TSuccess getButtonState(GHOST_TButton mask, bool &isDown) const;
/**
* Set which tablet API to use. Only affects Windows, other platforms have a single API.
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index 8677c0b9552..c247ef3daa0 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -37,7 +37,7 @@
#pragma mark KeyMap, mouse converters
-static GHOST_TButtonMask convertButton(int button)
+static GHOST_TButton convertButton(int button)
{
switch (button) {
case 0:
@@ -787,7 +787,7 @@ GHOST_IWindow *GHOST_SystemCocoa::getWindowUnderCursor(int32_t x, int32_t y)
}
/**
- * \note : returns coordinates in Cocoa screen coordinates
+ * \note returns coordinates in Cocoa screen coordinates.
*/
GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(int32_t &x, int32_t &y) const
{
@@ -800,7 +800,7 @@ GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(int32_t &x, int32_t &y) cons
}
/**
- * \note : expect Cocoa screen coordinates
+ * \note expect Cocoa screen coordinates.
*/
GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(int32_t x, int32_t y)
{
@@ -1779,7 +1779,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
NSString *characters;
NSData *convertedCharacters;
GHOST_TKey keyCode;
- unsigned char ascii;
NSString *charsIgnoringModifiers;
window = m_windowManager->getWindowAssociatedWithOSWindow((void *)[event window]);
@@ -1789,7 +1788,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
}
char utf8_buf[6] = {'\0'};
- ascii = 0;
switch ([event type]) {
@@ -1809,7 +1807,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
kUCKeyActionUp);
}
- /* handling both unicode or ascii */
characters = [event characters];
if ([characters length] > 0) {
convertedCharacters = [characters dataUsingEncoding:NSUTF8StringEncoding];
@@ -1835,41 +1832,31 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSEventModifierFlagCommand))
break; // Cmd-Q is directly handled by Cocoa
- /* ascii is a subset of unicode */
- if (utf8_buf[0] && !utf8_buf[1]) {
- ascii = utf8_buf[0];
- }
-
if ([event type] == NSEventTypeKeyDown) {
pushEvent(new GHOST_EventKey([event timestamp] * 1000,
GHOST_kEventKeyDown,
window,
keyCode,
- ascii,
- utf8_buf,
- [event isARepeat]));
+ [event isARepeat],
+ utf8_buf));
#if 0
- printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",
+ printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u utf8=%s\n",
[event keyCode],
[charsIgnoringModifiers length] > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
' ',
keyCode,
- ascii,
- ascii,
utf8_buf);
#endif
}
else {
pushEvent(new GHOST_EventKey(
- [event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, 0, NULL, false));
+ [event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, false, NULL));
#if 0
- printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",
+ printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u utf8=%s\n",
[event keyCode],
[charsIgnoringModifiers length] > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
' ',
keyCode,
- ascii,
- ascii,
utf8_buf);
#endif
}
diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h
index 48973a00573..644eb1ba0a5 100644
--- a/intern/ghost/intern/GHOST_SystemNULL.h
+++ b/intern/ghost/intern/GHOST_SystemNULL.h
@@ -40,7 +40,7 @@ class GHOST_SystemNULL : public GHOST_System {
}
char *getClipboard(bool selection) const
{
- return NULL;
+ return nullptr;
}
void putClipboard(const char *buffer, bool selection) const
{ /* nop */
@@ -69,7 +69,7 @@ class GHOST_SystemNULL : public GHOST_System {
}
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings)
{
- return NULL;
+ return nullptr;
}
GHOST_TSuccess disposeContext(GHOST_IContext *context)
{
@@ -117,6 +117,6 @@ class GHOST_SystemNULL : public GHOST_System {
GHOST_IWindow *getWindowUnderCursor(int32_t x, int32_t y)
{
- return NULL;
+ return nullptr;
}
};
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
index d2c678855f2..41babc5d312 100644
--- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
@@ -17,8 +17,8 @@
#include <sys/time.h>
#include <unistd.h>
+#include <cstdio> /* for fprintf only */
#include <cstdlib> /* for exit */
-#include <stdio.h> /* for fprintf only */
#include <pwd.h> /* for get home without use getenv() */
#include <string>
@@ -28,7 +28,7 @@ using std::string;
#ifdef PREFIX
static const char *static_path = PREFIX "/share";
#else
-static const char *static_path = NULL;
+static const char *static_path = nullptr;
#endif
GHOST_SystemPathsUnix::GHOST_SystemPathsUnix()
@@ -39,7 +39,7 @@ GHOST_SystemPathsUnix::~GHOST_SystemPathsUnix()
{
}
-const char *GHOST_SystemPathsUnix::getSystemDir(int, const char *versionstr) const
+const char *GHOST_SystemPathsUnix::getSystemDir(int /*version*/, const char *versionstr) const
{
/* no prefix assumes a portable build which only uses bundled scripts */
if (static_path) {
@@ -47,7 +47,7 @@ const char *GHOST_SystemPathsUnix::getSystemDir(int, const char *versionstr) con
return system_path.c_str();
}
- return NULL;
+ return nullptr;
}
const char *GHOST_SystemPathsUnix::getUserDir(int version, const char *versionstr) const
@@ -67,32 +67,29 @@ const char *GHOST_SystemPathsUnix::getUserDir(int version, const char *versionst
user_path = string(home) + "/.blender/" + versionstr;
}
else {
- return NULL;
+ return nullptr;
}
}
return user_path.c_str();
}
- else {
- if (user_path.empty() || last_version != version) {
- const char *home = getenv("XDG_CONFIG_HOME");
-
- last_version = version;
+ if (user_path.empty() || last_version != version) {
+ const char *home = getenv("XDG_CONFIG_HOME");
- if (home) {
- user_path = string(home) + "/blender/" + versionstr;
- }
- else {
- home = getenv("HOME");
+ last_version = version;
- if (home == NULL)
- home = getpwuid(getuid())->pw_dir;
-
- user_path = string(home) + "/.config/blender/" + versionstr;
+ if (home) {
+ user_path = string(home) + "/blender/" + versionstr;
+ }
+ else {
+ home = getenv("HOME");
+ if (home == nullptr) {
+ home = getpwuid(getuid())->pw_dir;
}
+ user_path = string(home) + "/.config/blender/" + versionstr;
}
-
- return user_path.c_str();
}
+
+ return user_path.c_str();
}
const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
@@ -135,7 +132,7 @@ const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes
GHOST_ASSERT(
false,
"GHOST_SystemPathsUnix::getUserSpecialDir(): Invalid enum value for type parameter");
- return NULL;
+ return nullptr;
}
static string path = "";
@@ -143,8 +140,8 @@ const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes
string command = string("xdg-user-dir ") + type_str + " 2> /dev/null";
FILE *fstream = popen(command.c_str(), "r");
- if (fstream == NULL) {
- return NULL;
+ if (fstream == nullptr) {
+ return nullptr;
}
std::stringstream path_stream;
while (!feof(fstream)) {
@@ -157,7 +154,7 @@ const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes
}
if (pclose(fstream) == -1) {
perror("GHOST_SystemPathsUnix::getUserSpecialDir failed at pclose()");
- return NULL;
+ return nullptr;
}
if (!add_path.empty()) {
@@ -165,12 +162,12 @@ const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes
}
path = path_stream.str();
- return path[0] ? path.c_str() : NULL;
+ return path[0] ? path.c_str() : nullptr;
}
const char *GHOST_SystemPathsUnix::getBinaryDir() const
{
- return NULL;
+ return nullptr;
}
void GHOST_SystemPathsUnix::addToSystemRecentFiles(const char * /*filename*/) const
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index b013127d1f3..d912b57f049 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -4,7 +4,7 @@
* \ingroup GHOST
*/
-#include <assert.h>
+#include <cassert>
#include "GHOST_ContextSDL.h"
#include "GHOST_SystemSDL.h"
@@ -47,7 +47,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
const bool /* is_dialog */,
const GHOST_IWindow *parentWindow)
{
- GHOST_WindowSDL *window = NULL;
+ GHOST_WindowSDL *window = nullptr;
window = new GHOST_WindowSDL(this,
title,
@@ -79,7 +79,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
}
else {
delete window;
- window = NULL;
+ window = nullptr;
}
}
return window;
@@ -127,20 +127,20 @@ uint8_t GHOST_SystemSDL::getNumDisplays() const
GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
{
- GHOST_Context *context = new GHOST_ContextSDL(0,
- NULL,
+ GHOST_Context *context = new GHOST_ContextSDL(false,
+ nullptr,
0, /* Profile bit. */
3,
3,
GHOST_OPENGL_SDL_CONTEXT_FLAGS,
GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY);
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
- return NULL;
+ return nullptr;
}
GHOST_TSuccess GHOST_SystemSDL::disposeContext(GHOST_IContext *context)
@@ -279,6 +279,141 @@ static GHOST_TKey convertSDLKey(SDL_Scancode key)
}
#undef GXMAP
+static char convert_keyboard_event_to_ascii(const SDL_KeyboardEvent &sdl_sub_evt)
+{
+ SDL_Keycode sym = sdl_sub_evt.keysym.sym;
+ if (sym > 127) {
+ switch (sym) {
+ case SDLK_KP_DIVIDE:
+ sym = '/';
+ break;
+ case SDLK_KP_MULTIPLY:
+ sym = '*';
+ break;
+ case SDLK_KP_MINUS:
+ sym = '-';
+ break;
+ case SDLK_KP_PLUS:
+ sym = '+';
+ break;
+ case SDLK_KP_1:
+ sym = '1';
+ break;
+ case SDLK_KP_2:
+ sym = '2';
+ break;
+ case SDLK_KP_3:
+ sym = '3';
+ break;
+ case SDLK_KP_4:
+ sym = '4';
+ break;
+ case SDLK_KP_5:
+ sym = '5';
+ break;
+ case SDLK_KP_6:
+ sym = '6';
+ break;
+ case SDLK_KP_7:
+ sym = '7';
+ break;
+ case SDLK_KP_8:
+ sym = '8';
+ break;
+ case SDLK_KP_9:
+ sym = '9';
+ break;
+ case SDLK_KP_0:
+ sym = '0';
+ break;
+ case SDLK_KP_PERIOD:
+ sym = '.';
+ break;
+ default:
+ sym = 0;
+ break;
+ }
+ }
+ else {
+ if (sdl_sub_evt.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
+ /* Weak US keyboard assumptions. */
+ if (sym >= 'a' && sym <= ('a' + 32)) {
+ sym -= 32;
+ }
+ else {
+ switch (sym) {
+ case '`':
+ sym = '~';
+ break;
+ case '1':
+ sym = '!';
+ break;
+ case '2':
+ sym = '@';
+ break;
+ case '3':
+ sym = '#';
+ break;
+ case '4':
+ sym = '$';
+ break;
+ case '5':
+ sym = '%';
+ break;
+ case '6':
+ sym = '^';
+ break;
+ case '7':
+ sym = '&';
+ break;
+ case '8':
+ sym = '*';
+ break;
+ case '9':
+ sym = '(';
+ break;
+ case '0':
+ sym = ')';
+ break;
+ case '-':
+ sym = '_';
+ break;
+ case '=':
+ sym = '+';
+ break;
+ case '[':
+ sym = '{';
+ break;
+ case ']':
+ sym = '}';
+ break;
+ case '\\':
+ sym = '|';
+ break;
+ case ';':
+ sym = ':';
+ break;
+ case '\'':
+ sym = '"';
+ break;
+ case ',':
+ sym = '<';
+ break;
+ case '.':
+ sym = '>';
+ break;
+ case '/':
+ sym = '?';
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ return (char)sym;
+}
+
/**
* Events don't always have valid windows,
* but GHOST needs a window _always_. fallback to the GL window.
@@ -286,7 +421,7 @@ static GHOST_TKey convertSDLKey(SDL_Scancode key)
static SDL_Window *SDL_GetWindowFromID_fallback(Uint32 id)
{
SDL_Window *sdl_win = SDL_GetWindowFromID(id);
- if (sdl_win == NULL) {
+ if (sdl_win == nullptr) {
sdl_win = SDL_GL_GetCurrentWindow();
}
return sdl_win;
@@ -294,16 +429,16 @@ static SDL_Window *SDL_GetWindowFromID_fallback(Uint32 id)
void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
{
- GHOST_Event *g_event = NULL;
+ GHOST_Event *g_event = nullptr;
switch (sdl_event->type) {
case SDL_WINDOWEVENT: {
SDL_WindowEvent &sdl_sub_evt = sdl_event->window;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- /* Can be NULL on close window. */
+ /* Can be nullptr on close window. */
#if 0
- assert(window != NULL);
+ assert(window != nullptr);
#endif
switch (sdl_sub_evt.event) {
@@ -340,7 +475,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
SDL_MouseMotionEvent &sdl_sub_evt = sdl_event->motion;
SDL_Window *sdl_win = SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID);
GHOST_WindowSDL *window = findGhostWindow(sdl_win);
- assert(window != NULL);
+ assert(window != nullptr);
int x_win, y_win;
SDL_GetWindowPosition(sdl_win, &x_win, &y_win);
@@ -410,28 +545,34 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN: {
SDL_MouseButtonEvent &sdl_sub_evt = sdl_event->button;
- GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
+ GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventButtonDown :
GHOST_kEventButtonUp;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- assert(window != NULL);
+ assert(window != nullptr);
/* process rest of normal mouse buttons */
- if (sdl_sub_evt.button == SDL_BUTTON_LEFT)
+ if (sdl_sub_evt.button == SDL_BUTTON_LEFT) {
gbmask = GHOST_kButtonMaskLeft;
- else if (sdl_sub_evt.button == SDL_BUTTON_MIDDLE)
+ }
+ else if (sdl_sub_evt.button == SDL_BUTTON_MIDDLE) {
gbmask = GHOST_kButtonMaskMiddle;
- else if (sdl_sub_evt.button == SDL_BUTTON_RIGHT)
+ }
+ else if (sdl_sub_evt.button == SDL_BUTTON_RIGHT) {
gbmask = GHOST_kButtonMaskRight;
- /* these buttons are untested! */
- else if (sdl_sub_evt.button == SDL_BUTTON_X1)
+ /* these buttons are untested! */
+ }
+ else if (sdl_sub_evt.button == SDL_BUTTON_X1) {
gbmask = GHOST_kButtonMaskButton4;
- else if (sdl_sub_evt.button == SDL_BUTTON_X2)
+ }
+ else if (sdl_sub_evt.button == SDL_BUTTON_X2) {
gbmask = GHOST_kButtonMaskButton5;
- else
+ }
+ else {
break;
+ }
g_event = new GHOST_EventButton(
getMilliSeconds(), type, window, gbmask, GHOST_TABLET_DATA_NONE);
@@ -441,156 +582,33 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
SDL_MouseWheelEvent &sdl_sub_evt = sdl_event->wheel;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- assert(window != NULL);
+ assert(window != nullptr);
g_event = new GHOST_EventWheel(getMilliSeconds(), window, sdl_sub_evt.y);
break;
}
case SDL_KEYDOWN:
case SDL_KEYUP: {
SDL_KeyboardEvent &sdl_sub_evt = sdl_event->key;
- SDL_Keycode sym = sdl_sub_evt.keysym.sym;
GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventKeyDown :
GHOST_kEventKeyUp;
+ const bool is_repeat = sdl_sub_evt.repeat != 0;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- assert(window != NULL);
+ assert(window != nullptr);
GHOST_TKey gkey = convertSDLKey(sdl_sub_evt.keysym.scancode);
/* NOTE: the `sdl_sub_evt.keysym.sym` is truncated,
* for unicode support ghost has to be modified. */
- // printf("%d\n", sym);
- if (sym > 127) {
- switch (sym) {
- case SDLK_KP_DIVIDE:
- sym = '/';
- break;
- case SDLK_KP_MULTIPLY:
- sym = '*';
- break;
- case SDLK_KP_MINUS:
- sym = '-';
- break;
- case SDLK_KP_PLUS:
- sym = '+';
- break;
- case SDLK_KP_1:
- sym = '1';
- break;
- case SDLK_KP_2:
- sym = '2';
- break;
- case SDLK_KP_3:
- sym = '3';
- break;
- case SDLK_KP_4:
- sym = '4';
- break;
- case SDLK_KP_5:
- sym = '5';
- break;
- case SDLK_KP_6:
- sym = '6';
- break;
- case SDLK_KP_7:
- sym = '7';
- break;
- case SDLK_KP_8:
- sym = '8';
- break;
- case SDLK_KP_9:
- sym = '9';
- break;
- case SDLK_KP_0:
- sym = '0';
- break;
- case SDLK_KP_PERIOD:
- sym = '.';
- break;
- default:
- sym = 0;
- break;
- }
- }
- else {
- if (sdl_sub_evt.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
- /* lame US keyboard assumptions */
- if (sym >= 'a' && sym <= ('a' + 32)) {
- sym -= 32;
- }
- else {
- switch (sym) {
- case '`':
- sym = '~';
- break;
- case '1':
- sym = '!';
- break;
- case '2':
- sym = '@';
- break;
- case '3':
- sym = '#';
- break;
- case '4':
- sym = '$';
- break;
- case '5':
- sym = '%';
- break;
- case '6':
- sym = '^';
- break;
- case '7':
- sym = '&';
- break;
- case '8':
- sym = '*';
- break;
- case '9':
- sym = '(';
- break;
- case '0':
- sym = ')';
- break;
- case '-':
- sym = '_';
- break;
- case '=':
- sym = '+';
- break;
- case '[':
- sym = '{';
- break;
- case ']':
- sym = '}';
- break;
- case '\\':
- sym = '|';
- break;
- case ';':
- sym = ':';
- break;
- case '\'':
- sym = '"';
- break;
- case ',':
- sym = '<';
- break;
- case '.':
- sym = '>';
- break;
- case '/':
- sym = '?';
- break;
- default:
- break;
- }
- }
- }
+
+ /* TODO(@campbellbarton): support full unicode, SDL supports this but it needs to be
+ * explicitly enabled via #SDL_StartTextInput which GHOST would have to wrap. */
+ char utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'};
+ if (type == GHOST_kEventKeyDown) {
+ utf8_buf[0] = convert_keyboard_event_to_ascii(sdl_sub_evt);
}
- g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, sym, NULL, false);
+ g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, is_repeat, utf8_buf);
break;
}
}
@@ -660,14 +678,14 @@ bool GHOST_SystemSDL::processEvents(bool waitForEvent)
uint64_t next = timerMgr->nextFireTime();
if (next == GHOST_kFireTimeNever) {
- SDL_WaitEventTimeout(NULL, -1);
+ SDL_WaitEventTimeout(nullptr, -1);
// SleepTillEvent(m_display, -1);
}
else {
int64_t maxSleep = next - getMilliSeconds();
if (maxSleep >= 0) {
- SDL_WaitEventTimeout(NULL, next - getMilliSeconds());
+ SDL_WaitEventTimeout(nullptr, next - getMilliSeconds());
// SleepTillEvent(m_display, next - getMilliSeconds()); /* X11. */
}
}
@@ -693,9 +711,9 @@ bool GHOST_SystemSDL::processEvents(bool waitForEvent)
GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
{
- if (sdl_win == NULL)
- return NULL;
-
+ if (sdl_win == nullptr) {
+ return nullptr;
+ }
/* It is not entirely safe to do this as the backptr may point
* to a window that has recently been removed.
* We should always check the window manager's list of windows
@@ -712,19 +730,19 @@ GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
return window;
}
}
- return NULL;
+ return nullptr;
}
void GHOST_SystemSDL::addDirtyWindow(GHOST_WindowSDL *bad_wind)
{
- GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
+ GHOST_ASSERT((bad_wind != nullptr), "addDirtyWindow() nullptr ptr trapped (window)");
m_dirty_windows.push_back(bad_wind);
}
GHOST_TSuccess GHOST_SystemSDL::getButtons(GHOST_Buttons &buttons) const
{
- Uint8 state = SDL_GetMouseState(NULL, NULL);
+ Uint8 state = SDL_GetMouseState(nullptr, nullptr);
buttons.set(GHOST_kButtonMaskLeft, (state & SDL_BUTTON_LMASK) != 0);
buttons.set(GHOST_kButtonMaskMiddle, (state & SDL_BUTTON_MMASK) != 0);
buttons.set(GHOST_kButtonMaskRight, (state & SDL_BUTTON_RMASK) != 0);
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 24d3f525c97..d7520f1243f 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -13,10 +13,19 @@
#include "GHOST_EventWheel.h"
#include "GHOST_TimerManager.h"
#include "GHOST_WindowManager.h"
+#include "GHOST_utildefines.h"
#include "GHOST_ContextEGL.h"
+#ifdef WITH_GHOST_WAYLAND_DYNLOAD
+# include <wayland_dynload_API.h> /* For `ghost_wl_dynload_libraries`. */
+#endif
+
#include <EGL/egl.h>
+
+#ifdef WITH_GHOST_WAYLAND_DYNLOAD
+# include <wayland_dynload_egl.h>
+#endif
#include <wayland-egl.h>
#include <algorithm>
@@ -26,22 +35,63 @@
#include <unordered_map>
#include <unordered_set>
-#include "GHOST_WaylandCursorSettings.h"
-#include <pointer-constraints-client-protocol.h>
-#include <relative-pointer-client-protocol.h>
+#ifdef WITH_GHOST_WAYLAND_DYNLOAD
+# include <wayland_dynload_cursor.h>
+#endif
#include <wayland-cursor.h>
+
+#include "GHOST_WaylandCursorSettings.h"
+
#include <xkbcommon/xkbcommon.h>
+/* Generated by `wayland-scanner`. */
+#include <pointer-constraints-unstable-v1-client-protocol.h>
+#include <relative-pointer-unstable-v1-client-protocol.h>
+#include <tablet-unstable-v2-client-protocol.h>
+#include <xdg-output-unstable-v1-client-protocol.h>
+
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <cstring>
+#include <mutex>
+
+/* Logging, use `ghost.wl.*` prefix. */
+#include "CLG_log.h"
+
+static void keyboard_handle_key_repeat_cancel(struct input_t *input);
+
+static void output_handle_done(void *data, struct wl_output *wl_output);
/**
+ * GNOME (mutter 42.2 had a bug with confine not respecting scale - Hi-DPI), See: T98793.
+ * Even though this has been fixed, at time of writing it's not yet in a release.
+ * Workaround the problem by implementing confine with a software cursor.
+ * While this isn't ideal, it's not adding a lot of overhead as software
+ * cursors are already used for warping (which WAYLAND doesn't support).
+ */
+#define USE_GNOME_CONFINE_HACK
+/**
+ * Always use software confine (not just in GNOME).
+ * Useful for developing with compositors that don't need this workaround.
+ */
+// #define USE_GNOME_CONFINE_HACK_ALWAYS_ON
+
+#ifdef USE_GNOME_CONFINE_HACK
+static bool use_gnome_confine_hack = false;
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Inline Event Codes
+ *
* Selected input event code defines from `linux/input-event-codes.h`
* We include some of the button input event codes here, since the header is
- * only available in more recent kernel versions. The event codes are used to
+ * only available in more recent kernel versions.
+ * \{ */
+
+/**
+ * The event codes are used to
* to differentiate from which mouse button an event comes from.
*/
#define BTN_LEFT 0x110
@@ -53,167 +103,394 @@
#define BTN_BACK 0x116
// #define BTN_TASK 0x117 /* UNUSED. */
-struct buffer_t {
- void *data;
- size_t size;
-};
+/**
+ * Tablet events.
+ */
+#define BTN_STYLUS 0x14b /* Use as right-mouse. */
+#define BTN_STYLUS2 0x14c /* Use as middle-mouse. */
+/* NOTE(@campbellbarton): Map to an additional button (not sure which hardware uses this). */
+#define BTN_STYLUS3 0x149
+
+/**
+ * Keyboard scan-codes.
+ */
+#define KEY_GRAVE 41
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Private Types & Defines
+ * \{ */
+
+/**
+ * From XKB internals, use for converting a scan-code from WAYLAND to a #xkb_keycode_t.
+ * Ideally this wouldn't need a local define.
+ */
+#define EVDEV_OFFSET 8
struct cursor_t {
- bool visible;
- struct wl_surface *surface = nullptr;
- struct wl_buffer *buffer;
- struct wl_cursor_image image;
- struct buffer_t *file_buffer = nullptr;
- struct wl_cursor_theme *theme = nullptr;
- int size;
+ bool visible = false;
+ /**
+ * When false, hide the hardware cursor, while the cursor is still considered to be `visible`,
+ * since the grab-mode determines the state of the software cursor,
+ * this may change - removing the need for a software cursor and in this case it's important
+ * the hardware cursor is used.
+ */
+ bool is_hardware = true;
+ bool is_custom = false;
+ struct wl_surface *wl_surface = nullptr;
+ struct wl_buffer *wl_buffer = nullptr;
+ struct wl_cursor_image wl_image = {0};
+ struct wl_cursor_theme *wl_theme = nullptr;
+ void *custom_data = nullptr;
+ size_t custom_data_size = 0;
+ int size = 0;
std::string theme_name;
- // outputs on which the cursor is visible
- std::unordered_set<const output_t *> outputs;
- int scale = 1;
+
+ int custom_scale = 1;
+};
+
+/**
+ * A single tablet can have multiple tools (pen, eraser, brush... etc).
+ * WAYLAND exposes tools via #zwp_tablet_tool_v2.
+ * Since are no API's to access properties of the tool, store the values here.
+ */
+struct tablet_tool_input_t {
+ struct input_t *input = nullptr;
+ struct wl_surface *cursor_surface = nullptr;
+ /** Used to delay clearing tablet focused surface until the frame is handled. */
+ bool proximity = false;
+
+ GHOST_TabletData data = GHOST_TABLET_DATA_NONE;
};
struct data_offer_t {
std::unordered_set<std::string> types;
- uint32_t source_actions;
- uint32_t dnd_action;
- struct wl_data_offer *id;
- std::atomic<bool> in_use;
+ uint32_t source_actions = 0;
+ uint32_t dnd_action = 0;
+ struct wl_data_offer *id = nullptr;
+ std::atomic<bool> in_use = false;
struct {
- int x, y;
+ /** Compatible with #input_t.xy coordinates. */
+ wl_fixed_t xy[2] = {0, 0};
} dnd;
};
struct data_source_t {
- struct wl_data_source *data_source;
- /** Last device that was active. */
- uint32_t source_serial;
- char *buffer_out;
+ struct wl_data_source *data_source = nullptr;
+ char *buffer_out = nullptr;
};
+/**
+ * Data used to implement client-side key-repeat.
+ *
+ * \note it's important not to store the target window here
+ * as it can be closed while the key is repeating,
+ * instead use the focused keyboard from #intput_t which is cleared when windows are closed.
+ * Therefor keyboard events must always check the window has not been cleared.
+ */
struct key_repeat_payload_t {
- GHOST_SystemWayland *system;
- GHOST_IWindow *window;
- GHOST_TKey key;
- GHOST_TEventKeyData key_data;
+ struct input_t *input = nullptr;
+
+ xkb_keycode_t key_code;
+
+ /**
+ * Don't cache the `utf8_buf` as this changes based on modifiers which may be pressed
+ * while key repeat is enabled.
+ */
+ struct {
+ GHOST_TKey gkey;
+ } key_data;
+};
+
+/** Internal variables used to track grab-state. */
+struct input_grab_state_t {
+ bool use_lock = false;
+ bool use_confine = false;
+};
+
+/**
+ * State of the pointing device (tablet or mouse).
+ */
+struct input_state_pointer_t {
+ /**
+ * High precision coordinates.
+ *
+ * Mapping to pixels requires the window scale.
+ * The following example converts these values to screen coordinates.
+ * \code{.cc}
+ * const wl_fixed_t scale = win->scale();
+ * const int event_xy[2] = {
+ * wl_fixed_to_int(scale * input_state->xy[0]),
+ * wl_fixed_to_int(scale * input_state->xy[1]),
+ * };
+ * \endcode
+ */
+ wl_fixed_t xy[2] = {0, 0};
+
+ /** Outputs on which the cursor is visible. */
+ std::unordered_set<const output_t *> outputs;
+
+ int theme_scale = 1;
+
+ /** The serial of the last used pointer or tablet. */
+ uint32_t serial = 0;
+
+ /**
+ * The surface last used with this pointing device
+ * (events with this pointing device will be sent here).
+ */
+ struct wl_surface *wl_surface = nullptr;
+
+ GHOST_Buttons buttons = GHOST_Buttons();
+};
+
+/**
+ * State of the keyboard.
+ */
+struct input_state_keyboard_t {
+ /** The serial of the last used pointer or tablet. */
+ uint32_t serial = 0;
+
+ /**
+ * The surface last used with this pointing device
+ * (events with this pointing device will be sent here).
+ */
+ struct wl_surface *wl_surface = nullptr;
};
struct input_t {
- GHOST_SystemWayland *system;
+ GHOST_SystemWayland *system = nullptr;
std::string name;
- struct wl_seat *seat;
- struct wl_pointer *pointer = nullptr;
- struct wl_keyboard *keyboard = nullptr;
+ struct wl_seat *wl_seat = nullptr;
+ struct wl_pointer *wl_pointer = nullptr;
+ struct wl_keyboard *wl_keyboard = nullptr;
+ struct zwp_tablet_seat_v2 *tablet_seat = nullptr;
+
+ /** All currently active tablet tools (needed for changing the cursor). */
+ std::unordered_set<zwp_tablet_tool_v2 *> tablet_tools;
+
+ /** Use to check if the last cursor input was tablet or pointer. */
+ uint32_t cursor_source_serial = 0;
+
+ input_state_pointer_t pointer;
+
+ /** Mostly this can be interchanged with `pointer` however it can't be locked/confined. */
+ input_state_pointer_t tablet;
+
+ input_state_keyboard_t keyboard;
+
+#ifdef USE_GNOME_CONFINE_HACK
+ bool use_pointer_software_confine = false;
+#endif
+ /** The cursor location (in pixel-space) when hidden grab started (#GHOST_kGrabHide). */
+ wl_fixed_t grab_lock_xy[2] = {0, 0};
- uint32_t pointer_serial;
- int x, y;
- GHOST_Buttons buttons;
struct cursor_t cursor;
- struct zwp_relative_pointer_v1 *relative_pointer;
- struct zwp_locked_pointer_v1 *locked_pointer;
+ struct zwp_relative_pointer_v1 *relative_pointer = nullptr;
+ struct zwp_locked_pointer_v1 *locked_pointer = nullptr;
+ struct zwp_confined_pointer_v1 *confined_pointer = nullptr;
+
+ struct xkb_context *xkb_context = nullptr;
+
+ struct xkb_state *xkb_state = nullptr;
+ /**
+ * Keep a state with no modifiers active, use for symbol lookups.
+ */
+ struct xkb_state *xkb_state_empty = nullptr;
+ /**
+ * Keep a state with number-lock enabled, use to access predictable key-pad symbols.
+ * If number-lock is not supported by the key-map, this is set to NULL.
+ */
+ struct xkb_state *xkb_state_empty_with_numlock = nullptr;
- struct xkb_context *xkb_context;
- struct xkb_state *xkb_state;
struct {
- /* Key repetition in character per second. */
- int32_t rate;
- /* Time (milliseconds) after which to start repeating keys. */
- int32_t delay;
- /* Timer for key repeats. */
+ /** Key repetition in character per second. */
+ int32_t rate = 0;
+ /** Time (milliseconds) after which to start repeating keys. */
+ int32_t delay = 0;
+ /** Timer for key repeats. */
GHOST_ITimerTask *timer = nullptr;
} key_repeat;
- struct wl_surface *focus_pointer = nullptr;
- struct wl_surface *focus_keyboard = nullptr;
+ struct wl_surface *focus_dnd = nullptr;
struct wl_data_device *data_device = nullptr;
- struct data_offer_t *data_offer_dnd; /* Drag & Drop. */
- struct data_offer_t *data_offer_copy_paste; /* Copy & Paste. */
+ /** Drag & Drop. */
+ struct data_offer_t *data_offer_dnd = nullptr;
+ std::mutex data_offer_dnd_mutex;
+
+ /** Copy & Paste. */
+ struct data_offer_t *data_offer_copy_paste = nullptr;
+ std::mutex data_offer_copy_paste_mutex;
- struct data_source_t *data_source;
+ struct data_source_t *data_source = nullptr;
+ std::mutex data_source_mutex;
+
+ /** Last device that was active. */
+ uint32_t data_source_serial = 0;
};
struct display_t {
- GHOST_SystemWayland *system;
+ GHOST_SystemWayland *system = nullptr;
- struct wl_display *display;
+ struct wl_display *display = nullptr;
struct wl_compositor *compositor = nullptr;
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ struct libdecor *decor_context = nullptr;
+#else
struct xdg_wm_base *xdg_shell = nullptr;
struct zxdg_decoration_manager_v1 *xdg_decoration_manager = nullptr;
+#endif
+
+ struct zxdg_output_manager_v1 *xdg_output_manager = nullptr;
struct wl_shm *shm = nullptr;
std::vector<output_t *> outputs;
std::vector<input_t *> inputs;
- struct {
- std::string theme;
- int size;
- } cursor;
+
struct wl_data_device_manager *data_device_manager = nullptr;
+ struct zwp_tablet_manager_v2 *tablet_manager = nullptr;
struct zwp_relative_pointer_manager_v1 *relative_pointer_manager = nullptr;
struct zwp_pointer_constraints_v1 *pointer_constraints = nullptr;
-
- std::vector<struct wl_surface *> os_surfaces;
- std::vector<struct wl_egl_window *> os_egl_windows;
};
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Private Utility Functions
+ * \{ */
+
static GHOST_WindowManager *window_manager = nullptr;
+/** Check this lock before accessing `GHOST_SystemWayland::selection` from a thread. */
+static std::mutex system_selection_mutex;
+
+/**
+ * Callback for WAYLAND to run when there is an error.
+ *
+ * \note It's useful to set a break-point on this function as some errors are fatal
+ * (for all intents and purposes) but don't crash the process.
+ */
+static void ghost_wayland_log_handler(const char *msg, va_list arg)
+{
+ fprintf(stderr, "GHOST/Wayland: ");
+ vfprintf(stderr, msg, arg); /* Includes newline. */
+
+ GHOST_TBacktraceFn backtrace_fn = GHOST_ISystem::getBacktraceFn();
+ if (backtrace_fn) {
+ backtrace_fn(stderr); /* Includes newline. */
+ }
+}
+
+static input_state_pointer_t *input_state_pointer_active(input_t *input)
+{
+ if (input->pointer.serial == input->cursor_source_serial) {
+ return &input->pointer;
+ }
+ if (input->tablet.serial == input->cursor_source_serial) {
+ return &input->tablet;
+ }
+ return nullptr;
+}
+
+static input_state_pointer_t *input_state_pointer_from_cursor_surface(input_t *input,
+ const wl_surface *wl_surface)
+{
+ if (ghost_wl_surface_own_cursor_pointer(wl_surface)) {
+ return &input->pointer;
+ }
+ if (ghost_wl_surface_own_cursor_tablet(wl_surface)) {
+ return &input->tablet;
+ }
+ GHOST_ASSERT(0, "Surface found without pointer/tablet tag");
+ return nullptr;
+}
+
static void display_destroy(display_t *d)
{
if (d->data_device_manager) {
wl_data_device_manager_destroy(d->data_device_manager);
}
+ if (d->tablet_manager) {
+ zwp_tablet_manager_v2_destroy(d->tablet_manager);
+ }
+
for (output_t *output : d->outputs) {
- wl_output_destroy(output->output);
+ wl_output_destroy(output->wl_output);
delete output;
}
for (input_t *input : d->inputs) {
- if (input->data_source) {
- free(input->data_source->buffer_out);
- if (input->data_source->data_source) {
- wl_data_source_destroy(input->data_source->data_source);
+
+ /* First handle members that require locking.
+ * While highly unlikely, it's possible they are being used while this function runs. */
+ {
+ std::lock_guard lock{input->data_source_mutex};
+ if (input->data_source) {
+ free(input->data_source->buffer_out);
+ if (input->data_source->data_source) {
+ wl_data_source_destroy(input->data_source->data_source);
+ }
+ delete input->data_source;
+ }
+ }
+
+ {
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+ if (input->data_offer_dnd) {
+ wl_data_offer_destroy(input->data_offer_dnd->id);
+ delete input->data_offer_dnd;
}
- delete input->data_source;
}
- if (input->data_offer_copy_paste) {
- wl_data_offer_destroy(input->data_offer_copy_paste->id);
- delete input->data_offer_copy_paste;
+
+ {
+ std::lock_guard lock{input->data_offer_copy_paste_mutex};
+ if (input->data_offer_copy_paste) {
+ wl_data_offer_destroy(input->data_offer_copy_paste->id);
+ delete input->data_offer_copy_paste;
+ }
}
+
if (input->data_device) {
wl_data_device_release(input->data_device);
}
- if (input->pointer) {
- if (input->cursor.file_buffer) {
- munmap(input->cursor.file_buffer->data, input->cursor.file_buffer->size);
- delete input->cursor.file_buffer;
- }
- if (input->cursor.surface) {
- wl_surface_destroy(input->cursor.surface);
+
+ if (input->cursor.custom_data) {
+ munmap(input->cursor.custom_data, input->cursor.custom_data_size);
+ }
+
+ if (input->wl_pointer) {
+ if (input->cursor.wl_surface) {
+ wl_surface_destroy(input->cursor.wl_surface);
}
- if (input->cursor.theme) {
- wl_cursor_theme_destroy(input->cursor.theme);
+ if (input->cursor.wl_theme) {
+ wl_cursor_theme_destroy(input->cursor.wl_theme);
}
- if (input->pointer) {
- wl_pointer_destroy(input->pointer);
+ if (input->wl_pointer) {
+ wl_pointer_destroy(input->wl_pointer);
}
}
- if (input->keyboard) {
+ if (input->wl_keyboard) {
if (input->key_repeat.timer) {
- delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData());
- input->system->removeTimer(input->key_repeat.timer);
- input->key_repeat.timer = nullptr;
+ keyboard_handle_key_repeat_cancel(input);
}
- wl_keyboard_destroy(input->keyboard);
- }
- if (input->xkb_state) {
- xkb_state_unref(input->xkb_state);
+ wl_keyboard_destroy(input->wl_keyboard);
}
- if (input->xkb_context) {
- xkb_context_unref(input->xkb_context);
- }
- wl_seat_destroy(input->seat);
+
+ /* Un-referencing checks for NULL case. */
+ xkb_state_unref(input->xkb_state);
+ xkb_state_unref(input->xkb_state_empty);
+ xkb_state_unref(input->xkb_state_empty_with_numlock);
+
+ xkb_context_unref(input->xkb_context);
+
+ wl_seat_destroy(input->wl_seat);
delete input;
}
@@ -229,18 +506,15 @@ static void display_destroy(display_t *d)
zwp_pointer_constraints_v1_destroy(d->pointer_constraints);
}
- for (wl_egl_window *os_egl_window : d->os_egl_windows) {
- wl_egl_window_destroy(os_egl_window);
- }
-
- for (wl_surface *os_surface : d->os_surfaces) {
- wl_surface_destroy(os_surface);
- }
-
if (d->compositor) {
wl_compositor_destroy(d->compositor);
}
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ if (d->decor_context) {
+ libdecor_unref(d->decor_context);
+ }
+#else
if (d->xdg_decoration_manager) {
zxdg_decoration_manager_v1_destroy(d->xdg_decoration_manager);
}
@@ -248,6 +522,7 @@ static void display_destroy(display_t *d)
if (d->xdg_shell) {
xdg_wm_base_destroy(d->xdg_shell);
}
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
if (eglGetDisplay) {
::eglTerminate(eglGetDisplay(EGLNativeDisplayType(d->display)));
@@ -260,7 +535,7 @@ static void display_destroy(display_t *d)
delete d;
}
-static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym)
+static GHOST_TKey xkb_map_gkey(const xkb_keysym_t sym)
{
GHOST_TKey gkey;
@@ -351,8 +626,7 @@ static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym)
GXMAP(gkey, XKB_KEY_XF86AudioPrev, GHOST_kKeyMediaFirst);
GXMAP(gkey, XKB_KEY_XF86AudioNext, GHOST_kKeyMediaLast);
default:
- GHOST_PRINT("unhandled key: " << std::hex << std::showbase << sym << std::dec << " ("
- << sym << ")" << std::endl);
+ /* Rely on #xkb_map_gkey_or_scan_code to report when no key can be found. */
gkey = GHOST_kKeyUnknown;
}
#undef GXMAP
@@ -361,14 +635,70 @@ static GHOST_TKey xkb_map_gkey(const xkb_keysym_t &sym)
return gkey;
}
+/**
+ * Map the keys using the users keyboard layout, if that fails fall back to physical locations.
+ * This is needed so users with keyboard layouts that don't expose #GHOST_kKeyAccentGrave
+ * (typically the key under escape) in the layout can still use this key in keyboard shortcuts.
+ *
+ * \param key: The key's scan-code, compatible with values in `linux/input-event-codes.h`.
+ */
+static GHOST_TKey xkb_map_gkey_or_scan_code(const xkb_keysym_t sym, const uint32_t key)
+{
+ GHOST_TKey gkey = xkb_map_gkey(sym);
+
+ if (UNLIKELY(gkey == GHOST_kKeyUnknown)) {
+ /* Fall back to physical location for keys that would otherwise do nothing. */
+ switch (key) {
+ case KEY_GRAVE: {
+ gkey = GHOST_kKeyAccentGrave;
+ break;
+ }
+ default: {
+ GHOST_PRINT(
+ /* Key-code. */
+ "unhandled key: " << std::hex << std::showbase << sym << /* Hex. */
+ std::dec << " (" << sym << "), " << /* Decimal. */
+ /* Scan-code. */
+ "scan-code: " << std::hex << std::showbase << key << /* Hex. */
+ std::dec << " (" << key << ")" << /* Decimal. */
+ std::endl);
+ break;
+ }
+ }
+ }
+
+ return gkey;
+}
+
+static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wl_tablet_tool_type)
+{
+ switch (wl_tablet_tool_type) {
+ case ZWP_TABLET_TOOL_V2_TYPE_ERASER: {
+ return GHOST_kTabletModeEraser;
+ }
+ case ZWP_TABLET_TOOL_V2_TYPE_PEN:
+ case ZWP_TABLET_TOOL_V2_TYPE_BRUSH:
+ case ZWP_TABLET_TOOL_V2_TYPE_PENCIL:
+ case ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH:
+ case ZWP_TABLET_TOOL_V2_TYPE_FINGER:
+ case ZWP_TABLET_TOOL_V2_TYPE_MOUSE:
+ case ZWP_TABLET_TOOL_V2_TYPE_LENS: {
+ return GHOST_kTabletModeStylus;
+ }
+ }
+
+ GHOST_PRINT("unknown tablet tool: " << wl_tablet_tool_type << std::endl);
+ return GHOST_kTabletModeStylus;
+}
+
static const int default_cursor_size = 24;
-static const std::unordered_map<GHOST_TStandardCursor, std::string> cursors = {
+static const std::unordered_map<GHOST_TStandardCursor, const char *> cursors = {
{GHOST_kStandardCursorDefault, "left_ptr"},
{GHOST_kStandardCursorRightArrow, "right_ptr"},
{GHOST_kStandardCursorLeftArrow, "left_ptr"},
{GHOST_kStandardCursorInfo, ""},
- {GHOST_kStandardCursorDestroy, ""},
+ {GHOST_kStandardCursorDestroy, "pirate"},
{GHOST_kStandardCursorHelp, "question_arrow"},
{GHOST_kStandardCursorWait, "watch"},
{GHOST_kStandardCursorText, "xterm"},
@@ -376,21 +706,21 @@ static const std::unordered_map<GHOST_TStandardCursor, std::string> cursors = {
{GHOST_kStandardCursorCrosshairA, ""},
{GHOST_kStandardCursorCrosshairB, ""},
{GHOST_kStandardCursorCrosshairC, ""},
- {GHOST_kStandardCursorPencil, ""},
+ {GHOST_kStandardCursorPencil, "pencil"},
{GHOST_kStandardCursorUpArrow, "sb_up_arrow"},
{GHOST_kStandardCursorDownArrow, "sb_down_arrow"},
- {GHOST_kStandardCursorVerticalSplit, ""},
- {GHOST_kStandardCursorHorizontalSplit, ""},
+ {GHOST_kStandardCursorVerticalSplit, "split_v"},
+ {GHOST_kStandardCursorHorizontalSplit, "split_h"},
{GHOST_kStandardCursorEraser, ""},
{GHOST_kStandardCursorKnife, ""},
- {GHOST_kStandardCursorEyedropper, ""},
- {GHOST_kStandardCursorZoomIn, ""},
- {GHOST_kStandardCursorZoomOut, ""},
+ {GHOST_kStandardCursorEyedropper, "color-picker"},
+ {GHOST_kStandardCursorZoomIn, "zoom-in"},
+ {GHOST_kStandardCursorZoomOut, "zoom-out"},
{GHOST_kStandardCursorMove, "move"},
- {GHOST_kStandardCursorNSEWScroll, ""},
- {GHOST_kStandardCursorNSScroll, ""},
- {GHOST_kStandardCursorEWScroll, ""},
- {GHOST_kStandardCursorStop, ""},
+ {GHOST_kStandardCursorNSEWScroll, "size_all"}, /* Not an exact match. */
+ {GHOST_kStandardCursorNSScroll, "size_ver"}, /* Not an exact match. */
+ {GHOST_kStandardCursorEWScroll, "size_hor"}, /* Not an exact match. */
+ {GHOST_kStandardCursorStop, "not-allowed"},
{GHOST_kStandardCursorUpDown, "sb_v_double_arrow"},
{GHOST_kStandardCursorLeftRight, "sb_h_double_arrow"},
{GHOST_kStandardCursorTopSide, "top_side"},
@@ -429,68 +759,209 @@ static const std::vector<std::string> mime_send = {
"text/plain",
};
+static int memfd_create_sealed(const char *name)
+{
+#ifdef HAVE_MEMFD_CREATE
+ const int fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (fd >= 0) {
+ fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
+ }
+ return fd;
+#else /* HAVE_MEMFD_CREATE */
+ char *path = getenv("XDG_RUNTIME_DIR");
+ if (!path) {
+ errno = ENOENT;
+ return -1;
+ }
+ char *tmpname;
+ asprintf(&tmpname, "%s/%s-XXXXXX", path, name);
+ const int fd = mkostemp(tmpname, O_CLOEXEC);
+ if (fd >= 0) {
+ unlink(tmpname);
+ }
+ free(tmpname);
+ return fd;
+#endif /* !HAVE_MEMFD_CREATE */
+}
+
+static size_t ghost_wl_shm_format_as_size(enum wl_shm_format format)
+{
+ switch (format) {
+ case WL_SHM_FORMAT_ARGB8888: {
+ return 4;
+ }
+ default: {
+ /* Support other formats as needed. */
+ GHOST_ASSERT(0, "Unexpected format passed in!");
+ return 4;
+ }
+ }
+}
+
+/**
+ * Return a #wl_buffer, ready to have it's data filled in or NULL in case of failure.
+ * The caller is responsible for calling `unmap(buffer_data, buffer_size)`.
+ *
+ * \param r_buffer_data: The buffer to be filled.
+ * \param r_buffer_data_size: The size of `r_buffer_data` in bytes.
+ */
+static wl_buffer *ghost_wl_buffer_create_for_image(struct wl_shm *shm,
+ const int32_t size_xy[2],
+ enum wl_shm_format format,
+ void **r_buffer_data,
+ size_t *r_buffer_data_size)
+{
+ const int fd = memfd_create_sealed("ghost-wl-buffer");
+ wl_buffer *buffer = nullptr;
+ if (fd >= 0) {
+ const int32_t buffer_stride = size_xy[0] * ghost_wl_shm_format_as_size(format);
+ const int32_t buffer_size = buffer_stride * size_xy[1];
+ if (posix_fallocate(fd, 0, buffer_size) == 0) {
+ void *buffer_data = mmap(nullptr, buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (buffer_data != MAP_FAILED) {
+ struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, buffer_size);
+ buffer = wl_shm_pool_create_buffer(pool, 0, UNPACK2(size_xy), buffer_stride, format);
+ wl_shm_pool_destroy(pool);
+ if (buffer) {
+ *r_buffer_data = buffer_data;
+ *r_buffer_data_size = (size_t)buffer_size;
+ }
+ else {
+ /* Highly unlikely. */
+ munmap(buffer_data, buffer_size);
+ }
+ }
+ }
+ close(fd);
+ }
+ return buffer;
+}
+
+/** \} */
+
/* -------------------------------------------------------------------- */
-/** \name Interface Callbacks
+/** \name Listener (Relative Motion), #zwp_relative_pointer_v1_listener
*
* These callbacks are registered for Wayland interfaces and called when
* an event is received from the compositor.
* \{ */
-static void relative_pointer_relative_motion(
- void *data,
- struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/,
- uint32_t /*utime_hi*/,
- uint32_t /*utime_lo*/,
- wl_fixed_t dx,
- wl_fixed_t dy,
- wl_fixed_t /*dx_unaccel*/,
- wl_fixed_t /*dy_unaccel*/)
+static CLG_LogRef LOG_WL_RELATIVE_POINTER = {"ghost.wl.handle.relative_pointer"};
+#define LOG (&LOG_WL_RELATIVE_POINTER)
+
+/**
+ * The caller is responsible for setting the value of `input->xy`.
+ */
+static void relative_pointer_handle_relative_motion_impl(input_t *input,
+ GHOST_WindowWayland *win,
+ const wl_fixed_t xy[2])
{
- input_t *input = static_cast<input_t *>(data);
+ const wl_fixed_t scale = win->scale();
- input->x += wl_fixed_to_int(dx);
- input->y += wl_fixed_to_int(dy);
+ input->pointer.xy[0] = xy[0];
+ input->pointer.xy[1] = xy[1];
- GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
+#ifdef USE_GNOME_CONFINE_HACK
+ if (input->use_pointer_software_confine) {
+ GHOST_Rect bounds;
+ win->getClientBounds(bounds);
+ /* Needed or the cursor is considered outside the window and doesn't restore the location. */
+ bounds.m_r -= 1;
+ bounds.m_b -= 1;
+ bounds.m_l = wl_fixed_from_int(bounds.m_l) / scale;
+ bounds.m_t = wl_fixed_from_int(bounds.m_t) / scale;
+ bounds.m_r = wl_fixed_from_int(bounds.m_r) / scale;
+ bounds.m_b = wl_fixed_from_int(bounds.m_b) / scale;
+ bounds.clampPoint(UNPACK2(input->pointer.xy));
+ }
+#endif
input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
GHOST_kEventCursorMove,
win,
- input->x,
- input->y,
+ wl_fixed_to_int(scale * input->pointer.xy[0]),
+ wl_fixed_to_int(scale * input->pointer.xy[1]),
GHOST_TABLET_DATA_NONE));
}
+static void relative_pointer_handle_relative_motion(
+ void *data,
+ struct zwp_relative_pointer_v1 * /*zwp_relative_pointer_v1*/,
+ const uint32_t /*utime_hi*/,
+ const uint32_t /*utime_lo*/,
+ const wl_fixed_t dx,
+ const wl_fixed_t dy,
+ const wl_fixed_t /*dx_unaccel*/,
+ const wl_fixed_t /*dy_unaccel*/)
+{
+ input_t *input = static_cast<input_t *>(data);
+ if (wl_surface *focus_surface = input->pointer.wl_surface) {
+ CLOG_INFO(LOG, 2, "relative_motion");
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ const wl_fixed_t scale = win->scale();
+ const wl_fixed_t xy_next[2] = {
+ input->pointer.xy[0] + (dx / scale),
+ input->pointer.xy[1] + (dy / scale),
+ };
+ relative_pointer_handle_relative_motion_impl(input, win, xy_next);
+ }
+ else {
+ CLOG_INFO(LOG, 2, "relative_motion (skipped)");
+ }
+}
+
static const zwp_relative_pointer_v1_listener relative_pointer_listener = {
- relative_pointer_relative_motion,
+ relative_pointer_handle_relative_motion,
};
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Data Source), #wl_data_source_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_DATA_SOURCE = {"ghost.wl.handle.data_source"};
+#define LOG (&LOG_WL_DATA_SOURCE)
+
static void dnd_events(const input_t *const input, const GHOST_TEventType event)
{
- const uint64_t time = input->system->getMilliSeconds();
- GHOST_IWindow *const window = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
- for (const std::string &type : mime_preference_order) {
- input->system->pushEvent(new GHOST_EventDragnDrop(time,
- event,
- mime_dnd.at(type),
- window,
- input->data_offer_dnd->dnd.x,
- input->data_offer_dnd->dnd.y,
- nullptr));
+ /* NOTE: `input->data_offer_dnd_mutex` must already be locked. */
+ if (wl_surface *focus_surface = input->focus_dnd) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ const wl_fixed_t scale = win->scale();
+ const int event_xy[2] = {
+ wl_fixed_to_int(scale * input->data_offer_dnd->dnd.xy[0]),
+ wl_fixed_to_int(scale * input->data_offer_dnd->dnd.xy[1]),
+ };
+
+ const uint64_t time = input->system->getMilliSeconds();
+ for (const std::string &type : mime_preference_order) {
+ input->system->pushEvent(new GHOST_EventDragnDrop(
+ time, event, mime_dnd.at(type), win, UNPACK2(event_xy), nullptr));
+ }
}
}
-static std::string read_pipe(data_offer_t *data_offer, const std::string mime_receive)
+static std::string read_pipe(data_offer_t *data_offer,
+ const std::string mime_receive,
+ std::mutex *mutex)
{
int pipefd[2];
- if (pipe(pipefd) != 0) {
+ if (UNLIKELY(pipe(pipefd) != 0)) {
return {};
}
wl_data_offer_receive(data_offer->id, mime_receive.c_str(), pipefd[1]);
close(pipefd[1]);
+ data_offer->in_use.store(false);
+
+ if (mutex) {
+ mutex->unlock();
+ }
+ /* WARNING: `data_offer` may be freed from now on. */
+
std::string data;
ssize_t len;
char buffer[4096];
@@ -498,7 +969,6 @@ static std::string read_pipe(data_offer_t *data_offer, const std::string mime_re
data.insert(data.end(), buffer, buffer + len);
}
close(pipefd[0]);
- data_offer->in_use.store(false);
return data;
}
@@ -507,29 +977,35 @@ static std::string read_pipe(data_offer_t *data_offer, const std::string mime_re
* A target accepts an offered mime type.
*
* Sent when a target accepts pointer_focus or motion events. If
- * a target does not accept any of the offered types, type is NULL.
+ * a target does not accept any of the offered types, type is nullptr.
*/
-static void data_source_target(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/,
- const char * /*mime_type*/)
+static void data_source_handle_target(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/)
{
- /* pass */
+ CLOG_INFO(LOG, 2, "target");
}
-static void data_source_send(void *data,
- struct wl_data_source * /*wl_data_source*/,
- const char * /*mime_type*/,
- int32_t fd)
+static void data_source_handle_send(void *data,
+ struct wl_data_source * /*wl_data_source*/,
+ const char * /*mime_type*/,
+ const int32_t fd)
{
- const char *const buffer = static_cast<char *>(data);
- if (write(fd, buffer, strlen(buffer) + 1) < 0) {
+ input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_source_mutex};
+
+ CLOG_INFO(LOG, 2, "send");
+
+ const char *const buffer = input->data_source->buffer_out;
+ if (write(fd, buffer, strlen(buffer)) < 0) {
GHOST_PRINT("error writing to clipboard: " << std::strerror(errno) << std::endl);
}
close(fd);
}
-static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
+static void data_source_handle_cancelled(void * /*data*/, struct wl_data_source *wl_data_source)
{
+ CLOG_INFO(LOG, 2, "cancelled");
wl_data_source_destroy(wl_data_source);
}
@@ -540,10 +1016,10 @@ static void data_source_cancelled(void * /*data*/, struct wl_data_source *wl_dat
* indicate acceptance, #wl_data_source.cancelled may still be
* emitted afterwards if the drop destination does not accept any mime type.
*/
-static void data_source_dnd_drop_performed(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/)
+static void data_source_handle_dnd_drop_performed(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/)
{
- /* pass */
+ CLOG_INFO(LOG, 2, "dnd_drop_performed");
}
/**
@@ -553,9 +1029,10 @@ static void data_source_dnd_drop_performed(void * /*data*/,
* source, so the client is now free to destroy this data source
* and free all associated data.
*/
-static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*wl_data_source*/)
+static void data_source_handle_dnd_finished(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/)
{
- /* pass */
+ CLOG_INFO(LOG, 2, "dnd_finished");
}
/**
@@ -565,73 +1042,108 @@ static void data_source_dnd_finished(void * /*data*/, struct wl_data_source * /*
* after matching the source/destination side actions. Only one
* action (or none) will be offered here.
*/
-static void data_source_action(void * /*data*/,
- struct wl_data_source * /*wl_data_source*/,
- uint32_t /*dnd_action*/)
+static void data_source_handle_action(void * /*data*/,
+ struct wl_data_source * /*wl_data_source*/,
+ const uint32_t dnd_action)
{
- /* pass */
+ CLOG_INFO(LOG, 2, "handle_action (dnd_action=%u)", dnd_action);
}
static const struct wl_data_source_listener data_source_listener = {
- data_source_target,
- data_source_send,
- data_source_cancelled,
- data_source_dnd_drop_performed,
- data_source_dnd_finished,
- data_source_action,
+ data_source_handle_target,
+ data_source_handle_send,
+ data_source_handle_cancelled,
+ data_source_handle_dnd_drop_performed,
+ data_source_handle_dnd_finished,
+ data_source_handle_action,
};
-static void data_offer_offer(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- const char *mime_type)
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Data Offer), #wl_data_offer_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_DATA_OFFER = {"ghost.wl.handle.data_offer"};
+#define LOG (&LOG_WL_DATA_OFFER)
+
+static void data_offer_handle_offer(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ const char *mime_type)
{
+ CLOG_INFO(LOG, 2, "offer (mime_type=%s)", mime_type);
static_cast<data_offer_t *>(data)->types.insert(mime_type);
}
-static void data_offer_source_actions(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- uint32_t source_actions)
+static void data_offer_handle_source_actions(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ const uint32_t source_actions)
{
+ CLOG_INFO(LOG, 2, "source_actions (%u)", source_actions);
static_cast<data_offer_t *>(data)->source_actions = source_actions;
}
-static void data_offer_action(void *data,
- struct wl_data_offer * /*wl_data_offer*/,
- uint32_t dnd_action)
+static void data_offer_handle_action(void *data,
+ struct wl_data_offer * /*wl_data_offer*/,
+ const uint32_t dnd_action)
{
+ CLOG_INFO(LOG, 2, "actions (%u)", dnd_action);
static_cast<data_offer_t *>(data)->dnd_action = dnd_action;
}
static const struct wl_data_offer_listener data_offer_listener = {
- data_offer_offer,
- data_offer_source_actions,
- data_offer_action,
+ data_offer_handle_offer,
+ data_offer_handle_source_actions,
+ data_offer_handle_action,
};
-static void data_device_data_offer(void * /*data*/,
- struct wl_data_device * /*wl_data_device*/,
- struct wl_data_offer *id)
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Data Device), #wl_data_device_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_DATA_DEVICE = {"ghost.wl.handle.data_device"};
+#define LOG (&LOG_WL_DATA_DEVICE)
+
+static void data_device_handle_data_offer(void * /*data*/,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
{
+ CLOG_INFO(LOG, 2, "data_offer");
+
data_offer_t *data_offer = new data_offer_t;
data_offer->id = id;
wl_data_offer_add_listener(id, &data_offer_listener, data_offer);
}
-static void data_device_enter(void *data,
- struct wl_data_device * /*wl_data_device*/,
- uint32_t serial,
- struct wl_surface * /*surface*/,
- wl_fixed_t x,
- wl_fixed_t y,
- struct wl_data_offer *id)
+static void data_device_handle_enter(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ const uint32_t serial,
+ struct wl_surface *surface,
+ const wl_fixed_t x,
+ const wl_fixed_t y,
+ struct wl_data_offer *id)
{
+ if (!ghost_wl_surface_own(surface)) {
+ CLOG_INFO(LOG, 2, "enter (skipped)");
+ return;
+ }
+ CLOG_INFO(LOG, 2, "enter");
+
input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+
input->data_offer_dnd = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
data_offer_t *data_offer = input->data_offer_dnd;
data_offer->in_use.store(true);
- data_offer->dnd.x = wl_fixed_to_int(x);
- data_offer->dnd.y = wl_fixed_to_int(y);
+ data_offer->dnd.xy[0] = x;
+ data_offer->dnd.xy[1] = y;
wl_data_offer_set_actions(id,
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
@@ -642,14 +1154,19 @@ static void data_device_enter(void *data,
wl_data_offer_accept(id, serial, type.c_str());
}
+ input->focus_dnd = surface;
dnd_events(input, GHOST_kEventDraggingEntered);
}
-static void data_device_leave(void *data, struct wl_data_device * /*wl_data_device*/)
+static void data_device_handle_leave(void *data, struct wl_data_device * /*wl_data_device*/)
{
input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+
+ CLOG_INFO(LOG, 2, "leave");
dnd_events(input, GHOST_kEventDraggingExited);
+ input->focus_dnd = nullptr;
if (input->data_offer_dnd && !input->data_offer_dnd->in_use.load()) {
wl_data_offer_destroy(input->data_offer_dnd->id);
@@ -658,21 +1175,30 @@ static void data_device_leave(void *data, struct wl_data_device * /*wl_data_devi
}
}
-static void data_device_motion(void *data,
- struct wl_data_device * /*wl_data_device*/,
- uint32_t /*time*/,
- wl_fixed_t x,
- wl_fixed_t y)
+static void data_device_handle_motion(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ const uint32_t /*time*/,
+ const wl_fixed_t x,
+ const wl_fixed_t y)
{
input_t *input = static_cast<input_t *>(data);
- input->data_offer_dnd->dnd.x = wl_fixed_to_int(x);
- input->data_offer_dnd->dnd.y = wl_fixed_to_int(y);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+
+ CLOG_INFO(LOG, 2, "motion");
+
+ input->data_offer_dnd->dnd.xy[0] = x;
+ input->data_offer_dnd->dnd.xy[1] = y;
+
dnd_events(input, GHOST_kEventDraggingUpdated);
}
-static void data_device_drop(void *data, struct wl_data_device * /*wl_data_device*/)
+static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_data_device*/)
{
input_t *input = static_cast<input_t *>(data);
+ std::lock_guard lock{input->data_offer_dnd_mutex};
+
+ CLOG_INFO(LOG, 2, "drop");
+
data_offer_t *data_offer = input->data_offer_dnd;
const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(),
@@ -680,13 +1206,13 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
data_offer->types.begin(),
data_offer->types.end());
- auto read_uris = [](input_t *const input,
- data_offer_t *data_offer,
- const std::string mime_receive) {
- const int x = data_offer->dnd.x;
- const int y = data_offer->dnd.y;
+ auto read_uris_fn = [](input_t *const input,
+ data_offer_t *data_offer,
+ wl_surface *surface,
+ const std::string mime_receive) {
+ const wl_fixed_t xy[2] = {UNPACK2(data_offer->dnd.xy)};
- const std::string data = read_pipe(data_offer, mime_receive);
+ const std::string data = read_pipe(data_offer, mime_receive, nullptr);
wl_data_offer_finish(data_offer->id);
wl_data_offer_destroy(data_offer->id);
@@ -700,6 +1226,7 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
static constexpr const char *file_proto = "file://";
static constexpr const char *crlf = "\r\n";
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(surface);
std::vector<std::string> uris;
size_t pos = 0;
@@ -723,32 +1250,37 @@ static void data_device_drop(void *data, struct wl_data_device * /*wl_data_devic
flist->strings[i] = static_cast<uint8_t *>(malloc((uris[i].size() + 1) * sizeof(uint8_t)));
memcpy(flist->strings[i], uris[i].data(), uris[i].size() + 1);
}
- GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_pointer));
+
+ const wl_fixed_t scale = win->scale();
system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
GHOST_kEventDraggingDropDone,
GHOST_kDragnDropTypeFilenames,
win,
- x,
- y,
+ wl_fixed_to_int(scale * xy[0]),
+ wl_fixed_to_int(scale * xy[1]),
flist));
}
- else if (mime_receive == mime_text_plain || mime_receive == mime_text_utf8) {
+ else if (ELEM(mime_receive, mime_text_plain, mime_text_utf8)) {
/* TODO: enable use of internal functions 'txt_insert_buf' and
* 'text_update_edited' to behave like dropped text was pasted. */
}
wl_display_roundtrip(system->display());
};
- std::thread read_thread(read_uris, input, data_offer, mime_receive);
+ /* Pass in `input->focus_dnd` instead of accessing it from `input` since the leave callback
+ * (#data_device_leave) will clear the value once this function starts. */
+ std::thread read_thread(read_uris_fn, input, data_offer, input->focus_dnd, mime_receive);
read_thread.detach();
}
-static void data_device_selection(void *data,
- struct wl_data_device * /*wl_data_device*/,
- struct wl_data_offer *id)
+static void data_device_handle_selection(void *data,
+ struct wl_data_device * /*wl_data_device*/,
+ struct wl_data_offer *id)
{
input_t *input = static_cast<input_t *>(data);
+
+ std::lock_guard lock{input->data_offer_copy_paste_mutex};
+
data_offer_t *data_offer = input->data_offer_copy_paste;
/* Delete old data offer. */
@@ -759,206 +1291,250 @@ static void data_device_selection(void *data,
}
if (id == nullptr) {
+ CLOG_INFO(LOG, 2, "selection: (skipped)");
return;
}
+ CLOG_INFO(LOG, 2, "selection");
/* Get new data offer. */
data_offer = static_cast<data_offer_t *>(wl_data_offer_get_user_data(id));
input->data_offer_copy_paste = data_offer;
- std::string mime_receive;
- for (const std::string type : {mime_text_utf8, mime_text_plain}) {
- if (data_offer->types.count(type)) {
- mime_receive = type;
- break;
+ auto read_selection_fn = [](input_t *input) {
+ GHOST_SystemWayland *const system = input->system;
+ input->data_offer_copy_paste_mutex.lock();
+
+ data_offer_t *data_offer = input->data_offer_copy_paste;
+ std::string mime_receive;
+ for (const std::string type : {mime_text_utf8, mime_text_plain}) {
+ if (data_offer->types.count(type)) {
+ mime_receive = type;
+ break;
+ }
}
- }
+ const std::string data = read_pipe(
+ data_offer, mime_receive, &input->data_offer_copy_paste_mutex);
- auto read_selection = [](GHOST_SystemWayland *const system,
- data_offer_t *data_offer,
- const std::string mime_receive) {
- const std::string data = read_pipe(data_offer, mime_receive);
- system->setSelection(data);
+ {
+ std::lock_guard lock{system_selection_mutex};
+ system->selection_set(data);
+ }
};
- std::thread read_thread(read_selection, input->system, data_offer, mime_receive);
+ std::thread read_thread(read_selection_fn, input);
read_thread.detach();
}
static const struct wl_data_device_listener data_device_listener = {
- data_device_data_offer,
- data_device_enter,
- data_device_leave,
- data_device_motion,
- data_device_drop,
- data_device_selection,
+ data_device_handle_data_offer,
+ data_device_handle_enter,
+ data_device_handle_leave,
+ data_device_handle_motion,
+ data_device_handle_drop,
+ data_device_handle_selection,
};
-static void cursor_buffer_release(void *data, struct wl_buffer *wl_buffer)
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Buffer), #wl_buffer_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_CURSOR_BUFFER = {"ghost.wl.handle.cursor_buffer"};
+#define LOG (&LOG_WL_CURSOR_BUFFER)
+
+static void cursor_buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
{
- cursor_t *cursor = static_cast<cursor_t *>(data);
+ CLOG_INFO(LOG, 2, "release");
+ cursor_t *cursor = static_cast<cursor_t *>(data);
wl_buffer_destroy(wl_buffer);
- if (wl_buffer == cursor->buffer) {
- /* the mapped buffer was from a custom cursor */
- cursor->buffer = nullptr;
+ if (wl_buffer == cursor->wl_buffer) {
+ /* The mapped buffer was from a custom cursor. */
+ cursor->wl_buffer = nullptr;
}
}
-const struct wl_buffer_listener cursor_buffer_listener = {
- cursor_buffer_release,
+static const struct wl_buffer_listener cursor_buffer_listener = {
+ cursor_buffer_handle_release,
};
-static GHOST_IWindow *get_window(struct wl_surface *surface)
-{
- if (!surface) {
- return nullptr;
- }
+#undef LOG
- for (GHOST_IWindow *win : window_manager->getWindows()) {
- if (surface == static_cast<const GHOST_WindowWayland *>(win)->surface()) {
- return win;
- }
- }
- return nullptr;
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Surface), #wl_surface_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_CURSOR_SURFACE = {"ghost.wl.handle.cursor_surface"};
+#define LOG (&LOG_WL_CURSOR_SURFACE)
-static bool update_cursor_scale(cursor_t &cursor, wl_shm *shm)
+static bool update_cursor_scale(cursor_t &cursor,
+ wl_shm *shm,
+ input_state_pointer_t *input_state,
+ wl_surface *cursor_surface)
{
int scale = 0;
- for (const output_t *output : cursor.outputs) {
- if (output->scale > scale)
+ for (const output_t *output : input_state->outputs) {
+ if (output->scale > scale) {
scale = output->scale;
+ }
}
- if (scale > 0 && cursor.scale != scale) {
- cursor.scale = scale;
- wl_surface_set_buffer_scale(cursor.surface, scale);
- wl_cursor_theme_destroy(cursor.theme);
- cursor.theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
+ if (scale > 0 && input_state->theme_scale != scale) {
+ input_state->theme_scale = scale;
+ if (!cursor.is_custom) {
+ wl_surface_set_buffer_scale(cursor_surface, scale);
+ }
+ wl_cursor_theme_destroy(cursor.wl_theme);
+ cursor.wl_theme = wl_cursor_theme_load(cursor.theme_name.c_str(), scale * cursor.size, shm);
return true;
}
return false;
}
-static void cursor_surface_enter(void *data,
- struct wl_surface * /*wl_surface*/,
- struct wl_output *output)
+static void cursor_surface_handle_enter(void *data,
+ struct wl_surface *wl_surface,
+ struct wl_output *output)
{
- input_t *input = static_cast<input_t *>(data);
- for (const output_t *reg_output : input->system->outputs()) {
- if (reg_output->output == output) {
- input->cursor.outputs.insert(reg_output);
- }
+ if (!ghost_wl_output_own(output)) {
+ CLOG_INFO(LOG, 2, "handle_enter (skipped)");
+ return;
}
- update_cursor_scale(input->cursor, input->system->shm());
+ CLOG_INFO(LOG, 2, "handle_enter");
+
+ input_t *input = static_cast<input_t *>(data);
+ input_state_pointer_t *input_state = input_state_pointer_from_cursor_surface(input, wl_surface);
+ const output_t *reg_output = ghost_wl_output_user_data(output);
+ input_state->outputs.insert(reg_output);
+ update_cursor_scale(input->cursor, input->system->shm(), input_state, wl_surface);
}
-static void cursor_surface_leave(void *data,
- struct wl_surface * /*wl_surface*/,
- struct wl_output *output)
+static void cursor_surface_handle_leave(void *data,
+ struct wl_surface *wl_surface,
+ struct wl_output *output)
{
- input_t *input = static_cast<input_t *>(data);
- for (const output_t *reg_output : input->system->outputs()) {
- if (reg_output->output == output) {
- input->cursor.outputs.erase(reg_output);
- }
+ if (!(output && ghost_wl_output_own(output))) {
+ CLOG_INFO(LOG, 2, "handle_leave (skipped)");
+ return;
}
- update_cursor_scale(input->cursor, input->system->shm());
+ CLOG_INFO(LOG, 2, "handle_leave");
+
+ input_t *input = static_cast<input_t *>(data);
+ input_state_pointer_t *input_state = input_state_pointer_from_cursor_surface(input, wl_surface);
+ const output_t *reg_output = ghost_wl_output_user_data(output);
+ input_state->outputs.erase(reg_output);
+ update_cursor_scale(input->cursor, input->system->shm(), input_state, wl_surface);
}
-struct wl_surface_listener cursor_surface_listener = {
- cursor_surface_enter,
- cursor_surface_leave,
+static const struct wl_surface_listener cursor_surface_listener = {
+ cursor_surface_handle_enter,
+ cursor_surface_handle_leave,
};
-static void pointer_enter(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t serial,
- struct wl_surface *surface,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
-{
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(surface));
+#undef LOG
- if (!win) {
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Pointer), #wl_pointer_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_POINTER = {"ghost.wl.handle.pointer"};
+#define LOG (&LOG_WL_POINTER)
+
+static void pointer_handle_enter(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ const uint32_t serial,
+ struct wl_surface *surface,
+ const wl_fixed_t surface_x,
+ const wl_fixed_t surface_y)
+{
+ if (!ghost_wl_surface_own(surface)) {
+ CLOG_INFO(LOG, 2, "enter (skipped)");
return;
}
+ CLOG_INFO(LOG, 2, "enter");
+
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(surface);
win->activate();
input_t *input = static_cast<input_t *>(data);
- input->pointer_serial = serial;
- input->x = win->scale() * wl_fixed_to_int(surface_x);
- input->y = win->scale() * wl_fixed_to_int(surface_y);
- input->focus_pointer = surface;
+ input->cursor_source_serial = serial;
+ input->pointer.serial = serial;
+ input->pointer.xy[0] = surface_x;
+ input->pointer.xy[1] = surface_y;
+ input->pointer.wl_surface = surface;
win->setCursorShape(win->getCursorShape());
+ const wl_fixed_t scale = win->scale();
input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
GHOST_kEventCursorMove,
- static_cast<GHOST_WindowWayland *>(win),
- input->x,
- input->y,
+ win,
+ wl_fixed_to_int(scale * input->pointer.xy[0]),
+ wl_fixed_to_int(scale * input->pointer.xy[1]),
GHOST_TABLET_DATA_NONE));
}
-static void pointer_leave(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*serial*/,
- struct wl_surface *surface)
+static void pointer_handle_leave(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ const uint32_t /*serial*/,
+ struct wl_surface *surface)
{
- GHOST_IWindow *win = get_window(surface);
-
- if (!win) {
- return;
+ /* First clear the `pointer.wl_surface`, since the window won't exist when closing the window. */
+ static_cast<input_t *>(data)->pointer.wl_surface = nullptr;
+ if (surface && ghost_wl_surface_own(surface)) {
+ CLOG_INFO(LOG, 2, "leave");
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(surface);
+ win->deactivate();
+ }
+ else {
+ CLOG_INFO(LOG, 2, "leave (skipped)");
}
-
- static_cast<input_t *>(data)->focus_pointer = nullptr;
- static_cast<GHOST_WindowWayland *>(win)->deactivate();
}
-static void pointer_motion(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*time*/,
- wl_fixed_t surface_x,
- wl_fixed_t surface_y)
+static void pointer_handle_motion(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ const uint32_t /*time*/,
+ const wl_fixed_t surface_x,
+ const wl_fixed_t surface_y)
{
input_t *input = static_cast<input_t *>(data);
-
- GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(get_window(input->focus_pointer));
-
- if (!win) {
- return;
+ input->pointer.xy[0] = surface_x;
+ input->pointer.xy[1] = surface_y;
+
+ if (wl_surface *focus_surface = input->pointer.wl_surface) {
+ CLOG_INFO(LOG, 2, "motion");
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ const wl_fixed_t scale = win->scale();
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ win,
+ wl_fixed_to_int(scale * input->pointer.xy[0]),
+ wl_fixed_to_int(scale * input->pointer.xy[1]),
+ GHOST_TABLET_DATA_NONE));
+ }
+ else {
+ CLOG_INFO(LOG, 2, "motion (skipped)");
}
-
- input->x = win->scale() * wl_fixed_to_int(surface_x);
- input->y = win->scale() * wl_fixed_to_int(surface_y);
-
- input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
- GHOST_kEventCursorMove,
- win,
- input->x,
- input->y,
- GHOST_TABLET_DATA_NONE));
}
-static void pointer_button(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t serial,
- uint32_t /*time*/,
- uint32_t button,
- uint32_t state)
+static void pointer_handle_button(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ const uint32_t serial,
+ const uint32_t /*time*/,
+ const uint32_t button,
+ const uint32_t state)
{
- input_t *input = static_cast<input_t *>(data);
-
- GHOST_IWindow *win = get_window(input->focus_pointer);
-
- if (!win) {
- return;
- }
+ CLOG_INFO(LOG, 2, "button (button=%u, state=%u)", button, state);
+ input_t *input = static_cast<input_t *>(data);
GHOST_TEventType etype = GHOST_kEventUnknown;
switch (state) {
case WL_POINTER_BUTTON_STATE_RELEASED:
@@ -969,7 +1545,7 @@ static void pointer_button(void *data,
break;
}
- GHOST_TButtonMask ebutton = GHOST_kButtonMaskLeft;
+ GHOST_TButton ebutton = GHOST_kButtonMaskLeft;
switch (button) {
case BTN_LEFT:
ebutton = GHOST_kButtonMaskLeft;
@@ -994,48 +1570,451 @@ static void pointer_button(void *data,
break;
}
- input->data_source->source_serial = serial;
- input->buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
- input->system->pushEvent(new GHOST_EventButton(
- input->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE));
+ input->data_source_serial = serial;
+ input->pointer.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
+
+ if (wl_surface *focus_surface = input->pointer.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ input->system->pushEvent(new GHOST_EventButton(
+ input->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE));
+ }
}
-static void pointer_axis(void *data,
- struct wl_pointer * /*wl_pointer*/,
- uint32_t /*time*/,
- uint32_t axis,
- wl_fixed_t value)
+static void pointer_handle_axis(void *data,
+ struct wl_pointer * /*wl_pointer*/,
+ const uint32_t /*time*/,
+ const uint32_t axis,
+ const wl_fixed_t value)
{
+ CLOG_INFO(LOG, 2, "axis (axis=%u, value=%d)", axis, value);
+
input_t *input = static_cast<input_t *>(data);
+ if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ return;
+ }
- GHOST_IWindow *win = get_window(input->focus_pointer);
+ if (wl_surface *focus_surface = input->pointer.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ input->system->pushEvent(new GHOST_EventWheel(
+ input->system->getMilliSeconds(), win, std::signbit(value) ? +1 : -1));
+ }
+}
- if (!win) {
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+};
+
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Tablet Tool), #zwp_tablet_tool_v2_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_TABLET_TOOL = {"ghost.wl.handle.tablet_tool"};
+#define LOG (&LOG_WL_TABLET_TOOL)
+
+static void tablet_tool_handle_type(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t tool_type)
+{
+ CLOG_INFO(LOG, 2, "type (type=%u)", tool_type);
+
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+
+ tool_input->data.Active = tablet_tool_map_type((enum zwp_tablet_tool_v2_type)tool_type);
+}
+
+static void tablet_tool_handle_hardware_serial(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t /*hardware_serial_hi*/,
+ const uint32_t /*hardware_serial_lo*/)
+{
+ CLOG_INFO(LOG, 2, "hardware_serial");
+}
+
+static void tablet_tool_handle_hardware_id_wacom(
+ void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t /*hardware_id_hi*/,
+ const uint32_t /*hardware_id_lo*/)
+{
+ CLOG_INFO(LOG, 2, "hardware_id_wacom");
+}
+
+static void tablet_tool_handle_capability(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t capability)
+{
+ CLOG_INFO(LOG,
+ 2,
+ "capability (tilt=%d, distance=%d, rotation=%d, slider=%d, wheel=%d)",
+ (capability & ZWP_TABLET_TOOL_V2_CAPABILITY_TILT) != 0,
+ (capability & ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE) != 0,
+ (capability & ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION) != 0,
+ (capability & ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER) != 0,
+ (capability & ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL) != 0);
+}
+
+static void tablet_tool_handle_done(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+ CLOG_INFO(LOG, 2, "done");
+}
+static void tablet_tool_handle_removed(void *data, struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2)
+{
+ CLOG_INFO(LOG, 2, "removed");
+
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+
+ if (tool_input->cursor_surface) {
+ wl_surface_destroy(tool_input->cursor_surface);
+ }
+ input->tablet_tools.erase(zwp_tablet_tool_v2);
+
+ delete tool_input;
+}
+static void tablet_tool_handle_proximity_in(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t serial,
+ struct zwp_tablet_v2 * /*tablet*/,
+ struct wl_surface *surface)
+{
+ if (!ghost_wl_surface_own(surface)) {
+ CLOG_INFO(LOG, 2, "proximity_in (skipped)");
return;
}
+ CLOG_INFO(LOG, 2, "proximity_in");
- if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL) {
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ tool_input->proximity = true;
+
+ input_t *input = tool_input->input;
+ input->cursor_source_serial = serial;
+ input->tablet.wl_surface = surface;
+ input->tablet.serial = serial;
+
+ input->data_source_serial = serial;
+
+ /* Update #GHOST_TabletData. */
+ GHOST_TabletData &td = tool_input->data;
+ /* Reset, to avoid using stale tilt/pressure. */
+ td.Xtilt = 0.0f;
+ td.Ytilt = 0.0f;
+ /* In case pressure isn't supported. */
+ td.Pressure = 1.0f;
+
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(input->tablet.wl_surface);
+
+ win->activate();
+
+ win->setCursorShape(win->getCursorShape());
+}
+static void tablet_tool_handle_proximity_out(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+ CLOG_INFO(LOG, 2, "proximity_out");
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ /* Defer clearing the surface until the frame is handled.
+ * Without this, the frame can not access the surface. */
+ tool_input->proximity = false;
+}
+
+static void tablet_tool_handle_down(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t serial)
+{
+ CLOG_INFO(LOG, 2, "down");
+
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ const GHOST_TButton ebutton = GHOST_kButtonMaskLeft;
+ const GHOST_TEventType etype = GHOST_kEventButtonDown;
+
+ input->data_source_serial = serial;
+ input->tablet.buttons.set(ebutton, true);
+
+ if (wl_surface *focus_surface = input->tablet.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ input->system->pushEvent(new GHOST_EventButton(
+ input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
+ }
+}
+
+static void tablet_tool_handle_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/)
+{
+ CLOG_INFO(LOG, 2, "up");
+
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ const GHOST_TButton ebutton = GHOST_kButtonMaskLeft;
+ const GHOST_TEventType etype = GHOST_kEventButtonUp;
+
+ input->tablet.buttons.set(ebutton, false);
+
+ if (wl_surface *focus_surface = input->tablet.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ input->system->pushEvent(new GHOST_EventButton(
+ input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
+ }
+}
+
+static void tablet_tool_handle_motion(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const wl_fixed_t x,
+ const wl_fixed_t y)
+{
+ CLOG_INFO(LOG, 2, "motion");
+
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+
+ input->tablet.xy[0] = x;
+ input->tablet.xy[1] = y;
+
+ /* NOTE: #tablet_tool_handle_frame generates the event (with updated pressure, tilt... etc). */
+}
+
+static void tablet_tool_handle_pressure(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t pressure)
+{
+ const float pressure_unit = (float)pressure / 65535;
+ CLOG_INFO(LOG, 2, "pressure (%.4f)", pressure_unit);
+
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ GHOST_TabletData &td = tool_input->data;
+ td.Pressure = pressure_unit;
+}
+static void tablet_tool_handle_distance(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t distance)
+{
+ CLOG_INFO(LOG, 2, "distance (distance=%u)", distance);
+}
+
+static void tablet_tool_handle_tilt(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const wl_fixed_t tilt_x,
+ const wl_fixed_t tilt_y)
+{
+ /* Map degrees to `-1.0..1.0`. */
+ const float tilt_unit[2] = {
+ (float)(wl_fixed_to_double(tilt_x) / 90.0),
+ (float)(wl_fixed_to_double(tilt_y) / 90.0),
+ };
+ CLOG_INFO(LOG, 2, "tilt (x=%.4f, y=%.4f)", UNPACK2(tilt_unit));
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ GHOST_TabletData &td = tool_input->data;
+ td.Xtilt = tilt_unit[0];
+ td.Ytilt = tilt_unit[1];
+ CLAMP(td.Xtilt, -1.0f, 1.0f);
+ CLAMP(td.Ytilt, -1.0f, 1.0f);
+}
+
+static void tablet_tool_handle_rotation(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const wl_fixed_t degrees)
+{
+ CLOG_INFO(LOG, 2, "rotation (degrees=%.4f)", wl_fixed_to_double(degrees));
+}
+
+static void tablet_tool_handle_slider(void * /*data*/,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const int32_t position)
+{
+ CLOG_INFO(LOG, 2, "slider (position=%d)", position);
+}
+static void tablet_tool_handle_wheel(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const wl_fixed_t /*degrees*/,
+ const int32_t clicks)
+{
+ if (clicks == 0) {
return;
}
+ CLOG_INFO(LOG, 2, "wheel (clicks=%d)", clicks);
- input->system->pushEvent(
- new GHOST_EventWheel(input->system->getMilliSeconds(), win, std::signbit(value) ? +1 : -1));
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+ if (wl_surface *focus_surface = input->tablet.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ input->system->pushEvent(new GHOST_EventWheel(input->system->getMilliSeconds(), win, clicks));
+ }
}
+static void tablet_tool_handle_button(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t serial,
+ const uint32_t button,
+ const uint32_t state)
+{
+ CLOG_INFO(LOG, 2, "button (button=%u, state=%u)", button, state);
-static const struct wl_pointer_listener pointer_listener = {
- pointer_enter,
- pointer_leave,
- pointer_motion,
- pointer_button,
- pointer_axis,
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+
+ GHOST_TEventType etype = GHOST_kEventUnknown;
+ switch (state) {
+ case WL_POINTER_BUTTON_STATE_RELEASED:
+ etype = GHOST_kEventButtonUp;
+ break;
+ case WL_POINTER_BUTTON_STATE_PRESSED:
+ etype = GHOST_kEventButtonDown;
+ break;
+ }
+
+ GHOST_TButton ebutton = GHOST_kButtonMaskLeft;
+ switch (button) {
+ case BTN_STYLUS:
+ ebutton = GHOST_kButtonMaskRight;
+ break;
+ case BTN_STYLUS2:
+ ebutton = GHOST_kButtonMaskMiddle;
+ break;
+ case BTN_STYLUS3:
+ ebutton = GHOST_kButtonMaskButton4;
+ break;
+ }
+
+ input->data_source_serial = serial;
+ input->tablet.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
+
+ if (wl_surface *focus_surface = input->tablet.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ input->system->pushEvent(new GHOST_EventButton(
+ input->system->getMilliSeconds(), etype, win, ebutton, tool_input->data));
+ }
+}
+static void tablet_tool_handle_frame(void *data,
+ struct zwp_tablet_tool_v2 * /*zwp_tablet_tool_v2*/,
+ const uint32_t /*time*/)
+{
+ CLOG_INFO(LOG, 2, "frame");
+
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(data);
+ input_t *input = tool_input->input;
+
+ /* No need to check the surfaces origin, it's already known to be owned by GHOST. */
+ if (wl_surface *focus_surface = input->tablet.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ const wl_fixed_t scale = win->scale();
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ win,
+ wl_fixed_to_int(scale * input->tablet.xy[0]),
+ wl_fixed_to_int(scale * input->tablet.xy[1]),
+ tool_input->data));
+ if (tool_input->proximity == false) {
+ win->setCursorShape(win->getCursorShape());
+ }
+ }
+
+ if (tool_input->proximity == false) {
+ input->tablet.wl_surface = nullptr;
+ }
+}
+
+static const struct zwp_tablet_tool_v2_listener tablet_tool_listner = {
+ tablet_tool_handle_type,
+ tablet_tool_handle_hardware_serial,
+ tablet_tool_handle_hardware_id_wacom,
+ tablet_tool_handle_capability,
+ tablet_tool_handle_done,
+ tablet_tool_handle_removed,
+ tablet_tool_handle_proximity_in,
+ tablet_tool_handle_proximity_out,
+ tablet_tool_handle_down,
+ tablet_tool_handle_up,
+ tablet_tool_handle_motion,
+ tablet_tool_handle_pressure,
+ tablet_tool_handle_distance,
+ tablet_tool_handle_tilt,
+ tablet_tool_handle_rotation,
+ tablet_tool_handle_slider,
+ tablet_tool_handle_wheel,
+ tablet_tool_handle_button,
+ tablet_tool_handle_frame,
};
-static void keyboard_keymap(
- void *data, struct wl_keyboard * /*wl_keyboard*/, uint32_t format, int32_t fd, uint32_t size)
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Table Seat), #zwp_tablet_seat_v2_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_TABLET_SEAT = {"ghost.wl.handle.tablet_seat"};
+#define LOG (&LOG_WL_TABLET_SEAT)
+
+static void tablet_seat_handle_tablet_added(void * /*data*/,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_v2 *id)
+{
+ CLOG_INFO(LOG, 2, "tablet_added (id=%p)", id);
+}
+
+static void tablet_seat_handle_tool_added(void *data,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_tool_v2 *id)
+{
+ CLOG_INFO(LOG, 2, "tool_added (id=%p)", id);
+
+ input_t *input = static_cast<input_t *>(data);
+ tablet_tool_input_t *tool_input = new tablet_tool_input_t();
+ tool_input->input = input;
+
+ /* Every tool has it's own cursor surface. */
+ tool_input->cursor_surface = wl_compositor_create_surface(input->system->compositor());
+ ghost_wl_surface_tag_cursor_tablet(tool_input->cursor_surface);
+
+ wl_surface_add_listener(tool_input->cursor_surface, &cursor_surface_listener, (void *)input);
+
+ zwp_tablet_tool_v2_add_listener(id, &tablet_tool_listner, tool_input);
+
+ input->tablet_tools.insert(id);
+}
+
+static void tablet_seat_handle_pad_added(void * /*data*/,
+ struct zwp_tablet_seat_v2 * /*zwp_tablet_seat_v2*/,
+ struct zwp_tablet_pad_v2 *id)
+{
+ CLOG_INFO(LOG, 2, "pad_added (id=%p)", id);
+}
+
+static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
+ tablet_seat_handle_tablet_added,
+ tablet_seat_handle_tool_added,
+ tablet_seat_handle_pad_added,
+};
+
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Keyboard), #wl_keyboard_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_KEYBOARD = {"ghost.wl.handle.keyboard"};
+#define LOG (&LOG_WL_KEYBOARD)
+
+static void keyboard_handle_keymap(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ const uint32_t format,
+ const int32_t fd,
+ const uint32_t size)
{
input_t *input = static_cast<input_t *>(data);
if ((!data) || (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)) {
+ CLOG_INFO(LOG, 2, "keymap (no data or wrong version)");
close(fd);
return;
}
@@ -1052,11 +2031,32 @@ static void keyboard_keymap(
close(fd);
if (!keymap) {
+ CLOG_INFO(LOG, 2, "keymap (not found)");
return;
}
+ CLOG_INFO(LOG, 2, "keymap");
+
+ /* In practice we can assume `xkb_state_new` always succeeds. */
+ xkb_state_unref(input->xkb_state);
input->xkb_state = xkb_state_new(keymap);
+ xkb_state_unref(input->xkb_state_empty);
+ input->xkb_state_empty = xkb_state_new(keymap);
+
+ xkb_state_unref(input->xkb_state_empty_with_numlock);
+ input->xkb_state_empty_with_numlock = nullptr;
+
+ {
+ const xkb_mod_index_t mod2 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM);
+ const xkb_mod_index_t num = xkb_keymap_mod_get_index(keymap, "NumLock");
+ if (num != XKB_MOD_INVALID && mod2 != XKB_MOD_INVALID) {
+ input->xkb_state_empty_with_numlock = xkb_state_new(keymap);
+ xkb_state_update_mask(
+ input->xkb_state_empty_with_numlock, (1 << mod2), 0, (1 << num), 0, 0, 0);
+ }
+ }
+
xkb_keymap_unref(keymap);
}
@@ -1066,15 +2066,21 @@ static void keyboard_keymap(
* Notification that this seat's keyboard focus is on a certain
* surface.
*/
-static void keyboard_enter(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- struct wl_surface *surface,
- struct wl_array * /*keys*/)
-{
- if (surface != nullptr) {
- static_cast<input_t *>(data)->focus_keyboard = surface;
+static void keyboard_handle_enter(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ const uint32_t serial,
+ struct wl_surface *surface,
+ struct wl_array * /*keys*/)
+{
+ if (!ghost_wl_surface_own(surface)) {
+ CLOG_INFO(LOG, 2, "enter (skipped)");
+ return;
}
+ CLOG_INFO(LOG, 2, "enter");
+
+ input_t *input = static_cast<input_t *>(data);
+ input->keyboard.serial = serial;
+ input->keyboard.wl_surface = surface;
}
/**
@@ -1083,13 +2089,23 @@ static void keyboard_enter(void *data,
* Notification that this seat's keyboard focus is no longer on a
* certain surface.
*/
-static void keyboard_leave(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- struct wl_surface *surface)
+static void keyboard_handle_leave(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ const uint32_t /*serial*/,
+ struct wl_surface *surface)
{
- if (surface != nullptr) {
- static_cast<input_t *>(data)->focus_keyboard = nullptr;
+ if (!(surface && ghost_wl_surface_own(surface))) {
+ CLOG_INFO(LOG, 2, "leave (skipped)");
+ return;
+ }
+ CLOG_INFO(LOG, 2, "leave");
+
+ input_t *input = static_cast<input_t *>(data);
+ input->keyboard.wl_surface = nullptr;
+
+ /* Losing focus must stop repeating text. */
+ if (input->key_repeat.timer) {
+ keyboard_handle_key_repeat_cancel(input);
}
}
@@ -1097,36 +2113,75 @@ static void keyboard_leave(void *data,
* A version of #xkb_state_key_get_one_sym which returns the key without any modifiers pressed.
* Needed because #GHOST_TKey uses these values as key-codes.
*/
-static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(struct xkb_state *xkb_state,
- xkb_keycode_t key)
+static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(
+ struct xkb_state *xkb_state_empty,
+ struct xkb_state *xkb_state_empty_with_numlock,
+ const xkb_keycode_t key)
{
/* Use an empty keyboard state to access key symbol without modifiers. */
- xkb_state_get_keymap(xkb_state);
- struct xkb_keymap *keymap = xkb_state_get_keymap(xkb_state);
- struct xkb_state *xkb_state_empty = xkb_state_new(keymap);
-
- /* Enable number-lock. */
- {
- const xkb_mod_index_t mod2 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM);
- const xkb_mod_index_t num = xkb_keymap_mod_get_index(keymap, "NumLock");
- if (num != XKB_MOD_INVALID && mod2 != XKB_MOD_INVALID) {
- xkb_state_update_mask(xkb_state_empty, (1 << mod2), 0, (1 << num), 0, 0, 0);
+ xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state_empty, key);
+
+ /* NOTE(@campbellbarton): Only perform the number-locked lookup as a fallback
+ * when a number-pad key has been pressed. This is important as some key-maps use number lock
+ * for switching other layers (in particular `de(neo_qwertz)` turns on layer-4), see: T96170.
+ * Alternative solutions could be to inspect the layout however this could get involved
+ * and turning on the number-lock is only needed for a limited set of keys. */
+
+ /* Accounts for key-pad keys typically swapped for numbers when number-lock is enabled:
+ * `Home Left Up Right Down Prior Page_Up Next Page_Dow End Begin Insert Delete`. */
+ if (xkb_state_empty_with_numlock && (sym >= XKB_KEY_KP_Home && sym <= XKB_KEY_KP_Delete)) {
+ const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(xkb_state_empty_with_numlock, key);
+ if (sym_test != XKB_KEY_NoSymbol) {
+ sym = sym_test;
}
}
- const xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state_empty, key);
- xkb_state_unref(xkb_state_empty);
return sym;
}
-static void keyboard_key(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t serial,
- uint32_t /*time*/,
- uint32_t key,
- uint32_t state)
+static void keyboard_handle_key_repeat_cancel(input_t *input)
+{
+ GHOST_ASSERT(input->key_repeat.timer != nullptr, "Caller much check for timer");
+ delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData());
+ input->system->removeTimer(input->key_repeat.timer);
+ input->key_repeat.timer = nullptr;
+}
+
+/**
+ * Restart the key-repeat timer.
+ * \param use_delay: When false, use the interval
+ * (prevents pause when the setting changes while the key is held).
+ */
+static void keyboard_handle_key_repeat_reset(input_t *input, const bool use_delay)
+{
+ GHOST_ASSERT(input->key_repeat.timer != nullptr, "Caller much check for timer");
+ GHOST_SystemWayland *system = input->system;
+ GHOST_ITimerTask *timer = input->key_repeat.timer;
+ GHOST_TimerProcPtr key_repeat_fn = timer->getTimerProc();
+ GHOST_TUserDataPtr payload = input->key_repeat.timer->getUserData();
+ input->system->removeTimer(input->key_repeat.timer);
+ const uint64_t time_step = 1000 / input->key_repeat.rate;
+ const uint64_t time_start = use_delay ? input->key_repeat.delay : time_step;
+ input->key_repeat.timer = system->installTimer(time_start, time_step, key_repeat_fn, payload);
+}
+
+static void keyboard_handle_key(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ const uint32_t serial,
+ const uint32_t /*time*/,
+ const uint32_t key,
+ const uint32_t state)
{
input_t *input = static_cast<input_t *>(data);
+ const xkb_keycode_t key_code = key + EVDEV_OFFSET;
+
+ const xkb_keysym_t sym = xkb_state_key_get_one_sym_without_modifiers(
+ input->xkb_state_empty, input->xkb_state_empty_with_numlock, key_code);
+ if (sym == XKB_KEY_NoSymbol) {
+ CLOG_INFO(LOG, 2, "key (no symbol, skipped)");
+ return;
+ }
+ CLOG_INFO(LOG, 2, "key");
GHOST_TEventType etype = GHOST_kEventUnknown;
switch (state) {
@@ -1138,168 +2193,369 @@ static void keyboard_key(void *data,
break;
}
- const xkb_keysym_t sym = xkb_state_key_get_one_sym_without_modifiers(input->xkb_state, key + 8);
-
- if (sym == XKB_KEY_NoSymbol) {
- return;
- }
- const GHOST_TKey gkey = xkb_map_gkey(sym);
+ struct key_repeat_payload_t *key_repeat_payload = nullptr;
/* Delete previous timer. */
- if (xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) &&
- input->key_repeat.timer) {
- delete static_cast<key_repeat_payload_t *>(input->key_repeat.timer->getUserData());
- input->system->removeTimer(input->key_repeat.timer);
- input->key_repeat.timer = nullptr;
- }
+ if (input->key_repeat.timer) {
+ enum { NOP = 1, RESET, CANCEL } timer_action = NOP;
+ key_repeat_payload = static_cast<key_repeat_payload_t *>(
+ input->key_repeat.timer->getUserData());
+
+ if (input->key_repeat.rate == 0) {
+ /* Repeat was disabled (unlikely but possible). */
+ timer_action = CANCEL;
+ }
+ else if (key_code == key_repeat_payload->key_code) {
+ /* Releasing the key that was held always cancels. */
+ timer_action = CANCEL;
+ }
+ else if (xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key_code)) {
+ if (etype == GHOST_kEventKeyDown) {
+ /* Any other key-down always cancels (and may start it's own repeat timer). */
+ timer_action = CANCEL;
+ }
+ else {
+ /* Key-up from keys that were not repeating cause the repeat timer to pause.
+ *
+ * NOTE(@campbellbarton): This behavior isn't universal, some text input systems will
+ * stop the repeat entirely. Choose to pause repeat instead as this is what GTK/WIN32 do,
+ * and it fits better for keyboard input that isn't related to text entry. */
+ timer_action = RESET;
+ }
+ }
- GHOST_TEventKeyData key_data;
+ switch (timer_action) {
+ case NOP: {
+ /* Don't add a new timer, leave the existing timer owning this `key_repeat_payload`. */
+ key_repeat_payload = nullptr;
+ break;
+ }
+ case RESET: {
+ /* The payload will be added again. */
+ input->system->removeTimer(input->key_repeat.timer);
+ input->key_repeat.timer = nullptr;
+ break;
+ }
+ case CANCEL: {
+ delete key_repeat_payload;
+ key_repeat_payload = nullptr;
- if (etype == GHOST_kEventKeyDown) {
- xkb_state_key_get_utf8(
- input->xkb_state, key + 8, key_data.utf8_buf, sizeof(GHOST_TEventKeyData::utf8_buf));
- }
- else {
- key_data.utf8_buf[0] = '\0';
+ input->system->removeTimer(input->key_repeat.timer);
+ input->key_repeat.timer = nullptr;
+ break;
+ }
+ }
}
- input->data_source->source_serial = serial;
+ const GHOST_TKey gkey = xkb_map_gkey_or_scan_code(sym, key);
+ char utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'};
+ if (etype == GHOST_kEventKeyDown) {
+ xkb_state_key_get_utf8(input->xkb_state, key_code, utf8_buf, sizeof(utf8_buf));
+ }
- GHOST_IWindow *win = static_cast<GHOST_WindowWayland *>(
- wl_surface_get_user_data(input->focus_keyboard));
- input->system->pushEvent(new GHOST_EventKey(
- input->system->getMilliSeconds(), etype, win, gkey, '\0', key_data.utf8_buf, false));
+ input->data_source_serial = serial;
- /* Start timer for repeating key, if applicable. */
- if (input->key_repeat.rate > 0 &&
- xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key + 8) &&
- etype == GHOST_kEventKeyDown) {
+ if (wl_surface *focus_surface = input->keyboard.wl_surface) {
+ GHOST_IWindow *win = ghost_wl_surface_user_data(focus_surface);
+ input->system->pushEvent(
+ new GHOST_EventKey(input->system->getMilliSeconds(), etype, win, gkey, false, utf8_buf));
+ }
- key_repeat_payload_t *payload = new key_repeat_payload_t({
- .system = input->system,
- .window = win,
- .key = gkey,
- .key_data = key_data,
- });
+ /* An existing payload means the key repeat timer is reset and will be added again. */
+ if (key_repeat_payload == nullptr) {
+ /* Start timer for repeating key, if applicable. */
+ if ((input->key_repeat.rate > 0) && (etype == GHOST_kEventKeyDown) &&
+ xkb_keymap_key_repeats(xkb_state_get_keymap(input->xkb_state), key_code)) {
+ key_repeat_payload = new key_repeat_payload_t({
+ .input = input,
+ .key_code = key_code,
+ .key_data = {.gkey = gkey},
+ });
+ }
+ }
- auto cb = [](GHOST_ITimerTask *task, uint64_t /*time*/) {
+ if (key_repeat_payload) {
+ auto key_repeat_fn = [](GHOST_ITimerTask *task, uint64_t /*time*/) {
struct key_repeat_payload_t *payload = static_cast<key_repeat_payload_t *>(
task->getUserData());
- payload->system->pushEvent(new GHOST_EventKey(payload->system->getMilliSeconds(),
- GHOST_kEventKeyDown,
- payload->window,
- payload->key,
- '\0',
- payload->key_data.utf8_buf,
- true));
+
+ input_t *input = payload->input;
+ if (wl_surface *focus_surface = input->keyboard.wl_surface) {
+ GHOST_IWindow *win = ghost_wl_surface_user_data(focus_surface);
+ GHOST_SystemWayland *system = input->system;
+ /* Calculate this value every time in case modifier keys are pressed. */
+ char utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'};
+ xkb_state_key_get_utf8(input->xkb_state, payload->key_code, utf8_buf, sizeof(utf8_buf));
+ system->pushEvent(new GHOST_EventKey(system->getMilliSeconds(),
+ GHOST_kEventKeyDown,
+ win,
+ payload->key_data.gkey,
+ true,
+ utf8_buf));
+ }
};
input->key_repeat.timer = input->system->installTimer(
- input->key_repeat.delay, 1000 / input->key_repeat.rate, cb, payload);
+ input->key_repeat.delay, 1000 / input->key_repeat.rate, key_repeat_fn, key_repeat_payload);
}
}
-static void keyboard_modifiers(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- uint32_t /*serial*/,
- uint32_t mods_depressed,
- uint32_t mods_latched,
- uint32_t mods_locked,
- uint32_t group)
+static void keyboard_handle_modifiers(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ const uint32_t /*serial*/,
+ const uint32_t mods_depressed,
+ const uint32_t mods_latched,
+ const uint32_t mods_locked,
+ const uint32_t group)
{
- xkb_state_update_mask(static_cast<input_t *>(data)->xkb_state,
- mods_depressed,
- mods_latched,
- mods_locked,
- 0,
- 0,
- group);
+ CLOG_INFO(LOG, 2, "modifiers");
+
+ input_t *input = static_cast<input_t *>(data);
+ xkb_state_update_mask(input->xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group);
+
+ /* A modifier changed so reset the timer,
+ * see comment in #keyboard_handle_key regarding this behavior. */
+ if (input->key_repeat.timer) {
+ keyboard_handle_key_repeat_reset(input, true);
+ }
}
-static void keyboard_repeat_info(void *data,
- struct wl_keyboard * /*wl_keyboard*/,
- int32_t rate,
- int32_t delay)
+static void keyboard_repeat_handle_info(void *data,
+ struct wl_keyboard * /*wl_keyboard*/,
+ const int32_t rate,
+ const int32_t delay)
{
- input_t *input = static_cast<input_t *>(data);
+ CLOG_INFO(LOG, 2, "info (rate=%d, delay=%d)", rate, delay);
+ input_t *input = static_cast<input_t *>(data);
input->key_repeat.rate = rate;
input->key_repeat.delay = delay;
+
+ /* Unlikely possible this setting changes while repeating. */
+ if (input->key_repeat.timer) {
+ keyboard_handle_key_repeat_reset(input, false);
+ }
}
static const struct wl_keyboard_listener keyboard_listener = {
- keyboard_keymap,
- keyboard_enter,
- keyboard_leave,
- keyboard_key,
- keyboard_modifiers,
- keyboard_repeat_info,
+ keyboard_handle_keymap,
+ keyboard_handle_enter,
+ keyboard_handle_leave,
+ keyboard_handle_key,
+ keyboard_handle_modifiers,
+ keyboard_repeat_handle_info,
};
-static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Seat), #wl_seat_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_SEAT = {"ghost.wl.handle.seat"};
+#define LOG (&LOG_WL_SEAT)
+
+static void seat_handle_capabilities(void *data,
+ struct wl_seat *wl_seat,
+ const uint32_t capabilities)
{
+ CLOG_INFO(LOG,
+ 2,
+ "capabilities (pointer=%d, keyboard=%d, touch=%d)",
+ (capabilities & WL_SEAT_CAPABILITY_POINTER) != 0,
+ (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) != 0,
+ (capabilities & WL_SEAT_CAPABILITY_TOUCH) != 0);
+
input_t *input = static_cast<input_t *>(data);
- input->pointer = nullptr;
- input->keyboard = nullptr;
+ input->wl_pointer = nullptr;
+ input->wl_keyboard = nullptr;
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
- input->pointer = wl_seat_get_pointer(wl_seat);
- input->cursor.surface = wl_compositor_create_surface(input->system->compositor());
+ input->wl_pointer = wl_seat_get_pointer(wl_seat);
+ input->cursor.wl_surface = wl_compositor_create_surface(input->system->compositor());
input->cursor.visible = true;
- input->cursor.buffer = nullptr;
- input->cursor.file_buffer = new buffer_t;
+ input->cursor.wl_buffer = nullptr;
if (!get_cursor_settings(input->cursor.theme_name, input->cursor.size)) {
input->cursor.theme_name = std::string();
input->cursor.size = default_cursor_size;
}
- wl_pointer_add_listener(input->pointer, &pointer_listener, data);
- wl_surface_add_listener(input->cursor.surface, &cursor_surface_listener, data);
+ wl_pointer_add_listener(input->wl_pointer, &pointer_listener, data);
+
+ wl_surface_add_listener(input->cursor.wl_surface, &cursor_surface_listener, data);
+ ghost_wl_surface_tag_cursor_pointer(input->cursor.wl_surface);
}
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
- input->keyboard = wl_seat_get_keyboard(wl_seat);
- wl_keyboard_add_listener(input->keyboard, &keyboard_listener, data);
+ input->wl_keyboard = wl_seat_get_keyboard(wl_seat);
+ wl_keyboard_add_listener(input->wl_keyboard, &keyboard_listener, data);
}
}
-static void seat_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
+static void seat_handle_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
{
+ CLOG_INFO(LOG, 2, "name (name=\"%s\")", name);
static_cast<input_t *>(data)->name = std::string(name);
}
static const struct wl_seat_listener seat_listener = {
- seat_capabilities,
- seat_name,
+ seat_handle_capabilities,
+ seat_handle_name,
};
-static void output_geometry(void *data,
- struct wl_output * /*wl_output*/,
- int32_t /*x*/,
- int32_t /*y*/,
- int32_t physical_width,
- int32_t physical_height,
- int32_t /*subpixel*/,
- const char *make,
- const char *model,
- int32_t transform)
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Output), #zxdg_output_v1_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_XDG_OUTPUT = {"ghost.wl.handle.xdg_output"};
+#define LOG (&LOG_WL_XDG_OUTPUT)
+
+static void xdg_output_handle_logical_position(void *data,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ const int32_t x,
+ const int32_t y)
+{
+ CLOG_INFO(LOG, 2, "logical_position [%d, %d]", x, y);
+
+ output_t *output = static_cast<output_t *>(data);
+ output->position_logical[0] = x;
+ output->position_logical[1] = y;
+ output->has_position_logical = true;
+}
+
+static void xdg_output_handle_logical_size(void *data,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ const int32_t width,
+ const int32_t height)
+{
+ CLOG_INFO(LOG, 2, "logical_size [%d, %d]", width, height);
+
+ output_t *output = static_cast<output_t *>(data);
+ if (output->size_logical[0] != 0 && output->size_logical[1] != 0) {
+ /* Original comment from SDL. */
+ /* FIXME(@flibit): GNOME has a bug where the logical size does not account for
+ * scale, resulting in bogus viewport sizes.
+ *
+ * Until this is fixed, validate that _some_ kind of scaling is being
+ * done (we can't match exactly because fractional scaling can't be
+ * detected otherwise), then override if necessary. */
+ if ((output->size_logical[0] == width) && (output->scale_fractional == wl_fixed_from_int(1))) {
+ GHOST_PRINT("xdg_output scale did not match, overriding with wl_output scale");
+
+#ifdef USE_GNOME_CONFINE_HACK
+ /* Use a bug in GNOME to check GNOME is in use. If the bug is fixed this won't cause an issue
+ * as T98793 has been fixed up-stream too, but not in a release at time of writing. */
+ use_gnome_confine_hack = true;
+#endif
+
+ return;
+ }
+ }
+
+ output->size_logical[0] = width;
+ output->size_logical[1] = height;
+ output->has_size_logical = true;
+}
+
+static void xdg_output_handle_done(void *data, struct zxdg_output_v1 * /*xdg_output*/)
{
+ CLOG_INFO(LOG, 2, "done");
+ /* NOTE: `xdg-output.done` events are deprecated and only apply below version 3 of the protocol.
+ * `wl-output.done` event will be emitted in version 3 or higher. */
+ output_t *output = static_cast<output_t *>(data);
+ if (zxdg_output_v1_get_version(output->xdg_output) < 3) {
+ output_handle_done(data, output->wl_output);
+ }
+}
+
+static void xdg_output_handle_name(void * /*data*/,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ const char *name)
+{
+ CLOG_INFO(LOG, 2, "name (name=\"%s\")", name);
+}
+
+static void xdg_output_handle_description(void * /*data*/,
+ struct zxdg_output_v1 * /*xdg_output*/,
+ const char *description)
+{
+ CLOG_INFO(LOG, 2, "description (description=\"%s\")", description);
+}
+
+static const struct zxdg_output_v1_listener xdg_output_listener = {
+ xdg_output_handle_logical_position,
+ xdg_output_handle_logical_size,
+ xdg_output_handle_done,
+ xdg_output_handle_name,
+ xdg_output_handle_description,
+};
+
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Output), #wl_output_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_OUTPUT = {"ghost.wl.handle.output"};
+#define LOG (&LOG_WL_OUTPUT)
+
+static void output_handle_geometry(void *data,
+ struct wl_output * /*wl_output*/,
+ const int32_t /*x*/,
+ const int32_t /*y*/,
+ const int32_t physical_width,
+ const int32_t physical_height,
+ const int32_t /*subpixel*/,
+ const char *make,
+ const char *model,
+ const int32_t transform)
+{
+ CLOG_INFO(LOG,
+ 2,
+ "geometry (make=\"%s\", model=\"%s\", transform=%d, size=[%d, %d])",
+ make,
+ model,
+ transform,
+ physical_width,
+ physical_height);
+
output_t *output = static_cast<output_t *>(data);
output->transform = transform;
output->make = std::string(make);
output->model = std::string(model);
- output->width_mm = physical_width;
- output->height_mm = physical_height;
+ output->size_mm[0] = physical_width;
+ output->size_mm[1] = physical_height;
}
-static void output_mode(void *data,
- struct wl_output * /*wl_output*/,
- uint32_t /*flags*/,
- int32_t width,
- int32_t height,
- int32_t /*refresh*/)
+static void output_handle_mode(void *data,
+ struct wl_output * /*wl_output*/,
+ const uint32_t flags,
+ const int32_t width,
+ const int32_t height,
+ const int32_t /*refresh*/)
{
+ if ((flags & WL_OUTPUT_MODE_CURRENT) == 0) {
+ CLOG_INFO(LOG, 2, "mode (skipped)");
+ return;
+ }
+ CLOG_INFO(LOG, 2, "mode (size=[%d, %d], flags=%u)", width, height, flags);
+
output_t *output = static_cast<output_t *>(data);
- output->width_pxl = width;
- output->height_pxl = height;
+ output->size_native[0] = width;
+ output->size_native[1] = height;
+
+ /* Don't rotate this yet, `wl-output` coordinates are transformed in
+ * handle_done and `xdg-output` coordinates are pre-transformed. */
+ if (!output->has_size_logical) {
+ output->size_logical[0] = width;
+ output->size_logical[1] = height;
+ }
}
/**
@@ -1310,42 +2566,143 @@ static void output_mode(void *data,
* changes done after that. This allows changes to the output
* properties to be seen as atomic, even if they happen via multiple events.
*/
-static void output_done(void * /*data*/, struct wl_output * /*wl_output*/)
+static void output_handle_done(void *data, struct wl_output * /*wl_output*/)
{
+ CLOG_INFO(LOG, 2, "done");
+
+ output_t *output = static_cast<output_t *>(data);
+ int32_t size_native[2];
+ if (output->transform & WL_OUTPUT_TRANSFORM_90) {
+ size_native[0] = output->size_native[1];
+ size_native[1] = output->size_native[0];
+ }
+ else {
+ size_native[0] = output->size_native[0];
+ size_native[1] = output->size_native[1];
+ }
+
+ /* If `xdg-output` is present, calculate the true scale of the desktop */
+ if (output->has_size_logical) {
+
+ /* NOTE: it's not necessary to divide these values by their greatest-common-denominator
+ * as even a 64k screen resolution doesn't approach overflowing an `int32_t`. */
+
+ GHOST_ASSERT(size_native[0] && output->size_logical[0],
+ "Screen size values were not set when they were expected to be.");
+
+ output->scale_fractional = wl_fixed_from_int(size_native[0]) / output->size_logical[0];
+ output->has_scale_fractional = true;
+ }
}
-static void output_scale(void *data, struct wl_output * /*wl_output*/, int32_t factor)
+static void output_handle_scale(void *data, struct wl_output * /*wl_output*/, const int32_t factor)
{
+ CLOG_INFO(LOG, 2, "scale");
static_cast<output_t *>(data)->scale = factor;
+
+ if (window_manager) {
+ for (GHOST_IWindow *iwin : window_manager->getWindows()) {
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin);
+ win->outputs_changed_update_scale();
+ /* TODO(@campbellbarton): support refreshing the UI when the DPI changes.
+ * There are glitches when resizing the monitor which would be nice to solve. */
+ }
+ }
}
static const struct wl_output_listener output_listener = {
- output_geometry,
- output_mode,
- output_done,
- output_scale,
+ output_handle_geometry,
+ output_handle_mode,
+ output_handle_done,
+ output_handle_scale,
};
-static void shell_ping(void * /*data*/, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
+#undef LOG
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG WM Base), #xdg_wm_base_listener
+ * \{ */
+
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR
+
+static CLG_LogRef LOG_WL_XDG_WM_BASE = {"ghost.wl.handle.output"};
+# define LOG (&LOG_WL_XDG_WM_BASE)
+
+static void shell_handle_ping(void * /*data*/,
+ struct xdg_wm_base *xdg_wm_base,
+ const uint32_t serial)
{
+ CLOG_INFO(LOG, 2, "ping");
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener shell_listener = {
- shell_ping,
+ shell_handle_ping,
+};
+
+# undef LOG
+
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (LibDecor), #libdecor_interface
+ * \{ */
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+
+static CLG_LogRef LOG_WL_LIBDECOR = {"ghost.wl.handle.libdecor"};
+# define LOG (&LOG_WL_LIBDECOR)
+
+static void decor_handle_error(struct libdecor * /*context*/,
+ enum libdecor_error error,
+ const char *message)
+{
+ CLOG_INFO(LOG, 2, "error (id=%d, message=%s)", error, message);
+
+ (void)(error);
+ (void)(message);
+ GHOST_PRINT("decoration error (" << error << "): " << message << std::endl);
+ exit(EXIT_FAILURE);
+}
+
+static struct libdecor_interface libdecor_interface = {
+ decor_handle_error,
};
-static void global_add(void *data,
- struct wl_registry *wl_registry,
- uint32_t name,
- const char *interface,
- uint32_t /*version*/)
+# undef LOG
+
+#endif /* WITH_GHOST_WAYLAND_LIBDECOR. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Registry), #wl_registry_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_REGISTRY = {"ghost.wl.handle.registry"};
+#define LOG (&LOG_WL_REGISTRY)
+
+static void global_handle_add(void *data,
+ struct wl_registry *wl_registry,
+ const uint32_t name,
+ const char *interface,
+ const uint32_t version)
{
+ /* Log last since it can be noted if the interface was handled or not. */
+ bool found = true;
+
struct display_t *display = static_cast<struct display_t *>(data);
if (!strcmp(interface, wl_compositor_interface.name)) {
display->compositor = static_cast<wl_compositor *>(
wl_registry_bind(wl_registry, name, &wl_compositor_interface, 3));
}
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ /* Pass. */
+#else
else if (!strcmp(interface, xdg_wm_base_interface.name)) {
display->xdg_shell = static_cast<xdg_wm_base *>(
wl_registry_bind(wl_registry, name, &xdg_wm_base_interface, 1));
@@ -1355,30 +2712,41 @@ static void global_add(void *data,
display->xdg_decoration_manager = static_cast<zxdg_decoration_manager_v1 *>(
wl_registry_bind(wl_registry, name, &zxdg_decoration_manager_v1_interface, 1));
}
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+ else if (!strcmp(interface, zxdg_output_manager_v1_interface.name)) {
+ display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>(
+ wl_registry_bind(wl_registry, name, &zxdg_output_manager_v1_interface, 2));
+ for (output_t *output : display->outputs) {
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
+ output->wl_output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ }
+ }
else if (!strcmp(interface, wl_output_interface.name)) {
output_t *output = new output_t;
- output->scale = 1;
- output->output = static_cast<wl_output *>(
+ output->wl_output = static_cast<wl_output *>(
wl_registry_bind(wl_registry, name, &wl_output_interface, 2));
+ ghost_wl_output_tag(output->wl_output);
+ wl_output_set_user_data(output->wl_output, output);
+
display->outputs.push_back(output);
- wl_output_add_listener(output->output, &output_listener, output);
+ wl_output_add_listener(output->wl_output, &output_listener, output);
+
+ if (display->xdg_output_manager) {
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
+ output->wl_output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ }
}
else if (!strcmp(interface, wl_seat_interface.name)) {
input_t *input = new input_t;
input->system = display->system;
input->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
- input->xkb_state = nullptr;
- input->data_offer_dnd = nullptr;
- input->data_offer_copy_paste = nullptr;
input->data_source = new data_source_t;
- input->data_source->data_source = nullptr;
- input->data_source->buffer_out = nullptr;
- input->relative_pointer = nullptr;
- input->locked_pointer = nullptr;
- input->seat = static_cast<wl_seat *>(
+ input->wl_seat = static_cast<wl_seat *>(
wl_registry_bind(wl_registry, name, &wl_seat_interface, 4));
display->inputs.push_back(input);
- wl_seat_add_listener(input->seat, &seat_listener, input);
+ wl_seat_add_listener(input->wl_seat, &seat_listener, input);
}
else if (!strcmp(interface, wl_shm_interface.name)) {
display->shm = static_cast<wl_shm *>(
@@ -1386,7 +2754,11 @@ static void global_add(void *data,
}
else if (!strcmp(interface, wl_data_device_manager_interface.name)) {
display->data_device_manager = static_cast<wl_data_device_manager *>(
- wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 1));
+ wl_registry_bind(wl_registry, name, &wl_data_device_manager_interface, 3));
+ }
+ else if (!strcmp(interface, zwp_tablet_manager_v2_interface.name)) {
+ display->tablet_manager = static_cast<zwp_tablet_manager_v2 *>(
+ wl_registry_bind(wl_registry, name, &zwp_tablet_manager_v2_interface, 1));
}
else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name)) {
display->relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(
@@ -1396,6 +2768,17 @@ static void global_add(void *data,
display->pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(
wl_registry_bind(wl_registry, name, &zwp_pointer_constraints_v1_interface, 1));
}
+ else {
+ found = false;
+ }
+
+ CLOG_INFO(LOG,
+ 2,
+ "add %s(interface=%s, version=%u, name=%u)",
+ found ? "" : "(skipped), ",
+ interface,
+ version,
+ name);
}
/**
@@ -1407,25 +2790,32 @@ static void global_add(void *data,
* name is no longer available. If the client bound to the global
* using the bind request, the client should now destroy that object.
*/
-static void global_remove(void * /*data*/, struct wl_registry * /*wl_registry*/, uint32_t /*name*/)
+static void global_handle_remove(void * /*data*/,
+ struct wl_registry * /*wl_registry*/,
+ const uint32_t name)
{
+ CLOG_INFO(LOG, 2, "remove (name=%u)", name);
}
static const struct wl_registry_listener registry_listener = {
- global_add,
- global_remove,
+ global_handle_add,
+ global_handle_remove,
};
+#undef LOG
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Ghost Implementation
+/** \name GHOST Implementation
*
- * Wayland specific implementation of the GHOST_System interface.
+ * WAYLAND specific implementation of the #GHOST_System interface.
* \{ */
GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
{
+ wl_log_set_handler_client(ghost_wayland_log_handler);
+
d->system = this;
/* Connect to the Wayland server. */
d->display = wl_display_connect(nullptr);
@@ -1443,19 +2833,35 @@ GHOST_SystemWayland::GHOST_SystemWayland() : GHOST_System(), d(new display_t)
wl_display_roundtrip(d->display);
wl_registry_destroy(registry);
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ d->decor_context = libdecor_new(d->display, &libdecor_interface);
+ if (!d->decor_context) {
+ display_destroy(d);
+ throw std::runtime_error("Wayland: unable to create window decorations!");
+ }
+#else
if (!d->xdg_shell) {
display_destroy(d);
throw std::runtime_error("Wayland: unable to access xdg_shell!");
}
+#endif
/* Register data device per seat for IPC between Wayland clients. */
if (d->data_device_manager) {
for (input_t *input : d->inputs) {
input->data_device = wl_data_device_manager_get_data_device(d->data_device_manager,
- input->seat);
+ input->wl_seat);
wl_data_device_add_listener(input->data_device, &data_device_listener, input);
}
}
+
+ if (d->tablet_manager) {
+ for (input_t *input : d->inputs) {
+ input->tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(d->tablet_manager,
+ input->wl_seat);
+ zwp_tablet_seat_v2_add_listener(input->tablet_seat, &tablet_seat_listener, input);
+ }
+ }
}
GHOST_SystemWayland::~GHOST_SystemWayland()
@@ -1484,42 +2890,52 @@ int GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*actio
GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- if (!d->inputs.empty()) {
- static const xkb_state_component mods_all = xkb_state_component(
- XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED |
- XKB_STATE_MODS_EFFECTIVE);
-
- keys.set(GHOST_kModifierKeyLeftShift,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
- 1);
- keys.set(GHOST_kModifierKeyRightShift,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) ==
- 1);
- keys.set(GHOST_kModifierKeyLeftAlt,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LAlt", mods_all) == 1);
- keys.set(GHOST_kModifierKeyRightAlt,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RAlt", mods_all) == 1);
- keys.set(GHOST_kModifierKeyLeftControl,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "LControl", mods_all) == 1);
- keys.set(GHOST_kModifierKeyRightControl,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "RControl", mods_all) == 1);
- keys.set(GHOST_kModifierKeyOS,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "Super", mods_all) == 1);
- keys.set(GHOST_kModifierKeyNumMasks,
- xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, "NumLock", mods_all) == 1);
-
- return GHOST_kSuccess;
+ if (UNLIKELY(d->inputs.empty())) {
+ return GHOST_kFailure;
}
- return GHOST_kFailure;
+
+ static const xkb_state_component mods_all = xkb_state_component(
+ XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED | XKB_STATE_MODS_LOCKED |
+ XKB_STATE_MODS_EFFECTIVE);
+
+ bool val;
+
+ /* NOTE: XKB doesn't seem to differentiate between left/right modifiers. */
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_SHIFT, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyLeftShift, val);
+ keys.set(GHOST_kModifierKeyRightShift, val);
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_ALT, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyLeftAlt, val);
+ keys.set(GHOST_kModifierKeyRightAlt, val);
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_CTRL, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyLeftControl, val);
+ keys.set(GHOST_kModifierKeyRightControl, val);
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_LOGO, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyOS, val);
+
+ val = xkb_state_mod_name_is_active(d->inputs[0]->xkb_state, XKB_MOD_NAME_NUM, mods_all) == 1;
+ keys.set(GHOST_kModifierKeyNum, val);
+
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
{
- if (!d->inputs.empty()) {
- buttons = d->inputs[0]->buttons;
- return GHOST_kSuccess;
+ if (UNLIKELY(d->inputs.empty())) {
+ return GHOST_kFailure;
}
- return GHOST_kFailure;
+ input_t *input = d->inputs[0];
+ input_state_pointer_t *input_state = input_state_pointer_active(input);
+ if (!input_state) {
+ return GHOST_kFailure;
+ }
+
+ buttons = input_state->buttons;
+ return GHOST_kSuccess;
}
char *GHOST_SystemWayland::getClipboard(bool /*selection*/) const
@@ -1531,28 +2947,33 @@ char *GHOST_SystemWayland::getClipboard(bool /*selection*/) const
void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) const
{
- if (!d->data_device_manager || d->inputs.empty()) {
+ if (UNLIKELY(!d->data_device_manager || d->inputs.empty())) {
return;
}
- data_source_t *data_source = d->inputs[0]->data_source;
+ input_t *input = d->inputs[0];
+
+ std::lock_guard lock{input->data_source_mutex};
+
+ data_source_t *data_source = input->data_source;
/* Copy buffer. */
- data_source->buffer_out = static_cast<char *>(malloc(strlen(buffer) + 1));
- std::strcpy(data_source->buffer_out, buffer);
+ free(data_source->buffer_out);
+ const size_t buffer_size = strlen(buffer) + 1;
+ data_source->buffer_out = static_cast<char *>(malloc(buffer_size));
+ std::memcpy(data_source->buffer_out, buffer, buffer_size);
data_source->data_source = wl_data_device_manager_create_data_source(d->data_device_manager);
- wl_data_source_add_listener(
- data_source->data_source, &data_source_listener, data_source->buffer_out);
+ wl_data_source_add_listener(data_source->data_source, &data_source_listener, input);
for (const std::string &type : mime_send) {
wl_data_source_offer(data_source->data_source, type.c_str());
}
- if (!d->inputs.empty() && d->inputs[0]->data_device) {
+ if (input->data_device) {
wl_data_device_set_selection(
- d->inputs[0]->data_device, data_source->data_source, data_source->source_serial);
+ input->data_device, data_source->data_source, input->data_source_serial);
}
}
@@ -1561,53 +2982,145 @@ uint8_t GHOST_SystemWayland::getNumDisplays() const
return d ? uint8_t(d->outputs.size()) : 0;
}
+static GHOST_TSuccess getCursorPositionClientRelative_impl(
+ const input_state_pointer_t *input_state,
+ const GHOST_WindowWayland *win,
+ int32_t &x,
+ int32_t &y)
+{
+ const wl_fixed_t scale = win->scale();
+ x = wl_fixed_to_int(scale * input_state->xy[0]);
+ y = wl_fixed_to_int(scale * input_state->xy[1]);
+ return GHOST_kSuccess;
+}
+
+static GHOST_TSuccess setCursorPositionClientRelative_impl(input_t *input,
+ GHOST_WindowWayland *win,
+ const int32_t x,
+ const int32_t y)
+{
+ /* NOTE: WAYLAND doesn't support warping the cursor.
+ * However when grab is enabled, we already simulate a cursor location
+ * so that can be set to a new location. */
+ if (!input->relative_pointer) {
+ return GHOST_kFailure;
+ }
+ const wl_fixed_t scale = win->scale();
+ const wl_fixed_t xy_next[2] = {
+ wl_fixed_from_int(x) / scale,
+ wl_fixed_from_int(y) / scale,
+ };
+
+ /* As the cursor was "warped" generate an event at the new location. */
+ relative_pointer_handle_relative_motion_impl(input, win, xy_next);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::getCursorPositionClientRelative(const GHOST_IWindow *window,
+ int32_t &x,
+ int32_t &y) const
+{
+ if (UNLIKELY(d->inputs.empty())) {
+ return GHOST_kFailure;
+ }
+ input_t *input = d->inputs[0];
+ input_state_pointer_t *input_state = input_state_pointer_active(input);
+ if (!input_state || !input_state->wl_surface) {
+ return GHOST_kFailure;
+ }
+ const GHOST_WindowWayland *win = static_cast<const GHOST_WindowWayland *>(window);
+ return getCursorPositionClientRelative_impl(input_state, win, x, y);
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorPositionClientRelative(GHOST_IWindow *window,
+ const int32_t x,
+ const int32_t y)
+{
+ if (UNLIKELY(d->inputs.empty())) {
+ return GHOST_kFailure;
+ }
+ input_t *input = d->inputs[0];
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(window);
+ return setCursorPositionClientRelative_impl(input, win, x, y);
+}
+
GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const
{
- if (!d->inputs.empty() && (d->inputs[0]->focus_pointer != nullptr)) {
- x = d->inputs[0]->x;
- y = d->inputs[0]->y;
- return GHOST_kSuccess;
+ if (UNLIKELY(d->inputs.empty())) {
+ return GHOST_kFailure;
}
- else {
+ input_t *input = d->inputs[0];
+ input_state_pointer_t *input_state = input_state_pointer_active(input);
+ if (!input_state) {
return GHOST_kFailure;
}
+
+ if (wl_surface *focus_surface = input_state->wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ return getCursorPositionClientRelative_impl(input_state, win, x, y);
+ }
+ return GHOST_kFailure;
}
-GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(int32_t /*x*/, int32_t /*y*/)
+GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(const int32_t x, const int32_t y)
{
+ if (UNLIKELY(d->inputs.empty())) {
+ return GHOST_kFailure;
+ }
+ input_t *input = d->inputs[0];
+
+ /* Intentionally different from `getCursorPosition` which supports both tablet & pointer.
+ * In the case of setting the cursor location, tablets don't support this. */
+ if (wl_surface *focus_surface = input->pointer.wl_surface) {
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(focus_surface);
+ return setCursorPositionClientRelative_impl(input, win, x, y);
+ }
return GHOST_kFailure;
}
void GHOST_SystemWayland::getMainDisplayDimensions(uint32_t &width, uint32_t &height) const
{
- if (getNumDisplays() > 0) {
- /* We assume first output as main. */
- width = uint32_t(d->outputs[0]->width_pxl) / d->outputs[0]->scale;
- height = uint32_t(d->outputs[0]->height_pxl) / d->outputs[0]->scale;
+ if (getNumDisplays() == 0) {
+ return;
}
+ /* We assume first output as main. */
+ width = uint32_t(d->outputs[0]->size_native[0]);
+ height = uint32_t(d->outputs[0]->size_native[1]);
}
void GHOST_SystemWayland::getAllDisplayDimensions(uint32_t &width, uint32_t &height) const
{
- getMainDisplayDimensions(width, height);
-}
+ int32_t xy_min[2] = {INT32_MAX, INT32_MAX};
+ int32_t xy_max[2] = {INT32_MIN, INT32_MIN};
-GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
-{
- /* Create new off-screen window. */
- wl_surface *os_surface = wl_compositor_create_surface(compositor());
- wl_egl_window *os_egl_window = wl_egl_window_create(os_surface, int(1), int(1));
+ for (const output_t *output : d->outputs) {
+ int32_t xy[2] = {0, 0};
+ if (output->has_position_logical) {
+ xy[0] = output->position_logical[0];
+ xy[1] = output->position_logical[1];
+ }
+ xy_min[0] = std::min(xy_min[0], xy[0]);
+ xy_min[1] = std::min(xy_min[1], xy[1]);
+ xy_max[0] = std::max(xy_max[0], xy[0] + output->size_native[0]);
+ xy_max[1] = std::max(xy_max[1], xy[1] + output->size_native[1]);
+ }
- d->os_surfaces.push_back(os_surface);
- d->os_egl_windows.push_back(os_egl_window);
+ width = xy_max[0] - xy_min[0];
+ height = xy_max[1] - xy_min[1];
+}
+static GHOST_Context *createOffscreenContext_impl(GHOST_SystemWayland *system,
+ struct wl_display *wl_display,
+ wl_egl_window *egl_window)
+{
GHOST_Context *context;
for (int minor = 6; minor >= 0; --minor) {
- context = new GHOST_ContextEGL(this,
+ context = new GHOST_ContextEGL(system,
false,
- EGLNativeWindowType(os_egl_window),
- EGLNativeDisplayType(d->display),
+ EGLNativeWindowType(egl_window),
+ EGLNativeDisplayType(wl_display),
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
4,
minor,
@@ -1615,16 +3128,16 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*g
GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
EGL_OPENGL_API);
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
- context = new GHOST_ContextEGL(this,
+ context = new GHOST_ContextEGL(system,
false,
- EGLNativeWindowType(os_egl_window),
- EGLNativeDisplayType(d->display),
+ EGLNativeWindowType(egl_window),
+ EGLNativeDisplayType(wl_display),
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
3,
3,
@@ -1635,34 +3148,60 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*g
if (context->initializeDrawingContext()) {
return context;
}
- else {
- delete context;
+ delete context;
+ return nullptr;
+}
+
+GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
+{
+ /* Create new off-screen window. */
+ wl_surface *wl_surface = wl_compositor_create_surface(compositor());
+ wl_egl_window *egl_window = wl_surface ? wl_egl_window_create(wl_surface, 1, 1) : nullptr;
+
+ GHOST_Context *context = createOffscreenContext_impl(this, d->display, egl_window);
+
+ if (!context) {
+ GHOST_PRINT("Cannot create off-screen EGL context" << std::endl);
+ if (wl_surface) {
+ wl_surface_destroy(wl_surface);
+ }
+ if (egl_window) {
+ wl_egl_window_destroy(egl_window);
+ }
+ return nullptr;
}
- GHOST_PRINT("Cannot create off-screen EGL context" << std::endl);
+ wl_surface_set_user_data(wl_surface, egl_window);
+ context->setUserData(wl_surface);
- return nullptr;
+ return context;
}
GHOST_TSuccess GHOST_SystemWayland::disposeContext(GHOST_IContext *context)
{
+ struct wl_surface *wl_surface = (struct wl_surface *)((GHOST_Context *)context)->getUserData();
+ wl_egl_window *egl_window = (wl_egl_window *)wl_surface_get_user_data(wl_surface);
+ wl_egl_window_destroy(egl_window);
+ wl_surface_destroy(wl_surface);
+
delete context;
+
return GHOST_kSuccess;
}
GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
- int32_t left,
- int32_t top,
- uint32_t width,
- uint32_t height,
- GHOST_TWindowState state,
- GHOST_TDrawingContextType type,
- GHOST_GLSettings glSettings,
+ const int32_t left,
+ const int32_t top,
+ const uint32_t width,
+ const uint32_t height,
+ const GHOST_TWindowState state,
+ const GHOST_TDrawingContextType type,
+ const GHOST_GLSettings glSettings,
const bool exclusive,
const bool is_dialog,
const GHOST_IWindow *parentWindow)
{
- /* globally store pointer to window manager */
+ /* Globally store pointer to window manager. */
if (!window_manager) {
window_manager = getWindowManager();
}
@@ -1696,76 +3235,210 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
return window;
}
-wl_display *GHOST_SystemWayland::display()
-{
- return d->display;
-}
-
-wl_compositor *GHOST_SystemWayland::compositor()
+/**
+ * Show the buffer defined by #cursor_buffer_set without changing anything else,
+ * so #cursor_buffer_hide can be used to display it again.
+ *
+ * The caller is responsible for setting `input->cursor.visible`.
+ */
+static void cursor_buffer_show(const input_t *input)
{
- return d->compositor;
-}
+ const cursor_t *c = &input->cursor;
-xdg_wm_base *GHOST_SystemWayland::shell()
-{
- return d->xdg_shell;
-}
+ if (input->wl_pointer) {
+ const int scale = c->is_custom ? c->custom_scale : input->pointer.theme_scale;
+ const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale;
+ const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale;
+ if (input->wl_pointer) {
+ wl_pointer_set_cursor(
+ input->wl_pointer, input->pointer.serial, c->wl_surface, hotspot_x, hotspot_y);
+ }
+ }
-zxdg_decoration_manager_v1 *GHOST_SystemWayland::decoration_manager()
-{
- return d->xdg_decoration_manager;
+ if (!input->tablet_tools.empty()) {
+ const int scale = c->is_custom ? c->custom_scale : input->tablet.theme_scale;
+ const int32_t hotspot_x = int32_t(c->wl_image.hotspot_x) / scale;
+ const int32_t hotspot_y = int32_t(c->wl_image.hotspot_y) / scale;
+ for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) {
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(
+ zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
+ zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
+ input->tablet.serial,
+ tool_input->cursor_surface,
+ hotspot_x,
+ hotspot_y);
+ }
+ }
}
-const std::vector<output_t *> &GHOST_SystemWayland::outputs() const
+/**
+ * Hide the buffer defined by #cursor_buffer_set without changing anything else,
+ * so #cursor_buffer_show can be used to display it again.
+ *
+ * The caller is responsible for setting `input->cursor.visible`.
+ */
+static void cursor_buffer_hide(const input_t *input)
{
- return d->outputs;
+ wl_pointer_set_cursor(input->wl_pointer, input->pointer.serial, nullptr, 0, 0);
+ for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) {
+ zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, input->tablet.serial, nullptr, 0, 0);
+ }
}
-wl_shm *GHOST_SystemWayland::shm() const
+/**
+ * Needed to ensure the cursor size is always a multiple of scale.
+ */
+static int cursor_buffer_compatible_scale_from_image(const struct wl_cursor_image *wl_image,
+ int scale)
{
- return d->shm;
+ const int32_t image_size_x = int32_t(wl_image->width);
+ const int32_t image_size_y = int32_t(wl_image->height);
+ while (scale > 1) {
+ if ((image_size_x % scale) == 0 && (image_size_y % scale) == 0) {
+ break;
+ }
+ scale -= 1;
+ }
+ return scale;
+}
+
+static void cursor_buffer_set_surface_impl(const input_t *input,
+ wl_buffer *buffer,
+ struct wl_surface *wl_surface,
+ const int scale)
+{
+ const wl_cursor_image *wl_image = &input->cursor.wl_image;
+ const int32_t image_size_x = int32_t(wl_image->width);
+ const int32_t image_size_y = int32_t(wl_image->height);
+ GHOST_ASSERT((image_size_x % scale) == 0 && (image_size_y % scale) == 0,
+ "The size must be a multiple of the scale!");
+
+ wl_surface_set_buffer_scale(wl_surface, scale);
+ wl_surface_attach(wl_surface, buffer, 0, 0);
+ wl_surface_damage(wl_surface, 0, 0, image_size_x, image_size_y);
+ wl_surface_commit(wl_surface);
+}
+
+static void cursor_buffer_set(const input_t *input, wl_buffer *buffer)
+{
+ const cursor_t *c = &input->cursor;
+ const wl_cursor_image *wl_image = &input->cursor.wl_image;
+ const bool visible = (c->visible && c->is_hardware);
+
+ /* This is a requirement of WAYLAND, when this isn't the case,
+ * it causes Blender's window to close intermittently. */
+ if (input->wl_pointer) {
+ const int scale = cursor_buffer_compatible_scale_from_image(
+ wl_image, c->is_custom ? c->custom_scale : input->pointer.theme_scale);
+ const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
+ const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
+ cursor_buffer_set_surface_impl(input, buffer, c->wl_surface, scale);
+ wl_pointer_set_cursor(input->wl_pointer,
+ input->pointer.serial,
+ visible ? c->wl_surface : nullptr,
+ hotspot_x,
+ hotspot_y);
+ }
+
+ /* Set the cursor for all tablet tools as well. */
+ if (!input->tablet_tools.empty()) {
+ const int scale = cursor_buffer_compatible_scale_from_image(
+ wl_image, c->is_custom ? c->custom_scale : input->tablet.theme_scale);
+ const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
+ const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
+ for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : input->tablet_tools) {
+ tablet_tool_input_t *tool_input = static_cast<tablet_tool_input_t *>(
+ zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
+ cursor_buffer_set_surface_impl(input, buffer, tool_input->cursor_surface, scale);
+ zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
+ input->tablet.serial,
+ visible ? tool_input->cursor_surface : nullptr,
+ hotspot_x,
+ hotspot_y);
+ }
+ }
}
-void GHOST_SystemWayland::setSelection(const std::string &selection)
-{
- this->selection = selection;
-}
+enum eCursorSetMode {
+ CURSOR_VISIBLE_ALWAYS_SET = 1,
+ CURSOR_VISIBLE_ONLY_HIDE,
+ CURSOR_VISIBLE_ONLY_SHOW,
+};
-static void set_cursor_buffer(input_t *input, wl_buffer *buffer)
+static void cursor_visible_set(input_t *input,
+ const bool visible,
+ const bool is_hardware,
+ const enum eCursorSetMode set_mode)
{
- cursor_t *c = &input->cursor;
-
- c->visible = (buffer != nullptr);
+ cursor_t *cursor = &input->cursor;
+ const bool was_visible = cursor->is_hardware && cursor->visible;
+ const bool use_visible = is_hardware && visible;
- wl_surface_attach(c->surface, buffer, 0, 0);
+ if (set_mode == CURSOR_VISIBLE_ALWAYS_SET) {
+ /* Pass. */
+ }
+ else if ((set_mode == CURSOR_VISIBLE_ONLY_SHOW)) {
+ if (!use_visible) {
+ return;
+ }
+ }
+ else if ((set_mode == CURSOR_VISIBLE_ONLY_HIDE)) {
+ if (use_visible) {
+ return;
+ }
+ }
- wl_surface_damage(c->surface, 0, 0, int32_t(c->image.width), int32_t(c->image.height));
- wl_pointer_set_cursor(input->pointer,
- input->pointer_serial,
- c->visible ? c->surface : nullptr,
- int32_t(c->image.hotspot_x) / c->scale,
- int32_t(c->image.hotspot_y) / c->scale);
+ if (use_visible) {
+ if (!was_visible) {
+ cursor_buffer_show(input);
+ }
+ }
+ else {
+ if (was_visible) {
+ cursor_buffer_hide(input);
+ }
+ }
+ cursor->visible = visible;
+ cursor->is_hardware = is_hardware;
+}
- wl_surface_commit(c->surface);
+static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_software_confine)
+{
+ if (mode == GHOST_kGrabWrap) {
+ return true;
+ }
+#ifdef USE_GNOME_CONFINE_HACK
+ if (mode == GHOST_kGrabNormal) {
+ if (use_software_confine) {
+ return true;
+ }
+ }
+#else
+ (void)use_software_confine;
+#endif
+ return false;
}
-GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
+GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor shape)
{
- if (d->inputs.empty()) {
+ if (UNLIKELY(d->inputs.empty())) {
return GHOST_kFailure;
}
- const std::string cursor_name = cursors.count(shape) ? cursors.at(shape) :
- cursors.at(GHOST_kStandardCursorDefault);
+ auto cursor_find = cursors.find(shape);
+ const char *cursor_name = (cursor_find == cursors.end()) ?
+ cursors.at(GHOST_kStandardCursorDefault) :
+ (*cursor_find).second;
input_t *input = d->inputs[0];
cursor_t *c = &input->cursor;
- if (!c->theme) {
+ if (!c->wl_theme) {
/* The cursor surface hasn't entered an output yet. Initialize theme with scale 1. */
- c->theme = wl_cursor_theme_load(c->theme_name.c_str(), c->size, d->inputs[0]->system->shm());
+ c->wl_theme = wl_cursor_theme_load(
+ c->theme_name.c_str(), c->size, d->inputs[0]->system->shm());
}
- wl_cursor *cursor = wl_cursor_theme_get_cursor(c->theme, cursor_name.c_str());
+ wl_cursor *cursor = wl_cursor_theme_get_cursor(c->wl_theme, cursor_name);
if (!cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
@@ -1778,81 +3451,56 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(GHOST_TStandardCursor shape)
return GHOST_kFailure;
}
- c->buffer = buffer;
- c->image = *image;
+ c->visible = true;
+ c->is_custom = false;
+ c->wl_buffer = buffer;
+ c->wl_image = *image;
- set_cursor_buffer(input, buffer);
+ cursor_buffer_set(input, buffer);
return GHOST_kSuccess;
}
-GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
+GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(const GHOST_TStandardCursor cursorShape)
{
- return GHOST_TSuccess(cursors.count(cursorShape) && !cursors.at(cursorShape).empty());
+ auto cursor_find = cursors.find(cursorShape);
+ if (cursor_find == cursors.end()) {
+ return GHOST_kFailure;
+ }
+ const char *value = (*cursor_find).second;
+ if (*value == '\0') {
+ return GHOST_kFailure;
+ }
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
uint8_t *mask,
- int sizex,
- int sizey,
- int hotX,
- int hotY,
- bool /*canInvertColor*/)
+ const int sizex,
+ const int sizey,
+ const int hotX,
+ const int hotY,
+ const bool /*canInvertColor*/)
{
- if (d->inputs.empty()) {
+ if (UNLIKELY(d->inputs.empty())) {
return GHOST_kFailure;
}
cursor_t *cursor = &d->inputs[0]->cursor;
- static const int32_t stride = sizex * 4; /* ARGB */
- cursor->file_buffer->size = size_t(stride * sizey);
-
-#ifdef HAVE_MEMFD_CREATE
- const int fd = memfd_create("blender-cursor-custom", MFD_CLOEXEC | MFD_ALLOW_SEALING);
- if (fd >= 0) {
- fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
- }
-#else
- char *path = getenv("XDG_RUNTIME_DIR");
- if (!path) {
- errno = ENOENT;
- return GHOST_kFailure;
+ if (cursor->custom_data) {
+ munmap(cursor->custom_data, cursor->custom_data_size);
+ cursor->custom_data = nullptr;
+ cursor->custom_data_size = 0; /* Not needed, but the value is no longer meaningful. */
}
- char *tmpname;
- asprintf(&tmpname, "%s/%s", path, "blender-XXXXXX");
- const int fd = mkostemp(tmpname, O_CLOEXEC);
- if (fd >= 0) {
- unlink(tmpname);
- }
- free(tmpname);
-#endif
-
- if (fd < 0) {
+ const int32_t size_xy[2] = {sizex, sizey};
+ wl_buffer *buffer = ghost_wl_buffer_create_for_image(
+ d->shm, size_xy, WL_SHM_FORMAT_ARGB8888, &cursor->custom_data, &cursor->custom_data_size);
+ if (buffer == nullptr) {
return GHOST_kFailure;
}
- if (posix_fallocate(fd, 0, int32_t(cursor->file_buffer->size)) != 0) {
- return GHOST_kFailure;
- }
-
- cursor->file_buffer->data = mmap(
- nullptr, cursor->file_buffer->size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-
- if (cursor->file_buffer->data == MAP_FAILED) {
- close(fd);
- return GHOST_kFailure;
- }
-
- struct wl_shm_pool *pool = wl_shm_create_pool(d->shm, fd, int32_t(cursor->file_buffer->size));
-
- wl_buffer *buffer = wl_shm_pool_create_buffer(
- pool, 0, sizex, sizey, stride, WL_SHM_FORMAT_ARGB8888);
-
- wl_shm_pool_destroy(pool);
- close(fd);
-
wl_buffer_add_listener(buffer, &cursor_buffer_listener, cursor);
static constexpr uint32_t black = 0xFF000000;
@@ -1863,7 +3511,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
uint32_t *pixel;
for (int y = 0; y < sizey; ++y) {
- pixel = &static_cast<uint32_t *>(cursor->file_buffer->data)[y * sizex];
+ pixel = &static_cast<uint32_t *>(cursor->custom_data)[y * sizex];
for (int x = 0; x < sizex; ++x) {
if ((x % 8) == 0) {
datab = *bitmap++;
@@ -1885,90 +3533,466 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
}
}
- cursor->buffer = buffer;
- cursor->image.width = uint32_t(sizex);
- cursor->image.height = uint32_t(sizey);
- cursor->image.hotspot_x = uint32_t(hotX);
- cursor->image.hotspot_y = uint32_t(hotY);
+ cursor->visible = true;
+ cursor->is_custom = true;
+ cursor->custom_scale = 1; /* TODO: support Hi-DPI custom cursors. */
+ cursor->wl_buffer = buffer;
+ cursor->wl_image.width = uint32_t(sizex);
+ cursor->wl_image.height = uint32_t(sizey);
+ cursor->wl_image.hotspot_x = uint32_t(hotX);
+ cursor->wl_image.hotspot_y = uint32_t(hotY);
- set_cursor_buffer(d->inputs[0], buffer);
+ cursor_buffer_set(d->inputs[0], buffer);
return GHOST_kSuccess;
}
-GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
+GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
{
- if (d->inputs.empty()) {
+ cursor_t *cursor = &d->inputs[0]->cursor;
+ if (cursor->custom_data == nullptr) {
+ return GHOST_kFailure;
+ }
+ if (!cursor->is_custom) {
+ return GHOST_kFailure;
+ }
+
+ bitmap->data_size[0] = cursor->wl_image.width;
+ bitmap->data_size[1] = cursor->wl_image.height;
+
+ bitmap->hot_spot[0] = cursor->wl_image.hotspot_x;
+ bitmap->hot_spot[1] = cursor->wl_image.hotspot_y;
+
+ bitmap->data = (uint8_t *)static_cast<void *>(cursor->custom_data);
+
+ return GHOST_kSuccess;
+}
+
+GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(const bool visible)
+{
+ if (UNLIKELY(d->inputs.empty())) {
return GHOST_kFailure;
}
input_t *input = d->inputs[0];
+ cursor_visible_set(input, visible, input->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
+ return GHOST_kSuccess;
+}
- cursor_t *cursor = &input->cursor;
- if (visible) {
- if (!cursor->visible) {
- set_cursor_buffer(input, cursor->buffer);
- }
+bool GHOST_SystemWayland::supportsCursorWarp()
+{
+ /* WAYLAND doesn't support setting the cursor position directly,
+ * this is an intentional choice, forcing us to use a software cursor in this case. */
+ return false;
+}
+
+bool GHOST_SystemWayland::supportsWindowPosition()
+{
+ /* WAYLAND doesn't support accessing the window position. */
+ return false;
+}
+
+bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode)
+{
+ if (UNLIKELY(d->inputs.empty())) {
+ return false;
}
- else {
- if (cursor->visible) {
- set_cursor_buffer(input, nullptr);
- }
+
+#ifdef USE_GNOME_CONFINE_HACK
+ input_t *input = d->inputs[0];
+ const bool use_software_confine = input->use_pointer_software_confine;
+#else
+ const bool use_software_confine = false;
+#endif
+
+ return cursor_is_software(mode, use_software_confine);
+}
+
+#ifdef USE_GNOME_CONFINE_HACK
+static bool setCursorGrab_use_software_confine(const GHOST_TGrabCursorMode mode,
+ wl_surface *surface)
+{
+# ifndef USE_GNOME_CONFINE_HACK_ALWAYS_ON
+ if (use_gnome_confine_hack == false) {
+ return false;
+ }
+# endif
+ if (mode != GHOST_kGrabNormal) {
+ return false;
+ }
+ const GHOST_WindowWayland *win = ghost_wl_surface_user_data(surface);
+ if (!win) {
+ return false;
}
- return GHOST_kSuccess;
+# ifndef USE_GNOME_CONFINE_HACK_ALWAYS_ON
+ if (win->scale() <= 1) {
+ return false;
+ }
+# endif
+ return true;
+}
+#endif
+
+static input_grab_state_t input_grab_state_from_mode(const GHOST_TGrabCursorMode mode,
+ const bool use_software_confine)
+{
+ /* Initialize all members. */
+ const struct input_grab_state_t grab_state = {
+ /* Warping happens to require software cursor which also hides. */
+ .use_lock = ELEM(mode, GHOST_kGrabWrap, GHOST_kGrabHide) || use_software_confine,
+ .use_confine = (mode == GHOST_kGrabNormal) && (use_software_confine == false),
+ };
+ return grab_state;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public WAYLAND Proxy Ownership API
+ * \{ */
+
+static const char *ghost_wl_output_tag_id = "GHOST-output";
+static const char *ghost_wl_surface_tag_id = "GHOST-window";
+static const char *ghost_wl_surface_cursor_pointer_tag_id = "GHOST-cursor-pointer";
+static const char *ghost_wl_surface_cursor_tablet_tag_id = "GHOST-cursor-tablet";
+
+bool ghost_wl_output_own(const struct wl_output *output)
+{
+ return wl_proxy_get_tag((struct wl_proxy *)output) == &ghost_wl_output_tag_id;
+}
+
+bool ghost_wl_surface_own(const struct wl_surface *surface)
+{
+ return wl_proxy_get_tag((struct wl_proxy *)surface) == &ghost_wl_surface_tag_id;
+}
+
+bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *surface)
+{
+ return wl_proxy_get_tag((struct wl_proxy *)surface) == &ghost_wl_surface_cursor_pointer_tag_id;
+}
+
+bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *surface)
+{
+ return wl_proxy_get_tag((struct wl_proxy *)surface) == &ghost_wl_surface_cursor_tablet_tag_id;
+}
+
+void ghost_wl_output_tag(struct wl_output *output)
+{
+ wl_proxy_set_tag((struct wl_proxy *)output, &ghost_wl_output_tag_id);
+}
+
+void ghost_wl_surface_tag(struct wl_surface *surface)
+{
+ wl_proxy_set_tag((struct wl_proxy *)surface, &ghost_wl_surface_tag_id);
+}
+
+void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *surface)
+{
+ wl_proxy_set_tag((struct wl_proxy *)surface, &ghost_wl_surface_cursor_pointer_tag_id);
+}
+
+void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface)
+{
+ wl_proxy_set_tag((struct wl_proxy *)surface, &ghost_wl_surface_cursor_tablet_tag_id);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public WAYLAND Direct Data Access
+ *
+ * Expose some members via methods.
+ * \{ */
+
+wl_display *GHOST_SystemWayland::display()
+{
+ return d->display;
+}
+
+wl_compositor *GHOST_SystemWayland::compositor()
+{
+ return d->compositor;
}
-GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
- const GHOST_TGrabCursorMode mode_current,
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+
+libdecor *GHOST_SystemWayland::decor_context()
+{
+ return d->decor_context;
+}
+
+#else /* WITH_GHOST_WAYLAND_LIBDECOR */
+
+xdg_wm_base *GHOST_SystemWayland::xdg_shell()
+{
+ return d->xdg_shell;
+}
- wl_surface *surface)
+zxdg_decoration_manager_v1 *GHOST_SystemWayland::xdg_decoration_manager()
{
- /* ignore, if the required protocols are not supported */
- if (!d->relative_pointer_manager || !d->pointer_constraints) {
+ return d->xdg_decoration_manager;
+}
+
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
+
+const std::vector<output_t *> &GHOST_SystemWayland::outputs() const
+{
+ return d->outputs;
+}
+
+wl_shm *GHOST_SystemWayland::shm() const
+{
+ return d->shm;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public WAYLAND Query Access
+ * \{ */
+
+struct output_t *ghost_wl_output_user_data(struct wl_output *wl_output)
+{
+ GHOST_ASSERT(wl_output, "output must not be NULL");
+ GHOST_ASSERT(ghost_wl_output_own(wl_output), "output is not owned by GHOST");
+ output_t *output = static_cast<output_t *>(wl_output_get_user_data(wl_output));
+ return output;
+}
+
+GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *surface)
+{
+ GHOST_ASSERT(surface, "surface must not be NULL");
+ GHOST_ASSERT(ghost_wl_surface_own(surface), "surface is not owned by GHOST");
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(wl_surface_get_user_data(surface));
+ return win;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public WAYLAND Utility Functions
+ *
+ * Functionality only used for the WAYLAND implementation.
+ * \{ */
+
+void GHOST_SystemWayland::selection_set(const std::string &selection)
+{
+ this->selection = selection;
+}
+
+void GHOST_SystemWayland::window_surface_unref(const wl_surface *surface)
+{
+#define SURFACE_CLEAR_PTR(surface_test) \
+ if (surface_test == surface) { \
+ surface_test = nullptr; \
+ } \
+ ((void)0);
+
+ /* Only clear window surfaces (not cursors, off-screen surfaces etc). */
+ for (input_t *input : d->inputs) {
+ SURFACE_CLEAR_PTR(input->pointer.wl_surface);
+ SURFACE_CLEAR_PTR(input->tablet.wl_surface);
+ SURFACE_CLEAR_PTR(input->keyboard.wl_surface);
+ SURFACE_CLEAR_PTR(input->focus_dnd);
+ }
+#undef SURFACE_CLEAR_PTR
+}
+
+bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mode,
+ const GHOST_TGrabCursorMode mode_current,
+ int32_t init_grab_xy[2],
+ const GHOST_Rect *wrap_bounds,
+ const GHOST_TAxisFlag wrap_axis,
+ wl_surface *surface,
+ const int scale)
+{
+ /* Ignore, if the required protocols are not supported. */
+ if (UNLIKELY(!d->relative_pointer_manager || !d->pointer_constraints)) {
return GHOST_kFailure;
}
- if (d->inputs.empty()) {
+ if (UNLIKELY(d->inputs.empty())) {
return GHOST_kFailure;
}
+ /* No change, success. */
+ if (mode == mode_current) {
+ return GHOST_kSuccess;
+ }
input_t *input = d->inputs[0];
- if (mode != GHOST_kGrabDisable) {
- /* TODO(@campbellbarton): Support #GHOST_kGrabWrap,
- * where the cursor moves but is constrained to a region. */
- input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
- d->relative_pointer_manager, input->pointer);
- zwp_relative_pointer_v1_add_listener(
- input->relative_pointer, &relative_pointer_listener, input);
- input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
- d->pointer_constraints,
- surface,
- input->pointer,
- nullptr,
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
-
- if (mode == GHOST_kGrabHide) {
- setCursorVisibility(false);
- }
- }
- else {
+#ifdef USE_GNOME_CONFINE_HACK
+ const bool was_software_confine = input->use_pointer_software_confine;
+ const bool use_software_confine = setCursorGrab_use_software_confine(mode, surface);
+#else
+ const bool was_software_confine = false;
+ const bool use_software_confine = false;
+#endif
+
+ const struct input_grab_state_t grab_state_prev = input_grab_state_from_mode(
+ mode_current, was_software_confine);
+ const struct input_grab_state_t grab_state_next = input_grab_state_from_mode(
+ mode, use_software_confine);
+
+ /* Check for wrap as #supportsCursorWarp isn't supported. */
+ const bool use_visible = !(ELEM(mode, GHOST_kGrabHide, GHOST_kGrabWrap) || use_software_confine);
+ const bool is_hardware_cursor = !cursor_is_software(mode, use_software_confine);
+
+ /* Only hide so the cursor is not made visible before it's location is restored.
+ * This function is called again at the end of this function which only shows. */
+ cursor_visible_set(input, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_HIDE);
+
+ /* Switching from one grab mode to another,
+ * in this case disable the current locks as it makes logic confusing,
+ * postpone changing the cursor to avoid flickering. */
+ if (!grab_state_next.use_lock) {
if (input->relative_pointer) {
zwp_relative_pointer_v1_destroy(input->relative_pointer);
input->relative_pointer = nullptr;
}
if (input->locked_pointer) {
+ /* Request location to restore to. */
+ if (mode_current == GHOST_kGrabWrap) {
+ /* Since this call is initiated by Blender, we can be sure the window wasn't closed
+ * by logic outside this function - as the window was needed to make this call. */
+ int32_t xy_new[2] = {UNPACK2(input->pointer.xy)};
+
+ GHOST_Rect bounds_scale;
+
+ bounds_scale.m_l = wl_fixed_from_int(wrap_bounds->m_l) / scale;
+ bounds_scale.m_t = wl_fixed_from_int(wrap_bounds->m_t) / scale;
+ bounds_scale.m_r = wl_fixed_from_int(wrap_bounds->m_r) / scale;
+ bounds_scale.m_b = wl_fixed_from_int(wrap_bounds->m_b) / scale;
+
+ bounds_scale.wrapPoint(UNPACK2(xy_new), 0, wrap_axis);
+
+ /* Push an event so the new location is registered. */
+ if ((xy_new[0] != input->pointer.xy[0]) || (xy_new[1] != input->pointer.xy[1])) {
+ input->system->pushEvent(new GHOST_EventCursor(input->system->getMilliSeconds(),
+ GHOST_kEventCursorMove,
+ ghost_wl_surface_user_data(surface),
+ wl_fixed_to_int(scale * xy_new[0]),
+ wl_fixed_to_int(scale * xy_new[1]),
+ GHOST_TABLET_DATA_NONE));
+ }
+ input->pointer.xy[0] = xy_new[0];
+ input->pointer.xy[1] = xy_new[1];
+
+ zwp_locked_pointer_v1_set_cursor_position_hint(input->locked_pointer, UNPACK2(xy_new));
+ wl_surface_commit(surface);
+ }
+ else if (mode_current == GHOST_kGrabHide) {
+ if ((init_grab_xy[0] != input->grab_lock_xy[0]) ||
+ (init_grab_xy[1] != input->grab_lock_xy[1])) {
+ const wl_fixed_t xy_next[2] = {
+ wl_fixed_from_int(init_grab_xy[0]) / scale,
+ wl_fixed_from_int(init_grab_xy[1]) / scale,
+ };
+ zwp_locked_pointer_v1_set_cursor_position_hint(input->locked_pointer, UNPACK2(xy_next));
+ wl_surface_commit(surface);
+ }
+ }
+#ifdef USE_GNOME_CONFINE_HACK
+ else if (mode_current == GHOST_kGrabNormal) {
+ if (was_software_confine) {
+ zwp_locked_pointer_v1_set_cursor_position_hint(input->locked_pointer,
+ UNPACK2(input->pointer.xy));
+ wl_surface_commit(surface);
+ }
+ }
+#endif
+
zwp_locked_pointer_v1_destroy(input->locked_pointer);
input->locked_pointer = nullptr;
}
+ }
+
+ if (!grab_state_next.use_confine) {
+ if (input->confined_pointer) {
+ zwp_confined_pointer_v1_destroy(input->confined_pointer);
+ input->confined_pointer = nullptr;
+ }
+ }
- if (mode_current == GHOST_kGrabHide) {
- setCursorVisibility(false);
+ if (mode != GHOST_kGrabDisable) {
+ if (grab_state_next.use_lock) {
+ if (!grab_state_prev.use_lock) {
+ /* TODO(@campbellbarton): As WAYLAND does not support warping the pointer it may not be
+ * possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates.
+ * An alternative could be to draw the cursor in software (and hide the real cursor),
+ * or just accept a locked cursor on WAYLAND. */
+ input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
+ d->relative_pointer_manager, input->wl_pointer);
+ zwp_relative_pointer_v1_add_listener(
+ input->relative_pointer, &relative_pointer_listener, input);
+ input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
+ d->pointer_constraints,
+ surface,
+ input->wl_pointer,
+ nullptr,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ }
+ if (mode == GHOST_kGrabHide) {
+ /* Set the initial position to detect any changes when un-grabbing,
+ * otherwise the unlocked cursor defaults to un-locking in-place. */
+ init_grab_xy[0] = wl_fixed_to_int(scale * input->pointer.xy[0]);
+ init_grab_xy[1] = wl_fixed_to_int(scale * input->pointer.xy[1]);
+ input->grab_lock_xy[0] = init_grab_xy[0];
+ input->grab_lock_xy[1] = init_grab_xy[1];
+ }
+ }
+ else if (grab_state_next.use_confine) {
+ if (!grab_state_prev.use_confine) {
+ input->confined_pointer = zwp_pointer_constraints_v1_confine_pointer(
+ d->pointer_constraints,
+ surface,
+ input->wl_pointer,
+ nullptr,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+ }
}
}
+ /* Only show so the cursor is made visible as the last step. */
+ cursor_visible_set(input, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_SHOW);
+
+#ifdef USE_GNOME_CONFINE_HACK
+ input->use_pointer_software_confine = use_software_confine;
+#endif
+
return GHOST_kSuccess;
}
+#ifdef WITH_GHOST_WAYLAND_DYNLOAD
+bool ghost_wl_dynload_libraries()
+{
+ /* Only report when `libwayland-client` is not found when building without X11,
+ * which will be used as a fallback. */
+# ifdef WITH_GHOST_X11
+ bool verbose = false;
+# else
+ bool verbose = true;
+# endif
+
+ if (wayland_dynload_client_init(verbose) && /* `libwayland-client`. */
+ wayland_dynload_cursor_init(verbose) && /* `libwayland-cursor`. */
+ wayland_dynload_egl_init(verbose) && /* `libwayland-egl`. */
+# ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ wayland_dynload_libdecor_init(verbose) && /* `libdecor-0`. */
+# endif
+ true) {
+ return true;
+ }
+# ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ wayland_dynload_libdecor_exit();
+# endif
+ wayland_dynload_client_exit();
+ wayland_dynload_cursor_exit();
+ wayland_dynload_egl_exit();
+
+ return false;
+}
+#endif /* WITH_GHOST_WAYLAND_DYNLOAD */
+
/** \} */
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 01b47358618..bdf5f2fc273 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -11,9 +11,21 @@
#include "GHOST_System.h"
#include "GHOST_WindowWayland.h"
+#ifdef WITH_GHOST_WAYLAND_DYNLOAD
+# include <wayland_dynload_client.h>
+#endif
#include <wayland-client.h>
-#include <xdg-decoration-client-protocol.h>
-#include <xdg-shell-client-protocol.h>
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+# ifdef WITH_GHOST_WAYLAND_DYNLOAD
+# include <wayland_dynload_libdecor.h>
+# endif
+# include <libdecor.h>
+#else
+/* Generated by `wayland-scanner`. */
+# include <xdg-decoration-unstable-v1-client-protocol.h>
+# include <xdg-shell-client-protocol.h>
+#endif
#include <string>
@@ -21,12 +33,56 @@ class GHOST_WindowWayland;
struct display_t;
+bool ghost_wl_output_own(const struct wl_output *output);
+void ghost_wl_output_tag(struct wl_output *output);
+struct output_t *ghost_wl_output_user_data(struct wl_output *output);
+
+bool ghost_wl_surface_own(const struct wl_surface *surface);
+void ghost_wl_surface_tag(struct wl_surface *surface);
+GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *surface);
+
+bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *surface);
+void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *surface);
+
+bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *surface);
+void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface);
+
+#ifdef WITH_GHOST_WAYLAND_DYNLOAD
+/**
+ * Return true when all required WAYLAND libraries are present,
+ * Performs dynamic loading when `WITH_GHOST_WAYLAND_DYNLOAD` is in use.
+ */
+bool ghost_wl_dynload_libraries();
+#endif
+
struct output_t {
- struct wl_output *output;
- int32_t width_pxl, height_pxl; // dimensions in pixel
- int32_t width_mm, height_mm; // dimensions in millimeter
- int transform;
- int scale;
+ struct wl_output *wl_output = nullptr;
+ struct zxdg_output_v1 *xdg_output = nullptr;
+ /** Dimensions in pixels. */
+ int32_t size_native[2] = {0, 0};
+ /** Dimensions in millimeter. */
+ int32_t size_mm[2] = {0, 0};
+
+ int32_t size_logical[2] = {0, 0};
+ bool has_size_logical = false;
+
+ /** Monitor position in pixels. */
+ int32_t position_logical[2] = {0, 0};
+ bool has_position_logical = false;
+
+ int transform = 0;
+ int scale = 1;
+ /**
+ * The integer `scale` value should be used in almost all cases,
+ * as this is what is used for most API calls.
+ * Only use fractional scaling to calculate the DPI.
+ *
+ * \note Internally an #wl_fixed_t is used to store the scale of the display,
+ * so use the same value here (avoid floating point arithmetic in general).
+ */
+ wl_fixed_t scale_fractional = wl_fixed_from_int(1);
+ bool has_scale_fractional = false;
+
std::string make;
std::string model;
};
@@ -51,8 +107,14 @@ class GHOST_SystemWayland : public GHOST_System {
uint8_t getNumDisplays() const override;
- GHOST_TSuccess getCursorPosition(int32_t &x, int32_t &y) const override;
+ GHOST_TSuccess getCursorPositionClientRelative(const GHOST_IWindow *window,
+ int32_t &x,
+ int32_t &y) const override;
+ GHOST_TSuccess setCursorPositionClientRelative(GHOST_IWindow *window,
+ int32_t x,
+ int32_t y) override;
+ GHOST_TSuccess getCursorPosition(int32_t &x, int32_t &y) const override;
GHOST_TSuccess setCursorPosition(int32_t x, int32_t y) override;
void getMainDisplayDimensions(uint32_t &width, uint32_t &height) const override;
@@ -75,20 +137,6 @@ class GHOST_SystemWayland : public GHOST_System {
const bool is_dialog,
const GHOST_IWindow *parentWindow) override;
- wl_display *display();
-
- wl_compositor *compositor();
-
- xdg_wm_base *shell();
-
- zxdg_decoration_manager_v1 *decoration_manager();
-
- const std::vector<output_t *> &outputs() const;
-
- wl_shm *shm() const;
-
- void setSelection(const std::string &selection);
-
GHOST_TSuccess setCursorShape(GHOST_TStandardCursor shape);
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape);
@@ -101,11 +149,46 @@ class GHOST_SystemWayland : public GHOST_System {
int hotY,
bool canInvertColor);
+ GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap);
+
GHOST_TSuccess setCursorVisibility(bool visible);
- GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode,
- const GHOST_TGrabCursorMode mode_current,
- wl_surface *surface);
+ bool supportsCursorWarp();
+ bool supportsWindowPosition();
+
+ bool getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode);
+
+ /* WAYLAND direct-data access. */
+
+ wl_display *display();
+
+ wl_compositor *compositor();
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor *decor_context();
+#else
+ xdg_wm_base *xdg_shell();
+ zxdg_decoration_manager_v1 *xdg_decoration_manager();
+#endif
+
+ const std::vector<output_t *> &outputs() const;
+
+ wl_shm *shm() const;
+
+ /* WAYLAND utility functions. */
+
+ void selection_set(const std::string &selection);
+
+ /** Clear all references to this surface to prevent accessing NULL pointers. */
+ void window_surface_unref(const wl_surface *surface);
+
+ bool window_cursor_grab_set(const GHOST_TGrabCursorMode mode,
+ const GHOST_TGrabCursorMode mode_current,
+ int32_t init_grab_xy[2],
+ const GHOST_Rect *wrap_bounds,
+ GHOST_TAxisFlag wrap_axis,
+ wl_surface *surface,
+ int scale);
private:
struct display_t *d;
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 8e07bf4ea3d..5a930209376 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -580,7 +580,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw,
// extra handling of modifier keys: don't send repeats out from GHOST
if (key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt) {
bool changed = false;
- GHOST_TModifierKeyMask modifier;
+ GHOST_TModifierKey modifier;
switch (key) {
case GHOST_kKeyLeftShift: {
changed = (modifiers.get(GHOST_kModifierKeyLeftShift) != *r_keyDown);
@@ -864,7 +864,7 @@ GHOST_TKey GHOST_SystemWin32::convertKey(short vKey, short scanCode, short exten
GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
GHOST_WindowWin32 *window,
- GHOST_TButtonMask mask)
+ GHOST_TButton mask)
{
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
@@ -1256,9 +1256,8 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
keyDown ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
window,
key,
- ascii,
- utf8_char,
- is_repeat);
+ is_repeat,
+ utf8_char);
// GHOST_PRINTF("%c\n", ascii); // we already get this info via EventPrinter
}
@@ -2211,31 +2210,28 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const
void GHOST_SystemWin32::putClipboard(const char *buffer, bool selection) const
{
- if (selection) {
+ if (selection || !buffer) {
return;
} // for copying the selection, used on X11
if (OpenClipboard(NULL)) {
- HLOCAL clipbuffer;
- wchar_t *data;
+ EmptyClipboard();
- if (buffer) {
- size_t len = count_utf_16_from_8(buffer);
- EmptyClipboard();
+ // Get length of buffer including the terminating null
+ size_t len = count_utf_16_from_8(buffer);
- clipbuffer = LocalAlloc(LMEM_FIXED, sizeof(wchar_t) * len);
- data = (wchar_t *)GlobalLock(clipbuffer);
+ HGLOBAL clipbuffer = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * len);
+ if (clipbuffer) {
+ wchar_t *data = (wchar_t *)GlobalLock(clipbuffer);
conv_utf_8_to_16(buffer, data, len);
- LocalUnlock(clipbuffer);
+ GlobalUnlock(clipbuffer);
SetClipboardData(CF_UNICODETEXT, clipbuffer);
}
+
CloseClipboard();
}
- else {
- return;
- }
}
/* -------------------------------------------------------------------- */
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 689b78b0317..b40f5e3fd75 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -310,7 +310,7 @@ class GHOST_SystemWin32 : public GHOST_System {
*/
static GHOST_EventButton *processButtonEvent(GHOST_TEventType type,
GHOST_WindowWin32 *window,
- GHOST_TButtonMask mask);
+ GHOST_TButton mask);
/**
* Creates tablet events from Wintab events.
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 54d38e1c0f3..00cc5f3af8f 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -25,6 +25,7 @@
#ifdef WITH_INPUT_NDOF
# include "GHOST_NDOFManagerUnix.h"
#endif
+#include "GHOST_utildefines.h"
#ifdef WITH_XDND
# include "GHOST_DropTargetX11.h"
@@ -58,9 +59,9 @@
#include <sys/time.h>
#include <unistd.h>
+#include <cstdio> /* for fprintf only */
#include <cstdlib> /* for exit */
#include <iostream>
-#include <stdio.h> /* for fprintf only */
#include <vector>
/* For debugging, so we can break-point X11 errors. */
@@ -89,8 +90,8 @@ static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key,
const KeyCode keycode);
/* these are for copy and select copy */
-static char *txt_cut_buffer = NULL;
-static char *txt_select_buffer = NULL;
+static char *txt_cut_buffer = nullptr;
+static char *txt_select_buffer = nullptr;
#ifdef WITH_XWAYLAND_HACK
static bool use_xwayland_hack = false;
@@ -98,10 +99,10 @@ static bool use_xwayland_hack = false;
using namespace std;
-GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_time(0)
+GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(nullptr), m_start_time(0)
{
XInitThreads();
- m_display = XOpenDisplay(NULL);
+ m_display = XOpenDisplay(nullptr);
if (!m_display) {
std::cerr << "Unable to open a display" << std::endl;
@@ -117,7 +118,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
/* NOTE: Don't open connection to XIM server here, because the locale has to be
* set before opening the connection but `setlocale()` has not been called yet.
* the connection will be opened after entering the event loop. */
- m_xim = NULL;
+ m_xim = nullptr;
#endif
#define GHOST_INTERN_ATOM_IF_EXISTS(atom) \
@@ -165,7 +166,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
/* compute the initial time */
timeval tv;
- if (gettimeofday(&tv, NULL) == -1) {
+ if (gettimeofday(&tv, nullptr) == -1) {
GHOST_ASSERT(false, "Could not instantiate timer!");
}
@@ -180,7 +181,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
use_xkb = XkbQueryExtension(
m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
if (use_xkb) {
- XkbSetDetectableAutoRepeat(m_display, true, NULL);
+ XkbSetDetectableAutoRepeat(m_display, true, nullptr);
m_xkb_descr = XkbGetMap(m_display, 0, XkbUseCoreKbd);
if (m_xkb_descr) {
@@ -190,7 +191,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
}
#ifdef WITH_XWAYLAND_HACK
- use_xwayland_hack = getenv("WAYLAND_DISPLAY") != NULL;
+ use_xwayland_hack = getenv("WAYLAND_DISPLAY") != nullptr;
#endif
#ifdef WITH_X11_XINPUT
@@ -266,7 +267,7 @@ GHOST_TSuccess GHOST_SystemX11::init()
uint64_t GHOST_SystemX11::getMilliSeconds() const
{
timeval tv;
- if (gettimeofday(&tv, NULL) == -1) {
+ if (gettimeofday(&tv, nullptr) == -1) {
GHOST_ASSERT(false, "Could not compute time!");
}
@@ -334,10 +335,11 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
const bool is_dialog,
const GHOST_IWindow *parentWindow)
{
- GHOST_WindowX11 *window = NULL;
+ GHOST_WindowX11 *window = nullptr;
- if (!m_display)
- return 0;
+ if (!m_display) {
+ return nullptr;
+ }
window = new GHOST_WindowX11(this,
m_display,
@@ -367,7 +369,7 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
}
else {
delete window;
- window = NULL;
+ window = nullptr;
}
}
return window;
@@ -395,7 +397,7 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
#if defined(WITH_GL_PROFILE_CORE)
{
const char *version_major = (char *)glewGetString(GLEW_VERSION_MAJOR);
- if (version_major != NULL && version_major[0] == '1') {
+ if (version_major != nullptr && version_major[0] == '1') {
fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
abort();
}
@@ -438,9 +440,9 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
EGL_OPENGL_API);
#else
context = new GHOST_ContextGLX(false,
- (Window)NULL,
+ (Window) nullptr,
m_display,
- (GLXFBConfig)NULL,
+ (GLXFBConfig) nullptr,
profile_mask,
4,
minor,
@@ -449,10 +451,10 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
#if defined(WITH_GL_EGL)
@@ -469,9 +471,9 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
EGL_OPENGL_API);
#else
context = new GHOST_ContextGLX(false,
- (Window)NULL,
+ (Window) nullptr,
m_display,
- (GLXFBConfig)NULL,
+ (GLXFBConfig) nullptr,
profile_mask,
3,
3,
@@ -480,12 +482,12 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
- return NULL;
+ return nullptr;
}
/**
@@ -505,8 +507,9 @@ static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
{
GHOST_PRINT("XIM server died\n");
- if (ptr)
- *(XIM *)ptr = NULL;
+ if (ptr) {
+ *(XIM *)ptr = nullptr;
+ }
}
bool GHOST_SystemX11::openX11_IM()
@@ -517,14 +520,15 @@ bool GHOST_SystemX11::openX11_IM()
/* set locale modifiers such as `@im=ibus` specified by XMODIFIERS. */
XSetLocaleModifiers("");
- m_xim = XOpenIM(m_display, NULL, (char *)GHOST_X11_RES_NAME, (char *)GHOST_X11_RES_CLASS);
- if (!m_xim)
+ m_xim = XOpenIM(m_display, nullptr, (char *)GHOST_X11_RES_NAME, (char *)GHOST_X11_RES_CLASS);
+ if (!m_xim) {
return false;
+ }
XIMCallback destroy;
destroy.callback = (XIMProc)destroyIMCallback;
destroy.client_data = (XPointer)&m_xim;
- XSetIMValues(m_xim, XNDestroyCallback, &destroy, NULL);
+ XSetIMValues(m_xim, XNDestroyCallback, &destroy, nullptr);
return true;
}
#endif
@@ -532,8 +536,9 @@ bool GHOST_SystemX11::openX11_IM()
GHOST_WindowX11 *GHOST_SystemX11::findGhostWindow(Window xwind) const
{
- if (xwind == 0)
- return NULL;
+ if (xwind == 0) {
+ return nullptr;
+ }
/* It is not entirely safe to do this as the backptr may point
* to a window that has recently been removed.
@@ -551,7 +556,7 @@ GHOST_WindowX11 *GHOST_SystemX11::findGhostWindow(Window xwind) const
return window;
}
}
- return NULL;
+ return nullptr;
}
static void SleepTillEvent(Display *display, int64_t maxSleep)
@@ -563,7 +568,7 @@ static void SleepTillEvent(Display *display, int64_t maxSleep)
FD_SET(fd, &fds);
if (maxSleep == -1) {
- select(fd + 1, &fds, NULL, NULL, NULL);
+ select(fd + 1, &fds, nullptr, nullptr, nullptr);
}
else {
timeval tv;
@@ -571,7 +576,7 @@ static void SleepTillEvent(Display *display, int64_t maxSleep)
tv.tv_sec = maxSleep / 1000;
tv.tv_usec = (maxSleep - tv.tv_sec * 1000) * 1000;
- select(fd + 1, &fds, NULL, NULL, &tv);
+ select(fd + 1, &fds, nullptr, nullptr, &tv);
}
}
@@ -639,10 +644,11 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
SleepTillEvent(m_display, -1);
}
else {
- int64_t maxSleep = next - getMilliSeconds();
+ const int64_t maxSleep = next - getMilliSeconds();
- if (maxSleep >= 0)
+ if (maxSleep >= 0) {
SleepTillEvent(m_display, next - getMilliSeconds());
+ }
}
}
@@ -658,7 +664,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
/* open connection to XIM server and create input context (XIC)
* when receiving the first FocusIn or KeyPress event after startup,
* or recover XIM and XIC when the XIM server has been restarted */
- if (xevent.type == FocusIn || xevent.type == KeyPress) {
+ if (ELEM(xevent.type, FocusIn, KeyPress)) {
if (!m_xim && openX11_IM()) {
GHOST_PRINT("Connected to XIM server\n");
}
@@ -677,7 +683,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
}
/* dispatch event to XIM server */
- if ((XFilterEvent(&xevent, (Window)NULL) == True)) {
+ if ((XFilterEvent(&xevent, (Window) nullptr) == True)) {
/* do nothing now, the event is consumed by XIM. */
continue;
}
@@ -690,8 +696,9 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
}
else if (xevent.type == KeyPress) {
if ((xevent.xkey.keycode == m_last_release_keycode) &&
- ((xevent.xkey.time <= m_last_release_time)))
+ ((xevent.xkey.time <= m_last_release_time))) {
continue;
+ }
}
processEvent(&xevent);
@@ -718,9 +725,9 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
* in order to confirm the window is active. */
XPeekEvent(m_display, &xev_next);
- if (xev_next.type == KeyPress || xev_next.type == KeyRelease) {
- /* XK_Hyper_L/R currently unused */
- const static KeySym modifiers[8] = {
+ if (ELEM(xev_next.type, KeyPress, KeyRelease)) {
+ /* XK_Hyper_L/R currently unused. */
+ const static KeySym modifiers[] = {
XK_Shift_L,
XK_Shift_R,
XK_Control_L,
@@ -731,16 +738,15 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
XK_Super_R,
};
- for (int i = 0; i < (sizeof(modifiers) / sizeof(*modifiers)); i++) {
+ for (int i = 0; i < (int)ARRAY_SIZE(modifiers); i++) {
KeyCode kc = XKeysymToKeycode(m_display, modifiers[i]);
if (kc != 0 && ((xevent.xkeymap.key_vector[kc >> 3] >> (kc & 7)) & 1) != 0) {
pushEvent(new GHOST_EventKey(getMilliSeconds(),
GHOST_kEventKeyDown,
window,
ghost_key_from_keysym(modifiers[i]),
- '\0',
- NULL,
- false));
+ false,
+ nullptr));
}
}
}
@@ -773,7 +779,7 @@ static bool checkTabletProximity(Display *display, XDevice *device)
/* see: state.c from xinput, to get more data out of the device */
XDeviceState *state;
- if (device == NULL) {
+ if (device == nullptr) {
return false;
}
@@ -812,17 +818,17 @@ static bool checkTabletProximity(Display *display, XDevice *device)
void GHOST_SystemX11::processEvent(XEvent *xe)
{
GHOST_WindowX11 *window = findGhostWindow(xe->xany.window);
- GHOST_Event *g_event = NULL;
+ GHOST_Event *g_event = nullptr;
/* Detect auto-repeat. */
bool is_repeat = false;
- if (xe->type == KeyPress || xe->type == KeyRelease) {
+ if (ELEM(xe->type, KeyPress, KeyRelease)) {
XKeyEvent *xke = &(xe->xkey);
/* Set to true if this key will repeat. */
bool is_repeat_keycode = false;
- if (m_xkb_descr != NULL) {
+ if (m_xkb_descr != nullptr) {
/* Use XKB support. */
is_repeat_keycode = (
/* Should always be true, check just in case. */
@@ -883,9 +889,11 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
if (xe->type == xi_presence) {
XDevicePresenceNotifyEvent *notify_event = (XDevicePresenceNotifyEvent *)xe;
- if ((notify_event->devchange == DeviceEnabled) ||
- (notify_event->devchange == DeviceDisabled) ||
- (notify_event->devchange == DeviceAdded) || (notify_event->devchange == DeviceRemoved)) {
+ if (ELEM(notify_event->devchange,
+ DeviceEnabled,
+ DeviceDisabled,
+ DeviceAdded,
+ DeviceRemoved)) {
refreshXInputDevices();
/* update all window events */
@@ -954,8 +962,9 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
GHOST_Rect bounds;
/* fallback to window bounds */
- if (window->getCursorGrabBounds(bounds) == GHOST_kFailure)
+ if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
window->getClientBounds(bounds);
+ }
/* Could also clamp to screen bounds wrap with a window outside the view will
* fail at the moment. Use offset of 8 in case the window is at screen bounds. */
@@ -1007,7 +1016,9 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case KeyRelease: {
XKeyEvent *xke = &(xe->xkey);
KeySym key_sym;
+ char *utf8_buf = nullptr;
char ascii;
+
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
/* utf8_array[] is initial buffer used for Xutf8LookupString().
* if the length of the utf8 string exceeds this array, allocate
@@ -1016,12 +1027,10 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
* at the end of this buffer when the constructor of GHOST_EventKey
* reads 6 bytes regardless of the effective data length. */
char utf8_array[16 * 6 + 5]; /* 16 utf8 characters */
- char *utf8_buf = utf8_array;
- int len = 1; /* at least one null character will be stored */
+ int len = 1; /* at least one null character will be stored */
#else
- char *utf8_buf = NULL;
+ char utf8_array[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'};
#endif
-
GHOST_TEventType type = (xke->type == KeyPress) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
GHOST_TKey gkey;
@@ -1065,7 +1074,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
key_sym = XLookupKeysym(xke, 0);
}
- if (!XLookupString(xke, &ascii, 1, &key_sym_str, NULL)) {
+ if (!XLookupString(xke, &ascii, 1, &key_sym_str, nullptr)) {
ascii = '\0';
}
@@ -1135,87 +1144,100 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
gkey = ghost_key_from_keysym_or_keycode(key_sym, m_xkb_descr, xke->keycode);
- if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
+ if (!XLookupString(xke, &ascii, 1, nullptr, nullptr)) {
ascii = '\0';
}
#endif
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
- /* Setting unicode on key-up events gives #XLookupNone status. */
- XIC xic = window->getX11_XIC();
- if (xic && xke->type == KeyPress) {
- Status status;
+ /* Only used for key-press. */
+ XIC xic = nullptr;
+#endif
- /* Use utf8 because its not locale repentant, from XORG docs. */
- if (!(len = Xutf8LookupString(
- xic, xke, utf8_buf, sizeof(utf8_array) - 5, &key_sym, &status))) {
- utf8_buf[0] = '\0';
- }
+ if (xke->type == KeyPress) {
+ utf8_buf = utf8_array;
+#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
+ /* Setting unicode on key-up events gives #XLookupNone status. */
+ xic = window->getX11_XIC();
+ if (xic) {
+ Status status;
+
+ /* Use utf8 because its not locale repentant, from XORG docs. */
+ if (!(len = Xutf8LookupString(
+ xic, xke, utf8_buf, sizeof(utf8_array) - 5, &key_sym, &status))) {
+ utf8_buf[0] = '\0';
+ }
- if (status == XBufferOverflow) {
- utf8_buf = (char *)malloc(len + 5);
- len = Xutf8LookupString(xic, xke, utf8_buf, len, &key_sym, &status);
- }
+ if (status == XBufferOverflow) {
+ utf8_buf = (char *)malloc(len + 5);
+ len = Xutf8LookupString(xic, xke, utf8_buf, len, &key_sym, &status);
+ }
- if ((status == XLookupChars || status == XLookupBoth)) {
- if ((unsigned char)utf8_buf[0] >= 32) { /* not an ascii control character */
- /* do nothing for now, this is valid utf8 */
+ if (ELEM(status, XLookupChars, XLookupBoth)) {
+ if ((unsigned char)utf8_buf[0] >= 32) { /* not an ascii control character */
+ /* do nothing for now, this is valid utf8 */
+ }
+ else {
+ utf8_buf[0] = '\0';
+ }
+ }
+ else if (status == XLookupKeySym) {
+ /* this key doesn't have a text representation, it is a command
+ * key of some sort */
}
else {
- utf8_buf[0] = '\0';
+ printf("Bad keycode lookup. Keysym 0x%x Status: %s\n",
+ (unsigned int)key_sym,
+ (status == XLookupNone ? "XLookupNone" :
+ status == XLookupKeySym ? "XLookupKeySym" :
+ "Unknown status"));
+
+ printf("'%.*s' %p %p\n", len, utf8_buf, xic, m_xim);
}
}
- else if (status == XLookupKeySym) {
- /* this key doesn't have a text representation, it is a command
- * key of some sort */
- }
else {
- printf("Bad keycode lookup. Keysym 0x%x Status: %s\n",
- (unsigned int)key_sym,
- (status == XLookupNone ? "XLookupNone" :
- status == XLookupKeySym ? "XLookupKeySym" :
- "Unknown status"));
-
- printf("'%.*s' %p %p\n", len, utf8_buf, xic, m_xim);
+ utf8_buf[0] = '\0';
}
- }
- else {
- utf8_buf[0] = '\0';
- }
#endif
+ if (!utf8_buf[0] && ascii) {
+ utf8_buf[0] = ascii;
+ utf8_buf[1] = '\0';
+ }
+ }
- g_event = new GHOST_EventKey(
- getMilliSeconds(), type, window, gkey, ascii, utf8_buf, is_repeat);
+ g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, is_repeat, utf8_buf);
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
/* when using IM for some languages such as Japanese,
* one event inserts multiple utf8 characters */
- if (xic && xke->type == KeyPress) {
+ if (xke->type == KeyPress && xic) {
unsigned char c;
int i = 0;
- while (1) {
- /* search character boundary */
- if ((unsigned char)utf8_buf[i++] > 0x7f) {
+ while (true) {
+ /* Search character boundary. */
+ if ((uchar)utf8_buf[i++] > 0x7f) {
for (; i < len; ++i) {
c = utf8_buf[i];
- if (c < 0x80 || c > 0xbf)
+ if (c < 0x80 || c > 0xbf) {
break;
+ }
}
}
- if (i >= len)
+ if (i >= len) {
break;
-
- /* enqueue previous character */
+ }
+ /* Enqueue previous character. */
pushEvent(g_event);
g_event = new GHOST_EventKey(
- getMilliSeconds(), type, window, gkey, '\0', &utf8_buf[i], is_repeat);
+ getMilliSeconds(), type, window, gkey, is_repeat, &utf8_buf[i]);
}
}
- if (utf8_buf != utf8_array)
+ if (utf8_buf != utf8_array) {
free(utf8_buf);
+ }
#endif
break;
@@ -1224,42 +1246,52 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
case ButtonPress:
case ButtonRelease: {
XButtonEvent &xbe = xe->xbutton;
- GHOST_TButtonMask gbmask = GHOST_kButtonMaskLeft;
+ GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown :
GHOST_kEventButtonUp;
/* process wheel mouse events and break, only pass on press events */
if (xbe.button == Button4) {
- if (xbe.type == ButtonPress)
+ if (xbe.type == ButtonPress) {
g_event = new GHOST_EventWheel(getMilliSeconds(), window, 1);
+ }
break;
}
- else if (xbe.button == Button5) {
- if (xbe.type == ButtonPress)
+ if (xbe.button == Button5) {
+ if (xbe.type == ButtonPress) {
g_event = new GHOST_EventWheel(getMilliSeconds(), window, -1);
+ }
break;
}
/* process rest of normal mouse buttons */
- if (xbe.button == Button1)
+ if (xbe.button == Button1) {
gbmask = GHOST_kButtonMaskLeft;
- else if (xbe.button == Button2)
+ }
+ else if (xbe.button == Button2) {
gbmask = GHOST_kButtonMaskMiddle;
- else if (xbe.button == Button3)
+ }
+ else if (xbe.button == Button3) {
gbmask = GHOST_kButtonMaskRight;
- /* It seems events 6 and 7 are for horizontal scrolling.
- * you can re-order button mapping like this... (swaps 6,7 with 8,9)
- * `xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7"` */
- else if (xbe.button == 6)
+ /* It seems events 6 and 7 are for horizontal scrolling.
+ * you can re-order button mapping like this... (swaps 6,7 with 8,9)
+ * `xmodmap -e "pointer = 1 2 3 4 5 8 9 6 7"` */
+ }
+ else if (xbe.button == 6) {
gbmask = GHOST_kButtonMaskButton6;
- else if (xbe.button == 7)
+ }
+ else if (xbe.button == 7) {
gbmask = GHOST_kButtonMaskButton7;
- else if (xbe.button == 8)
+ }
+ else if (xbe.button == 8) {
gbmask = GHOST_kButtonMaskButton4;
- else if (xbe.button == 9)
+ }
+ else if (xbe.button == 9) {
gbmask = GHOST_kButtonMaskButton5;
- else
+ }
+ else {
break;
+ }
g_event = new GHOST_EventButton(
getMilliSeconds(), type, window, gbmask, window->GetTabletData());
@@ -1323,8 +1355,9 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
if (XGetWindowAttributes(m_display, xcme.window, &attr) == True) {
if (XGetInputFocus(m_display, &fwin, &revert_to) == True) {
if (attr.map_state == IsViewable) {
- if (fwin != xcme.window)
+ if (fwin != xcme.window) {
XSetInputFocus(m_display, xcme.window, RevertToParent, xcme.data.l[1]);
+ }
}
}
}
@@ -1373,10 +1406,12 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
// printf("X: %s window %d\n",
// xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window);
- if (xce.type == EnterNotify)
+ if (xce.type == EnterNotify) {
m_windowManager->setActiveWindow(window);
- else
+ }
+ else {
m_windowManager->setWindowInactive(window);
+ }
break;
}
@@ -1429,8 +1464,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
nxe.xselection.time = xse->time;
/* Check to see if the requester is asking for String */
- if (xse->target == utf8_string || xse->target == string || xse->target == compound_text ||
- xse->target == c_string) {
+ if (ELEM(xse->target, utf8_string, string, compound_text, c_string)) {
if (xse->selection == XInternAtom(m_display, "PRIMARY", False)) {
XChangeProperty(m_display,
xse->requestor,
@@ -1483,7 +1517,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
default: {
#ifdef WITH_X11_XINPUT
for (GHOST_TabletX11 &xtablet : m_xtablets) {
- if (xe->type == xtablet.MotionEvent || xe->type == xtablet.PressEvent) {
+ if (ELEM(xe->type, xtablet.MotionEvent, xtablet.PressEvent)) {
XDeviceMotionEvent *data = (XDeviceMotionEvent *)xe;
if (data->deviceid != xtablet.ID) {
continue;
@@ -1642,10 +1676,10 @@ static GHOST_TSuccess getCursorPosition_impl(Display *display,
&mask_return) == False) {
return GHOST_kFailure;
}
- else {
- x = rx;
- y = ry;
- }
+
+ x = rx;
+ y = ry;
+
return GHOST_kSuccess;
}
@@ -1715,7 +1749,7 @@ GHOST_TSuccess GHOST_SystemX11::setCursorPosition(int32_t x, int32_t y)
void GHOST_SystemX11::addDirtyWindow(GHOST_WindowX11 *bad_wind)
{
- GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
+ GHOST_ASSERT((bad_wind != nullptr), "addDirtyWindow() nullptr ptr trapped (window)");
m_dirty_windows.push_back(bad_wind);
}
@@ -1952,18 +1986,19 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
return;
case XCLIB_XCOUT_SENTCONVSEL:
- if (evt->type != SelectionNotify)
+ if (evt->type != SelectionNotify) {
return;
+ }
if (target == m_atom.UTF8_STRING && evt->xselection.property == None) {
*context = XCLIB_XCOUT_FALLBACK_UTF8;
return;
}
- else if (target == m_atom.COMPOUND_TEXT && evt->xselection.property == None) {
+ if (target == m_atom.COMPOUND_TEXT && evt->xselection.property == None) {
*context = XCLIB_XCOUT_FALLBACK_COMP;
return;
}
- else if (target == m_atom.TEXT && evt->xselection.property == None) {
+ if (target == m_atom.TEXT && evt->xselection.property == None) {
*context = XCLIB_XCOUT_FALLBACK_TEXT;
return;
}
@@ -2039,12 +2074,14 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
* then read it, delete it, etc. */
/* make sure that the event is relevant */
- if (evt->type != PropertyNotify)
+ if (evt->type != PropertyNotify) {
return;
+ }
/* skip unless the property has a new value */
- if (evt->xproperty.state != PropertyNewValue)
+ if (evt->xproperty.state != PropertyNewValue) {
return;
+ }
/* check size and format of the property */
XGetWindowProperty(m_display,
@@ -2118,7 +2155,6 @@ void GHOST_SystemX11::getClipboard_xcout(const XEvent *evt,
XFlush(m_display);
return;
}
- return;
}
char *GHOST_SystemX11::getClipboard(bool selection) const
@@ -2133,10 +2169,12 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
XEvent evt;
unsigned int context = XCLIB_XCOUT_NONE;
- if (selection == True)
+ if (selection == True) {
sseln = m_atom.PRIMARY;
- else
+ }
+ else {
sseln = m_atom.CLIPBOARD;
+ }
const vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
@@ -2151,19 +2189,18 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
strcpy(sel_buf, txt_cut_buffer);
return sel_buf;
}
- else {
- sel_buf = (char *)malloc(strlen(txt_select_buffer) + 1);
- strcpy(sel_buf, txt_select_buffer);
- return sel_buf;
- }
+ sel_buf = (char *)malloc(strlen(txt_select_buffer) + 1);
+ strcpy(sel_buf, txt_select_buffer);
+ return sel_buf;
+ }
+ if (owner == None) {
+ return nullptr;
}
- else if (owner == None)
- return NULL;
/* Restore events so copy doesn't swallow other event types (keyboard/mouse). */
vector<XEvent> restore_events;
- while (1) {
+ while (true) {
/* only get an event if xcout() is doing something */
bool restore_this_event = false;
if (context != XCLIB_XCOUT_NONE) {
@@ -2184,26 +2221,27 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
target = m_atom.STRING;
continue;
}
- else if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
+ if (context == XCLIB_XCOUT_FALLBACK_UTF8) {
/* utf8 fail, move to compound text. */
context = XCLIB_XCOUT_NONE;
target = m_atom.COMPOUND_TEXT;
continue;
}
- else if (context == XCLIB_XCOUT_FALLBACK_COMP) {
+ if (context == XCLIB_XCOUT_FALLBACK_COMP) {
/* Compound text fail, move to text. */
context = XCLIB_XCOUT_NONE;
target = m_atom.TEXT;
continue;
}
- else if (context == XCLIB_XCOUT_FALLBACK_TEXT) {
+ if (context == XCLIB_XCOUT_FALLBACK_TEXT) {
/* Text fail, nothing else to try, break. */
context = XCLIB_XCOUT_NONE;
}
/* Only continue if #xcout() is doing something. */
- if (context == XCLIB_XCOUT_NONE)
+ if (context == XCLIB_XCOUT_NONE) {
break;
+ }
}
while (!restore_events.empty()) {
@@ -2217,14 +2255,16 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
memcpy(tmp_data, (char *)sel_buf, sel_len);
tmp_data[sel_len] = '\0';
- if (sseln == m_atom.STRING)
+ if (sseln == m_atom.STRING) {
XFree(sel_buf);
- else
+ }
+ else {
free(sel_buf);
+ }
return tmp_data;
}
- return NULL;
+ return nullptr;
}
void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
@@ -2240,8 +2280,9 @@ void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
if (selection == False) {
XSetSelectionOwner(m_display, m_atom.CLIPBOARD, m_window, CurrentTime);
owner = XGetSelectionOwner(m_display, m_atom.CLIPBOARD);
- if (txt_cut_buffer)
+ if (txt_cut_buffer) {
free((void *)txt_cut_buffer);
+ }
txt_cut_buffer = (char *)malloc(strlen(buffer) + 1);
strcpy(txt_cut_buffer, buffer);
@@ -2249,15 +2290,17 @@ void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
else {
XSetSelectionOwner(m_display, m_atom.PRIMARY, m_window, CurrentTime);
owner = XGetSelectionOwner(m_display, m_atom.PRIMARY);
- if (txt_select_buffer)
+ if (txt_select_buffer) {
free((void *)txt_select_buffer);
+ }
txt_select_buffer = (char *)malloc(strlen(buffer) + 1);
strcpy(txt_select_buffer, buffer);
}
- if (owner != m_window)
+ if (owner != m_window) {
fprintf(stderr, "failed to own primary\n");
+ }
}
}
@@ -2352,14 +2395,16 @@ static void split(const char *text, const char *seps, char ***str, int *count)
*count = 0;
data = strdup(text);
- for (tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps))
+ for (tok = strtok(data, seps); tok != nullptr; tok = strtok(nullptr, seps)) {
(*count)++;
+ }
free(data);
data = strdup(text);
*str = (char **)malloc((size_t)(*count) * sizeof(char *));
- for (i = 0, tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps), i++)
+ for (i = 0, tok = strtok(data, seps); tok != nullptr; tok = strtok(nullptr, seps), i++) {
(*str)[i] = strdup(tok);
+ }
free(data);
}
@@ -2368,9 +2413,9 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
const char *help_label,
const char *continue_label,
const char *link,
- GHOST_DialogOptions) const
+ GHOST_DialogOptions /*dialog_options*/) const
{
- char **text_splitted = NULL;
+ char **text_splitted = nullptr;
int textLines = 0;
split(message, "\n", &text_splitted, &textLines);
@@ -2433,7 +2478,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
XSelectInput(m_display, window, ExposureMask | ButtonPressMask | ButtonReleaseMask);
XMapWindow(m_display, window);
- while (1) {
+ while (true) {
XNextEvent(m_display, &e);
if (e.type == Expose) {
for (int i = 0; i < textLines; i++) {
@@ -2454,7 +2499,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
if (dialog_data.isInsideButton(e, 1)) {
break;
}
- else if (dialog_data.isInsideButton(e, 2)) {
+ if (dialog_data.isInsideButton(e, 2)) {
if (strlen(link)) {
string cmd = "xdg-open \"" + string(link) + "\"";
if (system(cmd.c_str()) != 0) {
@@ -2543,7 +2588,7 @@ int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/)
static bool is_filler_char(char c)
{
- return isspace(c) || c == '_' || c == '-' || c == ';' || c == ':';
+ return isspace(c) || ELEM(c, '_', '-', ';', ':');
}
/* These C functions are copied from Wine 3.12's `wintab.c` */
@@ -2551,18 +2596,23 @@ static bool match_token(const char *haystack, const char *needle)
{
const char *h, *n;
for (h = haystack; *h;) {
- while (*h && is_filler_char(*h))
+ while (*h && is_filler_char(*h)) {
h++;
- if (!*h)
+ }
+ if (!*h) {
break;
+ }
- for (n = needle; *n && *h && tolower(*h) == tolower(*n); n++)
+ for (n = needle; *n && *h && tolower(*h) == tolower(*n); n++) {
h++;
- if (!*n && (is_filler_char(*h) || !*h))
+ }
+ if (!*n && (is_filler_char(*h) || !*h)) {
return true;
+ }
- while (*h && !is_filler_char(*h))
+ while (*h && !is_filler_char(*h)) {
h++;
+ }
}
return false;
}
@@ -2580,19 +2630,19 @@ static bool match_token(const char *haystack, const char *needle)
static GHOST_TTabletMode tablet_mode_from_name(const char *name, const char *type)
{
int i;
- static const char *tablet_stylus_whitelist[] = {"stylus", "wizardpen", "acecad", "pen", NULL};
+ static const char *tablet_stylus_whitelist[] = {"stylus", "wizardpen", "acecad", "pen", nullptr};
- static const char *type_blacklist[] = {"pad", "cursor", "touch", NULL};
+ static const char *type_blacklist[] = {"pad", "cursor", "touch", nullptr};
/* Skip some known unsupported types. */
- for (i = 0; type_blacklist[i] != NULL; i++) {
+ for (i = 0; type_blacklist[i] != nullptr; i++) {
if (type && (strcasecmp(type, type_blacklist[i]) == 0)) {
return GHOST_kTabletModeNone;
}
}
/* First check device type to avoid cases where name is "Pen and Eraser" and type is "ERASER" */
- for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
+ for (i = 0; tablet_stylus_whitelist[i] != nullptr; i++) {
if (type && match_token(type, tablet_stylus_whitelist[i])) {
return GHOST_kTabletModeStylus;
}
@@ -2600,7 +2650,7 @@ static GHOST_TTabletMode tablet_mode_from_name(const char *name, const char *typ
if (type && match_token(type, "eraser")) {
return GHOST_kTabletModeEraser;
}
- for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
+ for (i = 0; tablet_stylus_whitelist[i] != nullptr; i++) {
if (name && match_token(name, tablet_stylus_whitelist[i])) {
return GHOST_kTabletModeStylus;
}
@@ -2629,7 +2679,7 @@ void GHOST_SystemX11::refreshXInputDevices()
for (int i = 0; i < device_count; ++i) {
char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) :
- NULL;
+ nullptr;
GHOST_TTabletMode tablet_mode = tablet_mode_from_name(device_info[i].name, device_type);
// printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i);
@@ -2638,7 +2688,7 @@ void GHOST_SystemX11::refreshXInputDevices()
XFree((void *)device_type);
}
- if (!(tablet_mode == GHOST_kTabletModeStylus || tablet_mode == GHOST_kTabletModeEraser)) {
+ if (!ELEM(tablet_mode, GHOST_kTabletModeStylus, GHOST_kTabletModeEraser)) {
continue;
}
@@ -2646,15 +2696,15 @@ void GHOST_SystemX11::refreshXInputDevices()
xtablet.ID = device_info[i].id;
xtablet.Device = XOpenDevice(m_display, xtablet.ID);
- if (xtablet.Device != NULL) {
+ if (xtablet.Device != nullptr) {
/* Find how many pressure levels tablet has */
XAnyClassPtr ici = device_info[i].inputclassinfo;
- if (ici != NULL) {
+ if (ici != nullptr) {
for (int j = 0; j < device_info[i].num_classes; ++j) {
if (ici->c_class == ValuatorClass) {
XValuatorInfo *xvi = (XValuatorInfo *)ici;
- if (xvi->axes != NULL) {
+ if (xvi->axes != nullptr) {
xtablet.PressureLevels = xvi->axes[2].max_value;
if (xvi->num_axes > 3) {
diff --git a/intern/ghost/intern/GHOST_TaskbarX11.cpp b/intern/ghost/intern/GHOST_TaskbarX11.cpp
index 85ec5eb6943..1e568c3a2b0 100644
--- a/intern/ghost/intern/GHOST_TaskbarX11.cpp
+++ b/intern/ghost/intern/GHOST_TaskbarX11.cpp
@@ -11,10 +11,10 @@
#include <cstdlib>
#include <dlfcn.h>
-typedef void *(*unity_get_entry_t)(const char *);
-typedef void (*unity_set_progress_t)(void *, double);
-typedef void (*unity_set_progress_visible_t)(void *, int);
-typedef int (*unity_event_loop_t)(void *, int);
+using unity_get_entry_t = void *(*)(const char *);
+using unity_set_progress_t = void (*)(void *, double);
+using unity_set_progress_visible_t = void (*)(void *, int);
+using unity_event_loop_t = int (*)(void *, int);
static unity_get_entry_t unity_get_entry;
static unity_set_progress_t unity_set_progress;
@@ -23,13 +23,13 @@ static unity_event_loop_t unity_event_loop;
static bool libunity_initialized = false;
static bool libunity_available = false;
-static void *libunity_handle = NULL;
+static void *libunity_handle = nullptr;
void GHOST_TaskBarX11::free()
{
if (libunity_handle) {
dlclose(libunity_handle);
- libunity_handle = NULL;
+ libunity_handle = nullptr;
}
}
@@ -42,7 +42,7 @@ bool GHOST_TaskBarX11::init()
libunity_initialized = true;
const char *libunity_names[] = {
- "libunity.so.4", "libunity.so.6", "libunity.so.9", "libunity.so", NULL};
+ "libunity.so.4", "libunity.so.6", "libunity.so.9", "libunity.so", nullptr};
for (int i = 0; libunity_names[i]; i++) {
libunity_handle = dlopen(libunity_names[i], RTLD_LAZY);
if (libunity_handle) {
@@ -90,13 +90,13 @@ GHOST_TaskBarX11::GHOST_TaskBarX11(const char *name)
handle = unity_get_entry(name);
}
else {
- handle = NULL;
+ handle = nullptr;
}
}
bool GHOST_TaskBarX11::is_valid()
{
- return (handle != NULL);
+ return (handle != nullptr);
}
void GHOST_TaskBarX11::set_progress(double progress)
@@ -109,5 +109,5 @@ void GHOST_TaskBarX11::set_progress_enabled(bool enabled)
{
assert(is_valid());
unity_set_progress_visible(handle, enabled ? 1 : 0);
- unity_event_loop(NULL, 0);
+ unity_event_loop(nullptr, 0);
}
diff --git a/intern/ghost/intern/GHOST_TimerTask.h b/intern/ghost/intern/GHOST_TimerTask.h
index f59b832740f..8ca8e36837e 100644
--- a/intern/ghost/intern/GHOST_TimerTask.h
+++ b/intern/ghost/intern/GHOST_TimerTask.h
@@ -25,7 +25,7 @@ class GHOST_TimerTask : public GHOST_ITimerTask {
GHOST_TimerTask(uint64_t start,
uint64_t interval,
GHOST_TimerProcPtr timerProc,
- GHOST_TUserDataPtr userData = NULL)
+ GHOST_TUserDataPtr userData = nullptr)
: m_start(start),
m_interval(interval),
m_next(start),
diff --git a/intern/ghost/intern/GHOST_WaylandCursorSettings.h b/intern/ghost/intern/GHOST_WaylandCursorSettings.h
index 1e8cc2ac8a9..f5649d20850 100644
--- a/intern/ghost/intern/GHOST_WaylandCursorSettings.h
+++ b/intern/ghost/intern/GHOST_WaylandCursorSettings.h
@@ -5,9 +5,13 @@
*/
#pragma once
-#include <dbus/dbus.h>
#include <string>
+#ifdef WITH_GHOST_WAYLAND_DBUS
+# include <dbus/dbus.h>
+#endif
+
+#ifdef WITH_GHOST_WAYLAND_DBUS
static DBusMessage *get_setting_sync(DBusConnection *const connection,
const char *key,
const char *value)
@@ -28,7 +32,7 @@ static DBusMessage *get_setting_sync(DBusConnection *const connection,
message, DBUS_TYPE_STRING, &key, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID);
if (!success) {
- return NULL;
+ return nullptr;
}
reply = dbus_connection_send_with_reply_and_block(
@@ -37,7 +41,7 @@ static DBusMessage *get_setting_sync(DBusConnection *const connection,
dbus_message_unref(message);
if (dbus_error_is_set(&error)) {
- return NULL;
+ return nullptr;
}
return reply;
@@ -66,9 +70,11 @@ static bool parse_type(DBusMessage *const reply, const int type, void *value)
return true;
}
+#endif /* WITH_GHOST_WAYLAND_DBUS */
static bool get_cursor_settings(std::string &theme, int &size)
{
+#ifdef WITH_GHOST_WAYLAND_DBUS
static const char name[] = "org.gnome.desktop.interface";
static const char key_theme[] = "cursor-theme";
static const char key_size[] = "cursor-size";
@@ -76,7 +82,7 @@ static bool get_cursor_settings(std::string &theme, int &size)
DBusError error;
DBusConnection *connection;
DBusMessage *reply;
- const char *value_theme = NULL;
+ const char *value_theme = nullptr;
dbus_error_init(&error);
@@ -113,4 +119,11 @@ static bool get_cursor_settings(std::string &theme, int &size)
dbus_message_unref(reply);
return true;
+#else
+ /* NOTE: eventually we could have alternative ways to access the theme,
+ * this uses the "default" theme which is functional (instead of a user-defined theme). */
+ (void)theme;
+ (void)size;
+ return false;
+#endif /* !WITH_GHOST_WAYLAND_DBUS */
}
diff --git a/intern/ghost/intern/GHOST_WaylandUtils.h b/intern/ghost/intern/GHOST_WaylandUtils.h
new file mode 100644
index 00000000000..0e1e133bc4c
--- /dev/null
+++ b/intern/ghost/intern/GHOST_WaylandUtils.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup GHOST
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+# undef wl_array_for_each
+/**
+ * This macro causes a warning for C++ code, define our own.
+ * See: https://gitlab.freedesktop.org/wayland/wayland/-/issues/34
+ */
+# define WL_ARRAY_FOR_EACH(pos, array) \
+ for (pos = (decltype(pos))((array)->data); \
+ (const char *)pos < ((const char *)(array)->data + (array)->size); \
+ (pos)++)
+#endif
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index 834836a7f4d..db4d6c3bb71 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -13,7 +13,7 @@
#include "GHOST_ContextNone.h"
-#include <assert.h>
+#include <cassert>
GHOST_Window::GHOST_Window(uint32_t width,
uint32_t height,
@@ -23,6 +23,7 @@ GHOST_Window::GHOST_Window(uint32_t width,
: m_drawingContextType(GHOST_kDrawingContextTypeNone),
m_cursorVisible(true),
m_cursorGrab(GHOST_kGrabDisable),
+ m_cursorGrabAxis(GHOST_kAxisNone),
m_cursorShape(GHOST_kStandardCursorDefault),
m_wantStereoVisual(wantStereoVisual),
m_context(new GHOST_ContextNone(false))
@@ -51,19 +52,19 @@ GHOST_Window::~GHOST_Window()
void *GHOST_Window::getOSWindow() const
{
- return NULL;
+ return nullptr;
}
GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type)
{
if (type != m_drawingContextType) {
delete m_context;
- m_context = NULL;
+ m_context = nullptr;
- if (type != GHOST_kDrawingContextTypeNone)
+ if (type != GHOST_kDrawingContextTypeNone) {
m_context = newDrawingContext(type);
-
- if (m_context != NULL) {
+ }
+ if (m_context != nullptr) {
m_drawingContextType = type;
}
else {
@@ -73,9 +74,7 @@ GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType typ
return (type == m_drawingContextType) ? GHOST_kSuccess : GHOST_kFailure;
}
- else {
- return GHOST_kSuccess;
- }
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_Window::swapBuffers()
@@ -119,9 +118,7 @@ GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible)
m_cursorVisible = visible;
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
@@ -129,10 +126,10 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
GHOST_Rect *bounds,
int32_t mouse_ungrab_xy[2])
{
- if (m_cursorGrab == mode)
+ if (m_cursorGrab == mode) {
return GHOST_kSuccess;
-
- /* override with new location */
+ }
+ /* Override with new location. */
if (mouse_ungrab_xy) {
assert(mode == GHOST_kGrabDisable);
m_cursorGrabInitPos[0] = mouse_ungrab_xy[0];
@@ -154,26 +151,52 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
m_cursorGrabAxis = wrap_axis;
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_Window::getCursorGrabBounds(GHOST_Rect &bounds)
{
+ if (m_cursorGrab != GHOST_kGrabWrap) {
+ return GHOST_kFailure;
+ }
bounds = m_cursorGrabBounds;
return (bounds.m_l == -1 && bounds.m_r == -1) ? GHOST_kFailure : GHOST_kSuccess;
}
+void GHOST_Window::getCursorGrabState(GHOST_TGrabCursorMode &mode,
+ GHOST_TAxisFlag &wrap_axis,
+ GHOST_Rect &bounds,
+ bool &use_software_cursor)
+{
+ mode = m_cursorGrab;
+ if (m_cursorGrab == GHOST_kGrabWrap) {
+ bounds = m_cursorGrabBounds;
+ wrap_axis = m_cursorGrabAxis;
+ }
+ else {
+ bounds.m_l = -1;
+ bounds.m_r = -1;
+ bounds.m_t = -1;
+ bounds.m_b = -1;
+ wrap_axis = GHOST_kAxisNone;
+ }
+ use_software_cursor = (m_cursorGrab != GHOST_kGrabDisable) ? getCursorGrabUseSoftwareDisplay() :
+ false;
+}
+
+bool GHOST_Window::getCursorGrabUseSoftwareDisplay()
+{
+ /* Sub-classes may override, by default don't use software cursor. */
+ return false;
+}
+
GHOST_TSuccess GHOST_Window::setCursorShape(GHOST_TStandardCursor cursorShape)
{
if (setWindowCursorShape(cursorShape)) {
m_cursorShape = cursorShape;
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_Window::setCustomCursorShape(
@@ -183,9 +206,13 @@ GHOST_TSuccess GHOST_Window::setCustomCursorShape(
m_cursorShape = GHOST_kStandardCursorCustom;
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
+}
+
+GHOST_TSuccess GHOST_Window::getCursorBitmap(GHOST_CursorBitmapRef * /*bitmap*/)
+{
+ /* Sub-classes may override. */
+ return GHOST_kFailure;
}
void GHOST_Window::setAcceptDragOperation(bool canAccept)
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 794e834d5c7..5ff91c05b16 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -117,6 +117,8 @@ class GHOST_Window : public GHOST_IWindow {
int hotY,
bool canInvertColor);
+ GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap);
+
/**
* Returns the visibility state of the cursor.
* \return The visibility state of the cursor.
@@ -152,6 +154,15 @@ class GHOST_Window : public GHOST_IWindow {
*/
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds);
+ void getCursorGrabState(GHOST_TGrabCursorMode &mode,
+ GHOST_TAxisFlag &axis_flag,
+ GHOST_Rect &bounds,
+ bool &use_software_cursor);
+ /**
+ * Return true when a software cursor should be used.
+ */
+ bool getCursorGrabUseSoftwareDisplay();
+
/**
* Sets the progress bar value displayed in the window/application icon
* \param progress: The progress percentage (0.0 to 1.0).
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index 28dd1bdb582..e8785cbdb24 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -15,7 +15,7 @@
#include <algorithm>
GHOST_WindowManager::GHOST_WindowManager()
- : m_fullScreenWindow(0), m_activeWindow(0), m_activeWindowBeforeFullScreen(0)
+ : m_fullScreenWindow(nullptr), m_activeWindow(nullptr), m_activeWindowBeforeFullScreen(nullptr)
{
}
@@ -75,12 +75,12 @@ bool GHOST_WindowManager::getWindowFound(const GHOST_IWindow *window) const
return found;
}
-bool GHOST_WindowManager::getFullScreen(void) const
+bool GHOST_WindowManager::getFullScreen() const
{
- return m_fullScreenWindow != NULL;
+ return m_fullScreenWindow != nullptr;
}
-GHOST_IWindow *GHOST_WindowManager::getFullScreenWindow(void) const
+GHOST_IWindow *GHOST_WindowManager::getFullScreenWindow() const
{
return m_fullScreenWindow;
}
@@ -100,17 +100,17 @@ GHOST_TSuccess GHOST_WindowManager::beginFullScreen(GHOST_IWindow *window, bool
return success;
}
-GHOST_TSuccess GHOST_WindowManager::endFullScreen(void)
+GHOST_TSuccess GHOST_WindowManager::endFullScreen()
{
GHOST_TSuccess success = GHOST_kFailure;
if (getFullScreen()) {
- if (m_fullScreenWindow != NULL) {
+ if (m_fullScreenWindow != nullptr) {
// GHOST_PRINT("GHOST_WindowManager::endFullScreen(): deleting full-screen window\n");
setWindowInactive(m_fullScreenWindow);
m_fullScreenWindow->endFullScreen();
delete m_fullScreenWindow;
// GHOST_PRINT("GHOST_WindowManager::endFullScreen(): done\n");
- m_fullScreenWindow = NULL;
+ m_fullScreenWindow = nullptr;
if (m_activeWindowBeforeFullScreen) {
setActiveWindow(m_activeWindowBeforeFullScreen);
}
@@ -134,7 +134,7 @@ GHOST_TSuccess GHOST_WindowManager::setActiveWindow(GHOST_IWindow *window)
return success;
}
-GHOST_IWindow *GHOST_WindowManager::getActiveWindow(void) const
+GHOST_IWindow *GHOST_WindowManager::getActiveWindow() const
{
return m_activeWindow;
}
@@ -142,7 +142,7 @@ GHOST_IWindow *GHOST_WindowManager::getActiveWindow(void) const
void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow *window)
{
if (window == m_activeWindow) {
- m_activeWindow = NULL;
+ m_activeWindow = nullptr;
}
}
@@ -156,22 +156,9 @@ GHOST_IWindow *GHOST_WindowManager::getWindowAssociatedWithOSWindow(void *osWind
std::vector<GHOST_IWindow *>::iterator iter;
for (iter = m_windows.begin(); iter != m_windows.end(); ++iter) {
- if ((*iter)->getOSWindow() == osWindow)
+ if ((*iter)->getOSWindow() == osWindow) {
return *iter;
+ }
}
-
- return NULL;
-}
-
-bool GHOST_WindowManager::getAnyModifiedState()
-{
- bool isAnyModified = false;
- std::vector<GHOST_IWindow *>::iterator iter;
-
- for (iter = m_windows.begin(); iter != m_windows.end(); ++iter) {
- if ((*iter)->getModifiedState())
- isAnyModified = true;
- }
-
- return isAnyModified;
+ return nullptr;
}
diff --git a/intern/ghost/intern/GHOST_WindowManager.h b/intern/ghost/intern/GHOST_WindowManager.h
index 9d20413c433..bf7a0f4ec61 100644
--- a/intern/ghost/intern/GHOST_WindowManager.h
+++ b/intern/ghost/intern/GHOST_WindowManager.h
@@ -109,12 +109,6 @@ class GHOST_WindowManager {
*/
GHOST_IWindow *getWindowAssociatedWithOSWindow(void *osWindow);
- /**
- * Return true if any windows has a modified status
- * \return True if any window has unsaved changes
- */
- bool getAnyModifiedState();
-
protected:
/** The list of windows managed */
std::vector<GHOST_IWindow *> m_windows;
diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h
index 1cbca80a49c..01b50251d69 100644
--- a/intern/ghost/intern/GHOST_WindowNULL.h
+++ b/intern/ghost/intern/GHOST_WindowNULL.h
@@ -153,6 +153,6 @@ class GHOST_WindowNULL : public GHOST_Window {
*/
GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type)
{
- return NULL;
+ return nullptr;
}
};
diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp
index 168949771c9..09192d989e4 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.cpp
+++ b/intern/ghost/intern/GHOST_WindowSDL.cpp
@@ -10,7 +10,7 @@
#include "GHOST_ContextSDL.h"
-#include <assert.h>
+#include <cassert>
GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
const char *title,
@@ -27,7 +27,7 @@ GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
m_system(system),
m_valid_setup(false),
m_invalid_window(false),
- m_sdl_custom_cursor(NULL)
+ m_sdl_custom_cursor(nullptr)
{
/* creating the window _must_ come after setting attributes */
@@ -73,16 +73,16 @@ GHOST_Context *GHOST_WindowSDL::newDrawingContext(GHOST_TDrawingContextType type
GHOST_OPENGL_SDL_CONTEXT_FLAGS,
GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY);
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
- return NULL;
+ return nullptr;
}
-GHOST_TSuccess GHOST_WindowSDL::invalidate(void)
+GHOST_TSuccess GHOST_WindowSDL::invalidate()
{
if (m_invalid_window == false) {
m_system->addDirtyWindow(this);
@@ -120,12 +120,15 @@ GHOST_TWindowState GHOST_WindowSDL::getState() const
{
Uint32 flags = SDL_GetWindowFlags(m_sdl_win);
- if (flags & SDL_WINDOW_FULLSCREEN)
+ if (flags & SDL_WINDOW_FULLSCREEN) {
return GHOST_kWindowStateFullScreen;
- else if (flags & SDL_WINDOW_MAXIMIZED)
+ }
+ if (flags & SDL_WINDOW_MAXIMIZED) {
return GHOST_kWindowStateMaximized;
- else if (flags & SDL_WINDOW_MINIMIZED)
+ }
+ if (flags & SDL_WINDOW_MINIMIZED) {
return GHOST_kWindowStateMinimized;
+ }
return GHOST_kWindowStateNormal;
}
@@ -164,7 +167,7 @@ void GHOST_WindowSDL::getClientBounds(GHOST_Rect &bounds) const
GHOST_TSuccess GHOST_WindowSDL::setClientWidth(uint32_t width)
{
int height;
- SDL_GetWindowSize(m_sdl_win, NULL, &height);
+ SDL_GetWindowSize(m_sdl_win, nullptr, &height);
SDL_SetWindowSize(m_sdl_win, width, height);
return GHOST_kSuccess;
}
@@ -172,7 +175,7 @@ GHOST_TSuccess GHOST_WindowSDL::setClientWidth(uint32_t width)
GHOST_TSuccess GHOST_WindowSDL::setClientHeight(uint32_t height)
{
int width;
- SDL_GetWindowSize(m_sdl_win, &width, NULL);
+ SDL_GetWindowSize(m_sdl_win, &width, nullptr);
SDL_SetWindowSize(m_sdl_win, width, height);
return GHOST_kSuccess;
}
@@ -483,7 +486,7 @@ static unsigned char sdl_std_cursor_arrow[] = {
#define sdl_std_cursor_HOT_Y_arrow -14
/* end cursor data */
-static SDL_Cursor *sdl_std_cursor_array[(int)GHOST_kStandardCursorNumCursors] = {0};
+static SDL_Cursor *sdl_std_cursor_array[(int)GHOST_kStandardCursorNumCursors] = {nullptr};
/* utility function mostly a copy of SDL_CreateCursor but allows us to change
* color and supports blenders flipped bits */
@@ -505,7 +508,7 @@ static SDL_Cursor *sdl_ghost_CreateCursor(
/* Create the surface from a bitmap */
surface = SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
if (!surface) {
- return NULL;
+ return nullptr;
}
for (y = 0; y < h; ++y) {
pixel = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch);
@@ -539,7 +542,7 @@ static SDL_Cursor *sdl_ghost_CreateCursor(
/* TODO: this is currently never freed but it won't leak either. */
static SDL_Cursor *getStandardCursorShape(GHOST_TStandardCursor shape)
{
- if (sdl_std_cursor_array[0] == NULL) {
+ if (sdl_std_cursor_array[0] == nullptr) {
#define DEF_CURSOR(name, ind) \
{ \
sdl_std_cursor_array[(int)ind] = sdl_ghost_CreateCursor( \
@@ -549,7 +552,7 @@ static SDL_Cursor *getStandardCursorShape(GHOST_TStandardCursor shape)
sdl_std_cursor_HEIGHT_##name, \
(sdl_std_cursor_WIDTH_##name + (sdl_std_cursor_HOT_X_##name)) - 1, \
(sdl_std_cursor_HEIGHT_##name + (sdl_std_cursor_HOT_Y_##name)) - 1); \
- assert(sdl_std_cursor_array[(int)ind] != NULL); \
+ assert(sdl_std_cursor_array[(int)ind] != nullptr); \
} \
(void)0
@@ -589,7 +592,7 @@ GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode /*mode
GHOST_TSuccess GHOST_WindowSDL::setWindowCursorShape(GHOST_TStandardCursor shape)
{
SDL_Cursor *cursor = getStandardCursorShape(shape);
- if (cursor == NULL) {
+ if (cursor == nullptr) {
cursor = getStandardCursorShape(GHOST_kStandardCursorDefault);
}
@@ -635,7 +638,7 @@ uint16_t GHOST_WindowSDL::getDPIHint()
}
float ddpi;
- if (SDL_GetDisplayDPI(displayIndex, &ddpi, NULL, NULL) != 0) {
+ if (SDL_GetDisplayDPI(displayIndex, &ddpi, nullptr, nullptr) != 0) {
return 96;
}
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 7f2a2c992d9..e303bd5b6aa 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -6,61 +6,170 @@
#include "GHOST_WindowWayland.h"
#include "GHOST_SystemWayland.h"
+#include "GHOST_WaylandUtils.h"
#include "GHOST_WindowManager.h"
+#include "GHOST_utildefines.h"
#include "GHOST_Event.h"
#include "GHOST_ContextEGL.h"
#include "GHOST_ContextNone.h"
+#include <wayland-client-protocol.h>
+
+#ifdef WITH_GHOST_WAYLAND_DYNLOAD
+# include <wayland_dynload_egl.h>
+#endif
#include <wayland-egl.h>
+#include <algorithm> /* For `std::find`. */
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+# ifdef WITH_GHOST_WAYLAND_DYNLOAD
+# include <wayland_dynload_libdecor.h>
+# endif
+# include <libdecor.h>
+#endif
+
+/* Logging, use `ghost.wl.*` prefix. */
+#include "CLG_log.h"
+
static constexpr size_t base_dpi = 96;
+static GHOST_WindowManager *window_manager = nullptr;
+
struct window_t {
- GHOST_WindowWayland *w;
- wl_surface *surface;
- /* Outputs on which the window is currently shown on. */
- std::unordered_set<const output_t *> outputs;
- uint16_t dpi = 0;
- int scale = 1;
- struct xdg_surface *xdg_surface;
- struct xdg_toplevel *xdg_toplevel;
+ GHOST_WindowWayland *w = nullptr;
+ struct wl_surface *wl_surface = nullptr;
+ /**
+ * Outputs on which the window is currently shown on.
+ *
+ * This is an ordered set (whoever adds to this is responsible for keeping members unique).
+ * In practice this is rarely manipulated and is limited by the number of physical displays.
+ */
+ std::vector<output_t *> outputs;
+
+ /** The scale value written to #wl_surface_set_buffer_scale. */
+ int scale = 0;
+ /**
+ * The DPI, either:
+ * - `scale * base_dpi`
+ * - `wl_fixed_to_int(scale_fractional * base_dpi)`
+ * When fractional scaling is available.
+ */
+ uint32_t dpi = 0;
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ struct libdecor_frame *decor_frame = nullptr;
+ bool decor_configured = false;
+#else
+ struct xdg_surface *xdg_surface = nullptr;
struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr;
- enum zxdg_toplevel_decoration_v1_mode decoration_mode;
- wl_egl_window *egl_window;
- int32_t pending_width, pending_height;
- bool is_maximised;
- bool is_fullscreen;
- bool is_active;
- bool is_dialog;
- int32_t width, height;
+ struct xdg_toplevel *xdg_toplevel = nullptr;
+
+ enum zxdg_toplevel_decoration_v1_mode decoration_mode = (enum zxdg_toplevel_decoration_v1_mode)0;
+#endif
+
+ wl_egl_window *egl_window = nullptr;
+ bool is_maximised = false;
+ bool is_fullscreen = false;
+ bool is_active = false;
+ bool is_dialog = false;
+
+ int32_t size[2] = {0, 0};
+ int32_t size_pending[2] = {0, 0};
};
/* -------------------------------------------------------------------- */
-/** \name Wayland Interface Callbacks
- *
- * These callbacks are registered for Wayland interfaces and called when
- * an event is received from the compositor.
+/** \name Internal Utilities
+ * \{ */
+
+/**
+ * Return -1 if `output_a` has a scale smaller than `output_b`, 0 when there equal, otherwise 1.
+ */
+static int output_scale_cmp(const output_t *output_a, const output_t *output_b)
+{
+ if (output_a->scale < output_b->scale) {
+ return -1;
+ }
+ if (output_a->scale > output_b->scale) {
+ return 1;
+ }
+ if (output_a->has_scale_fractional || output_b->has_scale_fractional) {
+ const wl_fixed_t scale_fractional_a = output_a->has_scale_fractional ?
+ output_a->scale_fractional :
+ wl_fixed_from_int(output_a->scale);
+ const wl_fixed_t scale_fractional_b = output_b->has_scale_fractional ?
+ output_b->scale_fractional :
+ wl_fixed_from_int(output_b->scale);
+ if (scale_fractional_a < scale_fractional_b) {
+ return -1;
+ }
+ if (scale_fractional_a > scale_fractional_b) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int outputs_max_scale_or_default(const std::vector<output_t *> &outputs,
+ const int32_t scale_default,
+ uint32_t *r_dpi)
+{
+ const output_t *output_max = nullptr;
+ for (const output_t *reg_output : outputs) {
+ if (!output_max || (output_scale_cmp(output_max, reg_output) == -1)) {
+ output_max = reg_output;
+ }
+ }
+
+ if (output_max) {
+ if (r_dpi) {
+ *r_dpi = output_max->has_scale_fractional ?
+ /* Fractional DPI. */
+ wl_fixed_to_int(output_max->scale_fractional * base_dpi) :
+ /* Simple non-fractional DPI. */
+ (output_max->scale * base_dpi);
+ }
+ return output_max->scale;
+ }
+
+ if (r_dpi) {
+ *r_dpi = scale_default * base_dpi;
+ }
+ return scale_default;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Top Level), #xdg_toplevel_listener
* \{ */
-static void toplevel_configure(
- void *data, xdg_toplevel * /*xdg_toplevel*/, int32_t width, int32_t height, wl_array *states)
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR
+
+static CLG_LogRef LOG_WL_XDG_TOPLEVEL = {"ghost.wl.handle.xdg_toplevel"};
+# define LOG (&LOG_WL_XDG_TOPLEVEL)
+
+static void xdg_toplevel_handle_configure(void *data,
+ xdg_toplevel * /*xdg_toplevel*/,
+ const int32_t width,
+ const int32_t height,
+ wl_array *states)
{
+ /* TODO: log `states`, not urgent. */
+ CLOG_INFO(LOG, 2, "configure (size=[%d, %d])", width, height);
+
window_t *win = static_cast<window_t *>(data);
- win->pending_width = width;
- win->pending_height = height;
+ win->size_pending[0] = win->scale * width;
+ win->size_pending[1] = win->scale * height;
win->is_maximised = false;
win->is_fullscreen = false;
win->is_active = false;
- /* Note that the macro 'wl_array_for_each' would typically be used to simplify this logic,
- * however it's not compatible with C++, so perform casts instead.
- * If this needs to be done more often we could define our own C++ compatible macro. */
- for (enum xdg_toplevel_state *state = static_cast<xdg_toplevel_state *>(states->data);
- reinterpret_cast<uint8_t *>(state) < (static_cast<uint8_t *>(states->data) + states->size);
- state++) {
+ enum xdg_toplevel_state *state;
+ WL_ARRAY_FOR_EACH (state, states) {
switch (*state) {
case XDG_TOPLEVEL_STATE_MAXIMIZED:
win->is_maximised = true;
@@ -77,42 +186,157 @@ static void toplevel_configure(
}
}
-static void toplevel_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
+static void xdg_toplevel_handle_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
{
+ CLOG_INFO(LOG, 2, "close");
static_cast<window_t *>(data)->w->close();
}
static const xdg_toplevel_listener toplevel_listener = {
- toplevel_configure,
- toplevel_close,
+ xdg_toplevel_handle_configure,
+ xdg_toplevel_handle_close,
+};
+
+# undef LOG
+
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (LibDecor Frame), #libdecor_frame_interface
+ * \{ */
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+
+static CLG_LogRef LOG_WL_LIBDECOR_FRAME = {"ghost.wl.handle.libdecor_frame"};
+# define LOG (&LOG_WL_LIBDECOR_FRAME)
+
+static void frame_handle_configure(struct libdecor_frame *frame,
+ struct libdecor_configuration *configuration,
+ void *data)
+{
+ CLOG_INFO(LOG, 2, "configure");
+
+ window_t *win = static_cast<window_t *>(data);
+
+ int size_next[2];
+ enum libdecor_window_state window_state;
+ struct libdecor_state *state;
+
+ if (!libdecor_configuration_get_content_size(
+ configuration, frame, &size_next[0], &size_next[1])) {
+ size_next[0] = win->size[0] / win->scale;
+ size_next[1] = win->size[1] / win->scale;
+ }
+
+ win->size[0] = win->scale * size_next[0];
+ win->size[1] = win->scale * size_next[1];
+
+ wl_egl_window_resize(win->egl_window, UNPACK2(win->size), 0, 0);
+ win->w->notify_size();
+
+ if (!libdecor_configuration_get_window_state(configuration, &window_state)) {
+ window_state = LIBDECOR_WINDOW_STATE_NONE;
+ }
+
+ win->is_maximised = window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED;
+ win->is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
+ win->is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
+
+ win->is_active ? win->w->activate() : win->w->deactivate();
+
+ state = libdecor_state_new(UNPACK2(size_next));
+ libdecor_frame_commit(frame, state, configuration);
+ libdecor_state_free(state);
+
+ win->decor_configured = true;
+}
+
+static void frame_handle_close(struct libdecor_frame * /*frame*/, void *data)
+{
+ CLOG_INFO(LOG, 2, "close");
+
+ static_cast<window_t *>(data)->w->close();
+}
+
+static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data)
+{
+ CLOG_INFO(LOG, 2, "commit");
+
+ /* We have to swap twice to keep any pop-up menus alive. */
+ static_cast<window_t *>(data)->w->swapBuffers();
+ static_cast<window_t *>(data)->w->swapBuffers();
+}
+
+static struct libdecor_frame_interface libdecor_frame_iface = {
+ frame_handle_configure,
+ frame_handle_close,
+ frame_handle_commit,
};
-static void toplevel_decoration_configure(
+# undef LOG
+
+#endif /* WITH_GHOST_WAYLAND_LIBDECOR. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Decoration Listener), #zxdg_toplevel_decoration_v1_listener
+ * \{ */
+
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR
+
+static CLG_LogRef LOG_WL_XDG_TOPLEVEL_DECORATION = {"ghost.wl.handle.xdg_toplevel_decoration"};
+# define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION)
+
+static void xdg_toplevel_decoration_handle_configure(
void *data,
struct zxdg_toplevel_decoration_v1 * /*zxdg_toplevel_decoration_v1*/,
- uint32_t mode)
+ const uint32_t mode)
{
- static_cast<window_t *>(data)->decoration_mode = zxdg_toplevel_decoration_v1_mode(mode);
+ CLOG_INFO(LOG, 2, "configure (mode=%u)", mode);
+ static_cast<window_t *>(data)->decoration_mode = (zxdg_toplevel_decoration_v1_mode)mode;
}
static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = {
- toplevel_decoration_configure,
+ xdg_toplevel_decoration_handle_configure,
};
-static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t serial)
+# undef LOG
+
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (XDG Surface Handle Configure), #xdg_surface_listener
+ * \{ */
+
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR
+
+static CLG_LogRef LOG_WL_XDG_SURFACE = {"ghost.wl.handle.xdg_surface"};
+# define LOG (&LOG_WL_XDG_SURFACE)
+
+static void xdg_surface_handle_configure(void *data,
+ xdg_surface *xdg_surface,
+ const uint32_t serial)
{
window_t *win = static_cast<window_t *>(data);
if (win->xdg_surface != xdg_surface) {
+ CLOG_INFO(LOG, 2, "configure (skipped)");
return;
}
-
- if (win->pending_width != 0 && win->pending_height != 0) {
- win->width = win->scale * win->pending_width;
- win->height = win->scale * win->pending_height;
- wl_egl_window_resize(win->egl_window, win->width, win->height, 0, 0);
- win->pending_width = 0;
- win->pending_height = 0;
+ const bool do_resize = win->size_pending[0] != 0 && win->size_pending[1] != 0;
+ CLOG_INFO(LOG, 2, "configure (do_resize=%d)", do_resize);
+
+ if (do_resize) {
+ win->size[0] = win->size_pending[0];
+ win->size[1] = win->size_pending[1];
+ wl_egl_window_resize(win->egl_window, UNPACK2(win->size), 0, 0);
+ win->size_pending[0] = 0;
+ win->size_pending[1] = 0;
win->w->notify_size();
}
@@ -126,62 +350,70 @@ static void surface_configure(void *data, xdg_surface *xdg_surface, uint32_t ser
xdg_surface_ack_configure(xdg_surface, serial);
}
-static const xdg_surface_listener surface_listener = {
- surface_configure,
+static const xdg_surface_listener xdg_surface_listener = {
+ xdg_surface_handle_configure,
};
-static bool update_scale(GHOST_WindowWayland *window)
+# undef LOG
+
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Listener (Surface), #wl_surface_listener
+ * \{ */
+
+static CLG_LogRef LOG_WL_SURFACE = {"ghost.wl.handle.surface"};
+#define LOG (&LOG_WL_SURFACE)
+
+static void surface_handle_enter(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
- int scale = 0;
- for (const output_t *output : window->outputs_active()) {
- if (output->scale > scale)
- scale = output->scale;
+ if (!ghost_wl_output_own(output)) {
+ CLOG_INFO(LOG, 2, "enter (skipped)");
+ return;
}
+ CLOG_INFO(LOG, 2, "enter");
- if (scale > 0 && window->scale() != scale) {
- window->scale() = scale;
- /* Using the real DPI will cause wrong scaling of the UI
- * use a multiplier for the default DPI as workaround. */
- window->dpi() = scale * base_dpi;
- wl_surface_set_buffer_scale(window->surface(), scale);
- return true;
+ output_t *reg_output = ghost_wl_output_user_data(output);
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(data);
+ if (win->outputs_enter(reg_output)) {
+ win->outputs_changed_update_scale();
}
- return false;
}
-static void surface_enter(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output)
+static void surface_handle_leave(void *data,
+ struct wl_surface * /*wl_surface*/,
+ struct wl_output *output)
{
- GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
- for (const output_t *reg_output : w->outputs()) {
- if (reg_output->output == output) {
- w->outputs_active().insert(reg_output);
- }
+ if (!ghost_wl_output_own(output)) {
+ CLOG_INFO(LOG, 2, "leave (skipped)");
+ return;
}
- update_scale(w);
-}
+ CLOG_INFO(LOG, 2, "leave");
-static void surface_leave(void *data, struct wl_surface * /*wl_surface*/, struct wl_output *output)
-{
- GHOST_WindowWayland *w = static_cast<GHOST_WindowWayland *>(data);
- for (const output_t *reg_output : w->outputs()) {
- if (reg_output->output == output) {
- w->outputs_active().erase(reg_output);
- }
+ output_t *reg_output = ghost_wl_output_user_data(output);
+ GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(data);
+ if (win->outputs_leave(reg_output)) {
+ win->outputs_changed_update_scale();
}
- update_scale(w);
}
-struct wl_surface_listener wl_surface_listener = {
- surface_enter,
- surface_leave,
+static struct wl_surface_listener wl_surface_listener = {
+ surface_handle_enter,
+ surface_handle_leave,
};
+#undef LOG
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Ghost Implementation
+/** \name GHOST Implementation
*
- * Wayland specific implementation of the GHOST_Window interface.
+ * WAYLAND specific implementation of the #GHOST_Window interface.
* \{ */
GHOST_TSuccess GHOST_WindowWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
@@ -191,13 +423,13 @@ GHOST_TSuccess GHOST_WindowWayland::hasCursorShape(GHOST_TStandardCursor cursorS
GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
const char *title,
- int32_t /*left*/,
- int32_t /*top*/,
- uint32_t width,
- uint32_t height,
- GHOST_TWindowState state,
+ const int32_t /*left*/,
+ const int32_t /*top*/,
+ const uint32_t width,
+ const uint32_t height,
+ const GHOST_TWindowState state,
const GHOST_IWindow *parentWindow,
- GHOST_TDrawingContextType type,
+ const GHOST_TDrawingContextType type,
const bool is_dialog,
const bool stereoVisual,
const bool exclusive)
@@ -205,34 +437,73 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
m_system(system),
w(new window_t)
{
+ /* Globally store pointer to window manager. */
+ if (!window_manager) {
+ window_manager = m_system->getWindowManager();
+ }
+
w->w = this;
- w->width = int32_t(width);
- w->height = int32_t(height);
+ w->size[0] = int32_t(width);
+ w->size[1] = int32_t(height);
w->is_dialog = is_dialog;
+ /* NOTE(@campbellbarton): The scale set here to avoid flickering on startup.
+ * When all monitors use the same scale (which is quite common) there aren't any problems.
+ *
+ * When monitors have different scales there may still be a visible window resize on startup.
+ * Ideally it would be possible to know the scale this window will use however that's only
+ * known once #surface_enter callback runs (which isn't guaranteed to run at all).
+ *
+ * Using the maximum scale is best as it results in the window first being smaller,
+ * avoiding a large window flashing before it's made smaller. */
+ w->scale = outputs_max_scale_or_default(this->m_system->outputs(), 1, &w->dpi);
+
/* Window surfaces. */
- w->surface = wl_compositor_create_surface(m_system->compositor());
- wl_surface_add_listener(w->surface, &wl_surface_listener, this);
+ w->wl_surface = wl_compositor_create_surface(m_system->compositor());
+ ghost_wl_surface_tag(w->wl_surface);
+
+ wl_surface_set_buffer_scale(w->wl_surface, w->scale);
+
+ wl_surface_add_listener(w->wl_surface, &wl_surface_listener, this);
- w->egl_window = wl_egl_window_create(w->surface, int(width), int(height));
+ w->egl_window = wl_egl_window_create(w->wl_surface, int(w->size[0]), int(w->size[1]));
- w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->shell(), w->surface);
+ /* NOTE: The limit is in points (not pixels) so Hi-DPI will limit to larger number of pixels.
+ * This has the advantage that the size limit is the same when moving the window between monitors
+ * with different scales set. If it was important to limit in pixels it could be re-calculated
+ * when the `w->scale` changed. */
+ const int32_t size_min[2] = {320, 240};
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ /* create window decorations */
+ w->decor_frame = libdecor_decorate(
+ m_system->decor_context(), w->wl_surface, &libdecor_frame_iface, w);
+ libdecor_frame_map(w->decor_frame);
+
+ libdecor_frame_set_min_content_size(w->decor_frame, UNPACK2(size_min));
+
+ if (parentWindow) {
+ libdecor_frame_set_parent(
+ w->decor_frame, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->decor_frame);
+ }
+#else
+ w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->xdg_shell(), w->wl_surface);
w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
- if (m_system->decoration_manager()) {
+ xdg_toplevel_set_min_size(w->xdg_toplevel, UNPACK2(size_min));
+
+ if (m_system->xdg_decoration_manager()) {
w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
- m_system->decoration_manager(), w->xdg_toplevel);
+ m_system->xdg_decoration_manager(), w->xdg_toplevel);
zxdg_toplevel_decoration_v1_add_listener(
w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w);
zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
- wl_surface_set_user_data(w->surface, this);
-
- xdg_surface_add_listener(w->xdg_surface, &surface_listener, w);
+ xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
if (parentWindow && is_dialog) {
@@ -240,87 +511,63 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
}
+#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
+
+ setTitle(title);
+
+ wl_surface_set_user_data(w->wl_surface, this);
+
/* Call top-level callbacks. */
- wl_surface_commit(w->surface);
+ wl_surface_commit(w->wl_surface);
wl_display_roundtrip(m_system->display());
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ /* It's important not to return until the window is configured or
+ * calls to `setState` from Blender will crash `libdecor`. */
+ while (!w->decor_configured) {
+ if (libdecor_dispatch(m_system->decor_context(), 0) < 0) {
+ break;
+ }
+ }
+#endif
+
#ifdef GHOST_OPENGL_ALPHA
setOpaque();
#endif
+#ifndef WITH_GHOST_WAYLAND_LIBDECOR /* Causes a glitch with `libdecor` for some reason. */
setState(state);
-
- setTitle(title);
+#endif
/* EGL context. */
if (setDrawingContextType(type) == GHOST_kFailure) {
GHOST_PRINT("Failed to create EGL context" << std::endl);
}
- /* set swap interval to 0 to prevent blocking */
+ /* Set swap interval to 0 to prevent blocking. */
setSwapInterval(0);
}
-GHOST_TSuccess GHOST_WindowWayland::close()
-{
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
-}
-
-GHOST_TSuccess GHOST_WindowWayland::activate()
-{
- if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
- return GHOST_kFailure;
- }
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
-}
-
-GHOST_TSuccess GHOST_WindowWayland::deactivate()
-{
- m_system->getWindowManager()->setWindowInactive(this);
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
-}
-
-GHOST_TSuccess GHOST_WindowWayland::notify_size()
-{
-#ifdef GHOST_OPENGL_ALPHA
- setOpaque();
-#endif
-
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
-}
-
-wl_surface *GHOST_WindowWayland::surface() const
-{
- return w->surface;
-}
-
-const std::vector<output_t *> &GHOST_WindowWayland::outputs() const
-{
- return m_system->outputs();
-}
-
-std::unordered_set<const output_t *> &GHOST_WindowWayland::outputs_active()
-{
- return w->outputs;
-}
-
-uint16_t &GHOST_WindowWayland::dpi()
-{
- return w->dpi;
-}
-
-int &GHOST_WindowWayland::scale()
-{
- return w->scale;
-}
-
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
{
- return m_system->setCursorGrab(mode, m_cursorGrab, w->surface);
+ GHOST_Rect bounds_buf;
+ GHOST_Rect *bounds = nullptr;
+ if (m_cursorGrab == GHOST_kGrabWrap) {
+ if (getCursorGrabBounds(bounds_buf) == GHOST_kFailure) {
+ getClientBounds(bounds_buf);
+ }
+ bounds = &bounds_buf;
+ }
+ if (m_system->window_cursor_grab_set(mode,
+ m_cursorGrab,
+ m_cursorGrabInitPos,
+ bounds,
+ m_cursorGrabAxis,
+ w->wl_surface,
+ w->scale)) {
+ return GHOST_kSuccess;
+ }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
@@ -330,16 +577,32 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor s
return ok;
}
+bool GHOST_WindowWayland::getCursorGrabUseSoftwareDisplay()
+{
+ return m_system->getCursorGrabUseSoftwareDisplay(m_cursorGrab);
+}
+
GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape(
uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
{
return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
}
+GHOST_TSuccess GHOST_WindowWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
+{
+ return m_system->getCursorBitmap(bitmap);
+}
+
void GHOST_WindowWayland::setTitle(const char *title)
{
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_set_app_id(w->decor_frame, title);
+ libdecor_frame_set_title(w->decor_frame, title);
+#else
xdg_toplevel_set_title(w->xdg_toplevel, title);
xdg_toplevel_set_app_id(w->xdg_toplevel, title);
+#endif
+
this->title = title;
}
@@ -355,22 +618,32 @@ void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
void GHOST_WindowWayland::getClientBounds(GHOST_Rect &bounds) const
{
- bounds.set(0, 0, w->width, w->height);
+ bounds.set(0, 0, UNPACK2(w->size));
}
-GHOST_TSuccess GHOST_WindowWayland::setClientWidth(uint32_t width)
+GHOST_TSuccess GHOST_WindowWayland::setClientWidth(const uint32_t width)
{
- return setClientSize(width, uint32_t(w->height));
+ return setClientSize(width, uint32_t(w->size[1]));
}
-GHOST_TSuccess GHOST_WindowWayland::setClientHeight(uint32_t height)
+GHOST_TSuccess GHOST_WindowWayland::setClientHeight(const uint32_t height)
{
- return setClientSize(uint32_t(w->width), height);
+ return setClientSize(uint32_t(w->size[0]), height);
}
-GHOST_TSuccess GHOST_WindowWayland::setClientSize(uint32_t width, uint32_t height)
+GHOST_TSuccess GHOST_WindowWayland::setClientSize(const uint32_t width, const uint32_t height)
{
wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
+
+ /* Override any pending size that may be set. */
+ w->size_pending[0] = 0;
+ w->size_pending[1] = 0;
+
+ w->size[0] = width;
+ w->size[1] = height;
+
+ notify_size();
+
return GHOST_kSuccess;
}
@@ -397,12 +670,27 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
releaseNativeHandles();
wl_egl_window_destroy(w->egl_window);
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_unref(w->decor_frame);
+#else
if (w->xdg_toplevel_decoration) {
zxdg_toplevel_decoration_v1_destroy(w->xdg_toplevel_decoration);
}
xdg_toplevel_destroy(w->xdg_toplevel);
xdg_surface_destroy(w->xdg_surface);
- wl_surface_destroy(w->surface);
+#endif
+
+ /* Clear any pointers to this window. This is needed because there are no guarantees
+ * that flushing the display will the "leave" handlers before handling events. */
+ m_system->window_surface_unref(w->wl_surface);
+
+ wl_surface_destroy(w->wl_surface);
+
+ /* NOTE(@campbellbarton): Flushing will often run the appropriate handlers event
+ * (#wl_surface_listener.leave in particular) to avoid attempted access to the freed surfaces.
+ * This is not fool-proof though, hence the call to #window_surface_unref, see: T99078. */
+ wl_display_flush(m_system->display());
delete w;
}
@@ -424,23 +712,43 @@ GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
/* Unset states. */
switch (getState()) {
case GHOST_kWindowStateMaximized:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_unset_maximized(w->decor_frame);
+#else
xdg_toplevel_unset_maximized(w->xdg_toplevel);
+#endif
break;
case GHOST_kWindowStateFullScreen:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_unset_fullscreen(w->decor_frame);
+#else
xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+#endif
break;
default:
break;
}
break;
case GHOST_kWindowStateMaximized:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_set_maximized(w->decor_frame);
+#else
xdg_toplevel_set_maximized(w->xdg_toplevel);
+#endif
break;
case GHOST_kWindowStateMinimized:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_set_minimized(w->decor_frame);
+#else
xdg_toplevel_set_minimized(w->xdg_toplevel);
+#endif
break;
case GHOST_kWindowStateFullScreen:
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_set_fullscreen(w->decor_frame, nullptr);
+#else
xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+#endif
break;
case GHOST_kWindowStateEmbedded:
return GHOST_kFailure;
@@ -453,12 +761,10 @@ GHOST_TWindowState GHOST_WindowWayland::getState() const
if (w->is_fullscreen) {
return GHOST_kWindowStateFullScreen;
}
- else if (w->is_maximised) {
+ if (w->is_maximised) {
return GHOST_kWindowStateMaximized;
}
- else {
- return GHOST_kWindowStateNormal;
- }
+ return GHOST_kWindowStateNormal;
}
GHOST_TSuccess GHOST_WindowWayland::invalidate()
@@ -473,13 +779,21 @@ GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/)
GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const
{
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_set_fullscreen(w->decor_frame, nullptr);
+#else
xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+#endif
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const
{
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ libdecor_frame_unset_fullscreen(w->decor_frame);
+#else
xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+#endif
return GHOST_kSuccess;
}
@@ -495,7 +809,7 @@ void GHOST_WindowWayland::setOpaque() const
/* Make the window opaque. */
region = wl_compositor_create_region(m_system->compositor());
- wl_region_add(region, 0, 0, w->width, w->height);
+ wl_region_add(region, 0, 0, UNPACK2(w->size));
wl_surface_set_opaque_region(w->surface, region);
wl_region_destroy(region);
}
@@ -525,10 +839,10 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
EGL_OPENGL_API);
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
context = new GHOST_ContextEGL(this->m_system,
m_wantStereoVisual,
@@ -546,3 +860,134 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public WAYLAND Direct Data Access
+ *
+ * Expose some members via methods.
+ * \{ */
+
+uint16_t GHOST_WindowWayland::dpi() const
+{
+ return w->dpi;
+}
+
+int GHOST_WindowWayland::scale() const
+{
+ return w->scale;
+}
+
+wl_surface *GHOST_WindowWayland::surface() const
+{
+ return w->wl_surface;
+}
+
+const std::vector<output_t *> &GHOST_WindowWayland::outputs()
+{
+ return w->outputs;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public WAYLAND Window Level Functions
+ *
+ * High Level Windowing Utilities.
+ * \{ */
+
+GHOST_TSuccess GHOST_WindowWayland::close()
+{
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::activate()
+{
+ if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
+ return GHOST_kFailure;
+ }
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::deactivate()
+{
+ m_system->getWindowManager()->setWindowInactive(this);
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
+}
+
+GHOST_TSuccess GHOST_WindowWayland::notify_size()
+{
+#ifdef GHOST_OPENGL_ALPHA
+ setOpaque();
+#endif
+
+ return m_system->pushEvent(
+ new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Public WAYLAND Utility Functions
+ *
+ * Functionality only used for the WAYLAND implementation.
+ * \{ */
+
+bool GHOST_WindowWayland::outputs_changed_update_scale()
+{
+ uint32_t dpi_next;
+ const int scale_next = outputs_max_scale_or_default(this->outputs(), 0, &dpi_next);
+ if (UNLIKELY(scale_next == 0)) {
+ return false;
+ }
+
+ window_t *win = this->w;
+ const uint32_t dpi_curr = win->dpi;
+ const int scale_curr = win->scale;
+ bool changed = false;
+
+ if (scale_next != scale_curr) {
+ /* Unlikely but possible there is a pending size change is set. */
+ win->size_pending[0] = (win->size_pending[0] / scale_curr) * scale_next;
+ win->size_pending[1] = (win->size_pending[1] / scale_curr) * scale_next;
+
+ win->scale = scale_next;
+ wl_surface_set_buffer_scale(w->wl_surface, scale_next);
+ changed = true;
+ }
+
+ if (dpi_next != dpi_curr) {
+ /* Using the real DPI will cause wrong scaling of the UI
+ * use a multiplier for the default DPI as workaround. */
+ win->dpi = dpi_next;
+ changed = true;
+ }
+
+ return changed;
+}
+
+bool GHOST_WindowWayland::outputs_enter(output_t *reg_output)
+{
+ std::vector<output_t *> &outputs = w->outputs;
+ auto it = std::find(outputs.begin(), outputs.end(), reg_output);
+ if (it != outputs.end()) {
+ return false;
+ }
+ outputs.push_back(reg_output);
+ return true;
+}
+
+bool GHOST_WindowWayland::outputs_leave(output_t *reg_output)
+{
+ std::vector<output_t *> &outputs = w->outputs;
+ auto it = std::find(outputs.begin(), outputs.end(), reg_output);
+ if (it == outputs.end()) {
+ return false;
+ }
+ outputs.erase(it);
+ return true;
+}
+
+/** \} */
diff --git a/intern/ghost/intern/GHOST_WindowWayland.h b/intern/ghost/intern/GHOST_WindowWayland.h
index d5dd123014b..c754e4cd9e7 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.h
+++ b/intern/ghost/intern/GHOST_WindowWayland.h
@@ -10,14 +10,12 @@
#include "GHOST_Window.h"
-#include <unordered_set>
#include <vector>
class GHOST_SystemWayland;
struct output_t;
struct window_t;
-struct wl_surface;
class GHOST_WindowWayland : public GHOST_Window {
public:
@@ -38,27 +36,10 @@ class GHOST_WindowWayland : public GHOST_Window {
~GHOST_WindowWayland() override;
- uint16_t getDPIHint() override;
-
- GHOST_TSuccess close();
-
- GHOST_TSuccess activate();
-
- GHOST_TSuccess deactivate();
-
- GHOST_TSuccess notify_size();
-
- wl_surface *surface() const;
-
- const std::vector<output_t *> &outputs() const;
-
- std::unordered_set<const output_t *> &outputs_active();
-
- uint16_t &dpi();
+ /* Ghost API */
- int &scale();
+ uint16_t getDPIHint() override;
- protected:
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override;
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override;
@@ -70,6 +51,9 @@ class GHOST_WindowWayland : public GHOST_Window {
int hotX,
int hotY,
bool canInvertColor) override;
+ bool getCursorGrabUseSoftwareDisplay() override;
+
+ GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) override;
void setTitle(const char *title) override;
@@ -109,6 +93,27 @@ class GHOST_WindowWayland : public GHOST_Window {
void setOpaque() const;
#endif
+ /* WAYLAND direct-data access. */
+
+ uint16_t dpi() const;
+ int scale() const;
+ struct wl_surface *surface() const;
+ const std::vector<output_t *> &outputs();
+
+ /* WAYLAND window-level functions. */
+
+ GHOST_TSuccess close();
+ GHOST_TSuccess activate();
+ GHOST_TSuccess deactivate();
+ GHOST_TSuccess notify_size();
+
+ /* WAYLAND utility functions. */
+
+ bool outputs_enter(output_t *reg_output);
+ bool outputs_leave(output_t *reg_output);
+
+ bool outputs_changed_update_scale();
+
private:
GHOST_SystemWayland *m_system;
struct window_t *w;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index c958a89ac48..88731597caa 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -34,7 +34,7 @@ typedef BOOL(API *GHOST_WIN32_AdjustWindowRectExForDpi)(
struct GHOST_PointerInfoWin32 {
int32_t pointerId;
int32_t isPrimary;
- GHOST_TButtonMask buttonMask;
+ GHOST_TButton buttonMask;
POINT pixelLocation;
uint64_t time;
GHOST_TabletData tabletData;
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index e2d23ceac0b..01045c516c1 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -17,6 +17,7 @@
#include "GHOST_IconX11.h"
#include "GHOST_SystemX11.h"
#include "GHOST_WindowX11.h"
+#include "GHOST_utildefines.h"
#ifdef WITH_XDND
# include "GHOST_DropTargetX11.h"
@@ -44,19 +45,19 @@
#include <unistd.h>
#include <algorithm>
-#include <limits.h>
-#include <math.h>
+#include <climits>
+#include <cmath>
#include <string>
/* For obscure full screen mode stuff
* lifted verbatim from blut. */
-typedef struct {
+using MotifWmHints = struct {
long flags;
long functions;
long decorations;
long input_mode;
-} MotifWmHints;
+};
enum {
MWM_HINTS_FUNCTIONS = (1L << 0),
@@ -107,7 +108,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
int glx_major, glx_minor, glx_version; /* GLX version: major.minor */
int glx_attribs[64];
- *fbconfig = NULL;
+ *fbconfig = nullptr;
/* Set up the minimum attributes that we require and see if
* X can find us a visual matching those requirements. */
@@ -119,7 +120,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
__FILE__,
__LINE__);
- return NULL;
+ return nullptr;
}
glx_version = glx_major * 100 + glx_minor;
# ifndef WITH_X11_ALPHA
@@ -129,10 +130,10 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
# ifdef WITH_X11_ALPHA
if (needAlpha && glx_version >= 103 &&
(glXChooseFBConfig || (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXChooseFBConfig")) != NULL) &&
+ (const GLubyte *)"glXChooseFBConfig")) != nullptr) &&
(glXGetVisualFromFBConfig ||
(glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXGetVisualFromFBConfig")) != NULL)) {
+ (const GLubyte *)"glXGetVisualFromFBConfig")) != nullptr)) {
GHOST_X11_GL_GetAttributes(glx_attribs, 64, stereoVisual, needAlpha, true);
@@ -177,7 +178,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
/* Any sample level or even zero, which means oversampling disabled, is good
* but we need a valid visual to continue */
- if (visual != NULL) {
+ if (visual != nullptr) {
return visual;
}
}
@@ -189,7 +190,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
__FILE__,
__LINE__);
- return NULL;
+ return nullptr;
}
#endif // WITH_GL_EGL
@@ -211,8 +212,8 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
const bool is_debug)
: GHOST_Window(width, height, state, stereoVisual, exclusive),
m_display(display),
- m_visualInfo(NULL),
- m_fbconfig(NULL),
+ m_visualInfo(nullptr),
+ m_fbconfig(nullptr),
m_normal_state(GHOST_kWindowStateNormal),
m_system(system),
m_invalid_window(false),
@@ -221,11 +222,11 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
m_visible_cursor(None),
m_taskbar("blender.desktop"),
#ifdef WITH_XDND
- m_dropTarget(NULL),
+ m_dropTarget(nullptr),
#endif
m_tabletData(GHOST_TABLET_DATA_NONE),
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
- m_xic(NULL),
+ m_xic(nullptr),
#endif
m_valid_setup(false),
m_is_debug_context(is_debug)
@@ -240,13 +241,13 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
#endif
}
else {
- XVisualInfo tmp = {0};
+ XVisualInfo tmp = {nullptr};
int n;
m_visualInfo = XGetVisualInfo(m_display, 0, &tmp, &n);
}
/* caller needs to check 'getValid()' */
- if (m_visualInfo == NULL) {
+ if (m_visualInfo == nullptr) {
fprintf(stderr, "initial window could not find the GLX extension\n");
return;
}
@@ -296,7 +297,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
GHOST_PRINT("Set drop target\n");
#endif
- if (state == GHOST_kWindowStateMaximized || state == GHOST_kWindowStateFullScreen) {
+ if (ELEM(state, GHOST_kWindowStateMaximized, GHOST_kWindowStateFullScreen)) {
Atom atoms[2];
int count = 0;
if (state == GHOST_kWindowStateMaximized) {
@@ -412,7 +413,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
32,
PropModeReplace,
(unsigned char *)BLENDER_ICONS_WM_X11,
- sizeof(BLENDER_ICONS_WM_X11) / sizeof(unsigned long));
+ ARRAY_SIZE(BLENDER_ICONS_WM_X11));
}
/* set the process ID (_NET_WM_PID) */
@@ -477,7 +478,7 @@ static Bool destroyICCallback(XIC /*xic*/, XPointer ptr, XPointer /*data*/)
GHOST_PRINT("XIM input context destroyed\n");
if (ptr) {
- *(XIC *)ptr = NULL;
+ *(XIC *)ptr = nullptr;
}
/* Ignored by X11. */
return True;
@@ -505,12 +506,12 @@ bool GHOST_WindowX11::createX11_XIC()
GHOST_X11_RES_CLASS,
XNDestroyCallback,
&destroy,
- NULL);
+ nullptr);
if (!m_xic)
return false;
unsigned long fevent;
- XGetICValues(m_xic, XNFilterEvents, &fevent, NULL);
+ XGetICValues(m_xic, XNFilterEvents, &fevent, nullptr);
XSelectInput(m_display,
m_window,
ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
@@ -586,7 +587,7 @@ void GHOST_WindowX11::setTitle(const char *title)
std::string GHOST_WindowX11::getTitle() const
{
- char *name = NULL;
+ char *name = nullptr;
XFetchName(m_display, m_window, &name);
std::string title = name ? name : "untitled";
@@ -719,8 +720,9 @@ void GHOST_WindowX11::icccmSetState(int state)
{
XEvent xev;
- if (state != IconicState)
+ if (state != IconicState) {
return;
+ }
xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
@@ -737,7 +739,7 @@ void GHOST_WindowX11::icccmSetState(int state)
&xev);
}
-int GHOST_WindowX11::icccmGetState(void) const
+int GHOST_WindowX11::icccmGetState() const
{
struct {
CARD32 state;
@@ -748,7 +750,7 @@ int GHOST_WindowX11::icccmGetState(void) const
int ret, format_ret;
CARD32 st;
- prop_ret = NULL;
+ prop_ret = nullptr;
ret = XGetWindowProperty(m_display,
m_window,
m_system->m_atom.WM_STATE,
@@ -761,7 +763,7 @@ int GHOST_WindowX11::icccmGetState(void) const
&num_ret,
&bytes_after,
((unsigned char **)&prop_ret));
- if ((ret == Success) && (prop_ret != NULL) && (num_ret == 2)) {
+ if ((ret == Success) && (prop_ret != nullptr) && (num_ret == 2)) {
st = prop_ret->state;
}
else {
@@ -786,10 +788,12 @@ void GHOST_WindowX11::netwmMaximized(bool set)
xev.xclient.message_type = m_system->m_atom._NET_WM_STATE;
xev.xclient.format = 32;
- if (set == True)
+ if (set == True) {
xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- else
+ }
+ else {
xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
+ }
xev.xclient.data.l[1] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ;
xev.xclient.data.l[2] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT;
@@ -802,7 +806,7 @@ void GHOST_WindowX11::netwmMaximized(bool set)
&xev);
}
-bool GHOST_WindowX11::netwmIsMaximized(void) const
+bool GHOST_WindowX11::netwmIsMaximized() const
{
Atom *prop_ret;
unsigned long bytes_after, num_ret, i;
@@ -810,7 +814,7 @@ bool GHOST_WindowX11::netwmIsMaximized(void) const
bool st;
int format_ret, ret, count;
- prop_ret = NULL;
+ prop_ret = nullptr;
st = False;
ret = XGetWindowProperty(m_display,
m_window,
@@ -840,8 +844,9 @@ bool GHOST_WindowX11::netwmIsMaximized(void) const
}
}
- if (prop_ret)
+ if (prop_ret) {
XFree(prop_ret);
+ }
return st;
}
@@ -856,10 +861,12 @@ void GHOST_WindowX11::netwmFullScreen(bool set)
xev.xclient.message_type = m_system->m_atom._NET_WM_STATE;
xev.xclient.format = 32;
- if (set == True)
+ if (set == True) {
xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- else
+ }
+ else {
xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
+ }
xev.xclient.data.l[1] = m_system->m_atom._NET_WM_STATE_FULLSCREEN;
xev.xclient.data.l[2] = 0;
@@ -872,7 +879,7 @@ void GHOST_WindowX11::netwmFullScreen(bool set)
&xev);
}
-bool GHOST_WindowX11::netwmIsFullScreen(void) const
+bool GHOST_WindowX11::netwmIsFullScreen() const
{
Atom *prop_ret;
unsigned long bytes_after, num_ret, i;
@@ -880,7 +887,7 @@ bool GHOST_WindowX11::netwmIsFullScreen(void) const
bool st;
int format_ret, ret;
- prop_ret = NULL;
+ prop_ret = nullptr;
st = False;
ret = XGetWindowProperty(m_display,
m_window,
@@ -903,8 +910,9 @@ bool GHOST_WindowX11::netwmIsFullScreen(void) const
}
}
- if (prop_ret)
+ if (prop_ret) {
XFree(prop_ret);
+ }
return st;
}
@@ -913,10 +921,12 @@ void GHOST_WindowX11::motifFullScreen(bool set)
MotifWmHints hints;
hints.flags = MWM_HINTS_DECORATIONS;
- if (set == True)
+ if (set == True) {
hints.decorations = 0;
- else
+ }
+ else {
hints.decorations = 1;
+ }
XChangeProperty(m_display,
m_window,
@@ -928,7 +938,7 @@ void GHOST_WindowX11::motifFullScreen(bool set)
4);
}
-bool GHOST_WindowX11::motifIsFullScreen(void) const
+bool GHOST_WindowX11::motifIsFullScreen() const
{
MotifWmHints *prop_ret;
unsigned long bytes_after, num_ret;
@@ -936,7 +946,7 @@ bool GHOST_WindowX11::motifIsFullScreen(void) const
bool state;
int format_ret, st;
- prop_ret = NULL;
+ prop_ret = nullptr;
state = False;
st = XGetWindowProperty(m_display,
m_window,
@@ -952,13 +962,15 @@ bool GHOST_WindowX11::motifIsFullScreen(void) const
(unsigned char **)&prop_ret);
if ((st == Success) && prop_ret) {
if (prop_ret->flags & MWM_HINTS_DECORATIONS) {
- if (!prop_ret->decorations)
+ if (!prop_ret->decorations) {
state = True;
+ }
}
}
- if (prop_ret)
+ if (prop_ret) {
XFree(prop_ret);
+ }
return state;
}
@@ -973,14 +985,18 @@ GHOST_TWindowState GHOST_WindowX11::getState() const
* In the Iconic and Withdrawn state, the window
* is unmapped, so only need return a Minimized state.
*/
- if ((state == IconicState) || (state == WithdrawnState))
+ if (ELEM(state, IconicState, WithdrawnState)) {
state_ret = GHOST_kWindowStateMinimized;
- else if (netwmIsFullScreen() == True)
+ }
+ else if (netwmIsFullScreen() == True) {
state_ret = GHOST_kWindowStateFullScreen;
- else if (motifIsFullScreen() == True)
+ }
+ else if (motifIsFullScreen() == True) {
state_ret = GHOST_kWindowStateFullScreen;
- else if (netwmIsMaximized() == True)
+ }
+ else if (netwmIsMaximized() == True) {
state_ret = GHOST_kWindowStateMaximized;
+ }
return state_ret;
}
@@ -990,8 +1006,9 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
bool is_max, is_full, is_motif_full;
cur_state = getState();
- if (state == (int)cur_state)
+ if (state == (int)cur_state) {
return GHOST_kSuccess;
+ }
if (cur_state != GHOST_kWindowStateMinimized) {
/*
@@ -1008,16 +1025,20 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
is_motif_full = motifIsFullScreen();
- if (state == GHOST_kWindowStateNormal)
+ if (state == GHOST_kWindowStateNormal) {
state = m_normal_state;
+ }
if (state == GHOST_kWindowStateNormal) {
- if (is_max == True)
+ if (is_max == True) {
netwmMaximized(False);
- if (is_full == True)
+ }
+ if (is_full == True) {
netwmFullScreen(False);
- if (is_motif_full == True)
+ }
+ if (is_motif_full == True) {
motifFullScreen(False);
+ }
icccmSetState(NormalState);
return GHOST_kSuccess;
}
@@ -1027,17 +1048,21 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
* We can't change to full screen if the window
* isn't mapped.
*/
- if (cur_state == GHOST_kWindowStateMinimized)
+ if (cur_state == GHOST_kWindowStateMinimized) {
return GHOST_kFailure;
+ }
m_normal_state = cur_state;
- if (is_max == True)
+ if (is_max == True) {
netwmMaximized(False);
- if (is_full == False)
+ }
+ if (is_full == False) {
netwmFullScreen(True);
- if (is_motif_full == False)
+ }
+ if (is_motif_full == False) {
motifFullScreen(True);
+ }
return GHOST_kSuccess;
}
@@ -1046,15 +1071,19 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
* We can't change to Maximized if the window
* isn't mapped.
*/
- if (cur_state == GHOST_kWindowStateMinimized)
+ if (cur_state == GHOST_kWindowStateMinimized) {
return GHOST_kFailure;
+ }
- if (is_full == True)
+ if (is_full == True) {
netwmFullScreen(False);
- if (is_motif_full == True)
+ }
+ if (is_motif_full == True) {
motifFullScreen(False);
- if (is_max == False)
+ }
+ if (is_max == False) {
netwmMaximized(True);
+ }
return GHOST_kSuccess;
}
@@ -1111,8 +1140,9 @@ GHOST_TSuccess GHOST_WindowX11::setOrder(GHOST_TWindowOrder order)
XGetWindowAttributes(m_display, m_window, &attr);
/* Minimized windows give bad match error. */
- if (attr.map_state == IsViewable)
+ if (attr.map_state == IsViewable) {
XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime);
+ }
XFlush(m_display);
}
else if (order == GHOST_kWindowOrderBottom) {
@@ -1137,7 +1167,7 @@ bool GHOST_WindowX11::isDialog() const
bool st;
int format_ret, ret;
- prop_ret = NULL;
+ prop_ret = nullptr;
st = False;
ret = XGetWindowProperty(m_display,
m_window,
@@ -1272,7 +1302,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
#if defined(WITH_GL_PROFILE_CORE)
{
const char *version_major = (char *)glewGetString(GLEW_VERSION_MAJOR);
- if (version_major != NULL && version_major[0] == '1') {
+ if (version_major != nullptr && version_major[0] == '1') {
fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
abort();
}
@@ -1327,10 +1357,10 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
#ifdef WITH_GL_EGL
@@ -1358,10 +1388,10 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
/* Ugly, but we get crashes unless a whole bunch of systems are patched. */
fprintf(stderr, "Error! Unsupported graphics card or driver.\n");
@@ -1372,7 +1402,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
exit(1);
}
- return NULL;
+ return nullptr;
}
GHOST_TSuccess GHOST_WindowX11::getStandardCursor(GHOST_TStandardCursor g_cursor, Cursor &xcursor)
@@ -1485,11 +1515,12 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
{
if (mode != GHOST_kGrabDisable) {
if (mode != GHOST_kGrabNormal) {
- m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
+ m_system->getCursorPosition(UNPACK2(m_cursorGrabInitPos));
setCursorGrabAccum(0, 0);
- if (mode == GHOST_kGrabHide)
+ if (mode == GHOST_kGrabHide) {
setWindowCursorVisibility(false);
+ }
}
#ifdef GHOST_X11_GRAB
XGrabPointer(m_display,
@@ -1505,7 +1536,7 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
}
else {
if (m_cursorGrab == GHOST_kGrabHide) {
- m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
+ m_system->setCursorPosition(UNPACK2(m_cursorGrabInitPos));
}
if (m_cursorGrab != GHOST_kGrabNormal) {
@@ -1580,10 +1611,12 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCustomCursorShape(uint8_t *bitmap,
Pixmap bitmap_pix, mask_pix;
XColor fg, bg;
- if (XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0)
+ if (XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0) {
return GHOST_kFailure;
- if (XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0)
+ }
+ if (XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0) {
return GHOST_kFailure;
+ }
if (m_custom_cursor) {
XFreeCursor(m_display, m_custom_cursor);
@@ -1631,8 +1664,9 @@ GHOST_TSuccess GHOST_WindowX11::beginFullScreen() const
int err;
err = XGrabKeyboard(m_display, m_window, False, GrabModeAsync, GrabModeAsync, CurrentTime);
- if (err != GrabSuccess)
+ if (err != GrabSuccess) {
printf("XGrabKeyboard failed %d\n", err);
+ }
err = XGrabPointer(m_display,
m_window,
@@ -1643,8 +1677,9 @@ GHOST_TSuccess GHOST_WindowX11::beginFullScreen() const
m_window,
None,
CurrentTime);
- if (err != GrabSuccess)
+ if (err != GrabSuccess) {
printf("XGrabPointer failed %d\n", err);
+ }
return GHOST_kSuccess;
}
@@ -1664,7 +1699,7 @@ uint16_t GHOST_WindowX11::getDPIHint()
if (resMan) {
XrmDatabase xrdb = XrmGetStringDatabase(resMan);
if (xrdb) {
- char *type = NULL;
+ char *type = nullptr;
XrmValue val;
int success = XrmGetResource(xrdb, "Xft.dpi", "Xft.Dpi", &type, &val);
@@ -1677,7 +1712,7 @@ uint16_t GHOST_WindowX11::getDPIHint()
XrmDestroyDatabase(xrdb);
}
- /* Fallback to calculating DPI using X reported DPI, set using xrandr --dpi */
+ /* Fallback to calculating DPI using X reported DPI, set using `xrandr --dpi`. */
XWindowAttributes attr;
if (!XGetWindowAttributes(m_display, m_window, &attr)) {
/* Failed to get window attributes, return X11 default DPI */
diff --git a/intern/ghost/intern/GHOST_Wintab.cpp b/intern/ghost/intern/GHOST_Wintab.cpp
index 974a07db9c3..c75a39bb34b 100644
--- a/intern/ghost/intern/GHOST_Wintab.cpp
+++ b/intern/ghost/intern/GHOST_Wintab.cpp
@@ -310,7 +310,7 @@ void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
outWintabInfo.reserve(numPackets);
for (int i = 0; i < numPackets; i++) {
- PACKET pkt = m_pkts[i];
+ const PACKET pkt = m_pkts[i];
GHOST_WintabInfoWin32 out;
/* % 3 for multiple devices ("DualTrack"). */
@@ -367,12 +367,13 @@ void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
/* Some Wintab libraries don't handle relative button input, so we track button presses
* manually. */
DWORD buttonsChanged = m_buttons ^ pkt.pkButtons;
- WORD buttonIndex = 0;
+ /* We only needed the prior button state to compare to current, so we can overwrite it now. */
+ m_buttons = pkt.pkButtons;
- while (buttonsChanged) {
+ /* Iterate over button flag indices until all flags are clear. */
+ for (WORD buttonIndex = 0; buttonsChanged; buttonIndex++, buttonsChanged >>= 1) {
if (buttonsChanged & 1) {
- /* Find the index for the changed button from the button map. */
- GHOST_TButtonMask button = mapWintabToGhostButton(pkt.pkCursor, buttonIndex);
+ GHOST_TButton button = mapWintabToGhostButton(pkt.pkCursor, buttonIndex);
if (button != GHOST_kButtonMaskNone) {
/* If this is not the first button found, push info for the prior Wintab button. */
@@ -381,15 +382,11 @@ void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
}
out.button = button;
- out.type = buttonsChanged & pkt.pkButtons ? GHOST_kEventButtonDown :
- GHOST_kEventButtonUp;
- }
- m_buttons ^= 1 << buttonIndex;
+ DWORD buttonFlag = 1 << buttonIndex;
+ out.type = pkt.pkButtons & buttonFlag ? GHOST_kEventButtonDown : GHOST_kEventButtonUp;
+ }
}
-
- buttonsChanged >>= 1;
- buttonIndex++;
}
outWintabInfo.push_back(out);
@@ -400,7 +397,7 @@ void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
}
}
-GHOST_TButtonMask GHOST_Wintab::mapWintabToGhostButton(UINT cursor, WORD physicalButton)
+GHOST_TButton GHOST_Wintab::mapWintabToGhostButton(UINT cursor, WORD physicalButton)
{
const WORD numButtons = 32;
BYTE logicalButtons[numButtons] = {0};
diff --git a/intern/ghost/intern/GHOST_Wintab.h b/intern/ghost/intern/GHOST_Wintab.h
index 86a0143ecc0..565aeb6ca02 100644
--- a/intern/ghost/intern/GHOST_Wintab.h
+++ b/intern/ghost/intern/GHOST_Wintab.h
@@ -54,7 +54,7 @@ struct GHOST_WintabInfoWin32 {
int32_t x = 0;
int32_t y = 0;
GHOST_TEventType type = GHOST_kEventCursorMove;
- GHOST_TButtonMask button = GHOST_kButtonMaskNone;
+ GHOST_TButton button = GHOST_kButtonMaskNone;
uint64_t time = 0;
GHOST_TabletData tabletData = GHOST_TABLET_DATA_NONE;
};
@@ -187,7 +187,7 @@ class GHOST_Wintab {
bool m_focused = false;
/** Pressed button map. */
- uint8_t m_buttons = 0;
+ DWORD m_buttons = 0;
/** Range of a coordinate space. */
struct Range {
@@ -243,7 +243,7 @@ class GHOST_Wintab {
* \param physicalButton: The physical button ID to inspect.
* \return The system mapped button.
*/
- GHOST_TButtonMask mapWintabToGhostButton(UINT cursor, WORD physicalButton);
+ GHOST_TButton mapWintabToGhostButton(UINT cursor, WORD physicalButton);
/**
* Applies common modifications to Wintab context.
diff --git a/intern/ghost/intern/GHOST_XrAction.cpp b/intern/ghost/intern/GHOST_XrAction.cpp
index 587b1124848..0e725bf4075 100644
--- a/intern/ghost/intern/GHOST_XrAction.cpp
+++ b/intern/ghost/intern/GHOST_XrAction.cpp
@@ -332,23 +332,26 @@ void GHOST_XrAction::updateState(XrSession session,
break;
}
case GHOST_kXrActionTypePoseInput: {
- XrActionStatePose state{XR_TYPE_ACTION_STATE_POSE};
- CHECK_XR(
- xrGetActionStatePose(session, &state_info, &state),
- (std::string("Failed to get state for pose action \"") + action_name + "\".").data());
- if (state.isActive) {
- XrSpace pose_space = ((subaction != nullptr) && (subaction->space != nullptr)) ?
- subaction->space->getSpace() :
- XR_NULL_HANDLE;
- if (pose_space != XR_NULL_HANDLE) {
- XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
- CHECK_XR(
- xrLocateSpace(
- pose_space, reference_space, predicted_display_time, &space_location),
- (std::string("Failed to query pose space for action \"") + action_name + "\".")
- .data());
- copy_openxr_pose_to_ghost_pose(space_location.pose,
- ((GHOST_XrPose *)m_states)[subaction_idx]);
+ /* Check for valid display time to avoid an error in #xrLocateSpace(). */
+ if (predicted_display_time > 0) {
+ XrActionStatePose state{XR_TYPE_ACTION_STATE_POSE};
+ CHECK_XR(xrGetActionStatePose(session, &state_info, &state),
+ (std::string("Failed to get state for pose action \"") + action_name + "\".")
+ .data());
+ if (state.isActive) {
+ XrSpace pose_space = ((subaction != nullptr) && (subaction->space != nullptr)) ?
+ subaction->space->getSpace() :
+ XR_NULL_HANDLE;
+ if (pose_space != XR_NULL_HANDLE) {
+ XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
+ CHECK_XR(
+ xrLocateSpace(
+ pose_space, reference_space, predicted_display_time, &space_location),
+ (std::string("Failed to query pose space for action \"") + action_name + "\".")
+ .data());
+ copy_openxr_pose_to_ghost_pose(space_location.pose,
+ ((GHOST_XrPose *)m_states)[subaction_idx]);
+ }
}
}
break;
diff --git a/intern/ghost/intern/GHOST_utildefines.h b/intern/ghost/intern/GHOST_utildefines.h
new file mode 100644
index 00000000000..f0ae6e12d3e
--- /dev/null
+++ b/intern/ghost/intern/GHOST_utildefines.h
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup GHOST
+ *
+ * Utility defines (avoid depending on `BLI_utildefines.h`).
+ */
+
+#pragma once
+
+#include "GHOST_utildefines_variadic.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Branch Prediction Macros
+ * \{ */
+
+/* hints for branch prediction, only use in code that runs a _lot_ where */
+#ifdef __GNUC__
+# define LIKELY(x) __builtin_expect(!!(x), 1)
+# define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+# define LIKELY(x) (x)
+# define UNLIKELY(x) (x)
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Array Unpacking Macros
+ * \{ */
+
+/* unpack vector for args */
+#define UNPACK2(a) ((a)[0]), ((a)[1])
+#define UNPACK3(a) UNPACK2(a), ((a)[2])
+#define UNPACK4(a) UNPACK3(a), ((a)[3])
+/* pre may be '&', '*' or func, post may be '->member' */
+#define UNPACK2_EX(pre, a, post) (pre((a)[0]) post), (pre((a)[1]) post)
+#define UNPACK3_EX(pre, a, post) UNPACK2_EX(pre, a, post), (pre((a)[2]) post)
+#define UNPACK4_EX(pre, a, post) UNPACK3_EX(pre, a, post), (pre((a)[3]) post)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Array Macros
+ * \{ */
+
+/* Assuming a static array. */
+#if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__) && !defined(__INTEL_COMPILER)
+# define ARRAY_SIZE(arr) \
+ ((sizeof(struct { int isnt_array : ((const void *)&(arr) == &(arr)[0]); }) * 0) + \
+ (sizeof(arr) / sizeof(*(arr))))
+#else
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr)))
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Equal to Any Element (ELEM) Macro
+ * \{ */
+
+/* Manual line breaks for readability. */
+/* clang-format off */
+
+/* ELEM#(v, ...): is the first arg equal any others? */
+/* internal helpers. */
+#define _VA_ELEM2(v, a) ((v) == (a))
+#define _VA_ELEM3(v, a, b) \
+ (_VA_ELEM2(v, a) || _VA_ELEM2(v, b))
+#define _VA_ELEM4(v, a, b, c) \
+ (_VA_ELEM3(v, a, b) || _VA_ELEM2(v, c))
+#define _VA_ELEM5(v, a, b, c, d) \
+ (_VA_ELEM4(v, a, b, c) || _VA_ELEM2(v, d))
+#define _VA_ELEM6(v, a, b, c, d, e) \
+ (_VA_ELEM5(v, a, b, c, d) || _VA_ELEM2(v, e))
+#define _VA_ELEM7(v, a, b, c, d, e, f) \
+ (_VA_ELEM6(v, a, b, c, d, e) || _VA_ELEM2(v, f))
+#define _VA_ELEM8(v, a, b, c, d, e, f, g) \
+ (_VA_ELEM7(v, a, b, c, d, e, f) || _VA_ELEM2(v, g))
+#define _VA_ELEM9(v, a, b, c, d, e, f, g, h) \
+ (_VA_ELEM8(v, a, b, c, d, e, f, g) || _VA_ELEM2(v, h))
+#define _VA_ELEM10(v, a, b, c, d, e, f, g, h, i) \
+ (_VA_ELEM9(v, a, b, c, d, e, f, g, h) || _VA_ELEM2(v, i))
+#define _VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) \
+ (_VA_ELEM10(v, a, b, c, d, e, f, g, h, i) || _VA_ELEM2(v, j))
+#define _VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) \
+ (_VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) || _VA_ELEM2(v, k))
+#define _VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) \
+ (_VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) || _VA_ELEM2(v, l))
+#define _VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \
+ (_VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) || _VA_ELEM2(v, m))
+#define _VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
+ (_VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) || _VA_ELEM2(v, n))
+#define _VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
+ (_VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) || _VA_ELEM2(v, o))
+#define _VA_ELEM17(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
+ (_VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) || _VA_ELEM2(v, p))
+/* clang-format on */
+
+/* reusable ELEM macro */
+#define ELEM(...) VA_NARGS_CALL_OVERLOAD(_VA_ELEM, __VA_ARGS__)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clamp Macros
+ * \{ */
+
+#define CLAMPIS(a, b, c) ((a) < (b) ? (b) : (a) > (c) ? (c) : (a))
+
+#define CLAMP(a, b, c) \
+ { \
+ if ((a) < (b)) { \
+ (a) = (b); \
+ } \
+ else if ((a) > (c)) { \
+ (a) = (c); \
+ } \
+ } \
+ (void)0
+
+#define CLAMP_MAX(a, c) \
+ { \
+ if ((a) > (c)) { \
+ (a) = (c); \
+ } \
+ } \
+ (void)0
+
+#define CLAMP_MIN(a, b) \
+ { \
+ if ((a) < (b)) { \
+ (a) = (b); \
+ } \
+ } \
+ (void)0
+
+#define CLAMP2(vec, b, c) \
+ { \
+ CLAMP((vec)[0], b, c); \
+ CLAMP((vec)[1], b, c); \
+ } \
+ (void)0
+
+#define CLAMP2_MIN(vec, b) \
+ { \
+ CLAMP_MIN((vec)[0], b); \
+ CLAMP_MIN((vec)[1], b); \
+ } \
+ (void)0
+
+#define CLAMP2_MAX(vec, b) \
+ { \
+ CLAMP_MAX((vec)[0], b); \
+ CLAMP_MAX((vec)[1], b); \
+ } \
+ (void)0
+
+#define CLAMP3(vec, b, c) \
+ { \
+ CLAMP((vec)[0], b, c); \
+ CLAMP((vec)[1], b, c); \
+ CLAMP((vec)[2], b, c); \
+ } \
+ (void)0
+
+#define CLAMP3_MIN(vec, b) \
+ { \
+ CLAMP_MIN((vec)[0], b); \
+ CLAMP_MIN((vec)[1], b); \
+ CLAMP_MIN((vec)[2], b); \
+ } \
+ (void)0
+
+#define CLAMP3_MAX(vec, b) \
+ { \
+ CLAMP_MAX((vec)[0], b); \
+ CLAMP_MAX((vec)[1], b); \
+ CLAMP_MAX((vec)[2], b); \
+ } \
+ (void)0
+
+#define CLAMP4(vec, b, c) \
+ { \
+ CLAMP((vec)[0], b, c); \
+ CLAMP((vec)[1], b, c); \
+ CLAMP((vec)[2], b, c); \
+ CLAMP((vec)[3], b, c); \
+ } \
+ (void)0
+
+#define CLAMP4_MIN(vec, b) \
+ { \
+ CLAMP_MIN((vec)[0], b); \
+ CLAMP_MIN((vec)[1], b); \
+ CLAMP_MIN((vec)[2], b); \
+ CLAMP_MIN((vec)[3], b); \
+ } \
+ (void)0
+
+#define CLAMP4_MAX(vec, b) \
+ { \
+ CLAMP_MAX((vec)[0], b); \
+ CLAMP_MAX((vec)[1], b); \
+ CLAMP_MAX((vec)[2], b); \
+ CLAMP_MAX((vec)[3], b); \
+ } \
+ (void)0
+
+/** \} */
diff --git a/intern/ghost/intern/GHOST_utildefines_variadic.h b/intern/ghost/intern/GHOST_utildefines_variadic.h
new file mode 100644
index 00000000000..4ee306a27b2
--- /dev/null
+++ b/intern/ghost/intern/GHOST_utildefines_variadic.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+/* NOTE: copied from `BLI_utildefines_variadic.h` which would be a bad-level include. */
+
+/* Over wrapped args. */
+/* clang-format off */
+
+/* --- internal helpers --- */
+#define _VA_NARGS_GLUE(x, y) x y
+#define _VA_NARGS_RETURN_COUNT(\
+ _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \
+ _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \
+ _33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \
+ _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \
+ count, ...) count
+#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args
+#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count
+#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count)
+#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count)
+/* --- expose for re-use --- */
+/* 64 args max */
+#define VA_NARGS_COUNT(...) _VA_NARGS_EXPAND((__VA_ARGS__, \
+ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \
+ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
+ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+#define VA_NARGS_CALL_OVERLOAD(name, ...) \
+ _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, VA_NARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__))
+
+/* clang-format on */
diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c
index 71f3a6f43b4..46c8fda0665 100644
--- a/intern/ghost/test/gears/GHOST_C-Test.c
+++ b/intern/ghost/test/gears/GHOST_C-Test.c
@@ -31,7 +31,7 @@
#endif /* defined(WIN32) || defined(__APPLE__) */
static void gearsTimerProc(GHOST_TimerTaskHandle task, uint64_t time);
-int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData);
+bool processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData);
static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
static GLfloat fAngle = 0.0;
@@ -269,9 +269,9 @@ static void setViewPortGL(GHOST_WindowHandle hWindow)
GHOST_DisposeRectangle(hRect);
}
-int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
+bool processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
{
- int handled = 1;
+ bool handled = true;
int cursor;
int visibility;
GHOST_TEventKeyData *keyData = NULL;
@@ -389,10 +389,10 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
} break;
case GHOST_kEventWindowActivate:
- handled = 0;
+ handled = false;
break;
case GHOST_kEventWindowDeactivate:
- handled = 0;
+ handled = false;
break;
case GHOST_kEventWindowUpdate: {
GHOST_WindowHandle window2 = GHOST_GetEventWindow(hEvent);
@@ -404,7 +404,7 @@ int processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
} break;
default:
- handled = 0;
+ handled = false;
break;
}
return handled;
diff --git a/intern/ghost/test/multitest/EventToBuf.c b/intern/ghost/test/multitest/EventToBuf.c
index baab32328c3..846a867a371 100644
--- a/intern/ghost/test/multitest/EventToBuf.c
+++ b/intern/ghost/test/multitest/EventToBuf.c
@@ -218,8 +218,10 @@ void event_to_buf(GHOST_EventHandle evt, char buf[128])
case GHOST_kEventKeyUp: {
GHOST_TEventKeyData *kd = data;
pos += sprintf(pos, " - key: %s (%d)", keytype_to_string(kd->key), kd->key);
- if (kd->ascii)
- pos += sprintf(pos, " ascii: '%c' (%d)", kd->ascii, kd->ascii);
+ /* TODO: ideally this would print the unicode character. */
+ if (kd->utf8_buf[0]) {
+ pos += sprintf(pos, " ascii: '%c' (%d)", kd->utf8_buf[0], kd->utf8_buf[0]);
+ }
break;
}
}
diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c
index 35b1de65171..157e4f1b0f2 100644
--- a/intern/ghost/test/multitest/MultiTest.c
+++ b/intern/ghost/test/multitest/MultiTest.c
@@ -812,7 +812,7 @@ struct _MultiTestApp {
int exit;
};
-static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data)
+static bool multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr data)
{
MultiTestApp *app = data;
GHOST_WindowHandle win;
@@ -820,7 +820,7 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat
win = GHOST_GetEventWindow(evt);
if (win && !GHOST_ValidWindow(app->sys, win)) {
loggerwindow_log(app->logger, "WARNING: bad event, non-valid window\n");
- return 1;
+ return true;
}
if (win) {
@@ -845,7 +845,7 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat
}
}
- return 1;
+ return true;
}
/**/
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index 8cd2c9f94dd..fca19fb9731 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -55,8 +55,8 @@ extern void (*MEM_freeN)(void *vmemh);
#if 0 /* UNUSED */
/**
- * Return zero if memory is not in allocated list
- */
+ * Return zero if memory is not in allocated list
+ */
extern short (*MEM_testN)(void *vmemh);
#endif
diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
index 73912ad07b1..300e2000a14 100644
--- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c
+++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c
@@ -44,6 +44,7 @@ enum {
#define PTR_FROM_MEMHEAD(memhead) (memhead + 1)
#define MEMHEAD_ALIGNED_FROM_PTR(ptr) (((MemHeadAligned *)ptr) - 1)
#define MEMHEAD_IS_ALIGNED(memhead) ((memhead)->len & (size_t)MEMHEAD_ALIGN_FLAG)
+#define MEMHEAD_LEN(memhead) ((memhead)->len & ~((size_t)(MEMHEAD_ALIGN_FLAG)))
/* Uncomment this to have proper peak counter. */
#define USE_ATOMIC_MAX
@@ -78,8 +79,8 @@ print_error(const char *str, ...)
size_t MEM_lockfree_allocN_len(const void *vmemh)
{
- if (vmemh) {
- return MEMHEAD_FROM_PTR(vmemh)->len & ~((size_t)(MEMHEAD_ALIGN_FLAG));
+ if (LIKELY(vmemh)) {
+ return MEMHEAD_LEN(MEMHEAD_FROM_PTR(vmemh));
}
return 0;
@@ -87,14 +88,11 @@ size_t MEM_lockfree_allocN_len(const void *vmemh)
void MEM_lockfree_freeN(void *vmemh)
{
- if (leak_detector_has_run) {
+ if (UNLIKELY(leak_detector_has_run)) {
print_error("%s\n", free_after_leak_detection_message);
}
- MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
- size_t len = MEM_lockfree_allocN_len(vmemh);
-
- if (vmemh == NULL) {
+ if (UNLIKELY(vmemh == NULL)) {
print_error("Attempt to free NULL pointer\n");
#ifdef WITH_ASSERT_ABORT
abort();
@@ -102,6 +100,9 @@ void MEM_lockfree_freeN(void *vmemh)
return;
}
+ MemHead *memh = MEMHEAD_FROM_PTR(vmemh);
+ size_t len = MEMHEAD_LEN(memh);
+
atomic_sub_and_fetch_u(&totblock, 1);
atomic_sub_and_fetch_z(&mem_in_use, len);
diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
index 282fbdb3f77..fc14c909f4d 100644
--- a/intern/mantaflow/intern/MANTA_main.cpp
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -562,15 +562,66 @@ MANTA::~MANTA()
pythonCommands.push_back(finalString);
result = runPythonString(pythonCommands);
+ /* WARNING: this causes crash on exit in the `cycles_volume_cpu/smoke_color` test,
+ * freeing a single modifier ends up clearing the shared module.
+ * For this to be handled properly there would need to be a initialize/free
+ * function for global data. */
+#if 0
+ MANTA::terminateMantaflow();
+#endif
+
BLI_assert(result);
UNUSED_VARS(result);
}
/**
- * Store a pointer to the __main__ module used by mantaflow. This is necessary, because sometimes
- * Blender will overwrite that module. That happens when e.g. scripts are executed in the text
- * editor.
- *
+ * Copied from `PyC_DefaultNameSpace` in Blender.
+ * with some differences:
+ * - Doesn't touch `sys.modules`, use #manta_python_main_module_activate instead.
+ * - Returns the module instead of the modules `dict`.
+ * */
+static PyObject *manta_python_main_module_create(const char *filename)
+{
+ PyObject *builtins = PyEval_GetBuiltins();
+ PyObject *mod_main = PyModule_New("__main__");
+ PyModule_AddStringConstant(mod_main, "__name__", "__main__");
+ if (filename) {
+ /* __file__ mainly for nice UI'ness
+ * NOTE: this won't map to a real file when executing text-blocks and buttons. */
+ PyModule_AddObject(mod_main, "__file__", PyUnicode_InternFromString(filename));
+ }
+ PyModule_AddObject(mod_main, "__builtins__", builtins);
+ Py_INCREF(builtins); /* AddObject steals a reference */
+ return mod_main;
+}
+
+static void manta_python_main_module_activate(PyObject *mod_main)
+{
+ PyObject *modules = PyImport_GetModuleDict();
+ PyObject *main_mod_cmp = PyDict_GetItemString(modules, "__main__");
+ if (mod_main == main_mod_cmp) {
+ return;
+ }
+ /* NOTE: we could remove the reference to `mod_main` here, but as it's know to be removed
+ * accept that there is temporarily an extra reference. */
+ PyDict_SetItemString(modules, "__main__", mod_main);
+}
+
+static void manta_python_main_module_backup(PyObject **r_main_mod)
+{
+ PyObject *modules = PyImport_GetModuleDict();
+ *r_main_mod = PyDict_GetItemString(modules, "__main__");
+ Py_XINCREF(*r_main_mod); /* don't free */
+}
+
+static void manta_python_main_module_restore(PyObject *main_mod)
+{
+ PyObject *modules = PyImport_GetModuleDict();
+ PyDict_SetItemString(modules, "__main__", main_mod);
+ Py_XDECREF(main_mod);
+}
+
+/**
* Mantaflow stores many variables in the globals() dict of the __main__ module. To be able to
* access these variables, the same __main__ module has to be used every time.
*
@@ -579,14 +630,35 @@ MANTA::~MANTA()
*/
static PyObject *manta_main_module = nullptr;
+static void manta_python_main_module_clear()
+{
+ if (manta_main_module) {
+ Py_DECREF(manta_main_module);
+ manta_main_module = nullptr;
+ }
+}
+
+static PyObject *manta_python_main_module_ensure()
+{
+ if (!manta_main_module) {
+ manta_main_module = manta_python_main_module_create("<manta_namespace>");
+ }
+ return manta_main_module;
+}
+
bool MANTA::runPythonString(vector<string> commands)
{
bool success = true;
PyGILState_STATE gilstate = PyGILState_Ensure();
- if (manta_main_module == nullptr) {
- manta_main_module = PyImport_ImportModule("__main__");
- }
+ /* Temporarily set `sys.modules["__main__"]` as some Python modules expect this. */
+ PyObject *main_mod_backup;
+ manta_python_main_module_backup(&main_mod_backup);
+
+ /* If we never want to run this when the module isn't initialize,
+ * assign with `manta_python_main_module_ensure()`. */
+ BLI_assert(manta_main_module != nullptr);
+ manta_python_main_module_activate(manta_main_module);
for (vector<string>::iterator it = commands.begin(); it != commands.end(); ++it) {
string command = *it;
@@ -605,6 +677,9 @@ bool MANTA::runPythonString(vector<string> commands)
Py_DECREF(return_value);
}
}
+
+ manta_python_main_module_restore(main_mod_backup);
+
PyGILState_Release(gilstate);
BLI_assert(success);
@@ -622,7 +697,10 @@ void MANTA::initializeMantaflow()
/* Initialize extension classes and wrappers. */
srand(0);
PyGILState_STATE gilstate = PyGILState_Ensure();
- Pb::setup(filename, fill); /* Namespace from Mantaflow (registry). */
+
+ PyObject *manta_main_module = manta_python_main_module_ensure();
+ PyObject *globals_dict = PyModule_GetDict(manta_main_module);
+ Pb::setup(false, filename, fill, globals_dict); /* Namespace from Mantaflow (registry). */
PyGILState_Release(gilstate);
}
@@ -632,7 +710,8 @@ void MANTA::terminateMantaflow()
cout << "Fluid: Releasing Mantaflow framework" << endl;
PyGILState_STATE gilstate = PyGILState_Ensure();
- Pb::finalize(); /* Namespace from Mantaflow (registry). */
+ Pb::finalize(false); /* Namespace from Mantaflow (registry). */
+ manta_python_main_module_clear();
PyGILState_Release(gilstate);
}
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index bb3aa16a9fe..14cc6a70cd5 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -42,18 +42,6 @@ if(WITH_OPENSUBDIV)
internal/base/util.cc
internal/base/util.h
- # Device.
- internal/device/device_context_cuda.cc
- internal/device/device_context_cuda.h
- internal/device/device_context_glsl_compute.cc
- internal/device/device_context_glsl_compute.h
- internal/device/device_context_glsl_transform_feedback.cc
- internal/device/device_context_glsl_transform_feedback.h
- internal/device/device_context_opencl.cc
- internal/device/device_context_opencl.h
- internal/device/device_context_openmp.cc
- internal/device/device_context_openmp.h
-
# Evaluator.
internal/evaluator/eval_output.cc
internal/evaluator/eval_output.h
diff --git a/intern/opensubdiv/internal/base/opensubdiv_capi.cc b/intern/opensubdiv/internal/base/opensubdiv_capi.cc
index 85f8120c76b..40d820836b9 100644
--- a/intern/opensubdiv/internal/base/opensubdiv_capi.cc
+++ b/intern/opensubdiv/internal/base/opensubdiv_capi.cc
@@ -21,55 +21,15 @@
#endif
#include "internal/base/util.h"
-#include "internal/device/device_context_cuda.h"
-#include "internal/device/device_context_glsl_compute.h"
-#include "internal/device/device_context_glsl_transform_feedback.h"
-#include "internal/device/device_context_opencl.h"
-#include "internal/device/device_context_openmp.h"
-
-using blender::opensubdiv::CUDADeviceContext;
-using blender::opensubdiv::GLSLComputeDeviceContext;
-using blender::opensubdiv::GLSLTransformFeedbackDeviceContext;
-using blender::opensubdiv::OpenCLDeviceContext;
-using blender::opensubdiv::OpenMPDeviceContext;
void openSubdiv_init()
{
- // Ensure all OpenGL strings are cached.
- openSubdiv_getAvailableEvaluators();
}
void openSubdiv_cleanup()
{
}
-int openSubdiv_getAvailableEvaluators()
-{
- int flags = OPENSUBDIV_EVALUATOR_CPU;
-
- if (OpenMPDeviceContext::isSupported()) {
- flags |= OPENSUBDIV_EVALUATOR_OPENMP;
- }
-
- if (OpenCLDeviceContext::isSupported()) {
- flags |= OPENSUBDIV_EVALUATOR_OPENCL;
- }
-
- if (CUDADeviceContext::isSupported()) {
- flags |= OPENSUBDIV_EVALUATOR_CUDA;
- }
-
- if (GLSLTransformFeedbackDeviceContext::isSupported()) {
- flags |= OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK;
- }
-
- if (GLSLComputeDeviceContext::isSupported()) {
- flags |= OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
- }
-
- return flags;
-}
-
int openSubdiv_getVersionHex()
{
#if defined(OPENSUBDIV_VERSION_NUMBER)
diff --git a/intern/opensubdiv/internal/device/device_context_cuda.cc b/intern/opensubdiv/internal/device/device_context_cuda.cc
deleted file mode 100644
index cd4336265a5..00000000000
--- a/intern/opensubdiv/internal/device/device_context_cuda.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#include "internal/device/device_context_cuda.h"
-
-namespace blender {
-namespace opensubdiv {
-
-bool CUDADeviceContext::isSupported()
-{
- // TODO(sergey): Add CUDA device support, using CUDA-RT API.
- return false;
-}
-
-CUDADeviceContext::CUDADeviceContext()
-{
-}
-
-CUDADeviceContext::~CUDADeviceContext()
-{
-}
-
-} // namespace opensubdiv
-} // namespace blender
diff --git a/intern/opensubdiv/internal/device/device_context_cuda.h b/intern/opensubdiv/internal/device/device_context_cuda.h
deleted file mode 100644
index d1bfb15fbcb..00000000000
--- a/intern/opensubdiv/internal/device/device_context_cuda.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#ifndef OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_
-#define OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_
-
-namespace blender {
-namespace opensubdiv {
-
-class CUDADeviceContext {
- public:
- // Stateless check to see whether CUDA functionality is available on this
- // platform.
- static bool isSupported();
-
- CUDADeviceContext();
- ~CUDADeviceContext();
-};
-
-} // namespace opensubdiv
-} // namespace blender
-
-#endif // _OPENSUBDIV_DEVICE_CONTEXT_CUDA_H_
diff --git a/intern/opensubdiv/internal/device/device_context_glsl_compute.cc b/intern/opensubdiv/internal/device/device_context_glsl_compute.cc
deleted file mode 100644
index 7b416976099..00000000000
--- a/intern/opensubdiv/internal/device/device_context_glsl_compute.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#include "internal/device/device_context_glsl_compute.h"
-
-#include <GL/glew.h>
-
-namespace blender {
-namespace opensubdiv {
-
-bool GLSLComputeDeviceContext::isSupported()
-{
- return GLEW_VERSION_4_3 || GLEW_ARB_compute_shader;
-}
-
-GLSLComputeDeviceContext::GLSLComputeDeviceContext()
-{
-}
-
-GLSLComputeDeviceContext::~GLSLComputeDeviceContext()
-{
-}
-
-} // namespace opensubdiv
-} // namespace blender
diff --git a/intern/opensubdiv/internal/device/device_context_glsl_compute.h b/intern/opensubdiv/internal/device/device_context_glsl_compute.h
deleted file mode 100644
index f64c7d1954b..00000000000
--- a/intern/opensubdiv/internal/device/device_context_glsl_compute.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#ifndef OPENSUBDIV_DEVICE_CONTEXT_GLSL_COMPUTE_H_
-#define OPENSUBDIV_DEVICE_CONTEXT_GLSL_COMPUTE_H_
-
-namespace blender {
-namespace opensubdiv {
-
-class GLSLComputeDeviceContext {
- public:
- // Stateless check to see whether GLSL compute functionality is
- // available on this platform.
- static bool isSupported();
-
- GLSLComputeDeviceContext();
- ~GLSLComputeDeviceContext();
-};
-
-} // namespace opensubdiv
-} // namespace blender
-
-#endif // _OPENSUBDIV_DEVICE_CONTEXT_GLSL_COMPUTE_H_
diff --git a/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.cc b/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.cc
deleted file mode 100644
index ef897608b6e..00000000000
--- a/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#include "internal/device/device_context_glsl_transform_feedback.h"
-
-#include <GL/glew.h>
-
-namespace blender {
-namespace opensubdiv {
-
-bool GLSLTransformFeedbackDeviceContext::isSupported()
-{
- return GLEW_VERSION_4_1;
-}
-
-GLSLTransformFeedbackDeviceContext::GLSLTransformFeedbackDeviceContext()
-{
-}
-
-GLSLTransformFeedbackDeviceContext::~GLSLTransformFeedbackDeviceContext()
-{
-}
-
-} // namespace opensubdiv
-} // namespace blender
diff --git a/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.h b/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.h
deleted file mode 100644
index 7bbbba1380f..00000000000
--- a/intern/opensubdiv/internal/device/device_context_glsl_transform_feedback.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#ifndef OPENSUBDIV_DEVICE_CONTEXT_GLSL_TRANSFORM_FEEDBACK_H_
-#define OPENSUBDIV_DEVICE_CONTEXT_GLSL_TRANSFORM_FEEDBACK_H_
-
-namespace blender {
-namespace opensubdiv {
-
-class GLSLTransformFeedbackDeviceContext {
- public:
- // Stateless check to see whether GLSL transform feedback functionality is
- // available on this platform.
- static bool isSupported();
-
- GLSLTransformFeedbackDeviceContext();
- ~GLSLTransformFeedbackDeviceContext();
-};
-
-} // namespace opensubdiv
-} // namespace blender
-
-#endif // _OPENSUBDIV_DEVICE_CONTEXT_GLSL_TRANSFORM_FEEDBACK_H_
diff --git a/intern/opensubdiv/internal/device/device_context_opencl.cc b/intern/opensubdiv/internal/device/device_context_opencl.cc
deleted file mode 100644
index 1670ea3c9d0..00000000000
--- a/intern/opensubdiv/internal/device/device_context_opencl.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#include "internal/device/device_context_opencl.h"
-
-namespace blender {
-namespace opensubdiv {
-
-bool OpenCLDeviceContext::isSupported()
-{
- // TODO(sergey): Add support of OpenCL devices.
- return false;
-}
-
-OpenCLDeviceContext::OpenCLDeviceContext()
-{
-}
-
-OpenCLDeviceContext::~OpenCLDeviceContext()
-{
-}
-
-} // namespace opensubdiv
-} // namespace blender
diff --git a/intern/opensubdiv/internal/device/device_context_opencl.h b/intern/opensubdiv/internal/device/device_context_opencl.h
deleted file mode 100644
index 57ec6ed3bb6..00000000000
--- a/intern/opensubdiv/internal/device/device_context_opencl.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#ifndef OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_
-#define OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_
-
-namespace blender {
-namespace opensubdiv {
-
-class OpenCLDeviceContext {
- public:
- // Stateless check to see whether OpenCL functionality is available on this
- // platform.
- static bool isSupported();
-
- OpenCLDeviceContext();
- ~OpenCLDeviceContext();
-};
-
-} // namespace opensubdiv
-} // namespace blender
-
-#endif // _OPENSUBDIV_DEVICE_CONTEXT_OPENCL_H_
diff --git a/intern/opensubdiv/internal/device/device_context_openmp.cc b/intern/opensubdiv/internal/device/device_context_openmp.cc
deleted file mode 100644
index e01312fefaf..00000000000
--- a/intern/opensubdiv/internal/device/device_context_openmp.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#include "internal/device/device_context_openmp.h"
-
-namespace blender {
-namespace opensubdiv {
-
-bool OpenMPDeviceContext::isSupported()
-{
-#ifdef OPENSUBDIV_HAS_OPENMP
- return true;
-#else
- return false;
-#endif
-}
-
-OpenMPDeviceContext::OpenMPDeviceContext()
-{
-}
-
-OpenMPDeviceContext::~OpenMPDeviceContext()
-{
-}
-
-} // namespace opensubdiv
-} // namespace blender
diff --git a/intern/opensubdiv/internal/device/device_context_openmp.h b/intern/opensubdiv/internal/device/device_context_openmp.h
deleted file mode 100644
index 2bebbdf40bc..00000000000
--- a/intern/opensubdiv/internal/device/device_context_openmp.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2020 Blender Foundation. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software Foundation,
-// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//
-// Author: Sergey Sharybin
-
-#ifndef OPENSUBDIV_DEVICE_CONTEXT_OPENMP_H_
-#define OPENSUBDIV_DEVICE_CONTEXT_OPENMP_H_
-
-namespace blender {
-namespace opensubdiv {
-
-class OpenMPDeviceContext {
- public:
- // Stateless check to see whether OpenMP functionality is available on this
- // platform.
- static bool isSupported();
-
- OpenMPDeviceContext();
- ~OpenMPDeviceContext();
-};
-
-} // namespace opensubdiv
-} // namespace blender
-
-#endif // _OPENSUBDIV_DEVICE_CONTEXT_OPENMP_H_
diff --git a/intern/opensubdiv/internal/evaluator/eval_output.h b/intern/opensubdiv/internal/evaluator/eval_output.h
index c0da108edca..e8480e8d816 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output.h
+++ b/intern/opensubdiv/internal/evaluator/eval_output.h
@@ -27,6 +27,8 @@
#include "internal/base/type.h"
#include "internal/evaluator/evaluator_impl.h"
+#include "opensubdiv_evaluator_capi.h"
+
using OpenSubdiv::Far::PatchTable;
using OpenSubdiv::Far::StencilTable;
using OpenSubdiv::Osd::BufferDescriptor;
@@ -42,6 +44,8 @@ class EvalOutputAPI::EvalOutput {
public:
virtual ~EvalOutput() = default;
+ virtual void updateSettings(const OpenSubdiv_EvaluatorSettings *settings) = 0;
+
virtual void updateData(const float *src, int start_vertex, int num_vertices) = 0;
virtual void updateVaryingData(const float *src, int start_vertex, int num_vertices) = 0;
@@ -347,13 +351,13 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
- const int vertex_data_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL,
DEVICE_CONTEXT *device_context = NULL)
- : src_desc_(0, 3, 3),
+ : src_vertex_data_(NULL),
+ src_desc_(0, 3, 3),
src_varying_desc_(0, 3, 3),
- src_vertex_data_desc_(0, vertex_data_width, vertex_data_width),
+ src_vertex_data_desc_(0, 0, 0),
face_varying_width_(face_varying_width),
evaluator_cache_(evaluator_cache),
device_context_(device_context)
@@ -371,15 +375,6 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
device_context_);
- // Optionally allocate additional data to be subdivided like vertex coordinates.
- if (vertex_data_width > 0) {
- src_vertex_data_ = SRC_VERTEX_BUFFER::Create(
- vertex_data_width, num_total_vertices, device_context_);
- }
- else {
- src_vertex_data_ = NULL;
- }
-
// Create evaluators for every face varying channel.
face_varying_evaluators_.reserve(all_face_varying_stencils.size());
int face_varying_channel = 0;
@@ -407,6 +402,23 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
}
}
+ void updateSettings(const OpenSubdiv_EvaluatorSettings *settings) override
+ {
+ // Optionally allocate additional data to be subdivided like vertex coordinates.
+ if (settings->num_vertex_data != src_vertex_data_desc_.length) {
+ delete src_vertex_data_;
+ if (settings->num_vertex_data > 0) {
+ src_vertex_data_ = SRC_VERTEX_BUFFER::Create(
+ settings->num_vertex_data, src_data_->GetNumVertices(), device_context_);
+ }
+ else {
+ src_vertex_data_ = NULL;
+ }
+ src_vertex_data_desc_ = BufferDescriptor(
+ 0, settings->num_vertex_data, settings->num_vertex_data);
+ }
+ }
+
// TODO(sergey): Implement binding API.
void updateData(const float *src, int start_vertex, int num_vertices) override
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_cpu.h b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h
index 35fd03f6158..42aa052863a 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output_cpu.h
+++ b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h
@@ -44,7 +44,6 @@ class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
- const int vertex_data_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL)
: VolatileEvalOutput<CpuVertexBuffer,
@@ -55,7 +54,6 @@ class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
varying_stencils,
all_face_varying_stencils,
face_varying_width,
- vertex_data_width,
patch_table,
evaluator_cache)
{
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
index 274772b2c37..b85272008e6 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
+++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
@@ -45,7 +45,6 @@ GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
- const int vertex_data_width,
const PatchTable *patch_table,
VolatileEvalOutput::EvaluatorCache *evaluator_cache)
: VolatileEvalOutput<GLVertexBuffer,
@@ -56,7 +55,6 @@ GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils,
varying_stencils,
all_face_varying_stencils,
face_varying_width,
- vertex_data_width,
patch_table,
evaluator_cache)
{
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
index 8a4950dd3bc..e65bd51cac0 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
+++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
@@ -40,7 +40,6 @@ class GpuEvalOutput : public VolatileEvalOutput<GLVertexBuffer,
const StencilTable *varying_stencils,
const vector<const StencilTable *> &all_face_varying_stencils,
const int face_varying_width,
- const int vertex_data_width,
const PatchTable *patch_table,
EvaluatorCache *evaluator_cache = NULL);
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc
index 2fffcefa460..efac0926fef 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc
@@ -30,7 +30,7 @@ OpenSubdiv_EvaluatorCacheImpl::~OpenSubdiv_EvaluatorCacheImpl()
OpenSubdiv_EvaluatorCacheImpl *openSubdiv_createEvaluatorCacheInternal(
eOpenSubdivEvaluator evaluator_type)
{
- if (evaluator_type != eOpenSubdivEvaluator::OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) {
+ if (evaluator_type != eOpenSubdivEvaluator::OPENSUBDIV_EVALUATOR_GPU) {
return nullptr;
}
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache;
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
index 5a3a2ff131c..7f30e0e5660 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
@@ -28,6 +28,12 @@
namespace {
+void setSettings(struct OpenSubdiv_Evaluator *evaluator,
+ const OpenSubdiv_EvaluatorSettings *settings)
+{
+ evaluator->impl->eval_output->setSettings(settings);
+}
+
void setCoarsePositions(OpenSubdiv_Evaluator *evaluator,
const float *positions,
const int start_vertex_index,
@@ -233,6 +239,8 @@ bool hasVertexData(struct OpenSubdiv_Evaluator *evaluator)
void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
{
+ evaluator->setSettings = setSettings;
+
evaluator->setCoarsePositions = setCoarsePositions;
evaluator->setVertexData = setVertexData;
evaluator->setVaryingData = setVaryingData;
@@ -272,16 +280,12 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
- OpenSubdiv_EvaluatorCache *evaluator_cache,
- const OpenSubdiv_EvaluatorSettings *settings)
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
{
OpenSubdiv_Evaluator *evaluator = MEM_new<OpenSubdiv_Evaluator>(__func__);
assignFunctionPointers(evaluator);
- evaluator->impl = openSubdiv_createEvaluatorInternal(topology_refiner,
- evaluator_type,
- evaluator_cache ? evaluator_cache->impl :
- nullptr,
- settings);
+ evaluator->impl = openSubdiv_createEvaluatorInternal(
+ topology_refiner, evaluator_type, evaluator_cache ? evaluator_cache->impl : nullptr);
evaluator->type = evaluator->impl ? evaluator_type : static_cast<eOpenSubdivEvaluator>(0);
return evaluator;
}
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
index a5273cad13a..262b418169d 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
@@ -166,6 +166,11 @@ EvalOutputAPI::~EvalOutputAPI()
delete implementation_;
}
+void EvalOutputAPI::setSettings(const OpenSubdiv_EvaluatorSettings *settings)
+{
+ implementation_->updateSettings(settings);
+}
+
void EvalOutputAPI::setCoarsePositions(const float *positions,
const int start_vertex_index,
const int num_vertices)
@@ -435,14 +440,8 @@ OpenSubdiv_EvaluatorImpl::~OpenSubdiv_EvaluatorImpl()
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
- OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr,
- const OpenSubdiv_EvaluatorSettings *settings)
+ OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr)
{
- // Only CPU and GLCompute are implemented at the moment.
- if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU &&
- evaluator_type != OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) {
- return NULL;
- }
using blender::opensubdiv::vector;
TopologyRefiner *refiner = topology_refiner->impl->topology_refiner;
if (refiner == NULL) {
@@ -455,7 +454,6 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
const bool has_face_varying_data = (num_face_varying_channels != 0);
const int level = topology_refiner->getSubdivisionLevel(topology_refiner);
const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner);
- const int vertex_data_width = settings->num_vertex_data;
// Common settings for stencils and patches.
const bool stencil_generate_intermediate_levels = is_adaptive;
const bool stencil_generate_offsets = true;
@@ -548,8 +546,8 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
// Create OpenSubdiv's CPU side evaluator.
blender::opensubdiv::EvalOutputAPI::EvalOutput *eval_output = nullptr;
- const bool use_gl_evaluator = evaluator_type == OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
- if (use_gl_evaluator) {
+ const bool use_gpu_evaluator = evaluator_type == OPENSUBDIV_EVALUATOR_GPU;
+ if (use_gpu_evaluator) {
blender::opensubdiv::GpuEvalOutput::EvaluatorCache *evaluator_cache = nullptr;
if (evaluator_cache_descr) {
evaluator_cache = static_cast<blender::opensubdiv::GpuEvalOutput::EvaluatorCache *>(
@@ -560,17 +558,12 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
varying_stencils,
all_face_varying_stencils,
2,
- vertex_data_width,
patch_table,
evaluator_cache);
}
else {
- eval_output = new blender::opensubdiv::CpuEvalOutput(vertex_stencils,
- varying_stencils,
- all_face_varying_stencils,
- 2,
- vertex_data_width,
- patch_table);
+ eval_output = new blender::opensubdiv::CpuEvalOutput(
+ vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table);
}
blender::opensubdiv::PatchMap *patch_map = new blender::opensubdiv::PatchMap(*patch_table);
@@ -581,7 +574,7 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
evaluator_descr->eval_output = new blender::opensubdiv::EvalOutputAPI(eval_output, patch_map);
evaluator_descr->patch_map = patch_map;
evaluator_descr->patch_table = patch_table;
- // TOOD(sergey): Look into whether we've got duplicated stencils arrays.
+ // TODO(sergey): Look into whether we've got duplicated stencils arrays.
delete vertex_stencils;
delete varying_stencils;
for (const StencilTable *table : all_face_varying_stencils) {
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
index df8ef70cc01..a7e3d5dff59 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.h
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
@@ -57,6 +57,9 @@ class EvalOutputAPI {
~EvalOutputAPI();
+ // Set settings for data buffers.
+ void setSettings(const OpenSubdiv_EvaluatorSettings *settings);
+
// Set coarse positions from a continuous array of coordinates.
void setCoarsePositions(const float *positions,
const int start_vertex_index,
@@ -210,8 +213,7 @@ struct OpenSubdiv_EvaluatorImpl {
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
struct OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
- OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr,
- const OpenSubdiv_EvaluatorSettings *settings);
+ OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr);
void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator);
diff --git a/intern/opensubdiv/internal/evaluator/gl_compute_evaluator.cc b/intern/opensubdiv/internal/evaluator/gl_compute_evaluator.cc
index acf628c7035..c2ab2a522d2 100644
--- a/intern/opensubdiv/internal/evaluator/gl_compute_evaluator.cc
+++ b/intern/opensubdiv/internal/evaluator/gl_compute_evaluator.cc
@@ -396,6 +396,8 @@ bool GLComputeEvaluator::EvalStencils(GLuint srcBuffer,
if (dvvWeightsBuffer)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 15, dvvWeightsBuffer);
+ GLint activeProgram;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
glUseProgram(_stencilKernel.program);
glUniform1i(_stencilKernel.uniformStart, start);
@@ -420,7 +422,7 @@ bool GLComputeEvaluator::EvalStencils(GLuint srcBuffer,
DispatchCompute(count);
- glUseProgram(0);
+ glUseProgram(activeProgram);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
for (int i = 0; i < 16; ++i) {
@@ -501,6 +503,8 @@ bool GLComputeEvaluator::EvalPatches(GLuint srcBuffer,
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, patchIndexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, patchParamsBuffer);
+ GLint activeProgram;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &activeProgram);
glUseProgram(_patchKernel.program);
glUniform1i(_patchKernel.uniformSrcOffset, srcDesc.offset);
@@ -534,7 +538,7 @@ bool GLComputeEvaluator::EvalPatches(GLuint srcBuffer,
DispatchCompute(numPatchCoords);
- glUseProgram(0);
+ glUseProgram(activeProgram);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0);
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index a26ea36b863..1fa75a9a8c2 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -31,9 +31,6 @@ extern "C" {
void openSubdiv_init(void);
void openSubdiv_cleanup(void);
-// Bitmask of eOpenSubdivEvaluator.
-int openSubdiv_getAvailableEvaluators(void);
-
int openSubdiv_getVersionHex(void);
#ifdef __cplusplus
diff --git a/intern/opensubdiv/opensubdiv_capi_type.h b/intern/opensubdiv/opensubdiv_capi_type.h
index e78842036be..585d9bc49df 100644
--- a/intern/opensubdiv/opensubdiv_capi_type.h
+++ b/intern/opensubdiv/opensubdiv_capi_type.h
@@ -23,15 +23,9 @@
extern "C" {
#endif
-// Keep this a bitmask so it's possible to pass available
-// evaluators to Blender.
typedef enum eOpenSubdivEvaluator {
- OPENSUBDIV_EVALUATOR_CPU = (1 << 0),
- OPENSUBDIV_EVALUATOR_OPENMP = (1 << 1),
- OPENSUBDIV_EVALUATOR_OPENCL = (1 << 2),
- OPENSUBDIV_EVALUATOR_CUDA = (1 << 3),
- OPENSUBDIV_EVALUATOR_GLSL_TRANSFORM_FEEDBACK = (1 << 4),
- OPENSUBDIV_EVALUATOR_GLSL_COMPUTE = (1 << 5),
+ OPENSUBDIV_EVALUATOR_CPU = 0,
+ OPENSUBDIV_EVALUATOR_GPU = 1,
} eOpenSubdivEvaluator;
typedef enum OpenSubdiv_SchemeType {
diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h
index 094244c4681..6d94141e755 100644
--- a/intern/opensubdiv/opensubdiv_evaluator_capi.h
+++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h
@@ -31,6 +31,11 @@ struct OpenSubdiv_EvaluatorInternal;
struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
+typedef struct OpenSubdiv_EvaluatorSettings {
+ // Number of smoothly interpolated vertex data channels.
+ int num_vertex_data;
+} OpenSubdiv_EvaluatorSettings;
+
// Callback type for doing input/output operations on buffers.
// Useful to abstract GPU buffers.
typedef struct OpenSubdiv_Buffer {
@@ -64,6 +69,10 @@ typedef struct OpenSubdiv_Buffer {
} OpenSubdiv_Buffer;
typedef struct OpenSubdiv_Evaluator {
+ // Set settings for data buffers used.
+ void (*setSettings)(struct OpenSubdiv_Evaluator *evaluator,
+ const OpenSubdiv_EvaluatorSettings *settings);
+
// Set coarse positions from a continuous array of coordinates.
void (*setCoarsePositions)(struct OpenSubdiv_Evaluator *evaluator,
const float *positions,
@@ -234,16 +243,10 @@ typedef struct OpenSubdiv_EvaluatorCache {
struct OpenSubdiv_EvaluatorCacheImpl *impl;
} OpenSubdiv_EvaluatorCache;
-typedef struct OpenSubdiv_EvaluatorSettings {
- // Number of smoothly interpolated vertex data channels.
- int num_vertex_data;
-} OpenSubdiv_EvaluatorSettings;
-
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
struct OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
- OpenSubdiv_EvaluatorCache *evaluator_cache,
- const OpenSubdiv_EvaluatorSettings *settings);
+ OpenSubdiv_EvaluatorCache *evaluator_cache);
void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator);
diff --git a/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc b/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc
index 78c1d23d2cc..bc39326b57d 100644
--- a/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc
+++ b/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc
@@ -23,8 +23,7 @@
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
struct OpenSubdiv_TopologyRefiner * /*topology_refiner*/,
eOpenSubdivEvaluator /*evaluator_type*/,
- OpenSubdiv_EvaluatorCache * /*evaluator_cache*/,
- const OpenSubdiv_EvaluatorSettings * /*settings*/)
+ OpenSubdiv_EvaluatorCache * /*evaluator_cache*/)
{
return NULL;
}
diff --git a/intern/opensubdiv/stub/opensubdiv_stub.cc b/intern/opensubdiv/stub/opensubdiv_stub.cc
index 24bdcbc79ff..5eaa2df9a27 100644
--- a/intern/opensubdiv/stub/opensubdiv_stub.cc
+++ b/intern/opensubdiv/stub/opensubdiv_stub.cc
@@ -28,11 +28,6 @@ void openSubdiv_cleanup()
{
}
-int openSubdiv_getAvailableEvaluators()
-{
- return 0;
-}
-
int openSubdiv_getVersionHex()
{
return 0;
diff --git a/intern/sky/include/sky_model.h b/intern/sky/include/sky_model.h
index 021bd0d9ae6..75770f8115c 100644
--- a/intern/sky/include/sky_model.h
+++ b/intern/sky/include/sky_model.h
@@ -25,7 +25,7 @@ Version history:
1.4a February 22nd, 2013
Removed unnecessary and counter-intuitive solar radius parameters
- from the interface of the colourspace sky dome initialisation functions.
+ from the interface of the colourspace sky dome initialization functions.
1.4 February 11th, 2013
Fixed a bug which caused the relative brightness of the solar disc
@@ -76,7 +76,7 @@ Usage information:
==================
-Model initialisation
+Model initialization
--------------------
A separate ArHosekSkyModelState has to be maintained for each spectral
@@ -101,12 +101,12 @@ is given in radians.
solarElevation
);
-Note that starting with version 1.3, there is also a second initialisation
+Note that starting with version 1.3, there is also a second initialization
function which generates skydome states for different solar emission spectra
and solar radii: 'arhosekskymodelstate_alienworld_alloc_init()'.
See the notes about the "Alien World" functionality provided further down for a
-discussion of the usefulness and limits of that second initialisation function.
+discussion of the usefulness and limits of that second initialization function.
Sky model states that have been initialized with either function behave in a
completely identical fashion during use and cleanup.
@@ -236,7 +236,7 @@ CAVEAT #3: you have to provide a value for the solar intensity of the star
fairly different in size from it, to still provide a reasonable and
inhabitable amount of irradiance. Red stars will need to be much
larger than our sun, while white or blue stars will have to be
- comparatively tiny. The initialisation function handles this and
+ comparatively tiny. The initialization function handles this and
computes a plausible solar radius for a given emission spectrum. In
terms of absolute radiometric values, you should probably not stray
all too far from a solar intensity value of 1.0.
diff --git a/intern/sky/source/sky_model.cpp b/intern/sky/source/sky_model.cpp
index f70a2a7588c..d67fe08772d 100644
--- a/intern/sky/source/sky_model.cpp
+++ b/intern/sky/source/sky_model.cpp
@@ -25,7 +25,7 @@ Version history:
1.4a February 22nd, 2013
Removed unnecessary and counter-intuitive solar radius parameters
- from the interface of the colourspace sky dome initialisation functions.
+ from the interface of the color-space sky dome initialization functions.
1.4 February 11th, 2013
Fixed a bug which caused the relative brightness of the solar disc
diff --git a/intern/sky/source/sky_model_data.h b/intern/sky/source/sky_model_data.h
index f8398e0839c..6ed763951ee 100644
--- a/intern/sky/source/sky_model_data.h
+++ b/intern/sky/source/sky_model_data.h
@@ -25,7 +25,7 @@ Version history:
1.4a February 22nd, 2013
Removed unnecessary and counter-intuitive solar radius parameters
- from the interface of the colourspace sky dome initialisation functions.
+ from the interface of the color-space sky dome initialization functions.
1.4 February 11th, 2013
Fixed a bug which caused the relative brightness of the solar disc
diff --git a/intern/wayland_dynload/CMakeLists.txt b/intern/wayland_dynload/CMakeLists.txt
new file mode 100644
index 00000000000..2b1a6370126
--- /dev/null
+++ b/intern/wayland_dynload/CMakeLists.txt
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(INC
+ extern
+
+ # For internal includes.
+ intern
+)
+
+set(INC_SYS
+ ${wayland-client_INCLUDE_DIRS}
+ ${wayland-egl_INCLUDE_DIRS}
+ ${wayland-cursor_INCLUDE_DIRS}
+)
+
+set(SRC
+ intern/wayland_dynload_client.c
+ intern/wayland_dynload_cursor.c
+ intern/wayland_dynload_egl.c
+ intern/wayland_dynload_utils.c
+
+ extern/wayland_dynload_API.h
+ extern/wayland_dynload_client.h
+ extern/wayland_dynload_cursor.h
+ extern/wayland_dynload_egl.h
+ intern/wayland_dynload_utils.h
+)
+
+if(WITH_GHOST_WAYLAND_LIBDECOR)
+ list(APPEND INC_SYS
+ ${libdecor_INCLUDE_DIRS}
+ )
+ list(APPEND SRC
+ intern/wayland_dynload_libdecor.c
+
+ extern/wayland_dynload_libdecor.h
+ )
+endif()
+
+set(LIB
+)
+
+
+blender_add_lib(bf_intern_wayland_dynload "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/intern/wayland_dynload/extern/wayland_dynload_API.h b/intern/wayland_dynload/extern/wayland_dynload_API.h
new file mode 100644
index 00000000000..07ff00b5a76
--- /dev/null
+++ b/intern/wayland_dynload/extern/wayland_dynload_API.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+
+bool wayland_dynload_client_init(bool verbose);
+void wayland_dynload_client_exit(void);
+
+bool wayland_dynload_cursor_init(bool verbose);
+void wayland_dynload_cursor_exit(void);
+
+bool wayland_dynload_egl_init(bool verbose);
+void wayland_dynload_egl_exit(void);
+
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+bool wayland_dynload_libdecor_init(bool verbose);
+void wayland_dynload_libdecor_exit(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/wayland_dynload/extern/wayland_dynload_client.h b/intern/wayland_dynload/extern/wayland_dynload_client.h
new file mode 100644
index 00000000000..8e9dddd91a3
--- /dev/null
+++ b/intern/wayland_dynload/extern/wayland_dynload_client.h
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Wrapper functions for `<wayland-client.h>`.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WAYLAND_DYNLOAD_FN
+WAYLAND_DYNLOAD_FN(wl_display_connect)
+WAYLAND_DYNLOAD_FN(wl_display_disconnect)
+WAYLAND_DYNLOAD_FN(wl_display_dispatch)
+WAYLAND_DYNLOAD_FN(wl_display_roundtrip)
+WAYLAND_DYNLOAD_FN(wl_display_flush)
+WAYLAND_DYNLOAD_FN(wl_log_set_handler_client)
+WAYLAND_DYNLOAD_FN(wl_proxy_add_listener)
+WAYLAND_DYNLOAD_FN(wl_proxy_destroy)
+WAYLAND_DYNLOAD_FN(wl_proxy_marshal_flags)
+WAYLAND_DYNLOAD_FN(wl_proxy_marshal_array_flags)
+WAYLAND_DYNLOAD_FN(wl_proxy_set_user_data)
+WAYLAND_DYNLOAD_FN(wl_proxy_get_user_data)
+WAYLAND_DYNLOAD_FN(wl_proxy_get_version)
+WAYLAND_DYNLOAD_FN(wl_proxy_get_tag)
+WAYLAND_DYNLOAD_FN(wl_proxy_set_tag)
+#elif defined(WAYLAND_DYNLOAD_IFACE)
+WAYLAND_DYNLOAD_IFACE(wl_buffer_interface)
+WAYLAND_DYNLOAD_IFACE(wl_compositor_interface)
+WAYLAND_DYNLOAD_IFACE(wl_data_device_interface)
+WAYLAND_DYNLOAD_IFACE(wl_data_device_manager_interface)
+WAYLAND_DYNLOAD_IFACE(wl_data_source_interface)
+WAYLAND_DYNLOAD_IFACE(wl_keyboard_interface)
+WAYLAND_DYNLOAD_IFACE(wl_output_interface)
+WAYLAND_DYNLOAD_IFACE(wl_pointer_interface)
+WAYLAND_DYNLOAD_IFACE(wl_region_interface)
+WAYLAND_DYNLOAD_IFACE(wl_registry_interface)
+WAYLAND_DYNLOAD_IFACE(wl_seat_interface)
+WAYLAND_DYNLOAD_IFACE(wl_shm_interface)
+WAYLAND_DYNLOAD_IFACE(wl_shm_pool_interface)
+WAYLAND_DYNLOAD_IFACE(wl_surface_interface)
+#else
+
+/* Header guard. */
+# if !defined(__WAYLAND_DYNLOAD_CLIENT_H__) && !defined(WAYLAND_DYNLOAD_VALIDATE)
+# define __WAYLAND_DYNLOAD_CLIENT_H__
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# include <wayland-client-core.h>
+extern struct WaylandDynload_Client wayland_dynload_client;
+# endif
+
+/* Support validating declarations against the header. */
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# define WL_DYN_FN(a) (*a)
+# else
+# define WL_DYN_FN(a) (a)
+# endif
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+struct WaylandDynload_Client {
+# endif
+ struct wl_display *WL_DYN_FN(wl_display_connect)(const char *name);
+ void WL_DYN_FN(wl_display_disconnect)(struct wl_display *display);
+ int WL_DYN_FN(wl_display_dispatch)(struct wl_display *display);
+ int WL_DYN_FN(wl_display_roundtrip)(struct wl_display *display);
+ int WL_DYN_FN(wl_display_flush)(struct wl_display *display);
+ void WL_DYN_FN(wl_log_set_handler_client)(wl_log_func_t);
+ int WL_DYN_FN(wl_proxy_add_listener)(struct wl_proxy *proxy,
+ void (**implementation)(void),
+ void *data);
+ void WL_DYN_FN(wl_proxy_destroy)(struct wl_proxy *proxy);
+ struct wl_proxy *WL_DYN_FN(wl_proxy_marshal_flags)(struct wl_proxy *proxy,
+ uint32_t opcode,
+ const struct wl_interface *interface,
+ uint32_t version,
+ uint32_t flags,
+ ...);
+ struct wl_proxy *WL_DYN_FN(wl_proxy_marshal_array_flags)(struct wl_proxy *proxy,
+ uint32_t opcode,
+ const struct wl_interface *interface,
+ uint32_t version,
+ uint32_t flags,
+ union wl_argument *args);
+ void WL_DYN_FN(wl_proxy_set_user_data)(struct wl_proxy *proxy, void *user_data);
+ void *WL_DYN_FN(wl_proxy_get_user_data)(struct wl_proxy *proxy);
+ uint32_t WL_DYN_FN(wl_proxy_get_version)(struct wl_proxy *proxy);
+ const char *const *WL_DYN_FN(wl_proxy_get_tag)(struct wl_proxy *proxy);
+ void WL_DYN_FN(wl_proxy_set_tag)(struct wl_proxy *proxy, const char *const *tag);
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+};
+# endif
+# undef WL_DYN_FN
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# define wl_display_connect(...) (*wayland_dynload_client.wl_display_connect)(__VA_ARGS__)
+# define wl_display_disconnect(...) \
+ (*wayland_dynload_client.wl_display_disconnect)(__VA_ARGS__)
+# define wl_display_dispatch(...) (*wayland_dynload_client.wl_display_dispatch)(__VA_ARGS__)
+# define wl_display_roundtrip(...) (*wayland_dynload_client.wl_display_roundtrip)(__VA_ARGS__)
+# define wl_display_flush(...) (*wayland_dynload_client.wl_display_flush)(__VA_ARGS__)
+# define wl_log_set_handler_client(...) \
+ (*wayland_dynload_client.wl_log_set_handler_client)(__VA_ARGS__)
+# define wl_proxy_add_listener(...) \
+ (*wayland_dynload_client.wl_proxy_add_listener)(__VA_ARGS__)
+# define wl_proxy_destroy(...) (*wayland_dynload_client.wl_proxy_destroy)(__VA_ARGS__)
+# define wl_proxy_marshal_flags(...) \
+ (*wayland_dynload_client.wl_proxy_marshal_flags)(__VA_ARGS__)
+# define wl_proxy_marshal_array_flags(...) \
+ (*wayland_dynload_client.wl_proxy_marshal_array_flags)(__VA_ARGS__)
+# define wl_proxy_set_user_data(...) \
+ (*wayland_dynload_client.wl_proxy_set_user_data)(__VA_ARGS__)
+# define wl_proxy_get_user_data(...) \
+ (*wayland_dynload_client.wl_proxy_get_user_data)(__VA_ARGS__)
+# define wl_proxy_get_version(...) (*wayland_dynload_client.wl_proxy_get_version)(__VA_ARGS__)
+# define wl_proxy_get_tag(...) (*wayland_dynload_client.wl_proxy_get_tag)(__VA_ARGS__)
+# define wl_proxy_set_tag(...) (*wayland_dynload_client.wl_proxy_set_tag)(__VA_ARGS__)
+
+# endif /* !WAYLAND_DYNLOAD_VALIDATE */
+# endif /* !defined(__WAYLAND_DYNLOAD_CLIENT_H__) && !defined(WAYLAND_DYNLOAD_VALIDATE) */
+#endif /* !defined(WAYLAND_DYNLOAD_FN) && !defined(WAYLAND_DYNLOAD_IFACE) */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/wayland_dynload/extern/wayland_dynload_cursor.h b/intern/wayland_dynload/extern/wayland_dynload_cursor.h
new file mode 100644
index 00000000000..3c444069a43
--- /dev/null
+++ b/intern/wayland_dynload/extern/wayland_dynload_cursor.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Wrapper functions for `<wayland-cursor.h>`.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WAYLAND_DYNLOAD_FN
+WAYLAND_DYNLOAD_FN(wl_cursor_theme_load)
+WAYLAND_DYNLOAD_FN(wl_cursor_theme_destroy)
+WAYLAND_DYNLOAD_FN(wl_cursor_theme_get_cursor)
+WAYLAND_DYNLOAD_FN(wl_cursor_image_get_buffer)
+WAYLAND_DYNLOAD_FN(wl_cursor_frame)
+WAYLAND_DYNLOAD_FN(wl_cursor_frame_and_duration)
+#elif defined(WAYLAND_DYNLOAD_IFACE)
+/* No interfaces. */
+#else
+
+/* Header guard. */
+# if !defined(__WAYLAND_DYNLOAD_CURSOR_H__) && !defined(WAYLAND_DYNLOAD_VALIDATE)
+# define __WAYLAND_DYNLOAD_CURSOR_H__
+
+# include <wayland-cursor.h>
+extern struct WaylandDynload_Cursor wayland_dynload_cursor;
+
+/* Support validating declarations against the header. */
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# define WL_DYN_FN(a) (*a)
+# else
+# define WL_DYN_FN(a) (a)
+# endif
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+struct WaylandDynload_Cursor {
+# endif
+
+ struct wl_cursor_theme *WL_DYN_FN(wl_cursor_theme_load)(const char *name,
+ int size,
+ struct wl_shm *shm);
+ void WL_DYN_FN(wl_cursor_theme_destroy)(struct wl_cursor_theme *theme);
+ struct wl_cursor *WL_DYN_FN(wl_cursor_theme_get_cursor)(struct wl_cursor_theme *theme,
+ const char *name);
+ struct wl_buffer *WL_DYN_FN(wl_cursor_image_get_buffer)(struct wl_cursor_image *image);
+ int WL_DYN_FN(wl_cursor_frame)(struct wl_cursor *cursor, uint32_t time);
+ int WL_DYN_FN(wl_cursor_frame_and_duration)(struct wl_cursor *cursor,
+ uint32_t time,
+ uint32_t *duration);
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+};
+# endif
+# undef WL_DYN_FN
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# define wl_cursor_theme_load(...) (*wayland_dynload_cursor.wl_cursor_theme_load)(__VA_ARGS__)
+# define wl_cursor_theme_destroy(...) \
+ (*wayland_dynload_cursor.wl_cursor_theme_destroy)(__VA_ARGS__)
+# define wl_cursor_theme_get_cursor(...) \
+ (*wayland_dynload_cursor.wl_cursor_theme_get_cursor)(__VA_ARGS__)
+# define wl_cursor_image_get_buffer(...) \
+ (*wayland_dynload_cursor.wl_cursor_image_get_buffer)(__VA_ARGS__)
+# define wl_cursor_frame(...) (*wayland_dynload_cursor.wl_cursor_frame)(__VA_ARGS__)
+# define wl_cursor_frame_and_duration(...) \
+ (*wayland_dynload_cursor.wl_cursor_frame_and_duration)(__VA_ARGS__)
+# endif /* !WAYLAND_DYNLOAD_VALIDATE */
+# endif /* !__WAYLAND_DYNLOAD_CLIENT_H__ */
+#endif /* !defined(WAYLAND_DYNLOAD_FN) && !defined(WAYLAND_DYNLOAD_IFACE) */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/wayland_dynload/extern/wayland_dynload_egl.h b/intern/wayland_dynload/extern/wayland_dynload_egl.h
new file mode 100644
index 00000000000..3829ac83301
--- /dev/null
+++ b/intern/wayland_dynload/extern/wayland_dynload_egl.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Wrapper functions for `<wayland-egl.h>`.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WAYLAND_DYNLOAD_FN
+WAYLAND_DYNLOAD_FN(wl_egl_window_create)
+WAYLAND_DYNLOAD_FN(wl_egl_window_destroy)
+WAYLAND_DYNLOAD_FN(wl_egl_window_resize)
+WAYLAND_DYNLOAD_FN(wl_egl_window_get_attached_size)
+#elif defined(WAYLAND_DYNLOAD_IFACE)
+/* No interfaces. */
+#else
+
+/* Header guard. */
+# if !defined(__WAYLAND_DYNLOAD_EGL_H__) && !defined(WAYLAND_DYNLOAD_VALIDATE)
+# define __WAYLAND_DYNLOAD_EGL_H__
+
+# include <wayland-egl-core.h>
+extern struct WaylandDynload_EGL wayland_dynload_egl;
+
+/* Support validating declarations against the header. */
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# define WL_DYN_FN(a) (*a)
+# else
+# define WL_DYN_FN(a) (a)
+# endif
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+struct WaylandDynload_EGL {
+# endif
+
+ struct wl_egl_window *WL_DYN_FN(wl_egl_window_create)(struct wl_surface *surface,
+ int width,
+ int height);
+ void WL_DYN_FN(wl_egl_window_destroy)(struct wl_egl_window *egl_window);
+ void WL_DYN_FN(wl_egl_window_resize)(
+ struct wl_egl_window *egl_window, int width, int height, int dx, int dy);
+ void WL_DYN_FN(wl_egl_window_get_attached_size)(struct wl_egl_window *egl_window,
+ int *width,
+ int *height);
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+};
+# endif
+# undef WL_DYN_FN
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# define wl_egl_window_create(...) (*wayland_dynload_egl.wl_egl_window_create)(__VA_ARGS__)
+# define wl_egl_window_destroy(...) (*wayland_dynload_egl.wl_egl_window_destroy)(__VA_ARGS__)
+# define wl_egl_window_resize(...) (*wayland_dynload_egl.wl_egl_window_resize)(__VA_ARGS__)
+# define wl_egl_window_get_attached_size(...) \
+ (*wayland_dynload_egl.wl_egl_window_get_attached_size)(__VA_ARGS__)
+
+# endif /* !WAYLAND_DYNLOAD_VALIDATE */
+# endif /* !defined(WAYLAND_DYNLOAD_FN) && !defined(WAYLAND_DYNLOAD_IFACE) */
+#endif /* !defined(__WAYLAND_DYNLOAD_EGL_H__) && !defined(WAYLAND_DYNLOAD_VALIDATE) */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/wayland_dynload/extern/wayland_dynload_libdecor.h b/intern/wayland_dynload/extern/wayland_dynload_libdecor.h
new file mode 100644
index 00000000000..9dcecb4d876
--- /dev/null
+++ b/intern/wayland_dynload/extern/wayland_dynload_libdecor.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Wrapper functions for `<libdecor.h>`.
+ *
+ * \note Not part of WAYLAND, but used with WAYLAND by GHOST.
+ * It follows WAYLAND conventions and is a middle-ware library that depends on `libwayland-client`.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WAYLAND_DYNLOAD_FN
+WAYLAND_DYNLOAD_FN(libdecor_configuration_get_content_size)
+WAYLAND_DYNLOAD_FN(libdecor_configuration_get_window_state)
+WAYLAND_DYNLOAD_FN(libdecor_decorate)
+WAYLAND_DYNLOAD_FN(libdecor_dispatch)
+WAYLAND_DYNLOAD_FN(libdecor_frame_commit)
+WAYLAND_DYNLOAD_FN(libdecor_frame_map)
+WAYLAND_DYNLOAD_FN(libdecor_frame_set_app_id)
+WAYLAND_DYNLOAD_FN(libdecor_frame_set_fullscreen)
+WAYLAND_DYNLOAD_FN(libdecor_frame_set_maximized)
+WAYLAND_DYNLOAD_FN(libdecor_frame_set_min_content_size)
+WAYLAND_DYNLOAD_FN(libdecor_frame_set_minimized)
+WAYLAND_DYNLOAD_FN(libdecor_frame_set_parent)
+WAYLAND_DYNLOAD_FN(libdecor_frame_set_title)
+WAYLAND_DYNLOAD_FN(libdecor_frame_unref)
+WAYLAND_DYNLOAD_FN(libdecor_frame_unset_fullscreen)
+WAYLAND_DYNLOAD_FN(libdecor_frame_unset_maximized)
+WAYLAND_DYNLOAD_FN(libdecor_new)
+WAYLAND_DYNLOAD_FN(libdecor_state_free)
+WAYLAND_DYNLOAD_FN(libdecor_state_new)
+WAYLAND_DYNLOAD_FN(libdecor_unref)
+#elif defined(WAYLAND_DYNLOAD_IFACE)
+/* No interfaces. */
+#else
+
+/* Header guard. */
+# if !defined(__WAYLAND_DYNLOAD_LIBDECOR_H__) && !defined(WAYLAND_DYNLOAD_VALIDATE)
+# define __WAYLAND_DYNLOAD_LIBDECOR_H__
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# include <libdecor.h>
+extern struct WaylandDynload_Libdecor wayland_dynload_libdecor;
+# endif
+
+/* Support validating declarations against the header. */
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# define WL_DYN_FN(sym) (*sym)
+# else
+# define WL_DYN_FN(sym) (sym)
+# endif
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+struct WaylandDynload_Libdecor {
+# endif
+
+ bool WL_DYN_FN(libdecor_configuration_get_content_size)(
+ struct libdecor_configuration *configuration,
+ struct libdecor_frame *frame,
+ int *width,
+ int *height);
+ bool WL_DYN_FN(libdecor_configuration_get_window_state)(
+ struct libdecor_configuration *configuration, enum libdecor_window_state *window_state);
+ struct libdecor_frame *WL_DYN_FN(libdecor_decorate)(struct libdecor *context,
+ struct wl_surface *surface,
+ struct libdecor_frame_interface *iface,
+ void *user_data);
+ int WL_DYN_FN(libdecor_dispatch)(struct libdecor *context, int timeout);
+ void WL_DYN_FN(libdecor_frame_commit)(struct libdecor_frame *frame,
+ struct libdecor_state *state,
+ struct libdecor_configuration *configuration);
+ void WL_DYN_FN(libdecor_frame_map)(struct libdecor_frame *frame);
+ void WL_DYN_FN(libdecor_frame_set_app_id)(struct libdecor_frame *frame, const char *app_id);
+ void WL_DYN_FN(libdecor_frame_set_fullscreen)(struct libdecor_frame *frame,
+ struct wl_output *output);
+ void WL_DYN_FN(libdecor_frame_set_maximized)(struct libdecor_frame *frame);
+ void WL_DYN_FN(libdecor_frame_set_min_content_size)(struct libdecor_frame *frame,
+ int content_width,
+ int content_height);
+ void WL_DYN_FN(libdecor_frame_set_minimized)(struct libdecor_frame *frame);
+ void WL_DYN_FN(libdecor_frame_set_parent)(struct libdecor_frame *frame,
+ struct libdecor_frame *parent);
+ void WL_DYN_FN(libdecor_frame_set_title)(struct libdecor_frame *frame, const char *title);
+ void WL_DYN_FN(libdecor_frame_unref)(struct libdecor_frame *frame);
+ void WL_DYN_FN(libdecor_frame_unset_fullscreen)(struct libdecor_frame *frame);
+ void WL_DYN_FN(libdecor_frame_unset_maximized)(struct libdecor_frame *frame);
+ struct libdecor *WL_DYN_FN(libdecor_new)(struct wl_display *display,
+ struct libdecor_interface *iface);
+ void WL_DYN_FN(libdecor_state_free)(struct libdecor_state *state);
+ struct libdecor_state *WL_DYN_FN(libdecor_state_new)(int width, int height);
+ void WL_DYN_FN(libdecor_unref)(struct libdecor *context);
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+};
+# endif
+# undef WL_DYN_FN
+
+# ifndef WAYLAND_DYNLOAD_VALIDATE
+# define libdecor_configuration_get_content_size(...) \
+ (*wayland_dynload_libdecor.libdecor_configuration_get_content_size)(__VA_ARGS__)
+# define libdecor_configuration_get_window_state(...) \
+ (*wayland_dynload_libdecor.libdecor_configuration_get_window_state)(__VA_ARGS__)
+# define libdecor_decorate(...) (*wayland_dynload_libdecor.libdecor_decorate)(__VA_ARGS__)
+# define libdecor_dispatch(...) (*wayland_dynload_libdecor.libdecor_dispatch)(__VA_ARGS__)
+# define libdecor_frame_commit(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_commit)(__VA_ARGS__)
+# define libdecor_frame_map(...) (*wayland_dynload_libdecor.libdecor_frame_map)(__VA_ARGS__)
+# define libdecor_frame_set_app_id(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_set_app_id)(__VA_ARGS__)
+# define libdecor_frame_set_fullscreen(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_set_fullscreen)(__VA_ARGS__)
+# define libdecor_frame_set_maximized(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_set_maximized)(__VA_ARGS__)
+# define libdecor_frame_set_min_content_size(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_set_min_content_size)(__VA_ARGS__)
+# define libdecor_frame_set_minimized(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_set_minimized)(__VA_ARGS__)
+# define libdecor_frame_set_parent(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_set_parent)(__VA_ARGS__)
+# define libdecor_frame_set_title(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_set_title)(__VA_ARGS__)
+# define libdecor_frame_unref(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_unref)(__VA_ARGS__)
+# define libdecor_frame_unset_fullscreen(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_unset_fullscreen)(__VA_ARGS__)
+# define libdecor_frame_unset_maximized(...) \
+ (*wayland_dynload_libdecor.libdecor_frame_unset_maximized)(__VA_ARGS__)
+# define libdecor_new(...) (*wayland_dynload_libdecor.libdecor_new)(__VA_ARGS__)
+# define libdecor_state_free(...) (*wayland_dynload_libdecor.libdecor_state_free)(__VA_ARGS__)
+# define libdecor_state_new(...) (*wayland_dynload_libdecor.libdecor_state_new)(__VA_ARGS__)
+# define libdecor_unref(...) (*wayland_dynload_libdecor.libdecor_unref)(__VA_ARGS__)
+
+# endif /* !WAYLAND_DYNLOAD_VALIDATE */
+# endif /* !defined(__WAYLAND_DYNLOAD_LIBDECOR_H__) && !defined(WAYLAND_DYNLOAD_VALIDATE) */
+#endif /* !defined(WAYLAND_DYNLOAD_FN) && !defined(WAYLAND_DYNLOAD_IFACE) */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/intern/wayland_dynload/intern/wayland_dynload_client.c b/intern/wayland_dynload/intern/wayland_dynload_client.c
new file mode 100644
index 00000000000..68ba5374aba
--- /dev/null
+++ b/intern/wayland_dynload/intern/wayland_dynload_client.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Wrapper functions for `<wayland-client.h>`.
+ */
+
+#include <stdlib.h> /* `atexit`. */
+#include <string.h>
+
+#include "wayland_dynload_API.h"
+#include "wayland_dynload_utils.h"
+
+#include "wayland_dynload_client.h" /* Own include. */
+
+/* Public handle. */
+struct WaylandDynload_Client wayland_dynload_client = {NULL};
+
+static DynamicLibrary lib = NULL;
+
+#define WAYLAND_DYNLOAD_IFACE(symbol) \
+ extern struct wl_interface symbol; \
+ struct wl_interface symbol;
+#include "wayland_dynload_client.h"
+#undef WAYLAND_DYNLOAD_IFACE
+
+bool wayland_dynload_client_init(const bool verbose)
+{
+ /* Library paths. */
+ const char *paths[] = {
+ "libwayland-client.so.0",
+ "libwayland-client.so",
+ };
+ const int paths_num = sizeof(paths) / sizeof(*paths);
+ int path_found;
+ if (!(lib = dynamic_library_open_array_with_error(paths, paths_num, verbose, &path_found))) {
+ return false;
+ }
+ if (atexit(wayland_dynload_client_exit)) {
+ return false;
+ }
+
+#define WAYLAND_DYNLOAD_IFACE(symbol) \
+ { \
+ const void *symbol_val; \
+ if (!(symbol_val = dynamic_library_find_with_error(lib, #symbol, paths[path_found]))) { \
+ return false; \
+ } \
+ memcpy(&symbol, symbol_val, sizeof(symbol)); \
+ }
+#include "wayland_dynload_client.h"
+#undef WAYLAND_DYNLOAD_IFACE
+
+#define WAYLAND_DYNLOAD_FN(symbol) \
+ if (!(wayland_dynload_client.symbol = dynamic_library_find_with_error( \
+ lib, #symbol, paths[path_found]))) { \
+ return false; \
+ }
+#include "wayland_dynload_client.h"
+#undef WAYLAND_DYNLOAD_FN
+
+ return true;
+}
+
+void wayland_dynload_client_exit(void)
+{
+ if (lib != NULL) {
+ dynamic_library_close(lib); /* Ignore errors. */
+ lib = NULL;
+ }
+}
+
+/* Validate local signatures against the original header. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#define WAYLAND_DYNLOAD_VALIDATE
+#include "wayland_dynload_client.h"
+#pragma GCC diagnostic pop
diff --git a/intern/wayland_dynload/intern/wayland_dynload_cursor.c b/intern/wayland_dynload/intern/wayland_dynload_cursor.c
new file mode 100644
index 00000000000..3d0526c7ba6
--- /dev/null
+++ b/intern/wayland_dynload/intern/wayland_dynload_cursor.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Wrapper functions for `<wayland-cursor.h>`.
+ */
+
+#include <stdlib.h> /* `atexit`. */
+#include <string.h>
+
+#include "wayland_dynload_API.h"
+#include "wayland_dynload_utils.h"
+
+#include "wayland_dynload_cursor.h" /* Own include. */
+
+struct WaylandDynload_Cursor wayland_dynload_cursor = {NULL};
+
+static DynamicLibrary lib = NULL;
+
+bool wayland_dynload_cursor_init(const bool verbose)
+{
+ /* Library paths. */
+ const char *paths[] = {
+ "libwayland-cursor.so.0",
+ "libwayland-cursor.so",
+ };
+ const int paths_num = sizeof(paths) / sizeof(*paths);
+ int path_index;
+ if (!(lib = dynamic_library_open_array_with_error(paths, paths_num, verbose, &path_index))) {
+ return false;
+ }
+ if (atexit(wayland_dynload_cursor_exit)) {
+ return false;
+ }
+
+#define WAYLAND_DYNLOAD_FN(symbol) \
+ if (!(wayland_dynload_cursor.symbol = dynamic_library_find_with_error( \
+ lib, #symbol, paths[path_index]))) { \
+ return false; \
+ }
+#include "wayland_dynload_cursor.h"
+#undef WAYLAND_DYNLOAD_FN
+
+ return true;
+}
+
+void wayland_dynload_cursor_exit(void)
+{
+ if (lib != NULL) {
+ dynamic_library_close(lib); /* Ignore errors. */
+ lib = NULL;
+ }
+}
+
+/* Validate local signatures against the original header. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#define WAYLAND_DYNLOAD_VALIDATE
+#include "wayland_dynload_cursor.h"
+#pragma GCC diagnostic pop
diff --git a/intern/wayland_dynload/intern/wayland_dynload_egl.c b/intern/wayland_dynload/intern/wayland_dynload_egl.c
new file mode 100644
index 00000000000..b62adb6c90e
--- /dev/null
+++ b/intern/wayland_dynload/intern/wayland_dynload_egl.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Wrapper functions for `<wayland-egl.h>`.
+ */
+
+#include <stdlib.h> /* `atexit`. */
+
+#include "wayland_dynload_API.h"
+#include "wayland_dynload_utils.h"
+
+#include "wayland_dynload_egl.h" /* Own include. */
+
+/* Public handle. */
+struct WaylandDynload_EGL wayland_dynload_egl = {NULL};
+
+static DynamicLibrary lib = NULL;
+
+bool wayland_dynload_egl_init(const bool verbose)
+{
+ /* Library paths. */
+ const char *paths[] = {
+ "libwayland-egl.so.0",
+ "libwayland-egl.so",
+ };
+ const int paths_num = sizeof(paths) / sizeof(*paths);
+ int path_found = 0;
+ if (!(lib = dynamic_library_open_array_with_error(paths, paths_num, verbose, &path_found))) {
+ return false;
+ }
+ if (atexit(wayland_dynload_egl_exit)) {
+ return false;
+ }
+
+#define WAYLAND_DYNLOAD_FN(symbol) \
+ if (!(wayland_dynload_egl.symbol = dynamic_library_find_with_error( \
+ lib, #symbol, paths[path_found]))) { \
+ return false; \
+ }
+#include "wayland_dynload_egl.h"
+#undef WAYLAND_DYNLOAD_FN
+
+ return true;
+}
+
+void wayland_dynload_egl_exit(void)
+{
+ if (lib != NULL) {
+ dynamic_library_close(lib); /* Ignore errors. */
+ lib = NULL;
+ }
+}
+
+/* Validate local signatures against the original header. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#define WAYLAND_DYNLOAD_VALIDATE
+#include "wayland_dynload_egl.h"
+#pragma GCC diagnostic pop
diff --git a/intern/wayland_dynload/intern/wayland_dynload_libdecor.c b/intern/wayland_dynload/intern/wayland_dynload_libdecor.c
new file mode 100644
index 00000000000..d8bdd27bb27
--- /dev/null
+++ b/intern/wayland_dynload/intern/wayland_dynload_libdecor.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Wrapper functions for `<libdecor.h>`.
+ */
+
+#include <stdlib.h> /* `atexit`. */
+
+#include "wayland_dynload_API.h"
+#include "wayland_dynload_utils.h"
+
+#include "wayland_dynload_libdecor.h" /* Own include. */
+
+/* Public handle. */
+struct WaylandDynload_Libdecor wayland_dynload_libdecor = {NULL};
+
+static DynamicLibrary lib = NULL;
+
+bool wayland_dynload_libdecor_init(const bool verbose)
+{
+ /* Library paths. */
+ const char *paths[] = {
+ "libdecor-0.so.0",
+ "libdecor-0.so",
+ };
+ const int paths_num = sizeof(paths) / sizeof(*paths);
+ int path_index;
+ if (!(lib = dynamic_library_open_array_with_error(paths, paths_num, verbose, &path_index))) {
+ return false;
+ }
+ if (atexit(wayland_dynload_libdecor_exit)) {
+ return false;
+ }
+
+#define WAYLAND_DYNLOAD_FN(symbol) \
+ if (!(wayland_dynload_libdecor.symbol = dynamic_library_find_with_error( \
+ lib, #symbol, paths[path_index]))) { \
+ return false; \
+ }
+#include "wayland_dynload_libdecor.h"
+#undef WAYLAND_DYNLOAD_FN
+
+ return true;
+}
+
+void wayland_dynload_libdecor_exit(void)
+{
+ if (lib != NULL) {
+ dynamic_library_close(lib); /* Ignore errors. */
+ lib = NULL;
+ }
+}
+
+/* Validate local signatures against the original header. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#define WAYLAND_DYNLOAD_VALIDATE
+#include "wayland_dynload_libdecor.h"
+#pragma GCC diagnostic pop
diff --git a/intern/wayland_dynload/intern/wayland_dynload_utils.c b/intern/wayland_dynload/intern/wayland_dynload_utils.c
new file mode 100644
index 00000000000..743dac14eec
--- /dev/null
+++ b/intern/wayland_dynload/intern/wayland_dynload_utils.c
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ */
+
+#include <stdio.h>
+
+#include "wayland_dynload_utils.h"
+
+DynamicLibrary dynamic_library_open_array_with_error(const char **paths,
+ const int paths_num,
+ const bool verbose,
+ int *r_path_index)
+{
+ DynamicLibrary lib = NULL;
+ for (int a = 0; a < paths_num; a++) {
+ lib = dynamic_library_open(paths[a]);
+ if (lib) {
+ *r_path_index = a;
+ break;
+ }
+ }
+ if (lib == NULL) {
+ /* Use the last path as it's likely to be least specific. */
+ if (verbose) {
+ fprintf(stderr, "Unable to find '%s'\n", paths[paths_num - 1]);
+ }
+ }
+ return lib;
+}
+
+void *dynamic_library_find_with_error(DynamicLibrary lib, const char *symbol, const char *path_lib)
+{
+ void *symbol_var = dynamic_library_find(lib, symbol);
+ if (symbol_var == NULL) {
+ fprintf(stderr, "Unable to find '%s' in '%s'.\n", symbol, path_lib);
+ }
+ return symbol_var;
+}
diff --git a/intern/wayland_dynload/intern/wayland_dynload_utils.h b/intern/wayland_dynload/intern/wayland_dynload_utils.h
new file mode 100644
index 00000000000..785f32521e4
--- /dev/null
+++ b/intern/wayland_dynload/intern/wayland_dynload_utils.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup intern_wayland_dynload
+ *
+ * Utility defines.
+ */
+
+#pragma once
+
+#include <dlfcn.h> /* Dynamic loading. */
+#include <stdbool.h>
+
+typedef void *DynamicLibrary;
+
+#define dynamic_library_open(path) dlopen(path, RTLD_NOW)
+#define dynamic_library_close(lib) dlclose(lib)
+#define dynamic_library_find(lib, symbol) dlsym(lib, symbol)
+
+/** Loads a library from an array, printing an error when the symbol isn't found. */
+DynamicLibrary dynamic_library_open_array_with_error(const char **paths,
+ int paths_num,
+ bool verbose,
+ int *r_path_index);
+
+/** Find a symbol, printing an error when the symbol isn't found. */
+void *dynamic_library_find_with_error(DynamicLibrary lib,
+ const char *symbol,
+ const char *path_lib);
diff --git a/pyproject.toml b/pyproject.toml
index 22d2d768d08..cded8e51bf0 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,10 +1,10 @@
# SPDX-License-Identifier: GPL-2.0-or-later
[tool.autopep8]
-# Configuratuion for `autopep8`, allowing the command: autopep8 .
+# Configuration for `autopep8`, allowing the command: autopep8 .
# to reformat all source files.
#
-# NOTE: the settings defined here map directly to commmand line arguments
+# NOTE: the settings defined here map directly to command line arguments
# which will override these settings when passed in to autopep8.
max_line_length = 120
diff --git a/release/bin/blender-softwaregl b/release/bin/blender-softwaregl
index 8628dca2202..acd4dc3eec5 100755
--- a/release/bin/blender-softwaregl
+++ b/release/bin/blender-softwaregl
@@ -2,16 +2,16 @@
BF_DIST_BIN=$(dirname "$0")
BF_PROGRAM="blender" # BF_PROGRAM=$(basename "$0")-bin
-LD_LIBRARY_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARY_PATH}
+LD_LIBRARY_PATH=${BF_DIST_BIN}/lib/mesa:${LD_LIBRARY_PATH}
if [ -n "$LD_LIBRARYN32_PATH" ]; then
- LD_LIBRARYN32_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARYN32_PATH}
+ LD_LIBRARYN32_PATH=${BF_DIST_BIN}/lib/mesa:${LD_LIBRARYN32_PATH}
fi
if [ -n "$LD_LIBRARYN64_PATH" ]; then
- LD_LIBRARYN64_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARYN64_PATH}
+ LD_LIBRARYN64_PATH=${BF_DIST_BIN}/lib/mesa:${LD_LIBRARYN64_PATH}
fi
if [ -n "$LD_LIBRARY_PATH_64" ]; then
- LD_LIBRARY_PATH_64=${BF_DIST_BIN}/lib:${LD_LIBRARY_PATH_64}
+ LD_LIBRARY_PATH_64=${BF_DIST_BIN}/lib/mesa:${LD_LIBRARY_PATH_64}
fi
# Workaround for half-transparent windows when compiz is enabled
diff --git a/release/datafiles/alert_icons_update.py b/release/datafiles/alert_icons_update.py
index 8c5d66e803a..bb4140d1ec2 100755
--- a/release/datafiles/alert_icons_update.py
+++ b/release/datafiles/alert_icons_update.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This script updates icons from the SVG file
import os
import subprocess
diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg
index f8164d1f646..41707261ac6 100644
--- a/release/datafiles/blender_icons.svg
+++ b/release/datafiles/blender_icons.svg
@@ -1,24 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="602"
- height="640"
- id="svg2"
- sodipodi:version="0.32"
- inkscape:version="1.0 (4035a4f, 2020-05-01)"
- version="1.0"
- sodipodi:docname="blender_icons.svg"
- inkscape:output_extension="org.inkscape.output.svg.inkscape"
- style="display:inline;enable-background:new"
- inkscape:export-filename="blender_icons.png"
+ inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-filename="blender_icons.png"
+ style="display:inline;enable-background:new"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ sodipodi:docname="blender_icons.svg"
+ version="1.0"
+ inkscape:version="1.2 (dc2aeda, 2022-05-15)"
+ sodipodi:version="0.32"
+ id="svg2"
+ height="640"
+ width="602"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata34337">
<rdf:RDF>
@@ -27,7 +27,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
+ <dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@@ -42,29 +42,21 @@
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
- inkscape:window-width="1792"
- inkscape:window-height="968"
+ inkscape:window-width="1728"
+ inkscape:window-height="1051"
id="namedview34335"
showgrid="false"
- inkscape:zoom="0.815521"
- inkscape:cx="60.911776"
- inkscape:cy="331.5525"
- inkscape:window-x="-1"
- inkscape:window-y="25"
+ inkscape:zoom="1.2495612"
+ inkscape:cx="196.46897"
+ inkscape:cy="320.51252"
+ inkscape:window-x="767"
+ inkscape:window-y="120"
inkscape:window-maximized="0"
- inkscape:current-layer="layer2" />
+ inkscape:current-layer="layer8"
+ inkscape:showpageshadow="2"
+ inkscape:deskcolor="#808080" />
<defs
id="defs4" />
- <path
- style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#1a1a1a;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path23417"
- sodipodi:nodetypes="cc"
- d="" />
- <path
- style="fill:none;stroke:#ffffff;stroke-width:1.79999995;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
- id="path23347"
- sodipodi:nodetypes="cc"
- d="" />
<g
inkscape:groupmode="layer"
id="layer5"
@@ -77,7 +69,7 @@
<g
id="g22995">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22955"
width="1"
height="7"
@@ -93,9 +85,9 @@
height="7"
width="1"
id="rect22957"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22959"
width="1"
height="7"
@@ -111,9 +103,9 @@
height="7"
width="1"
id="rect22961"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22963"
width="1"
height="7"
@@ -129,9 +121,9 @@
height="7"
width="1"
id="rect22965"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22967"
width="1"
height="7"
@@ -147,9 +139,9 @@
height="7"
width="1"
id="rect22969"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22971"
width="1"
height="7"
@@ -165,9 +157,9 @@
height="7"
width="1"
id="rect22973"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22975"
width="1"
height="7"
@@ -183,9 +175,9 @@
height="7"
width="1"
id="rect22977"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22979"
width="1"
height="7"
@@ -201,9 +193,9 @@
height="7"
width="1"
id="rect22981"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22983"
width="1"
height="7"
@@ -219,9 +211,9 @@
height="7"
width="1"
id="rect22985"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22987"
width="1"
height="7"
@@ -237,9 +229,9 @@
height="7"
width="1"
id="rect22989"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect22991"
width="1"
height="7"
@@ -255,7 +247,7 @@
height="7"
width="1"
id="rect22993"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
ry="0"
rx="0"
@@ -264,9 +256,9 @@
height="7"
width="1"
id="rect23024"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect23026"
width="1"
height="7"
@@ -282,9 +274,9 @@
height="7"
width="1"
id="rect23028"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect23030"
width="1"
height="7"
@@ -293,7 +285,7 @@
rx="0"
ry="0" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect10985"
width="1"
height="7"
@@ -308,7 +300,7 @@
id="g23711"
transform="translate(0,462)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect23713"
width="6"
height="1"
@@ -321,125 +313,125 @@
<path
id="path23717"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23719"
inkscape:connector-curvature="0" />
<path
id="path23721"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23723"
inkscape:connector-curvature="0" />
<path
id="path23725"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23727"
inkscape:connector-curvature="0" />
<path
id="path23729"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23731"
inkscape:connector-curvature="0" />
<path
id="path23733"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23735"
inkscape:connector-curvature="0" />
<path
id="path23737"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23739"
inkscape:connector-curvature="0" />
<path
id="path23741"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23743"
inkscape:connector-curvature="0" />
<path
id="path23745"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23747"
inkscape:connector-curvature="0" />
<path
id="path23749"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23751"
inkscape:connector-curvature="0" />
<path
id="path23753"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23755"
inkscape:connector-curvature="0" />
<path
id="path23757"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23759"
inkscape:connector-curvature="0" />
<path
id="path23761"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23763"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path10987"
inkscape:connector-curvature="0" />
@@ -456,133 +448,133 @@
height="1"
width="6"
id="rect23767"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g23769">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23771"
inkscape:connector-curvature="0" />
<path
id="path23773"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23775"
inkscape:connector-curvature="0" />
<path
id="path23777"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23779"
inkscape:connector-curvature="0" />
<path
id="path23781"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23783"
inkscape:connector-curvature="0" />
<path
id="path23785"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23787"
inkscape:connector-curvature="0" />
<path
id="path23789"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23791"
inkscape:connector-curvature="0" />
<path
id="path23793"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23795"
inkscape:connector-curvature="0" />
<path
id="path23797"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23799"
inkscape:connector-curvature="0" />
<path
id="path23801"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23803"
inkscape:connector-curvature="0" />
<path
id="path23805"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23807"
inkscape:connector-curvature="0" />
<path
id="path23809"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23811"
inkscape:connector-curvature="0" />
<path
id="path23813"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23815"
inkscape:connector-curvature="0" />
<path
id="path23817"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path10990"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -590,7 +582,7 @@
id="g23819"
transform="translate(0,420)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect23821"
width="6"
height="1"
@@ -603,125 +595,125 @@
<path
id="path23825"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23827"
inkscape:connector-curvature="0" />
<path
id="path23829"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23831"
inkscape:connector-curvature="0" />
<path
id="path23833"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23835"
inkscape:connector-curvature="0" />
<path
id="path23837"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23839"
inkscape:connector-curvature="0" />
<path
id="path23841"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23843"
inkscape:connector-curvature="0" />
<path
id="path23845"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23847"
inkscape:connector-curvature="0" />
<path
id="path23849"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23851"
inkscape:connector-curvature="0" />
<path
id="path23853"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23855"
inkscape:connector-curvature="0" />
<path
id="path23857"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23859"
inkscape:connector-curvature="0" />
<path
id="path23861"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23863"
inkscape:connector-curvature="0" />
<path
id="path23865"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23867"
inkscape:connector-curvature="0" />
<path
id="path23869"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23871"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path10992"
inkscape:connector-curvature="0" />
@@ -738,133 +730,133 @@
height="1"
width="6"
id="rect23875"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g23877">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23879"
inkscape:connector-curvature="0" />
<path
id="path23881"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23883"
inkscape:connector-curvature="0" />
<path
id="path23885"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23887"
inkscape:connector-curvature="0" />
<path
id="path23889"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23891"
inkscape:connector-curvature="0" />
<path
id="path23893"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23895"
inkscape:connector-curvature="0" />
<path
id="path23897"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23899"
inkscape:connector-curvature="0" />
<path
id="path23901"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23903"
inkscape:connector-curvature="0" />
<path
id="path23905"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23907"
inkscape:connector-curvature="0" />
<path
id="path23909"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23911"
inkscape:connector-curvature="0" />
<path
id="path23913"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23915"
inkscape:connector-curvature="0" />
<path
id="path23917"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23919"
inkscape:connector-curvature="0" />
<path
id="path23921"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23923"
inkscape:connector-curvature="0" />
<path
id="path23925"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path10994"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -872,7 +864,7 @@
id="g23927"
transform="translate(0,378)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect23929"
width="6"
height="1"
@@ -885,125 +877,125 @@
<path
id="path23933"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23935"
inkscape:connector-curvature="0" />
<path
id="path23937"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23939"
inkscape:connector-curvature="0" />
<path
id="path23941"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23943"
inkscape:connector-curvature="0" />
<path
id="path23945"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23947"
inkscape:connector-curvature="0" />
<path
id="path23949"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23951"
inkscape:connector-curvature="0" />
<path
id="path23953"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23955"
inkscape:connector-curvature="0" />
<path
id="path23957"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23959"
inkscape:connector-curvature="0" />
<path
id="path23961"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23963"
inkscape:connector-curvature="0" />
<path
id="path23965"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23967"
inkscape:connector-curvature="0" />
<path
id="path23969"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23971"
inkscape:connector-curvature="0" />
<path
id="path23973"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23975"
inkscape:connector-curvature="0" />
<path
id="path23977"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23979"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path10996"
inkscape:connector-curvature="0" />
@@ -1013,7 +1005,7 @@
id="g23981"
transform="translate(0,357)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect23983"
width="6"
height="1"
@@ -1026,125 +1018,125 @@
<path
id="path23987"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23989"
inkscape:connector-curvature="0" />
<path
id="path23991"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23993"
inkscape:connector-curvature="0" />
<path
id="path23995"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path23997"
inkscape:connector-curvature="0" />
<path
id="path23999"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24001"
inkscape:connector-curvature="0" />
<path
id="path24003"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24005"
inkscape:connector-curvature="0" />
<path
id="path24007"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24009"
inkscape:connector-curvature="0" />
<path
id="path24011"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24013"
inkscape:connector-curvature="0" />
<path
id="path24015"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24017"
inkscape:connector-curvature="0" />
<path
id="path24019"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24021"
inkscape:connector-curvature="0" />
<path
id="path24023"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24025"
inkscape:connector-curvature="0" />
<path
id="path24027"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24029"
inkscape:connector-curvature="0" />
<path
id="path24031"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24033"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path10998"
inkscape:connector-curvature="0" />
@@ -1161,133 +1153,133 @@
height="1"
width="6"
id="rect24037"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24039">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24041"
inkscape:connector-curvature="0" />
<path
id="path24043"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24045"
inkscape:connector-curvature="0" />
<path
id="path24047"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24049"
inkscape:connector-curvature="0" />
<path
id="path24051"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24053"
inkscape:connector-curvature="0" />
<path
id="path24055"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24057"
inkscape:connector-curvature="0" />
<path
id="path24059"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24061"
inkscape:connector-curvature="0" />
<path
id="path24063"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24065"
inkscape:connector-curvature="0" />
<path
id="path24067"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24069"
inkscape:connector-curvature="0" />
<path
id="path24071"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24073"
inkscape:connector-curvature="0" />
<path
id="path24075"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24077"
inkscape:connector-curvature="0" />
<path
id="path24079"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24081"
inkscape:connector-curvature="0" />
<path
id="path24083"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24085"
inkscape:connector-curvature="0" />
<path
id="path24087"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11000"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -1295,7 +1287,7 @@
id="g24089"
transform="translate(0,315)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect24091"
width="6"
height="1"
@@ -1308,125 +1300,125 @@
<path
id="path24095"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24097"
inkscape:connector-curvature="0" />
<path
id="path24099"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24101"
inkscape:connector-curvature="0" />
<path
id="path24103"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24105"
inkscape:connector-curvature="0" />
<path
id="path24107"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24109"
inkscape:connector-curvature="0" />
<path
id="path24111"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24113"
inkscape:connector-curvature="0" />
<path
id="path24115"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24117"
inkscape:connector-curvature="0" />
<path
id="path24119"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24121"
inkscape:connector-curvature="0" />
<path
id="path24123"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24125"
inkscape:connector-curvature="0" />
<path
id="path24127"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24129"
inkscape:connector-curvature="0" />
<path
id="path24131"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24133"
inkscape:connector-curvature="0" />
<path
id="path24135"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24137"
inkscape:connector-curvature="0" />
<path
id="path24139"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24141"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path11002"
inkscape:connector-curvature="0" />
@@ -1443,133 +1435,133 @@
height="1"
width="6"
id="rect24145"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24147">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24149"
inkscape:connector-curvature="0" />
<path
id="path24151"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24153"
inkscape:connector-curvature="0" />
<path
id="path24155"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24157"
inkscape:connector-curvature="0" />
<path
id="path24159"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24161"
inkscape:connector-curvature="0" />
<path
id="path24163"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24165"
inkscape:connector-curvature="0" />
<path
id="path24167"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24169"
inkscape:connector-curvature="0" />
<path
id="path24171"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24173"
inkscape:connector-curvature="0" />
<path
id="path24175"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24177"
inkscape:connector-curvature="0" />
<path
id="path24179"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24181"
inkscape:connector-curvature="0" />
<path
id="path24183"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24185"
inkscape:connector-curvature="0" />
<path
id="path24187"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24189"
inkscape:connector-curvature="0" />
<path
id="path24191"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24193"
inkscape:connector-curvature="0" />
<path
id="path24195"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11004"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -1577,7 +1569,7 @@
id="g24197"
transform="translate(0,273)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect24199"
width="6"
height="1"
@@ -1590,125 +1582,125 @@
<path
id="path24203"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24205"
inkscape:connector-curvature="0" />
<path
id="path24207"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24209"
inkscape:connector-curvature="0" />
<path
id="path24211"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24213"
inkscape:connector-curvature="0" />
<path
id="path24215"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24217"
inkscape:connector-curvature="0" />
<path
id="path24219"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24221"
inkscape:connector-curvature="0" />
<path
id="path24223"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24225"
inkscape:connector-curvature="0" />
<path
id="path24227"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24229"
inkscape:connector-curvature="0" />
<path
id="path24231"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24233"
inkscape:connector-curvature="0" />
<path
id="path24235"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24237"
inkscape:connector-curvature="0" />
<path
id="path24239"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24241"
inkscape:connector-curvature="0" />
<path
id="path24243"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24245"
inkscape:connector-curvature="0" />
<path
id="path24247"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24249"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path11006"
inkscape:connector-curvature="0" />
@@ -1725,133 +1717,133 @@
height="1"
width="6"
id="rect24253"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24255">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24257"
inkscape:connector-curvature="0" />
<path
id="path24259"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24261"
inkscape:connector-curvature="0" />
<path
id="path24263"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24265"
inkscape:connector-curvature="0" />
<path
id="path24267"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24269"
inkscape:connector-curvature="0" />
<path
id="path24271"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24273"
inkscape:connector-curvature="0" />
<path
id="path24275"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24277"
inkscape:connector-curvature="0" />
<path
id="path24279"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24281"
inkscape:connector-curvature="0" />
<path
id="path24283"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24285"
inkscape:connector-curvature="0" />
<path
id="path24287"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24289"
inkscape:connector-curvature="0" />
<path
id="path24291"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24293"
inkscape:connector-curvature="0" />
<path
id="path24295"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24297"
inkscape:connector-curvature="0" />
<path
id="path24299"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24301"
inkscape:connector-curvature="0" />
<path
id="path24303"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11008"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -1859,7 +1851,7 @@
id="g24305"
transform="translate(0,231)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect24307"
width="6"
height="1"
@@ -1872,125 +1864,125 @@
<path
id="path24311"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24313"
inkscape:connector-curvature="0" />
<path
id="path24315"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24317"
inkscape:connector-curvature="0" />
<path
id="path24319"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24321"
inkscape:connector-curvature="0" />
<path
id="path24323"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24325"
inkscape:connector-curvature="0" />
<path
id="path24327"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24329"
inkscape:connector-curvature="0" />
<path
id="path24331"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24333"
inkscape:connector-curvature="0" />
<path
id="path24335"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24337"
inkscape:connector-curvature="0" />
<path
id="path24339"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24341"
inkscape:connector-curvature="0" />
<path
id="path24343"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24345"
inkscape:connector-curvature="0" />
<path
id="path24347"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24349"
inkscape:connector-curvature="0" />
<path
id="path24351"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24353"
inkscape:connector-curvature="0" />
<path
id="path24355"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24357"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path11010"
inkscape:connector-curvature="0" />
@@ -2007,133 +1999,133 @@
height="1"
width="6"
id="rect24361"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24363">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24365"
inkscape:connector-curvature="0" />
<path
id="path24367"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24369"
inkscape:connector-curvature="0" />
<path
id="path24371"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24373"
inkscape:connector-curvature="0" />
<path
id="path24375"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24377"
inkscape:connector-curvature="0" />
<path
id="path24379"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24381"
inkscape:connector-curvature="0" />
<path
id="path24383"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24385"
inkscape:connector-curvature="0" />
<path
id="path24387"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24389"
inkscape:connector-curvature="0" />
<path
id="path24391"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24393"
inkscape:connector-curvature="0" />
<path
id="path24395"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24397"
inkscape:connector-curvature="0" />
<path
id="path24399"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24401"
inkscape:connector-curvature="0" />
<path
id="path24403"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24405"
inkscape:connector-curvature="0" />
<path
id="path24407"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24409"
inkscape:connector-curvature="0" />
<path
id="path24411"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11012"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -2141,7 +2133,7 @@
id="g24413"
transform="translate(0,189)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect24415"
width="6"
height="1"
@@ -2154,125 +2146,125 @@
<path
id="path24419"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24421"
inkscape:connector-curvature="0" />
<path
id="path24423"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24425"
inkscape:connector-curvature="0" />
<path
id="path24427"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24429"
inkscape:connector-curvature="0" />
<path
id="path24431"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24433"
inkscape:connector-curvature="0" />
<path
id="path24435"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24437"
inkscape:connector-curvature="0" />
<path
id="path24439"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24441"
inkscape:connector-curvature="0" />
<path
id="path24443"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24445"
inkscape:connector-curvature="0" />
<path
id="path24447"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24449"
inkscape:connector-curvature="0" />
<path
id="path24451"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24453"
inkscape:connector-curvature="0" />
<path
id="path24455"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24457"
inkscape:connector-curvature="0" />
<path
id="path24459"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24461"
inkscape:connector-curvature="0" />
<path
id="path24463"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24465"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path11014"
inkscape:connector-curvature="0" />
@@ -2289,133 +2281,133 @@
height="1"
width="6"
id="rect24469"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24471">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24473"
inkscape:connector-curvature="0" />
<path
id="path24475"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24477"
inkscape:connector-curvature="0" />
<path
id="path24479"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24481"
inkscape:connector-curvature="0" />
<path
id="path24483"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24485"
inkscape:connector-curvature="0" />
<path
id="path24487"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24489"
inkscape:connector-curvature="0" />
<path
id="path24491"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24493"
inkscape:connector-curvature="0" />
<path
id="path24495"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24497"
inkscape:connector-curvature="0" />
<path
id="path24499"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24501"
inkscape:connector-curvature="0" />
<path
id="path24503"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24505"
inkscape:connector-curvature="0" />
<path
id="path24507"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24509"
inkscape:connector-curvature="0" />
<path
id="path24511"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24513"
inkscape:connector-curvature="0" />
<path
id="path24515"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24517"
inkscape:connector-curvature="0" />
<path
id="path24519"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11016"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -2423,7 +2415,7 @@
id="g24521"
transform="translate(0,147)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect24523"
width="6"
height="1"
@@ -2436,125 +2428,125 @@
<path
id="path24527"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24529"
inkscape:connector-curvature="0" />
<path
id="path24531"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24533"
inkscape:connector-curvature="0" />
<path
id="path24535"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24537"
inkscape:connector-curvature="0" />
<path
id="path24539"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24541"
inkscape:connector-curvature="0" />
<path
id="path24543"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24545"
inkscape:connector-curvature="0" />
<path
id="path24547"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24549"
inkscape:connector-curvature="0" />
<path
id="path24551"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24553"
inkscape:connector-curvature="0" />
<path
id="path24555"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24557"
inkscape:connector-curvature="0" />
<path
id="path24559"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24561"
inkscape:connector-curvature="0" />
<path
id="path24563"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24565"
inkscape:connector-curvature="0" />
<path
id="path24567"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24569"
inkscape:connector-curvature="0" />
<path
id="path24571"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24573"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path11018"
inkscape:connector-curvature="0" />
@@ -2571,133 +2563,133 @@
height="1"
width="6"
id="rect24577"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24579">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24581"
inkscape:connector-curvature="0" />
<path
id="path24583"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24585"
inkscape:connector-curvature="0" />
<path
id="path24587"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24589"
inkscape:connector-curvature="0" />
<path
id="path24591"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24593"
inkscape:connector-curvature="0" />
<path
id="path24595"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24597"
inkscape:connector-curvature="0" />
<path
id="path24599"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24601"
inkscape:connector-curvature="0" />
<path
id="path24603"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24605"
inkscape:connector-curvature="0" />
<path
id="path24607"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24609"
inkscape:connector-curvature="0" />
<path
id="path24611"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24613"
inkscape:connector-curvature="0" />
<path
id="path24615"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24617"
inkscape:connector-curvature="0" />
<path
id="path24619"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24621"
inkscape:connector-curvature="0" />
<path
id="path24623"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24625"
inkscape:connector-curvature="0" />
<path
id="path24627"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11020"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -2705,7 +2697,7 @@
id="g24630"
transform="translate(0,105)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect24632"
width="6"
height="1"
@@ -2718,125 +2710,125 @@
<path
id="path24636"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24638"
inkscape:connector-curvature="0" />
<path
id="path24640"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24642"
inkscape:connector-curvature="0" />
<path
id="path24644"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24646"
inkscape:connector-curvature="0" />
<path
id="path24648"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24650"
inkscape:connector-curvature="0" />
<path
id="path24652"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24654"
inkscape:connector-curvature="0" />
<path
id="path24656"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24658"
inkscape:connector-curvature="0" />
<path
id="path24660"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24662"
inkscape:connector-curvature="0" />
<path
id="path24664"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24666"
inkscape:connector-curvature="0" />
<path
id="path24668"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24670"
inkscape:connector-curvature="0" />
<path
id="path24672"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24674"
inkscape:connector-curvature="0" />
<path
id="path24676"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24678"
inkscape:connector-curvature="0" />
<path
id="path24680"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24682"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path11022"
inkscape:connector-curvature="0" />
@@ -2853,133 +2845,133 @@
height="1"
width="6"
id="rect24686"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24688">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24690"
inkscape:connector-curvature="0" />
<path
id="path24692"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24694"
inkscape:connector-curvature="0" />
<path
id="path24696"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24698"
inkscape:connector-curvature="0" />
<path
id="path24700"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24702"
inkscape:connector-curvature="0" />
<path
id="path24704"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24706"
inkscape:connector-curvature="0" />
<path
id="path24708"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24710"
inkscape:connector-curvature="0" />
<path
id="path24712"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24714"
inkscape:connector-curvature="0" />
<path
id="path24716"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24718"
inkscape:connector-curvature="0" />
<path
id="path24720"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24722"
inkscape:connector-curvature="0" />
<path
id="path24724"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24726"
inkscape:connector-curvature="0" />
<path
id="path24728"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24730"
inkscape:connector-curvature="0" />
<path
id="path24732"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24734"
inkscape:connector-curvature="0" />
<path
id="path24736"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11024"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -2987,7 +2979,7 @@
id="g24738"
transform="translate(0,63)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect24740"
width="6"
height="1"
@@ -3000,125 +2992,125 @@
<path
id="path24744"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24746"
inkscape:connector-curvature="0" />
<path
id="path24748"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24750"
inkscape:connector-curvature="0" />
<path
id="path24752"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24754"
inkscape:connector-curvature="0" />
<path
id="path24756"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24758"
inkscape:connector-curvature="0" />
<path
id="path24760"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24762"
inkscape:connector-curvature="0" />
<path
id="path24764"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24766"
inkscape:connector-curvature="0" />
<path
id="path24768"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24770"
inkscape:connector-curvature="0" />
<path
id="path24772"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24774"
inkscape:connector-curvature="0" />
<path
id="path24776"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24778"
inkscape:connector-curvature="0" />
<path
id="path24780"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24782"
inkscape:connector-curvature="0" />
<path
id="path24784"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24786"
inkscape:connector-curvature="0" />
<path
id="path24788"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24790"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path11026"
inkscape:connector-curvature="0" />
@@ -3135,133 +3127,133 @@
height="1"
width="6"
id="rect24794"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24796">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24798"
inkscape:connector-curvature="0" />
<path
id="path24800"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24802"
inkscape:connector-curvature="0" />
<path
id="path24804"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24806"
inkscape:connector-curvature="0" />
<path
id="path24808"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24810"
inkscape:connector-curvature="0" />
<path
id="path24812"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24814"
inkscape:connector-curvature="0" />
<path
id="path24816"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24818"
inkscape:connector-curvature="0" />
<path
id="path24820"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24822"
inkscape:connector-curvature="0" />
<path
id="path24824"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24826"
inkscape:connector-curvature="0" />
<path
id="path24828"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24830"
inkscape:connector-curvature="0" />
<path
id="path24832"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24834"
inkscape:connector-curvature="0" />
<path
id="path24836"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24838"
inkscape:connector-curvature="0" />
<path
id="path24840"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24842"
inkscape:connector-curvature="0" />
<path
id="path24844"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11028"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -3269,7 +3261,7 @@
id="g24846"
transform="translate(0,21)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect24848"
width="6"
height="1"
@@ -3282,125 +3274,125 @@
<path
id="path24852"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24854"
inkscape:connector-curvature="0" />
<path
id="path24856"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24858"
inkscape:connector-curvature="0" />
<path
id="path24860"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24862"
inkscape:connector-curvature="0" />
<path
id="path24864"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24866"
inkscape:connector-curvature="0" />
<path
id="path24868"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24870"
inkscape:connector-curvature="0" />
<path
id="path24872"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24874"
inkscape:connector-curvature="0" />
<path
id="path24876"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24878"
inkscape:connector-curvature="0" />
<path
id="path24880"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24882"
inkscape:connector-curvature="0" />
<path
id="path24884"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24886"
inkscape:connector-curvature="0" />
<path
id="path24888"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24890"
inkscape:connector-curvature="0" />
<path
id="path24892"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24894"
inkscape:connector-curvature="0" />
<path
id="path24896"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24898"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path11030"
inkscape:connector-curvature="0" />
@@ -3416,133 +3408,133 @@
height="1"
width="6"
id="rect24902"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g24904">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24906"
inkscape:connector-curvature="0" />
<path
id="path24908"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24910"
inkscape:connector-curvature="0" />
<path
id="path24912"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24914"
inkscape:connector-curvature="0" />
<path
id="path24916"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24918"
inkscape:connector-curvature="0" />
<path
id="path24920"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24922"
inkscape:connector-curvature="0" />
<path
id="path24924"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24926"
inkscape:connector-curvature="0" />
<path
id="path24928"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24930"
inkscape:connector-curvature="0" />
<path
id="path24932"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24934"
inkscape:connector-curvature="0" />
<path
id="path24936"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24938"
inkscape:connector-curvature="0" />
<path
id="path24940"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24942"
inkscape:connector-curvature="0" />
<path
id="path24944"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24946"
inkscape:connector-curvature="0" />
<path
id="path24948"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path24950"
inkscape:connector-curvature="0" />
<path
id="path24952"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path11032"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -3557,133 +3549,133 @@
height="1"
width="6"
id="rect39835"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g39837">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39840"
inkscape:connector-curvature="0" />
<path
id="path39842"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39844"
inkscape:connector-curvature="0" />
<path
id="path39846"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39848"
inkscape:connector-curvature="0" />
<path
id="path39850"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39852"
inkscape:connector-curvature="0" />
<path
id="path39854"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39856"
inkscape:connector-curvature="0" />
<path
id="path39858"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39860"
inkscape:connector-curvature="0" />
<path
id="path39862"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39864"
inkscape:connector-curvature="0" />
<path
id="path39866"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39868"
inkscape:connector-curvature="0" />
<path
id="path39870"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39872"
inkscape:connector-curvature="0" />
<path
id="path39874"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39876"
inkscape:connector-curvature="0" />
<path
id="path39878"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39880"
inkscape:connector-curvature="0" />
<path
id="path39882"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39884"
inkscape:connector-curvature="0" />
<path
id="path39888"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path39890"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -3691,7 +3683,7 @@
id="g39892"
transform="translate(0,504)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect39894"
width="6"
height="1"
@@ -3704,125 +3696,125 @@
<path
id="path39898"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39900"
inkscape:connector-curvature="0" />
<path
id="path39902"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39904"
inkscape:connector-curvature="0" />
<path
id="path39907"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39909"
inkscape:connector-curvature="0" />
<path
id="path39911"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39913"
inkscape:connector-curvature="0" />
<path
id="path39915"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39917"
inkscape:connector-curvature="0" />
<path
id="path39919"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39921"
inkscape:connector-curvature="0" />
<path
id="path39923"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39925"
inkscape:connector-curvature="0" />
<path
id="path39927"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39929"
inkscape:connector-curvature="0" />
<path
id="path39931"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39933"
inkscape:connector-curvature="0" />
<path
id="path39935"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39937"
inkscape:connector-curvature="0" />
<path
id="path39939"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39941"
inkscape:connector-curvature="0" />
<path
id="path39943"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39945"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39947"
inkscape:connector-curvature="0" />
@@ -3839,133 +3831,133 @@
height="1"
width="6"
id="rect39951"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g39953">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39955"
inkscape:connector-curvature="0" />
<path
id="path39957"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39959"
inkscape:connector-curvature="0" />
<path
id="path39961"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39963"
inkscape:connector-curvature="0" />
<path
id="path39965"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39967"
inkscape:connector-curvature="0" />
<path
id="path39969"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39971"
inkscape:connector-curvature="0" />
<path
id="path39973"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39975"
inkscape:connector-curvature="0" />
<path
id="path39977"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39979"
inkscape:connector-curvature="0" />
<path
id="path39981"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39983"
inkscape:connector-curvature="0" />
<path
id="path39985"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39987"
inkscape:connector-curvature="0" />
<path
id="path39989"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39991"
inkscape:connector-curvature="0" />
<path
id="path39993"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39995"
inkscape:connector-curvature="0" />
<path
id="path39997"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path39999"
inkscape:connector-curvature="0" />
<path
id="path40001"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path40003"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -3973,7 +3965,7 @@
id="g40005"
transform="translate(0,546)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect40007"
width="6"
height="1"
@@ -3986,125 +3978,125 @@
<path
id="path40011"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40013"
inkscape:connector-curvature="0" />
<path
id="path40015"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40017"
inkscape:connector-curvature="0" />
<path
id="path40019"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40021"
inkscape:connector-curvature="0" />
<path
id="path40023"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40025"
inkscape:connector-curvature="0" />
<path
id="path40027"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40029"
inkscape:connector-curvature="0" />
<path
id="path40031"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40033"
inkscape:connector-curvature="0" />
<path
id="path40035"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40038"
inkscape:connector-curvature="0" />
<path
id="path40040"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40042"
inkscape:connector-curvature="0" />
<path
id="path40044"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40046"
inkscape:connector-curvature="0" />
<path
id="path40048"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40050"
inkscape:connector-curvature="0" />
<path
id="path40052"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40054"
inkscape:connector-curvature="0" />
<path
id="path40056"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40058"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40060"
inkscape:connector-curvature="0" />
@@ -4121,133 +4113,133 @@
height="1"
width="6"
id="rect40064"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<g
id="g40066">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40068"
inkscape:connector-curvature="0" />
<path
id="path40070"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40072"
inkscape:connector-curvature="0" />
<path
id="path40074"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40076"
inkscape:connector-curvature="0" />
<path
id="path40078"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40080"
inkscape:connector-curvature="0" />
<path
id="path40082"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40084"
inkscape:connector-curvature="0" />
<path
id="path40086"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40088"
inkscape:connector-curvature="0" />
<path
id="path40090"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40092"
inkscape:connector-curvature="0" />
<path
id="path40094"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40096"
inkscape:connector-curvature="0" />
<path
id="path40098"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40100"
inkscape:connector-curvature="0" />
<path
id="path40102"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40104"
inkscape:connector-curvature="0" />
<path
id="path40106"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40108"
inkscape:connector-curvature="0" />
<path
id="path40110"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40112"
inkscape:connector-curvature="0" />
<path
id="path40114"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path40116"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
</g>
@@ -4255,7 +4247,7 @@
id="g40118"
transform="translate(0,588)">
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect40120"
width="6"
height="1"
@@ -4268,125 +4260,125 @@
<path
id="path40124"
d="m 506,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 485,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40126"
inkscape:connector-curvature="0" />
<path
id="path40128"
d="m 464,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 443,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40130"
inkscape:connector-curvature="0" />
<path
id="path40132"
d="m 422,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 401,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40134"
inkscape:connector-curvature="0" />
<path
id="path40136"
d="m 380,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 359,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40138"
inkscape:connector-curvature="0" />
<path
id="path40140"
d="m 338,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 317,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40142"
inkscape:connector-curvature="0" />
<path
id="path40144"
d="m 296,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 275,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40146"
inkscape:connector-curvature="0" />
<path
id="path40148"
d="m 254,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 233,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40150"
inkscape:connector-curvature="0" />
<path
id="path40152"
d="m 212,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 191,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40154"
inkscape:connector-curvature="0" />
<path
id="path40156"
d="m 170,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 149,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40158"
inkscape:connector-curvature="0" />
<path
id="path40160"
d="m 128,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 107,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40162"
inkscape:connector-curvature="0" />
<path
id="path40164"
d="m 86,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 65,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40166"
inkscape:connector-curvature="0" />
<path
id="path40168"
d="m 44,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 23,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40170"
inkscape:connector-curvature="0" />
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
d="m 527,20 v 6 h -6 v 1 h 6 v 6 h 1 v -6 h 6 v -1 h -6 v -6 z"
id="path40172"
inkscape:connector-curvature="0" />
@@ -4404,9 +4396,9 @@
height="7"
width="1"
id="rect25956"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25958"
width="1"
height="7"
@@ -4422,9 +4414,9 @@
height="7"
width="1"
id="rect25960"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25962"
width="1"
height="7"
@@ -4440,9 +4432,9 @@
height="7"
width="1"
id="rect25964"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25966"
width="1"
height="7"
@@ -4458,9 +4450,9 @@
height="7"
width="1"
id="rect25968"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25970"
width="1"
height="7"
@@ -4476,9 +4468,9 @@
height="7"
width="1"
id="rect25972"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25974"
width="1"
height="7"
@@ -4494,9 +4486,9 @@
height="7"
width="1"
id="rect25976"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25978"
width="1"
height="7"
@@ -4512,9 +4504,9 @@
height="7"
width="1"
id="rect25980"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25982"
width="1"
height="7"
@@ -4530,9 +4522,9 @@
height="7"
width="1"
id="rect25984"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25986"
width="1"
height="7"
@@ -4548,9 +4540,9 @@
height="7"
width="1"
id="rect25988"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25990"
width="1"
height="7"
@@ -4566,9 +4558,9 @@
height="7"
width="1"
id="rect25992"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25994"
width="1"
height="7"
@@ -4577,7 +4569,7 @@
rx="0"
ry="0" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect25996"
width="1"
height="7"
@@ -4593,9 +4585,9 @@
height="7"
width="1"
id="rect25998"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect26000"
width="1"
height="7"
@@ -4611,7 +4603,7 @@
height="7"
width="1"
id="rect26002"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
ry="0"
rx="0"
@@ -4620,7 +4612,7 @@
height="7"
width="1"
id="rect11034"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
</g>
</g>
<g
@@ -4634,9 +4626,9 @@
height="1"
width="6"
id="rect26734"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect26788"
width="6"
height="1"
@@ -4652,9 +4644,9 @@
height="1"
width="6"
id="rect26842"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect26896"
width="6"
height="1"
@@ -4670,7 +4662,7 @@
height="1"
width="6"
id="rect26950"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
ry="0"
rx="0"
@@ -4679,9 +4671,9 @@
height="1"
width="6"
id="rect27004"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27058"
width="6"
height="1"
@@ -4697,9 +4689,9 @@
height="1"
width="6"
id="rect27112"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27166"
width="6"
height="1"
@@ -4715,9 +4707,9 @@
height="1"
width="6"
id="rect27220"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27274"
width="6"
height="1"
@@ -4733,9 +4725,9 @@
height="1"
width="6"
id="rect27328"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27382"
width="6"
height="1"
@@ -4751,9 +4743,9 @@
height="1"
width="6"
id="rect27436"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27490"
width="6"
height="1"
@@ -4769,9 +4761,9 @@
height="1"
width="6"
id="rect27544"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27598"
width="6"
height="1"
@@ -4787,9 +4779,9 @@
height="1"
width="6"
id="rect27652"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27706"
width="6"
height="1"
@@ -4805,9 +4797,9 @@
height="1"
width="6"
id="rect27760"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27814"
width="6"
height="1"
@@ -4823,9 +4815,9 @@
height="1"
width="6"
id="rect27868"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate" />
<rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.70000005;marker:none;enable-background:accumulate"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.9;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.7;marker:none;enable-background:accumulate"
id="rect27922"
width="6"
height="1"
@@ -7159,551 +7151,784 @@
<g
inkscape:groupmode="layer"
id="layer8"
- inkscape:label="2.81"
+ inkscape:label="icons"
style="display:inline">
- <path
- inkscape:connector-curvature="0"
- id="path6587"
- d="M 61.503909,123 A 6.5039066,6.5039066 0 0 1 55.000003,129.50391 6.5039066,6.5039066 0 0 1 48.496097,123 6.5039066,6.5039066 0 0 1 55.000003,116.4961 6.5039066,6.5039066 0 0 1 61.503909,123 Z"
- style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- id="g10975"
- transform="translate(-378.00707,-293.99994)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ transform="translate(-243,336)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21571"
+ inkscape:label="DA-26">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect37443-3"
+ width="18"
+ height="18"
+ x="771.99976"
+ y="-300"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ inkscape:connector-curvature="0"
+ id="rect21332"
+ d="M 775.46875,284 C 774.66371,284 774,284.66371 774,285.46875 v 11.0625 c 0,0.80504 0.66371,1.46875 1.46875,1.46875 h 8.0625 C 784.33629,298 785,297.33629 785,296.53125 v -0.58203 c -1.68181,-0.24823 -3,-1.70468 -3,-3.44922 0,-1.74454 1.31819,-3.20099 3,-3.44922 v -3.58203 C 785,284.66371 784.33629,284 783.53125,284 Z M 775,285 h 9 v 3 h -9 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 785.5,295 c -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 z"
+ id="circle21336"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
<g
- id="g10009"
- transform="translate(5.3904633e-4,-20.999933)"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ transform="translate(-285,336)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21575"
+ inkscape:label="DA-25">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0-02"
+ width="18"
+ height="18"
+ x="792.99976"
+ y="-300"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ sodipodi:nodetypes="sscssssccsssscccss"
+ inkscape:connector-curvature="0"
+ id="rect21315-8"
+ d="m 797,284 c -1.09935,0 -2,0.90065 -2,2 v 2 8 c 0,1.09935 0.90065,2 2,2 h 7 c 1.09935,0 2,-0.90065 2,-2 v -0.5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 0.5 c 0,0.56265 -0.43735,1 -1,1 h -7 c -0.56265,0 -1,-0.43735 -1,-1 v -8 h 10 v -2 c 0,-1.09935 -0.90065,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 806.5,294 c -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 z"
+ id="circle21317-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
<g
- transform="translate(-380,231)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g12153"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ id="g36632-6"
+ transform="translate(771.007,-831)"
+ style="display:inline;enable-background:new"
+ inkscape:label="DA-24">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect37443-9"
+ width="18"
+ height="18"
+ x="-284.00723"
+ y="-1467"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <g
+ id="g36628-4">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -272.5,1452 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -5,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 3,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z"
+ id="circle36626-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssssssssss" />
+ </g>
+ <path
+ id="path9540"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -268.5,1463 c 0.6573,0.01 0.6573,0.9907 0,1 h -3.5 v -1 z m -8.50781,0 v 1 h -4.5 c -0.6573,-0.01 -0.6573,-0.9907 0,-1 z m -4.5,-10 c -0.6573,0.01 -0.6573,0.9907 0,1 h 6.5 v -1 z M -270,1453 v 1 h 1.5 c 0.6573,-0.01 0.6573,-0.9907 0,-1 z m -11.50781,5 c -0.6573,0.01 -0.6573,0.9907 0,1 h 1.5 v -1 z m 6.50781,0 v 1 h 6.5 c 0.6573,-0.01 0.6573,-0.9907 0,-1 z"
+ inkscape:connector-curvature="0" />
+ </g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="translate(-336.00001,210.00001)"
- id="g12215"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ id="g10845"
+ inkscape:label="DA-23"
+ style="display:inline;enable-background:new">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0-95"
+ width="18"
+ height="18"
+ x="465.99979"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 473,628 a 1.0001,1.0001 0 1 0 0,2 h 2 a 1.0001,1.0001 0 1 0 0,-2 z m -4.5,-6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 1 0 -1,0 v 4.5 h -8 v -7 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 H 469 v -2 h 4.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path24739-4" />
+ <path
+ sodipodi:nodetypes="sssssccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path27428"
+ d="m 478.50003,620.0003 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ </g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12492"
- transform="translate(20.999999)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
- <g
- id="g12457"
- transform="matrix(0.69230791,0,0,0.69230793,-403.07713,196.14887)"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.44444394;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ id="g19348"
+ transform="translate(-252,-1102)"
+ inkscape:label="DA-22">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect37443-14"
+ width="18"
+ height="18"
+ x="696.99982"
+ y="-1738"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <g
+ style="display:inline;fill:#ffffff;stroke:#ffffff"
+ id="g19344">
+ <g
+ id="g19337"
+ style="opacity:0;fill:#ffffff" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path19342"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 701,1726 v 7.25 c 0,0.4861 0.17047,0.94 0.49023,1.2598 0.31977,0.3197 0.77366,0.4902 1.25977,0.4902 h 6.5 c 0.48611,0 0.94,-0.1705 1.25977,-0.4902 C 710.82953,1734.19 711,1733.7361 711,1733.25 V 1726 h -1 v 7.25 c 0,0.2639 -0.0795,0.435 -0.19727,0.5527 C 709.685,1733.9205 709.51389,1734 709.25,1734 h -6.5 c -0.26389,0 -0.435,-0.08 -0.55273,-0.1973 C 702.07953,1733.685 702,1733.5139 702,1733.25 V 1726 Z m 3.5,-4 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 1.5 h -3.5 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11 c 0.67616,0.01 0.67616,-1.0096 0,-1 H 708 v -1.5 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 z m 0.5,1 h 2 v 1 h -2 z"
+ sodipodi:nodetypes="cscsscsccscsscscccccccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 704.49219,1726.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 4 c -0.01,0.6762 1.00956,0.6762 1,0 v -4 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z m 3,0 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 4 c -0.01,0.6762 1.00956,0.6762 1,0 v -4 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z"
+ id="path19346"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ </g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12921"
- transform="translate(21.999999,-3)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
- <g
- style="display:inline;opacity:0.41300001;fill:#ffffff;enable-background:new"
- id="g5202-0"
- transform="translate(496.99495,-311.99288)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ id="g15578-7"
+ transform="matrix(1,0,0,-1,894,921)"
+ inkscape:label="DA-21">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0-08"
+ width="18"
+ height="18"
+ x="-470.00021"
+ y="-303"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -467.5,287 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.5 v -1 h -2 v -9 h 9 v 2 h 1 v -2.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path15572-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -463.50002,301 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -9 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 9 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 4.5 h -1 v -4 h -8 v 8 h 5 v -2.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 2.5 1 v 0.5 c -2e-5,0.1326 -0.0527,0.25972 -0.14648,0.35352 l -3,3 c -0.0938,0.0938 -0.22092,0.14646 -0.35352,0.14648 z"
+ id="path15574-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccsccc" />
+ </g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g13534"
- transform="translate(-9.5367432e-7,21)"
+ transform="matrix(-0.53033,-0.53033,-0.53033,0.53033,706.864,657.759)"
+ style="display:inline;fill:#ffffff;stroke:none;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ id="g10178-9"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ inkscape:export-ydpi="96"
+ inkscape:label="DA-20">
+ <rect
+ style="display:inline;fill:none;stroke:none;stroke-width:0;stroke-dasharray:none;enable-background:new"
+ id="rect37443-1"
+ width="18"
+ height="18"
+ x="403"
+ y="-636"
+ transform="matrix(-0.942809,-0.942809,0.942809,-0.942809,1286.58,46.2961)"
+ inkscape:label="frame" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 306.99023,241.72461 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 5.93359 h -5.93359 a 0.66673335,0.66673335 0 1 0 0,1.33204 h 5.93359 v 5.93359 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -5.93359 h 5.93359 a 0.66673335,0.66673335 0 1 0 0,-1.33204 h -5.93359 v -5.93359 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
+ id="path10253"
+ inkscape:connector-curvature="0" />
+ </g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g13838"
- transform="rotate(90,160.07935,395.5873)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- id="g13835"
- transform="matrix(0,1,1,0,205.49208,-205.33334)"
- style="fill:#ffffff" />
+ id="g37394"
+ inkscape:label="DA-19"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12791-5"
+ d="m 385,621 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0-0"
+ width="18"
+ height="18"
+ x="381.99985"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ </g>
+ <g
+ id="g37409"
+ inkscape:label="DA-18"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 370,625 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
+ id="circle14040"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect37443-4"
+ width="18"
+ height="18"
+ x="360.99988"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ </g>
+ <g
+ id="g37403"
+ inkscape:label="DA-17"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 353,628 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m 9,-3 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path14337" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0-8"
+ width="18"
+ height="18"
+ x="339.99988"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
</g>
<g
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g6922"
- transform="translate(-378.0172,105)"
+ id="g12707"
+ style="display:inline;opacity:0.99;fill:#ffffff;stroke-width:1.07692;enable-background:new"
+ transform="matrix(0.928571,0,0,0.928571,22.9301,44.2907)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <circle
- r="0"
- cy="162.5"
- cx="415.5"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="ellipse13645" />
+ inkscape:export-ydpi="96"
+ inkscape:label="DA-16">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 327.94922,619.99609 c -0.89539,0.0396 -1.29072,1.14622 -0.62305,1.74414 l 1.37305,1.26563 h -6.69727 c -1.36099,-0.0279 -1.36099,2.02794 0,2 h 3.0918 c -0.003,0.002 -0.005,0.004 -0.008,0.006 l -4.75,4.24805 c -0.99479,0.88933 0.33919,2.38151 1.33398,1.49218 l 2.33985,-2.09375 c 0.0823,2.95524 2.51793,5.34766 5.49218,5.34766 3.02565,0 5.49805,-2.47428 5.49805,-5.5 0,-1.56564 -0.6642,-2.98065 -1.72266,-3.98438 l -4.59961,-4.25195 c -0.19597,-0.18575 -0.45872,-0.28437 -0.72851,-0.27344 z m 1.55273,5.00977 c 1.94471,0 3.5,1.5551 3.5,3.5 0,1.94489 -1.55529,3.5 -3.5,3.5 -1.94472,0 -3.5,-1.55511 -3.5,-3.5 0,-1.9449 1.55528,-3.5 3.5,-3.5 z m -0.0176,1.78516 a 1.7319623,1.7139345 0 0 0 -1.73243,1.71484 1.7319623,1.7139345 0 0 0 1.73243,1.71289 1.7319623,1.7139345 0 0 0 1.73242,-1.71289 1.7319623,1.7139345 0 0 0 -1.73242,-1.71484 z"
+ transform="matrix(1.07692,0,0,1.07692,-24.694,-47.6977)"
+ id="path12703"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.75216;enable-background:new"
+ id="rect37443-2"
+ width="19.384615"
+ height="19.384617"
+ x="318.84433"
+ y="-637.22546"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
</g>
<g
- style="display:inline;fill:#ffffff;stroke-width:1.15384614;enable-background:new"
- id="g14341"
- transform="translate(-441.00001,525.00001)" />
- <g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14199"
- transform="translate(-9.5367432e-7,20)" />
- <g
- style="display:inline;fill:#ffffff;stroke:#666666;enable-background:new"
- id="g14215"
- inkscape:transform-center-x="-1.2499"
- inkscape:transform-center-y="9.9999999e-006"
- transform="matrix(0,-1,-1,0,723.9999,577.00011)" />
+ id="g22365"
+ transform="translate(-1.85367e-6,-26)"
+ inkscape:label="DA-15">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0-91"
+ width="18"
+ height="18"
+ x="297.99991"
+ y="-662"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ id="path22215"
+ d="m 302,649 v 8 h 4 v -8 z m 1,1 h 2 v 1 h -2 z m 0,2 h 2 v 1 h -2 z m 0,2 h 2 v 1 h -2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="sssssssssccccc"
+ inkscape:connector-curvature="0"
+ id="rect21916"
+ d="m 301.5,647 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 9 c 0,0.82235 0.67765,1.5 1.5,1.5 h 11 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -9 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m -0.5,1 h 12 v 10 h -12 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14644"
- transform="translate(-9.5367432e-7,30)" />
- <circle
- transform="scale(-1)"
- cy="-286.5"
- cx="-353.50003"
- id="ellipse14264"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- r="0" />
+ id="g37415"
+ inkscape:label="DA-14"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 286,622 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z"
+ id="circle13982"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect37443-8"
+ width="18"
+ height="18"
+ x="276.99994"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ </g>
+ <g
+ id="g37418"
+ inkscape:label="DA-13"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265,622 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z m 0,1 c 2.21506,0 4,1.78494 4,4 0,2.21506 -1.78494,4 -4,4 -2.21506,0 -4,-1.78494 -4,-4 0,-2.21506 1.78494,-4 4,-4 z"
+ id="path13966"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0-9"
+ width="18"
+ height="18"
+ x="255.99994"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ </g>
+ <g
+ id="g37400"
+ inkscape:label="DA-12"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 241.25,624 c -0.36727,2.9e-4 -0.60893,0.38318 -0.45117,0.71484 l 2.25,4.75 c 0.18125,0.37923 0.72109,0.37923 0.90234,0 l 2.25,-4.75 C 246.35893,624.38318 246.11727,624.00029 245.75,624 Z"
+ id="path14837"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect37443-5"
+ width="18"
+ height="18"
+ x="234.99995"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ </g>
+ <g
+ id="g37412"
+ inkscape:label="DA-11"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 220.4707,623.75 c -0.26463,0.0156 -0.47113,0.23492 -0.4707,0.5 v 4.25 c 1.7e-4,0.35718 0.36395,0.59902 0.69336,0.46094 l 4.75,-2 c 0.39771,-0.16741 0.41088,-0.72615 0.0215,-0.91211 l -4.75,-2.25 c -0.076,-0.0366 -0.15996,-0.0534 -0.24416,-0.0488 z"
+ id="path14031"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0-3"
+ width="18"
+ height="18"
+ x="213.99997"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ </g>
+ <g
+ id="g37406"
+ inkscape:label="DA-10"
+ style="display:inline;enable-background:new">
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 202.5,621.00003 a 5.4999997,5.4999997 0 0 0 -5.5,5.5 5.4999997,5.4999997 0 0 0 5.5,5.5 5.4999997,5.4999997 0 0 0 5.5,-5.5 5.4999997,5.4999997 0 0 0 -5.5,-5.5 z m -0.002,1.98438 a 0.50005001,0.50005001 0 0 1 0.50781,0.52343 v 2.5 h 2.50195 a 0.50005001,0.50005001 0 1 1 0,0.99805 h -2.50195 v 2.50195 a 0.50005001,0.50005001 0 0 1 -0.50586,0.50586 0.50005001,0.50005001 0 0 1 -0.49219,-0.50586 v -2.50195 h -2.5 a 0.50005001,0.50005001 0 1 1 0,-0.99805 h 2.5 v -2.5 a 0.50005001,0.50005001 0 0 1 0.49024,-0.52343 z"
+ id="path14370"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect37443"
+ width="18"
+ height="18"
+ x="192.99998"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ </g>
+ <g
+ id="g37397"
+ inkscape:label="DA-9"
+ style="display:inline;enable-background:new">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8-0"
+ width="18"
+ height="18"
+ x="172"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 184.49609,623.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 L 186.29297,627 h -10.58594 l 2.14649,-2.14648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 175.70703,628 h 10.58594 l -2.14649,2.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
+ id="path13677-7"
+ inkscape:connector-curvature="0" />
+ </g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g13212"
- transform="rotate(-180,454.00583,490.49795)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ id="g21059"
+ inkscape:label="DA-8"
+ style="display:inline;enable-background:new">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5-8"
+ width="18"
+ height="18"
+ x="151"
+ y="-636.01636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path9229"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 156,629.49414 c 0,0.27842 0.2216,0.50584 0.5,0.50586 h 7 c 0.4051,6e-4 0.6427,-0.45544 0.4102,-0.78711 l -3.5,-5 c -0.199,-0.28542 -0.6214,-0.28542 -0.8204,0 l -3.5,5 c -0.058,0.0826 -0.089,0.1806 -0.09,0.28125 z"
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:label="path9228" />
+ </g>
<g
- transform="translate(-105,22)"
- id="g13043"
- style="display:inline;opacity:0.4;fill:#ffffff;enable-background:new">
- <g
- id="g13161"
- style="fill:#ffffff" />
+ id="g21032"
+ inkscape:label="DA-7"
+ style="display:inline;enable-background:new">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004-5"
+ width="18"
+ height="18"
+ x="130"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path9227"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 141.49531,622.99926 c 0.27843,0 0.50584,0.2216 0.50587,0.5 v 7 c 5.9e-4,0.4051 -0.45545,0.6427 -0.78712,0.4102 l -5,-3.5 c -0.28541,-0.199 -0.28541,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z"
+ sodipodi:nodetypes="ccccccccc" />
</g>
- <path
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="circle21483"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- r="4"
- cy="335.5"
- cx="493.5"
- d=""
- inkscape:connector-curvature="0" />
- <circle
- r="0"
- cx="456.5"
- cy="420.50391"
- id="ellipse20722"
- style="display:inline;opacity:0.1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(71.999999)"
- id="g22120" />
- <path
- cx="306.99524"
- cy="291.97034"
- r="4.4703369"
- style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
- id="path24502"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- d=""
- inkscape:connector-curvature="0" />
+ id="g21016"
+ inkscape:label="DA-6"
+ style="display:inline;enable-background:new">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect21004"
+ width="18"
+ height="18"
+ x="109"
+ y="-636.03986"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ d="m 113.9992,624.50586 c 0,-0.27842 0.2216,-0.50584 0.5,-0.50586 h 7 c 0.4051,-6e-4 0.6427,0.45544 0.4102,0.78711 l -3.5,5 c -0.199,0.28542 -0.6214,0.28542 -0.8204,0 l -3.5,-5 c -0.058,-0.0826 -0.089,-0.1806 -0.09,-0.28125 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9225"
+ inkscape:connector-curvature="0" />
+ </g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new"
- id="g22419"
- transform="matrix(-0.866668,0,0,0.866668,728.467,163.39943)" />
+ id="g13525"
+ inkscape:label="DA-5"
+ style="display:inline;enable-background:new">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect13513"
+ width="18"
+ height="18"
+ x="88"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path9205-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 94.50586,623 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
<g
- style="display:inline;fill:#ffffff;stroke:#666666;enable-background:new"
- id="g22765"
- transform="translate(29.999999)" />
+ id="g13493"
+ inkscape:label="DA-4"
+ style="display:inline;enable-background:new">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect13481"
+ width="18"
+ height="18"
+ x="67"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20483"
+ d="m 75.999998,620 c -3.860077,0 -7,3.13991 -7,7 0,3.86009 3.139924,7 7,7 3.860076,0 7,-3.13991 7,-7 0,-3.86009 -3.139923,-7 -7,-7 z m 2.990234,2.98633 a 1.0001,1.0001 0 0 1 0.716797,1.7207 L 77.41406,627 l 2.292969,2.29297 a 1.0001,1.0001 0 1 1 -1.414062,1.41406 l -2.292969,-2.29297 -2.292969,2.29297 a 1.0001,1.0001 0 1 1 -1.414062,-1.41406 L 74.585936,627 72.292967,624.70703 a 1.0001,1.0001 0 0 1 0.697265,-1.7168 1.0001,1.0001 0 0 1 0.716797,0.30274 l 2.292969,2.29297 2.292969,-2.29297 a 1.0001,1.0001 0 0 1 0.697265,-0.30664 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(46.999999,3)"
- id="g23484" />
+ id="g10004"
+ inkscape:label="DA-3"
+ style="display:inline;enable-background:new">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect13319-7"
+ width="18"
+ height="18"
+ x="46"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 55.011717,620 c -0.689946,-0.004 -1.325726,0.38513 -1.634766,1.00195 l -5.1875,10.3711 c -0.594248,1.18749 0.293094,2.62623 1.621094,2.62695 h 10.378906 c 1.327265,-7.2e-4 2.213373,-1.43788 1.621094,-2.625 l -5.1875,-10.37305 C 56.317741,620.39258 55.693326,620.0046 55.011717,620 Z m -1.011719,3 h 2 v 6 h -2 z m 0,7 h 2 v 2 h -2 z"
+ id="path20558"
+ inkscape:connector-curvature="0" />
+ </g>
<g
- style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
- id="g22604"
- transform="translate(420,147)">
- <g
- style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- transform="matrix(0,-1,-1,0,688.99474,-44.97944)"
- id="g22557" />
- </g>
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22477"
- transform="rotate(180,475,353.5)" />
- <g
+ id="g20495"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(2.9786369,-3.978636)"
- id="g22894" />
+ inkscape:label="DA-2">
+ <rect
+ style="display:inline;fill:none;stroke-width:1.627;enable-background:new"
+ id="rect13319"
+ width="18"
+ height="18"
+ x="25.000002"
+ y="-636"
+ transform="scale(1,-1)"
+ inkscape:label="frame" />
+ <path
+ id="path20493"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 34,622 c -1.783333,0 -3,1.5 -3,3 h 2 c 0,-0.5 0.283333,-1 1,-1 0.716667,0 1,0.5 1,1 0,0.24702 -0.03644,0.30082 -0.117188,0.41016 -0.08074,0.10934 -0.253932,0.25966 -0.513671,0.4707 C 33.849662,626.30294 33,627.16667 33,628.5 v 0.5 h 2 v -0.5 c 0,-0.66667 0.150338,-0.67794 0.630859,-1.06836 0.240261,-0.19521 0.567072,-0.43551 0.861329,-0.83398 C 36.786444,626.19918 37,625.62798 37,625 c 0,-1.5 -1.216667,-3 -3,-3 z m -1,8.00009 h 2 v 2 H 33 Z M 34,620 c -3.86007,0 -7,3.13991 -7,7 0,3.86009 3.13993,7 7,7 3.86008,0 7,-3.13991 7,-7 0,-3.86009 -3.13992,-7 -7,-7 z m 0,1 c 3.31964,0 6,2.68035 6,6 0,3.31965 -2.68036,6 -6,6 -3.31963,0 -6,-2.68035 -6,-6 0,-3.31965 2.68037,-6 6,-6 z"
+ inkscape:connector-curvature="0" />
+ </g>
<g
- transform="matrix(-1,0,0,1,761,0)"
- id="g23294"
- style="display:inline;fill:#ffffff;enable-background:new" />
+ id="g26759"
+ inkscape:label="CA-26"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 534.49219,599 C 534.2199,599 534,599.223 534,599.5 v 1.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 3 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.5 c 0,0.277 0.2199,0.5 0.49219,0.5 h 0.0156 C 534.7801,608 535,607.777 535,607.5 v -8 c 0,-0.277 -0.2199,-0.5 -0.49219,-0.5 z m 1.25781,1 v 7 H 537 c 1.69468,0 3,-1.30532 3,-3 v -1 c 0,-1.69468 -1.30532,-3 -3,-3 z"
+ id="path22706-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 541.48633,603.02734 c -0.55718,0.017 -0.67407,0.7946 -0.14649,0.97461 1.47614,0.5388 2.51343,1.91841 2.64454,3.53711 0.13105,1.61806 -0.67507,3.15416 -2.04493,3.94532 C 541.32404,611.8398 540.6905,612 540,612 h -9 v 1 h 9 c 0.84916,0 1.67422,-0.20648 2.43945,-0.64844 1.70819,-0.98656 2.70486,-2.89381 2.54297,-4.89258 -0.16183,-1.99811 -1.44941,-3.72267 -3.30078,-4.39843 -0.0622,-0.024 -0.12865,-0.0353 -0.19531,-0.0332 z"
+ id="path22783-2-0"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
+ </g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="rotate(90,681.00003,3.9999745)"
- id="g23519" />
+ id="g3791"
+ inkscape:label="CA-24">
+ <path
+ sodipodi:nodetypes="csssscccccc"
+ inkscape:connector-curvature="0"
+ id="path28911-6"
+ d="m 489,604 v 8 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -8 h -1 v 8 h -12 v -8 z"
+ style="opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ <path
+ sodipodi:nodetypes="ssccccsssccccc"
+ inkscape:connector-curvature="0"
+ style="vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 490,599 c -0.54532,0 -1,0.45468 -1,1 v 3 h 1 12 1 v -3 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 h -2 z"
+ id="path28913-4" />
+ </g>
<g
- id="g23547"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="matrix(-1,0,0,1,985.8323,-544.99999)" />
+ style="display:inline;enable-background:new"
+ id="g28909-7"
+ transform="rotate(180,535.5,631.5)"
+ inkscape:label="CA-25">
+ <path
+ style="opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 7,654 v 8 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -8 h -1 v 8 H 8 v -8 z"
+ transform="translate(540,1)"
+ id="path28905-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssscccccc" />
+ <path
+ sodipodi:nodetypes="cssssccccccccc"
+ inkscape:connector-curvature="0"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 27,680 v 3 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -3 H 40 28 Z m 1,1 h 2 v 2 h -2 z"
+ transform="matrix(1,0,0,-1,520,1334)"
+ id="path28907-4" />
+ </g>
<g
- id="g6085"
- style="fill:#ffffff">
+ id="g9239"
+ inkscape:label="CA-23"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 199.5,221.00391 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.5 v 1.08789 c -2.83241,0.47934 -5.00001,2.94243 -5,5.9082 0,3.30787 2.69334,6 6.00195,6 3.30861,0 6.00196,-2.69214 6.00196,-6 0,-1.22417 -0.37149,-2.36223 -1.00391,-3.3125 a 0.50005,0.50005 0 0 0 0.10352,-0.0801 l 1.75,-1.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1.75,1.75 a 0.50005,0.50005 0 0 0 -0.0117,0.0137 C 205.28833,223.73959 203.73131,223 202.00195,223 c -6.5e-4,0 -0.001,0 -0.002,0 v -0.99609 h 1.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z M 202.00195,224 c 2.76833,0 5.00196,2.23273 5.00196,5 0,2.76726 -2.23363,5 -5.00196,5 C 199.23362,234 197,231.76727 197,229 c -1e-5,-2.76727 2.23362,-5 5.00195,-5 z"
- id="path17270"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468.4999,598.99994 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3.5 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3.5 z"
+ id="path24895-4"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 201.49219,224.99609 A 0.50005,0.50005 0 0 0 201,225.50391 v 3.91992 a 0.50005,0.50005 0 0 0 0.11328,0.40429 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.39453,0.10352 H 204.5 a 0.50005,0.50005 0 1 0 0,-1 H 202 v -3.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50782 z"
- id="path17274"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 471.4999,601.99994 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h 1 v -1 h 1 v -1 z m 2.5,0 v 1 h 2 v -1 z m 3,0 v 1 h 1 v 1 h 1 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -6,3 v 2 h 1 v -2 z m 7,0 v 2 h 1 v -2 z m -7,3 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v -1 h -1 v -1 z m 7,0 v 1 h -1 v 1 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.5 z m -4,1 v 1 h 2 v -1 z"
+ id="path24923-3"
inkscape:connector-curvature="0" />
</g>
<g
- id="g6171"
- style="fill:#ffffff">
+ id="g9217"
+ inkscape:label="CA-22"
+ style="display:inline;enable-background:new">
<path
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc"
inkscape:connector-curvature="0"
- id="path17287"
- d="m 405.5,476.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-1e-5 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,1.99219 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 1,0 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 -1,0 -1.99999,-10e-6 -3,0 z m -5,3.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-1e-5 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,1.99219 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-10e-6 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <g
- id="g17301"
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;enable-background:new"
- transform="translate(-41.999692,86.008184)">
- <path
- inkscape:connector-curvature="0"
- id="path17299"
- d="m 452.49219,387 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 V 387.5 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,0 -1.3386,0 -2.00781,0 z m 4.50781,1.98438 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66922,0 -1.33859,0 -2.00781,0 z m -0.49219,4 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00253,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,0 -2.00781,0 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- </g>
+ id="path24965-8"
+ d="m 447.5,599 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -9 h 9 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 9.99219,11.74219 A 0.50005,0.50005 0 0 0 457,611.25 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.25 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path24881-9"
+ d="m 455.5,602 c -0.58333,0 -1.08834,0.16632 -1.52734,0.45898 -0.43901,0.29267 -0.82618,0.6875 -1.32618,1.1875 l -1,1 c -0.5,0.5 -0.86283,0.85517 -1.17382,1.0625 C 450.16166,605.91632 449.91667,606 449.5,606 h -1 v 1 h 1 c 0.58333,0 1.08834,-0.16632 1.52734,-0.45898 0.43901,-0.29267 0.82618,-0.6875 1.32618,-1.1875 l 1,-1 c 0.5,-0.5 0.86283,-0.85517 1.17382,-1.0625 C 454.83834,603.08368 455.08333,603 455.5,603 h 1 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 201.5,389 a 0.50005,0.50005 0 0 0 -0.41406,0.2207 l -5.75,8.5 a 0.50005,0.50005 0 0 0 -0.0254,0.041 C 195.09791,398.15241 195,398.57992 195,399 c 0,1.21742 0.89627,2.23231 2.16602,2.91602 C 198.43576,402.59972 200.13233,403 202,403 c 1.86767,0 3.56424,-0.40028 4.83398,-1.08398 C 208.10373,401.23231 209,400.21742 209,399 c 0,-0.41956 -0.0964,-0.84696 -0.3125,-1.24023 a 0.50005,0.50005 0 0 0 -0.0234,-0.0391 l -5.75,-8.5 A 0.50005,0.50005 0 0 0 202.5,389 Z m 0.26562,1 h 0.46876 l 5.58007,8.24805 C 207.94195,398.48303 208,398.73145 208,399 c 0,0.71558 -0.55783,1.45211 -1.64062,2.03516 C 205.27658,401.6182 203.72216,402 202,402 c -1.72216,0 -3.27658,-0.3818 -4.35938,-0.96484 C 196.55783,400.45211 196,399.71558 196,399 c 0,-0.26272 0.0617,-0.52241 0.1875,-0.75586 z"
- id="path17361"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 55,389 c -3.86012,0 -7,3.13988 -7,7 0,3.86012 3.13988,7 7,7 3.86012,0 7,-3.13988 7,-7 0,-3.86012 -3.13988,-7 -7,-7 z m 0,1 c 3.31968,0 6,2.68032 6,6 0,3.31968 -2.68032,6 -6,6 -3.31968,0 -6,-2.68032 -6,-6 0,-3.31968 2.68032,-6 6,-6 z"
- id="path17412"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 6.5,389 A 0.50005,0.50005 0 0 0 6,389.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 19.5,389 Z m 0.5,1 h 12 v 12 H 7 Z"
- id="rect17430"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path17434"
- d="m 27.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.949219 L 32,420.62695 V 423.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.87305 L 39.550781,414 H 40.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 40.5,410 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 30.5,410 Z m 0.5,1 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -7,1 h 6 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.914062 l -3.214843,6 h -2.398438 l -3.214843,-6 H 30.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 2,9 h 2 v 2 h -2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- id="g17481"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="translate(-332.00634,585.99911)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- style="opacity:0.7;fill:#ffffff;stroke-width:1.1535517"
- transform="matrix(0.86707513,0,0,0.86670066,799.68613,161.07329)"
- id="g17477">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 432.96875,577.99609 a 0.50015801,0.499942 0 0 0 -0.0488,0.006 0.50015801,0.499942 0 0 0 -0.0879,0.0215 c -0.22504,0.005 -0.45054,4.4e-4 -0.67383,0.0273 -1.50924,0.18184 -2.95823,0.85326 -4.0957,1.98242 -2.27494,2.25834 -2.72493,5.78034 -1.08984,8.53711 1.26078,2.1257 3.51721,3.36761 5.89257,3.41407 6.5e-4,10e-6 10e-4,-2e-5 0.002,0 a 0.50015801,0.499942 0 0 0 0.32031,-0.01 c 0.60037,-0.016 1.20402,-0.0867 1.80078,-0.26367 a 0.50073965,0.5005234 0 1 0 -0.28516,-0.95899 c -0.52501,0.15567 -1.05482,0.21548 -1.58203,0.22657 -0.32205,-0.21838 -0.86207,-0.82158 -1.28906,-1.77344 -0.15847,-0.35327 -0.29568,-0.76712 -0.41992,-1.20508 H 433.5 a 0.50043241,0.50021629 0 1 0 0,-1 h -2.31641 C 431.07457,586.38509 431,585.72514 431,585 c 0,-0.72848 0.074,-1.38791 0.18359,-2 h 3.5625 c 0.15752,0.77172 0.25391,1.61389 0.25391,2.5 a 0.50015801,0.499942 0 1 0 1,0 c 0,-0.883 -0.0936,-1.71998 -0.24023,-2.5 h 2.88671 c 0.41677,1.17713 0.47801,2.4832 0.0937,3.74609 a 0.50015801,0.499942 0 1 0 0.95704,0.28907 c 0.93293,-3.06617 -0.34127,-6.37791 -3.08789,-8.03125 -1.07945,-0.64978 -2.27964,-0.96925 -3.47657,-0.99219 a 0.50015801,0.499942 0 0 0 -0.14648,-0.0156 0.50015801,0.499942 0 0 0 -0.0176,0 z m 0.0273,1.13086 c 0.3107,0.30928 0.79344,0.97648 1.16602,1.90039 0.12076,0.29947 0.23379,0.62673 0.33594,0.97266 h -3.08399 c 0.12298,-0.42695 0.25956,-0.8299 0.41602,-1.17578 0.37038,-0.81882 0.82294,-1.39159 1.16601,-1.69727 z m 1.33789,0.0312 c 0.60769,0.13919 1.20278,0.36589 1.75977,0.70118 0.89497,0.53872 1.60631,1.28287 2.10156,2.14062 h -2.66797 c -0.12978,-0.47868 -0.2726,-0.9368 -0.4375,-1.3457 -0.23548,-0.58396 -0.48644,-1.07928 -0.75586,-1.4961 z m -2.70507,0.0156 c -0.24979,0.35295 -0.49203,0.75628 -0.71094,1.24023 -0.21038,0.4651 -0.38853,1.0058 -0.53906,1.58594 h -2.5586 c 0.26045,-0.4489 0.56294,-0.87823 0.94531,-1.25781 0.81076,-0.80484 1.80942,-1.32143 2.86329,-1.56836 z m -4.26758,3.80664 A 0.50043241,0.50021629 0 0 0 427.50195,583 h 2.66993 C 430.0701,583.62227 430,584.28017 430,585 c 0,0.71751 0.0707,1.37536 0.17188,2 h -2.66993 a 0.50043241,0.50021629 0 0 0 -0.14648,0.0234 c -0.47566,-1.32219 -0.45827,-2.74775 0.006,-4.04297 z M 427.80469,588 h 2.57226 c 0.15111,0.59053 0.32906,1.14077 0.54102,1.61328 0.21198,0.47256 0.44409,0.86643 0.68555,1.21289 -1.53987,-0.36784 -2.91769,-1.3294 -3.76954,-2.76562 -0.0116,-0.0196 -0.0179,-0.0409 -0.0293,-0.0606 z"
- transform="matrix(1.1533026,0,0,1.1538009,-539.37632,-861.97281)"
- id="path17465"
- inkscape:connector-curvature="0" />
- <path
- cx="-40.000011"
- cy="-186.99979"
- r="7.5"
- id="path17471"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.1535517;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d=""
- inkscape:connector-curvature="0" />
- </g>
+ id="g17698"
+ inkscape:label="CA-21"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 767.49023,1 c -0.3497,0.00648 -0.58488,0.3607678 -0.45507,0.6855469 l 2,5 c 0.1836,0.4628079 0.85703,0.4022128 0.95507,-0.085937 l 0.43946,-2.1738282 2.16797,-0.4355468 c 0.48875,-0.096787 0.55077,-0.7707095 0.0879,-0.9550782 l -5,-2 C 767.62345,1.0105047 767.55703,0.99855041 767.49023,1 Z"
- id="path17479"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 428.49023,603.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 l 4,4 a 0.50005,0.50005 0 0 0 0.70704,0 l 4,-4 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -3.64648,3.64649 -3.64648,-3.64649 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
+ id="path13549"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(41.999988,1.0000045)"
- id="g10697"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g17701"
+ inkscape:label="CA-20"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 35.744141,52.003906 c -0.89409,0.01843 -1.828792,0.373713 -2.597657,1.142578 l -5,5 c -0.837869,0.83787 -1.178323,2.041781 -1.11914,3.226563 0.05918,1.184782 0.515289,2.376617 1.36914,3.230469 0.852133,0.852132 2.037527,1.314671 3.220704,1.376953 1.183176,0.06228 2.389387,-0.280013 3.236328,-1.126953 l 6,-6 a 0.50005,0.50005 0 1 0 -0.707032,-0.707032 l -6,6 c -0.60312,0.603121 -1.522254,0.886172 -2.476562,0.835938 -0.954308,-0.05023 -1.918539,-0.43807 -2.566406,-1.085938 -0.646149,-0.646148 -1.030262,-1.616046 -1.078125,-2.574218 -0.04786,-0.958173 0.23781,-1.878436 0.828125,-2.46875 l 5,-5 c 1.184971,-1.184974 2.75871,-1.004381 3.554687,-0.248047 0.796393,0.756731 0.863064,2.416231 -0.261719,3.541015 l -4.5,4.5 c -0.592865,0.592866 -1.094745,0.448224 -1.417968,0.125 -0.323224,-0.323223 -0.467866,-0.825103 0.125,-1.417968 l 3.5,-3.5 a 0.50005,0.50005 0 1 0 -0.707032,-0.707032 l -3.5,3.5 c -0.907134,0.907135 -0.801776,2.155255 -0.125,2.832032 0.676777,0.676776 1.924897,0.782134 2.832032,-0.125 l 4.5,-4.5 c 1.483397,-1.483398 1.519845,-3.762437 0.24414,-4.97461 -0.60598,-0.5758 -1.459426,-0.89343 -2.353515,-0.875 z"
- id="path10693"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 410.49414,601.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 3.64649,3.64648 -3.64649,3.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path13551"
inkscape:connector-curvature="0" />
- <rect
- style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="rect10695"
- width="16"
- height="16"
- x="26"
- y="52"
- rx="0.5"
- ry="0.5" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g10711"
- transform="translate(598,-637)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13042"
+ transform="translate(-21,42)"
+ inkscape:label="CA-19">
<g
- transform="translate(-189)"
- id="g10709"
- style="fill:#ffffff">
- <rect
- y="214.99997"
- x="-152"
- height="16"
- width="16"
- id="rect10699"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- transform="rotate(-90,-11.999985,564.99999)" />
- <g
- id="g10703"
- style="fill:#ffffff" />
+ id="g13022"
+ transform="translate(-42.0072,397.993)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
<path
- id="path10707"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -350.42969,690.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -6.00976,6 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C -353.31787,701.0249 -353,700.28067 -353,699.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z m 4.92968,-2.02149 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 447.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 2 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 455 v -2 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -10 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 9 h -12 z"
+ id="path13020"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccc" />
</g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 410.49023,558.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 408.70703,563 H 416.5 a 0.50005,0.50005 0 1 0 0,-1 h -7.79297 l 2.14649,-2.14648 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ id="path12420-1"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-252,-252)"
- id="g10731"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ transform="translate(-583.995,-390.005)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16002-8"
+ inkscape:label="CA-18">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 328,368 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
- id="path10721"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 372.50586,598.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 0.79297 l 3.70703,3.70703 h 0.79297 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -2e-5,-0.1326 -0.0527,-0.25975 -0.14648,-0.35352 l -3,-3 c -0.0938,-0.0938 -0.22092,-0.14646 -0.35352,-0.14648 z m -1.20703,2 -2,2 h -2.79297 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 l -1,1 c -0.19519,0.19528 -0.19519,0.51177 0,0.70704 l 6,6 c 0.19527,0.1952 0.51176,0.1952 0.70704,0 l 1,-1 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -2.79297 l 2,-2 z m -4.05274,7.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3.75,3.75 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3.75,-3.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ transform="translate(583.995,390.005)"
+ id="path15876-9"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-583.995,-390.005)"
+ id="g15882-7"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:label="CA-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 327.12891,369.9668 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 c -2.00329,0.41569 -3.57155,1.99062 -3.97656,3.9961 a 1.0003053,1.0003053 0 1 0 1.96093,0.39648 c 0.24758,-1.22589 1.19732,-2.17949 2.42188,-2.43359 a 1.0001,1.0001 0 0 0 -0.23828,-1.98242 z"
- id="path10723"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 351.50586,598.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.79297 l -2.70703,2.70703 h -2.79297 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 l 6,6 a 0.50005,0.50005 0 0 0 0.70704,0 l 1,-1 a 0.50005,0.50005 0 0 0 0.14648,-0.35352 v -2.79297 l 2.70703,-2.70703 h 0.79297 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35352,-0.14648 z m 0.5,1 h 0.29297 l 2.70703,2.70703 v 0.29297 h -0.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 a 0.50005,0.50005 0 0 0 -0.14648,0.35352 v 2.79297 l -0.5,0.5 -5.29297,-5.29297 0.5,-0.5 h 2.79297 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 a 0.50005,0.50005 0 0 0 0.14648,-0.35352 z m -5.75977,8.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3.75,3.75 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3.75,-3.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ transform="translate(583.995,390.005)"
+ id="path15847-7"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g17713"
+ inkscape:label="CA-16"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 332.49609,373.0957 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -0.75,2.25 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -1.25,1.75 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -1.75,1.25 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -2.23632,0.75 a 0.40004001,0.40004001 0 0 0 -0.27344,0.70508 l 2,1.75 a 0.40004001,0.40004001 0 1 0 0.52734,-0.60156 l -2,-1.75 a 0.40004001,0.40004001 0 0 0 -0.2539,-0.10352 z"
- id="path10727"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path20009-7"
+ d="m 328.5,600 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 1.5 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 332 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -5 v -1.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z m -0.5,6 h 1 v 1 1 h -1 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g15743"
- transform="translate(221,4.4999696e-6)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g17710"
+ inkscape:label="CA-15"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M -98.580078,578 C -99.98888,578 -101,579.16322 -101,580.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.87198 0.530524,-1.5 1.419922,-1.5 0.889383,0 1.580078,0.67678 1.580078,1.5 0,0.82323 -0.69069,1.49999 -1.580078,1.5 h -4.914062 a 0.50005,0.50005 0 1 0 0,1 h 4.914062 C -97.171286,582.99999 -96,581.88555 -96,580.5 c 0,-1.38554 -1.171281,-2.5 -2.580078,-2.5 z m -8.916012,0.004 c -1.38554,0 -2.5,1.17128 -2.5,2.58007 0,1.40881 1.16321,2.41797 2.5,2.41797 a 0.50005,0.50005 0 1 0 0,-1 c -0.87198,0 -1.5,-0.52857 -1.5,-1.41797 0,-0.88938 0.67678,-1.58007 1.5,-1.58007 0.82323,0 1.49804,0.69069 1.49804,1.58007 v 4.91211 a 0.50005,0.50005 0 1 0 1,0 v -4.91211 c -10e-6,-1.40879 -1.1125,-2.58007 -2.49804,-2.58007 z m 6.98828,5.98828 A 0.50005,0.50005 0 0 0 -101,584.5 v 4.91211 c 1e-5,1.40879 1.114453,2.58008 2.5,2.58008 1.385539,0 2.5,-1.17128 2.5,-2.58008 0,-1.4088 -1.163215,-2.41992 -2.5,-2.41992 a 0.50005,0.50005 0 1 0 0,1 c 0.871975,0 1.5,0.53052 1.5,1.41992 0,0.88938 -0.676779,1.58008 -1.5,1.58008 -0.823233,0 -1.499992,-0.69069 -1.5,-1.58008 V 584.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -6.90821,3.0039 c -1.40879,2e-5 -2.58007,1.11446 -2.58007,2.5 0,1.38554 1.17128,2.5 2.58007,2.5 1.40881,0 2.41993,-1.16321 2.41993,-2.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.87198 -0.53053,1.5 -1.41993,1.5 -0.88938,0 -1.58007,-0.67678 -1.58007,-1.5 0,-0.82323 0.69069,-1.49999 1.58007,-1.5 h 4.91211 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10848"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 303.5,600 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 0.5 h 1 v -0.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 313.5,605 H 307 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 2.5,6 h 7 v 4 h -7 z m 3,1 v 2 h 1 v -2 z"
+ id="path19950-6"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-84.000002,1.45e-5)"
- id="g10880"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- transform="translate(-523,-55.999969)"
- id="g10853"
- style="fill:#ffffff" />
- <g
- id="g10878"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 157.49219,453.99222 A 0.50005,0.50005 0 0 0 157,454.50003 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path10874"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 80.476562,451.02148 a 0.50005,0.50005 0 0 0 -0.314453,0.8711 c 0.58809,0.54453 0.841797,1.0856 0.841797,1.60156 L 81,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.0039,-6.00586 c 0,-0.8509 -0.431789,-1.65971 -1.162109,-2.33594 a 0.50005,0.50005 0 0 0 -0.365235,-0.13672 z M 71.5625,452 C 69.59752,452 68,453.59753 68,455.5625 v 7.875 C 68,465.40247 69.59752,467 71.5625,467 h 3.875 C 77.40247,467 79,465.40247 79,463.4375 v -7.875 C 79,453.59753 77.40247,452 75.4375,452 Z m 0,1 h 3.875 C 76.86577,453 78,454.13423 78,455.5625 v 7.875 C 78,464.86577 76.86577,466 75.4375,466 h -3.875 C 70.13422,466 69,464.86577 69,463.4375 v -7.875 C 69,454.13423 70.13422,453 71.5625,453 Z m 11.929688,0.0371 A 0.50005,0.50005 0 0 0 83,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z"
- transform="translate(84.000002,-1.449997e-5)"
- id="rect10876"
- inkscape:connector-curvature="0" />
- </g>
+ id="g17707"
+ inkscape:label="CA-14"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path13905"
+ d="M 282.03125,601 C 281.46859,601 281,601.46859 281,602.03125 v 7.9375 c 0,0.56266 0.46859,1.03125 1.03125,1.03125 h 7.9375 C 290.53141,611 291,610.53141 291,609.96875 v -7.9375 C 291,601.46859 290.53141,601 289.96875,601 Z m 6.94922,1.99023 a 1.0001,1.0001 0 0 1 0.72656,1.7168 l -4,4 a 1.0001,1.0001 0 0 1 -1.41406,0 l -2,-2 a 1.0001,1.0001 0 1 1 1.41406,-1.41406 l 1.29297,1.29297 3.29297,-3.29297 a 1.0001,1.0001 0 0 1 0.6875,-0.30274 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path10927"
- d="m 10.484375,452 c -0.752,0 -1.4538175,0.239 -2.0234375,0.64453 C 7.5752675,453.27508 7,454.31514 7,455.48438 V 458.5 c 3e-5,0.27537 0.2226769,0.4989 0.4980469,0.5 l 4.0097651,0.008 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 12,452.53516 v -0.002 -0.0352 C 11.999,452.22272 11.77534,452.00003 11.5,452 Z M 13,452 v 1 h 1.515625 C 15.900145,453 17,454.09985 17,455.48438 v 8.03124 C 17,464.90014 15.900145,466 14.515625,466 h -4.03125 C 9.099855,466 8,464.90014 8,463.51562 V 460 H 7 v 3.51562 C 7,465.43685 8.563145,467 10.484375,467 h 4.03125 C 16.436855,467 18,465.43686 18,463.51562 v -8.03124 C 18,453.56315 16.436855,452 14.515625,452 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- id="rect10947"
- d="M 31.484375,452 C 29.563145,452 28,453.56315 28,455.48438 v 8.03124 C 28,465.43685 29.563145,467 31.484375,467 h 4.03125 C 37.436855,467 39,465.43685 39,463.51562 v -8.03124 C 39,453.56315 37.436855,452 35.515625,452 Z m 0,1 h 4.03125 C 36.900155,453 38,454.09985 38,455.48438 v 8.03124 C 38,464.90015 36.900155,466 35.515625,466 h -4.03125 C 30.099845,466 29,464.90015 29,463.51562 v -8.03124 C 29,454.09985 30.099845,453 31.484375,453 Z m 1.5625,1 C 32.475545,454 32,454.47555 32,455.04688 v 3.90624 C 32,459.52445 32.475545,460 33.046875,460 h 0.90625 C 34.524455,460 35,459.52445 35,458.95312 v -3.90624 C 35,454.47555 34.524455,454 33.953125,454 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 69.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10850"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 48.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 7,3 a 0.50005,0.50005 0 1 0 0,1 h 5.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -7,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 7,3 a 0.50005,0.50005 0 1 0 0,1 h 5.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -7,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10852"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 27.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 4,3 a 0.50005,0.50005 0 1 0 0,1 h 4.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -4,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 4,3 a 0.50005,0.50005 0 1 0 0,1 h 4.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -4,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10854"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 6.5,306 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 5.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 5.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10856"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-462.00711,-314.99994)"
- id="g10872"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g17704"
+ inkscape:label="CA-13"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.20000005;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 552.5,621 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z M 552.5,624 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 4.05273,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91797 a 0.50005,0.50005 0 1 0 0,-1 z m 3.94727,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m -11,3 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z M 552.5,630 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 4.05273,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91797 a 0.50005,0.50005 0 1 0 0,-1 z m 3.94727,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m -11,3 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10870"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 261.03125,601 C 260.46859,601 260,601.46859 260,602.03125 v 7.9375 c 0,0.56266 0.46859,1.03125 1.03125,1.03125 h 7.9375 C 269.53141,611 270,610.53141 270,609.96875 v -7.9375 C 270,601.46859 269.53141,601 268.96875,601 Z m 0,1 h 7.9375 c 0.026,0 0.0312,0.005 0.0312,0.0312 v 7.9375 c 0,0.026 -0.005,0.0312 -0.0312,0.0312 h -7.9375 c -0.026,0 -0.0312,-0.005 -0.0312,-0.0312 v -7.9375 c 0,-0.026 0.005,-0.0312 0.0312,-0.0312 z"
+ id="rect13790"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 201.49219,305 a 0.50005,0.50005 0 1 0 0,1 h 2.5039 l -0.002,0.14258 -4.95898,11.4082 a 0.50005,0.50005 0 0 0 -0.041,0.21289 L 199,318 h -2.50781 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 H 200 a 0.50005,0.50005 0 0 0 0,-0.0137 l -0.004,-0.13867 4.95508,-11.39844 a 0.50005,0.50005 0 0 0 0.041,-0.19141 L 204.99609,306 h 2.4961 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10892"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 216.49219,305 a 0.50005,0.50005 0 1 0 0,1 H 218 v 6.00391 c 0,2.19985 1.79782,3.99206 4,3.99609 h 1 a 0.50005,0.50005 0 0 0 0.002,0 c 2.20199,-0.005 3.998,-1.79624 3.998,-3.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 1 0 0,1 H 226 v 6.00391 c 0,1.65832 -1.33799,2.99265 -3.00195,2.99609 H 222 c -1.66382,-0.003 -3,-1.33777 -3,-2.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 z m 1,13 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10901"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 111.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
- id="rect10983"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 113.49219,307 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path10977"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 132.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
- id="rect11046"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 134.49219,310 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path11048"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 153.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
- id="rect11050"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 155.49219,314 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path11052"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 177,305 a 1.0001,1.0001 0 0 0 -1,1 v 5.83203 a 1.0001,1.0001 0 0 0 0,0.32617 V 318 a 1.0001,1.0001 0 0 0 1,1 h 6 c 2.19729,0 4,-1.80271 4,-4 0,-1.76747 -1.1852,-3.22799 -2.78516,-3.75195 C 184.67235,310.59788 185,309.84948 185,309 c 0,-2.19729 -1.80271,-4 -4,-4 z m 1,2 h 3 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -3 z m 0,6 h 3 2 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -5 z"
- id="path10949"
- inkscape:connector-curvature="0" />
<g
- transform="matrix(0,1,1,0,37.999948,363)"
- id="g11084"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g17692"
+ inkscape:label="CA-12"
+ style="display:inline;enable-background:new">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 202,473 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m -4,4 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m 8,0 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m -4,1 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m 0,3 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m 4.96484,4 a 0.50005,0.50005 0 0 0 -0.47265,0.49219 A 0.50005,0.50005 0 0 0 207,487 h 0.5 c 0.83333,0 1.14655,0.35353 1.64648,0.85352 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 C 209.35355,486.64647 208.66667,486 207.5,486 H 207 a 0.50005,0.50005 0 0 0 -0.0352,0 z"
- transform="matrix(0,1,1,0,-363,-37.999948)"
- id="circle11078"
+ d="m 240,602 c -1.21759,0 -2.24187,0.34734 -2.94727,1.05273 C 236.34734,603.75813 236,604.78241 236,606 v 3.41992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 236.58203,610 H 236.75 A 0.50005,0.50005 0 0 0 237,609.06445 V 606 c 0,-1.03241 0.27766,-1.75813 0.75977,-2.24023 C 238.24187,603.27766 238.96759,603 240,603 h 4.29297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 247.5,606 h 1.5 c 0.63889,0 1.1225,0.20453 1.45898,0.54102 C 250.79547,606.8775 251,607.36111 251,608 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 608 c 0,-0.86111 -0.29547,-1.6275 -0.83398,-2.16602 C 250.6275,605.29547 249.86111,605 249,605 h -1.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 244.5,602 Z m -0.5,7 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m 6,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -9,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 9,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
+ id="circle12878-4"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- id="g13852"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96"
- style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
- <g
- id="g11167"
- transform="matrix(0,-1,-1,0,688.99474,-44.97944)"
- style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" />
+ id="g17716"
+ inkscape:label="CA-11"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 14.505859,263.01562 a 0.55005501,0.55005501 0 0 0 -0.05664,0.004 c -1.480032,0.16258 -2.81124,0.9768 -3.632813,2.21875 -0.754587,1.14068 -0.9438173,2.54615 -0.65039,3.875 l -3.5234379,3.52149 c -0.4164576,0.37981 -0.6354253,0.95498 -0.6601562,1.61328 -0.024627,0.65553 0.1896767,1.40646 0.7832031,2 0.5945619,0.59455 1.3481437,0.80114 1.9980469,0.76953 0.6519363,-0.0317 1.2112985,-0.25543 1.5917971,-0.63672 l 3.533203,-3.54297 c 1.328363,0.29148 2.734045,0.0991 3.873047,-0.6543 1.240498,-0.82051 2.05459,-2.151 2.21875,-3.6289 a 0.55005501,0.55005501 0 0 0 -0.160157,-0.45117 l -0.943359,-0.92969 a 0.55005501,0.55005501 0 0 0 -0.775391,0.002 l -1.80664,1.79883 h -0.589844 l -1.679687,-1.67969 v -0.58984 l 1.804687,-1.80078 a 0.55005501,0.55005501 0 0 0 0.0039,-0.77539 l -0.93164,-0.94727 a 0.55005501,0.55005501 0 0 0 -0.396485,-0.16602 z m -0.15625,1.17383 0.316407,0.32227 -1.580078,1.57617 a 0.55005501,0.55005501 0 0 0 -0.16211,0.39063 l 0.002,1.04687 a 0.55005501,0.55005501 0 0 0 0.16211,0.38672 l 2.001953,2.00195 a 0.55005501,0.55005501 0 0 0 0.388672,0.16211 l 1.046875,-0.002 a 0.55005501,0.55005501 0 0 0 0.386718,-0.16016 l 1.580079,-1.57422 0.318359,0.31446 c -0.183326,1.05859 -0.751902,2.01444 -1.654297,2.61132 -0.970627,0.64202 -2.219467,0.82961 -3.330078,0.49219 a 0.55005501,0.55005501 0 0 0 -0.548828,0.13672 l -3.699219,3.70899 c -0.1021327,0.10234 -0.4754005,0.29532 -0.8691406,0.31445 -0.395773,0.0192 -0.8021096,-0.0834 -1.1660156,-0.44727 -0.3650748,-0.36508 -0.4778317,-0.78393 -0.4628907,-1.18164 0.014838,-0.39496 0.2099663,-0.75541 0.3046875,-0.84179 a 0.55005501,0.55005501 0 0 0 0.017578,-0.0176 l 3.7070314,-3.70508 a 0.55005501,0.55005501 0 0 0 0.136719,-0.54883 c -0.339386,-1.11269 -0.154519,-2.36033 0.488281,-3.33203 0.59791,-0.90384 1.555081,-1.47203 2.615234,-1.6543 z"
- id="path11179"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path27826"
+ d="m 226.98047,602.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 L 222,607.58594 l -2.29297,-2.29297 a 1.0001,1.0001 0 1 0 -1.41406,1.41406 l 3,3 a 1.0001,1.0001 0 0 0 1.41406,0 l 5,-5 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(62.999978,21.041695)"
+ transform="translate(63,21.0417)"
id="g11141"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="CA-10">
<g
transform="translate(-126)"
id="g11139"
@@ -7711,90 +7936,91 @@
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 206.72656,599 c -0.19328,-0.004 -0.38654,0.0132 -0.57422,0.0508 -0.75071,0.15014 -1.44693,0.5778 -2.00586,1.13672 l -2.14453,2.10742 -1.14843,-1.14844 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1.64649,1.64648 -4.64844,4.68945 A 0.50005,0.50005 0 0 0 197,608.54102 v 0.79296 l -1.85352,1.85352 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 2,-2 A 0.50005,0.50005 0 0 0 198,609.54102 v -0.79493 l 4.50195,-4.53711 1.29297,1.29297 -4.5039,4.53907 H 198.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1.85351,-1.85351 H 199.5 a 0.50005,0.50005 0 0 0 0.35547,-0.14844 l 4.64648,-4.6836 1.64453,1.64454 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.14258,-1.14257 2.13867,-2.10547 0.004,-0.004 c 0.55892,-0.55893 0.98657,-1.25515 1.13671,-2.00586 0.15015,-0.75072 -0.0189,-1.58331 -0.63671,-2.20117 -0.4634,-0.46339 -1.04712,-0.67435 -1.62696,-0.6875 z"
- transform="translate(63.000022,-21.041695)"
+ transform="translate(63,-21.0417)"
id="path11133"
inkscape:connector-curvature="0" />
</g>
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13475"
- transform="translate(-21)">
- <path
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
- mask="none"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 111,515 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m -10,2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z m 4,0 h 2 v -2 h -2 z"
- id="path12185"
- inkscape:connector-curvature="0" />
+ id="g22423"
+ inkscape:label="CA-9">
<g
- transform="translate(63,-231)"
- id="g12189"
- style="opacity:0.6;fill:#ffffff">
+ id="g22461"
+ style="fill:#ffffff">
<path
- id="path12187"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 48,753 v 3.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 756 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 757 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -2 h -2 v 0 h -2 v 0 h -2 v 0 h -2 v 0 z"
+ sodipodi:nodetypes="ssscccssssccsss"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="csssssssssssscccccccccc" />
+ id="path22413"
+ d="m 175.5,599 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 6 c 0,0.64672 0.42101,1.19773 1,1.40625 V 606.5 v -3 -3 c 0,-0.28564 0.21436,-0.5 0.5,-0.5 h 9 c 0.28564,0 0.5,0.21436 0.5,0.5 v 1.5 h 1 v -1.5 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="rect22415"
+ transform="translate(0,-50)"
+ d="m 177.5,653 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 6 c 0,0.82235 0.67765,1.5 1.5,1.5 h 9 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -6 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m 2.00391,2 c 0.1882,0.002 0.35956,0.10882 0.44336,0.27734 l 2,4 c 0.16517,0.33222 -0.0763,0.72229 -0.44727,0.72266 h -4 c -0.37097,-3.7e-4 -0.61244,-0.39044 -0.44727,-0.72266 l 2,-4 c 0.0851,-0.17104 0.26016,-0.27834 0.45118,-0.27734 z m 3.99609,0 h 3 a 0.50005,0.50005 0 1 1 0,1 h -3 a 0.50005,0.50005 0 1 1 0,-1 z m 0,2 h 3 a 0.50005,0.50005 0 1 1 0,1 h -3 a 0.50005,0.50005 0 1 1 0,-1 z m 0,2 h 2 a 0.50005,0.50005 0 1 1 0,1 h -2 a 0.50005,0.50005 0 1 1 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="matrix(-1,0,0,1,89,-231)"
- id="g12197">
- <path
- inkscape:connector-curvature="0"
- id="path12191"
- transform="matrix(-1,0,0,1,90,231)"
- d="m 75,519 v 7 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 526 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -3.08789 A 1.50015,1.50015 0 0 1 83.5,521 h -3 A 1.50015,1.50015 0 0 1 79,519.5 V 519 Z"
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 16.5,746 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 9.5,747 h -3 A 0.50005,0.50005 0 0 0 6,747.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 10,750.5 V 749 h 6 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 19.5,746 Z m 0.5,1 h 2 v 2 h -2 z m -10,1 h 2 v 2 H 7 Z"
- id="path12195"
- inkscape:connector-curvature="0" />
+ id="g10247-8"
+ style="display:inline;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(-0.53033,-0.53033,-0.53033,0.53033,454.864,636.759)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="CA-8">
+ <g
+ id="g10245-2"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 306.99023,241.72461 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 5.93359 h -5.93359 a 0.66673335,0.66673335 0 1 0 0,1.33204 h 5.93359 v 5.93359 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -5.93359 h 5.93359 a 0.66673335,0.66673335 0 1 0 0,-1.33204 h -5.93359 v -5.93359 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
+ id="path10243-3"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
<g
- id="g17491"
- transform="matrix(0.875,0,0,0.875,264.125,159.75)"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.14285719;enable-background:new"
+ transform="matrix(-0.75,0,0,0.75,369.25,419.25)"
+ style="display:inline;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;enable-background:new"
+ id="g10315-7"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <rect
- y="430"
- x="257"
- height="16"
- width="16"
- id="rect17483"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3.42857146;marker:none;enable-background:accumulate" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 496,535.9375 c -2.73936,0 -5.1213,1.56371 -6.29102,3.84961 -0.49329,0.96401 -0.77148,2.05765 -0.77148,3.21289 0,3.89459 3.16791,7.0625 7.0625,7.0625 3.89459,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.89459 -3.16791,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.35415,0 6.0625,2.70835 6.0625,6.0625 0,3.35415 -2.70834,6.0625 -6.0625,6.0625 -3.35415,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-0.99492 0.23889,-1.93072 0.66211,-2.75781 1.00359,-1.96124 3.04116,-3.30469 5.40039,-3.30469 z M 496,538 a 0.99999996,0.99999996 0 0 0 -1,1 0.99999996,0.99999996 0 0 0 1,1 0.99999996,0.99999996 0 0 0 1,-1 0.99999996,0.99999996 0 0 0 -1,-1 z m -2.82422,1.16211 a 1.0001001,1.0001001 0 0 0 -0.6875,0.30469 c -0.61854,0.6208 -1.06287,1.393 -1.28906,2.24023 a 1.0001001,1.0001001 0 1 0 1.93164,0.51563 c 0.13595,-0.50922 0.40262,-0.97353 0.77344,-1.34571 a 1.0001001,1.0001001 0 0 0 -0.72852,-1.71484 z"
- transform="matrix(1.1428571,0,0,1.1428571,-301.85714,-182.57143)"
- id="path17485"
- inkscape:connector-curvature="0" />
+ inkscape:export-ydpi="96"
+ inkscape:label="CA-7">
+ <g
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333"
+ id="g10313-3">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 300.99023,247.67578 a 0.666995,0.666995 0 1 0 0,1.33399 h 10.66602 a 0.666995,0.666995 0 1 0 0,-1.33399 z"
+ id="path10309-7"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
<g
- style="display:inline;fill:#ffffff;stroke-width:1.09730649;enable-background:new"
- transform="matrix(1,0,0,0.83050847,1300,-195.57627)"
- id="g8019-1">
- <path
- sodipodi:nodetypes="cccccccccc"
- inkscape:connector-curvature="0"
- d="m -1207,502.79592 v 14.44898 h 2 v -14.44898 z m 6,0 v 14.44898 h 2 v -14.44898 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.19461298;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path8013-3" />
+ id="g7089-6"
+ style="display:inline;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(-0.75,0,0,0.75,348.757,418.757)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="CA-6">
+ <g
+ id="g7087-1"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 118.51367,601 a 0.50005001,0.50005001 0 0 0 -0.50586,0.50586 v 3.50195 h -3.50195 a 0.50005001,0.50005001 0 1 0 0,0.99805 h 3.50195 v 3.50195 a 0.50005001,0.50005001 0 1 0 0.99805,0 v -3.50195 h 3.50195 a 0.50005001,0.50005001 0 1 0 0,-0.99805 h -3.50195 v -3.50195 A 0.50005001,0.50005001 0 0 0 118.51367,601 Z"
+ transform="matrix(-1.33333,0,0,1.33333,465.009,-558.343)"
+ id="path7083-5"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <path
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 16.999998,228 a 4,4 0 0 1 -4,4 4,4 0 0 1 -3.9999999,-4 4,4 0 0 1 3.9999999,-4 4,4 0 0 1 4,4 z"
- id="circle8021-5"
- inkscape:connector-curvature="0" />
<g
id="g5627"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="CA-5">
<g
id="g5620"
style="fill:#ffffff">
@@ -7805,13 +8031,13 @@
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
- transform="translate(-42.000002,21.000005)"
+ transform="translate(-42,21)"
id="g4035-9"
style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 99,599 c -2.74773,0 -5,2.25226 -5,5 0,1.1945 0.441488,2.28163 1.148438,3.14453 l -5.001954,5.00195 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5.001953,-5.00196 C 96.718369,608.55851 97.805503,609 99,609 c 2.74773,0 5,-2.25227 5,-5 0,-2.74774 -2.25227,-5 -5,-5 z m 0,1 c 2.20227,0 4,1.79773 4,4 0,2.20226 -1.79773,4 -4,4 -2.20227,0 -4,-1.79774 -4,-4 0,-2.20227 1.79773,-4 4,-4 z"
- transform="translate(42.000002,-21.000005)"
+ transform="translate(42,-21)"
id="path4031-4"
inkscape:connector-curvature="0" />
</g>
@@ -7819,103 +8045,424 @@
</g>
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12132"
+ id="g12254"
+ transform="translate(-21,-21)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="CA-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 202.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 3.02727,0 5.5,2.47272 5.5,5.5 0,3.02727 -2.47273,5.5 -5.5,5.5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z m -0.008,1.99219 A 0.50005,0.50005 0 0 0 202,581.5 v 2.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 V 585 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 H 203 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- transform="translate(1.8536743e-6,-4.4999696e-6)"
- id="path4043-7"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 75,599 v 2 h 1 v -2 z m 3,0 v 1 h 2 v -1 z m 4,0 v 2 h 1 v -2 z m -6,3 c -2.197587,0 -4,1.80241 -4,4 0,0.91965 0.327327,1.75942 0.855469,2.4375 l -3.708985,3.70898 a 0.50005001,0.50005001 0 1 0 0.707032,0.70704 L 73.5625,609.14453 C 74.240452,609.67231 75.080704,610 76,610 c 2.197595,0 3.998047,-1.80241 3.998047,-4 0,-2.19759 -1.800452,-4 -3.998047,-4 z m 6,1 v 2 h 1 v -2 z m -6,0.002 c 1.652136,0 3,1.34592 3,2.99805 0,1.65213 -1.347864,3 -3,3 -1.652128,0 -3,-1.34787 -3,-3 0,-1.65214 1.347872,-2.99805 3,-2.99805 z M 82,607 v 2 h 1 v -2 z m -7,4 v 2 h 1 v -2 z m 7,0 v 2 h 1 v -2 z m -4,1 v 1 h 2 v -1 z"
+ transform="translate(21,21)"
+ id="rect12197"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.25;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 96,620 v 3.5 h 1 V 621 h 6 v 12 h -6 v -2.25 H 96 V 634 h 8 v -14 z"
+ id="rect12222"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g17695"
+ inkscape:label="CA-3"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 53.494141,601.99414 a 0.50005,0.50005 0 0 0 -0.347657,0.85938 l 3.646485,3.64648 -3.646485,3.64648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -4,-4 a 0.50005,0.50005 0 0 0 -0.359375,-0.15234 z"
+ id="path9518-7-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-420.007,439.993)"
+ id="g7406-1-2"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="CA-2">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 27.492188,598.99219 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.49805 L 41,605 l -1,-0.002 -0.0059,2.99414 H 27.992188 v -8 h 8 v 3.5 c 2.9e-5,0.27613 0.223869,0.49997 0.5,0.5 h 4 c 0.44533,-1.7e-4 0.668305,-0.53852 0.353515,-0.85352 l -4,-4 c -0.09376,-0.0938 -0.22116,-0.14439 -0.353515,-0.14453 v -0.002 h -0.0078 z M 35,610 l -2,0.004 v 1.98828 h -2.507812 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 7 c 0.676159,0.01 0.676159,-1.00956 0,-1 H 35 Z"
+ transform="translate(420.007,-439.993)"
+ id="path7395-0-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-541,-51)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15431-6"
+ inkscape:label="CA-1">
+ <path
+ inkscape:connector-curvature="0"
+ id="rect15415-8"
+ d="m 548,653 c -0.54532,0 -1,0.45468 -1,1 v 9 c 0,0.54532 0.45468,1 1,1 h 10 c 0.54532,0 1,-0.45468 1,-1 v -1 h -1 v 1 h -10 v -4 -5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="rect15379-7"
+ d="m 550,650 c -0.54532,0 -1,0.45468 -1,1 v 9 c 0,0.54532 0.45468,1 1,1 h 10 c 0.54532,0 1,-0.45468 1,-1 v -9 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 h -2 z m 0,3 h 10 v 6 h -10 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ </g>
+ <g
+ transform="translate(712,-665)"
+ style="display:inline;enable-background:new"
+ id="g25686"
+ inkscape:label="BA-26">
+ <g
+ transform="rotate(180,-177.4965,1250.005)"
+ id="g25671">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -242.00195,1242.9922 c -0.58284,0 -1.10871,0.154 -1.47657,0.5215 -0.36785,0.3675 -0.52148,0.8952 -0.52148,1.4785 V 1248 h 6 v -2.4863 c -0.002,-0.3369 0.17839,-0.7279 0.47461,-1.0254 0.29622,-0.2975 0.68988,-0.4819 1.0293,-0.4844 0.65765,-0.012 0.6539,-0.9937 -0.004,-1 h -0.004 L -239,1243 v 0.4863 c 0.01,0.6762 -1.00956,0.6762 -1,0 v -0.4883 h -1 v 0.4903 c 0.01,0.6762 -1.00956,0.6762 -1,0 v -0.4922 h -0.002 z M -244,1249 v 0.5 c 0,0.2521 0.16407,0.4981 0.5,0.4863 l 1.50195,0.01 -0.002,5.9941 c -0.0191,1.3523 2.01913,1.3523 2,0 l -0.002,-5.9941 1.50195,-0.01 c 0.32137,0 0.5,-0.2464 0.5,-0.4863 v -0.5 z"
+ transform="rotate(180,-208.9965,1250.005)"
+ id="path25652" />
+ <g
+ transform="matrix(1,0,0,-1,-61.9929,2500.02)"
+ id="g25669">
+ <g
+ id="g25662"
+ transform="translate(-17)">
+ <g
+ transform="translate(-2,-2)"
+ id="g25660" />
+ </g>
+ </g>
+ </g>
+ <g
+ id="g25684"
+ transform="matrix(1,0,0,-1,0,2500.01)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -232,1242.9863 c -0.50478,0 -1.00956,0.3375 -1,1.0137 v 7 h 2 v -7 c 0.01,-0.6762 -0.49522,-1.0137 -1,-1.0137 z m 0,9.0274 c -1.09865,0 -2,0.9013 -2,2 0,0.8274 -0.13264,1.3367 -0.33203,1.5937 -0.1994,0.257 -0.49978,0.3926 -1.16797,0.3926 -0.11793,0 -0.23139,0.046 -0.32031,0.123 -0.0251,0.022 -0.048,0.046 -0.0684,0.072 -0.0409,0.053 -0.0708,0.1132 -0.0879,0.1777 -0.004,0.016 -0.007,0.033 -0.01,0.049 -0.003,0.017 -0.005,0.034 -0.006,0.051 -0.002,0.033 -7.6e-4,0.067 0.004,0.1 0.005,0.033 0.0138,0.065 0.0254,0.096 0.0107,0.031 0.0244,0.061 0.041,0.09 0.009,0.015 0.0188,0.029 0.0293,0.043 0.0403,0.053 0.0907,0.098 0.14844,0.1308 0.0742,0.043 0.15827,0.067 0.24414,0.068 2.01924,0 3.30957,-0.2641 4.16992,-0.7461 0.85624,-0.4797 1.23067,-1.2322 1.30078,-1.918 0.0175,-0.1066 0.0293,-0.2142 0.0293,-0.3222 0,-1.0987 -0.90135,-2 -2,-2 z"
+ transform="matrix(1,0,0,-1,63,2500.01)"
+ id="path25673"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sccccssscscccccccccccccss" />
+ <g
+ transform="matrix(-1,0,0,1,-264,0)"
+ id="g25682" />
+ </g>
+ </g>
+ <g
+ transform="translate(1223,668.012)"
+ style="display:inline;enable-background:new"
+ id="g27941-8"
+ inkscape:label="BA-25">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -699.50391,-90.009766 a 0.50005,0.50005 0 0 0 -0.34375,0.150391 l -4.14648,4.136719 v -2.783203 a 0.50005,0.50005 0 1 0 -1,0 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.80274 l 4.1543,-4.144532 a 0.50005,0.50005 0 0 0 -0.36133,-0.859375 z m -11.98828,8.001954 a 0.50005,0.50005 0 1 0 0,1 h 2.78321 l -4.13868,4.148437 a 0.50005,0.50005 0 1 0 0.70899,0.705078 l 4.14648,-4.15625 v 2.802735 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path27716-4-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -710.49414,-88.007812 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4.501953 h 1 v -4.001953 h 4 v -1 z m 8.50195,5.001953 v 4 h -4.00195 v 1 h 4.50195 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4.5 z"
+ id="path27721-4-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(1223,668.012)"
+ style="display:inline;enable-background:new"
+ id="g27937-4"
+ inkscape:label="BA-24">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -733.49414,-90.007812 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6.501953 h 1 v -6.001953 h 6 v -1 z m 12.50195,7.001953 v 6 h -6.00195 v 1 h 6.50195 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6.5 z"
+ id="path27667-4-6"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -724.49219,-90.007812 a 0.50005,0.50005 0 1 0 0,1 h 2.78321 l -4.13868,4.148437 a 0.50005,0.50005 0 1 0 0.70899,0.705078 l 4.14648,-4.15625 v 2.802735 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -4.01172,7.998046 a 0.50005,0.50005 0 0 0 -0.34375,0.150391 l -4.14648,4.136719 v -2.783203 a 0.50005,0.50005 0 1 0 -1,0 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.80274 l 4.1543,-4.144532 a 0.50005,0.50005 0 0 0 -0.36133,-0.859375 z"
+ id="path27669-6-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g13413"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="BA-23">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 475.5,579 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z"
+ id="ellipse12367"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssssssssssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g18361"
+ inkscape:label="BA-22">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.99;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 447.49414,577.99023 a 0.50005,0.50005 0 0 0 -0.49219,0.50782 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.6875 c 1.48423,-2.56389 4.60739,-3.65907 7.36719,-2.58008 2.762,1.07985 4.31643,4.00744 3.66406,6.90039 -0.65237,2.89295 -3.31139,4.87021 -6.26953,4.66016 -2.95814,-0.21006 -5.31375,-2.5439 -5.55078,-5.5 a 0.50005,0.50005 0 1 0 -0.99609,0.0801 c 0.27595,3.44157 3.03067,6.17147 6.47461,6.41602 3.44393,0.24455 6.55885,-2.06751 7.31836,-5.43555 0.7595,-3.36803 -1.05982,-6.79554 -4.27539,-8.05273 -0.8039,-0.3143 -1.63664,-0.46878 -2.45899,-0.47852 -2.43307,-0.0288 -4.77966,1.22272 -6.08594,3.40821 v -2.91797 a 0.50005,0.50005 0 0 0 -0.50781,-0.50782 z m 8.98828,3.00391 a 0.50005,0.50005 0 0 0 -0.38281,0.20508 l -3,4 a 0.50005,0.50005 0 0 0 -0.0156,0.57812 l 2,3 a 0.50005,0.50005 0 1 0 0.83204,-0.55468 l -1.80274,-2.70508 2.78711,-3.7168 a 0.50005,0.50005 0 0 0 0.10352,-0.3125 0.50005,0.50005 0 0 0 -0.52149,-0.49414 z"
+ id="path13619"
inkscape:connector-curvature="0" />
<g
- id="g4159-3"
- transform="translate(61.94871,1.10183)"
- style="display:inline;fill:#ffffff;enable-background:new" />
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
- id="rect4248-2"
- width="16"
- height="16"
- x="193.95"
- y="577.04999" />
+ transform="matrix(0,-1,-1,0,955,1060)"
+ inkscape:transform-center-y="9.9999999e-06"
+ inkscape:transform-center-x="-1.2499"
+ id="g16343-6"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new" />
</g>
<g
- id="g7089-6"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- transform="matrix(-0.75,0,0,0.75,348.75712,418.75712)"
+ id="g17481"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-332.006,585.999)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-21">
<g
- id="g7087-1"
- style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
+ style="opacity:0.7;fill:#ffffff;stroke-width:1.15355"
+ transform="matrix(0.867075,0,0,0.866701,799.686,161.073)"
+ id="g17477">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 118.51367,601 a 0.50005001,0.50005001 0 0 0 -0.50586,0.50586 v 3.50195 h -3.50195 a 0.50005001,0.50005001 0 1 0 0,0.99805 h 3.50195 v 3.50195 a 0.50005001,0.50005001 0 1 0 0.99805,0 v -3.50195 h 3.50195 a 0.50005001,0.50005001 0 1 0 0,-0.99805 h -3.50195 v -3.50195 A 0.50005001,0.50005001 0 0 0 118.51367,601 Z"
- transform="matrix(-1.3333333,0,0,1.3333333,465.00949,-558.34283)"
- id="path7083-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 432.96875,577.99609 a 0.50015801,0.499942 0 0 0 -0.0488,0.006 0.50015801,0.499942 0 0 0 -0.0879,0.0215 c -0.22504,0.005 -0.45054,4.4e-4 -0.67383,0.0273 -1.50924,0.18184 -2.95823,0.85326 -4.0957,1.98242 -2.27494,2.25834 -2.72493,5.78034 -1.08984,8.53711 1.26078,2.1257 3.51721,3.36761 5.89257,3.41407 6.5e-4,10e-6 10e-4,-2e-5 0.002,0 a 0.50015801,0.499942 0 0 0 0.32031,-0.01 c 0.60037,-0.016 1.20402,-0.0867 1.80078,-0.26367 a 0.50073965,0.5005234 0 1 0 -0.28516,-0.95899 c -0.52501,0.15567 -1.05482,0.21548 -1.58203,0.22657 -0.32205,-0.21838 -0.86207,-0.82158 -1.28906,-1.77344 -0.15847,-0.35327 -0.29568,-0.76712 -0.41992,-1.20508 H 433.5 a 0.50043241,0.50021629 0 1 0 0,-1 h -2.31641 C 431.07457,586.38509 431,585.72514 431,585 c 0,-0.72848 0.074,-1.38791 0.18359,-2 h 3.5625 c 0.15752,0.77172 0.25391,1.61389 0.25391,2.5 a 0.50015801,0.499942 0 1 0 1,0 c 0,-0.883 -0.0936,-1.71998 -0.24023,-2.5 h 2.88671 c 0.41677,1.17713 0.47801,2.4832 0.0937,3.74609 a 0.50015801,0.499942 0 1 0 0.95704,0.28907 c 0.93293,-3.06617 -0.34127,-6.37791 -3.08789,-8.03125 -1.07945,-0.64978 -2.27964,-0.96925 -3.47657,-0.99219 a 0.50015801,0.499942 0 0 0 -0.14648,-0.0156 0.50015801,0.499942 0 0 0 -0.0176,0 z m 0.0273,1.13086 c 0.3107,0.30928 0.79344,0.97648 1.16602,1.90039 0.12076,0.29947 0.23379,0.62673 0.33594,0.97266 h -3.08399 c 0.12298,-0.42695 0.25956,-0.8299 0.41602,-1.17578 0.37038,-0.81882 0.82294,-1.39159 1.16601,-1.69727 z m 1.33789,0.0312 c 0.60769,0.13919 1.20278,0.36589 1.75977,0.70118 0.89497,0.53872 1.60631,1.28287 2.10156,2.14062 h -2.66797 c -0.12978,-0.47868 -0.2726,-0.9368 -0.4375,-1.3457 -0.23548,-0.58396 -0.48644,-1.07928 -0.75586,-1.4961 z m -2.70507,0.0156 c -0.24979,0.35295 -0.49203,0.75628 -0.71094,1.24023 -0.21038,0.4651 -0.38853,1.0058 -0.53906,1.58594 h -2.5586 c 0.26045,-0.4489 0.56294,-0.87823 0.94531,-1.25781 0.81076,-0.80484 1.80942,-1.32143 2.86329,-1.56836 z m -4.26758,3.80664 A 0.50043241,0.50021629 0 0 0 427.50195,583 h 2.66993 C 430.0701,583.62227 430,584.28017 430,585 c 0,0.71751 0.0707,1.37536 0.17188,2 h -2.66993 a 0.50043241,0.50021629 0 0 0 -0.14648,0.0234 c -0.47566,-1.32219 -0.45827,-2.74775 0.006,-4.04297 z M 427.80469,588 h 2.57226 c 0.15111,0.59053 0.32906,1.14077 0.54102,1.61328 0.21198,0.47256 0.44409,0.86643 0.68555,1.21289 -1.53987,-0.36784 -2.91769,-1.3294 -3.76954,-2.76562 -0.0116,-0.0196 -0.0179,-0.0409 -0.0293,-0.0606 z"
+ transform="matrix(1.1533,0,0,1.1538,-539.376,-861.973)"
+ id="path17465"
+ inkscape:connector-curvature="0" />
+ <path
+ cx="-40.000011"
+ cy="-186.99979"
+ r="7.5"
+ id="path17471"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.15355;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d=""
inkscape:connector-curvature="0" />
</g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 767.49023,1 c -0.3497,0.00648 -0.58488,0.3607678 -0.45507,0.6855469 l 2,5 c 0.1836,0.4628079 0.85703,0.4022128 0.95507,-0.085937 l 0.43946,-2.1738282 2.16797,-0.4355468 c 0.48875,-0.096787 0.55077,-0.7707095 0.0879,-0.9550782 l -5,-2 C 767.62345,1.0105047 767.55703,0.99855041 767.49023,1 Z"
+ id="path17479"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 240,602 c -1.21759,0 -2.24187,0.34734 -2.94727,1.05273 C 236.34734,603.75813 236,604.78241 236,606 v 3.41992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 236.58203,610 H 236.75 A 0.50005,0.50005 0 0 0 237,609.06445 V 606 c 0,-1.03241 0.27766,-1.75813 0.75977,-2.24023 C 238.24187,603.27766 238.96759,603 240,603 h 4.29297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 247.5,606 h 1.5 c 0.63889,0 1.1225,0.20453 1.45898,0.54102 C 250.79547,606.8775 251,607.36111 251,608 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 608 c 0,-0.86111 -0.29547,-1.6275 -0.83398,-2.16602 C 250.6275,605.29547 249.86111,605 249,605 h -1.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 244.5,602 Z m -0.5,7 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m 6,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -9,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 9,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
- id="circle12878-4"
- inkscape:connector-curvature="0" />
<g
- transform="matrix(-0.75,0,0,0.75,369.25,419.25)"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333325;enable-background:new"
- id="g10315-7"
+ id="g12940-5"
+ style="display:inline;fill:#ffffff;stroke:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-20">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 411.49219,577.94727 A 0.50005,0.50005 0 0 0 411,578.45508 v 7 a 0.50005,0.50005 0 1 0 1,0 v -7 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 408.47656,580 a 0.50005,0.50005 0 0 0 -0.22265,0.0684 c -2.54449,1.43695 -3.79437,4.38222 -3.03125,7.16797 0.76312,2.78575 3.34282,4.71875 6.27734,4.71875 2.93452,0 5.51422,-1.933 6.27734,-4.71875 0.76312,-2.78575 -0.48676,-5.73102 -3.03125,-7.16797 a 0.50025967,0.50025967 0 1 0 -0.49218,0.87109 c 2.15894,1.21922 3.20113,3.68764 2.55859,6.03321 -0.64254,2.34557 -2.81597,3.98242 -5.3125,3.98242 -2.49653,0 -4.66996,-1.63685 -5.3125,-3.98242 -0.64254,-2.34557 0.39965,-4.81399 2.55859,-6.03321 A 0.50005,0.50005 0 0 0 408.47656,580 Z"
+ id="path12897-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g21041"
+ inkscape:label="BA-19"
+ style="display:inline;enable-background:new">
+ <path
+ id="path18998-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 398,581 h -1 v -2 l 0.8535,-0.8535 c 0.091,0.09 0.1465,0.2154 0.1465,0.3535 z m -1,-2 0.8535,-0.8535 C 397.7635,578.0555 397.6381,578 397.5,578 h -9 c -0.1326,0 -0.2598,0.053 -0.3535,0.1465 l -4,4.0078 c -0.094,0.094 -0.1465,0.2209 -0.1465,0.3535 V 591.5 c 0,0.2761 0.2239,0.5 0.5,0.5 h 13 c 0.2761,0 0.5,-0.2239 0.5,-0.5 V 589 c -10e-5,-1.0628 -0.406,-2.084 -1.1367,-2.8438 l -0.01,-0.01 L 394.707,584 h 2.793 c 0.6761,0.01 0.6761,-1.0096 0,-1 h -3.9395 c -0.3255,-0.042 -0.6029,0.235 -0.5605,0.5605 V 587.5 c -0.01,0.6761 1.0096,0.6761 1,0 v -2.793 l 2.1426,2.1426 c 0.5484,0.5702 0.8573,1.3426 0.8574,2.1504 v 2 h -12 v -8.2852 L 388.707,579 Z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccscccccccssssscccccccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g10027-7"
+ transform="translate(109,-110)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-18">
+ <path
+ sodipodi:nodetypes="sssssccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path9906-8-8"
+ d="m 264.5,688 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
<g
- style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333325"
- id="g10313-3">
+ id="g9914-5"
+ transform="translate(100,195.999)"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 300.99023,247.67578 a 0.666995,0.666995 0 1 0 0,1.33399 h 10.66602 a 0.666995,0.666995 0 1 0 0,-1.33399 z"
- id="path10309-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 366.48438,579 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 580 h 1.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -2 v 0.002 c -0.005,0 -0.0101,-0.002 -0.0156,-0.002 z M 363,584 v 7.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 4.5 h -9 v -7 z"
+ transform="translate(-209,-85.9994)"
+ id="path9910-5"
inkscape:connector-curvature="0" />
</g>
</g>
<g
- id="g10247-8"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,454.86353,636.75914)"
+ transform="translate(365)"
+ id="g13349"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-17">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 349.5,578 c -1.48507,0 -2.8535,0.46731 -3.86133,1.33594 C 344.63084,580.20456 344,581.48473 344,583 v 3 c 0,0.83333 -0.007,1.35913 -0.11133,1.78711 -0.10481,0.42798 -0.303,0.80502 -0.77929,1.40039 A 0.50005,0.50005 0 0 0 343,589.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 1 a 0.50005,0.50005 0 0 0 0.33008,-0.12305 l 1.64648,-1.44336 1.41992,1.41993 A 0.50005,0.50005 0 0 0 349.25,592 h 0.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1.39648,-1.39649 1.39648,1.39649 A 0.50005,0.50005 0 0 0 353.25,592 h 1.25 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -1 -5.5 c 0,-1.51527 -0.63084,-2.79544 -1.63867,-3.66406 C 352.3535,578.46731 350.98507,578 349.5,578 Z m 0,1 c 1.27493,0 2.40681,0.40238 3.20898,1.09375 C 353.51116,580.78512 354,581.75527 354,583 v 5.5 1 1.5 h -0.54297 l -1.60351,-1.60352 a 0.50005,0.50005 0 0 0 -0.70704,0 L 349.54297,591 h -0.0859 l -1.60351,-1.60352 a 0.50005,0.50005 0 0 0 -0.6836,-0.0234 L 345.3125,591 H 344.5 344 v -1.38867 c 0.42104,-0.55984 0.73249,-1.05984 0.86133,-1.58594 C 345.00652,587.43254 345,586.83333 345,586 v -3 c 0,-1.24473 0.48884,-2.21488 1.29102,-2.90625 C 347.09319,579.40238 348.22507,579 349.5,579 Z m -1.00586,2.99219 a 0.50005,0.50005 0 0 0 -0.34766,0.15429 l -0.64648,0.64649 -0.64648,-0.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.64648,-0.64649 0.64648,0.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 0.64649,-0.64648 a 0.50005,0.50005 0 0 0 -0.35938,-0.86133 z m 4,0 a 0.50005,0.50005 0 0 0 -0.34766,0.15429 l -0.64648,0.64649 -0.64648,-0.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.64648,-0.64649 0.64648,0.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 0.64649,-0.64648 a 0.50005,0.50005 0 0 0 -0.35938,-0.86133 z"
+ transform="translate(-365)"
+ id="path13343"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g27501-8"
+ transform="translate(-20.9999,105)"
+ inkscape:label="BA-16">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 346.54688,478.16016 a 0.50005,0.50005 0 0 0 -0.18165,0.0293 c -1.54898,0.53108 -2.52602,2.0719 -2.34375,3.69922 0.18228,1.62732 1.47542,2.91657 3.10352,3.0918 1.6281,0.17523 3.16703,-0.80811 3.69141,-2.35938 a 0.50005,0.50005 0 1 0 -0.94727,-0.32031 c -0.37611,1.11265 -1.46896,1.81123 -2.63672,1.68555 -1.16775,-0.12568 -2.08606,-1.04179 -2.2168,-2.20899 -0.13073,-1.1672 0.56282,-2.26166 1.67383,-2.64257 a 0.50005,0.50005 0 0 0 -0.14257,-0.97461 z"
+ id="path27478-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 346.52148,476.09375 a 0.50004994,0.50004994 0 0 0 -0.0859,0.01 c -2.69151,0.53044 -4.58334,2.97414 -4.42578,5.71289 0.15755,2.73875 2.31815,4.94772 5.05273,5.16601 2.73458,0.21829 5.21856,-1.61975 5.80859,-4.29883 a 0.50004994,0.50004994 0 1 0 -0.97656,-0.21484 c -0.48423,2.19868 -2.50772,3.69672 -4.75195,3.51758 -2.24424,-0.17915 -4.00546,-1.98086 -4.13477,-4.22852 -0.1293,-2.24766 1.41221,-4.2385 3.6211,-4.67383 a 0.50004994,0.50004994 0 0 0 -0.10743,-0.99023 z"
+ id="circle27480-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 353.49219,473 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -5,5 c -0.0938,0.0938 -0.14646,0.22092 -0.14648,0.35352 v 1.79297 l -0.85352,0.85351 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 L 348.70703,481 H 350.5 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.14648 l 5,-5 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
+ id="path27485-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
+ </g>
+ <g
+ id="g21047"
+ inkscape:label="BA-15"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 306.49219,577.99219 A 0.50004997,0.50004997 0 0 0 306,578.5 v 2.79297 l -2.14648,-2.14649 a 0.50004997,0.50004997 0 1 0 -0.70704,0.70704 L 306,582.70703 v 0.58203 c -0.58959,0.34718 -0.99219,0.98165 -0.99219,1.71094 h -0.30078 l -2.85351,-2.85352 a 0.50004997,0.50004997 0 0 0 -0.35938,-0.15234 0.50004997,0.50004997 0 0 0 -0.34766,0.85938 L 303.29297,585 H 300.5 a 0.50004997,0.50004997 0 1 0 0,1 h 2.79297 l -2.14649,2.14648 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 L 304.70703,586 h 0.58203 c 0.34718,0.58959 0.98165,0.99219 1.71094,0.99219 v 0.30078 l -2.85352,2.85351 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 L 307,588.70703 V 591.5 a 0.50004997,0.50004997 0 1 0 1,0 v -2.79297 l 2.14648,2.14649 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 308,587.29297 v -0.58203 c 0.58959,-0.34718 0.99219,-0.98165 0.99219,-1.71094 h 0.30078 l 2.85351,2.85352 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 310.70703,585 H 313.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -2.79297 l 2.14649,-2.14648 a 0.50004997,0.50004997 0 0 0 -0.36329,-0.85743 0.50004997,0.50004997 0 0 0 -0.34375,0.15039 L 309.29297,584 h -0.58203 c -0.34718,-0.58959 -0.98165,-0.99219 -1.71094,-0.99219 v -0.30078 l 2.85352,-2.85351 a 0.50004997,0.50004997 0 1 0 -0.70704,-0.70704 L 307,581.29297 V 578.5 a 0.50004997,0.50004997 0 0 0 -0.50781,-0.50781 z M 307,584.00781 c 0.55427,0 0.99219,0.43792 0.99219,0.99219 0,0.55427 -0.43792,0.99219 -0.99219,0.99219 -0.55427,0 -0.99219,-0.43792 -0.99219,-0.99219 0,-0.55427 0.43792,-0.99219 0.99219,-0.99219 z"
+ id="path14282"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g15178-7"
+ style="display:inline;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ transform="matrix(-0.53033,-0.53033,-0.53033,0.53033,580.864,617.759)"
+ inkscape:label="BA-14">
<g
- id="g10245-2"
- style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
+ id="g15176-5"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none">
+ <g
+ id="g15174-3"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 281.51172,579 a 0.50005002,0.50005002 0 0 0 -0.41797,0.20898 c -2.81255,3.79393 -2.81255,9.78811 0,13.58204 a 0.50005002,0.50005002 0 1 0 0.80273,-0.59571 c -2.50459,-3.37852 -2.50459,-9.0121 0,-12.39062 A 0.50005002,0.50005002 0 0 0 281.51172,579 Z m 8.95898,0 a 0.50005002,0.50005002 0 0 0 -0.38476,0.80469 c 2.50459,3.37852 2.50459,9.0121 0,12.39062 a 0.50059472,0.50059472 0 1 0 0.80468,0.59571 c 2.81256,-3.79393 2.81256,-9.78811 0,-13.58204 A 0.50005002,0.50005002 0 0 0 290.47266,579 a 0.50005002,0.50005002 0 0 1 -0.002,0 z m -6.98047,2.99219 a 0.50005002,0.50005002 0 0 0 -0.39648,0.79883 l 2.29102,3.20898 -2.29297,3.20898 a 0.50131814,0.50131814 0 1 0 0.8164,0.58204 l 2.0918,-2.92969 2.0918,2.92969 a 0.50131814,0.50131814 0 1 0 0.8164,-0.58204 L 286.61523,586 l 2.29102,-3.20898 a 0.50005002,0.50005002 0 0 0 -0.0312,-0.63282 0.50005002,0.50005002 0 0 0 -0.78125,0.0508 l -2.0938,2.92967 -2.09375,-2.92969 a 0.50005002,0.50005002 0 0 0 -0.0527,-0.0664 0.50005002,0.50005002 0 0 0 -0.36329,-0.15039 z"
+ transform="matrix(-0.942809,-0.942809,-0.942809,0.942809,1130.07,-34.7855)"
+ id="path15160-1"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15242-0"
+ transform="translate(-558,-305)"
+ inkscape:label="BA-13">
+ <g
+ id="g15149-2"
+ transform="translate(21,43)"
+ style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 306.99023,241.72461 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 5.93359 h -5.93359 a 0.66673335,0.66673335 0 1 0 0,1.33204 h 5.93359 v 5.93359 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -5.93359 h 5.93359 a 0.66673335,0.66673335 0 1 0 0,-1.33204 h -5.93359 v -5.93359 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
- id="path10243-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 259.49219,578.99219 A 0.50005,0.50005 0 0 0 259,579.5 v 11.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 259.58203,592 H 271.5 a 0.50005,0.50005 0 1 0 0,-1 H 260 v -11.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 1.94922,3.08593 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3.28515,0.70899 a 0.50005,0.50005 0 0 0 -0.18945,0.96484 l 1,0.41602 a 0.50005,0.50005 0 1 0 0.38477,-0.92188 l -1,-0.41797 a 0.50005,0.50005 0 0 0 -0.19532,-0.041 z m 2.57813,1.99609 a 0.50005,0.50005 0 0 0 -0.45508,0.69922 l 0.41797,1 a 0.50037731,0.50037731 0 0 0 0.92383,-0.38476 l -0.41797,-1 a 0.50005,0.50005 0 0 0 -0.46875,-0.31446 z m 1.16601,3.25 a 0.50005,0.50005 0 0 0 -0.49218,0.50586 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50586 z"
+ transform="translate(537,262)"
+ id="path15133-4"
inkscape:connector-curvature="0" />
</g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(555.017,519.079)"
+ id="g12701-3-4"
+ style="display:inline;fill:#ffffff;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15124-5"
+ transform="translate(-558,-200)"
+ inkscape:label="BA-12">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 247.59961,579 a 0.60006002,0.60006002 0 0 0 -0.41797,1.03125 l 2.78711,2.78711 a 0.60076499,0.60076499 0 0 0 0.84961,-0.84961 l -2.78711,-2.78711 A 0.60006002,0.60006002 0 0 0 247.59961,579 Z m -0.11133,2.89453 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z m -3,3 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z m -3,3 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z M 237.59961,589 a 0.60006002,0.60006002 0 0 0 -0.41797,1.03125 l 2.78711,2.78711 a 0.60076499,0.60076499 0 0 0 0.84961,-0.84961 l -2.78711,-2.78711 A 0.60006002,0.60006002 0 0 0 237.59961,589 Z"
+ transform="translate(558,200)"
+ id="path15289-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12207"
+ transform="translate(21)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-11">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 223.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 3.02727,0 5.5,2.47272 5.5,5.5 0,3.02727 -2.47273,5.5 -5.5,5.5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z m -3,5 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 z"
+ transform="translate(-21)"
+ id="path12193"
+ inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(61.9487,1.10183)"
+ id="g12200" />
+ <rect
+ y="577.04999"
+ x="193.95"
+ height="16"
+ width="16"
+ id="rect12202"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12132"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-10">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 202.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 3.02727,0 5.5,2.47272 5.5,5.5 0,3.02727 -2.47273,5.5 -5.5,5.5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z m -0.008,1.99219 A 0.50005,0.50005 0 0 0 202,581.5 v 2.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 V 585 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 H 203 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path4043-7"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g4159-3"
+ transform="translate(61.9487,1.10183)"
+ style="display:inline;fill:#ffffff;enable-background:new" />
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
+ id="rect4248-2"
+ width="16"
+ height="16"
+ x="193.95"
+ y="577.04999" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
id="g12144"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 181.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 2.85852,0 5.21992,2.20548 5.47461,5 h -6.26758 l 2.14649,-2.14648 c 0.32529,-0.31801 0.0914,-0.86992 -0.36329,-0.85743 -0.12976,0.004 -0.25303,0.0575 -0.34375,0.15039 l -2.95703,2.95704 c -0.26095,0.19951 -0.26189,0.59214 -0.002,0.79296 0.002,10e-4 0.004,0.003 0.006,0.004 l 2.95312,2.95313 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 L 180.70703,585 h 6.26758 c -0.25469,2.79451 -2.61609,5 -5.47461,5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z"
- transform="translate(1.8536743e-6,-4.4999696e-6)"
id="path9890-4"
inkscape:connector-curvature="0" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(40.94871,1.10183)"
+ transform="translate(40.9487,1.10183)"
id="g9896-8" />
<rect
y="577.04999"
@@ -7926,49 +8473,75 @@
style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g5506-8"
- transform="translate(-44.000002,63.000005)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 556.57617,409.98047 a 0.55005501,0.55005501 0 0 0 -0.42383,0.18555 c -0.46657,0.51387 -1.20227,1.13094 -1.20312,2.14257 -10e-4,1.1847 0.85571,2.11411 1.94336,2.91797 1.08765,0.80386 2.47935,1.527 3.84765,2.25782 0.44143,0.23577 0.88243,0.47055 1.3086,0.70312 1.11316,0.60746 2.13512,1.2144 2.84375,1.81836 0.70862,0.60396 1.05894,1.15906 1.05859,1.68359 -4e-4,0.48086 -0.32771,1.0064 -0.79492,1.38086 a 0.55027044,0.55027044 0 1 0 0.6875,0.85938 c 0.65297,-0.52334 1.20625,-1.30182 1.20703,-2.23828 6.6e-4,-0.99421 -0.62031,-1.82029 -1.44531,-2.52344 -0.825,-0.70315 -1.89813,-1.32892 -3.03125,-1.94727 -0.43383,-0.23675 -0.87476,-0.47023 -1.31445,-0.70508 -1.37366,-0.73367 -2.73478,-1.45092 -3.71289,-2.17382 -0.97812,-0.72291 -1.49874,-1.40647 -1.49805,-2.03125 3.7e-4,-0.43907 0.39742,-0.83099 0.91797,-1.4043 a 0.55005501,0.55005501 0 0 0 -0.39063,-0.92578 z"
- id="path5432-2"
- inkscape:connector-curvature="0" />
+ id="g5759"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="BA-8">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 565.45508,409.94531 a 0.55005501,0.55005501 0 0 0 -0.31446,0.97071 c 0.44122,0.38244 0.8125,1.03351 0.8125,1.58398 -0.002,0.56635 -0.25363,0.95243 -0.74218,1.35938 -0.48909,0.40739 -1.20703,0.77343 -1.95703,1.14843 a 0.55028291,0.55028291 0 1 0 0.49218,0.98438 c 0.75,-0.375 1.5313,-0.75874 2.16797,-1.28907 0.63668,-0.53032 1.13681,-1.26964 1.13867,-2.20312 0,-0.98667 -0.54281,-1.85212 -1.19335,-2.41602 a 0.55005501,0.55005501 0 0 0 -0.4043,-0.13867 z m -6.95313,8.00196 a 0.55005501,0.55005501 0 0 0 -0.24804,0.0605 c -0.75,0.375 -1.5313,0.75874 -2.16797,1.28907 -0.63668,0.53032 -1.13681,1.26964 -1.13867,2.20312 0,0.98843 0.53602,1.85319 1.19335,2.41797 a 0.55122854,0.55122854 0 1 0 0.71876,-0.83594 c -0.44771,-0.38466 -0.8125,-1.01968 -0.8125,-1.58203 0.002,-0.56635 0.25363,-0.95243 0.74218,-1.35938 0.48909,-0.40739 1.20703,-0.77343 1.95703,-1.14843 a 0.55005501,0.55005501 0 0 0 -0.24414,-1.04492 z"
- id="path5435-6"
+ id="path12148"
+ d="m 161.5,578 c -3.02272,0 -5.5,2.47726 -5.5,5.5 0,1.3328 0.48165,2.55856 1.2793,3.51367 l -4.13282,4.13281 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 4.13281,-4.13282 C 158.94144,588.51835 160.1672,589 161.5,589 c 3.02273,0 5.5,-2.47727 5.5,-5.5 0,-3.02274 -2.47727,-5.5 -5.5,-5.5 z m 0,1 c 2.47727,0 4.5,2.02272 4.5,4.5 0,2.47727 -2.02273,4.5 -4.5,4.5 -2.47726,0 -4.5,-2.02273 -4.5,-4.5 0,-2.47728 2.02274,-4.5 4.5,-4.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- id="path5484-0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 557.5,421 a 0.50005,0.50005 0 1 0 0,1 h 2 A 0.50005,0.50005 0 0 0 560,421.58008 0.50005,0.50005 0 0 0 560.5,422 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -4 A 0.50005,0.50005 0 0 0 560,421.41992 0.50005,0.50005 0 0 0 559.5,421 Z m 0,-9 a 0.50005,0.50005 0 1 0 0,1 h 4 A 0.50005,0.50005 0 0 0 562,412.58008 0.50005,0.50005 0 0 0 562.5,413 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -2 A 0.50005,0.50005 0 0 0 562,412.41992 0.50005,0.50005 0 0 0 561.5,412 Z"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ccccscccccccccccccsccc"
+ inkscape:connector-curvature="0"
+ id="path12161"
+ d="m 159.5,583 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.2168 c -2.1e-4,0.14132 0.0594,0.27613 0.16406,0.37109 0.61652,0.55704 1.43526,0.91211 2.33594,0.91211 0.90068,0 1.71942,-0.35507 2.33594,-0.91211 0.10467,-0.095 0.16427,-0.22977 0.16406,-0.37109 V 583.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.97266,6.91992 c -0.2654,0.0146 -0.47303,0.2342 -0.47266,0.5 V 591.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.08008 c -4.1e-4,-0.30465 -0.27082,-0.53814 -0.57227,-0.49414 -0.31225,0.0453 -0.61944,0.0742 -0.92773,0.0742 -0.30829,0 -0.61548,-0.0289 -0.92773,-0.0742 -0.0329,-0.005 -0.0663,-0.007 -0.0996,-0.006 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,706.86353,657.75914)"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- id="g10178-9"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g10061"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-7">
+ <g
+ id="g9978"
+ transform="translate(159,3)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1.25053;enable-background:new"
+ id="g9976"
+ transform="matrix(0.799663,0,0,0.799663,-130.651,113.695)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 142,578 c -2.19759,0 -4,1.80241 -4,4 0,0.9193 0.32769,1.75955 0.85547,2.4375 l -3.70899,3.70898 a 0.50029086,0.50029086 0 1 0 0.70704,0.70704 l 3.70898,-3.70899 C 140.24045,585.67231 141.0807,586 142,586 c 2.19759,0 4,-1.80241 4,-4 0,-2.19759 -1.80241,-4 -4,-4 z m 0,1 c 1.65213,0 3,1.34787 3,3 0,1.65213 -1.34787,3 -3,3 -1.65214,0 -3,-1.34787 -3,-3 0,-1.65214 1.34786,-3 3,-3 z"
+ transform="matrix(1.25053,0,0,1.25053,-35.4509,-145.93)"
+ id="path9971"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
<g
- style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none"
- id="g10176-5">
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ transform="translate(-21,84.9994)"
+ id="g10042">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 306.99023,241.72461 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 5.93359 h -5.93359 a 0.66673335,0.66673335 0 1 0 0,1.33204 h 5.93359 v 5.93359 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -5.93359 h 5.93359 a 0.66673335,0.66673335 0 1 0 0,-1.33204 h -5.93359 v -5.93359 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
- id="path10174-2"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 135.48438,579 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 580 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1 v 0.002 c -0.005,0 -0.0101,-0.002 -0.0156,-0.002 z M 132,584 v 7.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 3.5 h -8 v -7 z"
+ transform="translate(21,-84.9994)"
+ id="path10038"
inkscape:connector-curvature="0" />
</g>
</g>
<g
- transform="translate(20.999998,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23194">
+ id="g15743"
+ transform="translate(221)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-6">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M -98.580078,578 C -99.98888,578 -101,579.16322 -101,580.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.87198 0.530524,-1.5 1.419922,-1.5 0.889383,0 1.580078,0.67678 1.580078,1.5 0,0.82323 -0.69069,1.49999 -1.580078,1.5 h -4.914062 a 0.50005,0.50005 0 1 0 0,1 h 4.914062 C -97.171286,582.99999 -96,581.88555 -96,580.5 c 0,-1.38554 -1.171281,-2.5 -2.580078,-2.5 z m -8.916012,0.004 c -1.38554,0 -2.5,1.17128 -2.5,2.58007 0,1.40881 1.16321,2.41797 2.5,2.41797 a 0.50005,0.50005 0 1 0 0,-1 c -0.87198,0 -1.5,-0.52857 -1.5,-1.41797 0,-0.88938 0.67678,-1.58007 1.5,-1.58007 0.82323,0 1.49804,0.69069 1.49804,1.58007 v 4.91211 a 0.50005,0.50005 0 1 0 1,0 v -4.91211 c -10e-6,-1.40879 -1.1125,-2.58007 -2.49804,-2.58007 z m 6.98828,5.98828 A 0.50005,0.50005 0 0 0 -101,584.5 v 4.91211 c 1e-5,1.40879 1.114453,2.58008 2.5,2.58008 1.385539,0 2.5,-1.17128 2.5,-2.58008 0,-1.4088 -1.163215,-2.41992 -2.5,-2.41992 a 0.50005,0.50005 0 1 0 0,1 c 0.871975,0 1.5,0.53052 1.5,1.41992 0,0.88938 -0.676779,1.58008 -1.5,1.58008 -0.823233,0 -1.499992,-0.69069 -1.5,-1.58008 V 584.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -6.90821,3.0039 c -1.40879,2e-5 -2.58007,1.11446 -2.58007,2.5 0,1.38554 1.17128,2.5 2.58007,2.5 1.40881,0 2.41993,-1.16321 2.41993,-2.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.87198 -0.53053,1.5 -1.41993,1.5 -0.88938,0 -1.58007,-0.67678 -1.58007,-1.5 0,-0.82323 0.69069,-1.49999 1.58007,-1.5 h 4.91211 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10848"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(21)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23194"
+ inkscape:label="BA-5">
<g
transform="translate(430,-112)"
id="g12465"
@@ -7980,318 +8553,557 @@
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new"
- id="g12595"
- transform="matrix(0.866668,0,0,0.866668,-177.46699,184.39943)"
- inkscape:export-filename="blender_icons.png"
+ transform="translate(-21)"
+ inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-filename="blender_icons.png"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g12548"
+ inkscape:label="BA-4">
<g
- style="fill:#ffffff;stroke-width:1.15384436"
- id="g12593">
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(640,-112)"
+ id="g7753-3">
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
- d="m 34,557 c -3.860079,0 -7,3.13992 -7,7 0,3.86008 3.139921,7 7,7 3.860079,0 7,-3.13992 7,-7 0,-3.86008 -3.139921,-7 -7,-7 z m 0,1 c 3.305801,0 5.975833,2.65852 5.998047,5.95898 C 38.886544,564.90262 36.995365,566 34,566 v 4 c -3.319633,0 -6,-2.68037 -6,-6 0,-0.0145 0.0019,-0.0285 0.002,-0.043 C 29.113203,564.90101 31.002992,566 34,566 Z"
- transform="matrix(1.1538444,0,0,1.1538444,204.76929,-212.76825)"
- id="path12589"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -539.42969,690.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -0.48633,0.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 0.5,-0.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -0.5,0.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 0.48828,-0.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -7.00976,7 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -0.48829,0.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 0.48829,-0.48828 C -543.31787,702.0249 -543,701.28067 -543,700.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -0.5,0.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 0.5,-0.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z"
+ id="path12469-4"
inkscape:connector-curvature="0" />
</g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 94.492188,577.99219 A 0.50005,0.50005 0 0 0 94,578.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2.998047,1.00195 a 0.50005,0.50005 0 0 0 -0.347657,0.85938 l 1,1 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1,-1 a 0.50005,0.50005 0 0 0 -0.359375,-0.15234 z M 90.5,582 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 11,5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m -2.007812,1.99219 A 0.50005,0.50005 0 0 0 99,589.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m 2.001952,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1,1 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path12538"
+ inkscape:connector-curvature="0" />
</g>
<g
- id="g6666-5"
- transform="translate(-63.000002,42.000005)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(0.999966)"
+ id="g13708"
+ style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-3">
<path
- style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.79999995;marker:none;enable-background:accumulate"
- d="m 363.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z m 2,2 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 0,1 h -1 v 1 h 1 z m -1,1 h -1 v 1 h 1 z m 2,0 v 1 h 3 v -1 z"
- transform="translate(63.000002,-42.000005)"
- id="rect40533-7-0"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 48.5,578 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 L 47.9922,589 c 0,1.51667 1.219299,3 2.984374,3 1.765077,0 3.015625,-1.475 3.015626,-3 L 54,578.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 2.5,10 c 0.546362,0 1,0.45364 1,1 0,0.54636 -0.453638,1 -1,1 -0.546362,0 -1,-0.45364 -1,-1 0,-0.54636 0.453638,-1 1,-1 z"
+ transform="translate(-0.99998)"
+ id="path13694" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 58.492188,586 c -0.132599,2e-5 -0.259759,0.0527 -0.353516,0.14648 l -4.75,4.75 c -0.09377,0.0938 -0.14646,0.22092 -0.146484,0.35352 v 0.25 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 H 60.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path13696"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 56.486328,579 c -0.130565,0.002 -0.25534,0.0541 -0.347656,0.14648 l -2,2 c -0.09377,0.0938 -0.14646,0.22092 -0.146484,0.35352 v 6 c 1.71e-4,0.44532 0.538516,0.6683 0.853515,0.35352 l 5,-5 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 C 56.750515,579.05126 56.620954,578.99846 56.486328,579 Z"
+ id="path13698"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path4106"
- d="m 408.48148,452.0625 c -1.71014,0.0728 -3.32227,1.4838 -3.32227,3.9375 0,2.05278 1.07076,4.01178 2.38672,5.71289 1.31595,1.70111 2.90024,3.15481 4.03125,4.16016 0.0914,0.0816 0.20954,0.12673 0.33203,0.12695 h 0.5 c 0.12249,-2.2e-4 0.24064,-0.0454 0.33203,-0.12695 1.13101,-1.00535 2.7153,-2.45905 4.03125,-4.16016 1.31596,-1.70111 2.38672,-3.66011 2.38672,-5.71289 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- sodipodi:nodetypes="csccccccsccc" />
<g
- transform="matrix(-1,0,0,1,635,-357)"
- id="g12824"
- style="fill:#ffffff">
+ id="g21044"
+ inkscape:label="BA-2"
+ style="display:inline;enable-background:new">
<path
- inkscape:connector-curvature="0"
- id="path12813"
- d="m 363.5,431 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 0 0 0.14648,0.35352 L 368,437.70703 V 441.5 a 0.50005,0.50005 0 0 0 0.14648,0.35352 l 3,3 A 0.50005,0.50005 0 0 0 372,444.5 v -6.79297 l 4.85352,-4.85351 A 0.50005,0.50005 0 0 0 377,432.5 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 0.29297 l -4.85352,4.85351 A 0.50005,0.50005 0 0 0 371,437.5 v 5.79297 l -2,-2 V 437.5 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 L 364,432.29297 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path20705"
+ d="m 34.5,578 c -1.48507,0 -2.8535,0.46731 -3.86133,1.33594 C 29.63084,580.20456 29,581.48473 29,583 v 3.5 c 0,1.66667 0.001,2.82293 -0.89062,3.9375 -0.0709,0.0887 -0.10946,0.19893 -0.10938,0.3125 v 0.75 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 29 c 1.04885,0 2.13736,-0.63444 3.45898,-2.04297 l 1.66797,1.875 c 0.19883,0.22274 0.54727,0.22274 0.7461,0 l 1.62695,-1.83008 1.62695,1.83008 c 0.0947,0.10662 0.23044,0.16774 0.37305,0.16797 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 -1 -5.5 c 0,-1.51527 -0.63084,-2.79544 -1.63867,-3.66406 C 37.3535,578.46731 35.98507,578 34.5,578 Z m -3.00781,4 c 0.1353,-0.002 0.26563,0.0508 0.36133,0.14648 l 2,2 c 0.31479,0.315 0.09181,0.85335 -0.35352,0.85352 h -2 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -2 c -10e-6,-0.27311 0.21911,-0.496 0.49219,-0.5 z m 5.99219,0 c 0.2822,-0.009 0.51573,0.21765 0.51562,0.5 v 2 c -3e-5,0.27613 -0.22387,0.49997 -0.5,0.5 h -2 c -0.44532,-1.7e-4 -0.66831,-0.53852 -0.35352,-0.85352 l 2,-2 c 0.0899,-0.0901 0.21072,-0.14248 0.3379,-0.14648 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g6750-7"
- transform="translate(-314.99995,-567)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13609"
+ transform="translate(-187,-90)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="BA-1">
+ <path
+ style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+ d="M 9.5,578 C 7.96808,578 7,579.29203 7,580.5 v 9 c 0,1.20797 0.96808,2.5 2.5,2.5 h 9 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -9 C 8.53192,591 8,590.17765 8,589.5 8,588.82235 8.53192,588 9.5,588 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 4,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.18026 -0.86027,2.25 -2,2.44531 V 585 h -1 v -1.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 -0.83435,0 -1.5,0.66565 -1.5,1.5 v 0.5 h -1 v -0.5 c 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m -0.5,7 h 1 v 1 h -1 z m -3.5,3 a 0.50005,0.50005 0 1 0 0,1 h 9 a 0.50005,0.50005 0 1 0 0,-1 z"
+ transform="translate(187,90)"
+ id="path13602"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g24378"
+ inkscape:label="AA-26"
+ style="display:inline;enable-background:new">
+ <path
+ id="path22885-3-7"
+ d="m 537.4922,557 c -0.1299,0 -0.2539,0.055 -0.3457,0.1465 -1.4018,1.4018 -2.9571,1.8535 -5.6465,1.8535 -0.2761,0 -0.5,0.2239 -0.5,0.5 v 3 c 0,2.4627 0.6805,4.0682 1.7871,5.2754 1.1066,1.2072 2.5736,2.0242 4.1777,3.1348 0.084,0.058 0.1832,0.09 0.2852,0.09 h 0.5 c 0.102,-2e-4 0.2015,-0.032 0.2852,-0.09 1.6041,-1.1106 3.0711,-1.9276 4.1777,-3.1348 C 543.3195,566.5682 544,564.9627 544,562.5 v -3 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 -2.6894,0 -4.2447,-0.4517 -5.6465,-1.8535 -0.096,-0.096 -0.226,-0.1486 -0.3613,-0.1465 z m 3.4766,3.9902 a 1.0001,1.0001 0 0 1 0.8124,1.6348 l -4,5 a 1.0001,1.0001 0 0 1 -1.4882,0.082 l -2,-2 a 1.0001,1.0001 0 1 1 1.414,-1.414 l 1.209,1.209 3.3028,-4.127 a 1.0001,1.0001 0 0 1 0.75,-0.3848 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g24375"
+ inkscape:label="AA-25"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 516.49219,557 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 C 514.74469,558.54828 513.18939,559 510.5,559 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 c 0,2.46272 0.6805,4.06818 1.78711,5.27539 1.10661,1.20722 2.57356,2.02419 4.17773,3.13477 A 0.50005,0.50005 0 0 0 516.25,571 h 0.5 a 0.50005,0.50005 0 0 0 0.28516,-0.0898 c 1.60417,-1.11058 3.07112,-1.92755 4.17773,-3.13477 C 522.3195,566.56818 523,564.96272 523,562.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 c -2.68939,0 -4.24469,-0.45172 -5.64648,-1.85352 A 0.50005,0.50005 0 0 0 516.49219,557 Z m 0.008,1.07031 c 1.42533,1.26825 3.16641,1.79779 5.5,1.86524 V 562.5 c 0,2.28728 -0.5695,3.55682 -1.52539,4.59961 -0.92707,1.01135 -2.30655,1.81425 -3.88867,2.90039 h -0.17188 c -1.58212,-1.08614 -2.9616,-1.88904 -3.88867,-2.90039 C 511.5695,566.05682 511,564.78728 511,562.5 v -2.56445 c 2.33359,-0.0675 4.07467,-0.59699 5.5,-1.86524 z"
+ id="path22877-22-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g10896"
+ inkscape:label="AA-18"
+ style="display:inline;enable-background:new">
<rect
- y="598"
- x="614"
- height="16"
- width="16"
- id="rect6732-0"
- style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1;stroke-opacity:1;marker:none" />
+ style="display:inline;fill:none;stroke-width:0;enable-background:new"
+ id="rect10849"
+ width="18"
+ height="18"
+ x="361"
+ y="555"
+ inkscape:label="BLANK_ICON" />
+ </g>
+ <g
+ id="g24381"
+ inkscape:label="AA-17"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 618.74609,599 a 0.50005,0.50005 0 0 0 -0.48437,0.37695 l -3.2461,12.75 A 0.50005,0.50005 0 0 0 615,612.25 v 0.25 a 0.50005,0.50005 0 1 0 1,0 v -0.1875 l 0.84961,-3.33398 A 0.50005,0.50005 0 0 0 617,609 h 4 a 0.50005,0.50005 0 0 0 0.14844,-0.0195 h 0.002 L 622,612.3125 V 612.5 a 0.50005,0.50005 0 1 0 1,0 v -0.25 a 0.50005,0.50005 0 0 0 -0.0156,-0.12305 l -3.25391,-12.75 A 0.50005,0.50005 0 0 0 619.24609,599 Z m 0.25,1.54492 1.90235,7.45508 h -3.80078 z"
- id="path6736-8"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 351.48242,557.01562 -0.96875,0.0156 c -0.0189,2.6e-4 -0.0378,0.002 -0.0566,0.004 -2.58289,0.33067 -4.57988,2.60038 -4.45117,5.21484 0.0288,0.58487 0.23179,1.09854 0.44141,1.5957 l -3.78516,3.78516 c -0.33708,0.30742 -0.60091,0.7293 -0.64063,1.23047 -0.0397,0.50117 0.17261,1.03979 0.625,1.49219 0.45357,0.45356 0.99596,0.65829 1.49219,0.61328 0.49624,-0.045 0.906,-0.30379 1.21485,-0.61328 l 3.80664,-3.80664 c 0.52791,0.22561 1.0693,0.4331 1.69336,0.45117 2.60313,0.0754 4.83493,-1.87377 5.11328,-4.46289 0.001,-0.0136 0.002,-0.0273 0.002,-0.041 l 0.0215,-0.9668 c 0.0105,-0.45102 -0.53451,-0.68424 -0.85351,-0.36523 L 352.29297,564 h -1.58594 L 349,562.29297 v -1.58594 l 2.84375,-2.83789 c 0.31756,-0.31766 0.0878,-0.86042 -0.36133,-0.85352 z"
+ id="path18095"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccc" />
+ </g>
+ <g
+ transform="translate(-390.004,-305.996)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15818-1"
+ inkscape:label="AA-16">
+ <path
+ inkscape:connector-curvature="0"
+ id="path15352-4"
+ d="m 718.49219,868 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 L 717,869.29297 718.70703,871 l 1.14649,-1.14648 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -1,-1 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z m -2.19922,2 -5.14649,5.14648 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 1,1 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 L 718,871.70703 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccscccccccc" />
+ <g
+ transform="translate(42)"
+ id="g15380-9"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 672.49219,862.99219 A 0.50005,0.50005 0 0 0 672,863.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 866 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 673 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 8,0.5 A 0.50005,0.50005 0 0 0 680,864 v 1 h -1 a 0.50005,0.50005 0 1 0 0,1 h 1 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 0,7.5 A 0.50005,0.50005 0 0 0 680,871.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 874 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 681 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path15378-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g9974-4-9"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-84,21)"
+ inkscape:label="AA-15">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path14003-8"
+ transform="translate(84,-21)"
+ d="M 308.06055,557 C 307.40848,557.63639 307,558.52103 307,559.5 c 0,1.5 0.75,2.5 2,3.14453 v 0.004 6.85156 c -0.0287,2.02848 3.02869,2.02848 3,0 v -6.85156 -0.002 c 1.28948,-0.66521 2,-1.64648 2,-3.14648 0,-0.97897 -0.40848,-1.86361 -1.06055,-2.5 H 312.91797 312 V 560 l -1,1 h -1 l -1,-1 2e-5,-3 z M 310,569 h 1 v 1 h -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccscscsccc"
+ id="path14013-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 387.00001,542 387,536.5 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 l 10e-6,5.5 z m 0.75,2 H 388.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 0.75001 v 1 c -0.75,0 -1.25,0.5 -1.25,1.25 L 384,547.5 c -10e-6,0.78517 0.31169,1.44054 0.78516,1.86719 0.47346,0.42664 1.08725,0.63281 1.69726,0.63281 0.61001,0 1.22902,-0.20449 1.71094,-0.62891 0.48192,-0.42441 0.80663,-1.08156 0.80664,-1.87109 l 10e-6,-1.25 c 0,-0.75 -0.5,-1.25 -1.25,-1.25 z"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13069"
+ transform="translate(-21,42)"
+ inkscape:label="AA-13">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 310,45 v -5 h 1.5 c 0.83481,0 1.5,0.664144 1.5,1.498047 v 2.007812 c 0,0.833914 -0.66519,1.498047 -1.5,1.496094 z m 4,-1.494141 V 41.498047 C 314,40.122764 312.87431,39 311.5,39 H 310 v -6.5 c 0.004,-0.28226 -0.22555,-0.512233 -0.50781,-0.507812 C 309.21605,31.996188 308.99568,32.22386 309,32.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 2,0.002 c 1.37431,0.002 2.5,-1.120801 2.5,-2.496094 z"
- transform="translate(314.99995,567)"
- id="path6744-7"
+ sodipodi:nodetypes="ccccccccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccsccccccsccccccccc" />
+ id="ellipse12909"
+ d="m 290,517 h 2.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2.91992 c -0.029,-0.005 -0.0584,-0.008 -0.0879,-0.008 -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 5.64062 c -0.56586,-0.20756 -1.28645,-0.18129 -1.98242,0.0723 -1.35506,0.4963 -2.23747,1.69879 -1.9707,2.68555 0.26595,0.98712 1.58042,1.38505 2.93554,0.88867 1.22872,-0.45129 2.01759,-1.35494 2.01758,-2.53711 z"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.99;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.755428px;marker:none;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 283.51562,517 a 0.50005,0.50005 0 0 0 -0.22656,0.0566 c -1.99745,1.00305 -3.4683,2.88412 -4.03515,5.13477 -0.56686,2.25064 -0.17629,4.64784 1.07421,6.56836 a 0.50005,0.50005 0 1 0 0.8379,-0.54493 c -1.09418,-1.68042 -1.44042,-3.798 -0.94141,-5.77929 0.49902,-1.9813 1.78869,-3.62011 3.51367,-4.48633 A 0.50005,0.50005 0 0 0 283.51562,517 Z m 0.98243,3 a 0.50005,0.50005 0 0 0 -0.26758,0.082 c -1.21391,0.77866 -2.01457,2.12204 -2.19336,3.63086 -0.17879,1.50883 0.2812,3.02564 1.26367,4.11719 a 0.50005,0.50005 0 1 0 0.74219,-0.66992 c -0.77619,-0.86237 -1.15757,-2.0993 -1.01172,-3.33008 0.14584,-1.23079 0.79828,-2.30329 1.73828,-2.90625 A 0.50005,0.50005 0 0 0 284.49805,520 Z"
+ id="path12979"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-231.00712,-588.00007)"
- id="g23192-6"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15967"
+ inkscape:label="AA-12">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 244,561 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z"
+ id="path17035"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 243.92383,557 c -0.2146,0.003 -0.42883,0.0151 -0.64063,0.0371 -2.54151,0.26418 -4.8299,1.914 -5.80664,4.42187 -1.30231,3.34383 0.14236,7.14072 3.33789,8.77344 3.19554,1.63272 7.11991,0.57913 9.06641,-2.43554 a 0.50005,0.50005 0 1 0 -0.83984,-0.54297 c -1.67274,2.59068 -5.02539,3.49293 -7.77149,2.08984 -2.7461,-1.40309 -3.98048,-4.64795 -2.86133,-7.52148 1.11915,-2.87354 4.22361,-4.42733 7.19532,-3.60352 a 0.50036742,0.50036742 0 1 0 0.26562,-0.96484 c -0.64839,-0.17975 -1.3015,-0.26149 -1.94531,-0.25391 z M 249,557 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
+ id="path17037"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="rotate(90,243.5,333.5)"
+ id="g12586"
+ style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="AA-11">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 469.5,356 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z"
+ id="path12572"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
<g
- transform="translate(21)"
- id="g23190-0"
- style="fill:#ffffff">
+ id="g23031"
+ style="opacity:0.7;fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 553.5,620 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 11 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path23186-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 218.5,557 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 V 564.5 c -0.01,0.67616 1.01,0.67616 1,0 v -4.59375 c 0.57903,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 9.5,0 c -1.09865,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -5.13868,5.13867 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 5.13867,-5.13868 C 227.28978,560.89117 227.63141,561 228,561 c 1.09865,-10e-6 2,-0.90135 2,-2 0,-1.09865 -0.90135,-1.99999 -2,-2 z m 0.5,10 c -0.64684,0 -1.19777,0.42097 -1.40625,1 H 222.5 c -0.67616,-0.01 -0.67616,1.01 0,1 h 4.59375 c 0.20848,0.57903 0.75941,1 1.40625,1 0.82251,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
+ transform="matrix(0,-1,-1,0,1038,577)"
+ id="path12578"
inkscape:connector-curvature="0" />
</g>
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g12563-2"
- transform="translate(-84.000002,4.4999696e-6)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g24384"
+ inkscape:label="AA-10"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 202,556.99628 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 198.00799,558.26759 198,559.00268 198,559.49628 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 199,559.99428 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-10e-6 2.78534,-0.23261 3.38867,-0.75196 C 205.99201,569.73274 206,568.99765 206,568.50405 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 a 0.50005,0.50005 0 0 0 -0.0586,-0.004 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 l 2.49595,-0.004 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 -0.27166,-0.2339 -0.26367,-0.49668 -0.26367,-0.99028 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z"
+ id="path12249-6"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25476"
+ transform="translate(-20)"
+ inkscape:label="AA-7">
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25445"
+ transform="translate(-218,-111)">
+ <path
+ sodipodi:nodetypes="ssssccccccccssssccs"
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 301.5,305 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 5 c 0,0.82235 1,1.5 1.5,1.5 h 0.5 v -3 h -0.5 c -0.67616,0.01 -0.67616,-1.01 0,-1 h 11 c 0.67616,-0.01 0.67616,1.01 0,1 H 312 v 3 h 0.5 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -5 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 H 312 302 Z"
+ transform="translate(70,363)"
+ id="path25441" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 135,562 v 8.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 562 Z m 6,2 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m -2.50781,2 c 0.16994,-0.003 0.32953,0.0812 0.42383,0.22266 l 2,3 c 0.22142,0.33228 -0.0167,0.77726 -0.41602,0.77734 h -4 c -0.39932,-8e-5 -0.63744,-0.44506 -0.41602,-0.77734 l 2,-3 c 0.0912,-0.13686 0.24381,-0.21966 0.40821,-0.22266 z"
+ transform="translate(238,111)"
+ id="path25443"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22484"
+ transform="translate(-220,-220)"
+ inkscape:label="AA-6">
<path
+ id="path22480"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 334.5,777 c -0.15738,-3e-4 -0.30571,0.0735 -0.40039,0.19922 L 332.75,779 H 332 c -0.54535,0 -1,0.45465 -1,1 v 9 c 0,0.54535 0.45465,1 1,1 h 12 c 0.54535,0 1,-0.45465 1,-1 v -9 c 0,-0.54535 -0.45465,-1 -1,-1 h -3.75 l -1.34961,-1.80078 C 338.80571,777.07351 338.65738,776.9997 338.5,777 Z m 1,1 h 2 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 1 c -3e-5,0.27613 -0.22387,0.49997 -0.5,0.5 h -2 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -1 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 z m -3.5,3 h 9 v 7 h -9 v -6.5 z m 11,1 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m 0,4 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z"
inkscape:connector-curvature="0"
- id="rect12547-2"
- d="m 405,32 v 8 h 14 v -8 z m 2.50781,2 h 8.98438 c 0.67616,-0.0096 0.67616,1.009563 0,1 h -8.98438 c -0.67616,0.0096 -0.67616,-1.009563 0,-1 z m 0,3 h 8.98438 c 0.67616,-0.0096 0.67616,1.009563 0,1 h -8.98438 c -0.67616,0.0096 -0.67616,-1.009563 0,-1 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1.00000003, 2.00000004;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- sodipodi:nodetypes="ccccccccccccccc" />
+ sodipodi:nodetypes="cccsssssssscccccccccccccccccccssssssssss" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 407.50781,42 a 0.50005,0.50005 0 1 0 0,1 h 8.98438 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 8.98438 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path12541-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.2;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 333.5,782 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z m 0,2 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z m 0,2 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z"
+ id="path22526"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 342.50195,777 c -0.67617,-0.01 -0.67617,1.00957 0,1 h 1 c 0.67617,0.01 0.67617,-1.00957 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path22529"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+ <g
+ id="g16187"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(462.005,-96.0051)"
+ inkscape:label="AA-5">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.99;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 103.49609,556.99023 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.57031,1.57032 c -1.22858,-1.06562 -2.825838,-1.7168 -4.576171,-1.7168 -3.86007,0 -7,3.13993 -7,7 0,1.75033 0.649231,3.34954 1.714844,4.57813 l -1.568359,1.56835 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.568359,-1.56836 c 1.228585,1.06561 2.827793,1.71484 4.578125,1.71484 3.860071,0 7.000001,-3.13993 7.000001,-7 0,-1.75033 -0.65118,-3.34759 -1.7168,-4.57617 l 1.57032,-1.57031 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -6.490231,1.00391 c 3.319631,0 6.000001,2.68037 6.000001,6 0,3.31963 -2.68037,6 -6.000001,6 -3.31963,0 -6,-2.68037 -6,-6 0,-0.88092 0.193846,-1.71405 0.533203,-2.4668 l 0.466797,0.4668 1,1 v 2 h 2 v 1 l 1,1 v 2 h 0.75 1.25 l 1,-1 1.000001,-1 v -1 l -1.000001,-1 h -2 -1 l -1,-1 h -1 l 1,-1 h 1 l 2,-2 -1,-1 h -1 l -1,-1 0.894532,-0.89453 c 0.358617,-0.0666 0.727234,-0.10547 1.105468,-0.10547 z"
+ transform="translate(-462.005,96.0051)"
+ id="circle16176"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 279.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 292.5,32 Z m 0.5,1 h 12 v 12 h -12 z"
- id="rect12615-8"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 282.56641,35 a 0.50005,0.50005 0 1 0 -0.008,1 l 4.9375,0.03125 a 0.50005,0.50005 0 1 0 0.008,-1 z m 0,2 a 0.50005,0.50005 0 1 0 -0.008,1 l 3.9375,0.03125 a 0.50005,0.50005 0 1 0 0.008,-1 z m 0.004,2 a 0.50006099,0.50006099 0 1 0 -0.0156,1 l 1.9375,0.03125 a 0.50006099,0.50006099 0 1 0 0.0156,-1 z m -0.006,2 a 0.50005,0.50005 0 1 0 -0.004,1 l 5.9375,0.03125 a 0.50005,0.50005 0 1 0 0.004,-1 z"
- id="path12623-2"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
+ transform="matrix(-1,0,0,1,384.832,63)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g10061"
+ id="g23034"
+ inkscape:label="AA-4">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 310.58203,494 c -1.1875,0 -2.13583,0.69085 -2.52344,1.62109 -0.3876,0.93025 -0.20775,2.10475 0.66993,2.98243 l 2.5,2.5 c 0.62232,0.62232 0.69247,1.32282 0.45507,1.89257 C 311.4462,503.56585 310.89453,504 310.08203,504 l -6.53515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 6.55078,0.008 c 1.1875,0 2.13584,-0.69085 2.52344,-1.62109 0.3876,-0.93025 0.20775,-2.10475 -0.66992,-2.98243 l -2.5,-2.5 c -0.62233,-0.62232 -0.69248,-1.32282 -0.45508,-1.89257 0.2374,-0.56976 0.78906,-1.00391 1.60156,-1.00391 h 4.75 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path23032"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g23748"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="AA-3">
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 49,558 v 3 h 3 v -3 z m 3,3 v 3 h 3 v -3 z m 3,0 h 3 v -3 h -3 z m 3,0 v 3 h 3 v -3 z m 0,3 h -3 v 3 h 3 z m 0,3 v 3 h 3 v -3 z m -3,0 h -3 v 3 h 3 z m -3,0 v -3 h -3 v 3 z"
+ id="path10767"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 48.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 61.5,557 Z m 0.5,1 h 12 v 12 H 49 Z"
+ id="rect22625"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1.15384;enable-background:new"
+ id="g12595"
+ transform="matrix(0.866668,0,0,0.866668,-177.467,184.399)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- id="g9978"
- transform="translate(159,3)"
- style="display:inline;fill:#ffffff;enable-background:new">
- <g
- style="display:inline;fill:#ffffff;stroke-width:1.25052631;enable-background:new"
- id="g9976"
- transform="matrix(0.79966332,0,0,0.79966332,-130.65118,113.69494)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 142,578 c -2.19759,0 -4,1.80241 -4,4 0,0.9193 0.32769,1.75955 0.85547,2.4375 l -3.70899,3.70898 a 0.50029086,0.50029086 0 1 0 0.70704,0.70704 l 3.70898,-3.70899 C 140.24045,585.67231 141.0807,586 142,586 c 2.19759,0 4,-1.80241 4,-4 0,-2.19759 -1.80241,-4 -4,-4 z m 0,1 c 1.65213,0 3,1.34787 3,3 0,1.65213 -1.34787,3 -3,3 -1.65214,0 -3,-1.34787 -3,-3 0,-1.65214 1.34786,-3 3,-3 z"
- transform="matrix(1.2505263,0,0,1.2505263,-35.450942,-145.9301)"
- id="path9971"
- inkscape:connector-curvature="0" />
- </g>
- </g>
+ inkscape:export-ydpi="96"
+ inkscape:label="AA-2">
<g
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- transform="translate(-21.00001,84.99938)"
- id="g10042">
+ style="fill:#ffffff;stroke-width:1.15384"
+ id="g12593">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 135.48438,579 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 580 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1 v 0.002 c -0.005,0 -0.0101,-0.002 -0.0156,-0.002 z M 132,584 v 7.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 3.5 h -8 v -7 z"
- transform="translate(21.000012,-84.999384)"
- id="path10038"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 34,557 c -3.860079,0 -7,3.13992 -7,7 0,3.86008 3.139921,7 7,7 3.860079,0 7,-3.13992 7,-7 0,-3.86008 -3.139921,-7 -7,-7 z m 0,1 c 3.305801,0 5.975833,2.65852 5.998047,5.95898 C 38.886544,564.90262 36.995365,566 34,566 v 4 c -3.319633,0 -6,-2.68037 -6,-6 0,-0.0145 0.0019,-0.0285 0.002,-0.043 C 29.113203,564.90101 31.002992,566 34,566 Z"
+ transform="matrix(1.15384,0,0,1.15384,204.769,-212.768)"
+ id="path12589"
inkscape:connector-curvature="0" />
</g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 370.49414,224.00195 a 0.50005,0.50005 0 0 0 -0.34766,0.14649 l -4,3.99804 a 0.50005,0.50005 0 0 0 0,0.70704 l 4,4 a 0.50005,0.50005 0 0 0 0.70508,0 l 3.99219,-3.97852 a 0.50005,0.50005 0 0 0 0.002,-0.70703 l -3.99218,-4.01953 a 0.50005,0.50005 0 0 0 -0.35938,-0.14649 z m 0.004,1.20899 3.28711,3.30859 L 370.5,231.79297 367.20703,228.5 Z"
- id="path23352-4"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 349.49414,224 c -0.13124,0.001 -0.25681,0.0537 -0.34961,0.14648 l -3.99805,4 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3.99805,4 c 0.19526,0.19518 0.51177,0.19518 0.70703,0 l 3.99219,-3.97852 c 0.19574,-0.19471 0.19663,-0.51121 0.002,-0.70703 l -3.99218,-4.01953 c -0.0949,-0.0959 -0.2245,-0.14948 -0.35943,-0.14844 z"
- id="path23378-3"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 328.48047,226.75 a 0.50005,0.50005 0 0 0 -0.39063,0.21484 l -3.99023,5.72461 a 0.50005,0.50005 0 0 0 -0.0898,0.27735 L 324,233.49219 A 0.50005,0.50005 0 0 0 324.5,234 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 233 a 0.50005,0.50005 0 0 0 -0.0898,-0.28516 l -4,-5.75 A 0.50005,0.50005 0 0 0 328.48047,226.75 Z m 0.0195,1.375 3.39062,4.875 h -6.78906 z"
- id="path23380-3"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 307.48242,226.75 c -0.15739,0.006 -0.30286,0.0854 -0.39258,0.21484 l -4,5.75 c -0.0583,0.0837 -0.0897,0.18317 -0.0898,0.28516 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27999,2e-5 0.50544,-0.22983 0.5,-0.50977 l -0.01,-0.47461 c -0.002,-0.0985 -0.0321,-0.19425 -0.0879,-0.27539 l -3.99023,-5.77539 c -0.0971,-0.14016 -0.25903,-0.22114 -0.42945,-0.21484 z"
- id="path23382-9"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccc" />
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g12105"
- transform="translate(-147.00001,-566.99994)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24819"
+ transform="translate(-1015,-999)"
+ inkscape:label="AA-1">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ id="path24815"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
+ id="path24817"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g27728"
+ inkscape:label="Z-25"
+ style="display:inline;enable-background:new">
+ <path
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ d="m 516,545 h 2 v -2 h -2 z m 0,-4 h 2 v -2 h -2 z"
+ style="display:inline;opacity:0.8;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path19014-3-8" />
+ <path
+ id="path19004-3"
+ d="m 512,536 c -0.52447,0 -1.0237,0.21715 -1.39258,0.57617 C 510.23866,536.93533 510,537.43678 510,538.00195 V 548 c 8e-5,0.53017 0.21103,1.03915 0.58594,1.41406 C 510.96085,549.78897 511.46978,550 512,550 h 1.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -10 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 512 c -0.45232,0 -1,-0.47106 -1,-0.99805 0,-0.26349 0.1383,-0.51454 0.33203,-0.69922 C 511.52545,537.11905 511.77501,537 512,537 h 6 v 2 h 2 v -2 h 2 v 2.00586 L 520,539 v 2 l 2,0.006 v 2 L 520,543 v 2 l 2,0.006 V 547 h -1.99414 l -0.01,-2 h -2 l 0.01,2 H 515 v 1 h 8.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -11 z m 8,7 v -2 h -2 v 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g17491"
+ transform="matrix(0.875,0,0,0.875,264.125,159.75)"
+ style="display:inline;fill:#ffffff;stroke-width:1.14286;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="Z-24">
<rect
- y="597.99994"
- x="278"
+ y="430"
+ x="257"
height="16"
width="16"
- id="rect12101"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
+ id="rect17483"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3.42857;marker:none;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 286,599 c -3.8542,0 -7,3.1458 -7,7 0,3.8542 3.1458,7 7,7 3.8542,0 7,-3.1458 7,-7 0,-3.8542 -3.1458,-7 -7,-7 z m 0,2 c 2.77332,0 5,2.22668 5,5 0,2.77332 -2.22668,5 -5,5 -2.77332,0 -5,-2.22668 -5,-5 0,-2.77332 2.22668,-5 5,-5 z"
- id="path12103"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 496,535.9375 c -2.73936,0 -5.1213,1.56371 -6.29102,3.84961 -0.49329,0.96401 -0.77148,2.05765 -0.77148,3.21289 0,3.89459 3.16791,7.0625 7.0625,7.0625 3.89459,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.89459 -3.16791,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.35415,0 6.0625,2.70835 6.0625,6.0625 0,3.35415 -2.70834,6.0625 -6.0625,6.0625 -3.35415,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-0.99492 0.23889,-1.93072 0.66211,-2.75781 1.00359,-1.96124 3.04116,-3.30469 5.40039,-3.30469 z M 496,538 a 0.99999996,0.99999996 0 0 0 -1,1 0.99999996,0.99999996 0 0 0 1,1 0.99999996,0.99999996 0 0 0 1,-1 0.99999996,0.99999996 0 0 0 -1,-1 z m -2.82422,1.16211 a 1.0001001,1.0001001 0 0 0 -0.6875,0.30469 c -0.61854,0.6208 -1.06287,1.393 -1.28906,2.24023 a 1.0001001,1.0001001 0 1 0 1.93164,0.51563 c 0.13595,-0.50922 0.40262,-0.97353 0.77344,-1.34571 a 1.0001001,1.0001001 0 0 0 -0.72852,-1.71484 z"
+ transform="matrix(1.14286,0,0,1.14286,-301.857,-182.571)"
+ id="path17485"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 6.5,32 A 0.50005,0.50005 0 0 0 6,32.5 v 13 A 0.50005,0.50005 0 0 0 6.5,46 h 13 A 0.50005,0.50005 0 0 0 20,45.5 v -13 A 0.50005,0.50005 0 0 0 19.5,32 Z M 7,33 H 19 V 45 H 7 Z"
- id="rect12121"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g12135"
+ id="g7662"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(1,0,0,-1,0,1085.98)"
+ inkscape:label="Z-23">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17742-5"
+ d="m 468.50781,535.99219 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 5.00586 l -1,-0.006 v 2 l 1,0.006 V 546 h -1.00586 l 0.006,-2.00781 h -2 L 478.00195,546 h -2 l 0.006,-2.00781 h -2 L 474.00195,546 h -2 l 0.006,-2.00781 h -2 L 470.00195,546 h -0.99414 v -2.00391 l 1,-0.006 v -2 l -1,0.006 z m 3,7 h 2 v -2 h -2 z m 4,0 h 2 v -2 h -2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ <path
+ id="path17758-8"
+ d="m 470.00781,539.99219 v 2 h 2 v -2 z m 4,0 v 2 h 2 v -2 z m 4,0 v 2 h 2 v -2 z"
+ style="display:inline;opacity:0.8;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14058"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="Z-22">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 158.5,222 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 155.29297,225 H 153.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 158.5,234 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 222.78125 222.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 159 v 10 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 155.5,230 H 154 v -4 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z"
- id="path12129"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 451.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 8 h -8 z"
+ id="path14208"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 165.4668,223.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27309,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41118,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10287,2.06013 1.10465,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25203,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
- id="path12133"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 449.49219,537.99219 A 0.50005,0.50005 0 0 0 449,538.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 450 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 447,540.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path14212"
inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 460.48438,536 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -9,9 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z"
+ id="path14252"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
</g>
<g
- id="g6417"
- style="fill:#ffffff">
- <path
- id="path8180-3"
- d="m 470.66016,493.97656 c -0.37961,-0.006 -0.76447,0.0652 -1.1211,0.21289 -0.93286,0.38641 -1.54492,1.30084 -1.54492,2.31055 v 3.5 h 1 v -3.5 c 0,-0.60813 0.3659,-1.154 0.92774,-1.38672 0.5437,-0.22521 1.42162,-0.0569 1.71874,0.24024 l 0.5,0.5 c 0.47128,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -0.5,-0.5 c -0.35144,-0.35143 -0.81472,-0.56325 -1.31055,-0.63867 -0.12396,-0.0188 -0.25042,-0.0294 -0.37695,-0.0312 z m 8.67382,0 c -0.12653,0.002 -0.25299,0.0124 -0.37695,0.0312 -0.49583,0.0754 -0.95911,0.28724 -1.31055,0.63867 l -0.5,0.5 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 0.5,-0.5 c 0.29713,-0.29714 1.17505,-0.46545 1.71875,-0.24024 C 480.63411,495.346 481,495.89187 481,496.5 v 3.5 h 1 v -3.5 c 0,-1.00971 -0.61206,-1.92414 -1.54492,-2.31055 -0.35663,-0.1477 -0.74149,-0.21856 -1.1211,-0.21289 z M 468.49414,501 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 3.00586 a 0.50005,0.50005 0 0 0 0.41602,-0.22266 L 474.76758,505 h 0.46484 l 1.85156,2.77734 A 0.50005,0.50005 0 0 0 477.5,508 h 2.99414 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z M 474,502 v 2.34766 L 472.23242,507 h -2.23828 -1 L 469,502.00195 Z m 1.99414,0 5,0.002 V 507 h -0.5 H 480 477.76758 L 476,504.34766 Z"
- style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- inkscape:connector-curvature="0" />
+ id="g27716"
+ inkscape:label="Z-21"
+ style="display:inline;enable-background:new">
<path
- sodipodi:nodetypes="ccccccccccc"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 433.5,536 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4.98242 8.01758 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -0.5,5.48242 c -0.007,-0.18325 -0.1131,-0.34814 -0.27734,-0.42969 l -2,-1 c -0.24704,-0.12272 -0.54679,-0.0222 -0.66993,0.22461 l -4,8 c -0.12272,0.24704 -0.0222,0.54679 0.22461,0.66993 l 2,1 c 0.24704,0.12272 0.54679,0.0222 0.66993,-0.22461 l 4,-8 c 0.0373,-0.0744 0.0554,-0.15702 0.0527,-0.24024 z M 434,537 h 1 v 12 h -1 z m 3.5,1 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="rect11443"
inkscape:connector-curvature="0"
- id="path8043-2"
- d="m 470.49414,503 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 471.5 c 0.16717,-10e-6 0.32328,-0.0836 0.41602,-0.22266 l 1,-1.5 c 0.0559,-0.0838 0.0852,-0.18249 0.084,-0.2832 l -0.006,-0.5 c -0.003,-0.27384 -0.22614,-0.49413 -0.5,-0.49414 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccc" />
</g>
- <path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 115,32 v 2 h 6 v -2 z m 6,2 v 2 h 2 v -2 z m 2,2 v 6 h 2 v -6 z m 0,6 h -2 v 2 h 2 z m -2,2 h -6 v 2 h 6 z m -6,0 v -2 h -2 v 2 z m -2,-2 v -6 h -2 v 6 z m 0,-6 h 2 v -2 h -2 z"
- id="rect23113-8"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="translate(-420.00718,439.99283)"
- id="g7406-1-2"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g27722"
+ inkscape:label="Z-20"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 27.492188,598.99219 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.49805 L 41,605 l -1,-0.002 -0.0059,2.99414 H 27.992188 v -8 h 8 v 3.5 c 2.9e-5,0.27613 0.223869,0.49997 0.5,0.5 h 4 c 0.44533,-1.7e-4 0.668305,-0.53852 0.353515,-0.85352 l -4,-4 c -0.09376,-0.0938 -0.22116,-0.14439 -0.353515,-0.14453 v -0.002 h -0.0078 z M 35,610 l -2,0.004 v 1.98828 h -2.507812 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 7 c 0.676159,0.01 0.676159,-1.00956 0,-1 H 35 Z"
- transform="translate(420.00718,-439.99283)"
- id="path7395-0-0"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 411,536 v 4 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.5 h -4 v 1 h 4 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v 4 h 1 v -4 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 544 h 4 v -1 h -4 v -2.5 A 0.50005,0.50005 0 0 0 414.5,540 H 412 v -4 z m -2,5 h 5 v 5 h -5 z m 2,2 v 1 h 1 v -1 z"
+ id="rect19268-0"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 53.494141,601.99414 a 0.50005,0.50005 0 0 0 -0.347657,0.85938 l 3.646485,3.64648 -3.646485,3.64648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -4,-4 a 0.50005,0.50005 0 0 0 -0.359375,-0.15234 z"
- id="path9518-7-7"
- inkscape:connector-curvature="0" />
<g
- id="g6733"
- transform="translate(-42.000002,503.9)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g6666-5"
+ transform="translate(-63,42)"
+ style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <rect
- ry="0"
- rx="0"
- y="31"
- x="68"
- height="16"
- width="16"
- id="rect4338"
- style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ inkscape:export-ydpi="96"
+ inkscape:label="Z-18">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 81.75,32.099609 c -1.433114,0 -2.573994,0.599965 -3.328125,1.414063 -0.754131,0.814098 -1.193245,1.779187 -1.615234,2.65039 -0.42199,0.871204 -0.825206,1.64712 -1.308594,2.146485 -0.483388,0.499365 -0.99066,0.789062 -1.998047,0.789062 H 69 v 2 h 4.5 c 1.476988,0 2.648427,-0.585302 3.435547,-1.398437 0.78712,-0.813135 1.246208,-1.787219 1.671875,-2.666016 0.425667,-0.878796 0.819561,-1.663707 1.28125,-2.162109 0.461689,-0.498402 0.919442,-0.773438 1.861328,-0.773438 H 83 v -2 z"
- id="path4336"
+ style="display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.8;marker:none;enable-background:accumulate"
+ d="m 363.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z m 2,2 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 1,1 v 1 h 1 v -1 z m 0,1 h -1 v 1 h 1 z m -1,1 h -1 v 1 h 1 z m 2,0 v 1 h 3 v -1 z"
+ transform="translate(63,-42)"
+ id="rect40533-7-0"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g17058"
+ transform="translate(-20.84,-20.8827)"
+ style="display:inline;enable-background:new"
+ inkscape:label="Z-17">
<g
- id="g23052"
- style="opacity:0.7;fill:#ffffff">
+ id="g7978">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 27,536.90039 v 1.19922 h 0.75 c 0.646429,0 1.301953,0.38 1.880859,1.04297 0.578907,0.66296 1.046871,1.58637 1.289063,2.49023 0.207018,0.77346 1.367174,0.46292 1.160156,-0.31054 -0.287808,-1.07411 -0.818828,-2.13723 -1.544922,-2.96875 -0.726093,-0.83153 -1.681585,-1.45313 -2.785156,-1.45313 z m 13.25,9 c -1.91571,0 -2.93215,0.90502 -3.558594,1.66992 -0.313222,0.38245 -0.555819,0.7142 -0.798828,0.91797 -0.243008,0.20377 -0.458964,0.3125 -0.892578,0.3125 -0.401011,0 -0.71548,-0.20341 -1.054688,-0.64648 -0.339207,-0.44308 -0.639641,-1.1033 -0.878906,-1.79492 -0.238226,-0.80225 -1.442094,-0.38505 -1.132812,0.39257 0.260735,0.7537 0.585301,1.5146 1.058594,2.13282 C 33.46548,549.50298 34.151011,550 35,550 c 0.691386,0 1.25668,-0.25378 1.662109,-0.59375 0.405429,-0.33997 0.678457,-0.73364 0.958985,-1.07617 0.561056,-0.68506 1.044616,-1.23047 2.628906,-1.23047 H 41 v -1.19922 z"
- transform="translate(42.000002,-503.9)"
- id="path4334"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.928338;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 373.21906,563.36205 c -2.04533,0 -3.71335,1.66802 -3.71335,3.71335 0,2.04534 1.66802,3.71336 3.71335,3.71336 2.04534,0 3.71336,-1.66802 3.71336,-3.71336 0,-2.04533 -1.66802,-3.71335 -3.71336,-3.71335 z"
+ id="path7726"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:922.783;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 364.3828,556.88974 c -0.8999,0 -1.63379,0.73389 -1.63379,1.6338 0,0.89988 0.73389,1.6338 1.63379,1.6338 0.89991,0 1.6338,-0.7339 1.6338,-1.6338 0,-0.8999 -0.73389,-1.6338 -1.6338,-1.6338 z"
+ id="path7808"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:922.783;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 366.50464,561.82783 c -1.31395,0 -2.38552,1.07155 -2.38552,2.3855 0,1.31395 1.07157,2.38555 2.38552,2.38555 1.31396,0 2.38553,-1.07158 2.38553,-2.38555 0,-1.31395 -1.07157,-2.3855 -2.38553,-2.3855 z"
+ id="path7890"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1881.46;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 368.88012,557.69285 c -1.06196,0 -1.928,0.86602 -1.928,1.92801 0,1.06192 0.86604,1.92798 1.928,1.92798 1.06195,0 1.92801,-0.86606 1.92801,-1.92798 0,-1.06195 -0.86606,-1.92801 -1.92801,-1.92801 z"
+ id="path7972"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
</g>
</g>
<g
- id="g7579"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14497"
+ inkscape:label="Z-16">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 324.60938,536 C 323.75288,536 323,536.6483 323,537.5 v 3 c 0,0.8517 0.75288,1.5 1.60938,1.5 h 4.78124 C 330.24712,542 331,541.3517 331,540.5 v -3 c 0,-0.8517 -0.75287,-1.5 -1.60938,-1.5 z M 332,537 v 3 c 0.56267,0 1,-0.50398 1,-1.03125 v -0.9375 C 333,537.50408 332.56269,537 332,537 Z m -7.53516,3 a 0.50005,0.50005 0 0 1 0.0352,0 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50030966,0.50030966 0 0 1 -0.0352,-1 z m -1.85546,4 C 321.75288,544 321,544.6483 321,545.5 v 3 c 0,0.8517 0.75288,1.5 1.60938,1.5 h 4.78124 C 328.24712,550 329,549.3517 329,548.5 v -3 c 0,-0.8517 -0.75287,-1.5 -1.60938,-1.5 z M 330,546 v 3 c 0.56267,0 1,-0.50398 1,-1.03125 v -0.9375 C 331,546.50408 330.56269,546 330,546 Z m -7.53516,2 a 0.50005,0.50005 0 0 1 0.0352,0 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50030966,0.50030966 0 0 1 -0.0352,-1 z"
+ id="rect12085"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(0,231)"
+ style="opacity:1;fill:#ffffff"
+ id="g12112">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 332.5,307 v 1 c 0.55917,0 0.9084,0.14278 1.13281,0.36719 C 333.85722,308.5916 334,308.94083 334,309.5 v 5 c 0,0.55917 -0.14278,0.9084 -0.36719,1.13281 C 333.4084,315.85722 333.05917,316 332.5,316 h -2 v 1 h 2 c 0.73927,0 1.38886,-0.20918 1.83984,-0.66016 C 334.79082,315.88886 335,315.23927 335,314.5 v -5 c 0,-0.73927 -0.20918,-1.38886 -0.66016,-1.83984 C 333.88886,307.20918 333.23927,307 332.5,307 Z"
+ id="path12102"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsssssccsssssc" />
+ </g>
+ </g>
+ <g
+ transform="matrix(1,0,0,-1,-167.993,1043.99)"
+ id="g17666-2"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="Z-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 48.499998,536.00001 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 4 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 7,6 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0,5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="rect5843"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccccc" />
+ id="path17674"
+ d="m 475.00071,508.00091 c -3.8601,0 -7,-3.1399 -7,-7 0,-3.8601 3.1399,-7 7,-7 3.8601,0 7,3.1399 7,7 0,3.8601 -3.1399,7 -7,7 z m 2.96094,-1.99804 a 1.0001,1.0001 0 0 0 1.04102,-0.98633 1.0001,1.0001 0 0 0 -0.20899,-0.62305 l -2.57617,-3.43555 1.60742,-2.41015 a 1.0001,1.0001 0 1 0 -1.66406,-1.10938 l -1.91211,2.86914 a 1.0001,1.0001 0 0 0 -0.26367,0.68164 1.0001,1.0001 0 0 0 0.004,0.0801 1.0001,1.0001 0 0 0 0.30664,0.66016 l 2.89844,3.86328 a 1.0001,1.0001 0 0 0 0.76758,0.41016 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13226"
+ transform="translate(-189,84)"
+ inkscape:label="Z-14">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 50,540 v 8.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 54 v -1 h -3 v -4 h 3 v -1 h -3 v -3 z"
- id="path5849"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
+ d="m 285,536 -0.15625,1.90625 c -0.6231,0.14227 -1.07677,0.25145 -1.59375,0.59375 l -1.75,-1.5 -1.5,1.5 1.5,1.75 c -0.34229,0.51699 -0.45148,0.97065 -0.59375,1.59375 L 279,542 v 1 1 l 1.90625,0.15625 c 0.14227,0.6231 0.25145,1.07677 0.59375,1.59375 l -1.5,1.75 1.5,1.5 1.75,-1.5 c 0.51699,0.34229 0.97065,0.45148 1.59375,0.59375 L 285,550 h 1 1 l 0.15625,-1.90625 c 0.6231,-0.14227 1.07677,-0.25145 1.59375,-0.59375 l 1.75,1.5 1.5,-1.5 -1.5,-1.75 c 0.34229,-0.51699 0.45148,-0.97065 0.59375,-1.59375 L 293,544 v -1 -1 l -1.90625,-0.15625 C 290.95148,541.22065 290.8423,540.76698 290.5,540.25 l 1.5,-1.75 -1.5,-1.5 -1.75,1.5 c -0.51699,-0.34229 -0.97065,-0.45148 -1.59375,-0.59375 L 287,536 h -1 z m 1,5 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 -1.11641,0 -2,-0.88359 -2,-2 0,-1.11641 0.88359,-2 2,-2 z"
+ transform="translate(189,-84)"
+ id="path52982-3"
inkscape:connector-curvature="0" />
</g>
<g
id="g7627"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="Z-13">
<g
- transform="matrix(1,0,0,-1,-42.000002,917.99993)"
+ transform="matrix(1,0,0,-1,-42,918)"
id="g4806"
style="opacity:0.6;fill:#ffffff">
<path
@@ -8311,61 +9123,13 @@
id="path4817"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 218.5,74 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 1.7e-4,0.445324 0.53852,0.668302 0.85352,0.353516 l 3.64648,-3.646485 3.64648,3.646485 c 0.315,0.314786 0.85335,0.09181 0.85352,-0.353516 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
- id="rect9857"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 326.49023,56 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707031 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.14649,-3.146485 H 334.5 a 0.50005,0.50005 0 1 0 0,-1 h -10.79297 l 3.14649,-3.146484 A 0.50005,0.50005 0 0 0 326.49023,56 Z"
- id="path12420"
- inkscape:connector-curvature="0" />
- <g
- id="g12536"
- transform="matrix(0,1,1,0,270,-183)"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 261.49023,51.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 258.70703,57 H 268.5 c 0.83435,0 1.5,0.665651 1.5,1.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 c 0,-1.374789 -1.12521,-2.5 -2.5,-2.5 h -9.79297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z"
- id="path12534"
- inkscape:connector-curvature="0" />
- </g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 350.50195,56 a 0.50005,0.50005 0 0 0 -0.34765,0.859375 l 3.14648,3.146484 h -10.79297 a 0.50005,0.50005 0 1 0 0,1 h 10.79297 l -3.14648,3.146485 a 0.50005,0.50005 0 1 0 0.70703,0.707031 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707031 l -4,-4 A 0.50005,0.50005 0 0 0 350.50195,56 Z"
- id="path9970"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 283.49023,52.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 280.70703,58 H 288 c 2.21506,0 4,1.784939 4,4 0,2.215061 -1.78494,4 -4,4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 2.7555,0 5,-2.244499 5,-5 0,-2.755501 -2.2445,-5 -5,-5 h -7.29297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z"
- id="path13225"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 309.49414,52.994141 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 L 312.29297,57 H 305 c -2.7555,0 -5,2.244499 -5,5 0,2.755501 2.2445,5 5,5 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 305 c -2.21506,0 -4,-1.784939 -4,-4 0,-2.215061 1.78494,-4 4,-4 h 7.29297 l -3.14649,3.146484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707032 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z"
- id="path13229"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 355.49219,73.992188 A 0.50004994,0.50004994 0 0 0 355,74.5 v 3.792969 l -2.11914,-2.117188 a 0.50004994,0.50004994 0 0 0 -0.0234,-0.02539 c -10e-4,-0.0015 -0.002,-0.0024 -0.004,-0.0039 a 0.50004994,0.50004994 0 0 0 -0.1875,-0.121093 c -1.78999,-1.727877 -3.76997,-2.331734 -5.85938,-1.875 -2.1873,0.478135 -3.98484,2.053048 -4.77539,4.175781 a 0.50004994,0.50004994 0 1 0 0.9375,0.347656 c 0.67415,-1.810183 2.19925,-3.142137 4.05078,-3.546875 1.87803,-0.410528 3.46011,0.02939 5.12305,1.722656 a 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.0332,0.03125 L 354.29297,79 H 350.5 a 0.50004994,0.50004994 0 1 0 0,1 h 5 a 0.50004994,0.50004994 0 0 0 0.5,-0.5 v -5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.507812 z"
- id="path13235"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 342.49805,81.992188 a 0.50004994,0.50004994 0 0 0 -0.5,0.5 v 5 a 0.50004994,0.50004994 0 1 0 1,0 v -3.792969 l 2.11914,2.11914 a 0.50004994,0.50004994 0 0 0 0.0234,0.02539 l 0.004,0.002 c 7.2e-4,7.3e-4 0.001,0.0012 0.002,0.002 a 0.50004994,0.50004994 0 0 0 0.18555,0.121094 c 1.78998,1.727877 3.76997,2.331734 5.85938,1.875 2.1873,-0.478136 3.98484,-2.053048 4.77539,-4.175781 a 0.50028327,0.50028327 0 1 0 -0.9375,-0.34961 c -0.67415,1.810184 -2.19925,3.14409 -4.05078,3.548829 -1.87804,0.410528 -3.46011,-0.03135 -5.12305,-1.72461 a 0.50004994,0.50004994 0 0 0 -0.004,-0.0039 l -0.0332,-0.03125 -2.11328,-2.115234 h 3.79297 a 0.50004994,0.50004994 0 1 0 0,-1 z"
- id="path13252"
- inkscape:connector-curvature="0" />
<g
id="g12053"
- transform="translate(0.99999815,210)"
- style="fill:#ffffff">
+ transform="translate(0.999998,210)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="Z-12">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 237.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 11,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m -6.02734,6.75 c -0.1137,0.009 -0.21981,0.0605 -0.29688,0.14453 l -3,3.25 c -0.16377,0.17723 -0.15861,0.45209 0.0117,0.62305 l 3,3 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 3,-3 c 0.17031,-0.17096 0.17547,-0.44582 0.0117,-0.62305 l -3,-3.25 c -0.0927,-0.10101 -0.22649,-0.15422 -0.36328,-0.14453 z m 0.0332,1.11133 2.37695,2.57617 -2.37695,2.375 -2.37695,-2.37695 z"
id="path12048"
inkscape:connector-curvature="0"
@@ -8378,3138 +9142,3375 @@
sodipodi:nodetypes="ccccccccc" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g23466"
- transform="translate(-1.8536743e-6,-0.999995)">
+ transform="translate(-274.031,440)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g13513"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="Z-11">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 10.482422,494 c -0.189602,0.007 -0.359053,0.12023 -0.4375,0.29297 l -3.7734376,8.25 c -0.00134,0.003 -0.00264,0.007 -0.00391,0.01 C 6.1587525,502.80633 6,503.10119 6,503.5 c 0,0.83813 0.5261723,1.53471 1.296875,1.92188 0.7707027,0.38715 1.7901254,0.55582 3.023437,0.57226 0.295371,0.003 0.52928,-0.24867 0.503907,-0.54297 9.47e-4,0.0108 -0.01109,-0.37852 -0.01563,-0.70898 -0.0045,-0.33047 -0.0078,-0.6698 -0.0078,-0.74219 0,-1.86768 1.015625,-3.51914 2.519531,-4.4375 0.228366,-0.13928 0.306682,-0.43361 0.177735,-0.66797 L 10.9375,494.25781 C 10.846425,494.09307 10.670549,493.99343 10.482422,494 Z M 18,494 c -1.098638,0 -1.999999,0.90136 -2,2 1e-6,1.09864 0.901362,2 2,2 1.098638,0 1.999999,-0.90136 2,-2 -1e-6,-1.09864 -0.901362,-2 -2,-2 z m -2,6 c -2.203217,0 -3.999999,1.79678 -4,4 10e-7,2.20322 1.796783,4 4,4 2.203217,0 3.999999,-1.79678 4,-4 -1e-6,-2.20322 -1.796783,-4 -4,-4 z m 0,1 c 1.662777,0 2.999999,1.33722 3,3 -1e-6,1.66278 -1.337223,3 -3,3 -1.662777,0 -2.999999,-1.33722 -3,-3 10e-7,-1.66278 1.337223,-3 3,-3 z m -0.541016,1.0332 C 14.658737,502.0332 14,502.69389 14,503.49414 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.25981 0.199172,-0.46094 0.458984,-0.46094 a 0.50005,0.50005 0 1 0 0,-1 z"
- transform="translate(1.8536743e-6,0.999995)"
- id="path10645"
+ style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.755428px;marker:none;enable-background:accumulate"
+ d="m 220.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9.64062 a 1.8365096,2.6222708 64.987834 0 0 -1.98242,0.0723 1.8365096,2.6222708 64.987834 0 0 -1.9707,2.68555 1.8365096,2.6222708 64.987834 0 0 2.93554,0.88867 1.8365096,2.6222708 64.987834 0 0 2.00977,-2.18945 A 0.50005,0.50005 0 0 0 221,547.5 V 547.47461 538 h 8 v 7.14062 a 1.8365125,2.6222911 64.988434 0 0 -1.98242,0.0723 1.8365125,2.6222911 64.988434 0 0 -1.9707,2.68555 1.8365125,2.6222911 64.988434 0 0 2.93554,0.88867 1.8365125,2.6222911 64.988434 0 0 2.00977,-2.18945 A 0.50005,0.50005 0 0 0 230,546.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ transform="translate(274.031,-440)"
+ id="ellipse13504"
inkscape:connector-curvature="0" />
</g>
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.70000005;marker:none;enable-background:accumulate"
- id="rect12082"
- width="16"
- height="16"
- x="26"
- y="136"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14497">
+ transform="translate(-1602.05,188)"
+ style="display:inline;enable-background:new"
+ id="g26614"
+ inkscape:label="Z-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 324.60938,536 C 323.75288,536 323,536.6483 323,537.5 v 3 c 0,0.8517 0.75288,1.5 1.60938,1.5 h 4.78124 C 330.24712,542 331,541.3517 331,540.5 v -3 c 0,-0.8517 -0.75287,-1.5 -1.60938,-1.5 z M 332,537 v 3 c 0.56267,0 1,-0.50398 1,-1.03125 v -0.9375 C 333,537.50408 332.56269,537 332,537 Z m -7.53516,3 a 0.50005,0.50005 0 0 1 0.0352,0 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50030966,0.50030966 0 0 1 -0.0352,-1 z m -1.85546,4 C 321.75288,544 321,544.6483 321,545.5 v 3 c 0,0.8517 0.75288,1.5 1.60938,1.5 h 4.78124 C 328.24712,550 329,549.3517 329,548.5 v -3 c 0,-0.8517 -0.75287,-1.5 -1.60938,-1.5 z M 330,546 v 3 c 0.56267,0 1,-0.50398 1,-1.03125 v -0.9375 C 331,546.50408 330.56269,546 330,546 Z m -7.53516,2 a 0.50005,0.50005 0 0 1 0.0352,0 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50030966,0.50030966 0 0 1 -0.0352,-1 z"
- transform="translate(1.8536743e-6,-4.4999696e-6)"
- id="rect12085"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1796.5,348 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5.5 h 1 v -5 h 2 v -1 z m 7.5,0 v 1 h 7 v 5 h 1 v -5.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -8,11 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v -1 h -2 v -2 z m 15,0 v 2 h -7 v 1 h 7.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 359 Z"
+ id="path33581"
inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="cccccccccc"
+ id="path33583"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 1800,348 h 3 v 14 h -3 z m -4,7 h 16 v 3 h -16 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-1141,-748)"
+ id="g17971-7"
+ inkscape:label="Z-9">
<g
- transform="translate(0,231)"
- style="opacity:1;fill:#ffffff"
- id="g12112">
+ style="fill:#ffffff"
+ transform="translate(62,59)"
+ id="g17967-7">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 332.5,307 v 1 c 0.55917,0 0.9084,0.14278 1.13281,0.36719 C 333.85722,308.5916 334,308.94083 334,309.5 v 5 c 0,0.55917 -0.14278,0.9084 -0.36719,1.13281 C 333.4084,315.85722 333.05917,316 332.5,316 h -2 v 1 h 2 c 0.73927,0 1.38886,-0.20918 1.83984,-0.66016 C 334.79082,315.88886 335,315.23927 335,314.5 v -5 c 0,-0.73927 -0.20918,-1.38886 -0.66016,-1.83984 C 333.88886,307.20918 333.23927,307 332.5,307 Z"
- id="path12102"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccsssssccsssssc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1085.5,1514 c -0.2761,0 -0.5,0.2239 -0.5,0.5 v 13 c 0,0.2761 0.2239,0.5 0.5,0.5 h 0.5 v -2 h 1 v 2 h 9.5 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -13 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 h -9.5 v 2 h -1 v -2 z m 3.5,2 h 6 v 1 h -6 z m -3,1 h 1 v 2 h -1 z m 3,1 h 6 v 1 h -6 z m -3,2 h 1 v 2 h -1 z m 3,0 h 6 v 1 h -6 z m 0,2 h 4 v 1 h -4 z m -3,1 h 1 v 2 h -1 z"
+ transform="translate(169,-289)"
+ id="path17960-2" />
</g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 218.5,472 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m -2,2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 12 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 217 v -1 h 2.50781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 477 H 229 v 2.5 c 0,0.525 -0.14815,0.87861 -0.38477,1.11523 C 228.37862,480.85186 228.02499,481 227.5,481 h -1 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.5 h -4.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 482 h 0.5 c 0.72501,0 1.37138,-0.22683 1.82227,-0.67773 C 229.77315,480.87137 230,480.225 230,479.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 224 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 6 v 1 h -6 z m 4,3 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z"
- id="path12120"
- inkscape:connector-curvature="0" />
<g
- id="g12136"
- transform="translate(21.999998,314.99995)"
- style="fill:#ffffff" />
+ transform="translate(-1162,-873.994)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g17413-4-0"
+ inkscape:label="Z-8">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17404-8-7"
+ transform="translate(1162,873.994)"
+ d="m 164.48438,535.00586 a 0.50005,0.50005 0 0 0 -0.1211,0.0195 l -1.36328,0.3887 0.01,2.03906 1.63085,-0.46679 A 0.50005,0.50005 0 0 0 165,536.50586 v -1 a 0.50005,0.50005 0 0 0 -0.51562,-0.5 z M 162,535.70117 l -2,0.57031 0.01,2.03907 2,-0.57227 z m -3,0.85547 -1.63672,0.46875 A 0.50005,0.50005 0 0 0 157,537.50586 v 1 a 0.50005,0.50005 0 0 0 0.63672,0.48047 l 1.36914,-0.39063 z M 157,542 v 1 l 8.5,0.01 c 0.276,-5e-4 0.4995,-0.224 0.5,-0.5 -5e-4,-0.276 -0.224,-0.4995 -0.5,-0.5 z m -3,2.00586 v 5.49219 c 0,0.2761 0.2239,0.5 0.5,0.5 h 11 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -4.99219 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1315.5078,1411.9922 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1.5 1.5 h -1 z"
+ id="path17409-0-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g27719"
+ inkscape:label="Z-7"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 134.49999,536.00009 c -1.3764,0 -2.5,1.1236 -2.5,2.5 v 7 c 0,1.3764 1.1236,2.5 2.5,2.5 h 0.5 v 2.5 c -8e-4,0.4686 0.5855,0.6809 0.8848,0.3203 l 2.3496,-2.8203 h 5.2656 c 1.3764,0 2.5,-1.1236 2.5,-2.5 v -7 c 0,-1.3764 -1.1236,-2.5 -2.5,-2.5 z m 3.5,2 h 2 v 2 h -2 z m -1,3 h 3 v 4 h 1 v 1 h -4 v -1 h 1 v -3 h -1 z"
+ id="path17991-2" />
+ </g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12254"
- transform="translate(-21.000002,-20.999995)"
+ id="g13993"
+ transform="translate(-21,-20.9999)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="Z-6">
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
- d="m 75,599 v 2 h 1 v -2 z m 3,0 v 1 h 2 v -1 z m 4,0 v 2 h 1 v -2 z m -6,3 c -2.197587,0 -4,1.80241 -4,4 0,0.91965 0.327327,1.75942 0.855469,2.4375 l -3.708985,3.70898 a 0.50005001,0.50005001 0 1 0 0.707032,0.70704 L 73.5625,609.14453 C 74.240452,609.67231 75.080704,610 76,610 c 2.197595,0 3.998047,-1.80241 3.998047,-4 0,-2.19759 -1.800452,-4 -3.998047,-4 z m 6,1 v 2 h 1 v -2 z m -6,0.002 c 1.652136,0 3,1.34592 3,2.99805 0,1.65213 -1.347864,3 -3,3 -1.652128,0 -3,-1.34787 -3,-3 0,-1.65214 1.347872,-2.99805 3,-2.99805 z M 82,607 v 2 h 1 v -2 z m -7,4 v 2 h 1 v -2 z m 7,0 v 2 h 1 v -2 z m -4,1 v 1 h 2 v -1 z"
- transform="translate(21.000002,20.999995)"
- id="rect12197"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 132.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 1 0 -1,0 v 7.5 h -12 v -12 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path13936"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.25;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 96,620 v 3.5 h 1 V 621 h 6 v 12 h -6 v -2.25 H 96 V 634 h 8 v -14 z"
- id="rect12222"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ccsssssssssssssccc"
+ inkscape:connector-curvature="0"
+ id="path12191-1"
+ d="m 136.5,557 c -0.25,0 -0.5,0.25 -0.5,0.5 v 5.5 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 3.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 562 c 0,-0.55228 0.44772,-1 1,-1 h 0.5 c 0.85547,0 1.5,-0.66406 1.5,-1.5 v -2 c 0,-0.25 -0.25,-0.5 -0.5,-0.5 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
</g>
<g
- id="g5759"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-273,442)"
+ id="g28092-0-4"
+ inkscape:label="Z-5">
<path
- id="path12148"
- d="m 161.5,578 c -3.02272,0 -5.5,2.47726 -5.5,5.5 0,1.3328 0.48165,2.55856 1.2793,3.51367 l -4.13282,4.13281 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 4.13281,-4.13282 C 158.94144,588.51835 160.1672,589 161.5,589 c 3.02273,0 5.5,-2.47727 5.5,-5.5 0,-3.02274 -2.47727,-5.5 -5.5,-5.5 z m 0,1 c 2.47727,0 4.5,2.02272 4.5,4.5 0,2.47727 -2.02273,4.5 -4.5,4.5 -2.47726,0 -4.5,-2.02273 -4.5,-4.5 0,-2.47728 2.02274,-4.5 4.5,-4.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ id="path28072-2-7"
+ d="m 363.5,95 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 99 h 14 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 368 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- sodipodi:nodetypes="ccccscccccccccccccsccc"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 363.5,100 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="rect28074-9-1"
inkscape:connector-curvature="0"
- id="path12161"
- d="m 159.5,583 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.2168 c -2.1e-4,0.14132 0.0594,0.27613 0.16406,0.37109 0.61652,0.55704 1.43526,0.91211 2.33594,0.91211 0.90068,0 1.71942,-0.35507 2.33594,-0.91211 0.10467,-0.095 0.16427,-0.22977 0.16406,-0.37109 V 583.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.97266,6.91992 c -0.2654,0.0146 -0.47303,0.2342 -0.47266,0.5 V 591.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.08008 c -4.1e-4,-0.30465 -0.27082,-0.53814 -0.57227,-0.49414 -0.31225,0.0453 -0.61944,0.0742 -0.92773,0.0742 -0.30829,0 -0.61548,-0.0289 -0.92773,-0.0742 -0.0329,-0.005 -0.0663,-0.007 -0.0996,-0.006 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ <g
+ id="g27725"
+ inkscape:label="Z-4"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 71.5,536 c -1.3819,0 -2.5,1.1181 -2.5,2.5 v 1 c 0,1.3818 1.118,2.5 2.5,2.5 h 9 c 1.382,0 2.5,-1.1182 2.5,-2.5 v -1 c 0,-1.3857 -1.13452,-2.48443 -2.51172,-2.48633 z m 3.5,1.00586 5.48633,0.008 c 0.8628,0 1.51367,0.63203 1.51367,1.48633 v 1 c 0,0.8578 -0.642,1.5 -1.5,1.5 H 75 Z M 71.5,544 c -1.3819,0 -2.5,1.1181 -2.5,2.5 v 1 c 0,1.3818 1.118,2.5 2.5,2.5 h 9 c 1.382,0 2.5,-1.1182 2.5,-2.5 v -1 c 0,-1.3857 -1.13452,-2.48443 -2.51172,-2.48633 z m 6.50977,1.00977 2.47656,0.004 c 0.8628,0 1.51367,0.63203 1.51367,1.48633 v 1 c 0,0.8578 -0.642,1.5 -1.5,1.5 H 78 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path18055-4" />
</g>
<g
+ id="g7579"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12207"
- transform="translate(20.999998,4.4999696e-6)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:label="Z-3">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 223.5,578 c -3.57273,0 -6.5,2.92727 -6.5,6.5 0,1.60752 0.59683,3.08042 1.57422,4.21875 l -2.42774,2.42773 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.42578,-2.42579 c 1.13822,0.977 2.61355,1.57227 4.2207,1.57227 3.57273,0 6.5,-2.92728 6.5,-6.5 0,-3.57273 -2.92727,-6.5 -6.5,-6.5 z m 0,1 c 3.02727,0 5.5,2.47272 5.5,5.5 0,3.02727 -2.47273,5.5 -5.5,5.5 -3.02727,0 -5.5,-2.47273 -5.5,-5.5 0,-3.02728 2.47273,-5.5 5.5,-5.5 z m -3,5 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 z"
- transform="translate(-20.999998,-4.4999696e-6)"
- id="path12193"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 48.499998,536.00001 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 4 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 7,6 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0,5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="rect5843"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 50,540 v 8.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 54 v -1 h -3 v -4 h 3 v -1 h -3 v -3 z"
+ id="path5849"
inkscape:connector-curvature="0" />
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(61.94871,1.10183)"
- id="g12200" />
- <rect
- y="577.04999"
- x="193.95"
- height="16"
- width="16"
- id="rect12202"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
</g>
<g
+ id="g6733"
+ transform="translate(-42,503.9)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12222"
- transform="rotate(-180,422.50583,500.99795)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="Z-2">
+ <rect
+ ry="0"
+ rx="0"
+ y="31"
+ x="68"
+ height="16"
+ width="16"
+ id="rect4338"
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 81.75,32.099609 c -1.433114,0 -2.573994,0.599965 -3.328125,1.414063 -0.754131,0.814098 -1.193245,1.779187 -1.615234,2.65039 -0.42199,0.871204 -0.825206,1.64712 -1.308594,2.146485 -0.483388,0.499365 -0.99066,0.789062 -1.998047,0.789062 H 69 v 2 h 4.5 c 1.476988,0 2.648427,-0.585302 3.435547,-1.398437 0.78712,-0.813135 1.246208,-1.787219 1.671875,-2.666016 0.425667,-0.878796 0.819561,-1.663707 1.28125,-2.162109 0.461689,-0.498402 0.919442,-0.773438 1.861328,-0.773438 H 83 v -2 z"
+ id="path4336"
+ inkscape:connector-curvature="0" />
<g
- id="g23057"
- style="opacity:1;fill:#ffffff">
+ id="g23052"
+ style="opacity:0.7;fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 415.99805,494 c -0.46823,5.5e-4 -0.93866,0.108 -1.3711,0.32422 l -6.83789,3.39453 a 0.50005,0.50005 0 0 0 -0.0273,0.0137 c -2.00082,1.15513 -3.06722,3.4434 -2.66602,5.71875 0.40121,2.27536 2.18559,4.05973 4.46094,4.46094 0.56884,0.1003 1.13889,0.11012 1.69141,0.0352 1.65755,-0.22472 3.1599,-1.20077 4.02734,-2.70313 a 0.50005,0.50005 0 0 0 0.0156,-0.0293 l 3.38476,-6.84179 c 0.57659,-1.15316 0.3761,-2.57898 -0.54687,-3.50196 -0.57687,-0.57686 -1.35049,-0.872 -2.13086,-0.87109 z m 0.3125,1.02539 c 0.41467,0.0623 0.80824,0.24966 1.11133,0.55273 0.60613,0.60614 0.74722,1.57588 0.36132,2.34766 a 0.50005,0.50005 0 0 0 -0.002,0.002 l -3.375,6.82032 c -0.9493,1.63933 -2.81295,2.50814 -4.67578,2.17968 -1.86473,-0.3288 -3.32159,-1.78565 -3.65039,-3.65039 -0.3288,-1.86473 0.54196,-3.7311 2.18164,-4.67773 l 6.81055,-3.38086 a 0.50005,0.50005 0 0 0 0.002,0 c 0.38589,-0.19295 0.82165,-0.25567 1.23633,-0.19336 z m -0.29883,0.9707 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -5.5,3 c -1.92707,0 -3.5,1.57293 -3.5,3.5 0,1.92707 1.57293,3.5 3.5,3.5 1.92707,0 3.5,-1.57293 3.5,-3.5 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1.97461 a 1.4874268,1.5 0 0 1 1.48828,1.5 1.4874268,1.5 0 0 1 -1.48828,1.5 1.4874268,1.5 0 0 1 -1.48828,-1.5 1.4874268,1.5 0 0 1 1.48828,-1.5 z"
- transform="rotate(180,422.50583,500.99795)"
- id="circle12201"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27,536.90039 v 1.19922 h 0.75 c 0.646429,0 1.301953,0.38 1.880859,1.04297 0.578907,0.66296 1.046871,1.58637 1.289063,2.49023 0.207018,0.77346 1.367174,0.46292 1.160156,-0.31054 -0.287808,-1.07411 -0.818828,-2.13723 -1.544922,-2.96875 -0.726093,-0.83153 -1.681585,-1.45313 -2.785156,-1.45313 z m 13.25,9 c -1.91571,0 -2.93215,0.90502 -3.558594,1.66992 -0.313222,0.38245 -0.555819,0.7142 -0.798828,0.91797 -0.243008,0.20377 -0.458964,0.3125 -0.892578,0.3125 -0.401011,0 -0.71548,-0.20341 -1.054688,-0.64648 -0.339207,-0.44308 -0.639641,-1.1033 -0.878906,-1.79492 -0.238226,-0.80225 -1.442094,-0.38505 -1.132812,0.39257 0.260735,0.7537 0.585301,1.5146 1.058594,2.13282 C 33.46548,549.50298 34.151011,550 35,550 c 0.691386,0 1.25668,-0.25378 1.662109,-0.59375 0.405429,-0.33997 0.678457,-0.73364 0.958985,-1.07617 0.561056,-0.68506 1.044616,-1.23047 2.628906,-1.23047 H 41 v -1.19922 z"
+ transform="translate(42,-503.9)"
+ id="path4334"
inkscape:connector-curvature="0" />
</g>
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- id="g13413"
+ transform="translate(-1.85541e-6,5.18e-5)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13451"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
- style="display:inline;fill:#ffffff;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 475.5,579 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z m 0,5 c -0.82252,0 -1.5,0.67748 -1.5,1.5 0,0.82252 0.67748,1.5 1.5,1.5 0.82252,0 1.5,-0.67748 1.5,-1.5 0,-0.82252 -0.67748,-1.5 -1.5,-1.5 z"
- id="ellipse12367"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssssssssssssss" />
- </g>
- <g
- id="g12575"
- transform="matrix(0.8666665,0,0,0.8666665,-253.07368,16.407198)"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384638;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:label="Z-1">
+ <g
+ id="g23046"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="opacity:0.99;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 16.501953,536 c -1.926262,0 -3.498047,1.57178 -3.498047,3.49805 0,1.92626 1.571785,3.49804 3.498047,3.49804 C 18.428216,542.99609 20,541.42431 20,539.49805 20,537.57178 18.428216,536 16.501953,536 Z m 0,0.99609 a 0.50005,0.50005 0 1 1 0,1 C 15.666793,537.99609 15,538.66288 15,539.49805 a 0.50005,0.50005 0 1 1 -1,0 c 0,-1.37561 1.126353,-2.50196 2.501953,-2.50196 z"
+ transform="translate(1.85541e-6,-5.18e-5)"
+ id="circle12697"
+ inkscape:connector-curvature="0" />
+ </g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 285.49219,388.99219 c -0.2763,0.004 -0.49651,0.23152 -0.49219,0.50781 v 2.6543 c -0.76567,0.19832 -1.43883,0.61396 -1.95508,1.18359 l -2.1914,-2.19141 c -0.0944,-0.0966 -0.22433,-0.15264 -0.35938,-0.15234 -0.4485,2.4e-4 -0.66889,0.54638 -0.34766,0.85938 l 2.32032,2.32031 C 282.17933,394.72335 282.0013,395.33918 282,396 h -2.5 c -0.66693,0 -0.66693,1 0,1 h 2.64062 c 0.19916,0.76891 0.61811,1.44388 1.19141,1.96094 l -2.18555,2.18554 c -0.4717,0.4717 0.23534,1.17874 0.70704,0.70704 l 2.3164,-2.31641 c 0.54947,0.28561 1.16223,0.46289 1.82227,0.46289 0.003,0 0.005,10e-6 0.008,0 v 2.5 c 0,0.66693 1,0.66693 1,0 v -2.64648 c 0.76569,-0.20169 1.4388,-0.6203 1.95312,-1.19336 l 2.19336,2.19336 c 0.47143,0.50593 1.2141,-0.23683 0.70704,-0.70704 l -2.32422,-2.32421 c 0.28283,-0.54738 0.45703,-1.15786 0.45703,-1.81446 0,-0.003 0,-0.005 0,-0.008 H 292.5 c 0.66693,0 0.66693,-1 0,-1 h -2.66016 c -0.20083,-0.76245 -0.61615,-1.43374 -1.18554,-1.94727 l 2.19922,-2.19921 c 0.32695,-0.31816 0.0927,-0.87325 -0.36329,-0.85938 -0.12999,0.004 -0.25338,0.0589 -0.34375,0.15234 l -2.33007,2.33008 C 287.26914,392.1921 286.6571,392.01496 286,392.01367 V 389.5 c 0.004,-0.28226 -0.22555,-0.51222 -0.50781,-0.50781 z m 0.5,4.02148 c 1.65884,0 2.99414,1.3353 2.99414,2.99414 0,1.65885 -1.3353,2.99219 -2.99414,2.99219 C 284.33334,399 283,397.66666 283,396.00781 c 0,-1.65884 1.33334,-2.99414 2.99219,-2.99414 z"
- transform="matrix(1.1538464,0,0,1.1538464,292.00815,-18.931386)"
- id="circle12556"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 10.503906,539.99219 a 0.50005,0.50005 0 0 0 -0.492187,0.39843 L 9.6542969,542 H 7.5 a 0.50005,0.50005 0 1 0 0,1 H 9.4316406 L 8.765625,546 H 6.5 a 0.50005,0.50005 0 1 0 0,1 h 2.0429688 l -0.53125,2.39062 a 0.50038237,0.50038237 0 1 0 0.9765624,0.21876 L 9.5683594,547 H 16.53125 l 0.476562,2.58984 a 0.50032015,0.50032015 0 1 0 0.984376,-0.17968 L 17.546875,547 H 19.5 a 0.50005,0.50005 0 1 0 0,-1 H 17.363281 L 17.0625,544.37109 a 0.50005,0.50005 0 1 0 -0.982422,0.18164 L 16.345703,546 H 9.7910156 l 0.6660154,-3 H 12.5 a 0.50005,0.50005 0 1 0 0,-1 h -1.820312 l 0.308593,-1.39062 a 0.50005,0.50005 0 0 0 -0.484375,-0.61719 z"
+ id="path8399"
inkscape:connector-curvature="0" />
</g>
<g
- id="g6143"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14371"
+ transform="matrix(1,0,0,-1,336,494)"
+ inkscape:label="Y-25">
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g12901"
- transform="matrix(-0.79928788,0,0,0.79928788,828.43189,282.2677)"
- style="display:inline;opacity:0.7;fill:#ffffff;stroke-width:1.25111365;enable-background:new">
+ transform="matrix(1,0,0,-1,0,-99.005)"
+ id="g14352"
+ style="fill:#ffffff">
<path
- id="path12894"
- transform="matrix(-1.2511137,0,0,1.2511137,1036.4625,-353.14898)"
- d="m 535.49805,458.00391 a 0.50004999,0.50004999 0 0 0 -0.50391,0.50781 l 0.002,1.33984 c -0.37236,0.0723 -0.71902,0.21977 -1.02148,0.42774 l -1.12695,-1.12305 a 0.50004999,0.50004999 0 0 0 -0.3418,-0.15039 0.50004999,0.50004999 0 0 0 -0.36328,0.85742 l 1.12695,1.12305 c -0.20781,0.30095 -0.35637,0.64504 -0.42969,1.01562 l -1.3457,0.004 a 0.50033487,0.50033487 0 0 0 0.002,1 l 1.33789,-0.002 c 0.0677,0.37781 0.20888,0.73164 0.41602,1.03906 l -1.10742,1.10937 a 0.50004999,0.50004999 0 1 0 0.70508,0.70508 l 1.10351,-1.10156 c 0.30838,0.21694 0.66219,0.37111 1.04492,0.44531 l -0.002,1.30078 a 0.50033678,0.50033678 0 1 0 1,0.004 l 0.002,-1.30274 c 0.3865,-0.0701 0.74651,-0.21619 1.0586,-0.43164 l 1.08203,1.08594 a 0.50005719,0.50005719 0 1 0 0.70703,-0.70508 l -1.08398,-1.08984 c 0.21441,-0.31231 0.36249,-0.67226 0.43164,-1.05859 h 1.30664 a 0.50098,0.50098 0 1 0 0,-1.00196 h -1.3125 c -0.0748,-0.37855 -0.23067,-0.72769 -0.44532,-1.0332 l 1.10352,-1.10547 a 0.50004999,0.50004999 0 0 0 -0.34961,-0.85937 0.50004999,0.50004999 0 0 0 -0.35742,0.15234 l -1.10938,1.10742 c -0.30548,-0.20557 -0.65624,-0.346 -1.03125,-0.41406 l -0.004,-1.33984 a 0.50004999,0.50004999 0 0 0 -0.49219,-0.50586 0.50004999,0.50004999 0 0 1 -0.002,0 z m -0.002,3.29882 c 0.66274,0 1.20117,0.53844 1.20118,1.20118 0,0.66273 -0.53844,1.19921 -1.20118,1.19921 -0.66273,0 -1.19921,-0.53648 -1.19921,-1.19921 0,-0.66273 0.53648,-1.20117 1.19921,-1.20118 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 520.49414,515 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 2.64649,2.64648 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 520.49414,515 Z m 0.0332,2.99414 a 0.50005,0.50005 0 0 0 -0.14843,0.0215 l -1,0.25 a 0.50005,0.50005 0 0 0 0.0937,0.98633 0.50005,0.50005 0 0 0 0.14843,-0.0176 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.99024 z m -3,0.75 a 0.50005,0.50005 0 0 0 -0.14843,0.0215 l -1,0.25 a 0.50005,0.50005 0 0 0 0.0937,0.98633 0.50005,0.50005 0 0 0 0.14843,-0.0176 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.99024 z m -3.02343,1.24805 a 0.50005,0.50005 0 0 0 -0.35743,0.15429 l -1,1 a 0.50005,0.50005 0 0 0 0.34766,0.85938 0.50005,0.50005 0 0 0 0.35938,-0.15234 l 1,-1 a 0.50005,0.50005 0 0 0 -0.34961,-0.86133 z m -1.9961,3 A 0.50005,0.50005 0 0 0 512,523.5 v 1 a 0.50005,0.50005 0 0 0 0.49219,0.50781 A 0.50005,0.50005 0 0 0 513,524.5 v -1 a 0.50005,0.50005 0 0 0 -0.49219,-0.50781 z"
+ transform="translate(-336,-593.005)"
+ id="path14350"
inkscape:connector-curvature="0" />
</g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 176.5,-32 c 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 z"
+ id="circle14357"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,677,550)"
+ id="g14389"
+ inkscape:label="Y-24">
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.25111365;enable-background:new"
- transform="matrix(-0.79928788,0,0,0.79928788,833.43189,275.2677)"
- id="g12909">
+ id="g14381"
+ transform="matrix(1,0,0,-1,0,-99.005)"
+ style="fill:#ffffff">
<path
- id="path12903"
- transform="matrix(-1.2511137,0,0,1.2511137,1042.718,-344.39118)"
- d="m 540.49805,451.00391 a 0.50004999,0.50004999 0 0 0 -0.50391,0.50781 l 0.002,1.33984 c -0.37236,0.0723 -0.71902,0.21977 -1.02148,0.42774 l -1.12695,-1.12305 a 0.50004999,0.50004999 0 0 0 -0.3418,-0.15039 0.50004999,0.50004999 0 0 0 -0.36328,0.85742 l 1.12695,1.12305 c -0.20781,0.30095 -0.35637,0.64503 -0.42969,1.01562 l -1.3457,0.004 a 0.50033487,0.50033487 0 0 0 0.002,1 l 1.33789,-0.002 c 0.0677,0.37781 0.20888,0.73164 0.41602,1.03906 l -1.10742,1.10937 a 0.50004999,0.50004999 0 1 0 0.70508,0.70508 l 1.10351,-1.10156 c 0.30838,0.21694 0.66219,0.37111 1.04492,0.44531 l -0.002,1.30078 a 0.50033678,0.50033678 0 1 0 1,0.004 l 0.002,-1.30274 c 0.386,-0.07 0.74484,-0.21858 1.05664,-0.43359 l 1.08399,1.08789 a 0.50005719,0.50005719 0 1 0 0.70703,-0.70508 l -1.08398,-1.08984 c 0.21441,-0.31231 0.36249,-0.67226 0.43164,-1.05859 h 1.30664 a 0.50098,0.50098 0 1 0 0,-1.00196 h -1.3125 c -0.0748,-0.37855 -0.23067,-0.72769 -0.44532,-1.0332 l 1.10352,-1.10547 a 0.50004999,0.50004999 0 0 0 -0.34961,-0.85937 0.50004999,0.50004999 0 0 0 -0.35742,0.15234 l -1.10938,1.10742 c -0.30548,-0.20557 -0.65624,-0.346 -1.03125,-0.41406 l -0.004,-1.33984 a 0.50004999,0.50004999 0 0 0 -0.49219,-0.50586 0.50004999,0.50004999 0 0 1 -0.002,0 z m -0.002,3.29882 c 0.66274,0 1.20117,0.53844 1.20118,1.20118 0,0.66273 -0.53844,1.19921 -1.20118,1.19921 -0.66273,0 -1.19921,-0.53648 -1.19921,-1.19921 0,-0.66273 0.53648,-1.20117 1.19921,-1.20118 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 500.50586,518.99219 A 0.50005,0.50005 0 0 0 500,519.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.49219,-0.50781 0.50005,0.50005 0 0 1 -0.002,0 z m -8.00977,2.99609 a 0.50005,0.50005 0 0 0 -0.34961,0.15234 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 0 0 0.35938,0.15234 0.50005,0.50005 0 0 0 0.34766,-0.85938 l -2.64649,-2.64648 2.64649,-2.64648 a 0.50005,0.50005 0 0 0 -0.35743,-0.85938 z m 7.00977,0.006 a 0.50005,0.50005 0 0 0 -0.35938,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.34766,-0.85938 z m -3.0293,2.00391 a 0.50005,0.50005 0 0 0 -0.0976,0.0176 l -1,0.25 a 0.50005,0.50005 0 1 0 0.24218,0.96876 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.98633 0.50005,0.50005 0 0 0 -0.0508,0 z m -3,0.75 a 0.50005,0.50005 0 0 0 -0.0976,0.0176 l -1,0.25 a 0.50005,0.50005 0 1 0 0.24218,0.96876 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.98633 0.50005,0.50005 0 0 0 -0.0508,0 z"
+ transform="rotate(180,338.5,225.4975)"
+ id="path14379"
inkscape:connector-curvature="0" />
</g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 176.5,-32 c 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 z"
+ id="circle14385"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12259"
- transform="matrix(0,-1,-1,0,312,-85.999995)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g14048"
+ transform="translate(294,571)"
+ inkscape:label="Y-23">
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="rotate(90,-175.5,-141.5)"
- id="g12255"
- mask="none">
+ transform="matrix(-0.53033,-0.53033,-0.53033,0.53033,472.858,-15.2358)"
+ id="g13853"
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 237.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path12253"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 306.99023,243.60938 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 4.99023 h -4.99023 a 0.666995,0.666995 0 1 0 0,1.33399 h 4.99023 v 4.99023 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -4.99023 h 4.99023 a 0.666995,0.666995 0 1 0 0,-1.33399 h -4.99023 v -4.99023 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
+ id="path13850"
+ inkscape:connector-curvature="0" />
</g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -614.5,272 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.50781 v 5 H -614.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 284 h 5 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.49219 v -3.5 a 0.50005,0.50005 0 1 0 -1,0 V 281 H -605.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -5 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.49219 v -5 H -611.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 274 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 h -3.5 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -1.41406 a 0.50005,0.50005 0 0 0 -0.16016,0 H -614 Z m 0,9 h 2 v 2 h -2 z m 9,0 h 2 v 2 h -2 z"
- id="path12257"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 177.49219,-56.007812 A 0.50005,0.50005 0 0 0 177,-55.5 v 6 a 0.50005,0.50005 0 1 0 1,0 V -52 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 178 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 7.00195,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.707032 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z M 180.5,-53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path13907"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12585"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96"
- transform="matrix(-1,0,0,1,782,4.4999696e-6)">
+ id="g14223"
+ transform="rotate(180,317.495,236.5015)"
+ inkscape:label="Y-22">
+ <g
+ style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g14219"
+ transform="matrix(-0.53033,-0.53033,-0.53033,0.53033,472.858,-15.2358)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 306.99023,243.60938 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 4.99023 h -4.99023 a 0.666995,0.666995 0 1 0 0,1.33399 h 4.99023 v 4.99023 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -4.99023 h 4.99023 a 0.666995,0.666995 0 1 0 0,-1.33399 h -4.99023 v -4.99023 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
+ id="path14217"
+ inkscape:connector-curvature="0" />
+ </g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 387.53125,473 C 386.69103,473 386,473.69103 386,474.53125 V 475 h -0.5 c -0.84022,0 -1.5,0.70952 -1.5,1.53125 v 0.9375 c 0,0.82173 0.65978,1.53125 1.5,1.53125 h 0.96875 c 0.1915,0 0.40039,-0.14519 0.61133,-0.21289 l 0.3164,0.31641 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.5,-0.5 a 0.50005,0.50005 0 0 0 -0.70704,0 C 386.86607,477.9269 386.67628,478 386.46875,478 H 385.5 c -0.28602,0 -0.5,-0.22674 -0.5,-0.53125 v -0.9375 C 385,476.22674 385.21398,476 385.5,476 h 0.96875 c 0.02,0 0.0255,2.9e-4 0.0156,0 A 0.50005,0.50005 0 0 0 387,475.48438 c 2.9e-4,0.01 0,0.004 0,-0.0156 v -0.9375 C 387,474.24523 387.24523,474 387.53125,474 h 0.9375 c 0.28603,0 0.53125,0.24521 0.53125,0.53125 v 0.9375 c 0,0.20745 -0.0731,0.39731 -0.10352,0.42773 a 0.50005,0.50005 0 0 0 0,0.70704 l 0.5,0.5 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.31641,-0.3164 C 389.85483,475.86914 390,475.66029 390,475.46875 v -0.9375 C 390,473.69101 389.30896,473 388.46875,473 Z m 6.71289,7.74414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.5,0.5 a 0.50005,0.50005 0 0 0 0.70704,0 c -0.0536,0.0536 0.0619,-0.0282 0.21093,-0.0586 C 395.46351,482.01449 395.64626,482 395.75,482 h 0.75 c 0.30453,0 0.5,0.19546 0.5,0.5 v 0.9375 c 0,0.30451 -0.23248,0.5625 -0.5,0.5625 h -0.9375 c -0.02,0 -0.0255,-2.9e-4 -0.0156,0 a 0.50005,0.50005 0 0 0 -0.46485,0.2832 0.50005,0.50005 0 0 0 -0.0117,0.0215 c -0.002,0.004 -0.003,0.004 -0.006,0.01 -0.006,0.0121 -0.0155,0.0273 -0.0273,0.0566 -0.006,0.0147 -0.012,0.0324 -0.0195,0.0606 -0.007,0.0281 -0.0176,0.13022 -0.0176,0.13086 V 485.5 c 0,0.28602 -0.24525,0.53126 -0.53125,0.53125 H 393.5 c -0.28602,0 -0.5,-0.22674 -0.5,-0.53125 v -0.9375 c 0,-0.19821 0.0977,-0.45261 0.11133,-0.4668 a 0.50005,0.50005 0 0 0 -0.008,-0.69922 l -0.5,-0.5 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 0.31836,0.31836 C 392.14451,484.14157 392,484.36068 392,484.5625 V 485.5 c 0,0.82173 0.65978,1.53125 1.5,1.53125 h 0.96875 C 395.30899,487.03126 396,486.34022 396,485.5 V 485 h 0.5 c 0.85872,0 1.5,-0.74077 1.5,-1.5625 V 482.5 c 0,-0.82174 -0.67829,-1.5 -1.5,-1.5 h -0.75 c -0.17782,0 -0.40107,0.0167 -0.63477,0.0645 -0.0763,0.0156 -0.15636,0.0877 -0.23437,0.10938 l -0.27734,-0.27735 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path12199"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 177.49219,-56.007812 A 0.50005,0.50005 0 0 0 177,-55.5 v 6 a 0.50005,0.50005 0 1 0 1,0 V -52 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 178 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 7.00195,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.707032 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z M 180.5,-53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14221"
inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 393.5,473 c -0.82416,0 -1.5,0.67974 -1.5,1.5 v 1 c 0,0.42842 0.21502,0.76851 0.50586,1.03711 l -4.96289,4.96484 C 387.27424,481.21375 386.93403,481 386.50781,481 h -1 c -0.82026,0 -1.5,0.67584 -1.5,1.5 0,0.82416 0.67974,1.5 1.5,1.5 h 1 0.5 v 0.5 1 c 0,0.82026 0.67585,1.5 1.5,1.5 0.82416,0 1.5,-0.67975 1.5,-1.5 v -1 c 0,-0.42841 -0.21502,-0.76851 -0.50586,-1.03711 l 4.96289,-4.96484 C 394.73357,478.78626 395.07378,479 395.5,479 h 1 c 0.82026,0 1.5,-0.67584 1.5,-1.5 0,-0.82416 -0.67974,-1.5 -1.5,-1.5 h -1 -0.5 v -0.5 -1 c 0,-0.82026 -0.67584,-1.5 -1.5,-1.5 z"
- id="path12208"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssccsssscccssssccsssscccss" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 388.50781,494 c -0.82415,0 -1.5,0.67974 -1.5,1.5 v 1 0.5 h -0.5 -1 c -0.82026,0 -1.5,0.67584 -1.5,1.5 0,0.82416 0.67974,1.5 1.5,1.5 h 1 c 0.42622,0 0.76643,-0.21374 1.03516,-0.50195 l 4.96289,4.96484 C 392.21502,504.73149 392,505.07159 392,505.5 v 1 c 0,0.82025 0.67584,1.5 1.5,1.5 0.82416,0 1.5,-0.67974 1.5,-1.5 v -1 -0.5 h 0.5 1 c 0.82026,0 1.5,-0.67584 1.5,-1.5 0,-0.82416 -0.67974,-1.5 -1.5,-1.5 h -1 c -0.42622,0 -0.76642,0.21375 -1.03516,0.50195 l -4.96289,-4.96484 c 0.29085,-0.2686 0.50586,-0.60869 0.50586,-1.03711 v -1 c 0,-0.82026 -0.67584,-1.5 -1.5,-1.5 z"
- id="path12213"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sscccssssccsssscccssssccsss" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g12687"
- transform="translate(-1.8536743e-6,42.000005)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g31071"
+ inkscape:label="Y-21"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 313.48633,389.00977 a 0.50005,0.50005 0 0 0 -0.13281,0.0156 l -10.64454,2.70117 a 0.50005,0.50005 0 0 0 -0.0176,0.006 c -0.39202,0.1157 -0.73529,0.32904 -1.00782,0.60156 -0.57977,0.57978 -0.79354,1.4303 -0.73828,2.33399 0.0553,0.90369 0.37679,1.88678 0.94141,2.83789 a 0.50005,0.50005 0 0 0 0,0.002 c 0.0547,0.092 0.11038,0.1837 0.16992,0.27539 a 0.50056694,0.50056694 0 1 0 0.83984,-0.54492 c -0.0521,-0.0802 -0.10227,-0.16121 -0.15039,-0.24219 -0.4939,-0.83198 -0.75942,-1.68043 -0.80273,-2.38867 -0.0433,-0.70823 0.13039,-1.24953 0.44726,-1.5664 0.16272,-0.16272 0.36207,-0.28412 0.58399,-0.34961 l 9.81055,-2.49024 -2.49024,9.81445 c -0.0654,0.2249 -0.18247,0.41294 -0.34961,0.58008 -0.32315,0.32316 -0.90925,0.49604 -1.67187,0.42578 -0.76263,-0.0702 -1.66859,-0.38268 -2.52735,-0.93164 a 0.50005,0.50005 0 1 0 -0.53906,0.8418 c 0.97998,0.62645 2.02029,0.99785 2.97656,1.08594 0.95627,0.0881 1.86106,-0.10716 2.46875,-0.71485 0.27194,-0.27193 0.4884,-0.61189 0.60352,-1.00781 a 0.50005,0.50005 0 0 0 0.004,-0.0176 l 2.70117,-10.64453 a 0.50005,0.50005 0 0 0 -0.47461,-0.62304 z M 308,393.99414 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0352,0.25586 l -0.88868,0.88867 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 0.88671,-0.88672 a 1,1 0 0 0 0.25977,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -3.50977,3.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.3418,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70704,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
- transform="translate(1.8536743e-6,-42.000005)"
- id="path7527-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 426.49214,518.99219 A 0.50005,0.50005 0 0 0 425.99995,519.5 v 6 a 0.50005,0.50005 0 1 0 1,0 v -2.92578 a 0.50005,0.50005 0 0 0 0.5,0.41797 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 a 0.50005,0.50005 0 0 0 -0.5,0.42187 V 519.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 438.99995,519.5 v 6 a 0.50005,0.50005 0 1 0 1,0 v -6 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -4.99805,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.85937 l 2.64649,2.64649 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z M 430.49995,522 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path20420"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g12682"
- transform="translate(-1.8536743e-6,42.000005)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g31068"
+ inkscape:label="Y-20"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 325.05469,389.00391 c -0.66782,-0.018 -1.21728,4.6e-4 -1.57813,0.002 h -0.002 c -0.34416,2.5e-4 -0.65424,0.0639 -0.91602,0.22852 -0.2623,0.16491 -0.44433,0.43888 -0.51367,0.7207 -0.13867,0.56363 0.037,1.13654 0.3125,1.76758 0.55094,1.26206 1.63318,2.77176 2.73438,4.10351 a 0.50004997,0.50004997 0 1 0 0.76953,-0.63867 c -1.06758,-1.2911 -2.11546,-2.78301 -2.58789,-3.86523 -0.23622,-0.54112 -0.29509,-0.9754 -0.25782,-1.12696 0.0186,-0.0758 0.0265,-0.0852 0.0742,-0.11523 0.0478,-0.03 0.16614,-0.0742 0.38672,-0.0742 a 0.50004997,0.50004997 0 0 0 0.002,0 c 1.54352,-0.006 5.58742,-0.20164 8.14453,2.35547 2.5571,2.5571 2.35972,6.59906 2.35351,8.14258 a 0.50004997,0.50004997 0 0 0 0,0.002 c 0,0.22058 -0.0442,0.33897 -0.0742,0.38672 -0.03,0.0477 -0.0375,0.0575 -0.11328,0.0762 -0.15155,0.0373 -0.58779,-0.0216 -1.1289,-0.25781 -1.08223,-0.47244 -2.57414,-1.52227 -3.86524,-2.58985 a 0.50015227,0.50015227 0 1 0 -0.63672,0.77149 c 1.33176,1.1012 2.8395,2.18343 4.10157,2.73437 0.63103,0.27547 1.20395,0.45117 1.76757,0.3125 0.28182,-0.0693 0.55774,-0.25136 0.72266,-0.51367 0.16426,-0.26126 0.22607,-0.57268 0.22656,-0.91601 v -0.004 c 0.006,-1.44452 0.29493,-5.9121 -2.64648,-8.85352 -2.20662,-2.20661 -5.27193,-2.59451 -7.27539,-2.64843 z m 3.95117,4.99023 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0332,0.25781 l -0.88672,0.88672 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 0.88671,-0.88672 a 1,1 0 0 0 0.25977,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -3.50977,3.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70899,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
- transform="translate(1.8536743e-6,-42.000005)"
- id="path7537-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 418.50786,518.99219 a 0.50005,0.50005 0 0 1 0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 1 -1,0 v -2.92578 a 0.50005,0.50005 0 0 1 -0.5,0.41797 h -1 a 0.50005,0.50005 0 1 1 0,-1 h 1 a 0.50005,0.50005 0 0 1 0.5,0.42187 V 519.5 a 0.50005,0.50005 0 0 1 0.50781,-0.50781 z m -13,0 a 0.50005,0.50005 0 0 1 0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 1 -1,0 v -6 a 0.50005,0.50005 0 0 1 0.50781,-0.50781 z m 4.99805,0.002 a 0.50005,0.50005 0 0 1 0.34766,0.85937 l -2.64649,2.64649 2.64649,2.64648 a 0.50005,0.50005 0 1 1 -0.70704,0.70703 l -3,-3 a 0.50005,0.50005 0 0 1 0,-0.70703 l 3,-3 a 0.50005,0.50005 0 0 1 0.35938,-0.15234 z M 414.50005,522 a 0.50005,0.50005 0 1 1 0,1 h -1 a 0.50005,0.50005 0 1 1 0,-1 z m -3,0 a 0.50005,0.50005 0 1 1 0,1 h -1 a 0.50005,0.50005 0 1 1 0,-1 z"
+ id="path14267"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12674"
- transform="translate(-1.8536743e-6,63.000005)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g14377"
+ transform="translate(210,592)"
+ inkscape:label="Y-19">
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
- d="m 343.50586,388.99219 a 0.50005,0.50005 0 0 0 -0.35547,0.14648 l -1.00391,1.00781 a 0.50005,0.50005 0 0 0 -0.0937,0.57618 l 3,6 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -2.83985,-5.67968 0.60547,-0.60547 h 6.4707 l 4.72266,10.39062 -0.60937,0.60938 -5.98633,0.008 -0.35743,-0.72656 a 0.50005,0.50005 0 1 0 -0.89648,0.4414 l 0.49414,1.00586 A 0.50005,0.50005 0 0 0 348,402 l 6.50586,-0.008 a 0.50005,0.50005 0 0 0 0.35352,-0.14649 l 1,-1 a 0.50005,0.50005 0 0 0 0.10156,-0.56054 l -5,-11 a 0.50005,0.50005 0 0 0 -0.45508,-0.29297 z m 5.5,6.00195 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0332,0.25977 l -0.14258,0.14257 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.14453,-0.14454 a 1,1 0 0 0 0.25781,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -2.50977,2.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70899,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
- transform="translate(1.8536743e-6,-63.000005)"
- id="circle12662"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 184.49414,-76.005859 c -0.4494,8.8e-5 -0.67059,0.546839 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 3,-3 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -3,-3 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z M 175.49219,-73 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 5.00781,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m -6,0.0078 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z M 175.49219,-70 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z"
+ id="path14373"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 175.5,-67 c -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 z"
+ id="circle14375"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
</g>
<g
- id="g12707"
- style="display:inline;opacity:0.98999999;fill:#ffffff;stroke-width:1.07692313;enable-background:new"
- transform="matrix(0.92857149,0,0,0.92857137,22.930148,44.290705)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="rotate(180,275.5,225.9975)"
+ id="g14033"
+ inkscape:label="Y-18">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 327.94922,619.99609 c -0.89539,0.0396 -1.29072,1.14622 -0.62305,1.74414 l 1.37305,1.26563 h -6.69727 c -1.36099,-0.0279 -1.36099,2.02794 0,2 h 3.0918 c -0.003,0.002 -0.005,0.004 -0.008,0.006 l -4.75,4.24805 c -0.99479,0.88933 0.33919,2.38151 1.33398,1.49218 l 2.33985,-2.09375 c 0.0823,2.95524 2.51793,5.34766 5.49218,5.34766 3.02565,0 5.49805,-2.47428 5.49805,-5.5 0,-1.56564 -0.6642,-2.98065 -1.72266,-3.98438 l -4.59961,-4.25195 c -0.19597,-0.18575 -0.45872,-0.28437 -0.72851,-0.27344 z m 1.55273,5.00977 c 1.94471,0 3.5,1.5551 3.5,3.5 0,1.94489 -1.55529,3.5 -3.5,3.5 -1.94472,0 -3.5,-1.55511 -3.5,-3.5 0,-1.9449 1.55528,-3.5 3.5,-3.5 z m -0.0176,1.78516 a 1.7319623,1.7139345 0 0 0 -1.73243,1.71484 1.7319623,1.7139345 0 0 0 1.73243,1.71289 1.7319623,1.7139345 0 0 0 1.73242,-1.71289 1.7319623,1.7139345 0 0 0 -1.73242,-1.71484 z"
- transform="matrix(1.076923,0,0,1.0769231,-24.694004,-47.697685)"
- id="path12703"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 184.49414,-76.005859 c -0.4494,8.8e-5 -0.67059,0.546839 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 3,-3 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -3,-3 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z M 175.49219,-73 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 5.00781,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m -6,0.0078 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z M 175.49219,-70 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z"
+ id="path14029"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 175.5,-67 c -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 z"
+ id="circle14031"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
</g>
<g
- transform="translate(-210.00712,-588.00007)"
- id="g12466"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g15557"
+ transform="translate(42)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="Y-17">
<g
- transform="translate(22)"
- id="g12463"
- style="fill:#ffffff">
+ transform="matrix(1,0,0,-1,-42,813.007)"
+ id="g15497"
+ style="display:inline;fill:#ffffff;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 557.5,620 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path12459"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 346,286.00391 c 0,-1.09977 -0.90081,-2.00196 -2,-2.00196 -1.09919,0 -2,0.90219 -2,2.00196 0,1.09976 0.90081,2.0039 2,2.0039 1.09919,0 2,-0.90414 2,-2.0039 z m -1,0 c 0,0.56041 -0.44233,1.0039 -1,1.0039 -0.55767,0 -1,-0.44349 -1,-1.0039 0,-0.56041 0.44233,-1.00196 1,-1.00196 0.55767,0 1,0.44155 1,1.00196 z"
+ id="ellipse15493"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 553.48438,620 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 553,621.70703 V 625.5 a 0.50005,0.50005 0 1 0 1,0 v -5 A 0.50005,0.50005 0 0 0 553.48438,620 Z M 553,628 c -0.79172,0 -1.70536,0.42737 -1.98047,1.35938 a 0.50062501,0.50062501 0 1 0 0.96094,0.28124 C 552.10464,629.21999 552.55814,629 553,629 c 0.31942,0 0.59941,0.0632 0.75391,0.16602 0.1545,0.10279 0.25034,0.21211 0.2539,0.58789 5.6e-4,0.20689 -0.076,0.32805 -0.29687,0.52148 -0.22152,0.19398 -0.57835,0.40234 -0.9668,0.64453 -0.38845,0.24219 -0.81151,0.52364 -1.1543,0.93555 -0.34278,0.4119 -0.58774,0.96871 -0.58984,1.64258 A 0.50005,0.50005 0 0 0 551.5,634 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -2.32227 c 0.0615,-0.1621 0.068,-0.36972 0.17969,-0.50391 0.22282,-0.26775 0.55267,-0.50197 0.91602,-0.72851 0.36335,-0.22654 0.7571,-0.44007 1.09765,-0.73828 0.34056,-0.29822 0.6393,-0.73918 0.63672,-1.28125 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.62417 -0.29003,-1.13985 -0.69922,-1.41211 C 553.89941,628.06173 553.43058,628 553,628 Z"
- id="path12461"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 356,296.00391 c 0,-1.09734 -0.90199,-1.9961 -2,-1.9961 -1.09801,0 -2,0.89876 -2,1.9961 0,1.09733 0.90199,1.99609 2,1.99609 1.09801,0 2,-0.89876 2,-1.99609 z"
+ id="ellipse15495"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
</g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 306.49609,516.00391 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m -2.00976,0.99414 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85937 z m -1.00195,3 a 0.50005,0.50005 0 0 0 -0.34766,0.85937 l 1,1 a 0.50005,0.50005 0 1 0 0.70703,-0.70703 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35937,-0.15234 z m 3.01171,2.00586 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 2.9961,0.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85937 l 1,1 a 0.50005,0.50005 0 1 0 0.70703,-0.70703 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35742,-0.15234 z m 0.99414,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85937 z m -4.9961,1.00586 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path15483-4"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- id="g21139"
- style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
+ transform="translate(-0.0299934)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14346"
+ inkscape:label="Y-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 412,179 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
- id="path12522"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 184.27734,515 c -0.3909,-0.007 -0.822,0.0708 -1.2832,0.25781 -1.22985,0.49878 -2.7569,1.66874 -4.85742,3.90039 -2.09205,2.22266 -3.24657,3.73559 -3.77539,4.91602 -0.26441,0.59022 -0.37396,1.11195 -0.31641,1.58984 0.0576,0.4779 0.29454,0.88243 0.60156,1.18946 0.013,0.0131 0.0267,0.0255 0.041,0.0371 l 2.5,2 c 0.49277,0.39559 1.11361,-0.29808 0.66602,-0.74414 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.97657,-1.9746 c -0.008,-0.009 -0.0153,-0.0172 -0.0234,-0.0254 -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.97657,-1.9746 c -0.008,-0.009 -0.0153,-0.0172 -0.0234,-0.0254 -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 c 0.44606,0.44759 1.13973,-0.17325 0.74414,-0.66602 l -2,-2.5 c -0.0116,-0.0143 -0.024,-0.028 -0.0371,-0.041 -0.30703,-0.30702 -0.7149,-0.52843 -1.19922,-0.61132 -0.12109,-0.0207 -0.24665,-0.0327 -0.37696,-0.0352 z"
+ id="path14236"
inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 412,184 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
- id="path12526"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
</g>
<g
- transform="rotate(-180,670.50713,476.50011)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g9316-9"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- transform="translate(438,704)"
- id="g8254-6"
- style="fill:#ffffff" />
- <g
- style="fill:#ffffff;stroke-width:1.09491563"
- id="g8219-5"
- transform="matrix(0.99217072,0,0,0.84072177,457.69618,698.42569)" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-189,168)"
+ id="g21028"
+ inkscape:label="Y-8">
+ <path
+ inkscape:connector-curvature="0"
+ id="path21020"
+ d="m 342.5,348 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ sodipodi:nodetypes="ccccccccc" />
<g
- id="g8268-6"
- transform="rotate(90,613.50354,483.5038)"
+ id="g21026"
+ transform="translate(188,-63)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 2.503906 l -2.5,0.0039 a 0.50005,0.50005 0 1 0 0,1 l 3,-0.0039 a 0.50005,0.50005 0 0 0 0.5,-0.5 V -90.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 2.00781,3.015624 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m 5,0 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m -7.00781,1.986329 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.505859 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.505859 z"
- id="path8265-4"
+ id="circle21024"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 162.50391,410 c -0.82054,0 -1.4961,0.67556 -1.4961,1.49609 0,0.82054 0.67556,1.4961 1.4961,1.4961 0.82053,0 1.49609,-0.67556 1.49609,-1.4961 C 164,410.67556 163.32444,410 162.50391,410 Z M 159.5,413 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.01562 0.49805 L 161,417.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97656,0.21094 0.67528,-3.15139 1.92341,-4.0882 3.51758,-5.42774 1.58398,1.34059 2.83152,2.27747 3.51953,5.42969 0.13318,0.66658 1.13543,0.44609 0.97656,-0.21484 -0.76273,-3.49457 -2.35104,-4.70351 -4.00195,-6.11719 L 162.01367,414 h 2.2168 3.28515 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04296 c -0.45945,0.59659 -1.17125,0.99219 -1.96875,0.99219 -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 h -0.0195 z"
inkscape:connector-curvature="0" />
</g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g19653"
+ transform="translate(-628,42)"
+ inkscape:label="Y-7">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 160.5,327 c -0.8223,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.6777,1.5 1.5,1.5 h 5 c 0.8224,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.6776,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
- transform="rotate(180,670.50713,476.50011)"
- id="rect8324-7-9-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 143.13867,515.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -1.75,1.75 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.75,-1.75 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -4.39648,3.7168 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -0.25,0.25 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 0 0 0.70704,0 l 0.25,-0.25 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 138.74219,518.75 Z m -1.25196,2.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4.25,4.25 c -0.83838,0.83839 -1.06879,1.7573 -0.80273,2.4668 C 132.35981,528.57278 133.04167,529 133.75,529 H 138 c 1.00042,0 2,-0.79793 2,-2 v -3.5 a 0.50005,0.50005 0 1 0 -1,0 v 3.5 c 0,0.66505 -0.50442,1 -1,1 h -4.25 c -0.29167,0 -0.60981,-0.19778 -0.71875,-0.48828 -0.10894,-0.2905 -0.0893,-0.74659 0.57227,-1.4082 l 4.25,-4.25 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ transform="translate(628,-42)"
+ id="path19637"
inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(418)"
+ id="g19647" />
</g>
<g
- transform="translate(-1022,-287.00021)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g9304-8"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22292"
+ transform="translate(-88,-170)"
+ inkscape:label="Y-6">
<g
- transform="translate(419,704)"
- id="g8292-1"
+ transform="translate(20,10)"
+ id="g22287"
style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
- id="path8290-6"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 112,515 v 2 h -1 v 4 h 1 v 2 h 2 v -8 z m 10,0 v 8 h 2 v -2 h 1 v -4 h -1 v -2 z m -7,3 v 2 h 6 v -2 z"
+ transform="translate(68,160)"
+ id="rect22279"
inkscape:connector-curvature="0" />
</g>
- <g
- transform="translate(435,709)"
- id="g8299-5"
- style="fill:#ffffff" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 134.5,330 c -0.8224,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.6776,1.5 1.5,1.5 h 5 c 0.8224,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.6776,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
- transform="translate(1022,287.00021)"
- id="rect8324-7-9"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path22290"
+ d="m 203,691 v 5 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 697 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -1 h -3 v -3 z"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ sodipodi:nodetypes="csssssssssssscccc" />
</g>
<g
- transform="translate(-1021,-287.00021)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g9296-0"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- id="g8328-6"
- transform="translate(415,710)"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 115.5,331 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.67765,1.5 1.5,1.5 h 5 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
- transform="translate(606,-422.99979)"
- id="rect8324-7"
- inkscape:connector-curvature="0" />
- </g>
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13475"
+ transform="translate(-21)"
+ inkscape:label="Y-5">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ mask="none"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 111,515 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m -10,2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z m 4,0 h 2 v -2 h -2 z"
+ id="path12185"
+ inkscape:connector-curvature="0" />
<g
- id="g8338-5"
- transform="rotate(90,593.00354,462.0038)"
- style="fill:#ffffff">
+ transform="translate(63,-231)"
+ id="g12189"
+ style="opacity:0.6;fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
- id="path8336-9"
- inkscape:connector-curvature="0" />
+ id="path12187"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 48,753 v 3.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 756 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 757 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -2 h -2 v 0 h -2 v 0 h -2 v 0 h -2 v 0 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssssssssssscccccccccc" />
</g>
</g>
- <path
- inkscape:connector-curvature="0"
- id="path22951-5"
- d="m 52.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 56,413.5 V 412 h 0.5 c 1.293073,0 2.425866,0.35206 3.21875,1.00977 C 60.511634,413.66747 61,414.62406 61,416 c 0,1.58333 -0.78109,3.05511 -2.240234,4.16406 C 57.300621,421.27301 55.159091,422 52.5,422 H 52 v -1.5 A 0.50005,0.50005 0 0 0 51.5,420 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 52,423.5 V 423 h 0.5 c 2.840909,0 5.199379,-0.77301 6.865234,-2.03906 C 61.03109,419.69489 62,417.91667 62,416 62,414.37594 61.372824,413.08253 60.357422,412.24023 59.34202,411.39794 57.973784,411 56.5,411 H 56 v -0.5 A 0.50005,0.50005 0 0 0 55.5,410 Z m 0.5,1 h 2 v 2 h -2 z m -4,10 h 2 v 2 h -2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 53.5,431 a 1.50015,1.50015 0 1 0 0,3 H 55 c 1.249468,0.006 2.332699,0.37671 3.013672,0.94141 0.682107,0.56564 1.059323,1.26298 0.988281,2.4707 -0.09036,1.53611 -0.972327,2.5432 -2.498047,3.35351 -1.525719,0.81032 -3.632465,1.22991 -5.447265,1.23438 H 49.5 a 1.50015,1.50015 0 1 0 0,3 h 1.5625 0.002 c 2.24072,-0.006 4.728077,-0.46126 6.845703,-1.58594 2.117627,-1.12468 3.928252,-3.11228 4.087891,-5.82617 0.120132,-2.04228 -0.719411,-3.83841 -2.068359,-4.95703 -1.348949,-1.11862 -3.108979,-1.6232 -4.923829,-1.63086 h -0.002 z"
- id="path8588-0"
- inkscape:connector-curvature="0" />
- <rect
- style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- id="rect5217-4-0"
- width="16"
- height="16"
- x="110"
- y="430"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,89,-231)"
+ id="g12197"
+ inkscape:label="Y-4">
+ <path
+ inkscape:connector-curvature="0"
+ id="path12191"
+ transform="matrix(-1,0,0,1,90,231)"
+ d="m 75,519 v 7 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 526 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -3.08789 A 1.50015,1.50015 0 0 1 83.5,521 h -3 A 1.50015,1.50015 0 0 1 79,519.5 V 519 Z"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 16.5,746 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 9.5,747 h -3 A 0.50005,0.50005 0 0 0 6,747.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 10,750.5 V 749 h 6 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 19.5,746 Z m 0.5,1 h 2 v 2 h -2 z m -10,1 h 2 v 2 H 7 Z"
+ id="path12195"
+ inkscape:connector-curvature="0" />
+ </g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g12761"
- transform="translate(71.999998)"
+ transform="translate(72)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="Y-3">
<path
style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
d="m 51.5,515 a 0.50005,0.50005 0 0 0 -0.353516,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 48,518.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 62,525.5 v -10 A 0.50005,0.50005 0 0 0 61.5,515 Z m 0.207031,1 H 61 v 9.29297 L 58.292969,528 H 49 v -9.29297 z M 52,519 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m 0,2 h -2 v 2 h 2 z m -2,0 v -2 h -2 v 2 z m -2,0 h -2 v 2 h 2 z m 0,-2 v -2 h -2 v 2 z"
- transform="translate(-71.999998)"
+ transform="translate(-72)"
id="path12740"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12793"
+ id="g12259"
+ transform="matrix(0,-1,-1,0,312,-86)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 92.496094,325.99414 a 0.50005,0.50005 0 0 0 -0.382813,0.82227 l 4.5,5.5 a 0.50005,0.50005 0 0 0 0.773438,0 l 4.500001,-5.5 a 0.50005,0.50005 0 1 0 -0.77344,-0.63282 L 97,331.21094 92.886719,326.18359 a 0.50005,0.50005 0 0 0 -0.390625,-0.18945 z"
- id="path10173-4"
- inkscape:connector-curvature="0" />
+ inkscape:export-ydpi="96"
+ inkscape:label="Y-2">
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="rotate(90,-175.5,-141.5)"
+ id="g12255"
+ mask="none">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 237.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path12253"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 91.25,334 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.683851,0 1.25,-0.56615 1.25,-1.25 v -3.5 C 96,334.56615 95.433851,334 94.75,334 Z m 8,0 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.68385,0 1.25,-0.56615 1.25,-1.25 v -3.5 c 0,-0.68385 -0.56615,-1.25 -1.25,-1.25 z m -7.75,4 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z m 8,0 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z"
- id="rect13911"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -614.5,272 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.50781 v 5 H -614.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 284 h 5 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.49219 v -3.5 a 0.50005,0.50005 0 1 0 -1,0 V 281 H -605.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -5 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.49219 v -5 H -611.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 274 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 h -3.5 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -1.41406 a 0.50005,0.50005 0 0 0 -0.16016,0 H -614 Z m 0,9 h 2 v 2 h -2 z m 9,0 h 2 v 2 h -2 z"
+ id="path12257"
inkscape:connector-curvature="0" />
</g>
<g
- id="g12836"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="translate(-123,458.99979)"
- inkscape:export-filename="blender_icons.png"
+ inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(-21,168)"
+ id="g15951-6"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="Y-1">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 540.5,263 c -2.47936,0 -4.5,2.02064 -4.5,4.5 0,2.47936 2.02064,4.5 4.5,4.5 2.47936,0 4.5,-2.02064 4.5,-4.5 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 z m 0,1 c 1.93892,0 3.5,1.56108 3.5,3.5 0,1.40621 -0.82672,2.60476 -2.01758,3.16211 -0.16784,-2.48561 -2.15892,-4.47669 -4.64453,-4.64453 C 537.89524,264.82672 539.09379,264 540.5,264 Z"
- transform="translate(123,-458.99979)"
- id="path12830"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
+ id="path15947-7"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 657.50195,-192.93359 a 0.50004997,0.50004997 0 0 0 -0.22656,0.0508 c -2.27231,1.07327 -3.57921,3.51034 -3.21484,5.99609 0.36436,2.48575 2.31598,4.44563 4.80078,4.82227 2.48479,0.37663 4.92837,-0.91763 6.01367,-3.1836 a 0.50013262,0.50013262 0 1 0 -0.90234,-0.43164 c -0.89704,1.8729 -2.90867,2.93833 -4.96289,2.62696 -2.05422,-0.31138 -3.6598,-1.92406 -3.96094,-3.97852 -0.30115,-2.05446 0.77387,-4.06001 2.65234,-4.94727 a 0.50004997,0.50004997 0 0 0 -0.19922,-0.95507 z"
- id="path12834"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 30.5,350 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 7 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 7 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -7 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="rect15949-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g12981"
- transform="translate(-1.8536743e-6,-20.999995)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g31077"
+ inkscape:label="X-26"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 226.5,206.99414 a 0.50004997,0.50004997 0 0 0 -0.34766,0.85938 L 228.29883,210 h -10.5918 l 2.14649,-2.14648 a 0.50004997,0.50004997 0 1 0 -0.70704,-0.70704 l -2.95703,2.95704 a 0.50004997,0.50004997 0 0 0 -0.002,0.79296 0.50004997,0.50004997 0 0 0 0.008,0.006 l 2.95117,2.95118 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 217.70703,211 h 10.5918 l -2.14649,2.14648 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 l 2.96484,-2.9668 a 0.50004997,0.50004997 0 0 0 0.0195,-0.0156 l 0.0156,-0.0176 a 0.50004997,0.50004997 0 0 0 0.0234,-0.68164 0.50004997,0.50004997 0 0 0 -0.0234,-0.0254 0.50004997,0.50004997 0 0 0 -0.01,-0.01 l -2.99023,-2.99024 A 0.50004997,0.50004997 0 0 0 226.5,206.99414 Z"
- id="path12879"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 535.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 2e-5,0.1326 0.0527,0.25976 0.14648,0.35352 L 536,496.70703 v 2.61524 l -4.38672,5.36132 -0.004,0.004 c -0.58889,0.7361 -0.70787,1.57018 -0.44922,2.2168 0.25864,0.64662 0.88151,1.0957 1.58984,1.0957 h 10.5 c 0.70833,0 1.33692,-0.44332 1.60352,-1.0918 0.26614,-0.64736 0.14367,-1.48967 -0.4668,-2.22461 L 540,499.32227 v -2.61524 l 0.85352,-0.85351 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 4 v 0.29297 l -0.85352,0.85351 c -0.0938,0.0938 -0.14646,0.22092 -0.14648,0.35352 v 3 c 1.3e-4,0.11538 0.0402,0.22717 0.11328,0.31641 l 4.5,5.5 c 6.6e-4,10e-4 9.5e-4,0.003 0.002,0.004 0.42848,0.51418 0.43133,0.91996 0.3125,1.20899 C 543.80886,506.81822 543.54167,507 543.25,507 h -10.5 c -0.29167,0 -0.5438,-0.17592 -0.66016,-0.4668 -0.11635,-0.29088 -0.11033,-0.7068 0.30078,-1.2207 l 4.4961,-5.49609 c 0.0731,-0.0892 0.11315,-0.20103 0.11328,-0.31641 v -3 c -2e-5,-0.1326 -0.0527,-0.25976 -0.14648,-0.35352 L 536,495.29297 Z m 0,8 c -0.14428,-3.9e-4 -0.2817,0.0616 -0.37695,0.16992 l -1.75,2 c -0.28426,0.32357 -0.0537,0.83118 0.37695,0.83008 h 7.5 c 0.43069,10e-4 0.66121,-0.50651 0.37695,-0.83008 l -1.75,-2 C 540.2817,503.06155 540.14428,502.99961 540,503 Z"
+ id="path13700"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g20181-9"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ transform="translate(-288.996,63.999)"
+ inkscape:label="X-25">
+ <g
+ id="g5276"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 803.49219,433.99219 A 0.50005,0.50005 0 0 0 803,434.5 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 4.99804,4.00586 a 0.50005,0.50005 0 0 0 -0.49414,0.50586 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.50586,-0.50586 z"
+ id="path20179-2"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path20173-5"
+ transform="translate(288.996,-63.999)"
+ d="m 514.5,497.99805 a 0.50004997,0.50004997 0 0 0 -0.35352,0.14453 l -4,4 A 0.50004997,0.50004997 0 0 0 510,502.49805 v 5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 l 9,0.006 a 0.50004997,0.50004997 0 0 0 0.35547,-0.14649 l 4,-4.0039 A 0.50004997,0.50004997 0 0 0 524,503.49805 v -5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.20898,1 h 7.5879 l -3.00391,3.00586 L 511.70312,502 Z M 523,499.70703 v 3.58399 l -3.70703,3.71289 L 511,507 v -4 l 8.5,0.004 a 0.50004997,0.50004997 0 0 0 0.35547,-0.14844 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ transform="translate(-329.99,63.9955)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g21552"
+ inkscape:label="X-24">
<path
- id="circle12970"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 224.00001,202.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z m 5,0 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z m -10,0 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
+ id="path8055"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 823.98994,430.00453 v 2 h 5 v 3.7086 l 1.8538,-1.85485 c 0.0937,-0.0939 0.14631,-0.22111 0.1462,-0.35375 0.0114,-0.97402 0,-3.0415 0,-3.5 z m -3,3 v 4 h 7 l -4e-5,-4 z m 11.48438,1.125 c -0.12717,0.004 -0.24801,0.0564 -0.3379,0.14648 l -3.72851,3.72852 h -8.91211 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8.49414 v -4.5 a 0.50005,0.50005 0 0 1 0.49219,-0.50586 0.50005,0.50005 0 0 1 0.50781,0.50586 v 4.33203 l 3.85352,-3.85351 c 0.0938,-0.0938 0.14645,-0.22092 0.14648,-0.35352 v -5 c 1.1e-4,-0.28235 -0.23342,-0.50879 -0.51562,-0.5 z"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 94.513672,32 a 0.50005,0.50005 0 0 0 -0.417969,0.203125 c -2.416051,3.180716 -3.444751,6.003207 -3.857422,8.287109 -0.412671,2.283903 -0.216543,4.049887 -0.21875,5.00586 a 0.50005,0.50005 0 1 0 1,0.0039 c 0.0025,-1.084327 -0.183742,-2.690936 0.203125,-4.832031 0.386868,-2.141095 1.341004,-4.795942 3.667969,-7.859375 A 0.50005,0.50005 0 0 0 94.513672,32 Z m 4.955078,3.001953 a 0.50005,0.50005 0 0 0 -0.304688,0.126953 c -4.123582,3.585034 -5.171874,7.536346 -5.171874,10.376953 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.600212 0.913619,-6.219783 4.828124,-9.623047 A 0.50005,0.50005 0 0 0 99.46875,35.001953 Z m 4.02539,5.003906 c -3.01703,-0.0065 -5.494281,2.470749 -5.501952,5.498047 a 0.50005,0.50005 0 1 0 1,0.0039 c 0.0063,-2.484383 2.030992,-4.507263 4.500002,-4.501953 a 0.50005,0.50005 0 1 0 0.002,-1 z"
- id="path18476-0-2"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g7347"
- transform="translate(921.00001,-553)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <rect
- transform="scale(-1,1)"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- id="rect7240"
- width="16"
- height="16"
- x="396"
- y="731" />
+ id="g6417"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="X-23">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -408.50391,736.99414 a 0.50005,0.50005 0 0 0 -0.43554,0.26563 c -1.5311,2.80698 -2.01417,5.0457 -2.02149,8.22461 a 0.50005,0.50005 0 1 0 1,0.004 c 0.007,-3.0834 0.43147,-5.05503 1.90039,-7.74805 a 0.50005,0.50005 0 0 0 -0.44336,-0.74609 z m 6.99805,2 a 0.50005,0.50005 0 0 0 -0.37891,0.18555 C -403.15877,740.70849 -404,742.16634 -404,745.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-3.18014 0.65877,-4.20849 1.88477,-5.67969 a 0.50005,0.50005 0 0 0 -0.39063,-0.82617 z"
- id="path7245"
+ id="path8180-3"
+ d="m 470.66016,493.97656 c -0.37961,-0.006 -0.76447,0.0652 -1.1211,0.21289 -0.93286,0.38641 -1.54492,1.30084 -1.54492,2.31055 v 3.5 h 1 v -3.5 c 0,-0.60813 0.3659,-1.154 0.92774,-1.38672 0.5437,-0.22521 1.42162,-0.0569 1.71874,0.24024 l 0.5,0.5 c 0.47128,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -0.5,-0.5 c -0.35144,-0.35143 -0.81472,-0.56325 -1.31055,-0.63867 -0.12396,-0.0188 -0.25042,-0.0294 -0.37695,-0.0312 z m 8.67382,0 c -0.12653,0.002 -0.25299,0.0124 -0.37695,0.0312 -0.49583,0.0754 -0.95911,0.28724 -1.31055,0.63867 l -0.5,0.5 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 0.5,-0.5 c 0.29713,-0.29714 1.17505,-0.46545 1.71875,-0.24024 C 480.63411,495.346 481,495.89187 481,496.5 v 3.5 h 1 v -3.5 c 0,-1.00971 -0.61206,-1.92414 -1.54492,-2.31055 -0.35663,-0.1477 -0.74149,-0.21856 -1.1211,-0.21289 z M 468.49414,501 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 3.00586 a 0.50005,0.50005 0 0 0 0.41602,-0.22266 L 474.76758,505 h 0.46484 l 1.85156,2.77734 A 0.50005,0.50005 0 0 0 477.5,508 h 2.99414 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z M 474,502 v 2.34766 L 472.23242,507 h -2.23828 -1 L 469,502.00195 Z m 1.99414,0 5,0.002 V 507 h -0.5 H 480 477.76758 L 476,504.34766 Z"
+ style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -407.5,732 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 7,2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path7250"
+ sodipodi:nodetypes="ccccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccc" />
+ id="path8043-2"
+ d="m 470.49414,503 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 471.5 c 0.16717,-10e-6 0.32328,-0.0836 0.41602,-0.22266 l 1,-1.5 c 0.0559,-0.0838 0.0852,-0.18249 0.084,-0.2832 l -0.006,-0.5 c -0.003,-0.27384 -0.22614,-0.49413 -0.5,-0.49414 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- id="g6932"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13344"
+ transform="translate(-42,21)"
+ inkscape:label="X-22">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 543.50781,181.99023 a 1.50015,1.50015 0 0 0 -0.67773,0.16797 c -3.41741,1.7087 -5.83009,5.05846 -5.83008,9.3418 a 1.50015,1.50015 0 1 0 3,0 c -10e-6,-3.21666 1.58731,-5.3669 4.16992,-6.6582 a 1.50015,1.50015 0 0 0 -0.66211,-2.85157 z"
- id="path7270"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 449.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 0,-0.0417 0.006,-0.0117 -0.0469,0.0547 -0.0531,0.0664 -0.15023,0.15467 -0.2539,0.23242 -0.16609,0.12457 -0.2761,0.17993 -0.33789,0.21289 H 447.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.77539 c 0.40889,-0.49501 0.89786,-0.93068 1.47461,-1.26367 l 0.42578,-0.26758 L 451,496.29297 V 494.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8.28125,0.002 c -0.50453,0.0148 -1.01019,0.15125 -1.46875,0.41602 a 0.50005,0.50005 0 0 0 -0.0156,0.01 l -5.04688,3.17579 -0.0156,0.01 a 0.50005,0.50005 0 0 0 -0.19532,0.2207 c -1.45784,0.9884 -2.27996,2.6934 -1.9707,4.44727 0.32821,1.86134 1.78904,3.32218 3.65039,3.65039 0.641,0.11303 1.28349,0.0836 1.88867,-0.0703 a 0.50005,0.50005 0 1 0 -0.24609,-0.96875 c -0.47064,0.11969 -0.96915,0.14277 -1.46875,0.0547 -1.45073,-0.25581 -2.58404,-1.38913 -2.83985,-2.83985 -0.2558,-1.45072 0.42152,-2.90212 1.69727,-3.63867 a 0.50005,0.50005 0 0 0 0.0156,-0.01 l 0.0274,-0.0156 a 0.50005,0.50005 0 0 0 0.01,-0.008 l 5.00977,-3.15039 c 0.83503,-0.4821 1.88265,-0.34391 2.56445,0.33789 0.6818,0.68178 0.81999,1.72943 0.33789,2.56445 a 0.50005,0.50005 0 0 0 -0.006,0.0137 0.50005,0.50005 0 0 0 -0.0195,0.0371 l -1.6289,3.02539 a 0.50005,0.50005 0 1 0 0.8789,0.47266 l 1.63477,-3.03711 0.008,-0.0117 c 6.7e-4,-10e-4 -6.7e-4,-0.003 0,-0.004 l 0.006,-0.01 a 0.50005,0.50005 0 0 0 0.0586,-0.3125 c 0.51014,-1.16591 0.35331,-2.52952 -0.5625,-3.44531 -0.49921,-0.49921 -1.13538,-0.80107 -1.80078,-0.88868 -0.16635,-0.0219 -0.33377,-0.0303 -0.50195,-0.0254 z M 458,496 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -4.65039,2.64258 -1.05078,0.66211 a 1.50015,1.50015 0 0 1 -0.0488,0.0293 c -0.34485,0.1991 -0.62663,0.47142 -0.83594,0.78711 l 4.22461,4.22657 1.3613,1.35936 V 507.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c 0,-0.0833 0.0571,-0.22505 0.16602,-0.33398 C 459.27495,506.05708 459.41667,506 459.5,506 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.79297 z"
+ transform="translate(42,-21)"
+ id="path13315"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20455"
+ transform="rotate(180,359.4965,417.0035)"
+ inkscape:label="X-21">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 536.49609,179.00195 a 0.50005,0.50005 0 0 0 -0.35351,0.12891 c -4.08383,3.59037 -5.14329,7.80863 -5.13086,13.36328 a 0.50005,0.50005 0 1 0 1,-0.002 c -0.0122,-5.43221 0.92902,-9.21403 4.79101,-12.60938 a 0.50005,0.50005 0 0 0 -0.30664,-0.88086 z"
- id="path7282"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 283.49219,330.00781 c -0.1326,3e-5 -0.25976,0.0527 -0.35352,0.14649 l -2,2 c -0.0938,0.0938 -0.14645,0.22091 -0.14648,0.35351 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.1326,-3e-5 0.25975,-0.0527 0.35351,-0.14648 l 2,-2 c 0.0938,-0.0938 0.14646,-0.22092 0.14649,-0.35352 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path20447"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 284.25,326 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -4.75,4.75 A 0.50005,0.50005 0 0 0 279,331.25 l -0.008,8.25586 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 287.75,340 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 4.75,-4.75 A 0.50005,0.50005 0 0 0 293,334.75 l -0.008,-8.24414 a 0.50005,0.50005 0 0 0 -0.49805,-0.49805 z m 0.20703,1 7.53711,0.006 0.006,7.53711 -4.45703,4.45703 -7.55078,0.008 0.008,-7.55078 z"
+ id="path20449"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="translate(919,-532)"
- id="g6686"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12222"
+ transform="rotate(180,422.506,501)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <rect
- transform="scale(-1,1)"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- id="rect6673"
- width="16"
- height="16"
- x="415"
- y="710" />
+ inkscape:export-ydpi="96"
+ inkscape:label="X-20">
+ <g
+ id="g23057"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 415.99805,494 c -0.46823,5.5e-4 -0.93866,0.108 -1.3711,0.32422 l -6.83789,3.39453 a 0.50005,0.50005 0 0 0 -0.0273,0.0137 c -2.00082,1.15513 -3.06722,3.4434 -2.66602,5.71875 0.40121,2.27536 2.18559,4.05973 4.46094,4.46094 0.56884,0.1003 1.13889,0.11012 1.69141,0.0352 1.65755,-0.22472 3.1599,-1.20077 4.02734,-2.70313 a 0.50005,0.50005 0 0 0 0.0156,-0.0293 l 3.38476,-6.84179 c 0.57659,-1.15316 0.3761,-2.57898 -0.54687,-3.50196 -0.57687,-0.57686 -1.35049,-0.872 -2.13086,-0.87109 z m 0.3125,1.02539 c 0.41467,0.0623 0.80824,0.24966 1.11133,0.55273 0.60613,0.60614 0.74722,1.57588 0.36132,2.34766 a 0.50005,0.50005 0 0 0 -0.002,0.002 l -3.375,6.82032 c -0.9493,1.63933 -2.81295,2.50814 -4.67578,2.17968 -1.86473,-0.3288 -3.32159,-1.78565 -3.65039,-3.65039 -0.3288,-1.86473 0.54196,-3.7311 2.18164,-4.67773 l 6.81055,-3.38086 a 0.50005,0.50005 0 0 0 0.002,0 c 0.38589,-0.19295 0.82165,-0.25567 1.23633,-0.19336 z m -0.29883,0.9707 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -5.5,3 c -1.92707,0 -3.5,1.57293 -3.5,3.5 0,1.92707 1.57293,3.5 3.5,3.5 1.92707,0 3.5,-1.57293 3.5,-3.5 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1.97461 a 1.4874268,1.5 0 0 1 1.48828,1.5 1.4874268,1.5 0 0 1 -1.48828,1.5 1.4874268,1.5 0 0 1 -1.48828,-1.5 1.4874268,1.5 0 0 1 1.48828,-1.5 z"
+ transform="rotate(180,422.506,501)"
+ id="circle12201"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g31074"
+ inkscape:label="X-19"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -416.49609,713.99609 a 0.50005,0.50005 0 0 0 -0.31055,0.10938 c -0.21339,0.16596 -0.41872,0.33348 -0.61524,0.50195 -4.0339,3.45843 -4.51787,6.50897 -4.57812,9.88281 a 0.50009544,0.50009544 0 1 0 1,0.0195 c 0.059,-3.3038 0.37586,-5.83955 4.22852,-9.14258 0.1842,-0.15793 0.37703,-0.31626 0.57812,-0.47266 a 0.50005,0.50005 0 0 0 -0.30273,-0.89844 z"
- id="path6675"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 388.50781,494 c -0.82415,0 -1.5,0.67974 -1.5,1.5 v 1 0.5 h -0.5 -1 c -0.82026,0 -1.5,0.67584 -1.5,1.5 0,0.82416 0.67974,1.5 1.5,1.5 h 1 c 0.42622,0 0.76643,-0.21374 1.03516,-0.50195 l 4.96289,4.96484 C 392.21502,504.73149 392,505.07159 392,505.5 v 1 c 0,0.82025 0.67584,1.5 1.5,1.5 0.82416,0 1.5,-0.67974 1.5,-1.5 v -1 -0.5 h 0.5 1 c 0.82026,0 1.5,-0.67584 1.5,-1.5 0,-0.82416 -0.67974,-1.5 -1.5,-1.5 h -1 c -0.42622,0 -0.76642,0.21375 -1.03516,0.50195 l -4.96289,-4.96484 c 0.29085,-0.2686 0.50586,-0.60869 0.50586,-1.03711 v -1 c 0,-0.82026 -0.67584,-1.5 -1.5,-1.5 z"
+ id="path12213"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sscccssssccsssscccssssccsss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16377"
+ transform="translate(-217,44)"
+ inkscape:label="X-18">
<path
- id="path6688"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -427.5,716 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -2,5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,-10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path16340"
+ d="m 589,450 c -1.09935,0 -2,0.90065 -2,2 v 0.42969 c 0.73665,0.57364 1.18952,1.45204 1.23438,2.41601 C 588.47082,454.9447 588.72885,455 589,455 h 1 c 1.09935,0 2,-0.90065 2,-2 v -1 c 0,-1.09935 -0.90065,-2 -2,-2 z m 2.58789,6.00586 c -0.28431,-0.0492 -0.58776,0.16015 -0.58789,0.49414 0,0.25 -0.25,0.5 -0.5,0.5 h -2 c -0.25,0 -0.5,-0.25 -0.5,-0.5 v 0.5 c 0,0.36306 -0.26134,0.68419 -0.44336,0.93555 l 0.004,0.004 c 0.41161,0.41161 0.88215,0.75715 1.375,1.25 0.40738,0.40739 0.86402,1.03976 1.01172,1.81055 H 593.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 459 c 0,-0.66667 -0.3572,-1.18923 -0.77148,-1.60352 -0.41429,-0.41428 -0.90447,-0.77946 -1.375,-1.25 -0.0788,-0.0787 -0.17086,-0.12422 -0.26563,-0.14062 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccccc" />
+ sodipodi:nodetypes="ssccsssssscccccccsccccsccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 584,453 c -1.09935,0 -2,0.90065 -2,2 v 1 c 0,1.09935 0.90065,2 2,2 h 1 c 1.09935,0 2,-0.90065 2,-2 v -1 c 0,-1.09935 -0.90065,-2 -2,-2 z m -1.51562,6 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 -0.47053,0.47054 -0.96071,0.83572 -1.375,1.25 C 580.3572,460.81077 580,461.33333 580,462 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 462 c 0,-0.66667 -0.3572,-1.18923 -0.77148,-1.60352 -0.41429,-0.41428 -0.90447,-0.77946 -1.375,-1.25 -0.32034,-0.32057 -0.86773,-0.0838 -0.85352,0.36914 8.5e-4,0.0269 -0.0479,0.18374 -0.16406,0.30274 C 585.71981,459.93736 585.56612,460 585.5,460 h -2 c -0.0803,0 -0.22193,-0.0571 -0.33203,-0.16797 -0.1101,-0.11083 -0.16786,-0.25596 -0.16797,-0.33203 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z"
+ id="path16332"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ssssssssscccsccccsccccssccc" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 265.00049,180.00029 c -0.56524,0 -1.07102,0.24537 -1.44727,0.61718 -0.37625,0.37181 -0.64955,0.85716 -0.88086,1.40821 -0.46263,1.10209 -0.75684,2.49042 -1.08008,3.85937 -0.32324,1.36896 -0.67626,2.7158 -1.17383,3.66406 -0.49757,0.94827 -1.04163,1.45118 -1.91211,1.45118 a 0.50005,0.50005 0 1 0 0,1 c 1.29399,0 2.21222,-0.8721 2.79688,-1.98633 0.58466,-1.11424 0.93562,-2.51739 1.26172,-3.89844 0.32609,-1.38105 0.62614,-2.74272 1.0293,-3.70312 0.20157,-0.48021 0.4296,-0.85424 0.6621,-1.08399 0.2325,-0.22975 0.4436,-0.32812 0.74415,-0.32812 0.30054,0 0.51164,0.0984 0.74414,0.32812 0.23249,0.22975 0.46053,0.60378 0.66211,1.08399 0.40315,0.9604 0.7032,2.32207 1.02929,3.70312 0.3261,1.38105 0.67511,2.7842 1.25977,3.89844 0.58466,1.11423 1.50289,1.98633 2.79687,1.98633 a 0.50005,0.50005 0 1 0 0,-1 c -0.87047,0 -1.41258,-0.50291 -1.91015,-1.45118 -0.49757,-0.94826 -0.85059,-2.2951 -1.17383,-3.66406 -0.32324,-1.36895 -0.61745,-2.75728 -1.08008,-3.85937 -0.23131,-0.55105 -0.50461,-1.0364 -0.88086,-1.40821 -0.37625,-0.37181 -0.88203,-0.61718 -1.44726,-0.61718 z"
- id="path10124-9"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path10162-3"
- d="m 349.01758,181.25 a 0.50005,0.50005 0 0 0 -0.41992,0.20312 l -6.48243,8.7461 a 0.50005,0.50005 0 1 0 0.80274,0.5957 L 349,182.58984 l 6.07031,8.20313 a 0.50005,0.50005 0 1 0 0.80469,-0.59375 l -6.47266,-8.7461 A 0.50005,0.50005 0 0 0 349.01758,181.25 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- id="rect18819-6"
- width="16"
- height="16"
- x="320"
- y="178"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
<g
- style="display:inline;fill:#ffffff;stroke-width:1.03551209;enable-background:new"
- id="g10170-0"
- transform="matrix(0.93036376,0,0,1.0023904,257.63778,150.90833)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g31092"
+ inkscape:label="X-17"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03551209;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 23.460938,40.029297 A 0.51780782,0.51780782 0 0 1 22.96875,39.486328 L 23,38.607422 v -0.0039 c 0.0063,-2.697355 1.432558,-5.191614 3.748047,-6.542969 2.32064,-1.354362 5.185219,-1.354362 7.505859,0 2.32064,1.354362 3.748047,3.85629 3.748047,6.560547 v 0.882812 a 0.51780782,0.51780782 0 1 1 -1.035156,0 V 38.6211 c 0,-2.339918 -1.23548,-4.49829 -3.236328,-5.666016 -2.000849,-1.167726 -4.460089,-1.167727 -6.460938,0 -2.000848,1.167726 -3.234375,3.326098 -3.234375,5.666016 a 0.51780782,0.51780782 0 0 1 -0.002,0.01758 l -0.0293,0.882812 a 0.51780782,0.51780782 0 0 1 -0.542968,0.507813 z"
- id="path10174-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.55078,494 a 0.50005,0.50005 0 0 1 0.33593,0.1641 l 2.64844,2.84179 h 1.00781 c 0.45995,0.6015 1.17678,1 1.97852,1 h -3.20312 a 0.50005,0.50005 0 0 1 -0.36719,-0.1582 l -2.79492,-2.99999 A 0.50005,0.50005 0 0 1 342.5,494 a 0.50005,0.50005 0 0 1 0.0508,0 z m 5.9707,4.00589 c 0.80174,0 1.51857,-0.3985 1.97852,-1 h 2.02148 a 0.50005,0.50005 0 0 1 0.35352,0.1465 l 3,3 a 0.50005,0.50005 0 1 1 -0.70704,0.707 l -2.85351,-2.8535 h -2.29297 v 3.832 c 0.96356,1.6489 2.8299,3.71521 5.58203,4.17391 A 0.50086299,0.50086299 0 1 1 355.43945,507 c -2.4267,-0.4044 -4.21553,-1.8644 -5.39844,-3.34761 a 0.50005,0.50005 0 0 1 -0.002,0 c -0.001,0 -0.003,0 -0.004,0 -1.00443,-0.9218 -2.17404,-1 -3.22851,-0.2383 -1.05449,0.76181 -1.78322,2.34671 -1.78321,4.09771 a 0.50005,0.50005 0 1 1 -1,0 c -10e-6,-2.0216 0.80114,-3.89961 2.19727,-4.90821 0.69807,-0.5043 1.49696,-0.7238 2.2832,-0.668 0.17359,0.012 0.34649,0.043 0.51758,0.082 a 0.50005,0.50005 0 0 1 0,-0.01 v -4 z m 0,-3.99999 c 0.8225,0 1.5,0.6775 1.5,1.49999 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.82249 0.6775,-1.49999 1.5,-1.49999 z"
+ id="path20567-5"
inkscape:connector-curvature="0" />
</g>
- <rect
- y="178"
- x="299"
- height="16"
- width="16"
- id="rect4967"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 307,180 c -1.24829,0 -2.24461,0.83463 -3,1.93555 -0.75539,1.10091 -1.32403,2.51399 -1.76367,3.91601 -0.87928,2.80405 -1.23047,5.58594 -1.23047,5.58594 a 0.50013931,0.50013931 0 1 0 0.99219,0.12695 c 0,0 0.34791,-2.71791 1.19336,-5.41406 0.42272,-1.34808 0.97296,-2.68677 1.63281,-3.64844 C 305.48407,181.54029 306.19904,181 307,181 c 0.80095,0 1.51593,0.54029 2.17578,1.50195 0.65985,0.96167 1.21009,2.30036 1.63281,3.64844 0.84545,2.69615 1.19336,5.41406 1.19336,5.41406 a 0.50013931,0.50013931 0 1 0 0.99219,-0.12695 c 0,0 -0.35119,-2.78189 -1.23047,-5.58594 -0.43964,-1.40202 -1.00828,-2.8151 -1.76367,-3.91601 C 309.24461,180.83464 308.24829,180 307,180 Z"
- id="path13261"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 327.48047,181 a 0.50005,0.50005 0 0 0 -0.46875,0.39453 c -0.73399,3.42527 -2.46804,7.48775 -5.67969,8.63477 a 0.50005,0.50005 0 1 0 0.33594,0.9414 c 3.19373,-1.14062 4.90029,-4.45895 5.83203,-7.61914 0.93174,3.16019 2.6383,6.47852 5.83203,7.61914 a 0.50005,0.50005 0 1 0 0.33594,-0.9414 c -3.21165,-1.14702 -4.9457,-5.2095 -5.67969,-8.63477 A 0.50005,0.50005 0 0 0 327.48047,181 Z"
- id="path10168-6-7"
- inkscape:connector-curvature="0" />
<g
- transform="matrix(-1,0,0,1,401.98389,150.99638)"
- id="g13323"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff">
+ transform="translate(-1134,-17)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23520-0"
+ inkscape:label="X-16">
<path
inkscape:connector-curvature="0"
- id="path13321"
- d="M 9.96875,29.048828 C 9.4658605,28.864829 8.9025328,28.986924 8.5410156,29.310547 8.1794984,29.63417 7.9598217,30.084792 7.7695312,30.613281 7.3889504,31.670259 7.1601578,33.086794 6.90625,34.523438 c -0.2539078,1.436643 -0.5324149,2.889409 -0.9414062,3.929687 -0.2044957,0.520139 -0.4424423,0.932648 -0.6894532,1.1875 -0.2470108,0.254852 -0.473033,0.363281 -0.7851562,0.363281 a 0.50005,0.50005 0 1 0 0,1 c 0.5904168,0 1.1159371,-0.267683 1.5039062,-0.667968 0.3879692,-0.400286 0.6690516,-0.922242 0.9023438,-1.515626 0.4665844,-1.186767 0.7390333,-2.679616 0.9941406,-4.123046 0.2551073,-1.443431 0.4935421,-2.842034 0.8183594,-3.744141 0.1624086,-0.451054 0.3541704,-0.76594 0.5,-0.896484 0.1458295,-0.130544 0.1865427,-0.15232 0.4160156,-0.06836 0.057045,0.02087 0.1634141,0.101911 0.2832031,0.296875 0.1197889,0.194965 0.2422649,0.485737 0.3515629,0.826172 0.218596,0.680871 0.393488,1.55941 0.582031,2.373047 0.188543,0.813637 0.358157,1.549689 0.740234,2.082031 0.191039,0.266171 0.511622,0.515788 0.900391,0.50586 0.388769,-0.0099 0.704011,-0.230804 1.001953,-0.542969 0.337514,-0.353626 0.595779,-0.497442 0.722656,-0.529297 0.126878,-0.03186 0.138013,-0.02504 0.242188,0.06836 0.20835,0.186805 0.512485,0.892009 0.740234,1.732422 0.227749,0.840413 0.429042,1.804722 0.716797,2.601563 0.143877,0.39842 0.30542,0.75895 0.542969,1.05664 0.237548,0.297691 0.601614,0.544922 1.027343,0.544922 a 0.50005,0.50005 0 1 0 0,-1 c -0.0724,0 -0.124723,-0.01782 -0.246093,-0.169922 -0.12137,-0.152098 -0.260285,-0.426776 -0.384766,-0.771484 -0.248961,-0.689415 -0.452791,-1.642926 -0.691406,-2.523438 -0.238616,-0.880511 -0.460258,-1.699598 -1.037109,-2.216796 -0.288426,-0.2586 -0.735893,-0.398016 -1.154297,-0.292969 -0.418405,0.105047 -0.794027,0.38192 -1.203125,0.810547 -0.205362,0.215165 -0.318948,0.232836 -0.302735,0.232422 0.01621,-4.14e-4 0.02252,0.02861 -0.0625,-0.08984 C 12.22449,34.745505 11.999507,34.047965 11.816406,33.257812 11.633305,32.46766 11.457527,31.57275 11.210938,30.804688 11.087643,30.420656 10.949285,30.066996 10.761719,29.761719 10.574152,29.456442 10.328076,29.1803 9.96875,29.048828 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ d="m 1461,518 c -1.3523,-0.0191 -1.3523,2.01913 0,2 h 2 c 1.3523,0.0191 1.3523,-2.01913 0,-2 z m -5,-1 v 7.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 517 h -1 v 7 h -10 v -7 z m 12.5,-1 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -3 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 h -13 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 3 c 0,0.27613 0.2239,0.49997 0.5,0.5 z m -12.5,-3 h 12 v 2 h -12 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path23618-7"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g5270-3"
- transform="translate(497.99495,-311.99288)"
- inkscape:export-filename="blender_icons.png"
+ id="g31086"
+ inkscape:label="X-15"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path6351"
+ d="m 310.57031,494.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -1.08008,3.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -4.92968,2.02149 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C 307.68213,505.0249 308,504.28067 308,503.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-filename="blender_icons.png"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g6359"
+ transform="rotate(90,306.5,333.5)"
+ inkscape:label="X-14">
<path
- id="path5169-5"
- style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
- d="m -115,532 h 16.005051 v 16 H -115 Z"
+ sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccc" />
+ id="path6353"
+ d="m 469.5,356 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- transform="translate(-1)"
- id="g5191-5"
- style="fill:#ffffff">
+ style="opacity:0.7;fill:#ffffff"
+ id="g6357">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 386.48633,221 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 6.55664 C 384.86022,229.298 384,230.30731 384,231.50781 c 0,1.372 1.12214,2.49414 2.49414,2.49414 1.372,0 2.49414,-1.12214 2.49414,-2.49414 0,-1.20116 -0.8593,-2.21054 -1.99414,-2.44336 v -6.55664 -1 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z m 1.00781,1.00781 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -1,8.00586 c 0.83156,0 1.49414,0.66258 1.49414,1.49414 0,0.83156 -0.66258,1.49414 -1.49414,1.49414 -0.83156,0 -1.49414,-0.66258 -1.49414,-1.49414 0,-0.83156 0.66258,-1.49414 1.49414,-1.49414 z"
- transform="translate(-496.99495,311.99288)"
- id="path5112-6"
+ id="path6355"
+ transform="matrix(0,-1,-1,0,1038,577)"
+ d="m 218.5,557 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 V 564.5 c -0.01,0.67616 1.01,0.67616 1,0 v -4.59375 c 0.57903,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 9.5,0 c -1.09865,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -5.13868,5.13867 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 5.13867,-5.13868 C 227.28978,560.89117 227.63141,561 228,561 c 1.09865,-10e-6 2,-0.90135 2,-2 0,-1.09865 -0.90135,-1.99999 -2,-2 z m 0.5,10 c -0.64684,0 -1.19777,0.42097 -1.40625,1 H 222.5 c -0.67616,-0.01 -0.67616,1.01 0,1 h 4.59375 c 0.20848,0.57903 0.75941,1 1.40625,1 0.82251,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
+ </g>
+ <g
+ transform="translate(624,-1354)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24304"
+ inkscape:label="X-13">
+ <path
+ style="display:inline;opacity:0.7;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.7;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m -356.5,1850 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.2179 0.5,0.5 0,0.2821 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.2179 -0.5,-0.5 0,-0.2821 0.21794,-0.5 0.5,-0.5 z m -7,1 a 0.5,0.5 0 0 0 -0.5,0.5 0.5,0.5 0 0 0 0.5,0.5 0.5,0.5 0 0 0 0.5,-0.5 0.5,0.5 0 0 0 -0.5,-0.5 z"
+ id="path24284"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path24300"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -357.5,1856.0041 h 0.49805 c 3.5943,0 5.00195,-2.5001 5.00195,-4.5001 v 0 c 0,-2.4794 -2.02064,-4.5 -4.5,-4.5 -1.88915,0 -3.45662,1.2594 -4.10547,3 h -0.51758 c -0.64602,-0.6132 -1.47755,-0.9979 -2.375,-1 h -0.002 c -1.92707,0 -3.5,1.5729 -3.5,3.5 0,1.9271 1.57293,3.5 3.5,3.5 z m -6,-1.0041 c -1.38663,0 -2.5,-1.1134 -2.5,-2.5 0,-1.386 1.11233,-2.4989 2.49805,-2.5 0.71036,0 1.38608,0.3048 1.85937,0.834 0.0951,0.1059 0.23074,0.1663 0.37305,0.166 h 0.90234 c 0.22809,10e-5 0.42734,-0.1542 0.48438,-0.375 0.39914,-1.5459 1.78609,-2.6224 3.38281,-2.625 1.93892,0 3.5,1.5611 3.5,3.5 0,1.9279 -1.54523,3.4765 -3.46875,3.4941 -0.0392,0 -0.0785,-6e-4 -0.11719,0.01 H -357.5 Z m -1.00781,1.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -1.5039 h 0.33594 l 2.61914,1.9043 c 0.0852,0.064 0.18852,0.099 0.29492,0.1 h 0.25 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -0.25 c -0.106,-10e-5 -0.20927,0.034 -0.29492,0.096 L -355.66211,1859 H -356 v -2 h -1 v 4 h -4.29297 L -362,1860.293 V 1857 h -1 v 1 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z M -353,1858.3008 v 2.3984 l -1.65039,-1.1992 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csssscccsscccsccccccscccccccccccccccccccccsccsccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m -362,1857 h 5 v 1 h -5 z"
+ id="path24302" />
+ </g>
+ <g
+ id="g5996"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,552.832,1.5e-5)"
+ inkscape:label="X-12">
+ <path
+ inkscape:connector-curvature="0"
+ id="path5994"
+ d="m 310.58203,494 c -1.1875,0 -2.13583,0.69085 -2.52344,1.62109 -0.3876,0.93025 -0.20775,2.10475 0.66993,2.98243 l 2.5,2.5 c 0.62232,0.62232 0.69247,1.32282 0.45507,1.89257 C 311.4462,503.56585 310.89453,504 310.08203,504 l -6.53515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 6.55078,0.008 c 1.1875,0 2.13584,-0.69085 2.52344,-1.62109 0.3876,-0.93025 0.20775,-2.10475 -0.66992,-2.98243 l -2.5,-2.5 c -0.62233,-0.62232 -0.69248,-1.32282 -0.45508,-1.89257 0.2374,-0.56976 0.78906,-1.00391 1.60156,-1.00391 h 4.75 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g5920"
+ transform="translate(168,-63)"
+ inkscape:label="X-11">
+ <path
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="path5916"
+ d="m 49,558 v 3 h 3 v -3 z m 3,3 v 3 h 3 v -3 z m 3,0 h 3 v -3 h -3 z m 3,0 v 3 h 3 v -3 z m 0,3 h -3 v 3 h 3 z m 0,3 v 3 h 3 v -3 z m -3,0 h -3 v 3 h 3 z m -3,0 v -3 h -3 v 3 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5918"
+ d="m 48.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 61.5,557 Z m 0.5,1 h 12 v 12 H 49 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="matrix(0.866668,0,0,0.866668,-9.46699,121.399)"
+ id="g5914"
+ style="display:inline;fill:#ffffff;stroke-width:1.15384;enable-background:new"
+ inkscape:label="X-10">
<g
- transform="translate(-2.9999978)"
- style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new"
- id="g5186-5-5-7">
+ id="g5912"
+ style="fill:#ffffff;stroke-width:1.15384">
<path
- id="path5179-0-9-1"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -97.896484,538.39648 -1.707032,1.70704 0.75,0.75 c 0.195265,0.19518 0.511767,0.19518 0.707032,0 l 0.52539,-0.5254 0.47461,-0.4746 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 z m -0.614086,-1.39969 a 0.50005,0.50005 0 0 0 -0.34376,0.15039 l -4.4121,4.41015 c -0.38435,-0.27257 -0.83195,-0.45926 -1.31446,-0.52734 a 0.50005,0.50005 0 0 0 -0.0996,-0.006 0.50005,0.50005 0 0 0 -0.041,0.99609 c 0.71727,0.10121 1.32147,0.58072 1.58398,1.25586 0.26252,0.67514 0.14019,1.43694 -0.32031,1.9961 -0.46051,0.55917 -1.18354,0.82547 -1.89649,0.69726 a 0.50014796,0.50014796 0 1 0 -0.17773,0.98438 c 1.06733,0.19194 2.15825,-0.20977 2.84766,-1.04688 0.6894,-0.83711 0.87347,-1.98341 0.48047,-2.99414 -0.0911,-0.23424 -0.21129,-0.45079 -0.35352,-0.65039 l 4.41016,-4.4082 a 0.50005,0.50005 0 0 0 -0.36328,-0.85742 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 202,494 c -3.86008,0 -7,3.13992 -7,7 0,3.86008 3.13992,7 7,7 3.86008,0 7,-3.13992 7,-7 0,-3.86008 -3.13992,-7 -7,-7 z m 0,1 c 3.3058,0 5.97583,2.65852 5.99805,5.95898 C 206.88654,501.90262 204.99536,503 202,503 v 4 c -3.31963,0 -6,-2.68037 -6,-6 0,-0.0145 0.002,-0.0285 0.002,-0.043 1.1112,0.94401 3.00099,2.043 5.998,2.043 z"
+ transform="matrix(1.15384,0,0,1.15384,10.9234,-140.076)"
+ id="path5908"
inkscape:connector-curvature="0" />
</g>
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g7388-6"
- transform="translate(731,-238)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <rect
- transform="scale(-1,1)"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- id="rect7384-9"
- width="16"
- height="16"
- x="437"
- y="710" />
+ transform="translate(-847,-1062)"
+ id="g24813"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="X-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -447.96289,710.98828 a 1.0001,1.0001 0 0 0 -0.83789,0.41211 c -3.30626,4.40835 -3.18183,10.96743 -3.18555,12.58399 a 1.0001,1.0001 0 1 0 2,0.006 c 0.004,-1.64212 0.0934,-7.79897 2.78711,-11.39062 a 1.0001,1.0001 0 0 0 -0.76367,-1.61133 z m 4.97461,3.00195 a 1.0001,1.0001 0 0 0 -0.69727,0.28125 c -2.25424,2.12239 -3.3739,3.98924 -3.89062,5.64258 C -448.0929,721.56741 -448,722.96385 -448,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-1.13631 -0.0696,-2.20308 0.33203,-3.48828 0.40167,-1.28521 1.28135,-2.83224 3.35352,-4.7832 a 1.0001,1.0001 0 0 0 -0.67383,-1.73829 z m 3.94531,4.00782 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 C -441.66808,718.54973 -444,720.82862 -444,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-2.17354 1.66808,-3.68979 3.21094,-4.02148 a 1.0001,1.0001 0 0 0 -0.25391,-1.98047 z"
- id="path7133-7"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path24809"
+ d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path24811"
+ d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g31089"
+ inkscape:label="X-8"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20392"
+ d="m 154.49904,493.99904 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.86133 l -0.82812,3.30664 a 0.50005,0.50005 0 0 0 -0.002,0.006 0.50005,0.50005 0 0 0 -0.0352,0.14258 0.50005,0.50005 0 0 0 0,0.004 l -1.48047,5.91993 a 0.50005,0.50005 0 0 0 0.48437,0.62304 h 4.92383 a 0.50005,0.50005 0 0 0 0.14453,0 h 4.90821 a 0.50005,0.50005 0 0 0 0.48437,-0.3789 l 3.03711,-11.99024 a 0.50005,0.50005 0 0 0 -0.48437,-0.62109 l -4.91016,-0.006 a 0.50005,0.50005 0 0 0 -0.20117,0 l -3.40235,-0.006 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -0.92187 a 0.50005,0.50005 0 0 0 -0.14453,0 h -0.9336 z m 3,1 2.85938,0.004 -1.24805,4.99609 h -3.96875 l 0.75,-3 h 1.10742 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 3.89063,0.006 3.98047,0.006 -1.26367,4.98828 h -3.96485 z m -6.49805,5.99414 h 3.96875 l -1.25195,5.00195 h -3.9668 z m 5,0 h 3.96094 l -1.26758,5.00195 h -3.94336 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path13682"
- d="m 100.45117,431 c -0.36065,0.005 -0.725199,0.0666 -1.080078,0.1875 -1.419514,0.48381 -2.371094,1.8128 -2.371094,3.3125 a 0.50005006,0.50005006 0 1 1 -1,0 c 0,-0.53249 0.102694,-1.04562 0.277344,-1.52734 -0.0921,0.0103 -0.173784,0.0274 -0.277344,0.0273 -3.307786,0 -6,2.69221 -6,6 0,3.30779 2.692214,6 6,6 3.307786,0 6.000002,-2.69221 6.000002,-6 v -0.002 c -4.7e-4,-0.11093 0.014,-0.19694 0.0332,-0.27344 -0.83987,0.3046 -1.77022,0.36483 -2.67578,0.12695 a 0.50005006,0.50005006 0 1 1 0.253906,-0.96679 c 1.450494,0.38101 2.978064,-0.20116 3.806644,-1.45118 0.82858,-1.25001 0.7694,-2.88277 -0.14649,-4.07031 -0.68691,-0.89068 -1.73836,-1.37897 -2.82031,-1.36328 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
+ id="g14544"
+ transform="translate(42,84)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14534">
+ inkscape:label="X-7">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 100.24805,410.01367 c -1.271268,0.11136 -2.328782,0.98616 -2.845706,2.17774 -2.575841,-0.61979 -5.266939,0.50372 -6.597656,2.80859 -1.356612,2.34971 -0.965414,5.32365 0.953124,7.24219 1.918537,1.91853 4.892473,2.30974 7.242188,0.95312 2.30486,-1.33072 3.42838,-4.02182 2.80859,-6.59765 1.3618,-0.59077 2.3103,-1.88718 2.17774,-3.40235 -0.14775,-1.68875 -1.49289,-3.03389 -3.18164,-3.18164 -0.1894,-0.0166 -0.37503,-0.0159 -0.55664,0 z m 0.0234,0.9961 c 0.14685,-0.0133 0.29578,-0.0133 0.44727,0 1.21193,0.10603 2.16545,1.05955 2.27148,2.27148 0.10604,1.21192 -0.66865,2.31795 -1.84375,2.63281 a 0.50005006,0.50005006 0 0 0 -0.35937,0.58203 l 0.0352,0.17969 a 0.50005006,0.50005006 0 0 0 0.008,0.0293 c 0.58634,2.18824 -0.36816,4.49227 -2.33008,5.625 -1.961931,1.13272 -4.433244,0.80698 -6.035156,-0.79492 -1.601912,-1.60191 -1.927645,-4.07323 -0.794922,-6.03516 1.132722,-1.96193 3.43675,-2.91642 5.625,-2.33008 a 0.50005006,0.50005006 0 0 0 0.0293,0.008 l 0.179687,0.0352 a 0.50005006,0.50005006 0 0 0 0.582032,-0.35937 c 0.275511,-1.02822 1.157648,-1.75045 2.185539,-1.84375 z M 94.5,416 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 97.5,416 Z m 0.5,1 h 2 v 2 h -2 z"
- transform="translate(1.8536743e-6,-4.4999696e-6)"
- id="circle13742"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 142.16211,494.00195 c -0.3928,-0.016 -0.79264,0.0268 -1.18555,0.13086 -1.05738,0.28017 -1.9221,0.97933 -2.44336,1.89453 -2.51672,-0.22477 -4.91162,1.1516 -5.97656,3.44727 -1.07271,2.31243 -0.56559,5.05473 1.26367,6.83008 1.82926,1.77534 4.58788,2.20194 6.86719,1.06054 2.20676,-1.10505 3.49065,-3.45007 3.27539,-5.89257 0.59118,-0.33407 1.10512,-0.8107 1.46875,-1.41797 0.83525,-1.3949 0.74131,-3.16186 -0.23633,-4.46094 -0.73322,-0.97431 -1.8548,-1.54394 -3.0332,-1.5918 z m -0.041,1 c 0.88379,0.0353 1.72432,0.4611 2.27539,1.19336 0.73477,0.97635 0.80549,2.29734 0.17774,3.34571 -0.62775,1.04836 -1.82561,1.61054 -3.0332,1.42382 a 0.50005006,0.50005006 0 1 0 -0.15235,0.98828 c 0.54314,0.084 1.08325,0.0449 1.59571,-0.0859 0.0521,1.92511 -0.99653,3.7274 -2.7461,4.60351 -1.90239,0.95265 -4.19394,0.59896 -5.7207,-0.88281 -1.52677,-1.48177 -1.94806,-3.76137 -1.05274,-5.69141 0.84423,-1.81987 2.6839,-2.93301 4.66602,-2.88086 -0.0398,0.15646 -0.0768,0.3137 -0.0977,0.47657 a 0.50013931,0.50013931 0 0 0 0.99219,0.12695 c 0.15491,-1.21208 1.02585,-2.20656 2.20703,-2.51953 0.2953,-0.0782 0.59408,-0.10943 0.88867,-0.0977 z"
+ transform="translate(-42,-84)"
+ id="path14540"
inkscape:connector-curvature="0" />
</g>
<g
+ id="g31083"
+ inkscape:label="X-6"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 115.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 496 h 0.5 c 1.29307,0 2.42587,0.35206 3.21875,1.00977 C 123.51163,497.66747 124,498.62406 124,500 c 0,1.58333 -0.78109,3.05511 -2.24023,4.16406 C 120.30062,505.27301 118.15909,506 115.5,506 H 115 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 507 h 0.5 c 2.84091,0 5.19938,-0.77301 6.86523,-2.03906 C 124.03109,503.69489 125,501.91667 125,500 c 0,-1.62406 -0.62718,-2.91747 -1.64258,-3.75977 C 122.34202,495.39794 120.97378,495 119.5,495 H 119 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -4,10 h 2 v 2 h -2 z"
+ id="path6006" />
+ </g>
+ <g
+ id="g31080"
+ inkscape:label="X-5"
+ style="display:inline;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 90.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.949219 L 95,504.62695 V 507.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.87305 L 102.55078,498 H 103.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 93.5,494 Z m 0.5,1 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -7,1 h 6 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.91406 l -3.214841,6 h -2.398438 l -3.214843,-6 H 93.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 2,9 h 2 v 2 h -2 z"
+ id="path6000" />
+ </g>
+ <g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14020"
- transform="translate(153.00001,38.000005)"
+ id="g6348"
+ transform="translate(42,147)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="X-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -76.5,394 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -75.936984,394.30587 -76.175116,394.00052 -76.5,394 Z m 6,0 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -69.936984,394.30587 -70.175116,394.00052 -70.5,394 Z m -8,7 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -77.936984,401.30587 -78.175116,401.00052 -78.5,401 Z m 6,0 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -71.936984,401.30587 -72.175116,401.00052 -72.5,401 Z"
- id="path13999"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ id="path6344"
+ d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path6346"
+ d="m 30.5,350 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 7 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 7 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -7 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 11.455078,430.98242 a 1.50015,1.50015 0 0 0 -1.4765624,1.52149 v 6.3789 l -3.5605468,3.56055 a 1.50015,1.50015 0 1 0 2.1210937,2.12109 l 3.5605465,-3.56054 h 6.378907 a 1.50015,1.50015 0 1 0 0,-3 h -5.5 v -5.5 a 1.50015,1.50015 0 0 0 -1.523438,-1.52149 z"
- id="path12350-2"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 199.50586,431 c -0.31034,2.7e-4 -0.5455,0.28021 -0.49219,0.58594 0.36378,2.06995 0.21088,3.24033 -0.13086,3.98828 -0.34174,0.74794 -0.89741,1.14621 -1.5625,1.65234 -0.66509,0.50614 -1.42742,1.12518 -1.87304,2.24414 -0.44562,1.11896 -0.57595,2.68203 -0.19141,5.10742 0.0385,0.24306 0.24806,0.422 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.27449 0.49414,-0.57812 -0.36857,-2.32471 -0.21903,-3.70089 0.13086,-4.58204 0.34989,-0.88114 0.89751,-1.32255 1.54492,-1.8164 0.64741,-0.49385 1.4068,-1.03318 1.86328,-2.03516 0.45648,-1.00198 0.58623,-2.39428 0.20313,-4.57422 C 208.70043,431.17484 208.49284,431.0002 208.25,431 Z"
- id="path8644-7"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccscccccssccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 96.5,473 c -2.087116,0 -3.478164,1.04607 -4.390625,2.1875 a 0.50024408,0.50024408 0 0 0 0.78125,0.625 C 93.690488,474.81193 94.734388,474 96.5,474 c 2.098393,0 3.134109,0.87695 3.75195,1.94531 C 100.8698,477.01367 101,478.31651 101,479 h -5.25 c -1.273438,0 -2.443243,0.36418 -3.314453,1.05469 -0.87121,0.69051 -1.427734,1.72791 -1.427735,2.94531 10e-7,1.2174 0.556525,2.2548 1.427735,2.94531 C 93.306757,486.63582 94.476562,487 95.75,487 h 0.75 c 1.755585,0 3.387714,-0.96684 4.53711,-2.0332 0.0781,0.53303 0.28951,1.00434 0.64062,1.35547 C 102.12862,486.77315 102.775,487 103.5,487 a 0.50005,0.50005 0 1 0 0,-1 c -0.525,0 -0.87862,-0.14815 -1.11523,-0.38477 C 102.14815,485.37862 102,485.025 102,484.5 V 479 c 0,-0.79721 -0.12242,-2.24322 -0.88086,-3.55469 C 100.3607,474.13385 98.896459,473 96.5,473 Z m -0.75,7 H 101 v 3.56055 C 100.04582,484.68473 98.18875,486 96.5,486 h -0.75 c -1.081007,0 -2.03187,-0.31555 -2.693359,-0.83984 -0.66149,-0.52429 -1.048828,-1.23676 -1.048829,-2.16016 10e-7,-0.9234 0.387339,-1.63587 1.048829,-2.16016 C 93.718131,480.31555 94.668993,480 95.75,480 Z"
- id="path10278-2"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g12310-0"
- transform="translate(62.999998,210)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ transform="translate(420.005,-159.005)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g5937"
+ inkscape:label="X-3">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 222,431 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 L 218.79297,434 H 216.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.29297 l 2.85351,2.85352 c 0.0938,0.0938 0.22092,0.14646 0.35352,0.14648 h 0.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 431.78125 431.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.4668,2.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27328,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41099,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10286,2.06013 1.1045,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25221,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
- transform="translate(-62.999998,-210)"
- id="path12304-9"
+ id="path5935"
+ transform="translate(-462.005,96.0051)"
+ d="m 103.49609,556.99023 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.57031,1.57032 c -1.22858,-1.06562 -2.825838,-1.7168 -4.576171,-1.7168 -3.86007,0 -7,3.13993 -7,7 0,1.75033 0.649231,3.34954 1.714844,4.57813 l -1.568359,1.56835 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.568359,-1.56836 c 1.228585,1.06561 2.827793,1.71484 4.578125,1.71484 3.860071,0 7.000001,-3.13993 7.000001,-7 0,-1.75033 -0.65118,-3.34759 -1.7168,-4.57617 l 1.57032,-1.57031 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -6.490231,1.00391 c 3.319631,0 6.000001,2.68037 6.000001,6 0,3.31963 -2.68037,6 -6.000001,6 -3.31963,0 -6,-2.68037 -6,-6 0,-0.88092 0.193846,-1.71405 0.533203,-2.4668 l 0.466797,0.4668 1,1 v 2 h 2 v 1 l 1,1 v 2 h 0.75 1.25 l 1,-1 1.000001,-1 v -1 l -1.000001,-1 h -2 -1 l -1,-1 h -1 l 1,-1 h 1 l 2,-2 -1,-1 h -1 l -1,-1 0.894532,-0.89453 c 0.358617,-0.0666 0.727234,-0.10547 1.105468,-0.10547 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.99;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
<g
- id="g5260"
- transform="translate(21,42)"
- style="fill:#ffffff">
+ id="g6342"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="X-2">
<path
inkscape:connector-curvature="0"
- id="path13014"
- d="m 176.5,410 a 0.50005,0.50005 0 1 0 0,1 h 0.79297 L 178,411.70703 v 10.58594 L 177.29297,423 H 176.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 0.64648,-0.64649 0.64648,0.64649 A 0.50005,0.50005 0 0 0 179.5,424 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.79297 L 179,422.29297 V 411.70703 L 179.70703,411 H 180.5 a 0.50005,0.50005 0 1 0 0,-1 h -1 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.64648,0.64649 -0.64648,-0.64649 A 0.50005,0.50005 0 0 0 177.5,410 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path8743"
+ d="m 31.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 A 0.50005,0.50005 0 0 0 40.5,494 Z m 0.5,1 h 8 v 8 h -8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path8759"
+ d="m 38,496 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z m -3.513672,1.05078 c -0.16529,0.005 -0.314526,0.10024 -0.388672,0.24805 l -2.75,5.5 c -0.148607,0.29892 0.06852,0.64991 0.402344,0.65039 h 5.75 c 0.340259,-0.001 0.55634,-0.36474 0.394531,-0.66406 l -3,-5.5 c -0.08111,-0.14873 -0.238867,-0.23931 -0.408203,-0.23438 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
- id="path13066"
- d="m 174.5,414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v -1 h -2 v -4 h 2 v -1 z m 5.5,0 v 1 h 7.00781 v 4 H 180 v 1 h 7.50781 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path8807"
+ d="M 29.492188,495.99219 A 0.50005,0.50005 0 0 0 29,496.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 30 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 27,498.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 28 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.693;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13176"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g23466"
+ transform="translate(-1.85367e-6,-0.999995)"
+ inkscape:label="X-1">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 14,472 c -0.486111,0 -0.97894,0.16032 -1.363281,0.50195 C 12.252378,472.84359 12,473.375 12,474 v 4 H 8.5 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 4 c 0,0.33333 -0.182083,0.72505 -0.4785156,1.02148 C 7.2250518,483.81792 6.8333333,484 6.5,484 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 2 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 3 c 0.1325988,-2e-5 0.259759,-0.0527 0.3535156,-0.14648 L 11,485.70703 V 486.5 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 5 c 1.777778,0 3.5,-1.46429 3.5,-3.5 v -5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 16 v -4 c 0,-0.625 -0.252378,-1.15641 -0.636719,-1.49805 C 14.97894,472.16032 14.486111,472 14,472 Z m 0,1 c 0.263889,0 0.52106,0.0897 0.699219,0.24805 C 14.877378,473.40641 15,473.625 15,474 v 4 h -0.5 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 19 v 1 H 9 v -1 h 3.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 V 474 c 0,-0.375 0.122622,-0.59359 0.300781,-0.75195 C 13.47894,473.08968 13.736111,473 14,473 Z m -5,8 h 10 v 2.5 c 0,1.46429 -1.277778,2.5 -2.5,2.5 H 16 v -1.5 c 0.0044,-0.28227 -0.225547,-0.51223 -0.507812,-0.50781 C 15.216044,483.9965 14.995681,484.22386 15,484.5 v 1.5 h -3 v -1.5 c -1.7e-4,-0.44532 -0.538517,-0.6683 -0.853516,-0.35352 L 9.2929688,486 H 7 v -1.22266 C 7.4441801,484.6575 7.9061001,484.55093 8.2285156,484.22852 8.682083,483.77495 9,483.16667 9,482.5 Z"
- transform="translate(1.8536743e-6,-4.4999696e-6)"
- id="path5504-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 10.482422,494 c -0.189602,0.007 -0.359053,0.12023 -0.4375,0.29297 l -3.7734376,8.25 c -0.00134,0.003 -0.00264,0.007 -0.00391,0.01 C 6.1587525,502.80633 6,503.10119 6,503.5 c 0,0.83813 0.5261723,1.53471 1.296875,1.92188 0.7707027,0.38715 1.7901254,0.55582 3.023437,0.57226 0.295371,0.003 0.52928,-0.24867 0.503907,-0.54297 9.47e-4,0.0108 -0.01109,-0.37852 -0.01563,-0.70898 -0.0045,-0.33047 -0.0078,-0.6698 -0.0078,-0.74219 0,-1.86768 1.015625,-3.51914 2.519531,-4.4375 0.228366,-0.13928 0.306682,-0.43361 0.177735,-0.66797 L 10.9375,494.25781 C 10.846425,494.09307 10.670549,493.99343 10.482422,494 Z M 18,494 c -1.098638,0 -1.999999,0.90136 -2,2 1e-6,1.09864 0.901362,2 2,2 1.098638,0 1.999999,-0.90136 2,-2 -1e-6,-1.09864 -0.901362,-2 -2,-2 z m -2,6 c -2.203217,0 -3.999999,1.79678 -4,4 10e-7,2.20322 1.796783,4 4,4 2.203217,0 3.999999,-1.79678 4,-4 -1e-6,-2.20322 -1.796783,-4 -4,-4 z m 0,1 c 1.662777,0 2.999999,1.33722 3,3 -1e-6,1.66278 -1.337223,3 -3,3 -1.662777,0 -2.999999,-1.33722 -3,-3 10e-7,-1.66278 1.337223,-3 3,-3 z m -0.541016,1.0332 C 14.658737,502.0332 14,502.69389 14,503.49414 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.25981 0.199172,-0.46094 0.458984,-0.46094 a 0.50005,0.50005 0 1 0 0,-1 z"
+ transform="translate(1.85367e-6,0.999995)"
+ id="path10645"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g6238-2"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="W-26">
+ <g
+ id="g15734-2"
+ style="fill:#ffffff">
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g15738-6">
+ <path
+ inkscape:connector-curvature="0"
+ id="path15684-1"
+ d="m 532.57617,472.98047 a 0.55005501,0.55005501 0 0 0 -0.42383,0.18555 c -0.46657,0.51387 -1.20227,1.13094 -1.20312,2.14257 -10e-4,1.1847 0.85571,2.11411 1.94336,2.91797 1.08765,0.80386 2.47935,1.527 3.84765,2.25782 0.44144,0.23578 0.88242,0.47056 1.3086,0.70312 1.11316,0.60746 2.13512,1.2144 2.84375,1.81836 0.70862,0.60396 1.05894,1.15906 1.05859,1.68359 -4e-4,0.48086 -0.32771,1.0064 -0.79492,1.38086 a 0.55027044,0.55027044 0 1 0 0.6875,0.85938 c 0.65297,-0.52334 1.20625,-1.30182 1.20703,-2.23828 6.6e-4,-0.99421 -0.62031,-1.82029 -1.44531,-2.52344 -0.825,-0.70315 -1.89813,-1.32892 -3.03125,-1.94727 -0.43382,-0.23673 -0.87477,-0.47022 -1.31445,-0.70508 -1.37366,-0.73367 -2.73478,-1.45092 -3.71289,-2.17382 -0.97812,-0.72291 -1.49874,-1.40647 -1.49805,-2.03125 3.7e-4,-0.43907 0.39742,-0.83099 0.91797,-1.4043 a 0.55005501,0.55005501 0 0 0 -0.39063,-0.92578 z m 1.92578,7.9668 a 0.55005501,0.55005501 0 0 0 -0.24804,0.0605 c -0.75,0.375 -1.5313,0.75874 -2.16797,1.28907 -0.63668,0.53032 -1.13681,1.26964 -1.13867,2.20312 0,0.98843 0.53602,1.85319 1.19335,2.41797 a 0.55122854,0.55122854 0 1 0 0.71876,-0.83594 c -0.44771,-0.38466 -0.8125,-1.01968 -0.8125,-1.58203 0.002,-0.56635 0.25363,-0.95243 0.74218,-1.35938 0.48909,-0.40739 1.20703,-0.77343 1.95703,-1.14843 a 0.55005501,0.55005501 0 0 0 -0.24414,-1.04492 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path15690-9"
+ d="m 533.5,475 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 0,9 a 0.50005,0.50005 0 1 0 0,1 h 2 A 0.50005,0.50005 0 0 0 536,484.58008 0.50005,0.50005 0 0 0 536.5,485 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -4 A 0.50005,0.50005 0 0 0 536,484.41992 0.50005,0.50005 0 0 0 535.5,484 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ sodipodi:nodetypes="sssssccccccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="scsccccccccccccccsccccscsscscccccccccscsccssccccccccccccsc" />
+ id="path13640-8-2"
+ d="m 540.5,472.25 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
</g>
<g
- transform="translate(-664,-513.00021)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g8745-3"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g5506-8"
+ transform="translate(-44,63)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="W-25">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 475.25,53 a 0.50005,0.50005 0 0 0 -0.21289,0.04687 l -5.75391,2.708984 a 0.50005,0.50005 0 0 0 -0.28515,0.453125 v 7.292969 a 0.50005,0.50005 0 0 0 0.27539,0.447266 l 6.00195,3.001953 a 0.50005,0.50005 0 0 0 0.44727,0 l 6.00195,-3.001953 A 0.50005,0.50005 0 0 0 482,63.501953 v -6.916015 a 0.50005,0.50005 0 0 0 0,-0.181641 v -0.195313 a 0.50005,0.50005 0 0 0 -0.28711,-0.453125 l -5.75,-2.707031 A 0.50005,0.50005 0 0 0 475.75,53 Z m 0.11133,1 h 0.27734 l 5.00977,2.359375 -5.14844,2.509766 -5.14844,-2.509766 z M 469.99805,57.298828 475,59.738281 v 5.957031 l -5.00195,-2.501953 z M 481,57.300781 v 5.892578 l -5,2.5 v -5.955078 z"
- transform="translate(664,513.00021)"
- id="path8739-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 556.57617,409.98047 a 0.55005501,0.55005501 0 0 0 -0.42383,0.18555 c -0.46657,0.51387 -1.20227,1.13094 -1.20312,2.14257 -10e-4,1.1847 0.85571,2.11411 1.94336,2.91797 1.08765,0.80386 2.47935,1.527 3.84765,2.25782 0.44143,0.23577 0.88243,0.47055 1.3086,0.70312 1.11316,0.60746 2.13512,1.2144 2.84375,1.81836 0.70862,0.60396 1.05894,1.15906 1.05859,1.68359 -4e-4,0.48086 -0.32771,1.0064 -0.79492,1.38086 a 0.55027044,0.55027044 0 1 0 0.6875,0.85938 c 0.65297,-0.52334 1.20625,-1.30182 1.20703,-2.23828 6.6e-4,-0.99421 -0.62031,-1.82029 -1.44531,-2.52344 -0.825,-0.70315 -1.89813,-1.32892 -3.03125,-1.94727 -0.43383,-0.23675 -0.87476,-0.47023 -1.31445,-0.70508 -1.37366,-0.73367 -2.73478,-1.45092 -3.71289,-2.17382 -0.97812,-0.72291 -1.49874,-1.40647 -1.49805,-2.03125 3.7e-4,-0.43907 0.39742,-0.83099 0.91797,-1.4043 a 0.55005501,0.55005501 0 0 0 -0.39063,-0.92578 z"
+ id="path5432-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 565.45508,409.94531 a 0.55005501,0.55005501 0 0 0 -0.31446,0.97071 c 0.44122,0.38244 0.8125,1.03351 0.8125,1.58398 -0.002,0.56635 -0.25363,0.95243 -0.74218,1.35938 -0.48909,0.40739 -1.20703,0.77343 -1.95703,1.14843 a 0.55028291,0.55028291 0 1 0 0.49218,0.98438 c 0.75,-0.375 1.5313,-0.75874 2.16797,-1.28907 0.63668,-0.53032 1.13681,-1.26964 1.13867,-2.20312 0,-0.98667 -0.54281,-1.85212 -1.19335,-2.41602 a 0.55005501,0.55005501 0 0 0 -0.4043,-0.13867 z m -6.95313,8.00196 a 0.55005501,0.55005501 0 0 0 -0.24804,0.0605 c -0.75,0.375 -1.5313,0.75874 -2.16797,1.28907 -0.63668,0.53032 -1.13681,1.26964 -1.13867,2.20312 0,0.98843 0.53602,1.85319 1.19335,2.41797 a 0.55122854,0.55122854 0 1 0 0.71876,-0.83594 c -0.44771,-0.38466 -0.8125,-1.01968 -0.8125,-1.58203 0.002,-0.56635 0.25363,-0.95243 0.74218,-1.35938 0.48909,-0.40739 1.20703,-0.77343 1.95703,-1.14843 a 0.55005501,0.55005501 0 0 0 -0.24414,-1.04492 z"
+ id="path5435-6"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path5484-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 557.5,421 a 0.50005,0.50005 0 1 0 0,1 h 2 A 0.50005,0.50005 0 0 0 560,421.58008 0.50005,0.50005 0 0 0 560.5,422 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -4 A 0.50005,0.50005 0 0 0 560,421.41992 0.50005,0.50005 0 0 0 559.5,421 Z m 0,-9 a 0.50005,0.50005 0 1 0 0,1 h 4 A 0.50005,0.50005 0 0 0 562,412.58008 0.50005,0.50005 0 0 0 562.5,413 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -2 A 0.50005,0.50005 0 0 0 562,412.41992 0.50005,0.50005 0 0 0 561.5,412 Z"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-801.00006,344.99979)"
- id="g13204"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ transform="translate(-574,-936.994)"
+ id="g17429-7-7"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="W-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1339.5,-270 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,3 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,3 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m -7,3 a 0.50004994,0.50004994 0 1 0 0,1 h 13 a 0.50004994,0.50004994 0 1 0 0,-1 z m -0.014,3 a 0.50004994,0.50004994 0 1 0 0,1 h 13.0449 a 0.50004994,0.50004994 0 1 0 0,-1 z"
- id="path13198"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1063.5078,1410.9922 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1.5 1.5 h -1 z"
+ id="path17417-2-4"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1332.4922,-263 c -0.2761,-0.004 -0.4965,-0.23166 -0.4922,-0.50781 v -5.08789 c 0,-0.86662 0.4883,-1.66406 1.2578,-2.08789 0.7696,-0.42387 1.709,-0.42387 2.4785,0 0.7695,0.42383 1.2559,1.22127 1.2559,2.08789 v 5.08789 c 0.01,0.67616 -1.0096,0.67616 -1,0 V -266 H 1333 v 2.49219 c 0,0.28226 -0.2255,0.51222 -0.5078,0.50781 z m 0.5078,-4 h 2.9922 v -1.5957 c 0,-0.49379 -0.2728,-0.95455 -0.7383,-1.21094 -0.4655,-0.25638 -1.0482,-0.25638 -1.5137,0 -0.4655,0.25639 -0.7402,0.71715 -0.7402,1.21094 z"
- id="path13202"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccsccsc" />
+ d="m 1340,1411 v 2 l 1.5,-0.01 1.75,-2 z m 4.5,-0.01 -1.75,2 h 2.75 l 1.7266,-2 z m 4,0 -1.7266,2 2.7266,0.01 c 0.276,-5e-4 0.4995,-0.224 0.5,-0.5 v -1 c -5e-4,-0.276 -0.224,-0.4995 -0.5,-0.5 z m -8.5,4.01 0.01,1.9922 -3.0098,0.01 v 5.4921 c 0,0.2761 0.2239,0.5 0.5,0.5 h 12 c 0.2761,0 0.5,-0.2239 0.5,-0.5 V 1415.5 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z m 2.5156,1 c 0.084,0 0.1663,0.026 0.2383,0.068 l 4.25,2.5 c 0.33,0.1931 0.33,0.6701 0,0.8632 l -4.25,2.5 c -0.3336,0.1966 -0.7545,-0.044 -0.7539,-0.4316 v -5 c -10e-5,-0.2823 0.2334,-0.51 0.5156,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ transform="translate(-273)"
+ id="path17425-5" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 114.49219,166.99219 A 0.50005,0.50005 0 0 0 114,167.5 v 1.5 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 170 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path4913-5-0"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- id="g10431-7"
- transform="matrix(1,0,0,-1,52.999998,288.99725)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
- <g
- transform="translate(62.999998,189)"
- id="g13463"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21550"
+ transform="translate(-21,189)"
+ inkscape:label="W-23">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 221.5,410 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 218.29297,413 H 216.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 221.5,424 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 410.78125 410.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 222 v 12 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 218.5,420 H 217 v -6 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z m 6.75977,1.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27328,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41099,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10286,2.06013 1.1045,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25221,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
- transform="translate(-62.999998,-189)"
- id="path13456"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 471.54297,473 -3,3 h 1.20703 8.20703 l 3,-3 z m 0.41406,1 h 6.58594 l -1,1 h -6.58594 z m 5.54297,3 -9.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 478,477.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,8.00781 h -8 v -8.00195 z"
+ transform="translate(21,-189)"
+ id="path21430"
inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 503,285.04297 -0.85352,0.85351 L 500,288.04297 v 9.41406 l 3,-3 z"
+ id="path21432"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
</g>
<g
- transform="translate(-274.03132,440.00025)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g13513"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g19103-5"
+ transform="rotate(-90,394.5,1587.5)"
+ inkscape:label="W-22">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate"
- d="m 220.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9.64062 a 1.8365096,2.6222708 64.987834 0 0 -1.98242,0.0723 1.8365096,2.6222708 64.987834 0 0 -1.9707,2.68555 1.8365096,2.6222708 64.987834 0 0 2.93554,0.88867 1.8365096,2.6222708 64.987834 0 0 2.00977,-2.18945 A 0.50005,0.50005 0 0 0 221,547.5 V 547.47461 538 h 8 v 7.14062 a 1.8365125,2.6222911 64.988434 0 0 -1.98242,0.0723 1.8365125,2.6222911 64.988434 0 0 -1.9707,2.68555 1.8365125,2.6222911 64.988434 0 0 2.93554,0.88867 1.8365125,2.6222911 64.988434 0 0 2.00977,-2.18945 A 0.50005,0.50005 0 0 0 230,546.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- transform="translate(274.03132,-440.00025)"
- id="ellipse13504"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 457.5,473 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -7.5 -0.5 c -0.5244,0 -1.02378,0.21717 -1.39258,0.57617 -0.3688,0.3592 -0.60742,0.86058 -0.60742,1.42578 V 485 c 10e-5,0.5302 0.21104,1.03916 0.58594,1.41406 C 447.96084,486.78896 448.4698,487 449,487 h 2.5 c 0.2762,0 0.5,-0.2238 0.5,-0.5 v -9 c 0,-0.2761 -0.2238,-0.4999 -0.5,-0.5 H 449 c -0.4523,0 -1,-0.47105 -1,-0.99805 0,-0.2635 0.13823,-0.51462 0.33203,-0.69922 C 448.52543,475.11903 448.775,475 449,475 h 8 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v 5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -4 v 1 h 4 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 460.5,482 H 460 v -5 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 0,9 h 2 v 2 h -2 z"
+ transform="rotate(90,394.5,1587.5)"
+ id="path19040-4"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- id="g12940-5"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g9998"
+ transform="matrix(-1,0,0,1,908,4.69997e-6)"
+ inkscape:label="W-21">
+ <g
+ transform="matrix(-0.615044,0,0,0.615029,510.71,122.71)"
+ id="g13879"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.62592;enable-background:new" />
+ <g
+ id="g9988"
+ style="fill:#ffffff">
+ <path
+ id="path13882"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 478.49219,473.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m -0.49233,3.9922 2.99609,0.006 c 0.2754,6.1e-4 0.49976,0.22265 0.5,0.49805 l 0.004,6.45885 c 0,1.02328 -0.80629,2.03747 -2,2.03711 -1.19534,0 -1.99609,-1.02155 -1.99609,-2.04297 l -0.004,-6.45704 c 1.8e-4,-0.27638 0.22362,-0.50048 0.5,-0.5 z m 1.5,6 a 1,0.99999999 0 0 0 -1,1.00001 1,0.99999999 0 0 0 1,1 1,0.99999999 0 0 0 1,-1 1,0.99999999 0 0 0 -1,-1.00001 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path13884"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 469.49219,474.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m 5.5151,2.99233 c 0.12999,0.002 0.25408,0.0546 0.34596,0.14655 l 1.00065,0.99942 c 0.094,0.094 0.14673,0.22146 0.14655,0.35436 v 4.0001 c 2e-5,0.4458 -0.53925,0.66879 -0.85409,0.35316 l -2.99954,-3.00067 c -0.19472,-0.19518 -0.19472,-0.51115 0,-0.70633 l 2.00009,-2.00004 c 0.0954,-0.0955 0.2254,-0.14835 0.36038,-0.14655 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path13886"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468.49219,483.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m 4.52221,-1.00695 c 0.12731,0.004 0.24847,0.0555 0.33876,0.14535 l 3.00074,3.00066 c 0.31399,0.31533 0.0906,0.8529 -0.35437,0.85288 h -2.99954 c -0.27591,-1.9e-4 -0.49954,-0.22381 -0.49972,-0.49972 v -2.99946 c 7e-5,-0.28163 0.23261,-0.50765 0.51413,-0.49971 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g6171"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="W-20">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 411.49219,577.94727 A 0.50005,0.50005 0 0 0 411,578.45508 v 7 a 0.50005,0.50005 0 1 0 1,0 v -7 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 408.47656,580 a 0.50005,0.50005 0 0 0 -0.22265,0.0684 c -2.54449,1.43695 -3.79437,4.38222 -3.03125,7.16797 0.76312,2.78575 3.34282,4.71875 6.27734,4.71875 2.93452,0 5.51422,-1.933 6.27734,-4.71875 0.76312,-2.78575 -0.48676,-5.73102 -3.03125,-7.16797 a 0.50025967,0.50025967 0 1 0 -0.49218,0.87109 c 2.15894,1.21922 3.20113,3.68764 2.55859,6.03321 -0.64254,2.34557 -2.81597,3.98242 -5.3125,3.98242 -2.49653,0 -4.66996,-1.63685 -5.3125,-3.98242 -0.64254,-2.34557 0.39965,-4.81399 2.55859,-6.03321 A 0.50005,0.50005 0 0 0 408.47656,580 Z"
- transform="translate(1.8536743e-6,-4.4999696e-6)"
- id="path12897-5"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path17287"
+ d="m 405.5,476.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-1e-5 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,1.99219 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 1,0 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 -1,0 -1.99999,-10e-6 -3,0 z m -5,3.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-1e-5 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,1.99219 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.99999,-10e-6 1.99999,10e-6 3,0 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ id="g17301"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;enable-background:new"
+ transform="translate(-41.9997,86.0082)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17299"
+ d="m 452.49219,387 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 V 387.5 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,0 -1.3386,0 -2.00781,0 z m 4.50781,1.98438 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66922,0 -1.33859,0 -2.00781,0 z m -0.49219,4 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00253,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,0 -2.00781,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g10027-7"
- transform="translate(109,-110)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12585"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ transform="matrix(-1,0,0,1,782,4.49997e-6)"
+ inkscape:label="W-19">
<path
- sodipodi:nodetypes="sssssccccccccccccc"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 387.53125,473 C 386.69103,473 386,473.69103 386,474.53125 V 475 h -0.5 c -0.84022,0 -1.5,0.70952 -1.5,1.53125 v 0.9375 c 0,0.82173 0.65978,1.53125 1.5,1.53125 h 0.96875 c 0.1915,0 0.40039,-0.14519 0.61133,-0.21289 l 0.3164,0.31641 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.5,-0.5 a 0.50005,0.50005 0 0 0 -0.70704,0 C 386.86607,477.9269 386.67628,478 386.46875,478 H 385.5 c -0.28602,0 -0.5,-0.22674 -0.5,-0.53125 v -0.9375 C 385,476.22674 385.21398,476 385.5,476 h 0.96875 c 0.02,0 0.0255,2.9e-4 0.0156,0 A 0.50005,0.50005 0 0 0 387,475.48438 c 2.9e-4,0.01 0,0.004 0,-0.0156 v -0.9375 C 387,474.24523 387.24523,474 387.53125,474 h 0.9375 c 0.28603,0 0.53125,0.24521 0.53125,0.53125 v 0.9375 c 0,0.20745 -0.0731,0.39731 -0.10352,0.42773 a 0.50005,0.50005 0 0 0 0,0.70704 l 0.5,0.5 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.31641,-0.3164 C 389.85483,475.86914 390,475.66029 390,475.46875 v -0.9375 C 390,473.69101 389.30896,473 388.46875,473 Z m 6.71289,7.74414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.5,0.5 a 0.50005,0.50005 0 0 0 0.70704,0 c -0.0536,0.0536 0.0619,-0.0282 0.21093,-0.0586 C 395.46351,482.01449 395.64626,482 395.75,482 h 0.75 c 0.30453,0 0.5,0.19546 0.5,0.5 v 0.9375 c 0,0.30451 -0.23248,0.5625 -0.5,0.5625 h -0.9375 c -0.02,0 -0.0255,-2.9e-4 -0.0156,0 a 0.50005,0.50005 0 0 0 -0.46485,0.2832 0.50005,0.50005 0 0 0 -0.0117,0.0215 c -0.002,0.004 -0.003,0.004 -0.006,0.01 -0.006,0.0121 -0.0155,0.0273 -0.0273,0.0566 -0.006,0.0147 -0.012,0.0324 -0.0195,0.0606 -0.007,0.0281 -0.0176,0.13022 -0.0176,0.13086 V 485.5 c 0,0.28602 -0.24525,0.53126 -0.53125,0.53125 H 393.5 c -0.28602,0 -0.5,-0.22674 -0.5,-0.53125 v -0.9375 c 0,-0.19821 0.0977,-0.45261 0.11133,-0.4668 a 0.50005,0.50005 0 0 0 -0.008,-0.69922 l -0.5,-0.5 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 0.31836,0.31836 C 392.14451,484.14157 392,484.36068 392,484.5625 V 485.5 c 0,0.82173 0.65978,1.53125 1.5,1.53125 h 0.96875 C 395.30899,487.03126 396,486.34022 396,485.5 V 485 h 0.5 c 0.85872,0 1.5,-0.74077 1.5,-1.5625 V 482.5 c 0,-0.82174 -0.67829,-1.5 -1.5,-1.5 h -0.75 c -0.17782,0 -0.40107,0.0167 -0.63477,0.0645 -0.0763,0.0156 -0.15636,0.0877 -0.23437,0.10938 l -0.27734,-0.27735 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path12199"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 393.5,473 c -0.82416,0 -1.5,0.67974 -1.5,1.5 v 1 c 0,0.42842 0.21502,0.76851 0.50586,1.03711 l -4.96289,4.96484 C 387.27424,481.21375 386.93403,481 386.50781,481 h -1 c -0.82026,0 -1.5,0.67584 -1.5,1.5 0,0.82416 0.67974,1.5 1.5,1.5 h 1 0.5 v 0.5 1 c 0,0.82026 0.67585,1.5 1.5,1.5 0.82416,0 1.5,-0.67975 1.5,-1.5 v -1 c 0,-0.42841 -0.21502,-0.76851 -0.50586,-1.03711 l 4.96289,-4.96484 C 394.73357,478.78626 395.07378,479 395.5,479 h 1 c 0.82026,0 1.5,-0.67584 1.5,-1.5 0,-0.82416 -0.67974,-1.5 -1.5,-1.5 h -1 -0.5 v -0.5 -1 c 0,-0.82026 -0.67584,-1.5 -1.5,-1.5 z"
+ id="path12208"
inkscape:connector-curvature="0"
- id="path9906-8-8"
- d="m 264.5,688 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ sodipodi:nodetypes="sssccsssscccssssccsssscccss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23341"
+ transform="translate(63,-42)"
+ inkscape:label="W-18">
<g
- id="g9914-5"
- transform="translate(99.99999,195.99938)"
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new">
+ transform="translate(231,-63)"
+ id="g23324"
+ style="opacity:0.6;fill:#ffffff">
+ <g
+ transform="translate(430,-112)"
+ id="g23301"
+ style="fill:#ffffff" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 366.48438,579 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 580 h 1.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -2 v 0.002 c -0.005,0 -0.0101,-0.002 -0.0156,-0.002 z M 363,584 v 7.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 4.5 h -9 v -7 z"
- transform="translate(-208.99999,-85.99938)"
- id="path9910-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 79.570312,578.01758 c -0.797869,-0.038 -1.571767,0.27684 -2.160156,0.86523 l -0.486328,0.48828 c -0.615772,0.57533 -0.93433,1.35407 -0.892578,2.1543 a 0.50005,0.50005 0 1 0 0.998047,-0.0508 c -0.02687,-0.51495 0.155664,-0.98016 0.576172,-1.37305 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 l 0.5,-0.5 c 0.411611,-0.41161 0.889666,-0.59872 1.404296,-0.57422 0.514631,0.0245 1.084383,0.26993 1.638672,0.82422 0.554795,0.5548 0.809544,1.13546 0.837891,1.65235 0.02835,0.51688 -0.152405,0.9848 -0.574219,1.3789 a 0.50005,0.50005 0 0 0 -0.01367,0.0117 l -0.5,0.5 c -0.412129,0.41213 -0.876932,0.60352 -1.396484,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.780667,0 1.524905,-0.31788 2.103516,-0.89649 l 0.488281,-0.48828 c 0.617686,-0.57711 0.936606,-1.36125 0.892578,-2.16406 -0.04403,-0.80281 -0.435654,-1.60948 -1.130859,-2.30469 -0.695711,-0.69571 -1.499006,-1.07724 -2.296876,-1.11523 z m -0.830078,3.72851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z m -6.179687,3.27149 c -0.807524,-0.0482 -1.595401,0.26944 -2.175781,0.89062 l -0.488282,0.48828 c -0.588388,0.58839 -0.903228,1.36034 -0.865234,2.15821 0.03799,0.79787 0.419524,1.60311 1.115234,2.29883 0.695206,0.6952 1.503832,1.08487 2.306641,1.1289 0.802809,0.044 1.584996,-0.27294 2.162109,-0.89062 l 0.488282,-0.48828 C 75.682126,590.0249 76,589.28067 76,588.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.191386,0.98436 -0.603516,1.39648 l -0.5,0.5 a 0.50005,0.50005 0 0 0 -0.01172,0.0117 c -0.394107,0.42182 -0.860068,0.60452 -1.376954,0.57618 -0.516885,-0.0283 -1.099502,-0.2831 -1.654296,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.822266,-1.63867 -0.02451,-0.51463 0.160654,-0.99268 0.572266,-1.40429 l 0.5,-0.5 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 c 0.39634,-0.4242 0.866283,-0.60725 1.386719,-0.57618 a 0.50005,0.50005 0 1 0 0.05859,-0.99804 z m 1.679687,1.22851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z"
+ id="path23322"
inkscape:connector-curvature="0" />
</g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 301.49414,515.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 312.29297,528 H 309.25 a 0.50005,0.50005 0 1 0 0,1 h 4.18945 A 0.50005,0.50005 0 0 0 314,528.43945 V 524.25 a 0.50005,0.50005 0 1 0 -1,0 v 3.04297 l -11.14648,-11.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path23333"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(365,4.4999696e-6)"
- id="g13349"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g37788"
+ inkscape:label="W-17"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 349.5,578 c -1.48507,0 -2.8535,0.46731 -3.86133,1.33594 C 344.63084,580.20456 344,581.48473 344,583 v 3 c 0,0.83333 -0.007,1.35913 -0.11133,1.78711 -0.10481,0.42798 -0.303,0.80502 -0.77929,1.40039 A 0.50005,0.50005 0 0 0 343,589.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 1 a 0.50005,0.50005 0 0 0 0.33008,-0.12305 l 1.64648,-1.44336 1.41992,1.41993 A 0.50005,0.50005 0 0 0 349.25,592 h 0.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1.39648,-1.39649 1.39648,1.39649 A 0.50005,0.50005 0 0 0 353.25,592 h 1.25 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -1 -5.5 c 0,-1.51527 -0.63084,-2.79544 -1.63867,-3.66406 C 352.3535,578.46731 350.98507,578 349.5,578 Z m 0,1 c 1.27493,0 2.40681,0.40238 3.20898,1.09375 C 353.51116,580.78512 354,581.75527 354,583 v 5.5 1 1.5 h -0.54297 l -1.60351,-1.60352 a 0.50005,0.50005 0 0 0 -0.70704,0 L 349.54297,591 h -0.0859 l -1.60351,-1.60352 a 0.50005,0.50005 0 0 0 -0.6836,-0.0234 L 345.3125,591 H 344.5 344 v -1.38867 c 0.42104,-0.55984 0.73249,-1.05984 0.86133,-1.58594 C 345.00652,587.43254 345,586.83333 345,586 v -3 c 0,-1.24473 0.48884,-2.21488 1.29102,-2.90625 C 347.09319,579.40238 348.22507,579 349.5,579 Z m -1.00586,2.99219 a 0.50005,0.50005 0 0 0 -0.34766,0.15429 l -0.64648,0.64649 -0.64648,-0.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.64648,-0.64649 0.64648,0.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 0.64649,-0.64648 a 0.50005,0.50005 0 0 0 -0.35938,-0.86133 z m 4,0 a 0.50005,0.50005 0 0 0 -0.34766,0.15429 l -0.64648,0.64649 -0.64648,-0.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.64648,-0.64649 0.64648,0.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 0.64649,-0.64648 a 0.50005,0.50005 0 0 0 -0.35938,-0.86133 z"
- transform="translate(-365,-4.4999696e-6)"
- id="path13343"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 352.72656,472.9707 c -0.84514,-0.0154 -1.69148,0.28718 -2.33008,0.92578 l -2.13476,2.13477 c -1.14247,-0.0826 -2.16028,-0.0359 -2.98047,0.30273 -0.89973,0.37145 -1.59595,1.03428 -2.08008,1.92774 C 342.23291,480.04863 342,482.7268 342,486.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 c 3.7729,0 6.45106,-0.23075 8.23828,-1.19727 0.89361,-0.48326 1.5563,-1.17766 1.92774,-2.07812 0.33865,-0.82099 0.38541,-1.84087 0.30273,-2.98633 l 2.13477,-2.13476 c 1.27714,-1.27719 1.21033,-3.38733 -0.0547,-4.65235 -0.63251,-0.63254 -1.47713,-0.96507 -2.32227,-0.98047 z m -0.01,1.00391 c 0.59016,0.0124 1.18356,0.24213 1.625,0.68359 0.88286,0.88287 0.92532,2.36759 0.0547,3.23828 l -2.25,2.25 a 0.50004997,0.50004997 0 0 0 -0.14453,0.4043 c 0.11985,1.19116 0.0231,2.10252 -0.26172,2.79297 -0.28481,0.69045 -0.74712,1.18455 -1.47851,1.58008 -1.27506,0.68955 -3.50366,0.96361 -6.50586,1.02734 l 3.10352,-3.10351 c 0.19538,0.094 0.41106,0.15234 0.64062,0.15234 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.22956 0.0584,0.44524 0.15234,0.64062 l -3.10351,3.10352 c 0.0645,-3.00197 0.34215,-5.23052 1.0332,-6.50586 0.3964,-0.73154 0.8902,-1.19371 1.58008,-1.47851 0.68987,-0.28481 1.59959,-0.38153 2.78711,-0.26172 a 0.50004997,0.50004997 0 0 0 0.4043,-0.14453 l 2.25,-2.25 c 0.43534,-0.43536 1.02312,-0.64126 1.61328,-0.62891 z"
+ id="path8087-0"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 291.98438,431.0625 c -1.31822,0 -2.69153,0.28723 -3.69727,1.29297 a 1.0001,1.0001 0 1 0 1.41406,1.41406 c 0.49426,-0.49426 1.2483,-0.70703 2.28321,-0.70703 a 1.0001,1.0001 0 1 0 0,-2 z m -7.24024,3.04297 c -0.74589,-0.0115 -1.46694,0.0868 -2.13086,0.30664 -1.32784,0.43972 -2.4721,1.53683 -2.61719,3.06055 -0.19518,2.0499 0.80702,3.49399 1.02735,4.3457 0.14607,0.56468 0.0225,0.72298 -0.18164,0.91797 -0.20413,0.19499 -0.61247,0.33203 -0.84961,0.33203 a 1.0001,1.0001 0 1 0 0,2 c 0.76285,0 1.57391,-0.25956 2.23047,-0.88672 0.65655,-0.62715 1.03297,-1.71849 0.73632,-2.86523 -0.37187,-1.43756 -1.0944,-2.37562 -0.97265,-3.6543 0.0682,-0.71615 0.4403,-1.08149 1.25586,-1.35156 0.81556,-0.27008 2.03005,-0.27431 3.23242,0.0684 1.20237,0.34267 2.38417,1.01511 3.21875,1.95703 0.83458,0.94191 1.35114,2.12713 1.29297,3.68945 -0.0218,0.58526 -0.18864,0.77371 -0.37305,0.89453 -0.18441,0.12083 -0.50228,0.18156 -0.91016,0.0723 -0.65709,-0.17607 -1.01294,-0.58503 -1.30078,-1.30274 -0.28784,-0.7177 -0.4082,-1.70364 -0.4082,-2.62695 a 1.0001,1.0001 0 1 0 -2,0 c 0,1.07669 0.11104,2.27463 0.55078,3.37109 0.43975,1.09647 1.30771,2.13309 2.64063,2.49024 0.84212,0.22565 1.76567,0.1664 2.52343,-0.33008 0.75729,-0.49617 1.23505,-1.42269 1.2754,-2.49219 v -0.002 c 0.0762,-2.06159 -0.66061,-3.80964 -1.79493,-5.08984 -1.1347,-1.28064 -2.63964,-2.11968 -4.16601,-2.55469 -0.76319,-0.21751 -1.53341,-0.33806 -2.2793,-0.34961 z"
- id="path8292"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 495.50391,451.99219 c -1.93006,0 -3.50391,1.57292 -3.50391,3.5 v 2 c 0,0.41666 0.19292,0.77495 0.45898,1.04101 0.26607,0.26607 0.62435,0.45899 1.04102,0.45899 a 0.50005,0.50005 0 1 0 0,-1 c -0.0833,0 -0.22505,-0.0571 -0.33398,-0.16602 C 493.05708,457.71724 493,457.57552 493,457.49219 v -2 c 0,-1.38664 1.11314,-2.5 2.50391,-2.5 h 1.0039 c 1.39077,0 2.50196,1.11336 2.50196,2.5 v 2 c 0,0.0833 -0.0571,0.22505 -0.16602,0.33398 -0.10893,0.10893 -0.25065,0.16602 -0.33398,0.16602 a 0.50005,0.50005 0 1 0 0,1 c 0.41666,0 0.77494,-0.19292 1.04101,-0.45899 0.26607,-0.26606 0.45899,-0.62435 0.45899,-1.04101 v -2 c 0,-1.92708 -1.57191,-3.5 -3.50196,-3.5 z m 3.94921,7.41406 a 0.50005,0.50005 0 0 0 -0.48632,0.33203 c -0.17381,0.48217 -0.35767,1.04392 -0.75391,1.48047 -0.39624,0.43655 -0.98986,0.78906 -2.17578,0.78906 -1.18761,0 -1.78805,-0.34711 -2.19141,-0.77929 -0.40336,-0.43219 -0.59802,-0.98975 -0.78515,-1.47266 a 0.50005,0.50005 0 0 0 -0.67578,-0.27344 c -0.97162,0.44606 -1.78522,0.89986 -2.38868,1.45508 C 489.39264,461.49272 489,462.19074 489,462.99219 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13.00977 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.5 c 0,-0.79711 -0.38431,-1.49976 -0.98243,-2.06446 -0.59811,-0.56469 -1.40897,-1.02891 -2.38086,-1.47461 a 0.50005,0.50005 0 0 0 -0.19336,-0.0469 z m 0.17579,1.19922 c 0.68529,0.34567 1.33558,0.69455 1.71289,1.05078 0.46505,0.43906 0.66797,0.84399 0.66797,1.33594 v 2 H 490 v -2 c 0,-0.49365 0.20477,-0.8868 0.67383,-1.31836 0.38208,-0.35154 1.03995,-0.69804 1.73437,-1.04492 0.1643,0.40983 0.28954,0.83601 0.70508,1.28125 0.58146,0.623 1.5239,1.09765 2.92383,1.09765 1.40162,0 2.34196,-0.48473 2.91601,-1.11719 0.40651,-0.44786 0.51938,-0.87307 0.67579,-1.28515 z"
- id="path6745-8"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 134.50977,472.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5039 c 0.0205,0.58311 0.0403,1.03618 -0.0488,1.24805 -0.22838,0.54301 -0.5609,0.82668 -1.00781,1.10937 -0.44691,0.28269 -1.00733,0.53131 -1.53711,0.97461 -0.52977,0.4433 -1.00108,1.10059 -1.22656,2.08789 -0.22548,0.9873 -0.2332,2.29903 0.0625,4.16406 0.0385,0.24311 0.24801,0.42203 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.2745 0.49414,-0.57812 -0.36883,-2.32606 -0.21493,-3.6368 0.12305,-4.40821 0.33798,-0.7714 0.85304,-1.08606 1.49804,-1.45508 0.645,-0.36901 1.43565,-0.7809 1.90821,-1.70703 0.47255,-0.92613 0.59571,-2.25921 0.21289,-4.4375 C 145.70043,474.17484 145.49284,474.0002 145.25,474 h -7.24023 v -0.50586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 3,1.00586 h 6.78125 c 0.25456,1.74951 0.14487,2.81594 -0.15235,3.39844 -0.3247,0.63637 -0.84774,0.91198 -1.51367,1.29297 -0.66593,0.38098 -1.46183,0.87882 -1.91797,1.91992 -0.41222,0.94085 -0.49675,2.35477 -0.23633,4.38867 h -7.73437 c -0.19264,-1.47462 -0.23076,-2.65205 -0.0684,-3.36328 0.18281,-0.80045 0.49635,-1.21142 0.89258,-1.54297 0.39622,-0.33155 0.90291,-0.56523 1.42968,-0.89844 0.52678,-0.33321 1.07351,-0.7985 1.39649,-1.5664 0.22021,-0.52359 0.17686,-1.05487 0.13867,-1.63477 h 0.48438 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z"
- id="path13566"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccscsccccccccccccccccccccccccccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 160.5,431 a 1.5,1.5 0 0 0 -1.5,1.5 1.5,1.5 0 0 0 0.0879,0.5 h -4.56836 a 1.50015,1.50015 0 1 0 0,3 H 158 v 1.94922 c -1.31983,1.3363 -2.47353,2.76999 -2.9707,5.25586 a 1.50015,1.50015 0 1 0 2.9414,0.58984 c 0.37009,-1.85045 0.99513,-2.60285 2.0293,-3.6289 1.03417,1.02605 1.65921,1.77845 2.0293,3.6289 a 1.50015,1.50015 0 1 0 2.9414,-0.58984 c -0.49717,-2.48587 -1.65087,-3.91956 -2.9707,-5.25586 V 436 h 3.48047 a 1.50015,1.50015 0 1 0 0,-3 h -2.53711 c -0.0387,0.18925 -0.094,0.37697 -0.17774,0.55664 C 162.35553,434.4361 161.47038,435 160.5,435 a 0.50005,0.50005 0 1 1 0,-1 1.5,1.5 0 0 0 0.41406,-0.0586 c 0.009,-0.002 0.0169,-0.005 0.0254,-0.008 a 1.5,1.5 0 0 0 0.35157,-0.16211 c 0.006,-0.004 0.0133,-0.006 0.0195,-0.01 a 1.5,1.5 0 0 0 0.004,-0.002 1.5,1.5 0 0 0 0.29102,-0.25 c 0.009,-0.0103 0.0202,-0.0187 0.0293,-0.0293 a 1.5,1.5 0 0 0 0.21484,-0.33008 c 0.003,-0.006 0.007,-0.01 0.01,-0.0156 0.002,-0.005 0.004,-0.0104 0.006,-0.0156 A 1.5,1.5 0 0 0 162,432.5 1.5,1.5 0 0 0 160.5,431 Z"
- id="path13634"
- inkscape:connector-curvature="0"
- inkscape:export-filename="blender_icons.png"
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 428.49023,603.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 l 4,4 a 0.50005,0.50005 0 0 0 0.70704,0 l 4,-4 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -3.64648,3.64649 -3.64648,-3.64649 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
- id="path13549"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 410.49414,601.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 3.64649,3.64648 -3.64649,3.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path13551"
- inkscape:connector-curvature="0" />
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(-21)"
+ id="g12839"
+ inkscape:label="W-16">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 353.13867,473.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -0.75,0.75 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.75,-0.75 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -3.39644,2.7168 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -6.25,6.25 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 l 6.25,-6.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22605,-0.14856 -0.36137,-0.14648 z"
+ id="path12837"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccscccccccccccccccc" />
+ </g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- transform="rotate(-180,307.00525,417)"
- id="g13597"
+ id="g7388-6"
+ transform="translate(731,-238)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="W-14">
+ <rect
+ transform="scale(-1,1)"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.8;marker:none;enable-background:accumulate"
+ id="rect7384-9"
+ width="16"
+ height="16"
+ x="437"
+ y="710" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 289.50391,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -0.99414 c -1.17529,0 -2.25213,0.41841 -2.88477,1.18164 -0.28029,0.32895 -0.0395,0.83456 0.39258,0.82422 0.14712,-0.004 0.28501,-0.0726 0.37695,-0.1875 C 286.27001,413.36537 287.08306,413 288.00977,413 h 0.99414 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -4.58594,3.95898 c -1.10666,0.0478 -2.07229,0.36866 -2.82031,0.91211 -0.99737,0.72461 -1.58789,1.85424 -1.58789,3.12891 v 1 h -1.50586 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.49414 v -1 c 0,-0.97533 0.41802,-1.76979 1.17578,-2.32031 0.75777,-0.55053 1.87662,-0.84701 3.26562,-0.6836 1.98998,0.23412 3.41358,1.22814 4.10352,2.33203 0.68994,1.10391 0.68215,2.23778 -0.14844,3.06836 -0.83795,0.83796 -1.98844,0.89361 -3.08398,0.26368 -1.09554,-0.62994 -2.08242,-1.9799 -2.31641,-3.96875 -0.0504,-0.69579 -1.10528,-0.57121 -0.99219,0.11718 0.26601,2.26115 1.40414,3.91119 2.8086,4.71875 0.70223,0.40379 1.48456,0.58895 2.23632,0.52735 0.75176,-0.0616 1.47366,-0.37015 2.05469,-0.95117 1.16941,-1.16942 1.16162,-2.91055 0.28906,-4.30664 -0.87256,-1.3961 -2.57396,-2.52709 -4.83398,-2.79297 -0.39761,-0.0468 -0.78151,-0.0608 -1.15039,-0.0449 z M 280.00391,421 h 2 v 2 h -2 z"
- transform="rotate(180,307.00525,417)"
- id="path13595"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -447.96289,710.98828 a 1.0001,1.0001 0 0 0 -0.83789,0.41211 c -3.30626,4.40835 -3.18183,10.96743 -3.18555,12.58399 a 1.0001,1.0001 0 1 0 2,0.006 c 0.004,-1.64212 0.0934,-7.79897 2.78711,-11.39062 a 1.0001,1.0001 0 0 0 -0.76367,-1.61133 z m 4.97461,3.00195 a 1.0001,1.0001 0 0 0 -0.69727,0.28125 c -2.25424,2.12239 -3.3739,3.98924 -3.89062,5.64258 C -448.0929,721.56741 -448,722.96385 -448,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-1.13631 -0.0696,-2.20308 0.33203,-3.48828 0.40167,-1.28521 1.28135,-2.83224 3.35352,-4.7832 a 1.0001,1.0001 0 0 0 -0.67383,-1.73829 z m 3.94531,4.00782 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 C -441.66808,718.54973 -444,720.82862 -444,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-2.17354 1.66808,-3.68979 3.21094,-4.02148 a 1.0001,1.0001 0 0 0 -0.25391,-1.98047 z"
+ id="path7133-7"
inkscape:connector-curvature="0" />
</g>
- <rect
- style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- id="rect13550"
- width="16"
- height="16"
- x="488.00128"
- y="430.00018"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
<g
+ id="g24294"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13226"
- transform="translate(-189,84.000005)">
+ transform="translate(84,110)"
+ inkscape:label="W-13">
<path
- style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;marker:none;enable-background:accumulate"
- d="m 285,536 -0.15625,1.90625 c -0.6231,0.14227 -1.07677,0.25145 -1.59375,0.59375 l -1.75,-1.5 -1.5,1.5 1.5,1.75 c -0.34229,0.51699 -0.45148,0.97065 -0.59375,1.59375 L 279,542 v 1 1 l 1.90625,0.15625 c 0.14227,0.6231 0.25145,1.07677 0.59375,1.59375 l -1.5,1.75 1.5,1.5 1.75,-1.5 c 0.51699,0.34229 0.97065,0.45148 1.59375,0.59375 L 285,550 h 1 1 l 0.15625,-1.90625 c 0.6231,-0.14227 1.07677,-0.25145 1.59375,-0.59375 l 1.75,1.5 1.5,-1.5 -1.5,-1.75 c 0.34229,-0.51699 0.45148,-0.97065 0.59375,-1.59375 L 293,544 v -1 -1 l -1.90625,-0.15625 C 290.95148,541.22065 290.8423,540.76698 290.5,540.25 l 1.5,-1.75 -1.5,-1.5 -1.75,1.5 c -0.51699,-0.34229 -0.97065,-0.45148 -1.59375,-0.59375 L 287,536 h -1 z m 1,5 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 -1.11641,0 -2,-0.88359 -2,-2 0,-1.11641 0.88359,-2 2,-2 z"
- transform="translate(189,-84.000005)"
- id="path52982-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 185.48047,363.06055 c -0.59845,-0.12754 -1.28387,0.0442 -1.90039,0.56445 -0.53509,0.4515 -1.05167,1.28657 -1.57813,2.31055 -0.51724,-1.01439 -1.02781,-1.84334 -1.5625,-2.29102 -0.61731,-0.51686 -1.30605,-0.68638 -1.90625,-0.56055 -1.20039,0.25167 -1.95047,1.38331 -2.44726,2.14258 a 0.50005,0.50005 0 1 0 0.83594,0.54688 c 0.467,-0.71375 1.196,-1.58087 1.8164,-1.71094 0.3102,-0.065 0.61722,-0.0219 1.0586,0.34766 0.44137,0.36955 0.97784,1.09019 1.54101,2.30078 A 0.50005,0.50005 0 0 0 181.79102,367 h 0.42187 a 0.50005,0.50005 0 0 0 0.45313,-0.28711 c 0.57516,-1.22093 1.11551,-1.9484 1.55859,-2.32227 0.44308,-0.37386 0.74393,-0.41807 1.04687,-0.35351 0.60589,0.12912 1.32737,1.00382 1.80664,1.73633 a 0.50005,0.50005 0 1 0 0.83594,-0.54688 c -0.50216,-0.76749 -1.23669,-1.91095 -2.43359,-2.16601 z M 176.5,370.0332 c -0.89413,-0.17031 -1.70729,0.35696 -2.38477,1.16992 a 0.50064923,0.50064923 0 1 0 0.76954,0.64063 c 0.57252,-0.68703 1.00936,-0.90781 1.42773,-0.82813 0.41837,0.0797 1.03934,0.56817 1.75781,1.76563 a 0.50005,0.50005 0 0 0 0.85938,0 c 0.71847,-1.19746 1.33944,-1.68594 1.75781,-1.76563 0.41837,-0.0797 0.85521,0.1411 1.42773,0.82813 a 0.50064923,0.50064923 0 1 0 0.76954,-0.64063 c -0.67748,-0.81296 -1.49064,-1.34023 -2.38477,-1.16992 -0.73042,0.13913 -1.36539,0.76726 -2,1.66797 -0.63461,-0.90071 -1.26958,-1.52884 -2,-1.66797 z m 6.18555,4.01758 c -0.21091,-0.0352 -0.44348,0.01 -0.63282,0.10938 -0.37867,0.19867 -0.6452,0.54404 -0.97656,1.07422 a 0.50018582,0.50018582 0 1 0 0.84766,0.53124 c 0.29364,-0.46982 0.52711,-0.68574 0.59375,-0.7207 0.0333,-0.0175 0.0107,-0.007 0.004,-0.008 -0.007,-0.001 0.0186,0.003 0.0781,0.0488 0.23799,0.1848 0.74712,0.97866 1.54492,1.78906 a 0.50005,0.50005 0 0 0 0.71094,0 c 0.7978,-0.8104 1.30693,-1.60426 1.54492,-1.78906 0.0595,-0.0462 0.0849,-0.05 0.0781,-0.0488 -0.007,10e-4 -0.0294,-0.01 0.004,0.008 0.0666,0.035 0.30011,0.25088 0.59375,0.7207 a 0.50018582,0.50018582 0 1 0 0.84766,-0.53124 c -0.33136,-0.53018 -0.59789,-0.87555 -0.97656,-1.07422 -0.18934,-0.0993 -0.42191,-0.14455 -0.63282,-0.10938 -0.2109,0.0352 -0.38371,0.13261 -0.52734,0.24414 -0.45025,0.34963 -0.83062,0.92221 -1.28711,1.47266 -0.45649,-0.55045 -0.83686,-1.12303 -1.28711,-1.47266 -0.14363,-0.11153 -0.31644,-0.20897 -0.52734,-0.24414 z"
+ id="path24292"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.14285719;enable-background:new"
- id="g13938"
- transform="matrix(0.875,0,0,0.875,-254.625,-304.87495)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3.42857146;marker:none;enable-background:accumulate"
- id="rect13853"
- width="16"
- height="16"
- x="299"
- y="408.99994" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12888"
+ transform="translate(-1.85367e-6,21)"
+ inkscape:label="W-12">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 241.48438,452 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z M 243,452 v 5 h -5 v 1.5 c 2e-5,0.1326 0.0527,0.25976 0.14648,0.35352 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 1.64648,1.64649 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 0.64648,0.64649 1,1 c 0.315,0.31479 0.85335,0.0918 0.85352,-0.35352 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 4.49219,9 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -2.64648,2.64649 -1.64648,-1.64649 c -0.19527,-0.19519 -0.51177,-0.19519 -0.70704,0 l -2.64648,2.64649 -1.64648,-1.64649 c -0.315,-0.31479 -0.85335,-0.0918 -0.85352,0.35352 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.00781 9.99219 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -2e-5,-0.1326 -0.0527,-0.25976 -0.14648,-0.35352 l -1,-1 -1,-1 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
+ id="path14234"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccc" />
+ </g>
+ <g
+ id="g37779"
+ inkscape:label="W-11"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 218.5,472 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m -2,2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 12 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 217 v -1 h 2.50781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 477 H 229 v 2.5 c 0,0.525 -0.14815,0.87861 -0.38477,1.11523 C 228.37862,480.85186 228.02499,481 227.5,481 h -1 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.5 h -4.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 482 h 0.5 c 0.72501,0 1.37138,-0.22683 1.82227,-0.67773 C 229.77315,480.87137 230,480.225 230,479.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 224 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 6 v 1 h -6 z m 4,3 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z"
+ id="path12120"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
+ transform="matrix(0,1,1,0,37.9999,363)"
+ id="g11084"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14058"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="W-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 451.5,536 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 8 h -8 z"
- id="path14208"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 202,473 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m -4,4 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m 8,0 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m -4,1 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m 0,3 c 1.09865,0 2,0.90135 2,2 0,1.09865 -0.90135,2 -2,2 -1.09865,0 -2,-0.90135 -2,-2 0,-1.09865 0.90135,-2 2,-2 z m 4.96484,4 a 0.50005,0.50005 0 0 0 -0.47265,0.49219 A 0.50005,0.50005 0 0 0 207,487 h 0.5 c 0.83333,0 1.14655,0.35353 1.64648,0.85352 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 C 209.35355,486.64647 208.66667,486 207.5,486 H 207 a 0.50005,0.50005 0 0 0 -0.0352,0 z"
+ transform="matrix(0,1,1,0,-363,-37.9999)"
+ id="circle11078"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(539.993,-999)"
+ id="g36643-9"
+ style="display:inline;enable-background:new"
+ inkscape:label="W-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 449.49219,537.99219 A 0.50005,0.50005 0 0 0 449,538.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 450 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 447,540.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path14212"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -359.5,1474 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path36414-1"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 460.48438,536 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -9,9 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z"
- id="path14252"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -364.5,1473 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z"
+ id="circle36422-1"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
+ sodipodi:nodetypes="sssssssssssssss"
+ inkscape:label="circle36422-1" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 414.55664,159.95508 a 0.50005,0.50005 0 0 0 -0.47461,0.61133 L 414.38867,162 h -4.70898 l 0.30859,-1.39062 a 0.5003812,0.5003812 0 1 0 -0.97656,-0.21876 L 408.6543,162 H 406.5 a 0.50005,0.50005 0 1 0 0,1 h 1.93164 l -0.66602,3 H 405.5 a 0.50005,0.50005 0 1 0 0,1 h 2.04297 l -0.53125,2.39062 a 0.5003812,0.5003812 0 1 0 0.97656,0.21876 L 408.56836,167 h 6.88672 l 0.55664,2.60352 a 0.50005,0.50005 0 1 0 0.97656,-0.20704 L 416.47656,167 H 418.5 a 0.50005,0.50005 0 1 0 0,-1 h -2.23633 l -0.63867,-3 h 1.875 a 0.50005,0.50005 0 1 0 0,-1 h -2.08984 l -0.34961,-1.64258 a 0.50005,0.50005 0 0 0 -0.50391,-0.40234 z M 409.45703,163 h 5.14453 l 0.64063,3 h -6.45117 z"
- id="path13985"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14370"
- transform="translate(20.999998,4.4999696e-6)">
+ id="g37791"
+ inkscape:label="W-8"
+ style="display:inline;enable-background:new">
<path
- id="rect14323"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 141.51562,82 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 145.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 145.5,82 Z m 0.5,1 H 145 v 4 h -2.98438 z m -9.5,-1 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 136.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 136.5,82 Z m 0.5,1 H 136 v 4 h -2.98438 z m 8.5,-9 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 145.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 145.5,74 Z m 0.5,1 H 145 v 4 h -2.98438 z m -9.5,-1 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 136.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 136.5,74 Z m 0.5,1 H 136 v 4 h -2.98438 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 157.49219,472.99219 A 0.50005,0.50005 0 0 0 157,473.5 v 8.79297 l -3.85352,3.85351 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 157.70703,483 H 166.5 a 0.50005,0.50005 0 1 0 0,-1 H 158 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22612"
inkscape:connector-curvature="0" />
</g>
<g
- id="g6448"
- style="fill:#ffffff">
- <path
- d="m 103,78.000008 h 1 v 1 h -1 z m 0,-3 h 1 v 1 h -1 z m -8,3 h 1 v 1 h -1 z m 0,3 h 1 v 1 h -1 z m 0,-6 h 1 v 1 h -1 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="rect14452"
- inkscape:connector-curvature="0" />
+ id="g37785"
+ inkscape:label="W-7"
+ style="display:inline;enable-background:new">
<path
- d="m 98.515625,74 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 6 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 H 101.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -6 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 101 v 2 h -1.984375 z m 0,3 H 101 v 2 h -1.984375 z m -8.5,-4 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 12 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 H 93.5 c 0.276131,-2.8e-5 0.499972,-0.223869 0.5,-0.5 v -12 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z m 0.5,1 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path14479"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 134.50977,472.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5039 c 0.0205,0.58311 0.0403,1.03618 -0.0488,1.24805 -0.22838,0.54301 -0.5609,0.82668 -1.00781,1.10937 -0.44691,0.28269 -1.00733,0.53131 -1.53711,0.97461 -0.52977,0.4433 -1.00108,1.10059 -1.22656,2.08789 -0.22548,0.9873 -0.2332,2.29903 0.0625,4.16406 0.0385,0.24311 0.24801,0.42203 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.2745 0.49414,-0.57812 -0.36883,-2.32606 -0.21493,-3.6368 0.12305,-4.40821 0.33798,-0.7714 0.85304,-1.08606 1.49804,-1.45508 0.645,-0.36901 1.43565,-0.7809 1.90821,-1.70703 0.47255,-0.92613 0.59571,-2.25921 0.21289,-4.4375 C 145.70043,474.17484 145.49284,474.0002 145.25,474 h -7.24023 v -0.50586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 3,1.00586 h 6.78125 c 0.25456,1.74951 0.14487,2.81594 -0.15235,3.39844 -0.3247,0.63637 -0.84774,0.91198 -1.51367,1.29297 -0.66593,0.38098 -1.46183,0.87882 -1.91797,1.91992 -0.41222,0.94085 -0.49675,2.35477 -0.23633,4.38867 h -7.73437 c -0.19264,-1.47462 -0.23076,-2.65205 -0.0684,-3.36328 0.18281,-0.80045 0.49635,-1.21142 0.89258,-1.54297 0.39622,-0.33155 0.90291,-0.56523 1.42968,-0.89844 0.52678,-0.33321 1.07351,-0.7985 1.39649,-1.5664 0.22021,-0.52359 0.17686,-1.05487 0.13867,-1.63477 h 0.48438 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z"
+ id="path13566"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccc" />
+ sodipodi:nodetypes="ccccccscsccccccccccccccccccccccccccccccccc" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14591">
+ id="g6505"
+ transform="translate(84,-21)"
+ inkscape:label="W-6">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 9.25,74 a 0.50005,0.50005 0 0 0 -0.4765625,0.351562 l -2.75,8.820313 A 0.50005,0.50005 0 0 0 6,83.320312 v 0.173829 a 0.50005,0.50005 0 1 0 1,0 v -0.09766 L 7.7460938,81 A 0.50005,0.50005 0 0 0 7.75,81 h 3.5 a 0.50005,0.50005 0 0 0 0.0039,0 L 12,83.396484 v 0.09766 a 0.50005,0.50005 0 1 0 1,0 v -0.173829 a 0.50005,0.50005 0 0 0 -0.02344,-0.148437 l -2.75,-8.820313 A 0.50005,0.50005 0 0 0 9.75,74 Z M 9.5,75.375 10.941406,80 H 8.0585938 Z"
- id="path14584"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 31.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 A 0.50005,0.50005 0 0 0 40.5,494 Z m 0.5,1 h 8 v 8 h -8 z"
+ id="path6499"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 14.5,79 a 0.50005,0.50005 0 1 0 0,1 H 19 v 0.08008 l -4.896484,6.365234 A 0.50005,0.50005 0 0 0 14,86.75 v 0.75 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 1 0 0,-1 H 15 v -0.08008 l 4.896484,-6.365234 A 0.50005,0.50005 0 0 0 20,80.25 V 79.5 A 0.50005,0.50005 0 0 0 19.5,79 Z"
- id="path14589"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 38,496 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z m -3.513672,1.05078 c -0.16529,0.005 -0.314526,0.10024 -0.388672,0.24805 l -2.75,5.5 c -0.148607,0.29892 0.06852,0.64991 0.402344,0.65039 h 5.75 c 0.340259,-0.001 0.55634,-0.36474 0.394531,-0.66406 l -3,-5.5 c -0.08111,-0.14873 -0.238867,-0.23931 -0.408203,-0.23438 z"
+ id="path6501"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.693;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 29.492188,495.99219 A 0.50005,0.50005 0 0 0 29,496.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 30 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 27,498.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 28 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ id="path6503"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 69.5,74 a 0.50005,0.50005 0 1 0 0,1 h 13 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14593"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 30.474609,74.994141 a 0.50004997,0.50004997 0 0 0 -0.40625,0.757812 L 33.128906,81 H 27.5 a 0.50004997,0.50004997 0 1 0 0,1 h 5.628906 l -3.060547,5.248047 a 0.50004997,0.50004997 0 1 0 0.863282,0.503906 L 34,82.492188 l 3.068359,5.259765 a 0.50004997,0.50004997 0 1 0 0.863282,-0.503906 L 34.871094,82 H 40.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -5.628906 l 3.060547,-5.248047 A 0.50004997,0.50004997 0 1 0 37.068359,75.248047 L 34,80.507812 30.931641,75.248047 a 0.50004997,0.50004997 0 0 0 -0.457032,-0.253906 z"
- id="path14603"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 50.494141,73.992188 A 0.50004997,0.50004997 0 0 0 50.417969,74 H 49.5 a 0.50004997,0.50004997 0 1 0 0,1 H 50 v 1.125 c 0,1.632015 0.971328,2.853007 2.201172,3.775391 L 53,80.5 v 0.5 0.5 l -0.798828,0.599609 C 50.971326,83.021991 50,84.242992 50,85.875 V 87 h -0.5 a 0.50004997,0.50004997 0 1 0 0,1 h 0.921875 a 0.50004997,0.50004997 0 0 0 0.160156,0 h 7.837891 a 0.50004997,0.50004997 0 0 0 0.162109,0 H 59.5 a 0.50004997,0.50004997 0 1 0 0,-1 H 59 v -1.125 c 0,-1.632008 -0.969373,-2.853009 -2.199219,-3.775391 L 56,81.5 V 81.035156 A 0.50004997,0.50004997 0 0 0 56,81 v -0.5 l 0.800781,-0.599609 C 58.030625,78.978007 59,77.757015 59,76.125 V 75 h 0.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -0.919922 a 0.50004997,0.50004997 0 0 0 -0.162109,0 h -7.835938 a 0.50004997,0.50004997 0 0 0 -0.08789,-0.0078 z M 51,75 h 7 v 1.125 c 0,1.245243 -0.698245,2.147707 -1.800781,2.974609 l -1,0.75 A 0.50004997,0.50004997 0 0 0 55,80.25 V 80.964844 81 81.75 a 0.50004997,0.50004997 0 0 0 0.199219,0.400391 l 1,0.75 C 57.301151,83.726838 57.999238,84.628869 58,85.873047 V 87 h -7 v -1.125 -0.002 c 7.62e-4,-1.244178 0.698849,-2.146209 1.800781,-2.972656 l 1,-0.75 A 0.50004997,0.50004997 0 0 0 54,81.75 V 81.035156 A 0.50004997,0.50004997 0 0 0 54,81 v -0.75 a 0.50004997,0.50004997 0 0 0 -0.199219,-0.400391 l -1,-0.75 C 51.698847,78.273158 51.000762,77.371141 51,76.126953 v -0.002 z"
- id="path14614"
- inkscape:connector-curvature="0" />
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g14256"
- transform="translate(-21.000002,4.4999696e-6)"
- style="display:inline;opacity:0.4;fill:#ffffff;enable-background:new">
+ id="g37782"
+ inkscape:label="W-5"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 92.496094,325.99414 a 0.50005,0.50005 0 0 0 -0.382813,0.82227 l 4.5,5.5 a 0.50005,0.50005 0 0 0 0.773438,0 l 4.500001,-5.5 a 0.50005,0.50005 0 1 0 -0.77344,-0.63282 L 97,331.21094 92.886719,326.18359 a 0.50005,0.50005 0 0 0 -0.390625,-0.18945 z"
- id="path14250"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 96.5,473 c -2.087116,0 -3.478164,1.04607 -4.390625,2.1875 a 0.50024408,0.50024408 0 0 0 0.78125,0.625 C 93.690488,474.81193 94.734388,474 96.5,474 c 2.098393,0 3.134109,0.87695 3.75195,1.94531 C 100.8698,477.01367 101,478.31651 101,479 h -5.25 c -1.273438,0 -2.443243,0.36418 -3.314453,1.05469 -0.87121,0.69051 -1.427734,1.72791 -1.427735,2.94531 10e-7,1.2174 0.556525,2.2548 1.427735,2.94531 C 93.306757,486.63582 94.476562,487 95.75,487 h 0.75 c 1.755585,0 3.387714,-0.96684 4.53711,-2.0332 0.0781,0.53303 0.28951,1.00434 0.64062,1.35547 C 102.12862,486.77315 102.775,487 103.5,487 a 0.50005,0.50005 0 1 0 0,-1 c -0.525,0 -0.87862,-0.14815 -1.11523,-0.38477 C 102.14815,485.37862 102,485.025 102,484.5 V 479 c 0,-0.79721 -0.12242,-2.24322 -0.88086,-3.55469 C 100.3607,474.13385 98.896459,473 96.5,473 Z m -0.75,7 H 101 v 3.56055 C 100.04582,484.68473 98.18875,486 96.5,486 h -0.75 c -1.081007,0 -2.03187,-0.31555 -2.693359,-0.83984 -0.66149,-0.52429 -1.048828,-1.23676 -1.048829,-2.16016 10e-7,-0.9234 0.387339,-1.63587 1.048829,-2.16016 C 93.718131,480.31555 94.668993,480 95.75,480 Z"
+ id="path10278-2"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13097"
+ inkscape:label="W-4">
<path
- id="path14254"
- d="m 91.25,334 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.683851,0 1.25,-0.56615 1.25,-1.25 v -3.5 C 96,334.56615 95.433851,334 94.75,334 Z m 8,0 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.68385,0 1.25,-0.56615 1.25,-1.25 v -3.5 c 0,-0.68385 -0.56615,-1.25 -1.25,-1.25 z m -7.75,4 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z m 8,0 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.99;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 74,477 c -0.710648,0 -1.272904,0.36437 -1.621094,0.82227 -0.348189,0.45789 -0.546604,0.99437 -0.748047,1.49023 -0.201442,0.49586 -0.404614,0.94894 -0.65039,1.24023 C 70.734693,480.84402 70.491667,481 70,481 h -1 v 1 h 1 c 0.758333,0 1.359057,-0.34402 1.746094,-0.80273 0.387036,-0.45871 0.605739,-1.00563 0.810547,-1.50977 0.204807,-0.50414 0.397017,-0.96766 0.61914,-1.25977 C 73.397904,478.13563 73.585648,478 74,478 c 0.376652,0 0.584084,0.165 0.837891,0.55664 0.253806,0.39164 0.470672,0.98903 0.689453,1.61524 0.21878,0.6262 0.438752,1.28115 0.794922,1.82812 0.35617,0.54697 0.933457,1.00595 1.68164,1 0.673157,-0.005 1.209041,-0.26371 1.570313,-0.62109 0.361272,-0.35739 0.571027,-0.77752 0.771484,-1.14649 0.200458,-0.36897 0.389328,-0.68586 0.623047,-0.89258 C 81.202469,480.13313 81.474401,480 82,480 h 1 v -1 h -1 c -0.724401,0 -1.296219,0.23882 -1.695312,0.5918 -0.399094,0.35298 -0.632099,0.78332 -0.837891,1.16211 -0.205793,0.37878 -0.386663,0.70727 -0.595703,0.91406 -0.209041,0.20679 -0.423157,0.32843 -0.875,0.33203 -0.376817,0.003 -0.58078,-0.15803 -0.833985,-0.54688 -0.253205,-0.38884 -0.470733,-0.98529 -0.689453,-1.61132 -0.218719,-0.62603 -0.439353,-1.28142 -0.794922,-1.83008 C 75.322166,477.46306 74.748348,477 74,477 Z"
+ id="path15332-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 82.5,473 -13,0.004 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 480 h 1 v -5.99609 L 82,474 v 4 h 1 v -4.5 A 0.50005,0.50005 0 0 0 82.5,473 Z m -0.5,8 v 5 H 70 v -3 h -1 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 A 0.50005,0.50005 0 0 0 83,486.5 V 481 Z"
+ id="path12638-3"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 6.5,116 A 0.50005,0.50005 0 0 0 6,116.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 117 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.007812,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.0156245,9 A 0.50005,0.50005 0 0 0 6,125.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 7 v -3.5 A 0.50005,0.50005 0 0 0 6.4921875,125 Z M 19.5,125 a 0.50005,0.50005 0 0 0 -0.492188,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 19.5,125 Z"
- id="path13927"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 48,11 v 2 h 2 v -2 z m 2,4 v 2 h 2 v -2 z m 2,3 v 2 h 2 v -2 z m 3,3 v 2 h 1.5 v 1 H 59 v 1 h 3 v -2 h -3 v -1 h -2 v -1 z"
- id="path14341"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
<g
- transform="matrix(-1,0,0,1,1290,302.99979)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g8530-0"
+ id="g8734-0"
+ transform="translate(-104,-19.9999)"
+ style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="W-3">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 158.48048,492.99995 c -0.15153,0.004 -0.29304,0.0766 -0.38477,0.19727 l -4.94922,4.94921 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.5 h 5 v 12 h -10 v -6 h -1 v 6.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -6 c -0.005,-6e-5 -0.009,-6e-5 -0.0137,0 -6.7e-4,2e-5 -0.001,-2e-5 -0.002,0 -0.001,4e-5 -0.003,-5e-5 -0.004,0 z"
+ id="path8730-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,1290,765)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g8530-0-8-3"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="W-2">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1258.4766,-286 a 0.50005,0.50005 0 0 0 -0.4102,0.25195 l -4,7 A 0.50005,0.50005 0 0 0 1254.5,-278 h 8 a 0.50005,0.50005 0 0 0 0.4336,-0.74805 l -4,-7 A 0.50005,0.50005 0 0 0 1258.4766,-286 Z m 0.023,1.50781 3.1387,5.49219 h -6.2774 z"
- id="path8523-4"
- inkscape:connector-curvature="0" />
+ d="m 1258.4766,-286 c -0.1708,0.008 -0.3255,0.10335 -0.4102,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.4336,0.74805 h 8 c 0.3836,-4.7e-4 0.6239,-0.41493 0.4336,-0.74805 l -4,-7 c -0.093,-0.16311 -0.2694,-0.26042 -0.457,-0.25195 z"
+ id="path8523-4-0-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
- id="ellipse8525-5"
+ id="ellipse8525-5-4-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<path
+ inkscape:connector-curvature="0"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z"
- transform="matrix(-1,0,0,1,1290,-302.99979)"
- id="path8528-7"
- inkscape:connector-curvature="0" />
+ transform="matrix(-1,0,0,1,1290,-303)"
+ id="path8528-7-3-1" />
</g>
- <path
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path14394"
- d="m 98.999998,11.000004 v 4.000002 h -1 -1 v 3 h -1 v -2 h -1 v 5.000001 h -1 v -2.000001 h -1 v 3.560548 h -1 v -2.085938 h -1 v 2.525389 h -1 v 2 L 104,25.000007 v -2.421875 h -1 v -4.578126 h -1 v 2.000001 h -1 v -6.000003 h -1.000002 v -3 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 76,11 c -0.08389,-2.87e-4 -0.166503,0.02054 -0.240234,0.06055 l -5.5,3 C 70.099297,14.148474 69.999666,14.317023 70,14.5 v 7 c -3.35e-4,0.182978 0.0993,0.351528 0.259766,0.439453 l 5.5,3 C 75.833498,24.979467 75.916111,25.000288 76,25 h 1 c 0.08389,2.87e-4 0.166503,-0.02053 0.240234,-0.06055 l 5.5,-3 C 82.900703,21.851526 83.000334,21.682977 83,21.5 v -7 c 3.35e-4,-0.182978 -0.0993,-0.351528 -0.259766,-0.439453 l -5.5,-3 C 77.166502,11.020533 77.083889,10.999712 77,11 Z m 0.382812,2 h 0.240235 L 81,15.390625 v 5.21875 L 76.617188,23 H 76.382812 L 72,20.609375 v -5.21875 z"
- id="path14426"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccc" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14475"
- transform="translate(-1.8536743e-6,25.000005)">
+ id="g13176"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="W-1">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 14,472 c -0.486111,0 -0.97894,0.16032 -1.363281,0.50195 C 12.252378,472.84359 12,473.375 12,474 v 4 H 8.5 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 4 c 0,0.33333 -0.182083,0.72505 -0.4785156,1.02148 C 7.2250518,483.81792 6.8333333,484 6.5,484 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 2 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 3 c 0.1325988,-2e-5 0.259759,-0.0527 0.3535156,-0.14648 L 11,485.70703 V 486.5 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 5 c 1.777778,0 3.5,-1.46429 3.5,-3.5 v -5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 16 v -4 c 0,-0.625 -0.252378,-1.15641 -0.636719,-1.49805 C 14.97894,472.16032 14.486111,472 14,472 Z m 0,1 c 0.263889,0 0.52106,0.0897 0.699219,0.24805 C 14.877378,473.40641 15,473.625 15,474 v 4 h -0.5 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 19 v 1 H 9 v -1 h 3.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 V 474 c 0,-0.375 0.122622,-0.59359 0.300781,-0.75195 C 13.47894,473.08968 13.736111,473 14,473 Z m -5,8 h 10 v 2.5 c 0,1.46429 -1.277778,2.5 -2.5,2.5 H 16 v -1.5 c 0.0044,-0.28227 -0.225547,-0.51223 -0.507812,-0.50781 C 15.216044,483.9965 14.995681,484.22386 15,484.5 v 1.5 h -3 v -1.5 c -1.7e-4,-0.44532 -0.538517,-0.6683 -0.853516,-0.35352 L 9.2929688,486 H 7 v -1.22266 C 7.4441801,484.6575 7.9061001,484.55093 8.2285156,484.22852 8.682083,483.77495 9,483.16667 9,482.5 Z"
+ id="path5504-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="scsccccccccccccccsccccscsscscccccccccscsccssccccccccccccsc" />
+ </g>
+ <g
+ id="g6143"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="V-26">
<g
- transform="matrix(1,0,0,-1,-294,368)"
- id="g4806-1"
- style="opacity:1;fill:#ffffff">
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g12901"
+ transform="matrix(-0.799288,0,0,0.799288,828.432,282.268)"
+ style="display:inline;opacity:0.7;fill:#ffffff;stroke-width:1.25111;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 2 h -10 z"
- id="path4801-8"
+ id="path12894"
+ transform="matrix(-1.25111,0,0,1.25111,1036.46,-353.149)"
+ d="m 535.49805,458.00391 a 0.50004999,0.50004999 0 0 0 -0.50391,0.50781 l 0.002,1.33984 c -0.37236,0.0723 -0.71902,0.21977 -1.02148,0.42774 l -1.12695,-1.12305 a 0.50004999,0.50004999 0 0 0 -0.3418,-0.15039 0.50004999,0.50004999 0 0 0 -0.36328,0.85742 l 1.12695,1.12305 c -0.20781,0.30095 -0.35637,0.64504 -0.42969,1.01562 l -1.3457,0.004 a 0.50033487,0.50033487 0 0 0 0.002,1 l 1.33789,-0.002 c 0.0677,0.37781 0.20888,0.73164 0.41602,1.03906 l -1.10742,1.10937 a 0.50004999,0.50004999 0 1 0 0.70508,0.70508 l 1.10351,-1.10156 c 0.30838,0.21694 0.66219,0.37111 1.04492,0.44531 l -0.002,1.30078 a 0.50033678,0.50033678 0 1 0 1,0.004 l 0.002,-1.30274 c 0.3865,-0.0701 0.74651,-0.21619 1.0586,-0.43164 l 1.08203,1.08594 a 0.50005719,0.50005719 0 1 0 0.70703,-0.70508 l -1.08398,-1.08984 c 0.21441,-0.31231 0.36249,-0.67226 0.43164,-1.05859 h 1.30664 a 0.50098,0.50098 0 1 0 0,-1.00196 h -1.3125 c -0.0748,-0.37855 -0.23067,-0.72769 -0.44532,-1.0332 l 1.10352,-1.10547 a 0.50004999,0.50004999 0 0 0 -0.34961,-0.85937 0.50004999,0.50004999 0 0 0 -0.35742,0.15234 l -1.10938,1.10742 c -0.30548,-0.20557 -0.65624,-0.346 -1.03125,-0.41406 l -0.004,-1.33984 a 0.50004999,0.50004999 0 0 0 -0.49219,-0.50586 0.50004999,0.50004999 0 0 1 -0.002,0 z m -0.002,3.29882 c 0.66274,0 1.20117,0.53844 1.20118,1.20118 0,0.66273 -0.53844,1.19921 -1.20118,1.19921 -0.66273,0 -1.19921,-0.53648 -1.19921,-1.19921 0,-0.66273 0.53648,-1.20117 1.19921,-1.20118 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.25111;enable-background:new"
+ transform="matrix(-0.799288,0,0,0.799288,833.432,275.268)"
+ id="g12909">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 302.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 2 h -10 z"
- id="path4804-1"
+ id="path12903"
+ transform="matrix(-1.25111,0,0,1.25111,1042.72,-344.391)"
+ d="m 540.49805,451.00391 a 0.50004999,0.50004999 0 0 0 -0.50391,0.50781 l 0.002,1.33984 c -0.37236,0.0723 -0.71902,0.21977 -1.02148,0.42774 l -1.12695,-1.12305 a 0.50004999,0.50004999 0 0 0 -0.3418,-0.15039 0.50004999,0.50004999 0 0 0 -0.36328,0.85742 l 1.12695,1.12305 c -0.20781,0.30095 -0.35637,0.64503 -0.42969,1.01562 l -1.3457,0.004 a 0.50033487,0.50033487 0 0 0 0.002,1 l 1.33789,-0.002 c 0.0677,0.37781 0.20888,0.73164 0.41602,1.03906 l -1.10742,1.10937 a 0.50004999,0.50004999 0 1 0 0.70508,0.70508 l 1.10351,-1.10156 c 0.30838,0.21694 0.66219,0.37111 1.04492,0.44531 l -0.002,1.30078 a 0.50033678,0.50033678 0 1 0 1,0.004 l 0.002,-1.30274 c 0.386,-0.07 0.74484,-0.21858 1.05664,-0.43359 l 1.08399,1.08789 a 0.50005719,0.50005719 0 1 0 0.70703,-0.70508 l -1.08398,-1.08984 c 0.21441,-0.31231 0.36249,-0.67226 0.43164,-1.05859 h 1.30664 a 0.50098,0.50098 0 1 0 0,-1.00196 h -1.3125 c -0.0748,-0.37855 -0.23067,-0.72769 -0.44532,-1.0332 l 1.10352,-1.10547 a 0.50004999,0.50004999 0 0 0 -0.34961,-0.85937 0.50004999,0.50004999 0 0 0 -0.35742,0.15234 l -1.10938,1.10742 c -0.30548,-0.20557 -0.65624,-0.346 -1.03125,-0.41406 l -0.004,-1.33984 a 0.50004999,0.50004999 0 0 0 -0.49219,-0.50586 0.50004999,0.50004999 0 0 1 -0.002,0 z m -0.002,3.29882 c 0.66274,0 1.20117,0.53844 1.20118,1.20118 0,0.66273 -0.53844,1.19921 -1.20118,1.19921 -0.66273,0 -1.19921,-0.53648 -1.19921,-1.19921 0,-0.66273 0.53648,-1.20117 1.19921,-1.20118 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
inkscape:connector-curvature="0" />
</g>
+ </g>
+ <g
+ id="g38026"
+ inkscape:label="V-25"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 8.5,-4 A 0.50005,0.50005 0 0 0 8,-3.5 v 3 A 0.50005,0.50005 0 0 0 8.5,0 h 11 A 0.50005,0.50005 0 0 0 20,-0.5 v -3 A 0.50005,0.50005 0 0 0 19.5,-4 Z M 9,-3 h 10 v 2 H 9 Z"
- id="path4817-4"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 511.5,452 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.64684,0 1.19777,-0.42097 1.40625,-1 h 1.1875 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 -0.64637,0 -1.19742,0.42162 -1.40625,1 h -1.1875 c -0.20883,-0.57838 -0.75988,-1 -1.40625,-1 z m 11,0 c -0.64637,0 -1.19742,0.42162 -1.40625,1 H 520.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 516.29297,457 h -3.38672 c -0.20883,-0.57838 -0.75988,-1 -1.40625,-1 -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.64684,0 1.19777,-0.42097 1.40625,-1 H 516.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 L 520.70703,454 h 0.38672 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.27091,0 0.47782,0.20294 0.49414,0.46875 a 0.50005,0.50005 0 0 0 0,0.0625 C 511.97782,453.79707 511.77091,454 511.5,454 c -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 4,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 515.02218,453.20294 515.22909,453 515.5,453 Z m 7,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 522.02218,453.20294 522.22909,453 522.5,453 Z m 0,3 c -0.64637,0 -1.19742,0.42162 -1.40625,1 H 520.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -5,5 A 0.50005,0.50005 0 0 0 515,462.5 v 0.59375 c -0.57903,0.20848 -1,0.75941 -1,1.40625 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.64684 -0.42097,-1.19777 -1,-1.40625 v -0.38672 L 520.70703,458 h 0.38672 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 11,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 522.02218,457.20294 522.22909,457 522.5,457 Z m -11,3 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 11,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.23017 0.0579,0.44679 0.15234,0.64258 a 0.50005,0.50005 0 0 0 -0.006,0.004 l -1,1 a 0.50005,0.50005 0 0 0 -0.004,0.006 C 519.94679,463.05791 519.73016,463 519.5,463 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.23002 -0.058,-0.44493 -0.15234,-0.64062 a 0.50005,0.50005 0 0 0 0.006,-0.006 l 1,-1 a 0.50005,0.50005 0 0 0 0.004,-0.004 c 0.1955,0.0946 0.41225,0.15062 0.64234,0.15062 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 11,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -3,3 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -4.0293,0.006 a 0.50005,0.50005 0 0 0 0.0371,0 0.50005,0.50005 0 0 0 0.0176,0 c 0.26874,0.0134 0.4746,0.22107 0.4746,0.494 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.27158 0.20391,-0.47876 0.4707,-0.49414 z"
+ id="circle28282" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14588"
- transform="translate(-42.000002,25.000005)">
+ id="g38038"
+ inkscape:label="V-24"
+ style="display:inline;enable-background:new">
<path
- id="path14541"
- d="m 153.5,-9 c -0.27613,2.76e-5 -0.49997,0.2238691 -0.5,0.5 v 8 c 3e-5,0.27613094 0.22387,0.499972391047 0.5,0.5 h 8 c 0.27613,-2.7608953e-5 0.49997,-0.22386906 0.5,-0.5 v -8 c -3e-5,-0.2761309 -0.22387,-0.4999724 -0.5,-0.5 z m 6.5,1 c 0.54636,0 1,0.4536376 1,1 0,0.5463624 -0.45364,1 -1,1 -0.54636,0 -1,-0.4536376 -1,-1 0,-0.5463624 0.45364,-1 1,-1 z m -2.98047,1.75 c 0.17034,0.00643 0.32566,0.099184 0.41211,0.2460938 l 2.5,4.25 C 160.12825,-1.4202448 159.88728,-0.99936558 159.5,-1 h -5 c -0.38728,6.3442e-4 -0.62825,-0.4202448 -0.43164,-0.7539062 l 2.5,-4.25 c 0.0935,-0.1589489 0.26691,-0.2535338 0.45117,-0.2460938 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 495.50391,451.99219 c -1.93006,0 -3.50391,1.57292 -3.50391,3.5 v 2 c 0,0.41666 0.19292,0.77495 0.45898,1.04101 0.26607,0.26607 0.62435,0.45899 1.04102,0.45899 a 0.50005,0.50005 0 1 0 0,-1 c -0.0833,0 -0.22505,-0.0571 -0.33398,-0.16602 C 493.05708,457.71724 493,457.57552 493,457.49219 v -2 c 0,-1.38664 1.11314,-2.5 2.50391,-2.5 h 1.0039 c 1.39077,0 2.50196,1.11336 2.50196,2.5 v 2 c 0,0.0833 -0.0571,0.22505 -0.16602,0.33398 -0.10893,0.10893 -0.25065,0.16602 -0.33398,0.16602 a 0.50005,0.50005 0 1 0 0,1 c 0.41666,0 0.77494,-0.19292 1.04101,-0.45899 0.26607,-0.26606 0.45899,-0.62435 0.45899,-1.04101 v -2 c 0,-1.92708 -1.57191,-3.5 -3.50196,-3.5 z m 3.94921,7.41406 a 0.50005,0.50005 0 0 0 -0.48632,0.33203 c -0.17381,0.48217 -0.35767,1.04392 -0.75391,1.48047 -0.39624,0.43655 -0.98986,0.78906 -2.17578,0.78906 -1.18761,0 -1.78805,-0.34711 -2.19141,-0.77929 -0.40336,-0.43219 -0.59802,-0.98975 -0.78515,-1.47266 a 0.50005,0.50005 0 0 0 -0.67578,-0.27344 c -0.97162,0.44606 -1.78522,0.89986 -2.38868,1.45508 C 489.39264,461.49272 489,462.19074 489,462.99219 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13.00977 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.5 c 0,-0.79711 -0.38431,-1.49976 -0.98243,-2.06446 -0.59811,-0.56469 -1.40897,-1.02891 -2.38086,-1.47461 a 0.50005,0.50005 0 0 0 -0.19336,-0.0469 z m 0.17579,1.19922 c 0.68529,0.34567 1.33558,0.69455 1.71289,1.05078 0.46505,0.43906 0.66797,0.84399 0.66797,1.33594 v 2 H 490 v -2 c 0,-0.49365 0.20477,-0.8868 0.67383,-1.31836 0.38208,-0.35154 1.03995,-0.69804 1.73437,-1.04492 0.1643,0.40983 0.28954,0.83601 0.70508,1.28125 0.58146,0.623 1.5239,1.09765 2.92383,1.09765 1.40162,0 2.34196,-0.48473 2.91601,-1.11719 0.40651,-0.44786 0.51938,-0.87307 0.67579,-1.28515 z"
+ id="path6745-8"
inkscape:connector-curvature="0" />
- <g
- id="g14560"
- transform="translate(147)"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 10.5,-14 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 3 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 h 9 c 0.276131,-2.8e-5 0.499972,-0.223869 0.5,-0.5 v -3 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z m 0.5,1 h 8 v 2 h -8 z m 5,7 v 1 h 3 v 2 h -3 v 1 h 3.5 c 0.276131,-2.76e-5 0.499972,-0.2238691 0.5,-0.5 v -3 c -2.8e-5,-0.2761309 -0.223869,-0.4999724 -0.5,-0.5 z"
- id="path14558"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccc" />
- </g>
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14668"
- transform="matrix(-1,0,0,1,530,30.000005)">
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 258.5,-19 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 3e-5,0.2761309 0.22387,0.4999724 0.5,0.5 h 13 c 0.27613,-2.76e-5 0.49997,-0.2238691 0.5,-0.5 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 1.5,2 h 6 v 4 h 4 v 6 h -6 v -4 h -4 z"
- id="path14664" />
+ id="g38053"
+ inkscape:label="V-23"
+ style="display:inline;enable-background:new">
<path
- style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.89999986;marker:none;enable-background:accumulate"
- d="m 260,-17 h 6 v 4 h -2 v 2 h -4 z"
- id="path14666"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 471.32227,452.0625 C 469.61213,452.13527 468,453.5463 468,456 c 0,1.29326 0.43161,2.55298 1.07227,3.72852 0.16015,0.29312 0.55714,0.34983 0.79296,0.11328 l 3.63477,-3.63477 1.64648,1.64649 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 2.48242,2.48242 c 0.27743,0.27645 0.75058,0.14111 0.83985,-0.24023 C 481.93311,456.97518 482,456.49157 482,456 c 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z M 478.49219,458 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -2.64648,2.64649 -1.64648,-1.64649 c -0.19527,-0.19519 -0.51177,-0.19519 -0.70704,0 l -2.34765,2.34766 c -0.18257,0.18194 -0.19694,0.47283 -0.0332,0.67188 1.2321,1.49847 2.62304,2.79208 3.65235,3.70703 0.0914,0.0816 0.20953,0.12673 0.33202,0.12695 h 0.5 c 0.12249,-2.2e-4 0.24064,-0.0454 0.33203,-0.12695 1.41546,-1.2582 3.54029,-3.21344 4.96094,-5.48828 0.12374,-0.19754 0.0946,-0.45438 -0.0703,-0.61915 l -1.61914,-1.61914 c -0.0957,-0.0957 -0.22604,-0.14856 -0.36134,-0.14648 z"
+ id="path6086"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
+ sodipodi:nodetypes="csccccccccscccccccccccccccccc" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 261.03125,601 C 260.46859,601 260,601.46859 260,602.03125 v 7.9375 c 0,0.56266 0.46859,1.03125 1.03125,1.03125 h 7.9375 C 269.53141,611 270,610.53141 270,609.96875 v -7.9375 C 270,601.46859 269.53141,601 268.96875,601 Z m 0,1 h 7.9375 c 0.026,0 0.0312,0.005 0.0312,0.0312 v 7.9375 c 0,0.026 -0.005,0.0312 -0.0312,0.0312 h -7.9375 c -0.026,0 -0.0312,-0.005 -0.0312,-0.0312 v -7.9375 c 0,-0.026 0.005,-0.0312 0.0312,-0.0312 z"
- id="rect13790"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path13905"
- d="M 282.03125,601 C 281.46859,601 281,601.46859 281,602.03125 v 7.9375 c 0,0.56266 0.46859,1.03125 1.03125,1.03125 h 7.9375 C 290.53141,611 291,610.53141 291,609.96875 v -7.9375 C 291,601.46859 290.53141,601 289.96875,601 Z m 6.94922,1.99023 a 1.0001,1.0001 0 0 1 0.72656,1.7168 l -4,4 a 1.0001,1.0001 0 0 1 -1.41406,0 l -2,-2 a 1.0001,1.0001 0 1 1 1.41406,-1.41406 l 1.29297,1.29297 3.29297,-3.29297 a 1.0001,1.0001 0 0 1 0.6875,-0.30274 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 265,622 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z m 0,1 c 2.21506,0 4,1.78494 4,4 0,2.21506 -1.78494,4 -4,4 -2.21506,0 -4,-1.78494 -4,-4 0,-2.21506 1.78494,-4 4,-4 z"
- id="path13966"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 286,622 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z"
- id="circle13982"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 220.4707,623.75 c -0.26463,0.0156 -0.47113,0.23492 -0.4707,0.5 v 4.25 c 1.7e-4,0.35718 0.36395,0.59902 0.69336,0.46094 l 4.75,-2 c 0.39771,-0.16741 0.41088,-0.72615 0.0215,-0.91211 l -4.75,-2.25 c -0.076,-0.0366 -0.15996,-0.0534 -0.24416,-0.0488 z"
- id="path14031"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 370,625 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
- id="circle14040"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 28.5,431 a 1.50015,1.50015 0 0 0 -1.341797,2.16992 l 5.5,11 a 1.50015,1.50015 0 0 0 2.683594,0 l 5.5,-11 A 1.50015,1.50015 0 0 0 39.5,431 Z m 2.425781,3 h 6.148438 L 34,440.14648 Z"
- id="path14201"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 306.49219,577.99219 A 0.50004997,0.50004997 0 0 0 306,578.5 v 2.79297 l -2.14648,-2.14649 a 0.50004997,0.50004997 0 1 0 -0.70704,0.70704 L 306,582.70703 v 0.58203 c -0.58959,0.34718 -0.99219,0.98165 -0.99219,1.71094 h -0.30078 l -2.85351,-2.85352 a 0.50004997,0.50004997 0 0 0 -0.35938,-0.15234 0.50004997,0.50004997 0 0 0 -0.34766,0.85938 L 303.29297,585 H 300.5 a 0.50004997,0.50004997 0 1 0 0,1 h 2.79297 l -2.14649,2.14648 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 L 304.70703,586 h 0.58203 c 0.34718,0.58959 0.98165,0.99219 1.71094,0.99219 v 0.30078 l -2.85352,2.85351 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 L 307,588.70703 V 591.5 a 0.50004997,0.50004997 0 1 0 1,0 v -2.79297 l 2.14648,2.14649 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 308,587.29297 v -0.58203 c 0.58959,-0.34718 0.99219,-0.98165 0.99219,-1.71094 h 0.30078 l 2.85351,2.85352 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 310.70703,585 H 313.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -2.79297 l 2.14649,-2.14648 a 0.50004997,0.50004997 0 0 0 -0.36329,-0.85743 0.50004997,0.50004997 0 0 0 -0.34375,0.15039 L 309.29297,584 h -0.58203 c -0.34718,-0.58959 -0.98165,-0.99219 -1.71094,-0.99219 v -0.30078 l 2.85352,-2.85351 a 0.50004997,0.50004997 0 1 0 -0.70704,-0.70704 L 307,581.29297 V 578.5 a 0.50004997,0.50004997 0 0 0 -0.50781,-0.50781 z M 307,584.00781 c 0.55427,0 0.99219,0.43792 0.99219,0.99219 0,0.55427 -0.43792,0.99219 -0.99219,0.99219 -0.55427,0 -0.99219,-0.43792 -0.99219,-0.99219 0,-0.55427 0.43792,-0.99219 0.99219,-0.99219 z"
- id="path14282"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14048"
- transform="translate(294,571)">
- <g
- transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,472.85846,-15.235808)"
- id="g13853"
- style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 306.99023,243.60938 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 4.99023 h -4.99023 a 0.666995,0.666995 0 1 0 0,1.33399 h 4.99023 v 4.99023 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -4.99023 h 4.99023 a 0.666995,0.666995 0 1 0 0,-1.33399 h -4.99023 v -4.99023 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
- id="path13850"
- inkscape:connector-curvature="0" />
- </g>
+ id="g38050"
+ inkscape:label="V-22"
+ style="display:inline;enable-background:new">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 177.49219,-56.007812 A 0.50005,0.50005 0 0 0 177,-55.5 v 6 a 0.50005,0.50005 0 1 0 1,0 V -52 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 178 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 7.00195,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.707032 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z M 180.5,-53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path13907"
+ d="M 450.32227,452.0625 C 448.61213,452.13527 447,453.5463 447,456 c 0,2.05278 1.07076,4.01178 2.38672,5.71289 1.31595,1.70111 2.90024,3.15481 4.03125,4.16016 A 0.50005,0.50005 0 0 0 453.75,466 h 0.5 a 0.50005,0.50005 0 0 0 0.33203,-0.12695 c 1.13101,-1.00535 2.7153,-2.45905 4.03125,-4.16016 C 459.92924,460.01178 461,458.05278 461,456 c 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z m 0.043,1 c 1.22737,-0.0522 2.55838,0.74689 2.89258,2.5293 A 0.50005,0.50005 0 0 0 453.75,456 h 0.5 a 0.50005,0.50005 0 0 0 0.49219,-0.4082 c 0.3342,-1.78241 1.66521,-2.58153 2.89258,-2.5293 C 458.86213,453.1147 460,453.9537 460,456 c 0,1.69722 -0.92924,3.48822 -2.17578,5.09961 -1.20727,1.56061 -2.67447,2.91135 -3.7832,3.90039 h -0.082 c -1.10873,-0.98904 -2.57593,-2.33978 -3.7832,-3.90039 C 448.92924,459.48822 448,457.69722 448,456 c 0,-2.0463 1.13787,-2.88527 2.36523,-2.9375 z"
+ id="path6081"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="rotate(-180,275.49999,225.99747)"
- id="g14033">
+ id="g38068"
+ inkscape:label="V-21"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 184.49414,-76.005859 c -0.4494,8.8e-5 -0.67059,0.546839 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 3,-3 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -3,-3 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z M 175.49219,-73 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 5.00781,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m -6,0.0078 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z M 175.49219,-70 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z"
- id="path14029"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 428.25,452 c -0.6506,0 -1.23633,0.19727 -1.64453,0.60547 -0.4083,0.4081 -0.60567,0.99393 -0.60547,1.64453 v 9.5 c 2e-4,0.6505 0.19727,1.23643 0.60547,1.64453 C 427.01357,465.80273 427.5994,466 428.25,466 H 429 v -1 h -0.75 c -0.4574,0 -0.7477,-0.1227 -0.9375,-0.3125 -0.1898,-0.1898 -0.3124,-0.48 -0.3125,-0.9375 v -9.5 c -10e-5,-0.4574 0.1227,-0.7477 0.3125,-0.9375 C 427.5023,453.1227 427.7926,453 428.25,453 H 429 v -1 z m 8.75,0 v 1 h 0.75 c 0.4574,0 0.7477,0.1227 0.9375,0.3125 0.1898,0.1898 0.3125,0.4801 0.3125,0.9375 v 9.5 c 0,0.4574 -0.1227,0.7477 -0.3125,0.9375 C 438.4977,464.8773 438.2074,465 437.75,465 H 437 v 1 h 0.75 c 0.6506,0 1.23643,-0.19727 1.64453,-0.60547 C 439.80273,464.98643 440,464.4006 440,463.75 v -9.5 c 0,-0.6506 -0.19727,-1.23643 -0.60547,-1.64453 C 438.98643,452.19727 438.4006,452 437.75,452 Z m -4,4 v 2 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -2 v 1 h 2 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v 2 h 1 v -2 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 461 h 2 v -1 h -2 v -1.5 A 0.50005,0.50005 0 0 0 435.5,458 H 434 v -2 z m -1,3 h 3 v 3 h -3 z"
+ id="path19168-3"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g38035"
+ inkscape:label="V-20"
+ style="display:inline;enable-background:new">
<path
+ inkscape:connector-curvature="0"
+ id="path4106"
+ d="m 408.48148,452.0625 c -1.71014,0.0728 -3.32227,1.4838 -3.32227,3.9375 0,2.05278 1.07076,4.01178 2.38672,5.71289 1.31595,1.70111 2.90024,3.15481 4.03125,4.16016 0.0914,0.0816 0.20954,0.12673 0.33203,0.12695 h 0.5 c 0.12249,-2.2e-4 0.24064,-0.0454 0.33203,-0.12695 1.13101,-1.00535 2.7153,-2.45905 4.03125,-4.16016 1.31596,-1.70111 2.38672,-3.66011 2.38672,-5.71289 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 175.5,-67 c -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 z"
- id="circle14031"
+ sodipodi:nodetypes="csccccccsccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23545-6"
+ transform="rotate(-90,318.416,448.416)"
+ inkscape:label="V-19">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 393.99219,462.28516 -2.13867,-2.13868 c -0.318,-0.32528 -0.86991,-0.0915 -0.85743,0.36329 0.004,0.12976 0.0575,0.25303 0.15039,0.34375 l 2.93555,2.93359 0.008,0.01 c 0.0962,0.13317 0.25175,0.21055 0.41602,0.20703 0.003,2e-5 0.005,2e-5 0.008,0 0.0157,-6e-4 0.0313,-0.002 0.0469,-0.004 0.0164,-0.002 0.0327,-0.005 0.0488,-0.008 0.11995,-0.0256 0.2263,-0.0944 0.29882,-0.19336 l 2.94532,-2.94531 c 0.49057,-0.47126 -0.23578,-1.19761 -0.70704,-0.70704 l -2.15429,2.1543 L 395,457.5 c 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 -2.47936,0 -4.5,2.02064 -4.5,4.5 v 6 c -0.01,0.67616 1.00956,0.67616 1,0 v -6 c 0,-1.93892 1.56108,-3.5 3.5,-3.5 1.93826,0 3.49893,1.56005 3.5,3.49902 z"
+ transform="rotate(90,318.416,448.416)"
+ id="path23541-6"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ sodipodi:nodetypes="cccccccccccccccssccsscc" />
</g>
<g
+ id="g20632"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14223"
- transform="rotate(-180,317.49493,236.50149)">
+ transform="translate(696,793)"
+ inkscape:label="V-18">
<g
- style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none"
- id="g14219"
- transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,472.85846,-15.235808)">
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g20623"
+ transform="translate(-740,-750)"
+ style="display:inline;fill:#ffffff;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 306.99023,243.60938 a 0.66673335,0.66673335 0 0 0 -0.65625,0.67578 v 4.99023 h -4.99023 a 0.666995,0.666995 0 1 0 0,1.33399 h 4.99023 v 4.99023 a 0.66673335,0.66673335 0 1 0 1.33204,0 v -4.99023 h 4.99023 a 0.666995,0.666995 0 1 0 0,-1.33399 h -4.99023 v -4.99023 a 0.66673335,0.66673335 0 0 0 -0.67579,-0.67578 z"
- id="path14217"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path20621"
+ transform="translate(594,-43)"
+ d="m -179.5,453 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 1.5 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -0.5 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -5 v -1.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z m -0.5,6 h 1 v 1 1 h -1 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
+ </g>
+ <g
+ id="g38071"
+ inkscape:label="V-17"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 177.49219,-56.007812 A 0.50005,0.50005 0 0 0 177,-55.5 v 6 a 0.50005,0.50005 0 1 0 1,0 V -52 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 178 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 7.00195,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.707032 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z M 180.5,-53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14221"
+ id="path20615"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 345.50001,453 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 0.5 h 1 v -0.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -6.5 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 2.5,6 h 7 v 4 h -7 z m 3,0.99999 h 1 V 462 h -1 z"
inkscape:connector-curvature="0" />
</g>
<g
+ transform="translate(-346,-12)"
+ id="g24012-1"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14371"
- transform="matrix(1,0,0,-1,336,494)">
+ inkscape:label="V-16">
<g
- transform="matrix(1,0,0,-1,0,-99.00505)"
- id="g14352"
- style="fill:#ffffff">
+ style="opacity:0.7;fill:#ffffff;stroke-width:1.18252"
+ transform="matrix(0.84565,0,0,0.84565,271.318,206.157)"
+ id="g24008-0">
+ <g
+ style="fill:#ffffff;stroke-width:1.18252"
+ transform="translate(829,-385)"
+ id="g24002-7" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 520.49414,515 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 2.64649,2.64648 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 520.49414,515 Z m 0.0332,2.99414 a 0.50005,0.50005 0 0 0 -0.14843,0.0215 l -1,0.25 a 0.50005,0.50005 0 0 0 0.0937,0.98633 0.50005,0.50005 0 0 0 0.14843,-0.0176 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.99024 z m -3,0.75 a 0.50005,0.50005 0 0 0 -0.14843,0.0215 l -1,0.25 a 0.50005,0.50005 0 0 0 0.0937,0.98633 0.50005,0.50005 0 0 0 0.14843,-0.0176 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.99024 z m -3.02343,1.24805 a 0.50005,0.50005 0 0 0 -0.35743,0.15429 l -1,1 a 0.50005,0.50005 0 0 0 0.34766,0.85938 0.50005,0.50005 0 0 0 0.35938,-0.15234 l 1,-1 a 0.50005,0.50005 0 0 0 -0.34961,-0.86133 z m -1.9961,3 A 0.50005,0.50005 0 0 0 512,523.5 v 1 a 0.50005,0.50005 0 0 0 0.49219,0.50781 A 0.50005,0.50005 0 0 0 513,524.5 v -1 a 0.50005,0.50005 0 0 0 -0.49219,-0.50781 z"
- transform="translate(-336,-593.00505)"
- id="path14350"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.18252;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 480.06836,304.9375 c -0.78863,-0.0147 -1.5648,0.35582 -2.23633,1.02734 l -1.47851,1.47852 a 0.59132004,0.59132004 0 1 0 0.83593,0.83594 l 1.47852,-1.47852 c 0.51101,-0.511 0.96056,-0.68742 1.37695,-0.67969 0.41639,0.008 0.86317,0.20868 1.33399,0.67969 0.4709,0.4711 0.67191,0.91763 0.67968,1.33399 0.008,0.41635 -0.16868,0.86595 -0.67968,1.37695 l -1.47852,1.47851 a 0.59132004,0.59132004 0 1 0 0.83594,0.83594 l 1.47851,-1.47851 c 0.67153,-0.67153 1.04012,-1.44777 1.02539,-2.23633 -0.0147,-0.78856 -0.40379,-1.52464 -1.02539,-2.14649 -0.62168,-0.62194 -1.35785,-1.01269 -2.14648,-1.02734 z m -0.94336,3.50977 a 0.59132004,0.59132004 0 0 0 -0.40625,0.17773 l -1.47852,1.47852 a 0.59132004,0.59132004 0 1 0 0.83594,0.83593 l 1.47852,-1.47851 a 0.59132004,0.59132004 0 0 0 -0.42969,-1.01367 z m -8.27344,4.72851 a 0.59132004,0.59132004 0 0 0 -0.4082,0.17774 l -1.51367,1.49218 a 0.59132004,0.59132004 0 0 0 -0.008,0.006 c -0.65272,0.66501 -1.01668,1.4358 -1.00782,2.22266 0.009,0.78686 0.38697,1.53124 1.01172,2.15625 0.62485,0.62507 1.3751,1.00952 2.16992,1.01953 0.79483,0.01 1.57721,-0.36041 2.25,-1.0332 l 1.47852,-1.47657 a 0.59178867,0.59178867 0 1 0 -0.83594,-0.83789 l -1.47851,1.47852 c -0.50973,0.50972 -0.97241,0.69289 -1.40039,0.6875 -0.42799,-0.005 -0.87805,-0.206 -1.34571,-0.67383 -0.46775,-0.46794 -0.66322,-0.91244 -0.66797,-1.33398 -0.005,-0.42154 0.17763,-0.8773 0.67188,-1.38086 l 1.50586,-1.48438 a 0.59132004,0.59132004 0 0 0 -0.42188,-1.01953 z m 2.65625,0.88867 a 0.59132004,0.59132004 0 0 0 -0.40625,0.17774 l -1.47851,1.47851 a 0.59132004,0.59132004 0 1 0 0.83593,0.83594 l 1.47852,-1.47852 a 0.59132004,0.59132004 0 0 0 -0.42969,-1.01367 z"
+ id="path24006-7"
inkscape:connector-curvature="0" />
</g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 176.5,-32 c 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 z"
- id="circle14357"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 668.49414,464.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 678.29297,476 H 675.25 a 0.50005,0.50005 0 1 0 0,1 h 4.18945 A 0.50005,0.50005 0 0 0 680,476.43945 V 472.25 a 0.50005,0.50005 0 1 0 -1,0 v 3.04297 l -10.14648,-10.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path24010-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g38047"
+ inkscape:label="V-15"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 310.26367,452.0293 c -0.67255,-0.0123 -1.33821,0.3 -1.8789,0.8789 l -0.23829,0.23828 a 0.50004997,0.50004997 0 0 0 -0.084,0.10938 0.50004997,0.50004997 0 0 0 -0.0879,0.0723 l -1.26563,1.25196 c -0.23797,0.23547 -0.44036,0.48356 -0.58984,0.75781 a 0.50004997,0.50004997 0 1 0 0.87695,0.47852 c 0.0885,-0.16243 0.22753,-0.33889 0.41602,-0.52539 l 1.26562,-1.25391 a 0.50004997,0.50004997 0 0 0 0.0899,-0.11523 0.50004997,0.50004997 0 0 0 0.002,-0.002 0.50004997,0.50004997 0 0 0 0.084,-0.0664 l 0.25,-0.25 a 0.50004997,0.50004997 0 0 0 0.0117,-0.0117 c 0.39332,-0.4211 0.76594,-0.57109 1.12891,-0.56446 0.36298,0.007 0.75841,0.18208 1.15234,0.57618 0.39504,0.3952 0.56757,0.78617 0.57422,1.14648 0.007,0.36031 -0.14053,0.73397 -0.56445,1.13672 l -0.26758,0.2539 a 0.50004997,0.50004997 0 0 0 -0.0957,0.12305 0.50004997,0.50004997 0 0 0 -0.0859,0.0684 l -1.25,1.25 a 0.50004997,0.50004997 0 0 0 -0.0137,0.0117 c -0.16233,0.1738 -0.32346,0.30196 -0.48047,0.39063 a 0.50026213,0.50026213 0 1 0 0.49219,0.87109 c 0.25644,-0.14482 0.49753,-0.33919 0.7207,-0.57813 l 1.23828,-1.23828 a 0.50004997,0.50004997 0 0 0 0.0859,-0.11133 0.50004997,0.50004997 0 0 0 0.0781,-0.0625 l 0.26563,-0.25195 c 0.57608,-0.54732 0.88934,-1.2117 0.87695,-1.88281 -0.0124,-0.67111 -0.33835,-1.30493 -0.86718,-1.83399 -0.52994,-0.53015 -1.16729,-0.85488 -1.83985,-0.86718 z m -1.77344,3.96679 a 0.50004997,0.50004997 0 0 0 -0.34375,0.15039 l -4.01367,4.01563 a 0.50004997,0.50004997 0 1 0 0.70703,0.70703 l 4.01368,-4.01562 a 0.50004997,0.50004997 0 0 0 -0.36329,-0.85743 z m -4.94921,2.1836 a 0.50004997,0.50004997 0 0 0 -0.22852,0.0469 c -0.33394,0.14944 -0.64532,0.37928 -0.92773,0.68164 l -1.23829,1.23828 a 0.50004997,0.50004997 0 0 0 -0.0547,0.0645 l -0.18555,0.17578 c -0.57608,0.54731 -0.88934,1.2117 -0.87695,1.88281 0.0124,0.67111 0.33835,1.30494 0.86718,1.83399 0.52994,0.53016 1.16729,0.85489 1.83985,0.86718 0.67255,0.0123 1.33821,-0.3 1.8789,-0.8789 l 0.23829,-0.23828 a 0.50004997,0.50004997 0 0 0 0.0605,-0.0723 0.50004997,0.50004997 0 0 0 0.004,-0.004 l 1.18359,-1.17187 c 0.27971,-0.27677 0.50962,-0.57119 0.66211,-0.9043 a 0.50004997,0.50004997 0 1 0 -0.9082,-0.41601 c -0.0851,0.18591 -0.2355,0.39018 -0.45703,0.60937 l -1.26563,1.25391 a 0.50004997,0.50004997 0 0 0 -0.0664,0.0762 0.50004997,0.50004997 0 0 0 -0.004,0.006 l -0.16602,0.16601 a 0.50004997,0.50004997 0 0 0 -0.0117,0.0117 c -0.39332,0.4211 -0.76594,0.57109 -1.12891,0.56446 -0.36298,-0.007 -0.75841,-0.18208 -1.15234,-0.57618 -0.39505,-0.3952 -0.56758,-0.78617 -0.57422,-1.14648 -0.007,-0.36031 0.14053,-0.73396 0.56445,-1.13672 l 0.26758,-0.2539 a 0.50004997,0.50004997 0 0 0 0.0742,-0.0879 l 1.16797,-1.16796 a 0.50004997,0.50004997 0 0 0 0.0117,-0.0117 c 0.20545,-0.21996 0.40997,-0.36564 0.60547,-0.45313 a 0.50004997,0.50004997 0 0 0 -0.17968,-0.95898 z"
+ id="path23240-3"
+ inkscape:connector-curvature="0" />
</g>
<g
+ transform="matrix(-1,0,0,1,593.832,-42)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14377"
- transform="translate(210,592)">
+ id="g24182"
+ inkscape:label="V-14">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 184.49414,-76.005859 c -0.4494,8.8e-5 -0.67059,0.546839 -0.34766,0.859375 l 2.64649,2.646484 -2.64649,2.646484 c -0.4905,0.471264 0.23578,1.197538 0.70704,0.707032 l 3,-3 c 0.19518,-0.195265 0.19518,-0.511767 0,-0.707032 l -3,-3 c -0.0942,-0.09737 -0.2239,-0.152345 -0.35938,-0.152343 z M 175.49219,-73 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 5.00781,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m -6,0.0078 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z M 175.49219,-70 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z"
- id="path14373"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 309.83203,496 c -0.79167,0 -1.54903,0.39305 -1.86328,1.11133 -0.31425,0.71827 -0.0786,1.6538 0.75977,2.49219 l 2.5,2.5 c 0.66161,0.66161 0.67598,1.10108 0.55273,1.38281 C 311.658,503.76805 311.29036,504 310.83203,504 l -7.28515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 7.30078,0.008 c 0.79167,0 1.55099,-0.39305 1.86524,-1.11133 0.31424,-0.71827 0.0767,-1.6538 -0.76172,-2.49219 l -2.5,-2.5 c -0.66161,-0.66161 -0.67404,-1.10108 -0.55078,-1.38281 C 309.00802,497.23195 309.3737,497 309.83203,497 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path24180"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g38041"
+ inkscape:label="V-13"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 175.5,-67 c -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 z"
- id="circle14375"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 264.49219,453.00195 a 0.50005,0.50005 0 0 0 -0.34571,0.14649 l -5,4.99804 a 0.50005,0.50005 0 0 0 0,0.70704 l 5,5 a 0.50005,0.50005 0 0 0 0.70508,0 l 4.99219,-4.97852 a 0.50005,0.50005 0 0 0 0.002,-0.70703 l -4.99218,-5.01953 a 0.50005,0.50005 0 0 0 -0.36133,-0.14649 z m 0.006,1.20703 4.28711,4.31055 -4.2853,4.27344 -4.29297,-4.29297 z"
+ id="path22390"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g38044"
+ inkscape:label="V-12"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 243.49219,453 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -5,5 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 5,5 c 0.19504,0.19389 0.51004,0.19389 0.70508,0 l 4.99219,-4.97852 c 0.19574,-0.19471 0.19663,-0.51121 0.002,-0.70703 l -4.99218,-5.02149 c -0.0957,-0.0957 -0.22606,-0.14857 -0.36138,-0.14648 z"
+ id="path22397"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ sodipodi:nodetypes="cccccccccc" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="matrix(-1,0,0,1,676.99998,550)"
- id="g14389">
+ id="g38602"
+ inkscape:label="V-11"
+ style="display:inline;enable-background:new">
<g
- id="g14381"
- transform="matrix(1,0,0,-1,0,-99.00505)"
- style="fill:#ffffff">
+ transform="translate(112.055,339.927)"
+ id="g44391-4"
+ style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
+ <circle
+ r="8"
+ cy="118"
+ cx="132"
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="circle44389-4"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ transform="matrix(-0.248353,0.0281678,0.0283072,0.248422,140.452,86.0103)" />
+ </g>
+ <g
+ transform="translate(112.055,339.927)"
+ id="g44391"
+ style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 500.50586,518.99219 A 0.50005,0.50005 0 0 0 500,519.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.49219,-0.50781 0.50005,0.50005 0 0 1 -0.002,0 z m -8.00977,2.99609 a 0.50005,0.50005 0 0 0 -0.34961,0.15234 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 0 0 0.35938,0.15234 0.50005,0.50005 0 0 0 0.34766,-0.85938 l -2.64649,-2.64648 2.64649,-2.64648 a 0.50005,0.50005 0 0 0 -0.35743,-0.85938 z m 7.00977,0.006 a 0.50005,0.50005 0 0 0 -0.35938,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.34766,-0.85938 z m -3.0293,2.00391 a 0.50005,0.50005 0 0 0 -0.0976,0.0176 l -1,0.25 a 0.50005,0.50005 0 1 0 0.24218,0.96876 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.98633 0.50005,0.50005 0 0 0 -0.0508,0 z m -3,0.75 a 0.50005,0.50005 0 0 0 -0.0976,0.0176 l -1,0.25 a 0.50005,0.50005 0 1 0 0.24218,0.96876 l 1,-0.25 a 0.50005,0.50005 0 0 0 -0.0937,-0.98633 0.50005,0.50005 0 0 0 -0.0508,0 z"
- transform="rotate(-180,338.49999,225.49747)"
- id="path14379"
+ transform="matrix(-0.248353,0.0281678,0.0283072,0.248422,140.452,86.0103)"
+ style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ d="m 140,118 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z"
+ id="circle44389"
inkscape:connector-curvature="0" />
</g>
+ </g>
+ <g
+ id="g5260"
+ transform="translate(21,42)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="V-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 176.5,-32 c 0.8225,0 1.5,-0.677495 1.5,-1.5 0,-0.822505 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.677495 -1.5,1.5 0,0.822505 0.6775,1.5 1.5,1.5 z"
- id="circle14385"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="path13014"
+ d="m 176.5,410 a 0.50005,0.50005 0 1 0 0,1 h 0.79297 L 178,411.70703 v 10.58594 L 177.29297,423 H 176.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 0.64648,-0.64649 0.64648,0.64649 A 0.50005,0.50005 0 0 0 179.5,424 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.79297 L 179,422.29297 V 411.70703 L 179.70703,411 H 180.5 a 0.50005,0.50005 0 1 0 0,-1 h -1 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.64648,0.64649 -0.64648,-0.64649 A 0.50005,0.50005 0 0 0 177.5,410 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path13066"
+ d="m 174.5,414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v -1 h -2 v -4 h 2 v -1 z m 5.5,0 v 1 h 7.00781 v 4 H 180 v 1 h 7.50781 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 412,120 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z m 0,1 c 1.11049,0 2,0.88951 2,2 0,1.11049 -0.88951,2 -2,2 -1.11049,0 -2,-0.88951 -2,-2 0,-1.11049 0.88951,-2 2,-2 z"
- id="circle14295"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 13.492188,54.005859 a 0.50005,0.50005 0 0 0 -0.345704,0.146485 l -3.9999996,4 a 0.50005,0.50005 0 1 0 0.7070312,0.707031 L 13,55.712891 v 9.792968 a 0.50005,0.50005 0 1 0 1,0 v -9.792968 l 3.146484,3.146484 a 0.50005,0.50005 0 1 0 0.707032,-0.707031 l -4,-4 a 0.50005,0.50005 0 0 0 -0.361328,-0.146485 z"
- id="path14327"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 34.492188,54.005859 A 0.50005,0.50005 0 0 0 34,54.511719 v 9.792969 l -3.146484,-3.146485 a 0.50005,0.50005 0 1 0 -0.707032,0.707031 l 4,4 a 0.50005,0.50005 0 0 0 0.707032,0 l 4,-4 A 0.50005,0.50005 0 1 0 38.146484,61.158203 L 35,64.304688 v -9.792969 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z"
- id="path14329"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.79999995;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 202.5,621.00003 a 5.4999997,5.4999997 0 0 0 -5.5,5.5 5.4999997,5.4999997 0 0 0 5.5,5.5 5.4999997,5.4999997 0 0 0 5.5,-5.5 5.4999997,5.4999997 0 0 0 -5.5,-5.5 z m -0.002,1.98438 a 0.50005001,0.50005001 0 0 1 0.50781,0.52343 v 2.5 h 2.50195 a 0.50005001,0.50005001 0 1 1 0,0.99805 h -2.50195 v 2.50195 a 0.50005001,0.50005001 0 0 1 -0.50586,0.50586 0.50005001,0.50005001 0 0 1 -0.49219,-0.50586 v -2.50195 h -2.5 a 0.50005001,0.50005001 0 1 1 0,-0.99805 h 2.5 v -2.5 a 0.50005001,0.50005001 0 0 1 0.49024,-0.52343 z"
- id="path14370"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 33.75,200 c -0.212514,-4.2e-4 -0.402079,0.13353 -0.472656,0.33398 L 31.644531,205 H 27.5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 0.75 c 4.22e-4,0.17006 0.08724,0.32824 0.230469,0.41992 l 3.166015,2.03711 -1.367187,3.87695 c -0.01909,0.0533 -0.029,0.10942 -0.0293,0.16602 v 0.75 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 0.75 c 0.119714,-2e-5 0.235448,-0.043 0.326172,-0.12109 L 33.935547,211 h 0.128906 l 3.359375,2.87891 c 0.09174,0.079 0.209022,0.12201 0.330078,0.12109 L 38.5,213.99414 c 0.273087,-0.002 0.49394,-0.223 0.496094,-0.49609 L 39,212.75195 c -7.9e-5,-0.0572 -0.01,-0.11407 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 C 40.912757,206.57824 40.999577,206.42006 41,206.25 v -0.75 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -4.144531 l -1.632813,-4.66602 C 34.652079,200.13353 34.462514,199.99958 34.25,200 h -0.251953 z"
- id="path14398"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 12.75,200 a 0.50004997,0.50004997 0 0 0 -0.472656,0.33398 L 10.644531,205 H 6.5 A 0.50004997,0.50004997 0 0 0 6,205.5 v 0.75 a 0.50004997,0.50004997 0 0 0 0.2304688,0.41992 l 3.1660156,2.03711 -1.3671875,3.87695 A 0.50004997,0.50004997 0 0 0 8,212.75 v 0.75 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 0.75 a 0.50004997,0.50004997 0 0 0 0.3261719,-0.12109 L 12.935547,211 h 0.128906 l 3.359375,2.87891 A 0.50004997,0.50004997 0 0 0 16.753906,214 L 17.5,213.99414 a 0.50004997,0.50004997 0 0 0 0.496094,-0.49609 L 18,212.75195 a 0.50004997,0.50004997 0 0 0 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 A 0.50004997,0.50004997 0 0 0 20,206.25 V 205.5 A 0.50004997,0.50004997 0 0 0 19.5,205 h -4.144531 l -1.632813,-4.66602 A 0.50004997,0.50004997 0 0 0 13.25,200 h -0.251953 z m 0.25,1.30078 1.527344,4.36524 A 0.50004997,0.50004997 0 0 0 15,206 h 3.962891 l -3.232422,2.08008 a 0.50004997,0.50004997 0 0 0 -0.201172,0.58594 L 17,212.83398 l -0.002,0.16407 h -0.06445 l -3.357422,-2.87696 A 0.50004997,0.50004997 0 0 0 13.25,210 h -0.5 a 0.50004997,0.50004997 0 0 0 -0.326172,0.12109 L 9.0644531,213 H 9 v -0.16406 l 1.470703,-4.16992 a 0.50004997,0.50004997 0 0 0 -0.201172,-0.58594 L 7.0371094,206 H 11 a 0.50004997,0.50004997 0 0 0 0.472656,-0.33398 z"
- id="path14401"
- inkscape:connector-curvature="0" />
<g
- transform="translate(0.99996615,4.4999696e-6)"
- id="g13708"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ transform="translate(-126.004,357)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15185-9"
+ inkscape:label="V-9">
<path
+ id="circle24228-7-4-8"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 301,99 c -0.54636,0 -1,0.453638 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.546362 -0.45364,-1 -1,-1 z m 0,4 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 0,4 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3.5,-7 c -0.67616,-0.0096 -0.67616,1.00956 0,1 h 2.25977 c -0.20553,-0.30677 -0.35861,-0.64616 -0.48438,-1 z m 0,4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m 0,4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8 c 0.67616,0.01 0.67616,-1.00956 0,-1 z"
inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 48.5,578 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 L 47.9922,589 c 0,1.51667 1.219299,3 2.984374,3 1.765077,0 3.015625,-1.475 3.015626,-3 L 54,578.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 2.5,10 c 0.546362,0 1,0.45364 1,1 0,0.54636 -0.453638,1 -1,1 -0.546362,0 -1,-0.45364 -1,-1 0,-0.54636 0.453638,-1 1,-1 z"
- transform="translate(-0.99998)"
- id="path13694" />
+ sodipodi:nodetypes="sssssssssssssssccccccccccccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 58.492188,586 c -0.132599,2e-5 -0.259759,0.0527 -0.353516,0.14648 l -4.75,4.75 c -0.09377,0.0938 -0.14646,0.22092 -0.146484,0.35352 v 0.25 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 H 60.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- id="path13696"
+ sodipodi:nodetypes="sssssccccccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccc" />
+ id="path13640-7-5"
+ d="m 310.5,95 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ </g>
+ <g
+ id="g28614"
+ transform="translate(-147,357)"
+ style="display:inline;enable-background:new"
+ inkscape:label="V-8">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 56.486328,579 c -0.130565,0.002 -0.25534,0.0541 -0.347656,0.14648 l -2,2 c -0.09377,0.0938 -0.14646,0.22092 -0.146484,0.35352 v 6 c 1.71e-4,0.44532 0.538516,0.6683 0.853515,0.35352 l 5,-5 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 C 56.750515,579.05126 56.620954,578.99846 56.486328,579 Z"
- id="path13698"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccc" />
+ id="path28606"
+ transform="translate(42)"
+ d="m 263.50391,94.996094 c -0.25245,0 -0.505,0.169732 -0.5,0.507812 L 263,97 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.5 l -1.49414,-0.002 c -0.67616,-0.0096 -0.67616,1.01 0,1 L 260,101 v 2 l -1.49414,-0.002 c -0.67616,-0.01 -0.67616,1.01 0,1 L 260,104 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 l 0.004,1.49609 c -0.01,0.67616 1.00956,0.67616 1,0 L 264,107 h 2 l 0.004,1.49609 c -0.01,0.67616 1.00956,0.67616 1,0 L 267,107 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 104 l 1.49805,-0.002 c 0.67616,0.01 0.67616,-1.00956 0,-1 L 270,103 v -2 l 1.49805,-0.002 c 0.67616,0.01 0.67616,-1.009563 0,-1.000003 L 270,100 V 97.5 A 0.50005,0.50005 0 0 0 269.5,97 H 267 l 0.004,-1.496094 c 0.01,-0.67616 -1.01,-0.67616 -1,0 L 266,97 h -2 l 0.004,-1.496094 c 0.005,-0.33808 -0.24756,-0.507812 -0.5,-0.507812 z M 261,98 h 8 v 8 h -8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ id="g28608"
+ transform="rotate(180,370.0035,70.5)" />
+ <path
+ inkscape:connector-curvature="0"
+ id="rect28616"
+ d="m 305.5,100 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g38065"
+ inkscape:label="V-7"
+ style="display:inline;enable-background:new">
+ <path
+ id="path6600"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 138.51562,452 c 0.752,0 1.45382,0.239 2.02344,0.64453 0.88567,0.63055 1.46094,1.67061 1.46094,2.83985 V 458.5 c -3e-5,0.27537 -0.22268,0.4989 -0.49805,0.5 l -4.00976,0.008 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 L 137,452.53516 v -0.002 -0.0352 c 0.001,-0.27524 0.22466,-0.49793 0.5,-0.49796 z M 136,452 v 1 h -1.51563 C 133.09986,453 132,454.09985 132,455.48438 v 8.03124 c 0,1.38452 1.09986,2.48438 2.48437,2.48438 h 4.03125 C 139.90014,466 141,464.90014 141,463.51562 V 460 h 1 v 3.51562 C 142,465.43685 140.43685,467 138.51562,467 h -4.03125 C 132.56315,467 131,465.43686 131,463.51562 v -8.03124 C 131,453.56315 132.56315,452 134.48437,452 Z m 7.47656,-0.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 144,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 146,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g38062"
+ inkscape:label="V-6"
+ style="display:inline;enable-background:new">
+ <path
+ id="path6598"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 113.48438,452 C 111.56315,452 110,453.56315 110,455.48438 v 8.03124 c 0,1.92123 1.56315,3.48438 3.48438,3.48438 h 4.03125 C 119.43685,467 121,465.43685 121,463.51562 v -8.03124 C 121,453.56315 119.43685,452 117.51563,452 Z m 0,1 h 4.03125 c 1.38452,0 2.48437,1.09985 2.48437,2.48438 v 8.03124 C 120,464.90015 118.90015,466 117.51563,466 h -4.03125 C 112.09985,466 111,464.90015 111,463.51562 v -8.03124 C 111,454.09985 112.09985,453 113.48438,453 Z m 1.5625,1 C 114.47554,454 114,454.47555 114,455.04688 v 3.90624 c 0,0.57133 0.47554,1.04688 1.04688,1.04688 h 0.90625 C 116.52446,460 117,459.52445 117,458.95312 v -3.90624 C 117,454.47555 116.52446,454 115.95313,454 Z m 7.42968,-2.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 123,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 125,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ inkscape:connector-curvature="0" />
</g>
<g
+ id="g38059"
+ inkscape:label="V-5"
+ style="display:inline;enable-background:new">
+ <path
+ id="path6596"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 92.484375,452 c -0.752,0 -1.453818,0.239 -2.023438,0.64453 C 89.575267,453.27508 89,454.31514 89,455.48438 V 458.5 c 3e-5,0.27537 0.222677,0.4989 0.498047,0.5 l 4.009765,0.008 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 94,452.53516 v -0.002 -0.0352 C 93.999,452.22272 93.77534,452.00003 93.5,452 Z M 95,452 v 1 h 1.515625 C 97.900145,453 99,454.09985 99,455.48438 v 8.03124 C 99,464.90014 97.900145,466 96.515625,466 h -4.03125 C 91.099855,466 90,464.90014 90,463.51562 V 460 h -1 v 3.51562 C 89,465.43685 90.563145,467 92.484375,467 h 4.03125 C 98.436855,467 100,465.43686 100,463.51562 v -8.03124 C 100,453.56315 98.436855,452 96.515625,452 Z m 6.47656,-0.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 102,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 104,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-84,1.45e-5)"
+ id="g10880"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g9998"
- transform="matrix(-1,0,0,1,907.99986,4.6999695e-6)">
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="V-4">
<g
- transform="matrix(-0.61504365,0,0,0.61502939,510.71013,122.71015)"
- id="g13879"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.6259197;enable-background:new" />
+ transform="translate(-523,-56)"
+ id="g10853"
+ style="fill:#ffffff" />
<g
- id="g9988"
+ id="g10878"
style="fill:#ffffff">
<path
- id="path13882"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 478.49219,473.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m -0.49233,3.9922 2.99609,0.006 c 0.2754,6.1e-4 0.49976,0.22265 0.5,0.49805 l 0.004,6.45885 c 0,1.02328 -0.80629,2.03747 -2,2.03711 -1.19534,0 -1.99609,-1.02155 -1.99609,-2.04297 l -0.004,-6.45704 c 1.8e-4,-0.27638 0.22362,-0.50048 0.5,-0.5 z m 1.5,6 a 1,0.99999999 0 0 0 -1,1.00001 1,0.99999999 0 0 0 1,1 1,0.99999999 0 0 0 1,-1 1,0.99999999 0 0 0 -1,-1.00001 z"
- inkscape:connector-curvature="0" />
- <path
- id="path13884"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 469.49219,474.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m 5.5151,2.99233 c 0.12999,0.002 0.25408,0.0546 0.34596,0.14655 l 1.00065,0.99942 c 0.094,0.094 0.14673,0.22146 0.14655,0.35436 v 4.0001 c 2e-5,0.4458 -0.53925,0.66879 -0.85409,0.35316 l -2.99954,-3.00067 c -0.19472,-0.19518 -0.19472,-0.51115 0,-0.70633 l 2.00009,-2.00004 c 0.0954,-0.0955 0.2254,-0.14835 0.36038,-0.14655 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 157.49219,453.99222 A 0.50005,0.50005 0 0 0 157,454.50003 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path10874"
inkscape:connector-curvature="0" />
<path
- id="path13886"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 468.49219,483.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,10e-6 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,10e-6 -1.3386,0 -2.00781,0 z m 4.52221,-1.00695 c 0.12731,0.004 0.24847,0.0555 0.33876,0.14535 l 3.00074,3.00066 c 0.31399,0.31533 0.0906,0.8529 -0.35437,0.85288 h -2.99954 c -0.27591,-1.9e-4 -0.49954,-0.22381 -0.49972,-0.49972 v -2.99946 c 7e-5,-0.28163 0.23261,-0.50765 0.51413,-0.49971 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 80.476562,451.02148 a 0.50005,0.50005 0 0 0 -0.314453,0.8711 c 0.58809,0.54453 0.841797,1.0856 0.841797,1.60156 L 81,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.0039,-6.00586 c 0,-0.8509 -0.431789,-1.65971 -1.162109,-2.33594 a 0.50005,0.50005 0 0 0 -0.365235,-0.13672 z M 71.5625,452 C 69.59752,452 68,453.59753 68,455.5625 v 7.875 C 68,465.40247 69.59752,467 71.5625,467 h 3.875 C 77.40247,467 79,465.40247 79,463.4375 v -7.875 C 79,453.59753 77.40247,452 75.4375,452 Z m 0,1 h 3.875 C 76.86577,453 78,454.13423 78,455.5625 v 7.875 C 78,464.86577 76.86577,466 75.4375,466 h -3.875 C 70.13422,466 69,464.86577 69,463.4375 v -7.875 C 69,454.13423 70.13422,453 71.5625,453 Z m 11.929688,0.0371 A 0.50005,0.50005 0 0 0 83,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z"
+ transform="translate(84,-1.45e-5)"
+ id="rect10876"
inkscape:connector-curvature="0" />
</g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 304.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 4.5,5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -8.5,2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
- id="rect13801"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14472"
- transform="translate(-42.000002,4.4999696e-6)">
+ id="g38056"
+ inkscape:label="V-3"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 373.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -10.5,9 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
- id="rect14387"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 56.515625,452 c 0.752,0 1.453818,0.239 2.023438,0.64453 C 59.424733,453.27508 60,454.31514 60,455.48438 V 458.5 c -3e-5,0.27537 -0.222677,0.4989 -0.498047,0.5 l -4.009765,0.008 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 L 55,452.53516 v -0.002 -0.0352 C 55.001,452.22272 55.22466,452.00003 55.5,452 Z M 54,452 v 1 H 52.484375 C 51.099855,453 50,454.09985 50,455.48438 v 8.03124 C 50,464.90014 51.099855,466 52.484375,466 h 4.03125 C 57.900145,466 59,464.90014 59,463.51562 V 460 h 1 v 3.51562 C 60,465.43685 58.436855,467 56.515625,467 h -4.03125 C 50.563145,467 49,465.43686 49,463.51562 v -8.03124 C 49,453.56315 50.563145,452 52.484375,452 Z"
+ id="path6557"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g38032"
+ inkscape:label="V-2"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 366.49219,160.99219 a 0.50005,0.50005 0 0 0 -0.31641,0.12109 0.50005,0.50005 0 0 0 -0.0195,0.0156 0.50005,0.50005 0 0 0 -0.0176,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 366,161.58203 V 162.5 a 0.50005,0.50005 0 1 0 1,0 V 162 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.008 z m 7,0 A 0.50005,0.50005 0 0 0 373.41797,161 H 372.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.91992 a 0.50005,0.50005 0 0 0 -0.11328,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.11133 z M 369.5,161 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -3.00781,2.99219 A 0.50005,0.50005 0 0 0 366,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7,0 A 0.50005,0.50005 0 0 0 373,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -7,3 A 0.50005,0.50005 0 0 0 366,167.5 v 0.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 366.58203,169 H 367.5 a 0.50005,0.50005 0 1 0 0,-1 H 367 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7,0 A 0.50005,0.50005 0 0 0 373,167.5 v 0.5 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.0312 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.004 A 0.50005,0.50005 0 0 0 374,168.41797 V 167.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 369.5,168 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14452"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="rect10947"
+ d="M 31.484375,452 C 29.563145,452 28,453.56315 28,455.48438 v 8.03124 C 28,465.43685 29.563145,467 31.484375,467 h 4.03125 C 37.436855,467 39,465.43685 39,463.51562 v -8.03124 C 39,453.56315 37.436855,452 35.515625,452 Z m 0,1 h 4.03125 C 36.900155,453 38,454.09985 38,455.48438 v 8.03124 C 38,464.90015 36.900155,466 35.515625,466 h -4.03125 C 30.099845,466 29,464.90015 29,463.51562 v -8.03124 C 29,454.09985 30.099845,453 31.484375,453 Z m 1.5625,1 C 32.475545,454 32,454.47555 32,455.04688 v 3.90624 C 32,459.52445 32.475545,460 33.046875,460 h 0.90625 C 34.524455,460 35,459.52445 35,458.95312 v -3.90624 C 35,454.47555 34.524455,454 33.953125,454 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14467"
- transform="translate(-63.000002,4.4999696e-6)">
+ id="g38029"
+ inkscape:label="V-1"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 347.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.5 h -1.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -2,3 h 2 v 2 h -2 z m 4,1 h 2 v 2 h -2 z"
- id="rect14393"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc" />
+ id="path10927"
+ d="m 10.484375,452 c -0.752,0 -1.4538175,0.239 -2.0234375,0.64453 C 7.5752675,453.27508 7,454.31514 7,455.48438 V 458.5 c 3e-5,0.27537 0.2226769,0.4989 0.4980469,0.5 l 4.0097651,0.008 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 12,452.53516 v -0.002 -0.0352 C 11.999,452.22272 11.77534,452.00003 11.5,452 Z M 13,452 v 1 h 1.515625 C 15.900145,453 17,454.09985 17,455.48438 v 8.03124 C 17,464.90014 15.900145,466 14.515625,466 h -4.03125 C 9.099855,466 8,464.90014 8,463.51562 V 460 H 7 v 3.51562 C 7,465.43685 8.563145,467 10.484375,467 h 4.03125 C 16.436855,467 18,465.43686 18,463.51562 v -8.03124 C 18,453.56315 16.436855,452 14.515625,452 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g76955"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-26"
+ transform="matrix(1,0,0,-1,0,876)">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 342.49219,157.99219 a 0.50005,0.50005 0 0 0 -0.31641,0.12109 0.50005,0.50005 0 0 0 -0.0195,0.0156 0.50005,0.50005 0 0 0 -0.0176,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0274,0.0371 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 342,158.58203 V 159.5 a 0.50005,0.50005 0 1 0 1,0 V 159 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.008 z m 13,0 A 0.50005,0.50005 0 0 0 355.41797,158 H 354.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.91992 a 0.50005,0.50005 0 0 0 -0.11328,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.11133 z M 345.5,158 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -9.00781,2.99219 A 0.50005,0.50005 0 0 0 342,161.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,161.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,167.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,167.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,170.5 v 0.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 342.58203,172 H 343.5 a 0.50005,0.50005 0 1 0 0,-1 H 343 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,170.5 v 0.5 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.0312 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0274,-0.0371 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.074,-0.35325 V 170.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 345.5,171 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14460"
- inkscape:connector-curvature="0" />
+ id="path19349-4"
+ style="display:inline;enable-background:accumulate;color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto"
+ d="m 534.23047,436.74023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -1.47656,1.47656 c -0.71563,0.66862 -1.1007,1.61087 -1.04883,2.55664 0.0519,0.94577 0.50998,1.86545 1.27539,2.63086 0.76642,0.76642 1.68942,1.21503 2.6289,1.25977 0.93949,0.0447 1.85838,-0.33299 2.53516,-1.00977 l 1.5,-1.5 a 1.0001,1.0001 0 1 0 -1.41406,-1.41406 l -1.5,1.5 c -0.32323,0.32322 -0.65433,0.4455 -1.02735,0.42773 -0.37301,-0.0178 -0.82501,-0.19415 -1.30859,-0.67773 -0.48459,-0.48459 -0.6709,-0.9542 -0.69141,-1.32813 -0.0205,-0.37392 0.0941,-0.68177 0.41797,-0.98437 a 1.0001,1.0001 0 0 0 0.0234,-0.0234 l 1.5,-1.5 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z m 6.84765,-5.70703 c -0.93948,-0.0447 -1.85838,0.33299 -2.53515,1.00977 l -1.5,1.5 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 1.5,-1.5 c 0.32322,-0.32322 0.65433,-0.4455 1.02734,-0.42773 0.37302,0.0178 0.82502,0.19415 1.3086,0.67773 0.48459,0.48459 0.6709,0.9542 0.6914,1.32813 0.0205,0.37392 -0.0941,0.68177 -0.41796,0.98437 a 1.0001,1.0001 0 0 0 -0.0234,0.0234 l -1.5,1.5 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 1.47656,-1.47656 c 0.71562,-0.66862 1.1007,-1.61087 1.04883,-2.55664 -0.0519,-0.94577 -0.50998,-1.86545 -1.27539,-2.63086 -0.76642,-0.76642 -1.68942,-1.21503 -2.62891,-1.25977 z m -1.09765,3.95703 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -4,4 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 4,-4 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ inkscape:connector-curvature="0"
+ transform="matrix(1,0,0,-1,0,876)" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 118.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 212 h -6.5 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 202 h 5.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path13715"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 144.5,201 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 133.29297,212 H 132.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 L 144.70703,202 H 145.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path13875"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g13432">
+ id="g76979"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-25">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 166,201 c -1.59692,0 -2.85915,0.78757 -3.86133,1.88086 -1.00218,1.09329 -1.79297,2.49805 -2.57422,3.87305 -0.78125,1.375 -1.55296,2.72024 -2.4414,3.68945 C 156.2346,211.41257 155.27808,212 154,212 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 1.59692,0 2.85915,-0.78757 3.86133,-1.88086 1.00218,-1.09329 1.79297,-2.49805 2.57422,-3.87305 0.78125,-1.375 1.55296,-2.72024 2.4414,-3.68945 C 163.7654,202.58743 164.72192,202 166,202 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14036"
+ id="path16385"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 515.5,432 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14647 L 513.29297,434 H 510.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6.45312 0.004 c 0.0131,-8.2e-4 0.0261,-0.002 0.0391,-0.004 0.004,5e-5 0.008,5e-5 0.0117,0 0.0143,0.002 0.0286,0.003 0.043,0.004 h 0.006 5.44336 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.79297 l -1.85351,-1.85353 C 518.76,432.05268 518.6327,431.99995 518.5,432 Z m 1.49781,1.99804 c 2.21589,-3.2e-4 4.00185,1.7855 4.00195,4.00196 -9e-4,2.19736 -1.75841,3.97457 -3.95508,4 -0.0131,8.2e-4 -0.0261,0.002 -0.0391,0.004 -0.0149,-0.002 -0.0299,-0.003 -0.0449,-0.004 -10e-4,0 -0.003,0 -0.004,0 -2.19824,-0.0228 -3.95803,-1.80057 -3.95898,-4 9e-5,-2.21578 1.78479,-4.00131 4,-4.00196 z M 516.99805,435 C 515.34742,435 514,436.34922 514,438 c 0,1.65079 1.34742,3 2.99805,3 1.65063,0 3,-1.34921 3,-3 0,-1.65078 -1.34937,-3 -3,-3 z m 0,1 c 1.11009,0 2,0.88955 2,2 0,1.11045 -0.88991,2 -2,2 C 515.88796,440 515,439.11045 515,438 c 0,-1.11045 0.88796,-2 1.99805,-2 z"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g76982"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 154.5,200 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 202 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 H 157 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 0.41992 a 0.50005,0.50005 0 0 0 0,0.16211 V 202 h -1 z m 8.50781,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 v -0.42383 a 0.50005,0.50005 0 0 0 0,-0.15234 z"
- id="path14257"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path22635-0-9"
+ d="m 494.5,432 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 492.29297,434 H 489.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.79297 l -1.85351,-1.85352 A 0.50005,0.50005 0 0 0 497.5,432 Z m 0.20703,1 h 2.58594 l 1.85351,1.85352 A 0.50005,0.50005 0 0 0 499.5,435 h 1.5 v 7 h -11 v -7 h 2.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z m -0.46094,2.74414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 l 1.39649,1.39648 -1.39649,1.39648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 496,438.70703 l 1.39648,1.39649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 496.70703,438 l 1.39649,-1.39648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 L 496,437.29297 l -1.39648,-1.39649 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 291.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,2.47889 -0.15954,4.38104 -0.52734,5.8125 -0.36781,1.43146 -0.92559,2.38009 -1.74024,3.05273 C 287.10312,211.71053 284.21571,212 279.5,212 a 0.50005,0.50005 0 1 0 0,1 c 4.75093,0 7.86511,-0.21053 9.86914,-1.86523 1.00202,-0.82736 1.66924,-2.00373 2.07227,-3.57227 0.36978,-1.43916 0.48747,-3.33151 0.51171,-5.5625 H 292.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14276"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 312.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,3.43021 -1.19149,5.7903 -3.2168,7.45898 -2.0253,1.66869 -4.93239,2.63003 -8.34375,3.04493 a 0.50005,0.50005 0 1 0 0.1211,0.99218 c 3.52614,-0.42885 6.61905,-1.41978 8.85937,-3.26562 2.13154,-1.75622 3.41037,-4.32825 3.5332,-7.73047 H 313.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14278"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 439,201 c -1.59692,0 -2.85915,0.78757 -3.86133,1.88086 -1.00218,1.09329 -1.79297,2.49805 -2.57422,3.87305 -0.78125,1.375 -1.55296,2.72024 -2.4414,3.68945 C 429.2346,211.41257 428.27808,212 427,212 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 1.59692,0 2.85915,-0.78757 3.86133,-1.88086 1.00218,-1.09329 1.79297,-2.49805 2.57422,-3.87305 0.78125,-1.375 1.55296,-2.72024 2.4414,-3.68945 C 436.7654,202.58743 437.72192,202 439,202 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14305"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 321.5,201 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 0.11714,0 0.21825,0.0354 0.36133,0.1582 0.14308,0.12279 0.30922,0.33684 0.46875,0.63282 0.31905,0.59195 0.61443,1.49542 0.87109,2.55468 0.51334,2.11854 0.89163,4.86411 1.30664,7.24024 a 0.50005,0.50005 0 0 0 0.98242,0.008 c 0.24141,-1.26736 0.60565,-2.19557 0.98829,-2.76953 0.38264,-0.57396 0.74023,-0.76172 1.02148,-0.76172 0.28125,0 0.63884,0.18776 1.02148,0.76172 0.38264,0.57396 0.74688,1.50217 0.98829,2.76953 a 0.50005,0.50005 0 0 0 0.96093,0.0762 c 0.24086,-0.66235 0.48023,-1.14224 0.6836,-1.42187 0.20337,-0.27964 0.32487,-0.31055 0.3457,-0.31055 0.0208,0 0.14233,0.0309 0.3457,0.31055 0.20337,0.27963 0.44274,0.75952 0.6836,1.42187 A 0.50005,0.50005 0 0 0 333.5,213 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.69141 c -0.20925,-0.52074 -0.41629,-1.01454 -0.65429,-1.3418 -0.29663,-0.40786 -0.67513,-0.7207 -1.1543,-0.7207 -0.47917,0 -0.85767,0.31284 -1.1543,0.7207 -0.10194,0.14017 -0.18655,0.39972 -0.28125,0.57422 -0.21984,-0.70238 -0.40285,-1.50076 -0.71093,-1.96289 -0.49236,-0.73854 -1.13477,-1.20703 -1.85352,-1.20703 -0.71875,0 -1.36116,0.46849 -1.85352,1.20703 -0.20879,0.3132 -0.31334,0.90706 -0.48242,1.33008 -0.30463,-1.87209 -0.5915,-3.83467 -0.99218,-5.48828 -0.26658,-1.10016 -0.56623,-2.0626 -0.96094,-2.79492 -0.19736,-0.36617 -0.41893,-0.67716 -0.69727,-0.91602 C 322.73533,201.16153 322.38008,201 322,201 Z"
- id="path53380-0"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 342.45117,201 a 0.50059574,0.50059574 0 0 0 0.0488,1 c 0.0215,2e-5 0.18225,-1.7e-4 0.33398,0 0.0105,0.42607 0.0502,2.52232 0.33594,5.05664 0.15671,1.39002 0.37504,2.78188 0.69727,3.86719 0.16111,0.54265 0.34457,1.00922 0.59179,1.38086 0.24723,0.37163 0.61429,0.69531 1.09375,0.69531 0.39174,0 0.74881,-0.20864 0.97657,-0.48047 0.22775,-0.27182 0.37091,-0.59987 0.48632,-0.96289 0.23084,-0.72603 0.34622,-1.61436 0.46876,-2.48828 0.12253,-0.87392 0.25275,-1.73314 0.44921,-2.31641 0.0982,-0.29163 0.21467,-0.50852 0.31446,-0.62109 C 348.34784,206.01829 348.39286,206 348.5,206 c 0.16824,0 0.2932,0.0848 0.48633,0.39062 0.19312,0.30582 0.37727,0.78401 0.5625,1.28321 0.18523,0.49919 0.37171,1.01992 0.64453,1.46289 0.27281,0.44297 0.71019,0.86328 1.30664,0.86328 0.41993,0 0.77613,-0.23568 0.99219,-0.49219 0.21606,-0.2565 0.34747,-0.53797 0.4707,-0.78906 0.12323,-0.25109 0.23849,-0.47074 0.33594,-0.58984 C 353.39628,208.0098 353.41651,208 353.5,208 c 0.0859,0 0.18647,0.0811 0.39844,0.32617 0.10598,0.12255 0.22449,0.26923 0.39453,0.40625 C 354.463,208.86945 354.71104,209 355,209 c 0.008,0 0.14542,-2.8e-4 0.27539,0 0.065,1.4e-4 0.13031,6e-5 0.18164,0 0.0513,-6e-5 0.0312,0.005 0.12109,0 a 0.50080138,0.50080138 0 1 0 -0.0566,-1 c 0.0748,-0.004 -0.0172,-5e-5 -0.0664,0 -0.0492,5e-5 -0.11331,1.4e-4 -0.17774,0 -0.12885,-2.8e-4 -0.25041,0 -0.27734,0 -0.0108,0 -0.0173,0.004 -0.0801,-0.0469 -0.0628,-0.0506 -0.15527,-0.15364 -0.26562,-0.28124 C 354.43358,207.41667 354.08387,207 353.5,207 c -0.4167,0 -0.76719,0.23824 -0.97656,0.49414 -0.20937,0.2559 -0.33683,0.53625 -0.45899,0.78516 -0.12215,0.24891 -0.23808,0.46744 -0.33789,0.58593 C 351.62675,208.98373 351.59835,209 351.5,209 c -0.14972,0 -0.26794,-0.0816 -0.45703,-0.38867 -0.18909,-0.30703 -0.37082,-0.78435 -0.55664,-1.28516 -0.18583,-0.5008 -0.37575,-1.02457 -0.65625,-1.46875 C 349.54958,205.41324 349.10136,205 348.5,205 c -0.39664,0 -0.76041,0.19848 -1,0.46875 -0.23959,0.27027 -0.39279,0.60017 -0.51562,0.96484 -0.24567,0.72934 -0.36739,1.61988 -0.49024,2.4961 -0.12285,0.87621 -0.24515,1.73764 -0.43164,2.32422 -0.0933,0.29328 -0.20581,0.51202 -0.29883,0.62304 -0.093,0.11102 -0.1237,0.12305 -0.21094,0.12305 -0.027,0 -0.10877,-0.0201 -0.26171,-0.25 -0.15295,-0.22991 -0.31979,-0.62276 -0.46485,-1.11133 -0.29011,-0.97714 -0.5088,-2.33541 -0.66211,-3.69531 -0.30662,-2.7198 -0.36328,-5.45313 -0.36328,-5.45313 a 0.50005,0.50005 0 0 0 -0.5,-0.49023 c -0.0468,0 -0.74734,5e-5 -0.80078,0 a 0.50005,0.50005 0 0 0 -0.0488,0 z"
- id="path16468-1"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14237">
+ id="g76985"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-23">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 207.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 200.78129,210.37772 198.70216,212 195.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 208.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14262"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path19969-0"
+ d="m 470.49125,433 c -0.3497,0.006 -0.58488,0.36077 -0.45507,0.68555 l 4,10.00195 c 0.1779,0.45034 0.82806,0.4102 0.94922,-0.0586 l 1.17578,-4.46875 4.46679,-1.17578 c 0.46499,-0.12321 0.50486,-0.76769 0.0586,-0.94727 l -10,-4.00195 c -0.0621,-0.0247 -0.12852,-0.0366 -0.19532,-0.0351 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g76988"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-22">
+ <path
+ inkscape:connector-curvature="0"
+ id="path19971-4"
+ d="m 449.49078,433 a 0.50005,0.50005 0 0 0 -0.45507,0.68555 l 4,10.00195 a 0.50050292,0.50050292 0 1 0 0.92968,-0.37109 l -3.5664,-8.91797 8.91601,3.5664 a 0.50005,0.50005 0 1 0 0.3711,-0.92773 l -10,-4.00195 A 0.50005,0.50005 0 0 0 449.49078,433 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g76952"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-21">
<path
+ inkscape:connector-curvature="0"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 197,199.99609 c -0.79172,0 -1.70536,0.42738 -1.98047,1.35938 a 0.50090117,0.50090117 0 1 0 0.96094,0.2832 c 0.12417,-0.42064 0.57767,-0.64258 1.01953,-0.64258 0.26308,0 0.50603,0.0889 0.67773,0.2461 0.17133,0.15683 0.29488,0.38005 0.29883,0.75976 0.001,0.2095 -0.10056,0.41777 -0.33789,0.6875 -0.23733,0.26973 -0.59584,0.56699 -0.97656,0.90235 -0.76143,0.67072 -1.65792,1.5571 -1.66211,2.90234 a 0.50005,0.50005 0 0 0 0.5,0.50195 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -2.33398 c 0.18416,-0.62502 0.58645,-1.15066 1.1582,-1.65429 0.36326,-0.31999 0.74752,-0.62977 1.0664,-0.99219 0.31889,-0.36243 0.58851,-0.81103 0.58594,-1.35156 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.61869 -0.24656,-1.14755 -0.62304,-1.49218 -0.37648,-0.34464 -0.8666,-0.50782 -1.35352,-0.50782 z"
- id="path12457-3"
- inkscape:connector-curvature="0" />
+ d="m 432.49961,433 c -3.27784,-9.4e-4 -5.036,2.7211 -6.36328,4.16211 -0.17644,0.19146 -0.17644,0.48627 0,0.67773 1.3275,1.44124 3.08593,4.15993 6.36328,4.16211 3.27801,0.002 5.03608,-2.72118 6.36328,-4.16211 0.17644,-0.19146 0.17644,-0.48627 0,-0.67773 -1.32741,-1.44115 -3.08573,-4.16117 -6.36328,-4.16211 z m 0,1 a 3.4999952,3.4999933 0 0 1 3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,-3.5 3.4999952,3.4999933 0 0 1 3.5,-3.5 z m 0,2 a 1.4999952,1.4999944 0 0 0 -1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,-1.5 1.4999952,1.4999944 0 0 0 -1.5,-1.5 z"
+ id="path19347-7" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
+ id="g76991"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-20">
+ <path
+ inkscape:connector-curvature="0"
+ id="path13646-9"
+ d="m 405.50174,437 a 0.50005,0.50005 0 0 0 -0.33203,0.84375 c 1.3239,1.43817 3.0824,4.1582 6.3457,4.1582 3.26331,0 5.02376,-2.72003 6.34766,-4.1582 a 0.50037481,0.50037481 0 1 0 -0.73633,-0.67773 c -1.43556,1.55946 -2.90607,3.83593 -5.61133,3.83593 -2.70525,0 -4.17576,-2.27647 -5.61132,-3.83593 A 0.50005,0.50005 0 0 0 405.50174,437 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(-84,22)"
+ id="g13033"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14233">
+ inkscape:label="U-19">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 186.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 179.78129,210.37772 177.70216,212 174.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 187.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14011"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ccccccccsssss"
+ inkscape:connector-curvature="0"
+ id="path12959"
+ d="m 473.49999,411 -2.99609,0.006 c -0.2754,6.1e-4 -0.49976,0.22265 -0.5,0.49805 l -0.004,8.45884 c 0,1.02328 0.80629,2.03747 2,2.03711 1.19534,0 1.99609,-1.02155 1.99609,-2.04297 l 0.004,-8.45703 c -1.8e-4,-0.27638 -0.22362,-0.50048 -0.5,-0.5 z m -1.5,8 c 0.55228,0 1,0.44772 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 176.48438,199.99609 a 0.50005,0.50005 0 0 0 -0.3379,0.14649 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70703 L 176,201.70312 V 206.5 a 0.50005,0.50005 0 1 0 1,0 v -6.00391 a 0.50005,0.50005 0 0 0 -0.51562,-0.5 z"
- id="path12461-0"
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ id="path12972"
+ d="m 478.14648,418.14648 -3,3 c -0.31399,0.31533 -0.0915,0.85354 0.35352,0.85352 h 3 2 c 0.27591,-1.9e-4 0.49982,-0.22409 0.5,-0.5 v -3 c -7e-5,-0.28163 -0.23215,-0.50794 -0.51367,-0.5 h -2 c -0.12731,0.004 -0.24956,0.0566 -0.33985,0.14648 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ id="path12974"
+ d="m 477.49257,412.00014 c -0.12999,0.002 -0.25408,0.0546 -0.34596,0.14655 l -2.00065,1.99942 c -0.094,0.094 -0.14673,0.22146 -0.14655,0.35436 v 4.0001 c -2e-5,0.4458 0.53925,0.66879 0.85409,0.35316 l 3.99954,-4.00067 c 0.19472,-0.19518 0.19472,-0.51115 0,-0.70633 l -2.00009,-2.00004 c -0.0954,-0.0955 -0.2254,-0.14835 -0.36038,-0.14655 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g20019-5"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:label="U-18">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20013-1"
+ d="m 365.5,433 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8.5 c 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 v -8.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 8 c 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ id="path20015-6"
+ transform="translate(718,837)"
+ d="m -345.50781,-403 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 L -348,-400.70703 v 1.41406 l 2.5,-2.5 1.29297,1.29297 -3.79297,3.79297 v 1.41406 l 4.85352,-4.85351 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 A 0.50005,0.50005 0 0 0 -345.50781,-403 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path20017-8"
+ d="m 373.25,440 -1,1 H 375 v 2 h -4.75 l -1,1 h 6.25 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14241">
+ id="g23658-7-6"
+ transform="translate(-1113,-80)"
+ inkscape:label="U-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 228.5,201 a 0.50005,0.50005 0 0 0 -0.47461,0.3418 c -0.75176,2.25527 -1.61792,4.94183 -3.29101,7.0332 -1.6731,2.09137 -4.11183,3.625 -8.23438,3.625 a 0.50005,0.50005 0 1 0 0,1 c 4.37745,0 7.18872,-1.71637 9.01562,-4 1.74159,-2.17699 2.6089,-4.81175 3.33594,-7 H 229.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14266"
+ id="path23654-6-8"
+ transform="translate(0,-21)"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1456,538 v 7.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 538 Z m 5,1 h 2 a 1.0001,1.0001 0 1 1 0,2 h -2 a 1.0001,1.0001 0 1 1 0,-2 z m -5.5,-6 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 3 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 13 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -3 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g10909"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,1290,263)"
+ inkscape:label="U-16">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 218.99805,199.99609 c -0.79172,0 -1.70536,0.42738 -1.98047,1.35938 a 0.50005,0.50005 0 1 0 0.95898,0.2832 c 0.12417,-0.42064 0.57962,-0.64258 1.02149,-0.64258 0.26387,0 0.51715,0.0894 0.69531,0.24805 0.17816,0.15864 0.30325,0.37905 0.30664,0.75586 0.001,0.39768 -0.25396,0.75725 -0.76367,1.07422 a 0.50005,0.50005 0 0 0 0,0.84766 c 0.51034,0.31737 0.7656,0.67798 0.76367,1.07617 -0.004,0.37528 -0.12888,0.59561 -0.30664,0.7539 -0.17816,0.15864 -0.43144,0.24805 -0.69531,0.24805 -0.44187,0 -0.89732,-0.21999 -1.02149,-0.64062 a 0.50005,0.50005 0 1 0 -0.95898,0.28124 c 0.27511,0.93201 1.18875,1.35938 1.98047,1.35938 0.48612,0 0.97796,-0.16058 1.36133,-0.50195 0.38336,-0.34137 0.63501,-0.871 0.64062,-1.49414 a 0.50005,0.50005 0 0 0 0,-0.002 c 0.003,-0.61795 -0.34308,-1.09989 -0.77734,-1.5039 0.43425,-0.40402 0.78027,-0.88601 0.77734,-1.50391 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.62314 -0.25726,-1.15277 -0.64062,-1.49414 -0.38337,-0.34137 -0.87521,-0.50196 -1.36133,-0.50196 z"
- id="path14395"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 968.5,168.00021 c 0.2761,3e-5 0.5,0.22387 0.5,0.5 v 13 c 0,0.27613 -0.2239,0.49997 -0.5,0.5 h -13 c -0.2761,-3e-5 -0.5,-0.22387 -0.5,-0.5 v -13 c 0,-0.27613 0.2239,-0.49997 0.5,-0.5 z m -10,2 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 4.97656,3 c -0.1708,0.008 -0.32545,0.10335 -0.41015,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.43359,0.74805 h 8 c 0.3836,-4.7e-4 0.62389,-0.41493 0.43359,-0.74805 l -4,-7 c -0.093,-0.16311 -0.26943,-0.26042 -0.45703,-0.25195 z"
+ id="path10907"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14249">
+ id="g76946"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 270.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,3.44341 -1.07548,6.03173 -3.02344,7.79102 C 265.02861,211.0503 262.16329,212 258.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.83671,0 6.97139,-1.00062 9.14844,-2.9668 2.06597,-1.86586 3.15029,-4.63736 3.26367,-8.0332 H 271.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14273"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.25;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 302.64518,431.00052 a 1.1251124,1.1233465 0 0 0 -0.7734,0.3412 l -1.5313,1.5269 a 1.1251124,1.1233465 0 1 0 1.5918,1.5874 l 1.5293,-1.5269 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m 5.0977,0 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -6.6289,6.6185 a 1.125572,1.1238054 0 1 0 1.5918,1.5893 l 2.1289,-2.1256 c 0.2384,-1.1729 1.1734,-2.1044 2.3477,-2.344 l 2.1523,-2.1489 a 1.1251124,1.1233465 0 0 0 -0.8183,-1.9286 z m 5.0996,0 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -3.916,3.9099 c 0.7144,0.3005 1.2901,0.8706 1.5996,1.5795 l 3.9063,-3.9001 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m 0,5.0916 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -2.123,2.1197 c -0.2257,1.2122 -1.1902,2.1751 -2.4043,2.4005 l -2.1016,2.0983 a 1.1251124,1.1233465 0 1 0 1.5918,1.5873 l 6.627,-6.6165 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m -5.8418,0.9204 c -0.5601,0 -0.9917,0.4296 -0.9981,0.9867 0.01,0.5524 0.4434,0.9887 0.9981,0.9887 0.5547,0 0.9926,-0.4363 0.998,-0.9887 -0.01,-0.5571 -0.438,-0.9867 -0.998,-0.9867 z m -2.7656,2.149 -3.8946,3.8884 a 1.1251124,1.1233465 0 1 0 1.5918,1.5873 l 3.8848,-3.8786 c -0.7095,-0.3088 -1.2808,-0.8846 -1.582,-1.5971 z m 8.6074,2.0202 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3413 l -1.5293,1.5269 a 1.1251124,1.1233465 0 1 0 1.5899,1.5873 l 1.5293,-1.5269 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z"
+ id="path21492-2"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g76970"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-14">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 258.5,199.99609 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 202.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 c 0.41667,0 1,0.45 1,1.5 0,1.04998 -0.58056,1.4941 -1.00195,1.49609 -0.52634,0.003 -0.86013,-0.33871 -1.05078,-0.72265 a 0.50005,0.50005 0 1 0 -0.89454,0.44531 c 0.30945,0.62316 0.97566,1.28254 1.94922,1.27734 C 261.08054,206.99099 262,205.95002 262,204.5 c 0,-1.45 -0.91667,-2.5 -2,-2.5 h -1 v -1.00391 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14399"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 291.98438,431.0625 c -1.31822,0 -2.69153,0.28723 -3.69727,1.29297 a 1.0001,1.0001 0 1 0 1.41406,1.41406 c 0.49426,-0.49426 1.2483,-0.70703 2.28321,-0.70703 a 1.0001,1.0001 0 1 0 0,-2 z m -7.24024,3.04297 c -0.74589,-0.0115 -1.46694,0.0868 -2.13086,0.30664 -1.32784,0.43972 -2.4721,1.53683 -2.61719,3.06055 -0.19518,2.0499 0.80702,3.49399 1.02735,4.3457 0.14607,0.56468 0.0225,0.72298 -0.18164,0.91797 -0.20413,0.19499 -0.61247,0.33203 -0.84961,0.33203 a 1.0001,1.0001 0 1 0 0,2 c 0.76285,0 1.57391,-0.25956 2.23047,-0.88672 0.65655,-0.62715 1.03297,-1.71849 0.73632,-2.86523 -0.37187,-1.43756 -1.0944,-2.37562 -0.97265,-3.6543 0.0682,-0.71615 0.4403,-1.08149 1.25586,-1.35156 0.81556,-0.27008 2.03005,-0.27431 3.23242,0.0684 1.20237,0.34267 2.38417,1.01511 3.21875,1.95703 0.83458,0.94191 1.35114,2.12713 1.29297,3.68945 -0.0218,0.58526 -0.18864,0.77371 -0.37305,0.89453 -0.18441,0.12083 -0.50228,0.18156 -0.91016,0.0723 -0.65709,-0.17607 -1.01294,-0.58503 -1.30078,-1.30274 -0.28784,-0.7177 -0.4082,-1.70364 -0.4082,-2.62695 a 1.0001,1.0001 0 1 0 -2,0 c 0,1.07669 0.11104,2.27463 0.55078,3.37109 0.43975,1.09647 1.30771,2.13309 2.64063,2.49024 0.84212,0.22565 1.76567,0.1664 2.52343,-0.33008 0.75729,-0.49617 1.23505,-1.42269 1.2754,-2.49219 v -0.002 c 0.0762,-2.06159 -0.66061,-3.80964 -1.79493,-5.08984 -1.1347,-1.28064 -2.63964,-2.11968 -4.16601,-2.55469 -0.76319,-0.21751 -1.53341,-0.33806 -2.2793,-0.34961 z"
+ id="path8292"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
+ transform="matrix(-1,0,0,1,1727,-80)"
+ id="g17779"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14245">
+ inkscape:label="U-13">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 249.5,201 a 0.50005,0.50005 0 0 0 -0.49805,0.45508 c -0.24047,2.64524 -1.32572,5.28945 -3.23633,7.25976 C 243.85502,210.68516 241.12778,212 237.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.87222,0 6.89498,-1.43516 8.98438,-3.58984 1.97612,-2.03788 3.06007,-4.712 3.39843,-7.41016 H 250.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14271"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1455.5,512 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 2 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -2 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m 0.5,4 v 6.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 516 Z m 4,1 h 2 c 1.3523,-0.0191 1.3523,2.01913 0,2 h -2 c -1.3523,0.0191 -1.3523,-2.01913 0,-2 z"
+ id="path17776"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssccsscccsccsccccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 238.4668,199.99414 c -0.21842,0.0156 -0.40126,0.17156 -0.45118,0.38477 l -1,4 c -0.0786,0.31522 0.15949,0.62057 0.48438,0.62109 h 2.5 v 1.5 c -0.01,0.67616 1.00956,0.67616 1,0 v -4 c -0.009,-0.6573 -0.9907,-0.6573 -1,0 v 1.5 h -1.85938 l 0.84376,-3.37891 c 0.0877,-0.33109 -0.17587,-0.65038 -0.51758,-0.62695 z"
- id="path14402"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1468,514 v 0.5 c 0,0.62337 -0.4468,1.06807 -1,1.28906 V 516 v 1 h 1.5 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -2 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m -1,4 v 4.5 c 0,0.8167 -0.6835,1.49991 -1.5,1.5 h -7.5 v 0.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 518 Z"
+ id="path17787"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccc" />
+ sodipodi:nodetypes="csccccsscccsccsccscc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13834"
+ transform="rotate(90,244,438)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="U-12">
+ <g
+ id="g13861"
+ transform="rotate(-90,244.008,459)"
+ style="fill:#ffffff;stroke:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 258.99609,451.98828 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 260.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z m 5,0 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 265.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z m 5,0 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 270.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z"
+ id="path13856"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 375.5,201 a 0.50005,0.50005 0 0 0 -0.47852,0.35547 c -0.97912,3.26329 -1.65795,6.01658 -2.41406,7.89453 -0.37805,0.93897 -0.77714,1.65307 -1.20117,2.10156 C 370.98222,211.80006 370.56872,212 370,212 c -0.81989,0 -1.77194,-0.85368 -2.74219,-1.84961 -0.48512,-0.49796 -0.97309,-1.01146 -1.49609,-1.41992 C 365.23871,208.32201 364.66174,208 364,208 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 0.32338,0 0.70916,0.17799 1.14648,0.51953 0.43732,0.34154 0.9074,0.82804 1.39649,1.33008 C 367.52115,211.85368 368.58382,213 370,213 c 0.83577,0 1.56694,-0.36242 2.13281,-0.96094 0.56587,-0.59851 1.00027,-1.41738 1.40235,-2.41601 0.7683,-1.90825 1.43134,-4.57357 2.33398,-7.62305 H 376.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path16580-7"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 396.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 389.78129,210.37772 387.70216,212 384.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 397.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14011-0"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 418.5,201 c -3.54784,0 -5.96871,1.87772 -7.79883,4.18945 -1.7781,2.24603 -3.06678,4.88493 -4.4707,6.81055 H 405.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.40039,-0.19922 c 1.548,-2.064 2.85356,-4.80197 4.58594,-6.99023 C 413.21871,203.62228 415.29784,202 418.5,202 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path14049"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14253">
+ id="g12310-0"
+ transform="translate(63,210)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="U-11">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 447.5,200 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 201 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.00781,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.01562,9 A 0.50005,0.50005 0 0 0 447,209.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -3.5 A 0.50005,0.50005 0 0 0 447.49219,209 Z M 460.5,209 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 460.5,209 Z"
- id="path13927-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 222,431 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 L 218.79297,434 H 216.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.29297 l 2.85351,2.85352 c 0.0938,0.0938 0.22092,0.14646 0.35352,0.14648 h 0.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 431.78125 431.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.4668,2.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27328,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41099,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10286,2.06013 1.1045,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25221,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
+ transform="translate(-63,-210)"
+ id="path12304-9"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g76967"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 449.5,203 a 0.50005,0.50005 0 1 0 0,1 h 1 c 0.39167,0 0.74862,0.27445 1.13672,0.86719 0.3881,0.59273 0.74407,1.4462 1.08594,2.3164 0.34186,0.8702 0.67067,1.75605 1.06836,2.4668 0.19884,0.35538 0.41332,0.66981 0.68554,0.91797 0.27222,0.24816 0.62761,0.43164 1.02344,0.43164 0.625,0 1.13349,-0.27613 1.44727,-0.64648 0.31377,-0.37036 0.47247,-0.79704 0.61523,-1.17774 0.14276,-0.3807 0.2723,-0.71757 0.41406,-0.91016 C 458.11833,208.07304 458.20536,208 458.5,208 a 0.50005,0.50005 0 1 0 0,-1 c -0.58036,0 -1.05583,0.30196 -1.32812,0.67188 -0.2723,0.36991 -0.40839,0.78304 -0.54688,1.15234 -0.13849,0.3693 -0.27667,0.69262 -0.43945,0.88476 C 456.02276,209.90113 455.875,210 455.5,210 c -0.10417,0 -0.20191,-0.0353 -0.34961,-0.16992 -0.1477,-0.13465 -0.31994,-0.3671 -0.48828,-0.66797 -0.33669,-0.60175 -0.66413,-1.4659 -1.00977,-2.3457 -0.34563,-0.8798 -0.70841,-1.77633 -1.17968,-2.4961 C 452.00138,203.60055 451.35833,203 450.5,203 Z"
- id="path14224"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 199.50586,431 c -0.31034,2.7e-4 -0.5455,0.28021 -0.49219,0.58594 0.36378,2.06995 0.21088,3.24033 -0.13086,3.98828 -0.34174,0.74794 -0.89741,1.14621 -1.5625,1.65234 -0.66509,0.50614 -1.42742,1.12518 -1.87304,2.24414 -0.44562,1.11896 -0.57595,2.68203 -0.19141,5.10742 0.0385,0.24306 0.24806,0.422 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.27449 0.49414,-0.57812 -0.36857,-2.32471 -0.21903,-3.70089 0.13086,-4.58204 0.34989,-0.88114 0.89751,-1.32255 1.54492,-1.8164 0.64741,-0.49385 1.4068,-1.03318 1.86328,-2.03516 0.45648,-1.00198 0.58623,-2.39428 0.20313,-4.57422 C 208.70043,431.17484 208.49284,431.0002 208.25,431 Z"
+ id="path8644-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccscccccssccc" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g13322"
- transform="translate(-1.8536743e-6,21.000005)">
- <g
- id="g14281"
- transform="translate(84,200)"
- style="opacity:0.6;fill:#ffffff">
- <g
- transform="matrix(1,0,0,-1,-294,368)"
- id="g14276"
- style="opacity:1;fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 9 v 2 h -9 z"
- id="path14272"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 304.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 2 h -8 z"
- id="path14274"
- inkscape:connector-curvature="0" />
- </g>
- </g>
+ id="g76976"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 93.5,179 c -0.412872,-7.2e-4 -0.648693,0.47092 -0.400391,0.80078 l 3,4 c 0.2,0.26732 0.600782,0.26732 0.800782,0 l 3,-4 C 100.14869,179.47092 99.912872,178.99928 99.5,179 Z"
- id="path14203-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 180.25977,430.99023 c -1.56005,0 -2.83737,0.68503 -4,1.32227 -0.15986,0.0876 -0.25939,0.25522 -0.25977,0.4375 v 1.75 c -0.002,0.58015 0.81953,0.69801 0.98047,0.14062 0.5477,-1.86218 2.26129,-2.69946 3.87109,-2.56445 0.056,0.003 0.0879,0.0161 0.14258,0.0195 C 182.58833,432.2915 184,433.38188 184,435.75 V 437 h -4.17383 c -1.71873,0 -2.95078,0.48602 -3.73828,1.26172 -0.7875,0.77569 -1.09766,1.80326 -1.09766,2.77539 0,1.37482 0.63393,2.43409 1.58008,3.07031 C 177.51646,444.74365 178.73744,445 180,445 c 1.61266,0 3.42658,-0.64151 4.45508,-1.56836 0.43191,0.42904 0.80166,0.78819 1.11328,1.03906 0.38759,0.31203 0.75096,0.5293 1.18164,0.5293 h 0.75 c 0.31531,0 0.5,-0.25 0.5,-0.5 0,-0.25 -0.16406,-0.5 -0.5,-0.5 -0.0833,0 -0.22505,-0.0571 -0.33398,-0.16602 C 187.05708,443.72508 187,443.58333 187,443.5 v -7 c 0,-1.04167 -0.0843,-2.5 -1.08398,-3.57617 -1.37045,-1.47528 -2.91602,-1.9336 -5.65625,-1.9336 z M 181.5,438 h 2.5 v 4.49023 c -0.8549,0.62028 -1.60427,0.95721 -2.2793,1.14844 -0.1561,0.0477 -0.30873,0.061 -0.46679,0.0977 -0.63626,0.10402 -1.2211,0.10508 -1.65821,-0.0742 C 178.58677,443.24823 178,442.20833 178,441 c 0,-0.63889 0.21654,-1.3962 0.74414,-1.97656 C 179.27174,438.44308 180.11111,438 181.5,438 Z"
+ id="path7432"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
+ sodipodi:nodetypes="sccccccscccscscssssscsscsscccccsss" />
+ </g>
+ <g
+ id="g76973"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-8">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 160.5,431 a 1.5,1.5 0 0 0 -1.5,1.5 1.5,1.5 0 0 0 0.0879,0.5 h -4.56836 a 1.50015,1.50015 0 1 0 0,3 H 158 v 1.94922 c -1.31983,1.3363 -2.47353,2.76999 -2.9707,5.25586 a 1.50015,1.50015 0 1 0 2.9414,0.58984 c 0.37009,-1.85045 0.99513,-2.60285 2.0293,-3.6289 1.03417,1.02605 1.65921,1.77845 2.0293,3.6289 a 1.50015,1.50015 0 1 0 2.9414,-0.58984 c -0.49717,-2.48587 -1.65087,-3.91956 -2.9707,-5.25586 V 436 h 3.48047 a 1.50015,1.50015 0 1 0 0,-3 h -2.53711 c -0.0387,0.18925 -0.094,0.37697 -0.17774,0.55664 C 162.35553,434.4361 161.47038,435 160.5,435 a 0.50005,0.50005 0 1 1 0,-1 1.5,1.5 0 0 0 0.41406,-0.0586 c 0.009,-0.002 0.0169,-0.005 0.0254,-0.008 a 1.5,1.5 0 0 0 0.35157,-0.16211 c 0.006,-0.004 0.0133,-0.006 0.0195,-0.01 a 1.5,1.5 0 0 0 0.004,-0.002 1.5,1.5 0 0 0 0.29102,-0.25 c 0.009,-0.0103 0.0202,-0.0187 0.0293,-0.0293 a 1.5,1.5 0 0 0 0.21484,-0.33008 c 0.003,-0.006 0.007,-0.01 0.01,-0.0156 0.002,-0.005 0.004,-0.0104 0.006,-0.0156 A 1.5,1.5 0 0 0 162,432.5 1.5,1.5 0 0 0 160.5,431 Z"
+ id="path13634"
+ inkscape:connector-curvature="0"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
+ transform="translate(477,-1375)"
+ id="g20978-8"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13175">
+ inkscape:label="U-7">
<path
- id="path34600-2"
- d="m 162.47852,32 c -0.75576,10e-7 -1.40256,0.282822 -1.83399,0.75 -0.30821,0.333747 -0.37373,0.80118 -0.46094,1.25 H 159.25 c -1.74879,0 -3.25,1.267585 -3.25,3 0,0.03444 0.0105,0.06555 0.0117,0.09961 C 156.33181,37.034347 156.66178,37 157,37 c 2.03325,0 3.79424,1.241664 4.57227,3 H 164.25 c 0.73055,0 1.4115,-0.231259 1.91992,-0.667969 C 166.67834,38.895322 167,38.242126 167,37.5 c 0,-1.192468 -0.94634,-2.062761 -2.04297,-2.306641 -0.002,-0.488483 0.0124,-1.101037 -0.24609,-1.74414 C 164.40699,32.693065 163.65613,32.000002 162.47852,32 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path20982-6"
+ transform="translate(42,-42)"
+ d="m -377.5,1847 c -2.13972,0 -3.85417,1.5351 -4.30664,3.541 -0.63415,-0.8727 -1.53397,-1.541 -2.69336,-1.541 -1.92708,0 -3.5,1.573 -3.5,3.5 0,1.9271 1.57294,3.5 3.5,3.5 h 7 c 2.47937,0 4.5,-2.0207 4.5,-4.5 0,-2.4793 -2.02063,-4.5 -4.5,-4.5 z m 0,3 c 0.82251,0 1.5,0.6775 1.5,1.5 0,0.8225 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8225 0.67749,-1.5 1.5,-1.5 z m -7,1 c 0.82251,0 1.5,0.6775 1.5,1.5 0,0.8225 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8225 0.67749,-1.5 1.5,-1.5 z m 7,0 c -0.28208,0 -0.5,0.2179 -0.5,0.5 0,0.2821 0.21792,0.5 0.5,0.5 0.28208,0 0.5,-0.2179 0.5,-0.5 0,-0.2821 -0.21792,-0.5 -0.5,-0.5 z m -3.94922,0.998 c 8e-5,7e-4 -8e-5,0 0,0 H -381.5 a 0.50005006,0.50005006 0 0 0 0.0508,0 z m -3.05078,0 c -0.28208,0 -0.5,0.2179 -0.5,0.5 0,0.2821 0.21792,0.5 0.5,0.5 0.28208,0 0.5,-0.2179 0.5,-0.5 0,-0.2821 -0.21792,-0.5 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.0000006;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 157,38 c -2.20322,0 -4,1.796783 -4,4 0,2.203217 1.79678,4 4,4 2.20322,0 4,-1.796783 4,-4 0,-2.203217 -1.79678,-4 -4,-4 z m 0,1 c 1.66278,0 3,1.337223 3,3 0,1.662777 -1.33722,3 -3,3 -1.66278,0 -3,-1.337223 -3,-3 0,-1.662777 1.33722,-3 3,-3 z"
- id="ellipse13733"
+ id="path20992-7"
+ transform="translate(42,-42)"
+ d="M -385.50781,1856.9922 A 0.50005,0.50005 0 0 0 -386,1857.5 v 1 1 a 0.50005,0.50005 0 0 0 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -6 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 0.5 h -1 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.5078 z m 11.99219,0.01 c -0.10819,0 -0.21237,0.042 -0.29688,0.1094 l -2.5,2 c -0.25044,0.2002 -0.25044,0.581 0,0.7812 l 2.5,2 c 0.32747,0.2621 0.81265,0.029 0.8125,-0.3906 v -4 c 1.1e-4,-0.2823 -0.23341,-0.5088 -0.51562,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g76949"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-6">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 154.5,32 c 0.8225,0 1.5,0.677496 1.5,1.5 0,0.822504 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.677496 -1.5,-1.5 0,-0.822504 0.6775,-1.5 1.5,-1.5 z"
- id="ellipse12632-2"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="path21010-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 115.5,442 a 0.50004997,0.50004997 0 1 0 0,1 h 5 a 0.50004997,0.50004997 0 1 0 0,-1 z m 0,2 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 V 445 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z m 2.5,-13 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7222 1.0876,3.2946 2.1465,4.3535 0.094,0.094 0.2209,0.1465 0.3535,0.1465 h 7 c 0.1326,0 0.2598,-0.053 0.3535,-0.1465 0.7109,-0.7108 1.4222,-1.6513 1.8262,-2.7148 C 123.8776,437.6179 124,437.066 124,436.5 c 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m -2.5098,5.0059 c 0.1351,0 0.2662,0.047 0.3633,0.1406 L 116.707,437 h 2.586 l 0.8535,-0.8535 c 0.4712,-0.4506 1.1576,0.2358 0.707,0.707 L 120,437.707 v 1.793 0.5 h -1 v -0.5 -1.5 h -2 v 1.5 0.5 h -1 v -0.5 -1.793 l -0.8535,-0.8535 c -0.302,-0.3119 -0.09,-0.8341 0.3437,-0.8476 z" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 292.49023,367.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -10,10 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 10,-10 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
- id="path14294"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14429"
- transform="translate(-1.8536743e-6,42.000005)">
+ id="g76961"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 201.49805,368.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.7207 C 203.68137,373.39211 205,375.04034 205,377 c 0,1.45833 -0.66274,2.34651 -1.76562,2.75 -1.1029,0.40349 -2.7161,0.26002 -4.5,-0.69141 a 0.50005,0.50005 0 1 0 -0.46876,0.88282 c 1.9661,1.04857 3.8529,1.2801 5.3125,0.74609 C 205.03775,380.15349 206,378.79167 206,377 c 0,-2.43412 -1.54431,-4.24525 -3.00195,-6.65039 v -0.85547 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- transform="translate(1.8536743e-6,-42.000005)"
- id="path14357"
- inkscape:connector-curvature="0" />
- <g
- style="opacity:0.6;fill:#ffffff"
- id="g13445">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 195.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 199.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.50195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 369 H 204.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.49805 v 0.49414 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.5,1 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z"
- transform="translate(1.8536743e-6,-42.000005)"
- id="path14367"
- inkscape:connector-curvature="0" />
- </g>
+ inkscape:connector-curvature="0"
+ id="path13682"
+ d="m 100.45117,431 c -0.36065,0.005 -0.725199,0.0666 -1.080078,0.1875 -1.419514,0.48381 -2.371094,1.8128 -2.371094,3.3125 a 0.50005006,0.50005006 0 1 1 -1,0 c 0,-0.53249 0.102694,-1.04562 0.277344,-1.52734 -0.0921,0.0103 -0.173784,0.0274 -0.277344,0.0273 -3.307786,0 -6,2.69221 -6,6 0,3.30779 2.692214,6 6,6 3.307786,0 6.000002,-2.69221 6.000002,-6 v -0.002 c -4.7e-4,-0.11093 0.014,-0.19694 0.0332,-0.27344 -0.83987,0.3046 -1.77022,0.36483 -2.67578,0.12695 a 0.50005006,0.50005006 0 1 1 0.253906,-0.96679 c 1.450494,0.38101 2.978064,-0.20116 3.806644,-1.45118 0.82858,-1.25001 0.7694,-2.88277 -0.14649,-4.07031 -0.68691,-0.89068 -1.73836,-1.37897 -2.82031,-1.36328 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14422"
- transform="translate(-1.8536743e-6,42.000005)">
+ id="g14020"
+ transform="translate(153,38)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="U-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 222.49805,369.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 l 0.002,0.60742 c -2.27831,0.46511 -4,2.48538 -4,4.89844 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.41306 -1.72169,-4.43333 -4,-4.89844 l -0.002,-0.60742 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z M 223,372 c 2.21488,0 4,1.78488 4,4 0,2.21512 -1.78512,4 -4,4 -2.21488,0 -4,-1.78488 -4,-4 0,-2.21512 1.78512,-4 4,-4 z"
- transform="translate(1.8536743e-6,-42.000005)"
- id="ellipse14399"
- inkscape:connector-curvature="0" />
- <g
- style="opacity:0.6;fill:#ffffff"
- id="g13453">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 216.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 220.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.50195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 369 h -1.5039 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.5039 v 0.49414 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
- transform="translate(1.8536743e-6,-42.000005)"
- id="path14421"
- inkscape:connector-curvature="0" />
- </g>
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -76.5,394 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -75.936984,394.30587 -76.175116,394.00052 -76.5,394 Z m 6,0 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -69.936984,394.30587 -70.175116,394.00052 -70.5,394 Z m -8,7 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -77.936984,401.30587 -78.175116,401.00052 -78.5,401 Z m 6,0 -3.751953,0.006 c -0.228491,0.001 -0.427071,0.15722 -0.482422,0.37891 l -1.25,4.99414 c -0.07853,0.31517 0.159565,0.6204 0.484375,0.62095 h 3.75 c 0.22922,-3.6e-4 0.428845,-0.15652 0.484375,-0.37891 l 1.25,-5 C -71.936984,401.30587 -72.175116,401.00052 -72.5,401 Z"
+ id="path13999"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14414"
- transform="translate(-1.8536743e-6,42.000005)">
+ id="g76958"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-3">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 250.05859,327.01172 c -2.15963,0 -4.15811,1.13935 -5.24023,2.99219 -1.08212,1.85283 -1.08212,4.1413 0,5.99414 1.08212,1.85284 3.0806,2.99218 5.24023,2.99218 l 0.43164,0.01 a 0.50009544,0.50009544 0 1 0 0.0195,-1 l -0.44141,-0.01 a 0.50004985,0.50004985 0 0 0 -0.01,0 c -1.80804,0 -3.47523,-0.95213 -4.37695,-2.49609 -0.90172,-1.54396 -0.90172,-3.44041 0,-4.98437 0.90107,-1.54285 2.56651,-2.49668 4.37305,-2.49805 l 0.4375,0.004 a 0.50004985,0.50004985 0 1 0 0.008,-1 l -0.4375,-0.004 a 0.50004985,0.50004985 0 0 0 -0.004,0 z"
- id="ellipse14411"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 53.5,431 a 1.50015,1.50015 0 1 0 0,3 H 55 c 1.249468,0.006 2.332699,0.37671 3.013672,0.94141 0.682107,0.56564 1.059323,1.26298 0.988281,2.4707 -0.09036,1.53611 -0.972327,2.5432 -2.498047,3.35351 -1.525719,0.81032 -3.632465,1.22991 -5.447265,1.23438 H 49.5 a 1.50015,1.50015 0 1 0 0,3 h 1.5625 0.002 c 2.24072,-0.006 4.728077,-0.46126 6.845703,-1.58594 2.117627,-1.12468 3.928252,-3.11228 4.087891,-5.82617 0.120132,-2.04228 -0.719411,-3.83841 -2.068359,-4.95703 -1.348949,-1.11862 -3.108979,-1.6232 -4.923829,-1.63086 h -0.002 z"
+ id="path8588-0"
inkscape:connector-curvature="0" />
- <g
- style="opacity:0.6;fill:#ffffff"
- id="g13459">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 237.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 H 238 v 8 h -0.50195 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 381 H 245 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -5.00195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 H 239 v -8 h 0.49805 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 245 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -5.00195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,11 h 1 v 1 h -1 z"
- transform="translate(1.8536743e-6,-42.000005)"
- id="path14415"
- inkscape:connector-curvature="0" />
- </g>
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14406"
- transform="translate(-1.8536743e-6,42.000005)">
+ id="g76994"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 258.49805,325.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z m -11.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
- id="path14443"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 28.5,431 a 1.50015,1.50015 0 0 0 -1.341797,2.16992 l 5.5,11 a 1.50015,1.50015 0 0 0 2.683594,0 l 5.5,-11 A 1.50015,1.50015 0 0 0 39.5,431 Z m 2.425781,3 h 6.148438 L 34,440.14648 Z"
+ id="path14201"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g76964"
+ style="display:inline;enable-background:new"
+ inkscape:label="U-1">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 265,328 c -2.75536,0 -5,2.24449 -5,5 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.75551 -2.24464,-5 -5,-5 z m 0,1 c 2.21488,0 4,1.78488 4,4 0,2.21512 -1.78512,4 -4,4 -2.21488,0 -4,-1.78488 -4,-4 0,-2.21512 1.78512,-4 4,-4 z"
- id="ellipse14445"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 11.455078,430.98242 a 1.50015,1.50015 0 0 0 -1.4765624,1.52149 v 6.3789 l -3.5605468,3.56055 a 1.50015,1.50015 0 1 0 2.1210937,2.12109 l 3.5605465,-3.56054 h 6.378907 a 1.50015,1.50015 0 1 0 0,-3 h -5.5 v -5.5 a 1.50015,1.50015 0 0 0 -1.523438,-1.52149 z"
+ id="path12350-2"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14334"
- transform="translate(-231,63.000005)">
+ id="g84220"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-26">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 250.05859,306.01172 c -2.15963,0 -4.15811,1.13935 -5.24023,2.99219 -1.08212,1.85283 -1.08212,4.1413 0,5.99414 1.08212,1.85284 3.0806,2.99218 5.24023,2.99218 l 0.43164,0.01 c 0.28003,0.005 0.50992,-0.22015 0.50977,-0.50023 l -0.004,-10.98438 c -2e-5,-0.27461 -0.22149,-0.49783 -0.49609,-0.5 l -0.4375,-0.004 c -0.001,-10e-6 -0.003,-10e-6 -0.004,0 z"
- id="path13470"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccscccccccc" />
- <g
- transform="translate(0,-21)"
- id="g13541"
- style="opacity:0.6;fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 6.4980469,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 H 7 v 8 H 6.4980469 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 381 H 14 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 8.9980469 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 H 8 v -8 h 0.4980469 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 14 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 8.9980469 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,11 h 1 v 1 h -1 z"
- transform="translate(231,-42.000005)"
- id="path13523"
- inkscape:connector-curvature="0" />
- </g>
+ id="path19316"
+ d="m 541.57031,410.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.26368,1.26367 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.26367,-1.26368 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.26368,1.26367 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.25195,-1.25196 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -8.08008,6.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.25,1.25 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.23829,-1.23828 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -1.25,1.25 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.25,-1.25 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14339"
- transform="translate(-231,63.000005)">
+ id="g84229"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-25">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 258.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z m -11.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
- id="path13555"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ d="m 512,414.00018 h 9 v 5 h -9 z m -1.5,-2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 1 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.6573,-0.009 0.6573,-0.9907 0,-1 H 517 v -1 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 11 v 7 h -11 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect22324-2" />
+ </g>
+ <g
+ id="g84232"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 265,307 c -2.75536,0 -5,2.24449 -5,5 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.75551 -2.24464,-5 -5,-5 z"
- id="ellipse13557"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 489.5,412 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 1 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.6573,-0.009 0.6573,-0.9907 0,-1 H 496 v -1 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 11 v 7 h -11 z"
+ id="path22338-8"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ sodipodi:nodetypes="cccccccccccccccccccccc" />
</g>
<g
+ transform="translate(42)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14394"
- transform="translate(-252,63.000005)">
+ id="g6098"
+ inkscape:label="T-23">
<path
- id="path17351-9"
- d="m 328,307 c -1.30038,0 -2.48006,0.21939 -3.37891,0.60352 -0.44942,0.19206 -0.83127,0.42394 -1.12304,0.71875 -0.29178,0.2948 -0.49805,0.67796 -0.49805,1.10156 v 2.30664 2.8457 c 0,0.4236 0.20627,0.80676 0.49805,1.10156 0.29177,0.29481 0.67362,0.52669 1.12304,0.71875 C 325.51994,316.78061 326.69962,317 328,317 c 1.30038,0 2.48006,-0.21939 3.37891,-0.60352 0.44942,-0.19206 0.83127,-0.42394 1.12304,-0.71875 0.29178,-0.2948 0.49805,-0.67796 0.49805,-1.10156 v -2.8457 -2.30664 c 0,-0.4236 -0.20627,-0.80676 -0.49805,-1.10156 -0.29177,-0.29481 -0.67362,-0.52669 -1.12304,-0.71875 C 330.48006,307.21939 329.30038,307 328,307 Z m 0,1 c 1.01151,0 1.92459,0.13316 2.61914,0.3418 0.34727,0.10431 0.63991,0.22479 0.88086,0.38281 0.24095,0.15802 0.5,0.38269 0.5,0.77539 0,0.3927 -0.25905,0.61737 -0.5,0.77539 -0.24095,0.15802 -0.53359,0.2785 -0.88086,0.38281 C 329.92459,310.86684 329.01151,311 328,311 c -1.0115,0 -1.92459,-0.13316 -2.61914,-0.3418 -0.34727,-0.10431 -0.63991,-0.22479 -0.88086,-0.38281 -0.24095,-0.15802 -0.5,-0.38268 -0.5,-0.77539 0,-0.3927 0.25905,-0.61737 0.5,-0.77539 0.24095,-0.15802 0.53359,-0.2785 0.88086,-0.38281 C 326.07541,308.13316 326.9885,308 328,308 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="circle20459-6"
+ transform="translate(-42)"
+ d="m 469.08398,415.58594 c -0.81593,0.95753 -1.21878,2.22985 -1.04296,3.52148 0.24625,1.80912 1.56436,3.29294 3.33203,3.75 1.43669,0.37149 2.93514,-0.006 4.03515,-0.9414 -0.29636,0.0501 -0.5984,0.084 -0.9082,0.084 -0.38579,0 -0.76279,-0.0423 -1.12695,-0.11914 -0.56283,0.14546 -1.16207,0.15983 -1.75,0.008 -1.37737,-0.35614 -2.39992,-1.50634 -2.5918,-2.91601 -0.0626,-0.45958 -0.0236,-0.91417 0.0879,-1.34571 C 469.04268,417.26409 469,416.88831 469,416.50391 c 0,-0.31305 0.0328,-0.61873 0.084,-0.91797 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 321.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path14314"
+ sodipodi:nodetypes="cssccscc"
+ id="circle20463-7"
+ transform="translate(-42)"
+ d="M 473.08594,412.25 C 471.30049,412.84735 470,414.51742 470,416.5 c 0,2.47936 2.02064,4.5 4.5,4.5 0.48878,0 0.95142,-0.0971 1.39258,-0.24219 -0.56289,-0.17378 -1.08535,-0.43906 -1.55664,-0.77343 C 472.47547,419.89744 471,418.3827 471,416.5 c 0,-1.08365 0.4989,-2.0367 1.26758,-2.67773 0.18577,-0.57127 0.46679,-1.09859 0.81836,-1.57227 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="circle19345"
+ d="m 435.5,411 c -2.47344,0 -4.5,2.02656 -4.5,4.5 0,2.47344 2.02656,4.5 4.5,4.5 2.47344,0 4.5,-2.02656 4.5,-4.5 0,-2.47344 -2.02656,-4.5 -4.5,-4.5 z m 0,2 c 1.39256,0 2.5,1.10744 2.5,2.5 0,1.39256 -1.10744,2.5 -2.5,2.5 -1.39256,0 -2.5,-1.10744 -2.5,-2.5 0,-1.39256 1.10744,-2.5 2.5,-2.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g14390"
- transform="translate(-294,63.000005)">
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g22801-1"
+ transform="translate(696,857.997)"
+ inkscape:label="T-22">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 347.50586,306 c -0.31034,2.7e-4 -0.5455,0.28021 -0.49219,0.58594 0.36436,2.07324 0.1958,3.10943 -0.10742,3.63086 -0.30322,0.52143 -0.79091,0.68645 -1.46094,0.9414 -0.67003,0.25495 -1.50865,0.62325 -1.98242,1.58985 -0.47377,0.96659 -0.59114,2.40736 -0.20703,4.83007 0.0385,0.24306 0.24806,0.422 0.49414,0.42188 h 6.75586 c 0.30739,1.4e-4 0.54213,-0.27449 0.49414,-0.57812 -0.369,-2.32739 -0.20658,-3.57589 0.11523,-4.23438 0.32182,-0.65849 0.7931,-0.85067 1.43555,-1.0957 0.64245,-0.24504 1.46993,-0.51949 1.96484,-1.37305 0.49492,-0.85356 0.6091,-2.12804 0.22657,-4.30469 C 354.70043,306.17484 354.49284,306.0002 354.25,306 Z"
- id="path14318"
+ id="path22797-9"
+ d="m -239.5,-446.99219 c -2.47912,0 -4.5,2.01847 -4.5,4.4961 0,2.47763 2.02088,4.49609 4.5,4.49609 2.47912,0 4.5,-2.01846 4.5,-4.49609 0,-2.47763 -2.02088,-4.4961 -4.5,-4.4961 z m 0,1.1875 c 1.83471,0 3.31055,1.47622 3.31055,3.3086 0,1.83238 -1.47584,3.30859 -3.31055,3.30859 -1.8347,0 -3.31055,-1.47621 -3.31055,-3.30859 0,-1.83238 1.47585,-3.3086 3.31055,-3.3086 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g84214"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-21">
+ <path
+ sodipodi:nodetypes="cccccscccccccccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccssccccccccccc" />
+ id="path17971-6"
+ d="m 433.60156,411.10938 c -0.0348,2.9e-4 -0.0695,0.004 -0.10351,0.0117 -2.03912,0.46668 -3.49042,2.28707 -3.49219,4.37891 9e-4,0.50625 0.15089,0.99318 0.31836,1.46875 l -2.42774,2.42773 c -1.00968,1.00969 -1.01874,2.3133 -0.3125,3.01954 0.70624,0.70624 2.00985,0.69718 3.01954,-0.3125 l 2.42968,-2.42969 c 0.47476,0.16775 0.9595,0.31841 1.46485,0.32031 6.7e-4,0 0.001,0 0.002,0 2.10425,-9.3e-4 3.93168,-1.46897 4.38672,-3.52344 0.0316,-0.14237 -4.7e-4,-0.29146 -0.0879,-0.4082 l -0.64844,-0.86328 c -0.17598,-0.23372 -0.51414,-0.2671 -0.73242,-0.0723 L 435.31055,417 h -1.08008 L 433,415.56445 v -0.85742 l 1.85352,-1.85351 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -0.89063,-0.89062 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g84217"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-20">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 342.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 10.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z"
- id="path14320"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path18042-5"
+ d="m 413.49609,411 c -1.31297,0 -2.2906,0.33758 -3.34961,1.39648 -1.07833,1.0783 -1.34444,2.83666 -0.73437,4.48438 l -2.51563,2.51562 c -1.00968,1.00969 -1.01874,2.3133 -0.3125,3.01954 0.70624,0.70624 2.00985,0.69718 3.01954,-0.3125 l 2.51757,-2.51758 c 1.64574,0.60684 3.4036,0.3464 4.48243,-0.73242 1.05892,-1.05893 1.39668,-2.03818 1.39257,-3.35547 a 0.50005,0.50005 0 0 0 -0.14648,-0.35157 l -1,-1 a 0.50005,0.50005 0 0 0 -0.70703,0 L 414.28906,416 h -0.58594 l -0.70703,-0.70703 v -0.58594 l 1.85352,-1.85351 a 0.50005,0.50005 0 0 0 0,-0.70704 l -1,-1 A 0.50005,0.50005 0 0 0 413.49609,411 Z m -0.18164,1.02539 0.47461,0.47461 -1.64648,1.64648 A 0.50005,0.50005 0 0 0 411.99609,414.5 v 1 a 0.50005,0.50005 0 0 0 0.14649,0.35352 l 1,1 A 0.50005,0.50005 0 0 0 413.49609,417 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1.64648,-1.64649 0.47461,0.47461 c -0.0187,1.03267 -0.19304,1.58367 -1.07422,2.46484 -0.83209,0.8321 -2.35353,1.13617 -3.75195,0.47266 a 0.50005,0.50005 0 0 0 -0.56836,0.0977 l -2.67969,2.67968 c -0.74031,0.74032 -1.3117,0.60626 -1.60546,0.3125 -0.29376,-0.29376 -0.42782,-0.86515 0.3125,-1.60546 l 2.67773,-2.67774 a 0.50005,0.50005 0 0 0 0.0977,-0.56836 c -0.66677,-1.39852 -0.3581,-2.92122 0.47461,-3.7539 0.88058,-0.8805 1.43264,-1.05616 2.46093,-1.07813 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
+ id="g19394"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14350"
- transform="translate(-210,63.000005)">
+ inkscape:label="T-19">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 307,306 c -3.30761,0 -6,2.6922 -6,6 0,3.3078 2.69239,6 6,6 3.30761,0 6,-2.6922 6,-6 0,-3.3078 -2.69239,-6 -6,-6 z m 4.75781,6.73438 a 0.50005,0.50005 0 0 1 0.28516,0.91992 c -1.16187,0.83991 -2.99782,1.34961 -5.04297,1.34961 -2.04361,0 -3.88093,-0.50932 -5.04297,-1.34766 a 0.50005,0.50005 0 0 1 0.25586,-0.91016 0.50005,0.50005 0 0 1 0.33008,0.0977 c 0.89908,0.64864 2.58702,1.16016 4.45703,1.16016 1.87213,0 3.55862,-0.50874 4.45703,-1.15821 a 0.50005,0.50005 0 0 1 0.30078,-0.11132 z"
- id="ellipse14291"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ d="m 390.5,416 c -0.98118,0 -1.79306,0.19786 -2.45312,0.51562 -0.008,0.17574 -0.0332,0.34151 -0.0332,0.52149 0,4.06772 2.58548,6.61176 5.30078,6.95117 2.02213,0.29647 2.40413,-2.76745 0.3711,-2.97656 -1.2847,-0.16059 -2.67188,-1.04233 -2.67188,-3.97461 0,-0.37546 0.0235,-0.72058 0.0664,-1.03711 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path19340"
+ sodipodi:nodetypes="scsccscs" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 300.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path14322"
+ id="path5291"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 395,410 c -1.86938,0 -3.40407,0.68718 -4.4375,1.85938 -0.30774,0.34905 -0.56557,0.74269 -0.7832,1.16601 C 390.01692,413.00864 390.25738,413 390.5,413 h 0.44922 c 0.11262,-0.16825 0.23234,-0.32999 0.36328,-0.47852 C 392.15407,411.56692 393.36938,411 395,411 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m -4.5,4 c -1.84524,0 -3.47115,0.52889 -4.64258,1.5625 C 384.686,416.59611 384,418.13095 384,420 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 420 c 0,-1.63095 0.564,-2.84611 1.51758,-3.6875 C 387.47115,415.47111 388.84524,415 390.5,415 h 1.00781 c 3.27827,0 5.29896,2.17669 5.49805,3.57031 a 0.50005,0.50005 0 1 0 0.98828,-0.14062 C 397.69323,416.32331 395.21551,414 391.50781,414 Z"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14344"
- transform="translate(-168,63.000005)">
+ transform="rotate(180,349.0055,417)"
+ id="g22180"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="T-18">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 286,307 c -1.846,0 -3.56208,0.52582 -4.8457,1.40625 C 279.87068,309.28668 279,310.55671 279,312 c 0,1.44329 0.87068,2.71332 2.1543,3.59375 C 282.43792,316.47418 284.154,317 286,317 c 1.846,0 3.56208,-0.52582 4.8457,-1.40625 C 292.12932,314.71332 293,313.44329 293,312 c 0,-1.44329 -0.87068,-2.71332 -2.1543,-3.59375 C 289.56208,307.52582 287.846,307 286,307 Z m 2.49219,3.61719 A 0.50005,0.50005 0 0 1 289,311.125 c 0,0.62131 -0.43923,1.10886 -0.98438,1.41016 C 287.47049,312.83646 286.77233,313 286,313 c -0.77233,0 -1.47049,-0.16354 -2.01562,-0.46484 C 283.43923,312.23386 283,311.74631 283,311.125 a 0.50005,0.50005 0 0 1 0.49414,-0.50586 A 0.50005,0.50005 0 0 1 284,311.125 c 0,0.13737 0.11369,0.33891 0.46875,0.53516 C 284.82381,311.85641 285.37451,312 286,312 c 0.62549,0 1.17619,-0.14359 1.53125,-0.33984 C 287.88631,311.46391 288,311.26237 288,311.125 a 0.50005,0.50005 0 0 1 0.49219,-0.50781 z"
- id="path13633"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 324.95117,410.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 2.83908,0.33401 5.63985,-1.05664 6.5332,-3.3125 a 0.50005,0.50005 0 1 0 -0.92969,-0.36718 c -0.67177,1.69632 -3.05327,2.97373 -5.48633,2.6875 -1.98998,-0.23411 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 c -0.31249,0.377 -0.92604,0.69672 -1.66015,0.78906 a 0.50005,0.50005 0 1 0 0.125,0.99219 c 0.94034,-0.11828 1.77818,-0.50935 2.30469,-1.14453 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z"
+ id="path22178"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 279.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path14324"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 331.50586,410 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -10,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path22182"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 429.50781,389 C 427.57283,389 426,390.57283 426,392.50781 v 6.98438 c 0,1.93498 1.57283,3.50781 3.50781,3.50781 h 6.98438 C 438.42717,403 440,401.42717 440,399.49219 v -6.98438 C 440,390.57283 438.42717,389 436.49219,389 Z m 0,1 h 6.98438 c 1.39828,0 2.50781,1.10953 2.50781,2.50781 v 6.98438 C 439,400.89047 437.89047,402 436.49219,402 h -6.98438 C 428.10953,402 427,400.89047 427,399.49219 v -6.98438 C 427,391.10953 428.10953,390 429.50781,390 Z"
- id="rect14490"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 243.49219,220.9707 c -0.18907,0.009 -0.3569,0.12383 -0.4336,0.29688 l -4,9 c -0.084,0.18909 -0.0428,0.41038 0.10352,0.55664 l 4,4 c 0.19526,0.19518 0.51177,0.19518 0.70703,0 l 4,-4 c 0.14634,-0.14626 0.1875,-0.36755 0.10352,-0.55664 l -4,-9 c -0.0836,-0.18859 -0.27441,-0.3065 -0.48047,-0.29688 z"
- id="path13222-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 264.49219,220.9707 a 0.50005,0.50005 0 0 0 -0.4336,0.29688 l -4,9 a 0.50005,0.50005 0 0 0 0.10352,0.55664 l 4,4 a 0.50005,0.50005 0 0 0 0.70703,0 l 4,-4 a 0.50005,0.50005 0 0 0 0.10352,-0.55664 l -4,-9 a 0.50005,0.50005 0 0 0 -0.48047,-0.29688 z m 0.0234,1.73047 3.4043,7.65821 -3.4043,3.40429 -3.40429,-3.40429 z"
- id="path14674"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 289.5,368 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -5,5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -5,5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path13250"
- inkscape:connector-curvature="0" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13344"
- transform="translate(-42.000002,21.000005)">
+ id="g20665"
+ inkscape:label="T-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 449.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 0,-0.0417 0.006,-0.0117 -0.0469,0.0547 -0.0531,0.0664 -0.15023,0.15467 -0.2539,0.23242 -0.16609,0.12457 -0.2761,0.17993 -0.33789,0.21289 H 447.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.77539 c 0.40889,-0.49501 0.89786,-0.93068 1.47461,-1.26367 l 0.42578,-0.26758 L 451,496.29297 V 494.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8.28125,0.002 c -0.50453,0.0148 -1.01019,0.15125 -1.46875,0.41602 a 0.50005,0.50005 0 0 0 -0.0156,0.01 l -5.04688,3.17579 -0.0156,0.01 a 0.50005,0.50005 0 0 0 -0.19532,0.2207 c -1.45784,0.9884 -2.27996,2.6934 -1.9707,4.44727 0.32821,1.86134 1.78904,3.32218 3.65039,3.65039 0.641,0.11303 1.28349,0.0836 1.88867,-0.0703 a 0.50005,0.50005 0 1 0 -0.24609,-0.96875 c -0.47064,0.11969 -0.96915,0.14277 -1.46875,0.0547 -1.45073,-0.25581 -2.58404,-1.38913 -2.83985,-2.83985 -0.2558,-1.45072 0.42152,-2.90212 1.69727,-3.63867 a 0.50005,0.50005 0 0 0 0.0156,-0.01 l 0.0274,-0.0156 a 0.50005,0.50005 0 0 0 0.01,-0.008 l 5.00977,-3.15039 c 0.83503,-0.4821 1.88265,-0.34391 2.56445,0.33789 0.6818,0.68178 0.81999,1.72943 0.33789,2.56445 a 0.50005,0.50005 0 0 0 -0.006,0.0137 0.50005,0.50005 0 0 0 -0.0195,0.0371 l -1.6289,3.02539 a 0.50005,0.50005 0 1 0 0.8789,0.47266 l 1.63477,-3.03711 0.008,-0.0117 c 6.7e-4,-10e-4 -6.7e-4,-0.003 0,-0.004 l 0.006,-0.01 a 0.50005,0.50005 0 0 0 0.0586,-0.3125 c 0.51014,-1.16591 0.35331,-2.52952 -0.5625,-3.44531 -0.49921,-0.49921 -1.13538,-0.80107 -1.80078,-0.88868 -0.16635,-0.0219 -0.33377,-0.0303 -0.50195,-0.0254 z M 458,496 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -4.65039,2.64258 -1.05078,0.66211 a 1.50015,1.50015 0 0 1 -0.0488,0.0293 c -0.34485,0.1991 -0.62663,0.47142 -0.83594,0.78711 l 4.22461,4.22657 1.3613,1.35936 V 507.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c 0,-0.0833 0.0571,-0.22505 0.16602,-0.33398 C 459.27495,506.05708 459.41667,506 459.5,506 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.79297 z"
- transform="translate(42.000002,-21.000005)"
- id="path13315"
+ id="path20610"
+ d="m 348.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 C 343.03811,413.14537 342,418.71429 342,422.5 a 1.50015,1.50015 0 1 0 3,0 c 0,-0.89832 0.0865,-1.89371 0.26758,-2.9043 -0.25845,-3.40076 0.85029,-7.04233 3.87109,-9.4707 a 1.50015,1.50015 0 0 0 -0.625,-0.13672 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
+ <path
+ id="path20608"
+ d="m 351.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 c -4.71461,2.94662 -5.33528,8.77693 -3.58399,12.86328 a 1.5005399,1.5005399 0 1 0 2.75782,-1.1836 c -0.38431,-0.89672 -0.59027,-1.91481 -0.62891,-2.95117 -0.67215,-3.14692 0.29131,-6.6121 2.9043,-8.82422 a 1.50015,1.50015 0 0 0 -0.64063,-0.14453 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20592"
+ d="m 354.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 c -4.9147,3.07168 -4.9147,10.47128 0,13.54296 a 1.50015,1.50015 0 1 0 1.58984,-2.54296 c -3.0853,-1.92832 -3.0853,-6.52872 0,-8.45704 a 1.50015,1.50015 0 0 0 -0.78125,-2.7832 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 449.50391,369 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 455 c 1.08333,0 2.07323,-0.26796 2.8125,-0.85938 C 458.55177,379.54921 459,378.625 459,377.5 c 0,-1.125 -0.44823,-2.04921 -1.1875,-2.64062 -0.49098,-0.39279 -1.11527,-0.59695 -1.78125,-0.72071 C 456.61178,373.63193 457,372.89881 457,372 c 0,-0.96354 -0.41934,-1.76349 -1.07422,-2.26758 C 455.27091,369.22833 454.41324,369 453.5,369 Z m 0.5,1 H 453.5 c 0.74361,0 1.38549,0.19369 1.81641,0.52539 0.43091,0.3317 0.68359,0.7813 0.68359,1.47461 0,0.69331 -0.25268,1.14291 -0.68359,1.47461 C 454.88549,373.80631 454.24361,374 453.5,374 h -3.49609 z m 0,5 h 3.46093 0.0352 1.5 c 0.91667,0 1.67677,0.23204 2.1875,0.64062 0.51073,0.40859 0.8125,0.98438 0.8125,1.85938 0,0.875 -0.30177,1.45079 -0.8125,1.85938 C 456.67677,379.76796 455.91667,380 455,380 h -4.99609 z"
- id="path10949-7"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccscsccscsccscscscccccscscscc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 408.50391,369 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5.91992 a 0.50005,0.50005 0 0 0 0,0.16211 V 380.5 a 0.50005,0.50005 0 1 0 1,0 V 376 h 3.25586 l 3.84961,4.8125 a 0.50024018,0.50024018 0 1 0 0.78124,-0.625 l -3.49414,-4.36914 c 1.48603,-0.40423 2.60743,-1.70768 2.60743,-3.31836 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0.5,1 h 3.5 c 1.38662,0 2.5,1.11337 2.5,2.5 0,1.38663 -1.11338,2.5 -2.5,2.5 a 0.50005,0.50005 0 0 0 -0.004,0 h -3.49609 z"
- id="path13132"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 431.51758,369.26562 C 429.42795,369.91461 428,371.85293 428,374.04102 V 376 c 0,1.78552 0.9537,3.43731 2.5,4.33008 1.54631,0.89277 3.45369,0.89277 5,0 1.5463,-0.89277 2.5,-2.54456 2.5,-4.33008 v -0.5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -4 a 0.50004997,0.50004997 0 1 0 0,1 h 3.5 c 0,1.42986 -0.7617,2.74991 -2,3.46484 -1.23829,0.71494 -2.76171,0.71494 -4,0 -1.2383,-0.71493 -2,-2.03498 -2,-3.46484 v -1.95898 c 0,-1.75422 1.13918,-3.30002 2.81445,-3.82032 1.69498,-0.52641 3.36746,-0.003 4.25196,1.5293 a 0.50050004,0.50050004 0 1 0 0.86718,-0.5 c -1.1155,-1.93212 -3.34609,-2.62724 -5.41601,-1.98438 z"
- id="path13141"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g13321"
- transform="translate(-42.000002,21.000005)">
- <g
- id="g13309"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 365.49219,94.992188 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.004,0.0059 l -1.95313,1.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707032 L 365,96.707031 V 98.5 a 0.50005,0.50005 0 1 0 1,0 v -1.792969 l 1.14648,1.146485 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 l -1.95704,-1.957031 a 0.50005,0.50005 0 0 0 -0.40429,-0.197265 z m 9.05859,1.941406 a 0.50005,0.50005 0 0 0 -0.0586,0.0059 h -2.93164 a 0.50005,0.50005 0 1 0 0,1 h 1.79297 l -3.14649,3.146486 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3.14649,-3.146485 v 1.792965 a 0.50005,0.50005 0 1 0 1,0 v -2.931637 a 0.50005,0.50005 0 0 0 -0.50977,-0.574218 z m -0.0566,7.060546 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 375.29297,106 H 371.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path13047-6"
- inkscape:connector-curvature="0" />
- </g>
- <g
- id="g13313"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98000004;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 324.5,121 c -1.14583,0 -1.86235,0.56478 -2.18359,1.12695 C 321.99517,122.68912 322,123.25 322,123.25 V 125 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 327 v -1.75 c 0,0 0.005,-0.56088 -0.31641,-1.12305 C 326.36235,121.56478 325.64583,121 324.5,121 Z m 0,1 c 0.85417,0 1.13765,0.31022 1.31641,0.62305 C 325.99517,122.93588 326,123.25 326,123.25 V 125 h -3 v -1.75 c 0,0 0.005,-0.31412 0.18359,-0.62695 C 323.36235,122.31022 323.64583,122 324.5,122 Z m -0.5,4 h 1 v 2 h -1 z"
- transform="translate(42.000002,-21.000005)"
- id="rect13261"
- inkscape:connector-curvature="0" />
- </g>
+ id="g10007"
+ inkscape:label="T-16"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 331,410 c -2.22355,0 -4.0767,1.3002 -5.12305,3.18945 0.93682,-0.21724 1.92473,-0.28964 2.92578,-0.17187 0.40221,0.0473 0.78928,0.12403 1.16797,0.21484 C 330.29795,413.09146 330.64197,413 331,413 h 0.5 c 2.02848,0.0287 2.02848,-3.02869 0,-3 z m -3.05859,3.95898 c -3.69856,-0.0756 -6.93164,2.52898 -6.93164,6.04102 v 1.5 c -0.0287,2.02848 3.02869,2.02848 3,0 V 420 c 0,-1.75382 1.80351,-3.30654 4.32617,-3.00977 0.37314,0.0439 0.71883,0.11732 1.03711,0.21485 1.3077,0.40071 2.14372,1.21003 2.47656,1.91211 0.22905,0.48316 0.34095,1.19341 -0.0996,1.63281 -0.4946,0.4933 -1.25,0.34848 -1.89258,-0.0527 -0.70436,-0.44 -1.43726,-1.36047 -1.75195,-2.71875 -0.21041,-0.0194 -0.41646,-0.0328 -0.60742,-0.0234 -1.06865,0.0527 -1.81638,0.53365 -2.19727,1.13086 0.52848,1.85114 1.6077,3.30531 2.9668,4.15429 1.61509,1.00892 3.82413,1.05951 5.33594,-0.2539 0.0754,-0.0514 0.14605,-0.10959 0.21093,-0.17383 0.0562,-0.057 0.10785,-0.11837 0.1543,-0.18359 1.19162,-1.34198 1.31147,-3.2788 0.5918,-4.79688 -0.75194,-1.58612 -2.28118,-2.87289 -4.3086,-3.49414 -0.49344,-0.15121 -1.01745,-0.26354 -1.5664,-0.32812 -0.2499,-0.0294 -0.49757,-0.0457 -0.74414,-0.0508 z"
+ id="path20562"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="scccsccscsccsccccccccccccccccc" />
</g>
<g
+ style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
- id="g13337"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- transform="matrix(-1,0,0,1,1458,302.99979)">
- <path
- style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1262.5,-278.49979 h -13 v -13 h 13 v 13"
- id="path14450"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1257.5039,-287 c -0.191,-10e-4 -0.3661,0.1063 -0.4512,0.27734 l -3,6 c -0.1652,0.33223 0.076,0.72231 0.4473,0.72266 h 6 c 0.371,-3.5e-4 0.6125,-0.39043 0.4473,-0.72266 l -3,-6 c -0.084,-0.16853 -0.2552,-0.27571 -0.4434,-0.27734 z"
- id="path13331"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
+ id="g20538"
+ transform="rotate(180,317.5055,417)"
+ inkscape:label="T-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1252.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
- id="ellipse13333"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 331.50586,410 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path20529"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ sodipodi:nodetypes="ccccccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1249.5,-292 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12.9199 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0,-0.002 0.50005,0.50005 0 0 0 0.033,-0.0312 0.50005,0.50005 0 0 0 0,-0.004 0.50005,0.50005 0 0 0 0.031,-0.0332 0.50005,0.50005 0 0 0 0,-0.004 0.50005,0.50005 0 0 0 0.1035,-0.39453 V -291.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
- id="path13335"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 323.95117,412.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 C 329.94786,421.40861 333,419.08206 333,416 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 c 0,2.41794 -2.42686,4.35855 -5.44141,4.00391 -1.98998,-0.23412 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 C 326.73975,422.63463 325.92671,423 325,423 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 1.17529,0 2.25213,-0.41841 2.88477,-1.18164 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z"
+ id="path20536"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- transform="matrix(1,0,0,-1,-1.8536743e-6,6.0000045)"
- id="g13398">
+ transform="rotate(180,307.0055,417)"
+ id="g13597"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="T-14">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 237.5,-19 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
- id="path13392"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 289.50391,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -0.99414 c -1.17529,0 -2.25213,0.41841 -2.88477,1.18164 -0.28029,0.32895 -0.0395,0.83456 0.39258,0.82422 0.14712,-0.004 0.28501,-0.0726 0.37695,-0.1875 C 286.27001,413.36537 287.08306,413 288.00977,413 h 0.99414 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -4.58594,3.95898 c -1.10666,0.0478 -2.07229,0.36866 -2.82031,0.91211 -0.99737,0.72461 -1.58789,1.85424 -1.58789,3.12891 v 1 h -1.50586 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.49414 v -1 c 0,-0.97533 0.41802,-1.76979 1.17578,-2.32031 0.75777,-0.55053 1.87662,-0.84701 3.26562,-0.6836 1.98998,0.23412 3.41358,1.22814 4.10352,2.33203 0.68994,1.10391 0.68215,2.23778 -0.14844,3.06836 -0.83795,0.83796 -1.98844,0.89361 -3.08398,0.26368 -1.09554,-0.62994 -2.08242,-1.9799 -2.31641,-3.96875 -0.0504,-0.69579 -1.10528,-0.57121 -0.99219,0.11718 0.26601,2.26115 1.40414,3.91119 2.8086,4.71875 0.70223,0.40379 1.48456,0.58895 2.23632,0.52735 0.75176,-0.0616 1.47366,-0.37015 2.05469,-0.95117 1.16941,-1.16942 1.16162,-2.91055 0.28906,-4.30664 -0.87256,-1.3961 -2.57396,-2.52709 -4.83398,-2.79297 -0.39761,-0.0468 -0.78151,-0.0608 -1.15039,-0.0449 z M 280.00391,421 h 2 v 2 h -2 z"
+ transform="rotate(180,307.0055,417)"
+ id="path13595"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(-84,-63)"
+ id="g21409"
+ inkscape:label="T-13">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 237.5,-19 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 1.7e-4,0.4453235 0.53852,0.6683012 0.85352,0.3535156 l 13,-12.9999996 C 251.1683,-18.461483 250.94532,-18.99983 250.5,-19 Z"
- id="path13396"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 269.13867,410.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -8.5,8.5 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 l 8.5,-8.5 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -1.88867,2.42383 2.29297,2.29297 -7.29883,7.29883 -3.05859,0.76562 0.76562,-3.05859 z"
+ transform="translate(84,63)"
+ id="path21405"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
+ sodipodi:nodetypes="cccccccccsccccccccc" />
</g>
<g
+ id="g84226"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-12">
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.7;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 240.51382,409.98613 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -3,3 a 0.50005,0.50005 0 1 0 0.707,0.707 l 3,-3 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 5,0 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -8,8 a 0.50005,0.50005 0 1 0 0.707,0.707 l 8,-8 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 5,0 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -4.416,4.416 c 0.2729,0.1952 0.5118,0.4341 0.707,0.707 l 4.416,-4.416 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 0,5 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -8,8 a 0.50005,0.50005 0 1 0 0.707,0.707 l 8,-8 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m -6.5059,1.0059 a 1.0000001,1 0 0 0 -1,1 1.0000001,1 0 0 0 1,1 1.0000001,1 0 0 0 1,-1 1.0000001,1 0 0 0 -1,-1 z m -2.4375,2.7305 -4.416,4.416 a 0.50005,0.50005 0 1 0 0.707,0.707 l 4.416,-4.416 c -0.2729,-0.1952 -0.5118,-0.4341 -0.707,-0.707 z m 8.9434,1.2636 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -3,3 a 0.50005,0.50005 0 1 0 0.707,0.707 l 3,-3 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z"
+ id="path21556-6"
+ inkscape:connector-curvature="0"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="115"
+ inkscape:export-ydpi="115" />
+ </g>
+ <g
+ transform="translate(63,189)"
+ id="g13463"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13454"
- transform="translate(41.999998,-20.999995)">
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="T-11">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 174.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 187.5,32 Z m 0.5,1 h 12 v 12 h -12 z"
- id="path13377"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 221.5,410 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 218.29297,413 H 216.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 221.5,424 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 410.78125 410.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 222 v 12 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 218.5,420 H 217 v -6 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z m 6.75977,1.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27328,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41099,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10286,2.06013 1.1045,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25221,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
+ transform="translate(-63,-189)"
+ id="path13456"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g84235"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 174.58789,32.005859 C 174.30358,31.956646 174.00013,32.166007 174,32.5 v 13 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 13 c 0.44532,-1.7e-4 0.6683,-0.538517 0.35352,-0.853516 l -13,-13 c -0.0788,-0.0787 -0.17086,-0.12422 -0.26563,-0.140625 z M 178.49609,38 c 0.191,-10e-4 0.36608,0.106304 0.45118,0.277344 l 3,6 C 182.11247,44.609574 181.8713,44.99965 181.5,45 h -6 c -0.371,-3.5e-4 -0.61247,-0.390426 -0.44727,-0.722656 l 3,-6 c 0.084,-0.16853 0.25516,-0.275714 0.44336,-0.277344 z"
- id="path13379"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ccccccscsccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path5256"
+ d="m 197.50977,409.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5039 c 0.0205,0.58311 0.0403,1.03618 -0.0488,1.24805 -0.22838,0.54301 -0.5609,0.82668 -1.00781,1.10937 -0.44691,0.28269 -1.00733,0.53131 -1.53711,0.97461 -0.52977,0.4433 -1.00108,1.10059 -1.22656,2.08789 -0.22548,0.9873 -0.2332,2.29903 0.0625,4.16406 0.0385,0.24311 0.24801,0.42203 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.2745 0.49414,-0.57812 -0.36883,-2.32606 -0.21493,-3.6368 0.12305,-4.40821 0.33798,-0.7714 0.85304,-1.08606 1.49804,-1.45508 0.645,-0.36901 1.43565,-0.7809 1.90821,-1.70703 0.47255,-0.92613 0.59571,-2.25921 0.21289,-4.4375 C 208.70043,411.17484 208.49284,411.0002 208.25,411 h -7.24023 v -0.50586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 3,1.00586 h 6.78125 c 0.25456,1.74951 0.14487,2.81594 -0.15235,3.39844 -0.3247,0.63637 -0.84774,0.91198 -1.51367,1.29297 -0.66593,0.38098 -1.46183,0.87882 -1.91797,1.91992 -0.41222,0.94085 -0.49675,2.35477 -0.23633,4.38867 h -7.73437 c -0.19264,-1.47462 -0.23076,-2.65205 -0.0684,-3.36328 0.18281,-0.80045 0.49635,-1.21142 0.89258,-1.54297 0.39622,-0.33155 0.90291,-0.56523 1.42968,-0.89844 0.52678,-0.33321 1.07351,-0.7985 1.39649,-1.5664 0.22021,-0.52359 0.17686,-1.05487 0.13867,-1.63477 h 0.48438 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g84238"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 184.5,35 c 0.82251,0 1.5,0.677494 1.5,1.5 0,0.822506 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.677494 -1.5,-1.5 0,-0.822506 0.67749,-1.5 1.5,-1.5 z"
- id="ellipse13420"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="path5262"
+ d="m 180.5,410 c -2.08712,0 -3.47816,1.04607 -4.39062,2.1875 a 0.50024408,0.50024408 0 0 0 0.78125,0.625 C 177.69049,411.81193 178.73439,411 180.5,411 c 2.09839,0 3.13411,0.87695 3.75195,1.94531 C 184.8698,414.01367 185,415.31651 185,416 h -5.25 c -1.27344,0 -2.44324,0.36418 -3.31445,1.05469 -0.87121,0.69051 -1.42774,1.72791 -1.42774,2.94531 0,1.2174 0.55653,2.2548 1.42774,2.94531 C 177.30676,423.63582 178.47656,424 179.75,424 h 0.75 c 1.75558,0 3.38771,-0.96684 4.53711,-2.0332 0.0781,0.53303 0.28951,1.00434 0.64062,1.35547 C 186.12862,423.77315 186.775,424 187.5,424 a 0.50005,0.50005 0 1 0 0,-1 c -0.525,0 -0.87862,-0.14815 -1.11523,-0.38477 C 186.14815,422.37862 186,422.025 186,421.5 V 416 c 0,-0.79721 -0.12242,-2.24322 -0.88086,-3.55469 C 184.3607,411.13385 182.89646,410 180.5,410 Z m -0.75,7 H 185 v 3.56055 C 184.04582,421.68473 182.18875,423 180.5,423 h -0.75 c -1.08101,0 -2.03187,-0.31555 -2.69336,-0.83984 -0.66149,-0.52429 -1.04883,-1.23676 -1.04883,-2.16016 0,-0.9234 0.38734,-1.63587 1.04883,-2.16016 C 177.71813,417.31555 178.66899,417 179.75,417 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(-0.02999339)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14346">
+ id="g20896"
+ transform="translate(-189,63)"
+ inkscape:label="T-8">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 184.27734,515 c -0.3909,-0.007 -0.822,0.0708 -1.2832,0.25781 -1.22985,0.49878 -2.7569,1.66874 -4.85742,3.90039 -2.09205,2.22266 -3.24657,3.73559 -3.77539,4.91602 -0.26441,0.59022 -0.37396,1.11195 -0.31641,1.58984 0.0576,0.4779 0.29454,0.88243 0.60156,1.18946 0.013,0.0131 0.0267,0.0255 0.041,0.0371 l 2.5,2 c 0.49277,0.39559 1.11361,-0.29808 0.66602,-0.74414 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.97657,-1.9746 c -0.008,-0.009 -0.0153,-0.0172 -0.0234,-0.0254 -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.97657,-1.9746 c -0.008,-0.009 -0.0153,-0.0172 -0.0234,-0.0254 -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 c -0.36948,-0.36947 -0.29946,-0.99351 0,-1.29296 0.3216,-0.32161 0.86101,-0.43196 1.29296,0 l 2,2 c 0.44606,0.44759 1.13973,-0.17325 0.74414,-0.66602 l -2,-2.5 c -0.0116,-0.0143 -0.024,-0.028 -0.0371,-0.041 -0.30703,-0.30702 -0.7149,-0.52843 -1.19922,-0.61132 -0.12109,-0.0207 -0.24665,-0.0327 -0.37696,-0.0352 z"
- transform="translate(1.8536743e-6)"
- id="path14236"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 161.50391,410 c -0.82054,0 -1.4961,0.67556 -1.4961,1.49609 0,0.82054 0.67556,1.4961 1.4961,1.4961 0.82053,0 1.49609,-0.67556 1.49609,-1.4961 C 163,410.67556 162.32444,410 161.50391,410 Z M 153.5,411 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 414 h 0.51562 2.49805 L 160,417.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97656,0.21094 0.67528,-3.15139 1.92341,-4.0882 3.51758,-5.42774 1.58398,1.34059 2.83152,2.27747 3.51953,5.42969 0.13318,0.66658 1.13543,0.44609 0.97656,-0.21484 -0.76273,-3.49457 -2.35104,-4.70351 -4.00195,-6.11719 L 161.01367,414 h 2.2168 3.28515 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04296 c -0.45945,0.59659 -1.17125,0.99219 -1.96875,0.99219 -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 H 157.51562 157 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
+ transform="translate(189,-63)"
+ id="path20782"
inkscape:connector-curvature="0" />
</g>
<g
+ id="g21469-5"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13042"
- transform="translate(-21.000002,42.000005)">
- <g
- id="g13022"
- transform="translate(-42.00718,397.99283)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 447.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 2 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 455 v -2 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -10 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 9 h -12 z"
- id="path13020"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccc" />
- </g>
+ transform="translate(498,-1438)"
+ inkscape:label="T-7">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 410.49023,558.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 408.70703,563 H 416.5 a 0.50005,0.50005 0 1 0 0,-1 h -7.79297 l 2.14649,-2.14648 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
- id="path12420-1"
+ inkscape:connector-curvature="0"
+ id="path21106-9"
+ d="m -356.5,1850 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.2179 0.5,0.5 0,0.2821 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.2179 -0.5,-0.5 0,-0.2821 0.21794,-0.5 0.5,-0.5 z m -7,1 a 0.5,0.5 0 0 0 -0.5,0.5 0.5,0.5 0 0 0 0.5,0.5 0.5,0.5 0 0 0 0.5,-0.5 0.5,0.5 0 0 0 -0.5,-0.5 z"
+ style="display:inline;opacity:0.7;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.7;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ <path
+ sodipodi:nodetypes="csssscccsscccsccccccscccccccccccccccccccccsccsccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ d="m -357.5,1856.0041 h 0.49805 c 3.5943,0 5.00195,-2.5001 5.00195,-4.5001 v 0 c 0,-2.4794 -2.02064,-4.5 -4.5,-4.5 -1.88915,0 -3.45662,1.2594 -4.10547,3 h -0.51758 c -0.64602,-0.6132 -1.47755,-0.9979 -2.375,-1 h -0.002 c -1.92707,0 -3.5,1.5729 -3.5,3.5 0,1.9271 1.57293,3.5 3.5,3.5 z m -6,-1.0041 c -1.38663,0 -2.5,-1.1134 -2.5,-2.5 0,-1.386 1.11233,-2.4989 2.49805,-2.5 0.71036,0 1.38608,0.3048 1.85937,0.834 0.0951,0.1059 0.23074,0.1663 0.37305,0.166 h 0.90234 c 0.22809,10e-5 0.42734,-0.1542 0.48438,-0.375 0.39914,-1.5459 1.78609,-2.6224 3.38281,-2.625 1.93892,0 3.5,1.5611 3.5,3.5 0,1.9279 -1.54523,3.4765 -3.46875,3.4941 -0.0392,0 -0.0785,-6e-4 -0.11719,0.01 H -357.5 Z m -1.00781,1.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -1.5039 h 0.33594 l 2.61914,1.9043 c 0.0852,0.064 0.18852,0.099 0.29492,0.1 h 0.25 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -0.25 c -0.106,-10e-5 -0.20927,0.034 -0.29492,0.096 L -355.66211,1859 H -356 v -2 h -1 v 4 h -4.29297 L -362,1860.293 V 1857 h -1 v 1 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z M -353,1858.3008 v 2.3984 l -1.65039,-1.1992 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path21108-3" />
+ <path
+ id="rect24266"
+ d="m -362,1857 h 5 v 1 h -5 z"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13097">
+ id="g24264-7"
+ transform="translate(-910,-1146)"
+ inkscape:label="T-6">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 74,477 c -0.710648,0 -1.272904,0.36437 -1.621094,0.82227 -0.348189,0.45789 -0.546604,0.99437 -0.748047,1.49023 -0.201442,0.49586 -0.404614,0.94894 -0.65039,1.24023 C 70.734693,480.84402 70.491667,481 70,481 h -1 v 1 h 1 c 0.758333,0 1.359057,-0.34402 1.746094,-0.80273 0.387036,-0.45871 0.605739,-1.00563 0.810547,-1.50977 0.204807,-0.50414 0.397017,-0.96766 0.61914,-1.25977 C 73.397904,478.13563 73.585648,478 74,478 c 0.376652,0 0.584084,0.165 0.837891,0.55664 0.253806,0.39164 0.470672,0.98903 0.689453,1.61524 0.21878,0.6262 0.438752,1.28115 0.794922,1.82812 0.35617,0.54697 0.933457,1.00595 1.68164,1 0.673157,-0.005 1.209041,-0.26371 1.570313,-0.62109 0.361272,-0.35739 0.571027,-0.77752 0.771484,-1.14649 0.200458,-0.36897 0.389328,-0.68586 0.623047,-0.89258 C 81.202469,480.13313 81.474401,480 82,480 h 1 v -1 h -1 c -0.724401,0 -1.296219,0.23882 -1.695312,0.5918 -0.399094,0.35298 -0.632099,0.78332 -0.837891,1.16211 -0.205793,0.37878 -0.386663,0.70727 -0.595703,0.91406 -0.209041,0.20679 -0.423157,0.32843 -0.875,0.33203 -0.376817,0.003 -0.58078,-0.15803 -0.833985,-0.54688 -0.253205,-0.38884 -0.470733,-0.98529 -0.689453,-1.61132 -0.218719,-0.62603 -0.439353,-1.28142 -0.794922,-1.83008 C 75.322166,477.46306 74.748348,477 74,477 Z"
- id="path15332-4"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ id="path24260-0"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 82.5,473 -13,0.004 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 480 h 1 v -5.99609 L 82,474 v 4 h 1 v -4.5 A 0.50005,0.50005 0 0 0 82.5,473 Z m -0.5,8 v 5 H 70 v -3 h -1 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 A 0.50005,0.50005 0 0 0 83,486.5 V 481 Z"
- id="path12638-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
+ id="path24262-3"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13177"
- transform="translate(-1.8536743e-6,-20.999995)">
- <g
- id="g13282"
- transform="translate(20,-21)"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 246.49805,74 c -0.13192,5.4e-4 -0.25829,0.0532 -0.35157,0.146484 C 245.43577,74.857204 244.09848,76 241.5,76 A 0.50005,0.50005 0 0 0 241,76.5 V 79 h -0.5 c -0.75833,0 -1.38671,0.318735 -1.90625,0.734375 -0.51954,0.41563 -0.962,0.926849 -1.44727,1.412109 -0.39648,0.39648 0.31056,1.103512 0.70704,0.707032 0.4558,-0.45581 0.79842,-0.643904 1.18164,-0.746094 C 239.41838,81.005232 239.875,81 240.5,81 h 0.5 v 4.5 c 0,0.75694 -0.56911,1.365513 -1.18359,1.476562 -0.30725,0.0555 -0.62032,0.004 -0.94141,-0.228515 -0.32109,-0.23272 -0.65388,-0.66673 -0.90039,-1.40625 A 0.50005,0.50005 0 0 0 237,85.5 v 1 a 0.50005,0.50005 0 0 0 0.14648,0.353516 C 238.22544,87.932473 239.1944,88.00968 240,88 c 0,0 0.002,0 0.002,0 9.9e-4,0 0.003,10e-7 0.004,0 0.001,-1.6e-5 0.003,1.8e-5 0.004,0 0.36494,-7.26e-4 0.98133,-0.05472 1.67773,-0.203125 0.19213,-0.0454 0.36061,-0.131526 0.54297,-0.197266 0.41443,-0.1248 0.82232,-0.201598 1.24219,-0.449218 C 244.82222,86.354491 246,84.75992 246,82 v -1 h 2.5 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.146484 l 1,-1 C 250.16831,79.538516 249.94532,79.00017 249.5,79 H 246 v -2.529297 c 0.26613,0.242116 0.53257,0.477435 0.83203,0.527344 0.63268,0.10544 1.23725,-0.0679 1.76563,-0.332031 1.05675,-0.52838 1.9005,-1.45715 2.25586,-1.8125 0.45304,-0.47127 -0.23577,-1.160072 -0.70704,-0.707032 -0.31826,0.31827 -0.84181,0.673592 -1.40039,0.763672 -0.55857,0.0901 -1.16912,-0.02339 -1.88867,-0.759765 -0.0945,-0.0967 -0.22417,-0.150901 -0.35937,-0.150391 z m -2.50977,3.013672 c 0.004,-1.62e-4 0.008,1.67e-4 0.0117,0 V 83 c 0,1.65476 -0.45037,2.602541 -1.13477,3.181641 -0.20404,0.172661 -0.46051,0.286861 -0.72656,0.390625 C 242.64927,85.748655 243,84.573733 243,83 v -5.982422 c 0.35078,0.0051 0.69957,0.0073 0.98828,-0.0039 z"
- transform="translate(-19.999998,41.999995)"
- id="path13240"
- inkscape:connector-curvature="0" />
- </g>
+ id="g14534"
+ inkscape:label="T-5">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 100.24805,410.01367 c -1.271268,0.11136 -2.328782,0.98616 -2.845706,2.17774 -2.575841,-0.61979 -5.266939,0.50372 -6.597656,2.80859 -1.356612,2.34971 -0.965414,5.32365 0.953124,7.24219 1.918537,1.91853 4.892473,2.30974 7.242188,0.95312 2.30486,-1.33072 3.42838,-4.02182 2.80859,-6.59765 1.3618,-0.59077 2.3103,-1.88718 2.17774,-3.40235 -0.14775,-1.68875 -1.49289,-3.03389 -3.18164,-3.18164 -0.1894,-0.0166 -0.37503,-0.0159 -0.55664,0 z m 0.0234,0.9961 c 0.14685,-0.0133 0.29578,-0.0133 0.44727,0 1.21193,0.10603 2.16545,1.05955 2.27148,2.27148 0.10604,1.21192 -0.66865,2.31795 -1.84375,2.63281 a 0.50005006,0.50005006 0 0 0 -0.35937,0.58203 l 0.0352,0.17969 a 0.50005006,0.50005006 0 0 0 0.008,0.0293 c 0.58634,2.18824 -0.36816,4.49227 -2.33008,5.625 -1.961931,1.13272 -4.433244,0.80698 -6.035156,-0.79492 -1.601912,-1.60191 -1.927645,-4.07323 -0.794922,-6.03516 1.132722,-1.96193 3.43675,-2.91642 5.625,-2.33008 a 0.50005006,0.50005006 0 0 0 0.0293,0.008 l 0.179687,0.0352 a 0.50005006,0.50005006 0 0 0 0.582032,-0.35937 c 0.275511,-1.02822 1.157648,-1.75045 2.185539,-1.84375 z M 94.5,416 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 97.5,416 Z m 0.5,1 h 2 v 2 h -2 z"
+ id="circle13742"
+ inkscape:connector-curvature="0" />
</g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g13304"
- transform="translate(-84.000015,-126)">
+ id="g84223"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 475,157.99609 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 471.00799,159.2674 471,160.00249 471,160.49609 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 472,160.99414 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-1e-5 2.78534,-0.23261 3.38867,-0.75196 C 478.99201,170.7326 479,169.99751 479,169.50391 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 A 0.50005,0.50005 0 0 0 478.49805,168 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 L 478,169.00586 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 C 471.99201,170.26029 472,169.99751 472,169.50391 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z"
- id="path13302"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 70.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.859375 l -0.824219,3.29883 a 0.50005,0.50005 0 0 0 -0.04102,0.16797 l -1.478516,5.91211 A 0.50005,0.50005 0 0 0 69.5,424 h 4.921875 a 0.50005,0.50005 0 0 0 0.160156,0 h 4.892578 a 0.50005,0.50005 0 0 0 0.484375,-0.37695 l 3.03711,-11.99024 a 0.50005,0.50005 0 0 0 -0.484375,-0.62304 l -4.90625,-0.006 a 0.50005,0.50005 0 0 0 -0.205078,0 L 74,411 v -0.5 A 0.50005,0.50005 0 0 0 73.5,410 Z m 0.5,1 h 2 v 2 h -0.921875 a 0.50005,0.50005 0 0 0 -0.160156,0 H 71 Z m 3,1 2.859375,0.004 -1.25,4.99609 h -3.96875 l 0.75,-3 H 73.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 3.888672,0.004 3.980469,0.006 -1.263672,4.99 H 76.640625 Z M 71.390625,418 h 3.96875 l -1.25,5 h -3.96875 z m 5,0 h 3.960937 l -1.265624,5 h -3.945313 z"
+ id="path14034"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 433,120 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z"
- id="circle13367"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ <g
+ id="g84211"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-3">
+ <path
+ inkscape:connector-curvature="0"
+ id="path22951-5"
+ d="m 52.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 56,413.5 V 412 h 0.5 c 1.293073,0 2.425866,0.35206 3.21875,1.00977 C 60.511634,413.66747 61,414.62406 61,416 c 0,1.58333 -0.78109,3.05511 -2.240234,4.16406 C 57.300621,421.27301 55.159091,422 52.5,422 H 52 v -1.5 A 0.50005,0.50005 0 0 0 51.5,420 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 A 0.50005,0.50005 0 0 0 52,423.5 V 423 h 0.5 c 2.840909,0 5.199379,-0.77301 6.865234,-2.03906 C 61.03109,419.69489 62,417.91667 62,416 62,414.37594 61.372824,413.08253 60.357422,412.24023 59.34202,411.39794 57.973784,411 56.5,411 H 56 v -0.5 A 0.50005,0.50005 0 0 0 55.5,410 Z m 0.5,1 h 2 v 2 h -2 z m -4,10 h 2 v 2 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g84208"
+ style="display:inline;enable-background:new"
+ inkscape:label="T-2">
+ <path
+ inkscape:connector-curvature="0"
+ id="path17434"
+ d="m 27.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.949219 L 32,420.62695 V 423.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.87305 L 39.550781,414 H 40.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 40.5,410 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 30.5,410 Z m 0.5,1 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -7,1 h 6 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.914062 l -3.214843,6 h -2.398438 l -3.214843,-6 H 30.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 2,9 h 2 v 2 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
<g
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
- id="g13384"
- transform="translate(-21.000002,-105)"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <rect
- style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- id="rect13372"
- width="16"
- height="16"
- x="236"
- y="325"
- rx="0"
- ry="0" />
- <g
- id="g13382"
- transform="translate(1)"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 238.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 9,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z"
- id="path13378"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccc" />
- <path
- style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 240.12109,326 1.43946,1.43945 c 0.58556,0.5858 0.58556,1.5353 0,2.1211 L 240.12109,331 h 5.75782 l -1.43946,-1.43945 c -0.58556,-0.5858 -0.58556,-1.5353 0,-2.1211 L 245.87891,326 Z"
- id="path13380"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
- </g>
+ transform="translate(-21,42)"
+ id="g12626"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="T-1">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 31.492188,367.99219 A 0.50005,0.50005 0 0 0 31,368.5 v 8.79297 l -3.853516,3.85351 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 31.707031,378 H 40.5 a 0.50005,0.50005 0 1 0 0,-1 H 32 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ id="path12205"
+ inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 221.50195,227 c -0.35971,-0.001 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0266 -0.12814,-0.0406 -0.19535,-0.041 z"
- id="path12946-5"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
<g
+ id="g6275"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12888"
- transform="translate(-1.8536743e-6,21.000005)">
+ inkscape:label="S-25">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 241.48438,452 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 l -3,3 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z M 243,452 v 5 h -5 v 1.5 c 2e-5,0.1326 0.0527,0.25976 0.14648,0.35352 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 1.64648,1.64649 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 0.64648,0.64649 1,1 c 0.315,0.31479 0.85335,0.0918 0.85352,-0.35352 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 4.49219,9 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -2.64648,2.64649 -1.64648,-1.64649 c -0.19527,-0.19519 -0.51177,-0.19519 -0.70704,0 l -2.64648,2.64649 -1.64648,-1.64649 c -0.315,-0.31479 -0.85335,-0.0918 -0.85352,0.35352 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.00781 9.99219 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -2e-5,-0.1326 -0.0527,-0.25976 -0.14648,-0.35352 l -1,-1 -1,-1 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
- id="path14234"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccc" />
+ id="path14559-8"
+ d="m 519.02539,389.05664 c -1.23014,0.0645 -2.42356,0.6345 -3.37891,1.58984 l -4,4 c -0.95534,0.95535 -1.53001,2.15146 -1.59765,3.38477 -0.0676,1.23331 0.38786,2.49571 1.41406,3.50977 1.02392,1.0118 2.28158,1.46686 3.51172,1.40234 1.23014,-0.0645 2.42356,-0.6345 3.37891,-1.58984 l 4,-4 c 0.95534,-0.95535 1.53001,-2.15146 1.59765,-3.38477 0.0676,-1.23331 -0.38786,-2.4957 -1.41406,-3.50977 -1.02392,-1.0118 -2.28158,-1.46686 -3.51172,-1.40234 z m 0.0527,0.99805 c 0.95617,-0.0502 1.91199,0.28134 2.75586,1.11523 0.8416,0.83165 1.17171,1.78562 1.11914,2.74414 -0.0526,0.95853 -0.50462,1.93042 -1.30664,2.73242 l -4,4 c -0.80201,0.80202 -1.76844,1.24868 -2.7246,1.29883 -0.95617,0.0502 -1.91199,-0.28134 -2.75586,-1.11523 -0.8416,-0.83164 -1.17171,-1.78562 -1.11914,-2.74414 0.0526,-0.95853 0.50462,-1.93041 1.30664,-2.73242 l 4,-4 c 0.80201,-0.80202 1.76844,-1.24868 2.7246,-1.29883 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14564"
+ d="m 517.47266,391.99414 a 0.50005,0.50005 0 0 0 -0.45899,0.62305 c 0.18668,0.77642 0.28491,1.42494 1.14063,2.24414 0.815,0.78022 1.39282,0.94312 2.24023,1.12695 a 0.50005,0.50005 0 1 0 0.21094,-0.97656 c -0.84931,-0.18425 -1.03849,-0.18255 -1.75977,-0.87305 -0.72218,-0.69136 -0.65665,-0.91268 -0.85937,-1.75586 a 0.50005,0.50005 0 0 0 -0.51367,-0.38867 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
+ id="g6267"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13069"
- transform="translate(-21.000002,42.000005)">
+ inkscape:label="S-24">
<path
- sodipodi:nodetypes="ccccccccccccccc"
inkscape:connector-curvature="0"
- id="ellipse12909"
- d="m 290,517 h 2.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2.91992 c -0.029,-0.005 -0.0584,-0.008 -0.0879,-0.008 -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 5.64062 c -0.56586,-0.20756 -1.28645,-0.18129 -1.98242,0.0723 -1.35506,0.4963 -2.23747,1.69879 -1.9707,2.68555 0.26595,0.98712 1.58042,1.38505 2.93554,0.88867 1.22872,-0.45129 2.01759,-1.35494 2.01758,-2.53711 z"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.98999999;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate" />
+ id="path14468-2"
+ d="m 499.91406,389.05664 c -0.77439,-0.15321 -1.63518,-0.1241 -2.51367,0.0664 -1.75698,0.38102 -3.63558,1.4051 -5.25391,3.02343 -1.61833,1.61833 -2.64241,3.49693 -3.02343,5.25391 -0.38103,1.75698 -0.11706,3.43764 0.96093,4.51563 1.07799,1.07798 2.75865,1.34196 4.51563,0.96093 1.75698,-0.38102 3.63558,-1.40511 5.25391,-3.02343 1.61832,-1.61833 2.64241,-3.49693 3.02343,-5.25391 0.38102,-1.75698 0.11705,-3.43764 -0.96093,-4.51563 -0.539,-0.53899 -1.22757,-0.87413 -2.00196,-1.02734 z m -0.21289,0.97656 c 0.61146,0.11888 1.12564,0.37564 1.50781,0.75782 0.76435,0.76434 1.0245,2.05973 0.69141,3.5957 -0.33309,1.53597 -1.26116,3.26702 -2.75391,4.75976 -1.49274,1.49275 -3.22379,2.42081 -4.75976,2.75391 -1.53597,0.3331 -2.83136,0.0729 -3.5957,-0.69141 -0.76435,-0.76434 -1.02451,-2.05973 -0.69141,-3.5957 0.33309,-1.53597 1.26117,-3.26702 2.75391,-4.75976 1.49274,-1.49275 3.22379,-2.42082 4.75976,-2.75391 0.76799,-0.16655 1.47643,-0.18529 2.08789,-0.0664 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 283.51562,517 a 0.50005,0.50005 0 0 0 -0.22656,0.0566 c -1.99745,1.00305 -3.4683,2.88412 -4.03515,5.13477 -0.56686,2.25064 -0.17629,4.64784 1.07421,6.56836 a 0.50005,0.50005 0 1 0 0.8379,-0.54493 c -1.09418,-1.68042 -1.44042,-3.798 -0.94141,-5.77929 0.49902,-1.9813 1.78869,-3.62011 3.51367,-4.48633 A 0.50005,0.50005 0 0 0 283.51562,517 Z m 0.98243,3 a 0.50005,0.50005 0 0 0 -0.26758,0.082 c -1.21391,0.77866 -2.01457,2.12204 -2.19336,3.63086 -0.17879,1.50883 0.2812,3.02564 1.26367,4.11719 a 0.50005,0.50005 0 1 0 0.74219,-0.66992 c -0.77619,-0.86237 -1.15757,-2.0993 -1.01172,-3.33008 0.14584,-1.23079 0.79828,-2.30329 1.73828,-2.90625 A 0.50005,0.50005 0 0 0 284.49805,520 Z"
- id="path12979"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path14550"
+ d="m 493.47266,393.99414 a 0.50005,0.50005 0 0 0 -0.45899,0.62305 c 0.22122,0.92011 0.78151,1.92168 1.64063,2.74414 0.81151,0.77689 1.74924,1.41197 2.74023,1.62695 a 0.50005,0.50005 0 1 0 0.21094,-0.97656 c -0.70573,-0.1531 -1.535,-0.67922 -2.25977,-1.37305 -0.71878,-0.6881 -1.19119,-1.55637 -1.35937,-2.25586 a 0.50005,0.50005 0 0 0 -0.51367,-0.38867 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
+ id="g6259"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(336,21.000005)"
- id="g13340">
- <g
- id="g13324"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 501.98047,136.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -2.7207,2.7207 c -0.0264,-10e-4 -0.0514,-0.008 -0.0781,-0.008 -0.82235,0 -1.5,0.67765 -1.5,1.5 0,0.82235 0.67765,1.5 1.5,1.5 0.82235,0 1.5,-0.67765 1.5,-1.5 0,-0.0267 -0.006,-0.0518 -0.008,-0.0781 l 2.7207,-2.7207 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
- transform="translate(-336,-21.000005)"
- id="rect13317"
- inkscape:connector-curvature="0" />
- </g>
- <g
- id="g13338"
- transform="translate(717.99456,-488.99997)"
- style="opacity:0.6;fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 489.49414,140 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -0.50781 h 5 V 150.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.5 v -4 h -1 v 4 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.49219 h -5 V 148.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.5 v -5 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -0.50781 H 496 v -1 h -4.00586 V 140.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,8 h 1 v 1 h -1 z m 8,0 h 1 v 1 h -1 z"
- transform="translate(-1053.9946,467.99997)"
- id="path13330"
- inkscape:connector-curvature="0" />
- </g>
+ inkscape:label="S-23">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14478-2"
+ d="m 475,388.9375 c -3.89459,0 -7.0625,3.1679 -7.0625,7.0625 0,3.89459 3.16791,7.0625 7.0625,7.0625 3.89459,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.8946 -3.16791,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.35415,0 6.0625,2.70834 6.0625,6.0625 0,3.35415 -2.70835,6.0625 -6.0625,6.0625 -3.35415,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-3.35416 2.70835,-6.0625 6.0625,-6.0625 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14482"
+ d="m 474.47656,390.74414 a 0.50005,0.50005 0 0 0 -0.40039,0.24024 C 473.18442,392.40936 473,393.97991 473,396 c 0,1.96736 0.17366,3.58622 1.07617,5.01758 a 0.50122941,0.50122941 0 1 0 0.84766,-0.53516 C 474.1712,399.28878 474,397.90804 474,396 c 0,-1.96025 0.17286,-3.28436 0.92383,-4.48438 a 0.50005,0.50005 0 0 0 -0.44727,-0.77148 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
+ id="g6251"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(357,21.000005)"
- id="g13370">
- <g
- id="g13360"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 181.98438,115.98633 A 1.0001,1.0001 0 0 0 181,117 v 4.83203 a 1.0001,1.0001 0 0 0 0.28906,0.88477 1.0001,1.0001 0 0 0 0.006,0.006 1.0001,1.0001 0 0 0 0.0137,0.0137 A 1.0001,1.0001 0 0 0 182.1582,123 H 187 a 1.0001,1.0001 0 1 0 0,-2 h -4 v -4 a 1.0001,1.0001 0 0 0 -1.01562,-1.01367 z"
- id="path13358"
- inkscape:connector-curvature="0" />
- </g>
- <g
- transform="matrix(0,-1,-1,0,301.99245,326.99752)"
- id="g13368"
- style="fill:#ffffff">
- <g
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- id="g13366"
- transform="translate(760.99456,-488.99997)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- id="g13364"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -563.5,607 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 l 0.006,-5.50781 h -1 L -555,616 h -8 v -8 h 5.00391 v -1 z"
- id="path13362"
- inkscape:connector-curvature="0" />
- </g>
- </g>
- </g>
+ inkscape:label="S-22">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14492-1-5"
+ d="m 452.5,389 c -0.79539,1.6e-4 -1.5587,0.31644 -2.12109,0.87891 l -2.5,2.5 C 447.31644,392.9413 447.00016,393.70461 447,394.5 v 5.5 c 1.7e-4,1.65084 1.34916,2.99983 3,3 h 5.5 c 0.79539,-1.6e-4 1.5587,-0.31644 2.12109,-0.87891 l 2.5,-2.5 c 0.56247,-0.56238 0.87875,-1.3257 0.87891,-2.12109 v -5.75 c -8e-5,-0.79524 -0.25969,-1.50187 -0.75391,-1.99609 C 459.75187,389.25969 459.04524,389.00008 458.25,389 Z m 0,1 h 5.75 c 0.58541,6e-5 1.00348,0.17535 1.28906,0.46094 0.28559,0.28558 0.46088,0.70365 0.46094,1.28906 v 5.75 c -10e-5,0.53061 -0.21073,1.03891 -0.58594,1.41406 l -2.5,2.5 C 456.53889,401.78928 456.03061,401.9999 455.5,402 H 450 c -1.11046,-1.1e-4 -1.99989,-0.88954 -2,-2 v -5.5 c 10e-5,-0.53061 0.21072,-1.03889 0.58594,-1.41406 l 2.5,-2.5 C 451.46111,390.21072 451.96939,390.0001 452.5,390 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path14494-2"
+ d="m 458.49023,390.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 450.5,393 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 z m 5.99219,1.99219 A 0.50005,0.50005 0 0 0 456,395.5 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 352.72656,472.9707 c -0.84514,-0.0154 -1.69148,0.28718 -2.33008,0.92578 l -2.13476,2.13477 c -1.14247,-0.0826 -2.16028,-0.0359 -2.98047,0.30273 -0.89973,0.37145 -1.59595,1.03428 -2.08008,1.92774 C 342.23291,480.04863 342,482.7268 342,486.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 c 3.7729,0 6.45106,-0.23075 8.23828,-1.19727 0.89361,-0.48326 1.5563,-1.17766 1.92774,-2.07812 0.33865,-0.82099 0.38541,-1.84087 0.30273,-2.98633 l 2.13477,-2.13476 c 1.27714,-1.27719 1.21033,-3.38733 -0.0547,-4.65235 -0.63251,-0.63254 -1.47713,-0.96507 -2.32227,-0.98047 z m -0.01,1.00391 c 0.59016,0.0124 1.18356,0.24213 1.625,0.68359 0.88286,0.88287 0.92532,2.36759 0.0547,3.23828 l -2.25,2.25 a 0.50004997,0.50004997 0 0 0 -0.14453,0.4043 c 0.11985,1.19116 0.0231,2.10252 -0.26172,2.79297 -0.28481,0.69045 -0.74712,1.18455 -1.47851,1.58008 -1.27506,0.68955 -3.50366,0.96361 -6.50586,1.02734 l 3.10352,-3.10351 c 0.19538,0.094 0.41106,0.15234 0.64062,0.15234 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.22956 0.0584,0.44524 0.15234,0.64062 l -3.10351,3.10352 c 0.0645,-3.00197 0.34215,-5.23052 1.0332,-6.50586 0.3964,-0.73154 0.8902,-1.19371 1.58008,-1.47851 0.68987,-0.28481 1.59959,-0.38153 2.78711,-0.26172 a 0.50004997,0.50004997 0 0 0 0.4043,-0.14453 l 2.25,-2.25 c 0.43534,-0.43536 1.02312,-0.64126 1.61328,-0.62891 z"
- id="path8087-0"
- inkscape:connector-curvature="0" />
<g
- id="g6603"
- style="fill:#ffffff">
+ id="g91501"
+ style="display:inline;enable-background:new"
+ inkscape:label="S-21">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 237.49219,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 306 h 3 v 12 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -1.5 v -12 h 3 v 1.5 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 7,6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 V 312 h 2 v 6 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -6 h 2 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path6924-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 429.50781,389 C 427.57283,389 426,390.57283 426,392.50781 v 6.98438 c 0,1.93498 1.57283,3.50781 3.50781,3.50781 h 6.98438 C 438.42717,403 440,401.42717 440,399.49219 v -6.98438 C 440,390.57283 438.42717,389 436.49219,389 Z m 0,1 h 6.98438 c 1.39828,0 2.50781,1.10953 2.50781,2.50781 v 6.98438 C 439,400.89047 437.89047,402 436.49219,402 h -6.98438 C 428.10953,402 427,400.89047 427,399.49219 v -6.98438 C 427,391.10953 428.10953,390 429.50781,390 Z"
+ id="rect14490"
inkscape:connector-curvature="0" />
</g>
- <path
- inkscape:connector-curvature="0"
- d="m 353,628 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m 9,-3 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z m -3,0 h 1 v 1 h -1 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path14337" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 374.4375,121.17773 c -0.55229,-0.19531 -1.19407,-0.23097 -1.84766,0.002 -0.65359,0.23293 -1.30733,0.71399 -1.9707,1.49609 -0.28137,0.33173 -0.45085,0.79694 -0.61914,1.24219 -0.17701,-0.45587 -0.36207,-0.94012 -0.61914,-1.24219 -0.66249,-0.77846 -1.31558,-1.25837 -1.96875,-1.49023 -0.65317,-0.23186 -1.2953,-0.19616 -1.84766,-0.002 -1.10471,0.38842 -1.89002,1.32506 -2.44922,1.9961 a 0.50064603,0.50064603 0 1 0 0.76954,0.64062 c 0.54481,-0.65377 1.26345,-1.43095 2.00976,-1.69336 0.37316,-0.1312 0.7444,-0.1559 1.18359,0 0.4392,0.1559 0.95757,0.51168 1.54102,1.19727 0.19894,0.23376 0.56603,0.91963 0.64063,1.27734 A 0.50005,0.50005 0 0 0 369.75,125 h 0.5 a 0.50005,0.50005 0 0 0 0.49023,-0.40234 c 0.0736,-0.37229 0.37785,-0.96363 0.64063,-1.27344 0.58467,-0.68931 1.10595,-1.04668 1.54492,-1.20313 0.43897,-0.15644 0.80714,-0.13175 1.17969,0 0.74509,0.2635 1.46354,1.04375 2.00976,1.69922 a 0.50064603,0.50064603 0 1 0 0.76954,-0.64062 c -0.55904,-0.67084 -1.34269,-1.61133 -2.44727,-2.00196 z"
- id="path17826-1"
- inkscape:connector-curvature="0" />
<g
+ transform="translate(-348,478)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14433"
- transform="rotate(-90,380.52904,134)">
+ id="g16413-1"
+ inkscape:label="S-20">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 390.04688,140.46484 a 0.50005,0.50005 0 0 0 -0.41797,0.20704 l -2.95508,3.93945 a 0.50005,0.50005 0 0 0 -0.01,0.70703 l 2.96485,3.95312 a 0.50019216,0.50019216 0 1 0 0.80078,-0.5996 l -2.40039,-3.20118 h 7.1914 l -0.63867,1.27735 a 0.50005635,0.50005635 0 1 0 0.89453,0.44726 l 0.96875,-1.93554 a 0.50005,0.50005 0 0 0 -0.006,-0.58399 l -0.96289,-1.92773 a 0.50005635,0.50005635 0 1 0 -0.89453,0.44726 l 0.63867,1.27539 h -7.1914 l 2.40039,-3.19922 a 0.50005,0.50005 0 0 0 -0.38281,-0.80664 z"
- id="path17796-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 759.5,-89 a 0.50005,0.50005 0 0 0 -0.41406,0.220703 l -5.75,8.5 a 0.50005,0.50005 0 0 0 -0.0254,0.04102 C 753.09798,-79.847634 753,-79.420118 753,-79 c 0,1.217423 0.89627,2.23231 2.16602,2.916016 C 756.43576,-75.400278 758.13235,-75 760,-75 c 1.86765,0 3.56424,-0.400278 4.83398,-1.083984 C 766.10373,-76.76769 767,-77.782577 767,-79 c 0,-0.419749 -0.0968,-0.847195 -0.3125,-1.240234 a 0.50005,0.50005 0 0 0 -0.0234,-0.03906 l -5.75,-8.5 A 0.50005,0.50005 0 0 0 760.5,-89 Z m 0.26562,1 h 0.46876 l 5.58007,8.248047 C 765.94193,-79.51674 766,-79.268361 766,-79 c 0,0.715577 -0.55782,1.452112 -1.64062,2.035156 C 763.27657,-76.3818 761.72215,-76 760,-76 c -1.72215,0 -3.27657,-0.3818 -4.35938,-0.964844 C 754.55782,-77.547888 754,-78.284423 754,-79 c 0,-0.262685 0.0617,-0.522361 0.1875,-0.755859 z"
+ id="path22956-5"
inkscape:connector-curvature="0" />
- </g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 348.5,120 c -1.47879,0 -2.81353,0.43206 -3.80469,1.06641 C 343.70416,121.70075 343,122.54357 343,123.5 c 0,1.02778 0.79097,1.88608 1.87891,2.49805 1.08228,0.60878 2.52394,0.99597 4.09765,1 0.0129,9.4e-4 3.75669,0.27336 6.02344,-2.21094 V 127.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4.25 a 0.50005,0.50005 0 1 0 0,1 h 3.10156 c -1.87731,2.16501 -5.32031,2 -5.32031,2 A 0.50005,0.50005 0 0 0 349,126 c -1.41667,0 -2.71684,-0.36001 -3.62891,-0.87305 C 344.45903,124.61392 344,123.97222 344,123.5 c 0,-0.41012 0.41561,-1.06779 1.23438,-1.5918 C 346.05313,121.38419 347.21846,121 348.5,121 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path18766-5"
- inkscape:connector-curvature="0" />
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g12950"
- transform="translate(-42.000002,4.4999696e-6)">
- <g
- id="g12531-9"
- transform="translate(-209.00718,-44.00717)"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 446.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452.4707 447.5 Z m 4.50718,10.00717 L 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z"
- id="path12529-5"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccc" />
- </g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 206.5,115.99219 c -1.39025,0 -2.5,1.19177 -2.5,2.61523 V 120.5 a 0.50004994,0.50004994 0 1 0 1,0 v -1.89258 c 0,-0.91233 0.68117,-1.61523 1.5,-1.61523 0.81884,0 1.5,0.70289 1.5,1.61523 V 120.5 a 0.50004994,0.50004994 0 1 0 1,0 v -1.89258 c 0,-1.42345 -1.10974,-2.61523 -2.5,-2.61523 z m -2.00781,9 A 0.50004994,0.50004994 0 0 0 204,125.5 v 1.88477 c 0,1.42346 1.10975,2.61523 2.5,2.61523 1.39026,0 2.5,-1.19178 2.5,-2.61523 V 125.5 a 0.50004994,0.50004994 0 1 0 -1,0 v 1.88477 c 0,0.91234 -0.68116,1.61523 -1.5,1.61523 -0.81883,0 -1.5,-0.7029 -1.5,-1.61523 V 125.5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.50781 z"
- transform="translate(42.000002,-4.4999696e-6)"
- id="path12537-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 760,-82 c -1.85842,0 -3.5402,0.34854 -4.79688,0.898438 -0.62833,0.274948 -1.15274,0.599804 -1.54296,0.982421 C 753.26993,-79.736524 753,-79.270893 753,-78.75 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.169742 0.0937,-0.393844 0.36133,-0.65625 0.26762,-0.262406 0.69425,-0.539532 1.24219,-0.779297 C 756.69939,-80.665077 758.26862,-81 760,-81 c 1.73138,0 3.30061,0.334923 4.39648,0.814453 0.54794,0.239765 0.97457,0.516891 1.24219,0.779297 C 765.90629,-79.143844 766,-78.919742 766,-78.75 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.520893 -0.26993,-0.986524 -0.66016,-1.369141 -0.39022,-0.382617 -0.91463,-0.707473 -1.54296,-0.982421 C 763.5402,-81.65146 761.85842,-82 760,-82 Z"
+ id="path23072-3"
inkscape:connector-curvature="0" />
</g>
<g
+ transform="translate(-327,478)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12957"
- transform="translate(-42.000002,4.4999696e-6)">
+ id="g16423-6"
+ inkscape:label="S-19">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 391,389 c -3.83836,-10e-6 -6.96097,3.10534 -6.99609,6.93555 A 0.50005,0.50005 0 0 0 384,396 c 0,3.86012 3.13988,7.00001 7,7 0.0171,0 0.0337,-0.002 0.0508,-0.002 a 0.50005,0.50005 0 0 0 0.01,-0.002 C 394.89256,402.96308 398,399.83968 398,396 c 0,-0.0171 -0.002,-0.0337 -0.002,-0.0508 a 0.50005,0.50005 0 0 0 -0.002,-0.01 c -0.0328,-3.81095 -3.12289,-6.90166 -6.93359,-6.93554 A 0.50005,0.50005 0 0 0 391,389 Z m 0,1 c 3.31968,0 6,2.68032 6,6 0,0.16955 -0.0858,0.36541 -0.34766,0.60352 -0.26184,0.2381 -0.68795,0.48634 -1.23632,0.69726 C 394.31926,397.72262 392.74298,398 391,398 c -0.65939,0 -1.28221,-0.0509 -1.87695,-0.12305 C 389.05085,397.28221 389,396.65939 389,396 c 0,-1.74298 0.27738,-3.31926 0.69922,-4.41602 0.21092,-0.54837 0.45916,-0.97448 0.69726,-1.23632 C 390.63459,390.08581 390.83045,390 391,390 Z m -1.76367,0.26367 c -0.17337,0.28719 -0.33274,0.60224 -0.47071,0.96094 C 388.28261,392.48043 388,394.15308 388,396 c 0,0.59486 0.0379,1.16229 0.0937,1.71289 -0.55897,-0.113 -1.07951,-0.24662 -1.50977,-0.41211 -0.54837,-0.21092 -0.97448,-0.45916 -1.23632,-0.69726 C 385.08581,396.36541 385,396.16955 385,396 c 0,-2.70567 1.78034,-4.98512 4.23633,-5.73633 z m -3.97266,7.5 c 0.28719,0.17337 0.60224,0.33274 0.96094,0.47071 0.58524,0.22509 1.26802,0.40153 2.00977,0.53124 0.12972,0.74174 0.30616,1.42453 0.53124,2.00977 0.13797,0.3587 0.29734,0.67375 0.47071,0.96094 -1.89863,-0.58074 -3.39192,-2.07402 -3.97266,-3.97266 z m 11.47266,0 C 395.98511,400.21966 393.70566,402 391,402 c -0.16955,0 -0.36541,-0.0858 -0.60352,-0.34766 -0.2381,-0.26184 -0.48634,-0.68795 -0.69726,-1.23632 -0.16549,-0.43026 -0.29911,-0.9508 -0.41211,-1.50977 0.5506,0.0559 1.11803,0.0937 1.71289,0.0937 1.84692,0 3.51957,-0.28262 4.77539,-0.76562 0.3587,-0.13797 0.67375,-0.29734 0.96094,-0.47071 z"
+ transform="translate(327,-478)"
+ id="path22958-5"
+ inkscape:connector-curvature="0" />
<g
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- transform="translate(-188.00718,-44.00717)"
- id="g12922">
+ transform="translate(327,-415)"
+ id="g23066-1"
+ style="display:inline;fill:#ffffff;enable-background:new">
<path
- id="path12920"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 451.00718,171.00717 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z M 446.5,161 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 1 0 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 a 0.50005,0.50005 0 1 0 0,-1 H 452.4707 447.5 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 391,330 c -1.84692,0 -3.51957,0.28261 -4.77539,0.76562 -0.62791,0.24151 -1.15478,0.53052 -1.55078,0.89063 C 384.27783,332.01636 384,332.47917 384,333 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.16955 0.0858,-0.36541 0.34766,-0.60352 0.26184,-0.2381 0.68795,-0.48634 1.23632,-0.69726 C 387.68074,331.27738 389.25702,331 391,331 c 1.74298,0 3.31926,0.27738 4.41602,0.69922 0.54837,0.21092 0.97448,0.45916 1.23632,0.69726 C 396.91419,332.63459 397,332.83045 397,333 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.52083 -0.27783,-0.98364 -0.67383,-1.34375 -0.396,-0.36011 -0.92287,-0.64912 -1.55078,-0.89063 C 394.51957,330.28261 392.84692,330 391,330 Z"
+ id="path23061-5"
inkscape:connector-curvature="0" />
</g>
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g22966-4-3"
+ transform="translate(-504,167.99288)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="S-18">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 366.5,389 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 363,392.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 377,399.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 h 8.58008 l -1.99414,2 h -8.58594 z M 376,390.70117 v 8.5918 l -2,2 v -8.58789 z M 364,393 h 9 v 9 h -9 z"
+ transform="translate(504,-167.99288)"
+ id="path22960-9-5"
+ inkscape:connector-curvature="0" />
<path
- id="path12942"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 269.5,120 c -1.40822,0 -2.5,1.26701 -2.5,2.75195 v 1.5 c 0,1.48181 1.09178,2.74805 2.5,2.74805 1.40823,0 2.5,-1.26624 2.5,-2.74805 v -0.32031 a 0.50004994,0.50004994 0 1 0 -1,0 v 0.32031 c 0,1.00094 -0.69911,1.74805 -1.5,1.74805 -0.80086,0 -1.5,-0.74712 -1.5,-1.74805 v -1.5 C 268,121.7464 268.69914,121 269.5,121 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,-4 c -1.40823,0 -2.5,1.26624 -2.5,2.74805 v 0.32031 a 0.50004994,0.50004994 0 1 0 1,0 v -0.32031 C 268,117.74711 268.69911,117 269.5,117 c 0.80086,0 1.5,0.74712 1.5,1.74805 v 1.5 C 271,121.2536 270.30086,122 269.5,122 a 0.50004994,0.50004994 0 1 0 0,1 c 1.40822,0 2.5,-1.26701 2.5,-2.75195 v -1.5 C 272,117.26624 270.90822,116 269.5,116 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 870.49219,220.99219 A 0.50005,0.50005 0 0 0 870,221.5 v 9.79297 l -2.85352,2.86133 a 0.50005,0.50005 0 1 0 0.70704,0.70508 L 870.70703,232 H 880.5 a 0.50005,0.50005 0 1 0 0,-1 H 871 v -9.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path23055-1-8"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 225.02539,389.05664 c -1.23014,0.0645 -2.42356,0.6345 -3.37891,1.58984 l -4,4 c -0.95534,0.95535 -1.53001,2.15146 -1.59765,3.38477 -0.0676,1.23331 0.38786,2.49571 1.41406,3.50977 1.02392,1.0118 2.28158,1.46686 3.51172,1.40234 1.23014,-0.0645 2.42356,-0.6345 3.37891,-1.58984 l 4,-4 c 0.95534,-0.95535 1.53001,-2.15146 1.59765,-3.38477 0.0676,-1.23331 -0.38786,-2.49571 -1.41406,-3.50977 -1.02392,-1.0118 -2.28158,-1.46686 -3.51172,-1.40234 z m 0.0527,0.99805 c 0.95617,-0.0502 1.91199,0.28134 2.75586,1.11523 0.8416,0.83164 1.17171,1.78562 1.11914,2.74414 -0.0526,0.95853 -0.50462,1.93041 -1.30664,2.73242 l -4,4 c -0.80201,0.80202 -1.76844,1.24868 -2.7246,1.29883 -0.95617,0.0502 -1.91199,-0.28134 -2.75586,-1.11523 -0.8416,-0.83164 -1.17171,-1.78562 -1.11914,-2.74414 0.0526,-0.95853 0.50462,-1.93041 1.30664,-2.73242 l 4,-4 c 0.80201,-0.80202 1.76844,-1.24868 2.7246,-1.29883 z"
- id="path14559-9"
- inkscape:connector-curvature="0" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13834"
- transform="rotate(90,244,438.00001)"
+ id="g12674"
+ transform="translate(-1.85367e-6,63)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- id="g13861"
- transform="rotate(-90,244.00797,459)"
- style="fill:#ffffff;stroke:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 258.99609,451.98828 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 260.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z m 5,0 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 265.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z m 5,0 a 1.0001,1.0001 0 0 0 -0.82031,1.56641 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 0 0 0,1.10938 l 1.63086,2.44531 -1.63086,2.44531 a 1.0001,1.0001 0 1 0 1.66406,1.10938 l 2,-3 a 1.0001,1.0001 0 0 0 0,-1.10938 L 270.20898,459 l 1.63086,-2.44531 a 1.0001,1.0001 0 0 0 0,-1.10938 l -2,-3 a 1.0001,1.0001 0 0 0 -0.84375,-0.45703 z"
- id="path13856"
- inkscape:connector-curvature="0" />
- </g>
- </g>
- <path
- id="path15447"
- d="m 539.5,10.000005 c -3.5682,0 -6.5,2.931819 -6.5,6.499999 0,1.42599 0.4737,2.74606 1.2637,3.822271 l -3.9707,3.9707 a 1.0001,1.0001 0 1 0 1.414,1.41406 l 3.9707,-3.9707 c 1.0762,0.78998 2.3963,1.26367 3.8223,1.26367 3.5682,0 6.5,-2.93182 6.5,-6.500001 0,-3.56818 -2.9318,-6.499999 -6.5,-6.499999 z m 0,2.999999 c 0.051,0 0.098,0.0135 0.1484,0.0156 a 0.50005,0.50005 0 0 1 0.3516,0.4844 v 2.5 h 2.5 a 0.50005,0.50005 0 0 1 0.4863,0.35742 0.50005,0.50005 0 0 1 0,0.002 c 0,0.0477 0.014,0.0925 0.014,0.14062 0,0.0488 -0.012,0.0942 -0.014,0.14258 A 0.50005,0.50005 0 0 1 542.5,17.000004 H 540 v 2.5 a 0.50005,0.50005 0 0 1 -0.3574,0.486331 c -0.048,0.002 -0.092,0.0137 -0.1406,0.0137 -0.049,0 -0.094,-0.0117 -0.1426,-0.0137 A 0.50005,0.50005 0 0 1 539,19.500004 v -2.5 h -2.5 a 0.50005,0.50005 0 0 1 -0.4863,-0.35742 0.50005,0.50005 0 0 1 0,-0.002 c 0,-0.0476 -0.014,-0.0925 -0.014,-0.14062 0,-0.0488 0.012,-0.0942 0.014,-0.14258 a 0.50005,0.50005 0 0 1 0.4863,-0.35738 h 2.5 v -2.5 a 0.50005,0.50005 0 0 1 0.3516,-0.48438 c 0.05,-0.002 0.098,-0.0156 0.1484,-0.0156 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647076;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 467.5,10.000005 a 0.50005006,0.50005006 0 0 0 -0.5,0.5 v 15 a 0.50005006,0.50005006 0 0 0 0.5,0.5 h 15 a 0.50005006,0.50005006 0 0 0 0.5,-0.5 v -15 a 0.50005006,0.50005006 0 0 0 -0.5,-0.5 z m 0.5,0.999999 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m -10,5 h 4 v 4.000001 h -4 z m 5,0 h 4 v 4.000001 h -4 z m 5,0 h 4 v 4.000001 h -4 z m -10,5.000001 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z"
- id="rect15343"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path15369"
- d="m 449.75,12.000004 a 0.50005006,0.50005006 0 0 0 -0.4824,0.36914 l -3.25,12.000001 a 0.50005006,0.50005006 0 0 0 0.4824,0.63086 h 15 a 0.50005006,0.50005006 0 0 0 0.4824,-0.63086 l -3.25,-12.000001 a 0.50005006,0.50005006 0 0 0 -0.4824,-0.36914 z m 0.3828,1 h 2.086 l -0.2169,2 h -2.4121 z m 3.0938,0 h 1.5468 l 0.2168,2 h -1.9804 z m 2.5547,0 h 2.0859 l 0.541,2 h -2.4101 z m -6.461,3 h 2.5723 l -0.3262,3 h -3.0586 z m 3.5801,0 h 2.1992 l 0.3262,3 h -2.8516 z m 3.207,0 h 2.5723 l 0.8125,3 h -3.0586 z m -7.8711,4.000001 h 3.2207 l -0.4336,4 h -3.8711 z m 4.2305,0 h 3.0664 l 0.4356,4 h -3.9375 z m 4.0762,0 h 3.2207 l 1.084,4 h -3.8711 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <g
- id="g14544"
- transform="translate(41.999998,84.000005)"
- style="display:inline;fill:#ffffff;enable-background:new">
+ inkscape:export-ydpi="96"
+ inkscape:label="S-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 142.16211,494.00195 c -0.3928,-0.016 -0.79264,0.0268 -1.18555,0.13086 -1.05738,0.28017 -1.9221,0.97933 -2.44336,1.89453 -2.51672,-0.22477 -4.91162,1.1516 -5.97656,3.44727 -1.07271,2.31243 -0.56559,5.05473 1.26367,6.83008 1.82926,1.77534 4.58788,2.20194 6.86719,1.06054 2.20676,-1.10505 3.49065,-3.45007 3.27539,-5.89257 0.59118,-0.33407 1.10512,-0.8107 1.46875,-1.41797 0.83525,-1.3949 0.74131,-3.16186 -0.23633,-4.46094 -0.73322,-0.97431 -1.8548,-1.54394 -3.0332,-1.5918 z m -0.041,1 c 0.88379,0.0353 1.72432,0.4611 2.27539,1.19336 0.73477,0.97635 0.80549,2.29734 0.17774,3.34571 -0.62775,1.04836 -1.82561,1.61054 -3.0332,1.42382 a 0.50005006,0.50005006 0 1 0 -0.15235,0.98828 c 0.54314,0.084 1.08325,0.0449 1.59571,-0.0859 0.0521,1.92511 -0.99653,3.7274 -2.7461,4.60351 -1.90239,0.95265 -4.19394,0.59896 -5.7207,-0.88281 -1.52677,-1.48177 -1.94806,-3.76137 -1.05274,-5.69141 0.84423,-1.81987 2.6839,-2.93301 4.66602,-2.88086 -0.0398,0.15646 -0.0768,0.3137 -0.0977,0.47657 a 0.50013931,0.50013931 0 0 0 0.99219,0.12695 c 0.15491,-1.21208 1.02585,-2.20656 2.20703,-2.51953 0.2953,-0.0782 0.59408,-0.10943 0.88867,-0.0977 z"
- transform="translate(-41.999998,-84.000005)"
- id="path14540"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.7;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m 343.50586,388.99219 a 0.50005,0.50005 0 0 0 -0.35547,0.14648 l -1.00391,1.00781 a 0.50005,0.50005 0 0 0 -0.0937,0.57618 l 3,6 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -2.83985,-5.67968 0.60547,-0.60547 h 6.4707 l 4.72266,10.39062 -0.60937,0.60938 -5.98633,0.008 -0.35743,-0.72656 a 0.50005,0.50005 0 1 0 -0.89648,0.4414 l 0.49414,1.00586 A 0.50005,0.50005 0 0 0 348,402 l 6.50586,-0.008 a 0.50005,0.50005 0 0 0 0.35352,-0.14649 l 1,-1 a 0.50005,0.50005 0 0 0 0.10156,-0.56054 l -5,-11 a 0.50005,0.50005 0 0 0 -0.45508,-0.29297 z m 5.5,6.00195 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0332,0.25977 l -0.14258,0.14257 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.14453,-0.14454 a 1,1 0 0 0 0.25781,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -2.50977,2.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70899,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
+ transform="translate(1.85367e-6,-63)"
+ id="circle12662"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 241.25,624 c -0.36727,2.9e-4 -0.60893,0.38318 -0.45117,0.71484 l 2.25,4.75 c 0.18125,0.37923 0.72109,0.37923 0.90234,0 l 2.25,-4.75 C 246.35893,624.38318 246.11727,624.00029 245.75,624 Z"
- id="path14837"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13609"
- transform="translate(-187,-89.999995)"
+ id="g12682"
+ transform="translate(-1.85367e-6,42)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="S-16">
<path
- style="fill:#ffffff;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
- d="M 9.5,578 C 7.96808,578 7,579.29203 7,580.5 v 9 c 0,1.20797 0.96808,2.5 2.5,2.5 h 9 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -9 C 8.53192,591 8,590.17765 8,589.5 8,588.82235 8.53192,588 9.5,588 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 4,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.18026 -0.86027,2.25 -2,2.44531 V 585 h -1 v -1.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 -0.83435,0 -1.5,0.66565 -1.5,1.5 v 0.5 h -1 v -0.5 c 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m -0.5,7 h 1 v 1 h -1 z m -3.5,3 a 0.50005,0.50005 0 1 0 0,1 h 9 a 0.50005,0.50005 0 1 0 0,-1 z"
- transform="translate(187,89.999995)"
- id="path13602"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 325.05469,389.00391 c -0.66782,-0.018 -1.21728,4.6e-4 -1.57813,0.002 h -0.002 c -0.34416,2.5e-4 -0.65424,0.0639 -0.91602,0.22852 -0.2623,0.16491 -0.44433,0.43888 -0.51367,0.7207 -0.13867,0.56363 0.037,1.13654 0.3125,1.76758 0.55094,1.26206 1.63318,2.77176 2.73438,4.10351 a 0.50004997,0.50004997 0 1 0 0.76953,-0.63867 c -1.06758,-1.2911 -2.11546,-2.78301 -2.58789,-3.86523 -0.23622,-0.54112 -0.29509,-0.9754 -0.25782,-1.12696 0.0186,-0.0758 0.0265,-0.0852 0.0742,-0.11523 0.0478,-0.03 0.16614,-0.0742 0.38672,-0.0742 a 0.50004997,0.50004997 0 0 0 0.002,0 c 1.54352,-0.006 5.58742,-0.20164 8.14453,2.35547 2.5571,2.5571 2.35972,6.59906 2.35351,8.14258 a 0.50004997,0.50004997 0 0 0 0,0.002 c 0,0.22058 -0.0442,0.33897 -0.0742,0.38672 -0.03,0.0477 -0.0375,0.0575 -0.11328,0.0762 -0.15155,0.0373 -0.58779,-0.0216 -1.1289,-0.25781 -1.08223,-0.47244 -2.57414,-1.52227 -3.86524,-2.58985 a 0.50015227,0.50015227 0 1 0 -0.63672,0.77149 c 1.33176,1.1012 2.8395,2.18343 4.10157,2.73437 0.63103,0.27547 1.20395,0.45117 1.76757,0.3125 0.28182,-0.0693 0.55774,-0.25136 0.72266,-0.51367 0.16426,-0.26126 0.22607,-0.57268 0.22656,-0.91601 v -0.004 c 0.006,-1.44452 0.29493,-5.9121 -2.64648,-8.85352 -2.20662,-2.20661 -5.27193,-2.59451 -7.27539,-2.64843 z m 3.95117,4.99023 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0332,0.25781 l -0.88672,0.88672 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 0.88671,-0.88672 a 1,1 0 0 0 0.25977,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -3.50977,3.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70899,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
+ transform="translate(1.85367e-6,-42)"
+ id="path7537-6"
inkscape:connector-curvature="0" />
</g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12687"
+ transform="translate(-1.85367e-6,42)"
inkscape:export-filename="blender_icons.png"
- id="g10909"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- transform="matrix(-1,0,0,1,1290,262.99979)">
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="S-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 968.5,168.00021 c 0.2761,3e-5 0.5,0.22387 0.5,0.5 v 13 c 0,0.27613 -0.2239,0.49997 -0.5,0.5 h -13 c -0.2761,-3e-5 -0.5,-0.22387 -0.5,-0.5 v -13 c 0,-0.27613 0.2239,-0.49997 0.5,-0.5 z m -10,2 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 4.97656,3 c -0.1708,0.008 -0.32545,0.10335 -0.41015,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.43359,0.74805 h 8 c 0.3836,-4.7e-4 0.62389,-0.41493 0.43359,-0.74805 l -4,-7 c -0.093,-0.16311 -0.26943,-0.26042 -0.45703,-0.25195 z"
- id="path10907"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 313.48633,389.00977 a 0.50005,0.50005 0 0 0 -0.13281,0.0156 l -10.64454,2.70117 a 0.50005,0.50005 0 0 0 -0.0176,0.006 c -0.39202,0.1157 -0.73529,0.32904 -1.00782,0.60156 -0.57977,0.57978 -0.79354,1.4303 -0.73828,2.33399 0.0553,0.90369 0.37679,1.88678 0.94141,2.83789 a 0.50005,0.50005 0 0 0 0,0.002 c 0.0547,0.092 0.11038,0.1837 0.16992,0.27539 a 0.50056694,0.50056694 0 1 0 0.83984,-0.54492 c -0.0521,-0.0802 -0.10227,-0.16121 -0.15039,-0.24219 -0.4939,-0.83198 -0.75942,-1.68043 -0.80273,-2.38867 -0.0433,-0.70823 0.13039,-1.24953 0.44726,-1.5664 0.16272,-0.16272 0.36207,-0.28412 0.58399,-0.34961 l 9.81055,-2.49024 -2.49024,9.81445 c -0.0654,0.2249 -0.18247,0.41294 -0.34961,0.58008 -0.32315,0.32316 -0.90925,0.49604 -1.67187,0.42578 -0.76263,-0.0702 -1.66859,-0.38268 -2.52735,-0.93164 a 0.50005,0.50005 0 1 0 -0.53906,0.8418 c 0.97998,0.62645 2.02029,0.99785 2.97656,1.08594 0.95627,0.0881 1.86106,-0.10716 2.46875,-0.71485 0.27194,-0.27193 0.4884,-0.61189 0.60352,-1.00781 a 0.50005,0.50005 0 0 0 0.004,-0.0176 l 2.70117,-10.64453 a 0.50005,0.50005 0 0 0 -0.47461,-0.62304 z M 308,393.99414 a 1,1 0 0 0 -1,1 1,1 0 0 0 0.0352,0.25586 l -0.88868,0.88867 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 0.88671,-0.88672 a 1,1 0 0 0 0.25977,0.0352 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z m -3.50977,3.99219 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 z m -3.00195,3 a 0.50005,0.50005 0 0 0 -0.3418,0.15234 l -1,1.00391 a 0.50005,0.50005 0 1 0 0.70704,0.70508 l 1,-1.00391 a 0.50005,0.50005 0 0 0 -0.36524,-0.85742 z"
+ transform="translate(1.85367e-6,-42)"
+ id="path7527-5"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 220.50391,17 c -0.19102,-0.0013 -0.36611,0.106306 -0.45118,0.277344 l -3,6 C 216.88757,23.609565 217.12899,23.99963 217.5,24 h 6 c 0.37101,-3.7e-4 0.61243,-0.390435 0.44727,-0.722656 l -3,-6 C 220.86345,17.108826 220.69211,17.001644 220.50391,17 Z"
- id="path13331-5"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g20257"
- transform="translate(171,5.7999696e-6)">
+ id="g12575"
+ transform="matrix(0.866667,0,0,0.866667,-253.074,16.4072)"
+ style="display:inline;fill:#ffffff;stroke-width:1.15385;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="S-14">
<path
- id="path20203"
- d="m -156.48438,137 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 v 0.5 h -1.5 c -0.32865,0.005 -0.51562,0.25232 -0.51562,0.5 v 0.5 h 2.51562 1 H -153 v -0.5 c 0,-0.25267 -0.14909,-0.49526 -0.48438,-0.5 h -1.5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 3.48438,2 0.0156,0.5 v 0.5 h -6 v -0.5 L -159,139 h -1.48438 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 v 3.5 h 2.3086 a 1.50015,1.50015 0 0 1 0.16211,-0.0137 1.50015,1.50015 0 0 1 1.52929,1.69726 V 149 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 285.49219,388.99219 c -0.2763,0.004 -0.49651,0.23152 -0.49219,0.50781 v 2.6543 c -0.76567,0.19832 -1.43883,0.61396 -1.95508,1.18359 l -2.1914,-2.19141 c -0.0944,-0.0966 -0.22433,-0.15264 -0.35938,-0.15234 -0.4485,2.4e-4 -0.66889,0.54638 -0.34766,0.85938 l 2.32032,2.32031 C 282.17933,394.72335 282.0013,395.33918 282,396 h -2.5 c -0.66693,0 -0.66693,1 0,1 h 2.64062 c 0.19916,0.76891 0.61811,1.44388 1.19141,1.96094 l -2.18555,2.18554 c -0.4717,0.4717 0.23534,1.17874 0.70704,0.70704 l 2.3164,-2.31641 c 0.54947,0.28561 1.16223,0.46289 1.82227,0.46289 0.003,0 0.005,10e-6 0.008,0 v 2.5 c 0,0.66693 1,0.66693 1,0 v -2.64648 c 0.76569,-0.20169 1.4388,-0.6203 1.95312,-1.19336 l 2.19336,2.19336 c 0.47143,0.50593 1.2141,-0.23683 0.70704,-0.70704 l -2.32422,-2.32421 c 0.28283,-0.54738 0.45703,-1.15786 0.45703,-1.81446 0,-0.003 0,-0.005 0,-0.008 H 292.5 c 0.66693,0 0.66693,-1 0,-1 h -2.66016 c -0.20083,-0.76245 -0.61615,-1.43374 -1.18554,-1.94727 l 2.19922,-2.19921 c 0.32695,-0.31816 0.0927,-0.87325 -0.36329,-0.85938 -0.12999,0.004 -0.25338,0.0589 -0.34375,0.15234 l -2.33007,2.33008 C 287.26914,392.1921 286.6571,392.01496 286,392.01367 V 389.5 c 0.004,-0.28226 -0.22555,-0.51222 -0.50781,-0.50781 z m 0.5,4.02148 c 1.65884,0 2.99414,1.3353 2.99414,2.99414 0,1.65885 -1.3353,2.99219 -2.99414,2.99219 C 284.33334,399 283,397.66666 283,396.00781 c 0,-1.65884 1.33334,-2.99414 2.99219,-2.99414 z"
+ transform="matrix(1.15385,0,0,1.15385,292.008,-18.9314)"
+ id="circle12556"
inkscape:connector-curvature="0" />
- <g
- id="g20226"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
- id="path20207"
- inkscape:connector-curvature="0" />
- </g>
</g>
<g
+ id="g19402"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g20243"
- transform="matrix(-1,0,0,1,-102.98438,5.7999696e-6)">
- <path
- id="path20230"
- transform="matrix(-1,0,0,1,-274.98438,0)"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -144.5,139 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 2 c 0.10658,-1e-5 0.20011,-0.0408 0.28125,-0.0977 l -3.3418,-3.34179 a 1.50015,1.50015 0 1 1 2.1211,-2.1211 L -135,144.87891 V 139.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.48438 L -137,139.5 v 0.5 h -6 v -0.5 l 0.0156,-0.5 z m 5,-2 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 0.5 h 1.5 c 0.32865,0.005 0.51562,0.25232 0.51562,0.5 v 0.5 h -2.51562 -1 -2.48438 v -0.5 c 0,-0.25267 0.14909,-0.49526 0.48438,-0.5 h 1.5 v -0.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 z"
- inkscape:connector-curvature="0" />
+ inkscape:label="S-13">
<g
- transform="rotate(180,-150.98485,147.5)"
- id="g20236"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-84,42)"
+ id="g19210">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
- id="path20234"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ d="m 348.48047,347 c -3.16361,0.009 -5.86504,2.31609 -6.39063,5.45117 -0.52558,3.13508 1.27477,6.20467 4.25977,7.25781 a 0.50005,0.50005 0 1 0 0.33203,-0.94336 c -2.52985,-0.89255 -4.05213,-3.48414 -3.60547,-6.14843 0.44666,-2.66429 2.72792,-4.6094 5.40821,-4.61719 2.68028,-0.008 4.97166,1.92234 5.43359,4.58398 0.46193,2.66165 -1.0456,5.26268 -3.57031,6.16993 a 0.50043111,0.50043111 0 1 0 0.33984,0.9414 c 2.9789,-1.07046 4.75841,-4.14926 4.21484,-7.28125 -0.54356,-3.13198 -3.25826,-5.42325 -6.42187,-5.41406 z m 0.0195,4.99999 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 v 0.59375 c -0.01,0.67616 1.00956,0.67616 1,0 v -0.59375 c 0.57902,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.67751,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -0.002,3.98438 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 c -0.01,0.67616 1.00957,0.67616 1,0 v -1 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z m 0,3 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1.00195 c -0.01,0.67616 1.00957,0.67616 1,0 v -1.00195 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="circle19208" />
</g>
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g20375"
- transform="matrix(-1,0,0,1,131,5.7999696e-6)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 48.492188,137 A 0.50005,0.50005 0 0 0 48,137.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,137 Z m 0,5 A 0.50005,0.50005 0 0 0 48,142.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,142 Z m 0,5 A 0.50005,0.50005 0 0 0 48,147.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,147 Z"
- id="path20369"
- inkscape:connector-curvature="0" />
+ id="g23051-0"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ transform="translate(210,21)"
+ inkscape:label="S-12">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 51.515625,137 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 V 138 H 50 v 1 h 1.515625 1 H 55 v -0.5 c 0,-0.25267 -0.149085,-0.49526 -0.484375,-0.5 h -1.5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z M 55,139 l 0.01563,0.5 V 140 H 50 v 9 h 6.515625 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -0.35938 l -2.580078,-2.58007 a 1.50015,1.50015 0 1 1 2.121094,-2.1211 l 0.458984,0.45899 V 139.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path20371"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 243.49219,389 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -3,3 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 L 243,390.70703 V 402 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 244 v -11.29297 l 2.14648,2.14649 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
+ transform="translate(-210,-21)"
+ id="path23043-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccc" />
+ </g>
+ <g
+ id="g91498"
+ style="display:inline;enable-background:new"
+ inkscape:label="S-11">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 55.490234,143.99414 a 0.50005,0.50005 0 0 0 -0.349609,0.85938 L 60.287109,150 h -2.792968 a 0.50005,0.50005 0 1 0 0,1 h 3.939453 a 0.50005,0.50005 0 0 0 0.560547,-0.57031 V 146.5 a 0.50005,0.50005 0 1 0 -1,0 v 2.79297 l -5.146485,-5.14649 a 0.50005,0.50005 0 0 0 -0.357422,-0.15234 z"
- id="path20373"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 225.02539,389.05664 c -1.23014,0.0645 -2.42356,0.6345 -3.37891,1.58984 l -4,4 c -0.95534,0.95535 -1.53001,2.15146 -1.59765,3.38477 -0.0676,1.23331 0.38786,2.49571 1.41406,3.50977 1.02392,1.0118 2.28158,1.46686 3.51172,1.40234 1.23014,-0.0645 2.42356,-0.6345 3.37891,-1.58984 l 4,-4 c 0.95534,-0.95535 1.53001,-2.15146 1.59765,-3.38477 0.0676,-1.23331 -0.38786,-2.49571 -1.41406,-3.50977 -1.02392,-1.0118 -2.28158,-1.46686 -3.51172,-1.40234 z m 0.0527,0.99805 c 0.95617,-0.0502 1.91199,0.28134 2.75586,1.11523 0.8416,0.83164 1.17171,1.78562 1.11914,2.74414 -0.0526,0.95853 -0.50462,1.93041 -1.30664,2.73242 l -4,4 c -0.80201,0.80202 -1.76844,1.24868 -2.7246,1.29883 -0.95617,0.0502 -1.91199,-0.28134 -2.75586,-1.11523 -0.8416,-0.83164 -1.17171,-1.78562 -1.11914,-2.74414 0.0526,-0.95853 0.50462,-1.93041 1.30664,-2.73242 l 4,-4 c 0.80201,-0.80202 1.76844,-1.24868 2.7246,-1.29883 z"
+ id="path14559-9"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g20474">
+ id="g91510"
+ style="display:inline;enable-background:new"
+ inkscape:label="S-10">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 48.492188,137 A 0.50005,0.50005 0 0 0 48,137.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,137 Z m 0,5 A 0.50005,0.50005 0 0 0 48,142.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,142 Z m 0,5 A 0.50005,0.50005 0 0 0 48,147.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,147 Z"
- id="path8290-6-5"
+ d="m 201.5,389 a 0.50005,0.50005 0 0 0 -0.41406,0.2207 l -5.75,8.5 a 0.50005,0.50005 0 0 0 -0.0254,0.041 C 195.09791,398.15241 195,398.57992 195,399 c 0,1.21742 0.89627,2.23231 2.16602,2.91602 C 198.43576,402.59972 200.13233,403 202,403 c 1.86767,0 3.56424,-0.40028 4.83398,-1.08398 C 208.10373,401.23231 209,400.21742 209,399 c 0,-0.41956 -0.0964,-0.84696 -0.3125,-1.24023 a 0.50005,0.50005 0 0 0 -0.0234,-0.0391 l -5.75,-8.5 A 0.50005,0.50005 0 0 0 202.5,389 Z m 0.26562,1 h 0.46876 l 5.58007,8.24805 C 207.94195,398.48303 208,398.73145 208,399 c 0,0.71558 -0.55783,1.45211 -1.64062,2.03516 C 205.27658,401.6182 203.72216,402 202,402 c -1.72216,0 -3.27658,-0.3818 -4.35938,-0.96484 C 196.55783,400.45211 196,399.71558 196,399 c 0,-0.26272 0.0617,-0.52241 0.1875,-0.75586 z"
+ id="path17361"
inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 51.509766,137 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 138 H 50 v 1 h 1.509766 1 2.515625 v -0.5 c 0,-0.24768 -0.186975,-0.495 -0.515625,-0.5 h -1.5 v -0.5 c -4e-5,-0.27613 -0.22388,-0.49997 -0.5,-0.5 z m 3.515625,2 -0.01563,0.5 V 140 H 50 v 9 h 4.009766 v -4.31641 c -0.12178,-0.91601 0.605587,-1.72326 1.529296,-1.69726 0.05424,0.002 0.10831,0.007 0.16211,0.0137 h 1.308594 v -3.5 c -4e-5,-0.27613 -0.22388,-0.49997 -0.5,-0.5 z"
- id="path20454"
- inkscape:connector-curvature="0" />
- <g
- transform="matrix(-1,0,0,1,-102.97428,1.2445863e-6)"
- id="g20458"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
- id="path20456"
- inkscape:connector-curvature="0" />
- </g>
</g>
<g
+ id="g6344"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g21550"
- transform="translate(-21.000002,189)">
+ inkscape:label="S-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 471.54297,473 -3,3 h 1.20703 8.20703 l 3,-3 z m 0.41406,1 h 6.58594 l -1,1 h -6.58594 z m 5.54297,3 -9.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 478,477.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,8.00781 h -8 v -8.00195 z"
- transform="translate(21.000002,-189)"
- id="path21430"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path17355-2"
+ d="m 181,390 c -2.19521,0 -4.16987,0.64081 -5.61914,1.70898 -1.44928,1.06818 -2.38087,2.59156 -2.38086,4.29102 0,1.69945 0.93159,3.22284 2.38086,4.29102 C 176.83013,401.35919 178.80479,402 181,402 c 2.19521,0 4.16987,-0.64081 5.61914,-1.70898 C 188.06841,399.22284 189,397.69945 189,396 c 0,-1.69945 -0.93159,-3.22284 -2.38086,-4.29102 C 185.16987,390.64081 183.19522,390 181,390 Z m 0,1 c 1.99941,0 3.77332,0.59085 5.02539,1.51367 C 187.27746,393.4365 188,394.66345 188,396 c 0,1.33655 -0.72254,2.5635 -1.97461,3.48633 C 184.77332,400.40915 182.99941,401 181,401 c -1.99941,0 -3.77332,-0.59085 -5.02539,-1.51367 C 174.72254,398.5635 174,397.33655 174,396 c 0,-1.33654 0.72254,-2.5635 1.97461,-3.48633 C 177.22668,391.59085 179.00059,391 181,391 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 503,285.04297 -0.85352,0.85351 L 500,288.04297 v 9.41406 l 3,-3 z"
- id="path21432"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccc" />
+ id="path17357"
+ d="M 178.49219,394.49219 A 0.50005,0.50005 0 0 0 178,395.00195 v 0.25 c 5.5e-4,0.26762 0.10104,0.43267 0.23438,0.61719 0.13369,0.18504 0.32089,0.36854 0.5664,0.53516 0.49103,0.33322 1.21831,0.59296 2.19727,0.5957 0.98079,0.003 1.71165,-0.25661 2.20312,-0.5918 0.24574,-0.16759 0.43113,-0.35326 0.56445,-0.53906 0.13296,-0.18529 0.23383,-0.34989 0.23438,-0.61719 v -0.002 -0.24805 a 0.50005,0.50005 0 1 0 -1,-0.004 v 0.2521 c 0,-0.11242 0.009,-0.0414 -0.0469,0.0371 -0.0564,0.0786 -0.16044,0.18856 -0.3164,0.29492 -0.31192,0.21273 -0.83026,0.42022 -1.63477,0.41797 -0.80517,-0.002 -1.32795,-0.21164 -1.64062,-0.42383 -0.15634,-0.10609 -0.26023,-0.21522 -0.31641,-0.29297 C 178.98874,395.20545 179,395.13726 179,395.25 v -0.25195 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(-243,336)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g21571">
+ id="g6336"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="S-8">
<path
inkscape:connector-curvature="0"
- id="rect21332"
- d="M 775.46875,284 C 774.66371,284 774,284.66371 774,285.46875 v 11.0625 c 0,0.80504 0.66371,1.46875 1.46875,1.46875 h 8.0625 C 784.33629,298 785,297.33629 785,296.53125 v -0.58203 c -1.68181,-0.24823 -3,-1.70468 -3,-3.44922 0,-1.74454 1.31819,-3.20099 3,-3.44922 v -3.58203 C 785,284.66371 784.33629,284 783.53125,284 Z M 775,285 h 9 v 3 h -9 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path17349-5"
+ d="m 156.49609,393.24609 a 0.50005,0.50005 0 0 0 -0.27343,0.91993 c 0.927,0.618 2.37713,0.83398 3.77734,0.83398 1.39708,0 2.84978,-0.21561 3.77734,-0.83398 a 0.50005,0.50005 0 1 0 -0.55468,-0.83204 C 162.65022,393.71561 161.2722,394 160,394 c -1.27563,0 -2.64966,-0.28402 -3.22266,-0.66602 a 0.50005,0.50005 0 0 0 -0.28125,-0.0879 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 785.5,295 c -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 z"
- id="circle21336"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="path17351"
+ d="m 160,389 c -1.5802,0 -3.01318,0.28529 -4.0957,0.77734 -0.54126,0.24603 -0.9977,0.54261 -1.33789,0.90821 C 154.22621,391.05115 154,391.5062 154,392 v 3 5 c 0,0.4938 0.22621,0.94885 0.56641,1.31445 0.34019,0.3656 0.79663,0.66218 1.33789,0.90821 C 156.98682,402.71471 158.4198,403 160,403 c 1.5802,0 3.01318,-0.28529 4.0957,-0.77734 0.54126,-0.24603 0.9977,-0.54261 1.33789,-0.90821 C 165.77379,400.94885 166,400.4938 166,400 v -5 -3 c 0,-0.4938 -0.22621,-0.94885 -0.56641,-1.31445 -0.34019,-0.3656 -0.79663,-0.66218 -1.33789,-0.90821 C 163.01318,389.28529 161.5802,389 160,389 Z m 0,1 c 1.45737,0 2.77356,0.27473 3.68164,0.6875 0.45404,0.20638 0.8031,0.4471 1.01953,0.67969 C 164.9176,391.59978 165,391.80344 165,392 v 3 5 c 0,0.19656 -0.0824,0.40022 -0.29883,0.63281 -0.21643,0.23259 -0.56549,0.47331 -1.01953,0.67969 C 162.77356,401.72527 161.45737,402 160,402 c -1.45737,0 -2.77356,-0.27473 -3.68164,-0.6875 -0.45404,-0.20638 -0.8031,-0.4471 -1.01953,-0.67969 C 155.0824,400.40022 155,400.19656 155,400 v -5 -3 c 0,-0.19656 0.0824,-0.40022 0.29883,-0.63281 0.21643,-0.23259 0.56549,-0.47331 1.01953,-0.67969 C 157.22644,390.27473 158.54263,390 160,390 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(-285,336)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g21575">
+ id="g6328"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="S-7">
<path
- sodipodi:nodetypes="sscssssccsssscccss"
inkscape:connector-curvature="0"
- id="rect21315-8"
- d="m 797,284 c -1.09935,0 -2,0.90065 -2,2 v 2 8 c 0,1.09935 0.90065,2 2,2 h 7 c 1.09935,0 2,-0.90065 2,-2 v -0.5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 0.5 c 0,0.56265 -0.43735,1 -1,1 h -7 c -0.56265,0 -1,-0.43735 -1,-1 v -8 h 10 v -2 c 0,-1.09935 -0.90065,-2 -2,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path12377-5"
+ d="m 135.5,389 a 0.50004997,0.50004997 0 0 0 -0.33008,0.12305 l -2,1.75 A 0.50004997,0.50004997 0 0 0 133,391.25 V 393 h -1.5 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 1.5 c 0,0.98611 0.74054,1.6889 1.56836,1.91992 0.71525,0.19961 1.51421,0.0482 2.18359,-0.38476 L 136,397.93945 V 400.25 c 0,0.88889 0.39419,1.61848 0.96875,2.07812 C 137.54331,402.78777 138.275,403 139,403 c 0.725,0 1.45669,-0.21223 2.03125,-0.67188 C 141.60581,401.86848 142,401.13889 142,400.25 v -2.31055 l 1.24805,-1.40429 c 0.66938,0.43298 1.46834,0.58437 2.18359,0.38476 C 146.25946,396.6889 147,395.98611 147,395 v -1.5 A 0.50004997,0.50004997 0 0 0 146.5,393 H 145 v -1.75 a 0.50004997,0.50004997 0 0 0 -0.16992,-0.37695 l -2,-1.75 A 0.50004997,0.50004997 0 0 0 142.5,389 h -2 a 0.50004997,0.50004997 0 0 0 -0.35352,0.14648 L 139.29297,390 h -0.58594 l -0.85351,-0.85352 A 0.50004997,0.50004997 0 0 0 137.5,389 Z m 0.1875,1 h 1.60547 l 0.85351,0.85352 A 0.50004997,0.50004997 0 0 0 138.5,391 h 1 a 0.50004997,0.50004997 0 0 0 0.35352,-0.14648 L 140.70703,390 h 1.60547 L 144,391.47852 V 393.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1.5 v 1 c 0,0.51389 -0.32196,0.8111 -0.83789,0.95508 -0.39408,0.10997 -0.8212,-0.0629 -1.20703,-0.25 a 0.50004997,0.50004997 0 0 0 -0.82813,-0.53711 l -2,2.25 A 0.50004997,0.50004997 0 0 0 141,397.75 v 2.5 c 0,0.61111 -0.23081,1.00652 -0.59375,1.29688 C 140.04331,401.83723 139.525,402 139,402 c -0.525,0 -1.04331,-0.16277 -1.40625,-0.45312 C 137.23081,401.25652 137,400.86111 137,400.25 v -2.5 a 0.50004997,0.50004997 0 0 0 -0.12695,-0.33203 l -2,-2.25 a 0.50004997,0.50004997 0 0 0 -0.82813,0.53711 c -0.38583,0.18707 -0.81295,0.35997 -1.20703,0.25 C 132.32196,395.8111 132,395.51389 132,395 v -1 h 1.5 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -2.02344 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 806.5,294 c -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 z"
- id="circle21317-8"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="path12383"
+ d="m 137,392 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.5,0.5 A 0.50005,0.50005 0 0 0 136,393 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.29297 L 137.20703,393 H 137.5 a 0.50005,0.50005 0 1 0 0,-1 z m 4,0 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.5,0.5 A 0.50005,0.50005 0 0 0 140,393 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.29297 L 141.20703,393 H 141.5 a 0.50005,0.50005 0 1 0 0,-1 z m -2.5,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
+ id="g6320-8"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14854"
- transform="translate(-70.000007,21.000006)">
+ inkscape:label="S-6">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 333.49219,94.992188 A 0.50005,0.50005 0 0 0 333,95.5 v 8.91016 l -4.68555,1.875 a 0.50050477,0.50050477 0 1 0 0.3711,0.92968 l 4.82812,-1.93164 7.82422,2.68946 a 0.50005,0.50005 0 1 0 0.32422,-0.94532 L 334,104.39258 V 95.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
- id="path14834"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="rect17377-5-5"
+ d="m 111.4668,389 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13.0957 a 0.50005,0.50005 0 0 0 0.5,0.5 H 124.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 389.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 H 124 v 12.0957 h -12.0332 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 335.50586,95.435547 c -0.27842,-0.0032 -0.50585,0.221565 -0.50586,0.5 v 6.884763 c -1.3e-4,0.21757 0.14044,0.41026 0.34766,0.47657 l 6,1.92968 c 0.32275,0.10319 0.65252,-0.13772 0.65234,-0.47656 v -6.884766 c 1.3e-4,-0.217571 -0.14044,-0.410257 -0.34766,-0.476562 l -6,-1.929688 c -0.0474,-0.01505 -0.0968,-0.02295 -0.14648,-0.02344 z"
- id="path14836"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccc" />
+ id="path17381-7"
+ d="M 115.49219,390.99219 A 0.50005,0.50005 0 0 0 115,391.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 399 h 4 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 399 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 121 v -4 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 121 v -1.5 a 0.50005,0.50005 0 1 0 -1,0 v 1.5 h -4 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 116,394 h 4 v 4 h -4 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
+ id="g6312"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="matrix(-1,0,0,1,551.0001,21.000006)"
- id="g14869">
+ inkscape:label="S-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 263.49219,94.992188 A 0.50005,0.50005 0 0 0 263,95.5 v 8.91016 l -4.68555,1.875 a 0.50050477,0.50050477 0 1 0 0.3711,0.92968 l 4.82812,-1.93164 7.82422,2.68946 a 0.50005,0.50005 0 1 0 0.32422,-0.94532 L 264,104.39258 V 95.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
- id="path14865"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path17390-7"
+ mask="none"
+ d="m 96,389 a 0.50005,0.50005 0 0 0 -0.240234,0.0605 l -5.5,3 A 0.50005,0.50005 0 0 0 90,392.5 v 7 a 0.50005,0.50005 0 0 0 0.259766,0.43945 l 5.5,3 A 0.50005,0.50005 0 0 0 96,403 h 1 a 0.50005,0.50005 0 0 0 0.240234,-0.0605 l 5.499996,-3 A 0.50005,0.50005 0 0 0 103,399.5 v -7 a 0.50005,0.50005 0 0 0 -0.25977,-0.43945 l -5.499996,-3 A 0.50005,0.50005 0 0 0 97,389 Z m 0.126953,1 h 0.746094 L 102,392.79688 v 6.40624 L 96.873047,402 H 96.126953 L 91,399.20312 v -6.40624 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 265.50586,95.435547 c -0.27842,-0.0032 -0.50585,0.221565 -0.50586,0.5 v 6.884763 c -1.3e-4,0.21757 0.14044,0.41026 0.34766,0.47657 l 6,1.92968 c 0.32275,0.10319 0.65252,-0.13772 0.65234,-0.47656 v -6.884766 c 1.3e-4,-0.217571 -0.14044,-0.410257 -0.34766,-0.476562 l -6,-1.929688 c -0.0474,-0.01505 -0.0968,-0.02295 -0.14648,-0.02344 z"
- id="path14867"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccc" />
+ id="path17400"
+ d="m 92.5,392 a 0.50005,0.50005 0 1 0 0,1 H 98.513672 100.5 a 0.50005,0.50005 0 1 0 0,-1 z m 6.013672,1 a 0.50005,0.50005 0 0 0 -0.404297,0.1875 l -3.595703,4.49609 -2.613281,-3.48437 a 0.50078095,0.50078095 0 1 0 -0.800782,0.60156 l 3,4 A 0.50005,0.50005 0 0 0 94.486328,399 a 0.50005,0.50005 0 0 0 0.404297,-0.1875 l 3.595703,-4.49609 2.613282,3.48437 a 0.50078015,0.50078015 0 1 0 0.80078,-0.60156 l -2.999999,-4 A 0.50005,0.50005 0 0 0 98.513672,393 Z m -4.027344,6 H 92.5 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(-6.3536743e-6,22.000006)"
+ id="g6304"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22568">
+ inkscape:label="S-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 307.51172,103 c -0.0577,-0.001 -0.11517,0.007 -0.16992,0.0254 l -6,2 c -0.45678,0.15155 -0.45678,0.79767 0,0.94922 l 6,2 c 0.10269,0.0343 0.21371,0.0343 0.3164,0 l 6,-2 c 0.45678,-0.15155 0.45678,-0.79767 0,-0.94922 l -6,-2 c -0.0473,-0.0157 -0.0967,-0.0243 -0.14648,-0.0254 z"
- id="path14873"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccc" />
+ id="path17418-8"
+ d="m 76,388.9375 c -3.894591,0 -7.0625,3.1679 -7.0625,7.0625 0,3.89459 3.167908,7.0625 7.0625,7.0625 3.894592,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.8946 -3.167909,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.354153,0 6.0625,2.70834 6.0625,6.0625 0,3.35415 -2.708348,6.0625 -6.0625,6.0625 -3.354152,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-3.35416 2.708347,-6.0625 6.0625,-6.0625 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 307.49219,93.992188 A 0.50005,0.50005 0 0 0 307,94.5 v 5.88867 l -5.6582,1.88672 a 0.50028181,0.50028181 0 1 0 0.3164,0.94922 l 5.8418,-1.94727 5.8418,1.94727 a 0.50028181,0.50028181 0 1 0 0.3164,-0.94922 L 308,100.38867 V 94.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
- id="path14875"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path17424"
+ d="m 75.476562,390.74414 a 0.50005,0.50005 0 0 0 -0.40039,0.24024 C 74.184416,392.40936 74,393.97991 74,396 c 0,0.33476 0.05553,0.60654 0.06836,0.92188 -1.166939,-0.0798 -2.112698,-0.42664 -3.201171,-1.52344 a 0.50005,0.50005 0 1 0 -0.710938,0.70312 c 1.257685,1.26731 2.545083,1.75219 3.986328,1.83008 0.125352,1.11893 0.352857,2.1649 0.933594,3.08594 a 0.50122772,0.50122772 0 1 0 0.847656,-0.53516 C 75.471077,399.76437 75.263567,398.92779 75.142578,398 H 76 c 2.575016,3.5e-4 3.847653,-0.61523 4.722656,-1.05273 a 0.50005,0.50005 0 1 0 -0.445312,-0.89454 C 79.402347,396.49023 78.424978,397.00033 76,397 H 75.072266 C 75.055487,396.65897 75,396.38014 75,396 c 0,-1.96025 0.172858,-3.28436 0.923828,-4.48438 a 0.50005,0.50005 0 0 0 -0.447266,-0.77148 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g20896"
- transform="translate(-189,63.000005)">
+ id="g91507"
+ style="display:inline;enable-background:new"
+ inkscape:label="S-3">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 161.50391,410 c -0.82054,0 -1.4961,0.67556 -1.4961,1.49609 0,0.82054 0.67556,1.4961 1.4961,1.4961 0.82053,0 1.49609,-0.67556 1.49609,-1.4961 C 163,410.67556 162.32444,410 161.50391,410 Z M 153.5,411 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 414 h 0.51562 2.49805 L 160,417.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97656,0.21094 0.67528,-3.15139 1.92341,-4.0882 3.51758,-5.42774 1.58398,1.34059 2.83152,2.27747 3.51953,5.42969 0.13318,0.66658 1.13543,0.44609 0.97656,-0.21484 -0.76273,-3.49457 -2.35104,-4.70351 -4.00195,-6.11719 L 161.01367,414 h 2.2168 3.28515 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04296 c -0.45945,0.59659 -1.17125,0.99219 -1.96875,0.99219 -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 H 157.51562 157 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
- transform="translate(189,-63.000005)"
- id="path20782"
+ d="m 55,389 c -3.86012,0 -7,3.13988 -7,7 0,3.86012 3.13988,7 7,7 3.86012,0 7,-3.13988 7,-7 0,-3.86012 -3.13988,-7 -7,-7 z m 0,1 c 3.31968,0 6,2.68032 6,6 0,3.31968 -2.68032,6 -6,6 -3.31968,0 -6,-2.68032 -6,-6 0,-3.31968 2.68032,-6 6,-6 z"
+ id="path17412"
inkscape:connector-curvature="0" />
- <g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(188,-63)"
- id="g20817"
- style="fill:#ffffff" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 285.49219,220.9707 a 0.50005,0.50005 0 0 0 -0.4336,0.29688 l -4,9 a 0.50005,0.50005 0 0 0 0.10352,0.55664 l 4,4 a 0.50005,0.50005 0 0 0 0.70703,0 l 4,-4 a 0.50005,0.50005 0 0 0 0.10352,-0.55664 l -4,-9 a 0.50005,0.50005 0 0 0 -0.48047,-0.29688 z m 0.0234,1.73047 3.4043,7.65821 -3.4043,3.40429 -3.40429,-3.40429 z"
- id="path20963"
- inkscape:connector-curvature="0" />
<g
+ id="g6296"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(-189,168)"
- id="g21028">
+ inkscape:label="S-2">
<path
inkscape:connector-curvature="0"
- id="path21020"
- d="m 342.5,348 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- sodipodi:nodetypes="ccccccccc" />
- <g
- id="g21026"
- transform="translate(188,-63)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96"
- style="fill:#ffffff">
- <path
- id="circle21024"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 162.50391,410 c -0.82054,0 -1.4961,0.67556 -1.4961,1.49609 0,0.82054 0.67556,1.4961 1.4961,1.4961 0.82053,0 1.49609,-0.67556 1.49609,-1.4961 C 164,410.67556 163.32444,410 162.50391,410 Z M 159.5,413 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.01562 0.49805 L 161,417.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97656,0.21094 0.67528,-3.15139 1.92341,-4.0882 3.51758,-5.42774 1.58398,1.34059 2.83152,2.27747 3.51953,5.42969 0.13318,0.66658 1.13543,0.44609 0.97656,-0.21484 -0.76273,-3.49457 -2.35104,-4.70351 -4.00195,-6.11719 L 162.01367,414 h 2.2168 3.28515 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04296 c -0.45945,0.59659 -1.17125,0.99219 -1.96875,0.99219 -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 h -0.0195 z"
- inkscape:connector-curvature="0" />
- </g>
+ id="path8006-3-4"
+ d="m 30.5,389 a 0.50005,0.50005 0 0 0 -0.353516,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 27,392.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 41,399.5 v -10 A 0.50005,0.50005 0 0 0 40.5,389 Z m 0.207031,1 H 40 v 9.29297 L 37.292969,402 H 28 v -9.29297 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8009-8"
+ d="m 39.490234,389.98828 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 L 37.292969,392 H 29.5 a 0.50005,0.50005 0 1 0 0,1 H 37 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -7.79297 l 1.853516,-1.86133 a 0.50005,0.50005 0 0 0 -0.363282,-0.85742 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(-84.000002,-62.999995)"
- id="g21409">
+ id="g91504"
+ style="display:inline;enable-background:new"
+ inkscape:label="S-1">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 269.13867,410.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -8.5,8.5 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 l 8.5,-8.5 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -1.88867,2.42383 2.29297,2.29297 -7.29883,7.29883 -3.05859,0.76562 0.76562,-3.05859 z"
- transform="translate(84.000002,62.999995)"
- id="path21405"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccsccccccccc" />
+ d="M 6.5,389 A 0.50005,0.50005 0 0 0 6,389.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 19.5,389 Z m 0.5,1 h 12 v 12 H 7 Z"
+ id="rect17430"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(-21.000001)"
- id="g12839">
+ id="g98816"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-26"
+ transform="translate(-0.35799351,-0.56441723)">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 353.13867,473.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -0.75,0.75 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.75,-0.75 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -3.39644,2.7168 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -6.25,6.25 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 l 6.25,-6.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22605,-0.14856 -0.36137,-0.14648 z"
- id="path12837"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccscccccccccccccccc" />
+ id="path9260-6"
+ style="display:inline;enable-background:accumulate;color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto"
+ d="m 542,379.49414 c 0,0.27842 -0.2216,0.50585 -0.5,0.50586 h -7 c -0.4051,6.1e-4 -0.6427,-0.45544 -0.4102,-0.78711 l 3.5,-5 c 0.199,-0.28542 0.6214,-0.28542 0.8204,0 l 3.5,5 c 0.058,0.0826 0.089,0.1806 0.09,0.28125 z M 542,373 h -8 v -2 h 8 z"
+ sodipodi:nodetypes="cccccccccccccc"
+ transform="translate(0.35799351,0.56441723)" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g14495"
- transform="matrix(-1,0,0,1,718.99999,4.4999696e-6)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 363.49414,141.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 7.15235,7.15234 H 367.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.006,0 0.50005,0.50005 0 0 0 0.0937,-0.0117 0.50005,0.50005 0 0 0 0.0488,-0.0117 0.50005,0.50005 0 0 0 0.3515,-0.54301 v -3.93359 a 0.50005,0.50005 0 1 0 -1,0 v 2.78711 l -7.14648,-7.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path14485"
- inkscape:connector-curvature="0" />
+ id="g98819"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-25">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 368.49414,137 a 0.50005,0.50005 0 0 0 -0.0937,0.01 0.50005,0.50005 0 0 0 -0.0488,0.0117 A 0.50005,0.50005 0 0 0 368,137.56445 V 141.5 a 0.50005,0.50005 0 1 0 1,0 v -2.78711 l 7.14648,7.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 369.70117,138 H 372.5 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 0 0 -0.006,0 z"
- id="path14491"
+ sodipodi:nodetypes="cccccccccccccc"
+ d="m 520.49414,371 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z M 514,371 v 8 h -2 v -8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9264"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g19653"
- transform="translate(-627.99987,42.000005)">
+ id="g98813"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 143.13867,515.0332 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -1.75,1.75 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.75,-1.75 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -4.39648,3.7168 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -0.25,0.25 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 0 0 0.70704,0 l 0.25,-0.25 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 138.74219,518.75 Z m -1.25196,2.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4.25,4.25 c -0.83838,0.83839 -1.06879,1.7573 -0.80273,2.4668 C 132.35981,528.57278 133.04167,529 133.75,529 H 138 c 1.00042,0 2,-0.79793 2,-2 v -3.5 a 0.50005,0.50005 0 1 0 -1,0 v 3.5 c 0,0.66505 -0.50442,1 -1,1 h -4.25 c -0.29167,0 -0.60981,-0.19778 -0.71875,-0.48828 -0.10894,-0.2905 -0.0893,-0.74659 0.57227,-1.4082 l 4.25,-4.25 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
- transform="translate(628,-42.000005)"
- id="path19637"
+ sodipodi:nodetypes="cccccccccccccc"
+ d="m 500,371.50586 c 0,-0.27842 -0.2216,-0.50585 -0.5,-0.50586 h -7 c -0.4051,-6.1e-4 -0.6427,0.45544 -0.4102,0.78711 l 3.5,5 c 0.199,0.28542 0.6214,0.28542 0.8204,0 l 3.5,-5 c 0.058,-0.0826 0.089,-0.1806 0.09,-0.28125 z M 500,378 h -8 v 2 h 8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9258"
inkscape:connector-curvature="0" />
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(418)"
- id="g19647" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path20483"
- d="m 75.999998,620 c -3.860077,0 -7,3.13991 -7,7 0,3.86009 3.139924,7 7,7 3.860076,0 7,-3.13991 7,-7 0,-3.86009 -3.139923,-7 -7,-7 z m 2.990234,2.98633 a 1.0001,1.0001 0 0 1 0.716797,1.7207 L 77.41406,627 l 2.292969,2.29297 a 1.0001,1.0001 0 1 1 -1.414062,1.41406 l -2.292969,-2.29297 -2.292969,2.29297 a 1.0001,1.0001 0 1 1 -1.414062,-1.41406 L 74.585936,627 72.292967,624.70703 a 1.0001,1.0001 0 0 1 0.697265,-1.7168 1.0001,1.0001 0 0 1 0.716797,0.30274 l 2.292969,2.29297 2.292969,-2.29297 a 1.0001,1.0001 0 0 1 0.697265,-0.30664 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- transform="translate(-1.8536743e-6,3.4999696e-6)"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g20495"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <g
- transform="translate(-189,588)"
- id="g20491"
- style="fill:#ffffff" />
+ id="g98810"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-23">
<path
- id="path20493"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 34,622 c -1.783333,0 -3,1.5 -3,3 h 2 c 0,-0.5 0.283333,-1 1,-1 0.716667,0 1,0.5 1,1 0,0.24702 -0.03644,0.30082 -0.117188,0.41016 -0.08074,0.10934 -0.253932,0.25966 -0.513671,0.4707 C 33.849662,626.30294 33,627.16667 33,628.5 v 0.5 h 2 v -0.5 c 0,-0.66667 0.150338,-0.67794 0.630859,-1.06836 0.240261,-0.19521 0.567072,-0.43551 0.861329,-0.83398 C 36.786444,626.19918 37,625.62798 37,625 c 0,-1.5 -1.216667,-3 -3,-3 z m -1,8.00009 h 2 v 2 H 33 Z M 34,620 c -3.86007,0 -7,3.13991 -7,7 0,3.86009 3.13993,7 7,7 3.86008,0 7,-3.13991 7,-7 0,-3.86009 -3.13992,-7 -7,-7 z m 0,1 c 3.31964,0 6,2.68035 6,6 0,3.31965 -2.68036,6 -6,6 -3.31963,0 -6,-2.68035 -6,-6 0,-3.31965 2.68037,-6 6,-6 z"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path27544-8"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 471.50586,371 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z M 478,371 v 8 h 2 v -8 z"
+ sodipodi:nodetypes="cccccccccccccc" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 55.011717,620 c -0.689946,-0.004 -1.325726,0.38513 -1.634766,1.00195 l -5.1875,10.3711 c -0.594248,1.18749 0.293094,2.62623 1.621094,2.62695 h 10.378906 c 1.327265,-7.2e-4 2.213373,-1.43788 1.621094,-2.625 l -5.1875,-10.37305 C 56.317741,620.39258 55.693326,620.0046 55.011717,620 Z m -1.011719,3 h 2 v 6 h -2 z m 0,7 h 2 v 2 h -2 z"
- id="path20558"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g20538"
- transform="rotate(-180,317.50525,417)">
+ id="g98798"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-22">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 331.50586,410 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path20529"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 449.50391,369 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 455 c 1.08333,0 2.07323,-0.26796 2.8125,-0.85938 C 458.55177,379.54921 459,378.625 459,377.5 c 0,-1.125 -0.44823,-2.04921 -1.1875,-2.64062 -0.49098,-0.39279 -1.11527,-0.59695 -1.78125,-0.72071 C 456.61178,373.63193 457,372.89881 457,372 c 0,-0.96354 -0.41934,-1.76349 -1.07422,-2.26758 C 455.27091,369.22833 454.41324,369 453.5,369 Z m 0.5,1 H 453.5 c 0.74361,0 1.38549,0.19369 1.81641,0.52539 0.43091,0.3317 0.68359,0.7813 0.68359,1.47461 0,0.69331 -0.25268,1.14291 -0.68359,1.47461 C 454.88549,373.80631 454.24361,374 453.5,374 h -3.49609 z m 0,5 h 3.46093 0.0352 1.5 c 0.91667,0 1.67677,0.23204 2.1875,0.64062 0.51073,0.40859 0.8125,0.98438 0.8125,1.85938 0,0.875 -0.30177,1.45079 -0.8125,1.85938 C 456.67677,379.76796 455.91667,380 455,380 h -4.99609 z"
+ id="path10949-7"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 323.95117,412.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 C 329.94786,421.40861 333,419.08206 333,416 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 c 0,2.41794 -2.42686,4.35855 -5.44141,4.00391 -1.98998,-0.23412 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 C 326.73975,422.63463 325.92671,423 325,423 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 1.17529,0 2.25213,-0.41841 2.88477,-1.18164 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z"
- id="path20536"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ccccscsccscsccscscscccccscscscc" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 331,410 c -2.22355,0 -4.0767,1.3002 -5.12305,3.18945 0.93682,-0.21724 1.92473,-0.28964 2.92578,-0.17187 0.40221,0.0473 0.78928,0.12403 1.16797,0.21484 C 330.29795,413.09146 330.64197,413 331,413 h 0.5 c 2.02848,0.0287 2.02848,-3.02869 0,-3 z m -3.05859,3.95898 c -3.69856,-0.0756 -6.93164,2.52898 -6.93164,6.04102 v 1.5 c -0.0287,2.02848 3.02869,2.02848 3,0 V 420 c 0,-1.75382 1.80351,-3.30654 4.32617,-3.00977 0.37314,0.0439 0.71883,0.11732 1.03711,0.21485 1.3077,0.40071 2.14372,1.21003 2.47656,1.91211 0.22905,0.48316 0.34095,1.19341 -0.0996,1.63281 -0.4946,0.4933 -1.25,0.34848 -1.89258,-0.0527 -0.70436,-0.44 -1.43726,-1.36047 -1.75195,-2.71875 -0.21041,-0.0194 -0.41646,-0.0328 -0.60742,-0.0234 -1.06865,0.0527 -1.81638,0.53365 -2.19727,1.13086 0.52848,1.85114 1.6077,3.30531 2.9668,4.15429 1.61509,1.00892 3.82413,1.05951 5.33594,-0.2539 0.0754,-0.0514 0.14605,-0.10959 0.21093,-0.17383 0.0562,-0.057 0.10785,-0.11837 0.1543,-0.18359 1.19162,-1.34198 1.31147,-3.2788 0.5918,-4.79688 -0.75194,-1.58612 -2.28118,-2.87289 -4.3086,-3.49414 -0.49344,-0.15121 -1.01745,-0.26354 -1.5664,-0.32812 -0.2499,-0.0294 -0.49757,-0.0457 -0.74414,-0.0508 z"
- id="path20562"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="scccsccscsccsccccccccccccccccc" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g20665">
+ id="g98804"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-21">
<path
- id="path20610"
- d="m 348.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 C 343.03811,413.14537 342,418.71429 342,422.5 a 1.50015,1.50015 0 1 0 3,0 c 0,-0.89832 0.0865,-1.89371 0.26758,-2.9043 -0.25845,-3.40076 0.85029,-7.04233 3.87109,-9.4707 a 1.50015,1.50015 0 0 0 -0.625,-0.13672 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 431.51758,369.26562 C 429.42795,369.91461 428,371.85293 428,374.04102 V 376 c 0,1.78552 0.9537,3.43731 2.5,4.33008 1.54631,0.89277 3.45369,0.89277 5,0 1.5463,-0.89277 2.5,-2.54456 2.5,-4.33008 v -0.5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -4 a 0.50004997,0.50004997 0 1 0 0,1 h 3.5 c 0,1.42986 -0.7617,2.74991 -2,3.46484 -1.23829,0.71494 -2.76171,0.71494 -4,0 -1.2383,-0.71493 -2,-2.03498 -2,-3.46484 v -1.95898 c 0,-1.75422 1.13918,-3.30002 2.81445,-3.82032 1.69498,-0.52641 3.36746,-0.003 4.25196,1.5293 a 0.50050004,0.50050004 0 1 0 0.86718,-0.5 c -1.1155,-1.93212 -3.34609,-2.62724 -5.41601,-1.98438 z"
+ id="path13141"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g98801"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-20">
<path
- id="path20608"
- d="m 351.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 c -4.71461,2.94662 -5.33528,8.77693 -3.58399,12.86328 a 1.5005399,1.5005399 0 1 0 2.75782,-1.1836 c -0.38431,-0.89672 -0.59027,-1.91481 -0.62891,-2.95117 -0.67215,-3.14692 0.29131,-6.6121 2.9043,-8.82422 a 1.50015,1.50015 0 0 0 -0.64063,-0.14453 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 408.50391,369 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5.91992 a 0.50005,0.50005 0 0 0 0,0.16211 V 380.5 a 0.50005,0.50005 0 1 0 1,0 V 376 h 3.25586 l 3.84961,4.8125 a 0.50024018,0.50024018 0 1 0 0.78124,-0.625 l -3.49414,-4.36914 c 1.48603,-0.40423 2.60743,-1.70768 2.60743,-3.31836 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0.5,1 h 3.5 c 1.38662,0 2.5,1.11337 2.5,2.5 0,1.38663 -1.11338,2.5 -2.5,2.5 a 0.50005,0.50005 0 0 0 -0.004,0 h -3.49609 z"
+ id="path13132"
inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path20592"
- d="m 354.51367,409.98828 a 1.50015,1.50015 0 0 0 -0.80859,0.24024 c -4.9147,3.07168 -4.9147,10.47128 0,13.54296 a 1.50015,1.50015 0 1 0 1.58984,-2.54296 c -3.0853,-1.92832 -3.0853,-6.52872 0,-8.45704 a 1.50015,1.50015 0 0 0 -0.78125,-2.7832 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
+ transform="translate(-104.994,85.0365)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22444"
- transform="translate(-1.8536743e-6,-41.999995)">
+ id="g19021-7-6"
+ inkscape:label="R-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 292.5,305 -9.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.50781 l 0.0391,2.49219 1,-0.0156 -0.0312,-1.98438 8,-0.008 -0.006,8.01172 -2,0.0195 0.01,1 2.49414,-0.0234 a 0.50005,0.50005 0 0 0 0.49414,-0.5 L 293,305.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path22408"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.7;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 448.5,284 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -10,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -10,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z"
+ id="ellipse19010-6-5"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g19186-9-4"
+ transform="translate(-146.994,85.0365)"
+ inkscape:label="R-16">
<path
- id="path22122"
- d="m 279,309 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m 0,2 h -2 v 2 h 2 z m 0,2 v 2 h 2 v -2 z m -2,0 h -2 v 2 h 2 z m -2,0 v -2 h -2 v 2 z m -2,0 h -2 v 2 h 2 z m 0,-2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 327.49805,368.03711 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -7,7 a 0.50005,0.50005 0 0 0 0,0.70703 l 7,7 a 0.50005,0.50005 0 0 0 0.70704,0 l 7.03124,-7 a 0.50005,0.50005 0 0 0 0,-0.70703 l -7.03124,-7 a 0.50005,0.50005 0 0 0 -0.36133,-0.14648 z m 0.008,1.20703 6.32226,6.29297 -6.32226,6.29297 -6.29297,-6.29297 z m 0,4.79297 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
+ transform="translate(146.994,-85.0365)"
+ id="path19093-9-7"
inkscape:connector-curvature="0" />
</g>
<g
+ id="g6286"
style="display:inline;fill:#ffffff;enable-background:new"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(422.00881,-131.00682)"
- id="g22132">
+ inkscape:label="R-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -76.509766,394.00586 a 0.50005,0.50005 0 0 0 -0.486328,0.38867 l -3.011718,12.98828 a 0.50005,0.50005 0 0 0 0.486328,0.61328 h 9.974609 a 0.50005,0.50005 0 0 0 0.488281,-0.38476 l 3.03711,-12.99024 a 0.50005,0.50005 0 0 0 -0.488282,-0.61523 z m 0.398438,1 h 3.974609 l -1.154297,5 h -3.978515 z m 5,0 h 3.972656 l -1.169922,5 h -3.955078 z m -6.390625,6 h 3.980469 l -1.382813,5.99023 h -3.986328 z m 5.005859,0 h 3.953125 l -1.40039,5.99023 h -3.933594 z"
- id="path22130"
+ d="m 303.5,369 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 300,372.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 313,378.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 312 v 8.29297 L 309.29297,381 H 301 v -8.29297 z m 1.79883,5.03711 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.8225 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21793 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path19061-0-7-6"
inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8009-8-5-8-9-1-5"
+ d="M 312.14648,369.14648 309.29297,372 H 300.5 v 1 h 8.5 l 0.006,8.53711 h 1 l -0.006,-8.83008 2.85352,-2.85351 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(-231,-83.999995)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g26345">
+ id="g98792"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-14">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 292.49023,367.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -10,10 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 10,-10 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ id="path14294"
+ inkscape:connector-curvature="0" />
<g
- id="g22592"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 300.5,326 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
- id="path22548"
- inkscape:connector-curvature="0" />
+ id="g98795"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 307.49219,326.99219 A 0.50005,0.50005 0 0 0 307,327.5 v 5.5 h -5.5 a 0.50005,0.50005 0 1 0 0,1 h 5.5 v 2 h -5.5 a 0.50005,0.50005 0 1 0 0,1 h 5.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 337 h 2 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 337 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 311 v -2 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 311 v -5.5 a 0.50005,0.50005 0 1 0 -1,0 v 5.5 h -2 v -5.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 308,334 h 2 v 2 h -2 z"
- id="path22585"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 289.5,368 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -5,5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -5,5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path13250"
inkscape:connector-curvature="0" />
</g>
</g>
<g
- transform="translate(-168.00001,-20.999988)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g26390">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14406"
+ transform="translate(-1.85367e-6,42)"
+ inkscape:label="R-13">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 74.492188,262.99219 a 0.50005,0.50005 0 0 0 -0.09961,0.0117 l -4.90039,0.004 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 5 a 0.50005,0.50005 0 1 0 1,0 V 269 H 74.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4.49805 L 79.5,264 a 0.50005,0.50005 0 1 0 0,-1 l -4.892578,0.004 a 0.50005,0.50005 0 0 0 -0.115234,-0.0117 z M 74,264.00391 V 268 h -4.007812 v -3.99414 z"
- transform="translate(168.00001,20.999988)"
- id="path23021"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 258.49805,325.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z m -11.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
+ id="path14443"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 250.48438,284 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -13.00781,13.00782 a 0.50005,0.50005 0 0 0 0.35352,0.85351 L 250.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 250.48438,284 Z M 250,285.70703 V 297 l -11.30078,0.008 z"
- id="path23044"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265,328 c -2.75536,0 -5,2.24449 -5,5 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.75551 -2.24464,-5 -5,-5 z m 0,1 c 2.21488,0 4,1.78488 4,4 0,2.21512 -1.78512,4 -4,4 -2.21488,0 -4,-1.78488 -4,-4 0,-2.21512 1.78512,-4 4,-4 z"
+ id="ellipse14445"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-2.8536743e-6,-20.999996)"
- id="g22228"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 225.5,286 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6.5 h -6.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 l -0.008,4.00586 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 229.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 10 l -10.00781,0.008 0.006,-3.00781 H 225.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z"
- id="path22226"
- inkscape:connector-curvature="0" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14414"
+ transform="translate(-1.85367e-6,42)"
+ inkscape:label="R-12">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 222.5,284 a 0.50005,0.50005 0 0 1 0.5,0.5 v 6 a 0.50005,0.50005 0 0 1 -0.5,0.5 h -6 a 0.50005,0.50005 0 0 1 -0.5,-0.5 v -6 a 0.50005,0.50005 0 0 1 0.5,-0.5 z m -0.5,1 h -5 v 5 h 5 z"
- id="rect22230"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 250.05859,327.01172 c -2.15963,0 -4.15811,1.13935 -5.24023,2.99219 -1.08212,1.85283 -1.08212,4.1413 0,5.99414 1.08212,1.85284 3.0806,2.99218 5.24023,2.99218 l 0.43164,0.01 a 0.50009544,0.50009544 0 1 0 0.0195,-1 l -0.44141,-0.01 a 0.50004985,0.50004985 0 0 0 -0.01,0 c -1.80804,0 -3.47523,-0.95213 -4.37695,-2.49609 -0.90172,-1.54396 -0.90172,-3.44041 0,-4.98437 0.90107,-1.54285 2.56651,-2.49668 4.37305,-2.49805 l 0.4375,0.004 a 0.50004985,0.50004985 0 1 0 0.008,-1 l -0.4375,-0.004 a 0.50004985,0.50004985 0 0 0 -0.004,0 z"
+ id="ellipse14411"
inkscape:connector-curvature="0" />
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g13459">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 237.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 H 238 v 8 h -0.50195 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 381 H 245 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -5.00195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 H 239 v -8 h 0.49805 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 245 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -5.00195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,11 h 1 v 1 h -1 z"
+ transform="translate(1.85367e-6,-42)"
+ id="path14415"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 327.41406,263 a 0.50005,0.50005 0 1 0 0,1 h 1.17969 c 1.54365,0 2.90268,0.42079 3.85937,1.21484 0.9567,0.79406 1.54688,1.95474 1.54688,3.60352 0,1.90166 -0.93943,3.66928 -2.68164,4.99414 -1.74221,1.32486 -4.29199,2.1875 -7.44922,2.1875 h -2.36133 a 0.50005,0.50005 0 1 0 0,1 h 2.36133 c 3.33916,0 6.10577,-0.91054 8.05469,-2.39258 1.94891,-1.48204 3.07617,-3.55426 3.07617,-5.78906 0,-1.89677 -0.72902,-3.39433 -1.9082,-4.37305 C 331.91261,263.46659 330.31821,263 328.59375,263 Z"
- id="path22657"
- inkscape:connector-curvature="0" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22284"
- transform="translate(-1.8536743e-6,-41.999995)">
+ id="g14422"
+ transform="translate(-1.85367e-6,42)"
+ inkscape:label="R-11">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 54.75,284 a 0.50004997,0.50004997 0 0 0 -0.431641,0.24805 l -3.646484,6.25 a 0.50004997,0.50004997 0 0 0 -0.002,0.002 c -1.211575,2.0985 -0.741006,4.77251 1.115234,6.33008 1.856239,1.55756 4.573449,1.55756 6.429688,0 1.85624,-1.55757 2.326809,-4.23158 1.115234,-6.33008 a 0.50004997,0.50004997 0 0 0 -0.002,-0.002 l -3.646484,-6.25 A 0.50004997,0.50004997 0 0 0 55.25,284 Z m 0.25,1.06445 3.464844,5.9375 c 0.970958,1.6837 0.594513,3.81305 -0.894532,5.0625 -1.489569,1.2499 -3.651055,1.2499 -5.140624,0 -1.489045,-1.24945 -1.86549,-3.3788 -0.894532,-5.0625 V 291 Z m -0.511719,2.92969 a 0.50004997,0.50004997 0 0 0 -0.429687,0.27148 l -1.697266,3.20704 c -0.166111,0.28617 -0.283806,0.59778 -0.349609,0.92187 a 0.50005872,0.50005872 0 1 0 0.980469,0.19727 c 0.04414,-0.2174 0.122796,-0.42496 0.234374,-0.61719 a 0.50004997,0.50004997 0 0 0 0.0098,-0.0176 l 1.705078,-3.22265 a 0.50004997,0.50004997 0 0 0 -0.453125,-0.74024 z"
- id="path22264"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 222.49805,369.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 l 0.002,0.60742 c -2.27831,0.46511 -4,2.48538 -4,4.89844 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.41306 -1.72169,-4.43333 -4,-4.89844 l -0.002,-0.60742 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z M 223,372 c 2.21488,0 4,1.78488 4,4 0,2.21512 -1.78512,4 -4,4 -2.21488,0 -4,-1.78488 -4,-4 0,-2.21512 1.78512,-4 4,-4 z"
+ transform="translate(1.85367e-6,-42)"
+ id="ellipse14399"
inkscape:connector-curvature="0" />
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g13453">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 216.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 220.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.50195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 369 h -1.5039 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.5039 v 0.49414 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
+ transform="translate(1.85367e-6,-42)"
+ id="path14421"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22457"
- transform="translate(20.999998,-20.999995)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 280.5,284 a 0.50004976,0.50004976 0 0 0 -0.5,0.5 v 0.75 7.25 a 0.50004976,0.50004976 0 0 0 0.5,0.5 h 0.5 a 0.50004976,0.50004976 0 0 0 0.2832,-0.0879 l 10.5,-7.25 A 0.50004976,0.50004976 0 0 0 292,285.25 v -0.75 a 0.50004976,0.50004976 0 0 0 -0.5,-0.5 z m 0.5,1 h 9.98242 L 281,291.89258 V 285.25 Z"
- id="path22322"
- inkscape:connector-curvature="0" />
+ id="g14429"
+ transform="translate(-1.85367e-6,42)"
+ inkscape:label="R-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 285.25,292 a 0.50004976,0.50004976 0 1 0 0,1 H 291 v 0.15625 l -10,3.80859 V 295.25 a 0.50004976,0.50004976 0 1 0 -1,0 v 2.25 a 0.50004976,0.50004976 0 0 0 0.5,0.5 h 0.5 a 0.50004976,0.50004976 0 0 0 0.17773,-0.0332 l 10.5,-4 A 0.50004976,0.50004976 0 0 0 292,293.5 v -1 a 0.50004976,0.50004976 0 0 0 -0.5,-0.5 z"
- id="path22334"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 201.49805,368.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.7207 C 203.68137,373.39211 205,375.04034 205,377 c 0,1.45833 -0.66274,2.34651 -1.76562,2.75 -1.1029,0.40349 -2.7161,0.26002 -4.5,-0.69141 a 0.50005,0.50005 0 1 0 -0.46876,0.88282 c 1.9661,1.04857 3.8529,1.2801 5.3125,0.74609 C 205.03775,380.15349 206,378.79167 206,377 c 0,-2.43412 -1.54431,-4.24525 -3.00195,-6.65039 v -0.85547 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ transform="translate(1.85367e-6,-42)"
+ id="path14357"
inkscape:connector-curvature="0" />
- </g>
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22510"
- transform="translate(-1.8536743e-6,21.000005)">
<g
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- id="g22476"
- transform="translate(168,-42)">
+ style="opacity:0.6;fill:#ffffff"
+ id="g13445">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 447.5,263 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 8 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 276 h 8 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 A 0.50005,0.50005 0 0 0 460.5,274 H 460 v -8 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -8 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z m -9,1 h 8 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 8 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -8 v -0.5 A 0.50005,0.50005 0 0 0 449.5,274 H 449 v -8 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m -2,10 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z"
- transform="translate(-168,20.999995)"
- id="path22458"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 195.49805,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 199.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -1.50195 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 369 H 204.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.49805 v 0.49414 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.5,1 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z"
+ transform="translate(1.85367e-6,-42)"
+ id="path14367"
inkscape:connector-curvature="0" />
</g>
+ </g>
+ <g
+ transform="translate(147)"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g12973-3-2"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="R-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 451.5,246 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 4 v 4 h -4 z"
- id="rect22466"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 178.49219,368 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 178,369.70703 v 7.58594 l -3,3 V 378.5 A 0.50005,0.50005 0 0 0 174.49219,377.99219 0.50005,0.50005 0 0 0 174,378.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -1.79297 l 3,-3 h 7.58594 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 186.29297,377 H 179 v -7.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 A 0.50005,0.50005 0 0 0 178.49219,368 Z"
+ transform="translate(-147)"
+ id="path12965-4-0"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(21.999998,18.000004)"
- id="g22745">
- <g
- id="g22756"
- transform="translate(20,-60)"
- style="fill:#ffffff">
- <g
- id="g22751"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 279.5,288 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.71484 L 283,295.64062 V 297.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.85938 L 288.78516,291 H 289.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 0.5 h -5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 8,0 h 1 v 1 h -1 z m -6,1 h 5 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.11523 l -2.40039,4 h -1.42968 l -2.40039,-4 H 281.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z m 2,6 h 1 v 1 h -1 z"
- id="path22741"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 283.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.5 h 1 v -3 h 8 v 10 h -3.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path22747"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccc" />
- </g>
- </g>
+ id="g98807"
+ style="display:inline;enable-background:new"
+ inkscape:label="R-8">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 163.00977,368 c -1.1753,0 -2.25213,0.41841 -2.88477,1.18164 a 0.50005,0.50005 0 1 0 0.76953,0.63672 C 161.27001,369.36537 162.08306,369 163.00977,369 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 z m -1.44141,3.00391 c -1.72788,-0.20328 -3.32792,0.12142 -4.53125,0.90234 -1.20333,0.78092 -1.99513,2.0489 -2.02734,3.58398 v 0.004 0.006 c 0,1.08246 0.28424,1.81368 0.53711,2.38867 0.25286,0.575 0.45312,0.97127 0.45312,1.61133 0,0.46148 -0.10735,0.76987 -0.43555,1.02734 -0.3282,0.25748 -0.96151,0.47266 -2.05468,0.47266 a 0.50005,0.50005 0 1 0 0,1 c 1.21947,0 2.08348,-0.22395 2.67187,-0.68555 C 156.77003,380.85286 157,380.16225 157,379.5 c 0,-0.85994 -0.29523,-1.46367 -0.53711,-2.01367 -0.24115,-0.54835 -0.44991,-1.06809 -0.45117,-1.98047 0.0269,-1.212 0.60444,-2.1349 1.57031,-2.76172 0.96712,-0.62763 2.33652,-0.92835 3.86914,-0.74805 1.98998,0.23412 3.41358,1.22813 4.10352,2.33203 0.68994,1.10391 0.68215,2.23778 -0.14844,3.06836 -0.83795,0.83796 -1.98844,0.89361 -3.08398,0.26368 -1.09554,-0.62994 -2.08047,-1.9799 -2.31446,-3.96875 a 0.50051111,0.50051111 0 1 0 -0.99414,0.11718 c 0.26602,2.26115 1.40609,3.91119 2.81055,4.71875 1.40446,0.80757 3.12702,0.73822 4.28906,-0.42382 1.16941,-1.16942 1.16162,-2.91055 0.28906,-4.30664 -0.87256,-1.3961 -2.57396,-2.52709 -4.83398,-2.79297 z"
+ id="path23575"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g21947"
- transform="matrix(-1,0,0,1,67.986641,-20.999995)">
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ transform="translate(-357,168)"
+ id="g23559"
+ inkscape:label="R-7">
<path
- id="circle21927"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 27.460938,284.01172 a 0.50005,0.50005 0 1 0 0.04297,0.99805 c 3.348416,-0.1388 6.600566,1.12874 8.972656,3.49609 2.372091,2.36735 3.645762,5.61811 3.513672,8.9668 a 0.50038206,0.50038206 0 1 0 1,0.0391 c 0.143077,-3.62723 -1.237239,-7.14863 -3.80664,-9.71289 -2.569402,-2.56427 -6.09572,-3.93745 -9.722656,-3.78711 z m -0.0332,4.00586 a 0.50005,0.50005 0 1 0 0.0625,0.99804 c 2.281784,-0.14542 4.516597,0.69332 6.140625,2.30274 1.62403,1.60942 2.482218,3.83613 2.357422,6.11914 a 0.50005,0.50005 0 1 0 0.998047,0.0547 c 0.140364,-2.5678 -0.823774,-5.07459 -2.65039,-6.88477 -1.826617,-1.81018 -4.341781,-2.75341 -6.908204,-2.58984 z m 0.03711,4.01172 a 0.50005,0.50005 0 1 0 0.107422,0.99414 c 1.199607,-0.12917 2.392346,0.29002 3.248046,1.14062 0.855701,0.8506 1.282148,2.03988 1.160157,3.24024 a 0.50005,0.50005 0 1 0 0.99414,0.10156 c 0.152408,-1.49965 -0.380162,-2.99006 -1.449218,-4.05274 -1.069056,-1.06268 -2.561836,-1.5852 -4.060547,-1.42382 z M 28,296 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 495.49219,199.99219 A 0.50005,0.50005 0 0 0 495,200.5 v 6.79297 l -3.85352,3.85351 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 495.70703,208 H 502.5 a 0.50005,0.50005 0 1 0 0,-1 H 496 v -6.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path23553"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 499.49023,202.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 489.5,207 a 0.50005,0.50005 0 1 0 0,1 h 3.25 a 0.50005,0.50005 0 1 0 0,-1 z m 5.99219,2.74219 A 0.50005,0.50005 0 0 0 495,210.25 v 3.25 a 0.50005,0.50005 0 1 0 1,0 v -3.25 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path23557"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22083"
- transform="translate(-1.8536743e-6,-42.000055)">
+ id="g14344"
+ transform="translate(-168,63)"
+ inkscape:label="R-6">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 205.49805,242 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 5 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 206,252 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 208.5,246 H 206 v -3.5 A 0.50005,0.50005 0 0 0 205.49805,242 Z M 205,243.00195 V 246 h -2.00781 v -2.99414 z M 202.99219,247 H 205 v 4 h -2.00781 z M 206,247 h 2 v 4 h -2 z m -3.00781,5 h 2.00586 l -0.006,3.00781 h -2 z"
- transform="translate(1.8536743e-6,42.000055)"
- id="path22040"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 286,307 c -1.846,0 -3.56208,0.52582 -4.8457,1.40625 C 279.87068,309.28668 279,310.55671 279,312 c 0,1.44329 0.87068,2.71332 2.1543,3.59375 C 282.43792,316.47418 284.154,317 286,317 c 1.846,0 3.56208,-0.52582 4.8457,-1.40625 C 292.12932,314.71332 293,313.44329 293,312 c 0,-1.44329 -0.87068,-2.71332 -2.1543,-3.59375 C 289.56208,307.52582 287.846,307 286,307 Z m 2.49219,3.61719 A 0.50005,0.50005 0 0 1 289,311.125 c 0,0.62131 -0.43923,1.10886 -0.98438,1.41016 C 287.47049,312.83646 286.77233,313 286,313 c -0.77233,0 -1.47049,-0.16354 -2.01562,-0.46484 C 283.43923,312.23386 283,311.74631 283,311.125 a 0.50005,0.50005 0 0 1 0.49414,-0.50586 A 0.50005,0.50005 0 0 1 284,311.125 c 0,0.13737 0.11369,0.33891 0.46875,0.53516 C 284.82381,311.85641 285.37451,312 286,312 c 0.62549,0 1.17619,-0.14359 1.53125,-0.33984 C 287.88631,311.46391 288,311.26237 288,311.125 a 0.50005,0.50005 0 0 1 0.49219,-0.50781 z"
+ id="path13633"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 200.53711,284.16992 a 0.50005,0.50005 0 0 0 -0.13477,0.0156 c -3.14392,0.73681 -5.37898,3.53464 -5.40234,6.76367 -0.0234,3.22902 2.17176,6.05956 5.30469,6.8418 a 0.50005,0.50005 0 1 0 0.24219,-0.96875 c -2.69014,-0.67168 -4.56694,-3.09259 -4.54688,-5.86524 0.0201,-2.77265 1.93128,-5.16615 4.63086,-5.79883 a 0.50005,0.50005 0 0 0 -0.0937,-0.98828 z"
- id="path22034"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 279.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path14324"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g21627"
- transform="translate(2.8146326e-5,-41.999965)">
+ id="g14350"
+ transform="translate(-210,63)"
+ inkscape:label="R-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 495.5,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -3.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 1 0 1,0 V 312 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 308 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 306 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path21618"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 307,306 c -3.30761,0 -6,2.6922 -6,6 0,3.3078 2.69239,6 6,6 3.30761,0 6,-2.6922 6,-6 0,-3.3078 -2.69239,-6 -6,-6 z m 4.75781,6.73438 a 0.50005,0.50005 0 0 1 0.28516,0.91992 c -1.16187,0.83991 -2.99782,1.34961 -5.04297,1.34961 -2.04361,0 -3.88093,-0.50932 -5.04297,-1.34766 a 0.50005,0.50005 0 0 1 0.25586,-0.91016 0.50005,0.50005 0 0 1 0.33008,0.0977 c 0.89908,0.64864 2.58702,1.16016 4.45703,1.16016 1.87213,0 3.55862,-0.50874 4.45703,-1.15821 a 0.50005,0.50005 0 0 1 0.30078,-0.11132 z"
+ id="ellipse14291"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 502.5,308 c -5.79307,0 -10.5,4.70693 -10.5,10.5 a 0.50004997,0.50004997 0 1 0 1,0 c 0,-5.25263 4.24737,-9.5 9.5,-9.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
- id="circle21622"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 300.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path14322"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g21555"
- transform="translate(-1.8536743e-6,-20.999995)">
+ id="g14394"
+ transform="translate(-252,63)"
+ inkscape:label="R-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 160.50391,263.00391 c -0.82069,0 -1.4961,0.67734 -1.4961,1.49804 1e-5,0.64713 0.422,1.19917 1.00196,1.40625 -0.004,0.17741 -0.01,0.3625 -0.01,0.58594 0,0.8575 0.30572,1.55064 0.73242,2.08984 0.42671,0.53921 0.958,0.94374 1.45313,1.34375 0.99025,0.80003 1.81445,1.48075 1.81445,3.0293 0,1.03964 -0.41467,1.75679 -1.05859,2.26367 C 162.29747,275.72759 161.4016,276 160.5,276 c -0.9016,0 -1.79749,-0.27241 -2.44141,-0.7793 C 157.41467,274.71382 157,273.99667 157,272.95703 v -1.25 l 1.14648,1.14649 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -2,-2 c -0.315,-0.31479 -0.85335,-0.0918 -0.85352,0.35352 v 2.45703 c 0,1.32194 0.58533,2.37688 1.44141,3.05078 0.85608,0.6739 1.96019,0.99219 3.05859,0.99219 1.0984,0 2.20251,-0.31829 3.05859,-0.99219 0.85608,-0.6739 1.44141,-1.72884 1.44141,-3.05078 0,-1.93167 -1.1758,-2.99085 -2.18555,-3.80664 -0.50487,-0.40789 -0.97358,-0.77897 -1.29687,-1.1875 C 161.19428,267.55436 161,267.12816 161,266.49414 c 0,-0.20716 0.005,-0.40692 0.01,-0.58984 0.57393,-0.21035 0.99023,-0.75955 0.99023,-1.40235 0,-0.8207 -0.67541,-1.49804 -1.49609,-1.49804 z m 0,1 c 0.27921,0 0.49609,0.21676 0.49609,0.49804 0,0.28129 -0.21688,0.49805 -0.49609,0.49805 -0.27922,0 -0.4961,-0.21676 -0.4961,-0.49805 0,-0.28128 0.21688,-0.49804 0.4961,-0.49804 z"
- transform="translate(1.8536743e-6,20.999995)"
- id="path16949-6-5"
+ id="path17351-9"
+ d="m 328,307 c -1.30038,0 -2.48006,0.21939 -3.37891,0.60352 -0.44942,0.19206 -0.83127,0.42394 -1.12304,0.71875 -0.29178,0.2948 -0.49805,0.67796 -0.49805,1.10156 v 2.30664 2.8457 c 0,0.4236 0.20627,0.80676 0.49805,1.10156 0.29177,0.29481 0.67362,0.52669 1.12304,0.71875 C 325.51994,316.78061 326.69962,317 328,317 c 1.30038,0 2.48006,-0.21939 3.37891,-0.60352 0.44942,-0.19206 0.83127,-0.42394 1.12304,-0.71875 0.29178,-0.2948 0.49805,-0.67796 0.49805,-1.10156 v -2.8457 -2.30664 c 0,-0.4236 -0.20627,-0.80676 -0.49805,-1.10156 -0.29177,-0.29481 -0.67362,-0.52669 -1.12304,-0.71875 C 330.48006,307.21939 329.30038,307 328,307 Z m 0,1 c 1.01151,0 1.92459,0.13316 2.61914,0.3418 0.34727,0.10431 0.63991,0.22479 0.88086,0.38281 0.24095,0.15802 0.5,0.38269 0.5,0.77539 0,0.3927 -0.25905,0.61737 -0.5,0.77539 -0.24095,0.15802 -0.53359,0.2785 -0.88086,0.38281 C 329.92459,310.86684 329.01151,311 328,311 c -1.0115,0 -1.92459,-0.13316 -2.61914,-0.3418 -0.34727,-0.10431 -0.63991,-0.22479 -0.88086,-0.38281 -0.24095,-0.15802 -0.5,-0.38268 -0.5,-0.77539 0,-0.3927 0.25905,-0.61737 0.5,-0.77539 0.24095,-0.15802 0.53359,-0.2785 0.88086,-0.38281 C 326.07541,308.13316 326.9885,308 328,308 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 321.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -1 h 1 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.5 h 1 v 1 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -11.00976,11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 1 0 -1,0 v 0.5 h -1 v -1 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z m 12.00976,0 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 1 h -1 v -0.5 a 0.50005,0.50005 0 1 0 -1,0 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path14314"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22356"
- transform="translate(-336,-62.999995)">
+ id="g14390"
+ transform="translate(-294,63)"
+ inkscape:label="R-3">
<path
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- sodipodi:nodetypes="ccccc"
- id="path22236"
- d="m 363.5,308.5 3,-3 h 6 l -3,3 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 347.50586,306 c -0.31034,2.7e-4 -0.5455,0.28021 -0.49219,0.58594 0.36436,2.07324 0.1958,3.10943 -0.10742,3.63086 -0.30322,0.52143 -0.79091,0.68645 -1.46094,0.9414 -0.67003,0.25495 -1.50865,0.62325 -1.98242,1.58985 -0.47377,0.96659 -0.59114,2.40736 -0.20703,4.83007 0.0385,0.24306 0.24806,0.422 0.49414,0.42188 h 6.75586 c 0.30739,1.4e-4 0.54213,-0.27449 0.49414,-0.57812 -0.369,-2.32739 -0.20658,-3.57589 0.11523,-4.23438 0.32182,-0.65849 0.7931,-0.85067 1.43555,-1.0957 0.64245,-0.24504 1.46993,-0.51949 1.96484,-1.37305 0.49492,-0.85356 0.6091,-2.12804 0.22657,-4.30469 C 354.70043,306.17484 354.49284,306.0002 354.25,306 Z"
+ id="path14318"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccssccccccccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 366.5,305 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 363.5,309 h 6 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 372.5,305 Z m 0.20703,1 h 4.58594 l -2,2 h -4.58594 z m 9.77735,3 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 373,312.5 v 6 a 0.50005,0.50005 0 0 0 0.85352,0.35352 l 3,-3 A 0.50005,0.50005 0 0 0 377,315.5 v -6 A 0.50005,0.50005 0 0 0 376.48438,309 Z M 376,310.70703 v 4.58594 l -2,2 v -4.58594 z M 369.5,312 l -6.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 370,312.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,5.00781 h -5 v -5.00195 z"
- id="path22324"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 10.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z"
+ id="path14320"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22409">
+ id="g14339"
+ transform="translate(-231,63)"
+ inkscape:label="R-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 347.75,247 -5.25781,0.002 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.49804 L 351,251.50195 a 0.50005,0.50005 0 1 0 -1,-0.004 l -0.008,3.5039 h -7 v -7 L 347.75,248 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path22405"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 258.49805,304.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z m -11.50976,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 11.00976,0 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10.50976,1 h 1 v 1 h -1 z m 11.00976,0 h 1 v 1 h -1 z"
+ id="path13555"
inkscape:connector-curvature="0" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265,307 c -2.75536,0 -5,2.24449 -5,5 0,2.75551 2.24464,5 5,5 2.75536,0 5,-2.24449 5,-5 0,-2.75551 -2.24464,-5 -5,-5 z"
+ id="ellipse13557"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14334"
+ transform="translate(-231,63)"
+ inkscape:label="R-1">
+ <path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 350.49219,241.99219 A 0.50005,0.50005 0 0 0 350,242.5 v 4.59766 c -0.58199,0.20687 -1.00586,0.75933 -1.00586,1.4082 0,0.82235 0.67765,1.5 1.5,1.5 0.36227,0 0.69258,-0.13606 0.95313,-0.35352 l 3.79492,2.27735 a 0.50109829,0.50109829 0 1 0 0.51562,-0.85938 l -3.79297,-2.27734 c 0.0184,-0.0931 0.0293,-0.18901 0.0293,-0.28711 0,-0.10213 -0.0114,-0.20218 -0.0312,-0.29883 l 3.79492,-2.27734 a 0.50109829,0.50109829 0 1 0 -0.51562,-0.85938 l -3.80469,2.28321 C 351.30689,247.24613 351.16128,247.1604 351,247.10156 V 242.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- transform="translate(1.8536743e-6,-4.4999696e-6)"
- id="path22407"
- inkscape:connector-curvature="0" />
+ d="m 250.05859,306.01172 c -2.15963,0 -4.15811,1.13935 -5.24023,2.99219 -1.08212,1.85283 -1.08212,4.1413 0,5.99414 1.08212,1.85284 3.0806,2.99218 5.24023,2.99218 l 0.43164,0.01 c 0.28003,0.005 0.50992,-0.22015 0.50977,-0.50023 l -0.004,-10.98438 c -2e-5,-0.27461 -0.22149,-0.49783 -0.49609,-0.5 l -0.4375,-0.004 c -0.001,-10e-6 -0.003,-10e-6 -0.004,0 z"
+ id="path13470"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccscccccccc" />
+ <g
+ transform="translate(0,-21)"
+ id="g13541"
+ style="opacity:0.6;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 6.4980469,367.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 H 7 v 8 H 6.4980469 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 381 H 14 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 8.9980469 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 H 8 v -8 h 0.4980469 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 370 H 14 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 8.9980469 v -0.50586 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,11 h 1 v 1 h -1 z"
+ transform="translate(231,-42)"
+ id="path13523"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22292"
- transform="translate(-88.000002,-170)">
+ id="g16467"
+ transform="translate(-222,478)"
+ inkscape:label="Q-26">
<g
- transform="translate(20,10)"
- id="g22287"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12626-8"
+ transform="translate(726,-499)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 112,515 v 2 h -1 v 4 h 1 v 2 h 2 v -8 z m 10,0 v 8 h 2 v -2 h 1 v -4 h -1 v -2 z m -7,3 v 2 h 6 v -2 z"
- transform="translate(68.000002,160)"
- id="rect22279"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 30.492188,367.99219 A 0.50005,0.50005 0 0 0 30,368.5 v 9.79297 l -2.853516,2.85351 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 30.707031,379 H 40.5 a 0.50005,0.50005 0 1 0 0,-1 H 31 v -9.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ id="path12205-4"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,1420,228)"
+ id="g8805-9"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 653.5,-359 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 0.5 h 1 v -0.5 -7.5 h 7.5 0.5 v -1 h -0.5 z"
+ id="path8743-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 542,349 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -3.48047,2.05078 c -0.16946,-0.008 -0.32881,0.0808 -0.41211,0.22852 l -2.25,4 c -0.17018,0.3004 0.0473,0.67264 0.39258,0.67187 h 4.5 c 0.34528,7.7e-4 0.56276,-0.37147 0.39258,-0.67187 l -2.25,-4 c -0.0765,-0.13552 -0.21755,-0.22152 -0.37305,-0.22852 z"
+ transform="matrix(-1,0,0,1,1198,-706)"
+ id="path8759-7"
inkscape:connector-curvature="0" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path22290"
- d="m 203,691 v 5 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 2.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 697 c 0,-0.55228 0.44772,-1 1,-1 0.55229,0 1,-0.44771 1,-1 v -1 h -3 v -3 z"
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- sodipodi:nodetypes="csssssssssssscccc" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22354"
- transform="translate(-26.000002,-443)">
+ id="g16457"
+ transform="translate(-285,478)"
+ inkscape:label="Q-25">
<g
- id="g22339"
- transform="translate(0,10)"
- style="fill:#ffffff">
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g7406-1-2-5"
+ transform="translate(348,-290.004)"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 154,242 v 2 h -1 v 4 h 1 v 2 h 2 v -8 z m 10,0 v 8 h 2 v -2 h 1 v -4 h -1 v -2 z m -7,3 v 2 h 6 v -2 z"
- transform="translate(26.000002,433)"
- id="path22321"
+ id="path7416-1-8-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 453,170 v 2 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.91992 a 0.50005,0.50005 0 0 0 0.16211,0 h 0.83789 a 0.50005,0.50005 0 0 0 0.16211,0 H 457.5 a 0.50005,0.50005 0 1 0 0,-1 H 455 v -2 z m -5.5,-11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 8 h -12 z"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-267.99969,306.00818)"
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;enable-background:new"
- id="g22352">
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g16437"
+ transform="matrix(-1,0,0,1,1460,228)">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 452.49219,387 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 V 387.5 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,0 -1.3386,0 -2.00781,0 z m 4.50781,0.98438 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z M 447.5,389 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1,-10e-6 2,10e-6 3,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1,0 -2,0 -3,0 z m 10.5,0.98438 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66922,0 -1.33859,0 -2.00781,0 z M 448,390 c 0.66667,0 1.33333,0 2,0 v 2 c -0.66667,0 -1.33333,0 -2,0 z"
- id="path22350"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 520,349 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -4.50391,1.05078 c -0.16882,0.001 -0.32263,0.0972 -0.39843,0.24805 l -2.75,5.5 c -0.15067,0.29943 0.0671,0.65258 0.40234,0.65234 h 5.75 c 0.34173,-2.4e-4 0.55851,-0.36622 0.39453,-0.66601 l -3,-5.5 c -0.0795,-0.14558 -0.23258,-0.23538 -0.39844,-0.23438 z"
+ transform="matrix(-1,0,0,1,1175,-706)"
+ id="path16433"
inkscape:connector-curvature="0" />
</g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 118.89062,157.9668 c -1.59478,-0.0195 -3.16997,0.53887 -4.2539,1.6914 l -0.74024,0.73828 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.5,-0.5 c 0.5849,-0.58491 1.58165,-0.89809 2.3457,-0.69336 0.80156,0.21477 1.42585,0.83907 1.64062,1.64062 0.20473,0.76404 -0.10844,1.76078 -0.69336,2.3457 l -0.5,0.5 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.75,-0.75 c 2.22378,-2.22379 2.21818,-6.29752 -0.0977,-8.61329 -1.15793,-1.15796 -2.77045,-1.75392 -4.36524,-1.77343 z m -6.14848,3.7832 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -1.25,1.25 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.25,-1.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.226,-0.14854 -0.36128,-0.14648 z m 6.00019,6 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -1.25,1.25 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.25,-1.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.22612,-0.14859 -0.36147,-0.14648 z"
- id="path21201-1"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccscccccccccccccccccccccccccccccc" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22386"
- transform="translate(-886.00002,80.000125)">
+ id="g16449"
+ transform="translate(-285,478)"
+ inkscape:label="Q-24">
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ id="g15951-6-3"
+ transform="translate(747,-478)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
+ id="path15947-7-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,1439,230)"
+ id="g8805-98"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 653.5,-359 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 8 h -8 z"
+ id="path8743-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 656,-357 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3.50391,1 c -0.18479,-10e-4 -0.35529,0.0993 -0.44336,0.26172 l -3,5.5 c -0.1805,0.33311 0.0606,0.73812 0.43945,0.73828 h 5.75 c 0.37101,-3.7e-4 0.61244,-0.39044 0.44727,-0.72266 l -2.75,-5.5 c -0.0838,-0.16852 -0.25516,-0.2757 -0.44336,-0.27734 z"
+ id="circle8761-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ssssscccccccc" />
+ </g>
+ </g>
+ <g
+ id="g5375"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="Q-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 433,263 c -3.84758,0 -6.97776,3.12003 -6.99805,6.96289 -6e-5,0.0125 -0.002,0.0246 -0.002,0.0371 a 0.50004994,0.50004994 0 0 0 0.002,0.0488 0.50004994,0.50004994 0 0 0 0,0.002 l -0.01,6.45508 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 432.96484,277 A 0.50004994,0.50004994 0 0 0 433,277 c 0.0171,0 0.0337,-0.002 0.0508,-0.002 a 0.50005,0.50005 0 0 0 0.008,0 C 436.89154,276.96613 440,273.84031 440,270 c 0,-3.86007 -3.1399,-7 -7,-7 z m 0,1 c 3.3196,0 6,2.68037 6,6 0,3.31963 -2.6804,6 -6,6 l -6.00781,0.008 0.01,-6.00781 a 0.50005,0.50005 0 0 0 0,-0.0215 C 427.01364,266.66895 429.68766,264 433,264 Z"
- transform="translate(886.00002,-80.000125)"
- id="path22377"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path9106-6-2"
+ d="m 346.49261,354.99229 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3 c 0,0.725 0.22685,1.37138 0.67773,1.82226 0.45089,0.45089 1.09727,0.67774 1.82227,0.67774 0.725,0 1.37138,-0.22685 1.82226,-0.67774 0.45089,-0.45088 0.67774,-1.09726 0.67774,-1.82226 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 3 c 0,0.525 -0.14815,0.87862 -0.38477,1.11523 -0.23661,0.23661 -0.59023,0.38477 -1.11523,0.38477 -0.525,0 -0.87862,-0.14816 -1.11524,-0.38477 -0.23661,-0.23661 -0.38476,-0.59023 -0.38476,-1.11523 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1314.5,189 a 0.50005,0.50005 0 1 0 0,1 h 4.5 v 4.5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path22381"
+ d="m 348.49261,349.99229 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 0 1,0 v -6 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -5.99219,-2.99219 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.75 c 0,0.97222 0.53688,1.82801 1.27539,2.19726 a 0.50005635,0.50005635 0 1 0 0.44726,-0.89453 c -0.26148,-0.13074 -0.72265,-0.77495 -0.72265,-1.30273 v -1.75 h 5 v 1.75 c 0,0.52778 -0.46312,1.17199 -0.72461,1.30273 a 0.50005635,0.50005635 0 1 0 0.44726,0.89453 c 0.73852,-0.36925 1.27735,-1.22504 1.27735,-2.19726 v -1.75 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path9108-6-6"
inkscape:connector-curvature="0" />
</g>
<g
+ id="g5381"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22599"
- transform="translate(-1.8536743e-6,-21.999995)">
+ inkscape:label="Q-16">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 132.5,285 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
- id="path22722"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03999px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 329.97518,350.98014 a 0.52004817,0.52004817 0 0 0 -0.38086,0.19532 l -3.61133,4.51562 -3.09179,-3.5332 a 0.52004817,0.52004817 0 1 0 -0.78321,0.68359 l 3.5,4 a 0.52004817,0.52004817 0 0 0 0.79883,-0.0176 l 3.61133,-4.51367 3.08984,3.53125 a 0.52004817,0.52004817 0 1 0 0.78321,-0.68359 l -3.5,-4 a 0.52004817,0.52004817 0 0 0 -0.41602,-0.17774 z"
+ id="path4898"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 139,287 c -2.75493,0 -5,2.24492 -5,5 0,2.75508 2.24507,5 5,5 2.75493,0 5,-2.24492 5,-5 0,-2.75508 -2.24507,-5 -5,-5 z m 0,1.09961 c 2.1604,0 3.90039,1.73975 3.90039,3.90039 0,2.16064 -1.73999,3.90039 -3.90039,3.90039 -2.1604,0 -3.90039,-1.73975 -3.90039,-3.90039 0,-2.16064 1.73999,-3.90039 3.90039,-3.90039 z"
- id="ellipse22724"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03999px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 321.49219,347.97266 A 0.52004817,0.52004817 0 0 0 320.97852,348.5 v 11 a 0.520505,0.520505 0 0 0 1.04101,0 V 358 h 11.95899 v 1.5 a 0.520505,0.520505 0 0 0 1.04101,0 v -11 a 0.52004817,0.52004817 0 0 0 -0.52734,-0.52734 0.52004817,0.52004817 0 0 0 -0.51367,0.52734 v 1.5 h -11.95899 v -1.5 a 0.52004817,0.52004817 0 0 0 -0.52734,-0.52734 z M 322.01953,351 h 11.95899 v 6 h -11.95899 z"
+ id="path4902" />
</g>
<g
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- transform="translate(-356.99997,168.00001)"
- id="g23559">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24475"
+ transform="matrix(-1,0,0,1,551,4.49997e-6)"
+ inkscape:label="Q-13">
+ <g
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
+ transform="translate(188,63)"
+ id="g24356">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 265.26367,347.00781 c -0.18015,-0.0118 -0.36127,-0.0106 -0.54101,0.002 -0.71897,0.05 -1.42538,0.29465 -2.03516,0.72656 -1.07953,0.76463 -1.69855,2.00863 -1.68359,3.31055 -0.73615,0.10606 -1.42713,0.4336 -1.96289,0.96289 -0.64152,0.63369 -1.00529,1.49176 -1.03125,2.39062 A 0.50005,0.50005 0 0 0 258,354.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.96484 a 0.50005,0.50005 0 0 0 0,-0.0352 c 0,-0.66852 0.26659,-1.30947 0.74219,-1.7793 0.47558,-0.46982 1.12059,-0.7287 1.78906,-0.7207 a 0.50005,0.50005 0 0 0 0.49609,-0.61914 c -0.14075,-1.09982 0.33186,-2.1861 1.23828,-2.82813 0.9161,-0.64887 2.11612,-0.73246 3.11329,-0.21679 C 267.37607,348.85161 268,349.87739 268,351 a 0.50005,0.50005 0 0 0 0.002,0.043 c -0.15856,-0.001 -0.31755,-0.003 -0.47461,0.0137 -0.85318,0.0929 -1.67617,0.45304 -2.33203,1.06641 a 0.5002238,0.5002238 0 1 0 0.6836,0.73047 c 0.98705,-0.92311 2.4814,-1.08629 3.65234,-0.39649 1.17094,0.6898 1.72204,2.04918 1.35937,3.33399 -0.36266,1.2848 -1.55342,2.17677 -2.92187,2.17578 -1.36845,-10e-4 -2.5592,-0.89437 -2.91992,-2.17969 a 0.50005,0.50005 0 0 0 -0.0469,-0.11719 0.50004997,0.50004997 0 0 0 0,-0.002 0.50004997,0.50004997 0 0 0 -0.0156,-0.0977 c -0.19194,-0.87762 -0.95663,-1.51856 -1.85742,-1.56836 -0.9008,-0.0498 -1.73485,0.50125 -2.02539,1.35157 a 0.50060304,0.50060304 0 0 0 0.94726,0.32421 c 0.14448,-0.42284 0.5581,-0.70333 1.02149,-0.67773 0.46338,0.0256 0.84227,0.34777 0.9375,0.7832 a 0.50004997,0.50004997 0 0 0 0.0566,0.1543 0.50005,0.50005 0 0 0 0.0195,0.11914 c 0.4828,1.72035 2.07532,2.90916 3.88086,2.91016 1.80554,10e-4 3.40131,-1.18467 3.88672,-2.9043 0.4854,-1.71963 -0.26339,-3.55306 -1.81446,-4.4668 -0.33807,-0.19915 -0.69725,-0.33834 -1.06445,-0.43164 A 0.50005,0.50005 0 0 0 269,351 c 0,-1.4945 -0.83461,-2.86624 -2.16211,-3.55273 -0.49781,-0.25748 -1.03377,-0.40392 -1.57422,-0.43946 z"
+ transform="matrix(-1,0,0,1,363,-63)"
+ id="path24346"
+ inkscape:connector-curvature="0" />
+ </g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 495.49219,199.99219 A 0.50005,0.50005 0 0 0 495,200.5 v 6.79297 l -3.85352,3.85351 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 495.70703,208 H 502.5 a 0.50005,0.50005 0 1 0 0,-1 H 496 v -6.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path23553"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 290.99609,357 c -1.09865,0 -2,0.90134 -2,2 0,1.09866 0.90135,2 2,2 1.09866,0 2,-0.90134 2,-2 0,-1.09866 -0.90134,-2 -2,-2 z"
+ id="circle24448"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22594"
+ transform="translate(-1.85367e-6,21)"
+ inkscape:label="Q-12">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 239.00391,336 c 1.09865,0 2,0.90134 2,2 0,1.09866 -0.90135,2 -2,2 -1.09866,0 -2,-0.90134 -2,-2 0,-1.09866 0.90134,-2 2,-2 z"
+ id="circle22541"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <g
+ id="g22585"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 244.04102,347.03125 c -1.67358,-0.0335 -3.28213,0.6908 -3.99805,2.26758 -0.007,0.016 -0.0126,0.0323 -0.0176,0.0488 l -2,5.99414 c -0.21093,0.63281 0.73829,0.94921 0.94922,0.3164 l 1.98437,-5.95117 c 0.004,-0.009 0.0113,-0.0162 0.0156,-0.0254 l 7.3457,7.3457 c -0.008,0.004 -0.0138,0.008 -0.0215,0.0117 l -5.95703,1.98633 c -0.63281,0.21093 -0.31641,1.16015 0.3164,0.94922 l 6,-2 c 0.0166,-0.006 0.0329,-0.0122 0.0488,-0.0195 1.57453,-0.7157 2.29587,-2.32277 2.26172,-3.9961 -0.0342,-1.67332 -0.77095,-3.46821 -2.11523,-4.8125 -1.34429,-1.34428 -3.13893,-2.08176 -4.8125,-2.11523 z m -0.0195,1 c 1.00796,0.0202 2.11393,0.36656 3.0879,0.99414 -1.6826,0.11569 -2.73353,0.941 -3.59961,1.77734 l -1.94336,-1.94335 c 0.60824,-0.57833 1.46627,-0.84791 2.45507,-0.82813 z M 247.5,350 h 0.5 c 0,6.5e-4 0,10e-4 0,0.002 l 0.002,0.5 c -6.4e-4,1.6083 -0.66875,2.43361 -1.50586,3.28711 l -2.2832,-2.2832 C 245.06632,350.66889 245.89088,350 247.5,350 Z m 1.47656,0.89258 c 0.62645,0.97337 0.97164,2.0788 0.99219,3.08594 0.0202,0.98929 -0.2502,1.84704 -0.82813,2.45507 l -1.9414,-1.9414 c 0.83635,-0.86594 1.6611,-1.91749 1.77734,-3.59961 z"
+ transform="translate(1.85367e-6,-21)"
+ id="path24556"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccscccccsccccc" />
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23638"
+ inkscape:label="Q-11">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 229.49023,351.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -0.74609,0.7461 -1.67773,-0.83985 a 0.50005,0.50005 0 0 0 -0.62305,0.14649 L 225.5,353 h -1 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 A 0.50005,0.50005 0 0 0 223,354.5 v 2.79297 l -1.85352,1.85351 a 0.50005,0.50005 0 0 0 0,0.70704 l 1,1 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 1.64649,-1.64648 A 0.50005,0.50005 0 0 0 224,357.5 v -2.79297 L 224.70703,354 H 225.75 a 0.50005,0.50005 0 0 0 0.40039,-0.19922 l 0.5,-0.66601 1.62695,0.8125 a 0.50005,0.50005 0 0 0 0.57618,-0.0937 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ id="path42208-0"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 499.49023,202.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 489.5,207 a 0.50005,0.50005 0 1 0 0,1 h 3.25 a 0.50005,0.50005 0 1 0 0,-1 z m 5.99219,2.74219 A 0.50005,0.50005 0 0 0 495,210.25 v 3.25 a 0.50005,0.50005 0 1 0 1,0 v -3.25 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path23557"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 223.49219,347 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -2,2 A 0.50005,0.50005 0 0 0 221,349.5 v 0.79297 L 220.29297,351 H 218.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 L 218,353.70703 v 2.58594 l -1.85352,1.85351 A 0.50005,0.50005 0 0 0 216,358.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -1.79297 l 1.85352,-1.85351 A 0.50005,0.50005 0 0 0 219,356.5 v -3 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 l -0.64649,-0.64648 0.5,-0.5 H 220.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1,-1 A 0.50005,0.50005 0 0 0 222,350.5 v -0.79297 l 1.5,-1.5 0.64648,0.64649 A 0.50005,0.50005 0 0 0 224.5,349 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 348 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 h -2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -2.29297 l -0.85351,-0.85352 A 0.50005,0.50005 0 0 0 223.49219,347 Z"
+ id="path42222-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 228.5,357 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 0,-0.70704 l -0.64649,-0.64648 0.5,-0.5 H 229.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path23824"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 163.00977,368 c -1.1753,0 -2.25213,0.41841 -2.88477,1.18164 a 0.50005,0.50005 0 1 0 0.76953,0.63672 C 161.27001,369.36537 162.08306,369 163.00977,369 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 z m -1.44141,3.00391 c -1.72788,-0.20328 -3.32792,0.12142 -4.53125,0.90234 -1.20333,0.78092 -1.99513,2.0489 -2.02734,3.58398 v 0.004 0.006 c 0,1.08246 0.28424,1.81368 0.53711,2.38867 0.25286,0.575 0.45312,0.97127 0.45312,1.61133 0,0.46148 -0.10735,0.76987 -0.43555,1.02734 -0.3282,0.25748 -0.96151,0.47266 -2.05468,0.47266 a 0.50005,0.50005 0 1 0 0,1 c 1.21947,0 2.08348,-0.22395 2.67187,-0.68555 C 156.77003,380.85286 157,380.16225 157,379.5 c 0,-0.85994 -0.29523,-1.46367 -0.53711,-2.01367 -0.24115,-0.54835 -0.44991,-1.06809 -0.45117,-1.98047 0.0269,-1.212 0.60444,-2.1349 1.57031,-2.76172 0.96712,-0.62763 2.33652,-0.92835 3.86914,-0.74805 1.98998,0.23412 3.41358,1.22813 4.10352,2.33203 0.68994,1.10391 0.68215,2.23778 -0.14844,3.06836 -0.83795,0.83796 -1.98844,0.89361 -3.08398,0.26368 -1.09554,-0.62994 -2.08047,-1.9799 -2.31446,-3.96875 a 0.50051111,0.50051111 0 1 0 -0.99414,0.11718 c 0.26602,2.26115 1.40609,3.91119 2.81055,4.71875 1.40446,0.80757 3.12702,0.73822 4.28906,-0.42382 1.16941,-1.16942 1.16162,-2.91055 0.28906,-4.30664 -0.87256,-1.3961 -2.57396,-2.52709 -4.83398,-2.79297 z"
- id="path23575"
- inkscape:connector-curvature="0" />
<g
- transform="matrix(-1,0,0,1,382.99922,-15.999998)"
+ transform="matrix(-1,0,0,1,382.999,-16)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24066">
+ id="g24066"
+ inkscape:label="Q-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 198.03906,347.00195 c -0.16252,-0.007 -0.32108,0.006 -0.47461,0.0371 -1.22821,0.25238 -1.95915,1.36682 -2.45507,2.09766 a 0.60006002,0.60006002 0 1 0 0.99218,0.67383 c 0.46736,-0.68874 1.16385,-1.48449 1.70508,-1.59571 0.27061,-0.0556 0.53217,-0.0252 0.94727,0.3125 0.41509,0.33772 0.93861,1.01123 1.49804,2.15625 a 0.60006002,0.60006002 0 0 0 0.53907,0.33594 h 0.41406 a 0.60006002,0.60006002 0 0 0 0.54101,-0.33789 c 0.54756,-1.13491 1.06338,-1.80121 1.47657,-2.13476 0.41318,-0.3336 0.68072,-0.3648 0.95898,-0.3086 0.55653,0.1125 1.2624,0.90264 1.7168,1.57227 a 0.60006002,0.60006002 0 1 0 0.99218,-0.67383 c -0.49155,-0.72441 -1.2401,-1.82545 -2.4707,-2.07422 -0.6153,-0.12438 -1.32524,0.0455 -1.95117,0.55078 -0.51038,0.41204 -0.98784,1.19591 -1.4707,2.07617 -0.49098,-0.88906 -0.97541,-1.67806 -1.48633,-2.09375 -0.46868,-0.38133 -0.98509,-0.5741 -1.47266,-0.59375 z M 202.23047,353 c -0.77376,-7.6e-4 -1.47981,0.46475 -2.07031,1.12109 a 0.60022344,0.60022344 0 1 0 0.89257,0.80274 c 0.54185,-0.60226 0.93231,-0.77859 1.30469,-0.71289 0.37239,0.0657 0.94999,0.47591 1.63867,1.53906 a 0.60006002,0.60006002 0 0 0 1.00782,0 c 0.68868,-1.06315 1.26628,-1.47336 1.63867,-1.53906 0.37238,-0.0657 0.76284,0.11063 1.30469,0.71289 a 0.60022344,0.60022344 0 1 0 0.89257,-0.80274 c -0.67486,-0.75011 -1.50108,-1.25149 -2.40625,-1.09179 -0.70977,0.12522 -1.32665,0.68468 -1.93359,1.45508 -0.60694,-0.7704 -1.22382,-1.32986 -1.93359,-1.45508 -0.11315,-0.02 -0.2254,-0.0292 -0.33594,-0.0293 z"
- transform="matrix(-1,0,0,1,382.99922,15.999998)"
+ transform="matrix(-1,0,0,1,382.999,16)"
id="path23960"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 185.50195,372 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z"
id="circle24296"
inkscape:connector-curvature="0"
@@ -11518,15 +12519,16 @@
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g24237"
- transform="translate(-1.8536743e-6,21.000005)">
+ transform="translate(-1.85367e-6,21)"
+ inkscape:label="Q-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 176.49609,335 c -1.37479,0 -2.5,1.12521 -2.5,2.5 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z"
id="circle24230"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 181.54297,326 a 0.60006002,0.60006002 0 1 0 0,1.19922 h 0.97656 c 1.24133,0 2.31915,0.34169 3.06836,0.9668 0.74922,0.6251 1.21289,1.52687 1.21289,2.85156 0,2.62859 -2.35092,5.18453 -6.32422,5.78906 a 0.60006002,0.60006002 0 1 0 0.18164,1.18555 c 4.40846,-0.67075 7.3418,-3.63746 7.3418,-6.97461 0,-1.62072 -0.62669,-2.92584 -1.64258,-3.77344 C 185.34154,326.39654 183.97898,326 182.51953,326 Z"
id="path24226"
inkscape:connector-curvature="0" />
@@ -11534,7 +12536,8 @@
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g24286"
- transform="matrix(-1,0,0,1,319.99683,63.000005)">
+ transform="matrix(-1,0,0,1,319.997,63)"
+ inkscape:label="Q-8">
<path
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
@@ -11545,32 +12548,130 @@
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 163.99805,292.00391 c -1.65006,0 -2.99805,1.34799 -2.99805,2.99804 0,1.65006 1.34799,2.99805 2.99805,2.99805 1.65005,0 2.99804,-1.34799 2.99804,-2.99805 0,-1.65005 -1.34799,-2.99804 -2.99804,-2.99804 z"
id="circle24230-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
</g>
<g
- id="g24294"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(83.999995,110)">
+ id="g24513"
+ transform="matrix(0,1,1,0,-152.003,47.0064)"
+ inkscape:label="Q-7">
+ <g
+ id="g24612"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 142.49609,347.00195 c -1.17351,0 -2.15665,0.82286 -2.42187,1.91797 1.14862,0.70733 2.04128,1.7894 2.50586,3.07422 1.33547,-0.0457 2.41601,-1.14613 2.41601,-2.49219 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 0.50196,8 c -1.65181,0 -3.00196,1.35015 -3.00196,3.00196 0,1.65181 1.35015,3.00195 3.00196,3.00195 1.65181,0 3.00195,-1.35014 3.00195,-3.00195 0,-1.65181 -1.35014,-3.00196 -3.00195,-3.00196 z"
+ transform="matrix(0,1,1,0,-47.0064,152.003)"
+ id="circle24338"
+ inkscape:connector-curvature="0" />
+ <path
+ id="circle24481"
+ transform="matrix(0,1,1,0,-47.0063,152.003)"
+ d="m 136.9668,349.03125 c -2.73852,0 -4.97071,2.23218 -4.97071,4.9707 0,2.73853 2.23219,4.96875 4.97071,4.96875 0.74568,0 1.44822,-0.1767 2.08398,-0.47265 -0.0209,-0.16376 -0.0508,-0.32518 -0.0508,-0.49414 0,-0.2598 0.0297,-0.51312 0.0781,-0.75977 -0.60661,0.39452 -1.33048,0.62695 -2.11132,0.62695 -2.14404,0 -3.8711,-1.72509 -3.8711,-3.86914 0,-2.14404 1.72706,-3.87109 3.8711,-3.87109 2.14405,0 3.86914,1.72705 3.86914,3.87109 0,0.23797 -0.0296,0.46946 -0.0703,0.69532 0.35109,-0.23908 0.74721,-0.40722 1.16407,-0.52539 0.002,-0.0568 0.008,-0.11267 0.008,-0.16993 0,-2.73852 -2.23217,-4.9707 -4.9707,-4.9707 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g106133"
+ style="display:inline;enable-background:new"
+ inkscape:label="Q-6">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 185.48047,363.06055 c -0.59845,-0.12754 -1.28387,0.0442 -1.90039,0.56445 -0.53509,0.4515 -1.05167,1.28657 -1.57813,2.31055 -0.51724,-1.01439 -1.02781,-1.84334 -1.5625,-2.29102 -0.61731,-0.51686 -1.30605,-0.68638 -1.90625,-0.56055 -1.20039,0.25167 -1.95047,1.38331 -2.44726,2.14258 a 0.50005,0.50005 0 1 0 0.83594,0.54688 c 0.467,-0.71375 1.196,-1.58087 1.8164,-1.71094 0.3102,-0.065 0.61722,-0.0219 1.0586,0.34766 0.44137,0.36955 0.97784,1.09019 1.54101,2.30078 A 0.50005,0.50005 0 0 0 181.79102,367 h 0.42187 a 0.50005,0.50005 0 0 0 0.45313,-0.28711 c 0.57516,-1.22093 1.11551,-1.9484 1.55859,-2.32227 0.44308,-0.37386 0.74393,-0.41807 1.04687,-0.35351 0.60589,0.12912 1.32737,1.00382 1.80664,1.73633 a 0.50005,0.50005 0 1 0 0.83594,-0.54688 c -0.50216,-0.76749 -1.23669,-1.91095 -2.43359,-2.16601 z M 176.5,370.0332 c -0.89413,-0.17031 -1.70729,0.35696 -2.38477,1.16992 a 0.50064923,0.50064923 0 1 0 0.76954,0.64063 c 0.57252,-0.68703 1.00936,-0.90781 1.42773,-0.82813 0.41837,0.0797 1.03934,0.56817 1.75781,1.76563 a 0.50005,0.50005 0 0 0 0.85938,0 c 0.71847,-1.19746 1.33944,-1.68594 1.75781,-1.76563 0.41837,-0.0797 0.85521,0.1411 1.42773,0.82813 a 0.50064923,0.50064923 0 1 0 0.76954,-0.64063 c -0.67748,-0.81296 -1.49064,-1.34023 -2.38477,-1.16992 -0.73042,0.13913 -1.36539,0.76726 -2,1.66797 -0.63461,-0.90071 -1.26958,-1.52884 -2,-1.66797 z m 6.18555,4.01758 c -0.21091,-0.0352 -0.44348,0.01 -0.63282,0.10938 -0.37867,0.19867 -0.6452,0.54404 -0.97656,1.07422 a 0.50018582,0.50018582 0 1 0 0.84766,0.53124 c 0.29364,-0.46982 0.52711,-0.68574 0.59375,-0.7207 0.0333,-0.0175 0.0107,-0.007 0.004,-0.008 -0.007,-0.001 0.0186,0.003 0.0781,0.0488 0.23799,0.1848 0.74712,0.97866 1.54492,1.78906 a 0.50005,0.50005 0 0 0 0.71094,0 c 0.7978,-0.8104 1.30693,-1.60426 1.54492,-1.78906 0.0595,-0.0462 0.0849,-0.05 0.0781,-0.0488 -0.007,10e-4 -0.0294,-0.01 0.004,0.008 0.0666,0.035 0.30011,0.25088 0.59375,0.7207 a 0.50018582,0.50018582 0 1 0 0.84766,-0.53124 c -0.33136,-0.53018 -0.59789,-0.87555 -0.97656,-1.07422 -0.18934,-0.0993 -0.42191,-0.14455 -0.63282,-0.10938 -0.2109,0.0352 -0.38371,0.13261 -0.52734,0.24414 -0.45025,0.34963 -0.83062,0.92221 -1.28711,1.47266 -0.45649,-0.55045 -0.83686,-1.12303 -1.28711,-1.47266 -0.14363,-0.11153 -0.31644,-0.20897 -0.52734,-0.24414 z"
- id="path24292"
+ style="display:inline;opacity:0.6;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
+ d="m 121.47461,347 a 3.4883757,3.4883673 0 0 0 -3.48828,3.48828 3.4883757,3.4883673 0 0 0 3.48828,3.48828 3.4883757,3.4883673 0 0 0 3.48828,-3.48828 A 3.4883757,3.4883673 0 0 0 121.47461,347 Z m -2.48047,3 H 124 v 1.01367 h -5.00586 z"
+ id="circle23728"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g106130"
+ style="display:inline;enable-background:new">
+ <path
+ style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m 114.49609,354 a 3.4824922,3.4824822 0 0 0 -3.48242,3.48242 3.4824922,3.4824822 0 0 0 3.48242,3.48242 3.4824922,3.4824822 0 0 0 3.48243,-3.48242 A 3.4824922,3.4824822 0 0 0 114.49609,354 Z m -0.50586,0.98633 h 1.01368 v 1.98633 H 117 v 1.01367 h -1.99609 v 1.98633 h -1.01368 v -1.98633 h -1.99609 v -1.01367 h 1.99609 z"
+ id="circle23722"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22663"
+ transform="translate(-126,21)"
+ inkscape:label="Q-5">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 219.77539,326 c -0.5582,0 -1.07768,0.24943 -1.49219,0.64258 -0.41451,0.39314 -0.75014,0.92623 -1.04101,1.57422 -0.58174,1.29596 -0.98621,3.07228 -1.23828,5.21484 a 0.55005495,0.55005495 0 1 0 1.09179,0.12891 c 0.24409,-2.07475 0.64639,-3.77175 1.15039,-4.89453 0.252,-0.5614 0.52906,-0.97431 0.79297,-1.22461 0.26391,-0.25031 0.48846,-0.3418 0.73633,-0.3418 0.24788,0 0.46416,0.0907 0.7207,0.33398 0.25655,0.24329 0.52547,0.64294 0.77149,1.17579 0.49204,1.06569 0.89452,2.64518 1.18945,4.47851 0.3037,1.88782 0.70794,3.53465 1.27539,4.76367 0.28373,0.61451 0.60805,1.12901 1.01367,1.51367 0.40563,0.38466 0.92032,0.63477 1.47852,0.63477 1.08819,0 1.93098,-0.8296 2.51953,-1.97266 0.58855,-1.14305 0.99634,-2.67751 1.25,-4.45312 a 0.55005495,0.55005495 0 1 0 -1.08789,-0.15625 c -0.2425,1.69747 -0.64149,3.13986 -1.13867,4.10547 -0.49719,0.9656 -1.01901,1.37695 -1.54297,1.37695 -0.24788,0 -0.46416,-0.0907 -0.7207,-0.33398 -0.25655,-0.24329 -0.52547,-0.64294 -0.77149,-1.17579 -0.49204,-1.06569 -0.89451,-2.64518 -1.18945,-4.47851 -0.30369,-1.88783 -0.70794,-3.53465 -1.27539,-4.76367 -0.28373,-0.61451 -0.60805,-1.12901 -1.01367,-1.51367 C 220.84828,326.25011 220.33359,326 219.77539,326 Z"
+ id="use22627"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 218.75,333 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 6.5,0 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="rect42619-7-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g56772"
+ inkscape:label="Q-4">
+ <g
+ id="g106127"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 75.492188,347.04102 A 0.50005,0.50005 0 0 0 75,347.54688 V 354.5 a 0.50005,0.50005 0 1 0 1,0 v -6.95312 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z m 0,10.95117 A 0.50005,0.50005 0 0 0 75,358.5 v 2.04688 a 0.50005,0.50005 0 1 0 1,0 V 358.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
+ id="rect42619-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g106124"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 81.492188,347.13672 c -0.442306,0.006 -0.696492,0.5058 -0.441407,0.86719 0.49808,0.72856 0.898438,1.27175 0.898438,2.60351 0,2.36371 -1.912476,5.29297 -6.919922,5.29297 -2.17926,0 -3.451901,-0.37865 -4.130859,-0.79883 -0.678959,-0.42018 -0.798829,-0.80387 -0.798829,-1.10156 0,-0.45749 0.450606,-1.844 3.496094,-2.17969 0.731186,-0.0565 0.647202,-1.15413 -0.08398,-1.09765 -0.01241,9.1e-4 -0.02479,0.002 -0.03711,0.004 C 70.097311,351.09872 69,352.84097 69,354 c 0,0.6737 0.378574,1.45551 1.318359,2.03711 0.939785,0.58159 2.407524,0.96289 4.710938,0.96289 5.452133,0 8.021484,-3.41358 8.021484,-6.39258 0,-1.58243 -0.595669,-2.49605 -1.09375,-3.22461 -0.103149,-0.1556 -0.278176,-0.24826 -0.464843,-0.24609 z M 77.5,350.96875 c -0.645258,0.008 -0.75144,0.92907 -0.125,1.08398 0.86985,0.23625 1.603372,0.59862 2.212891,1.02539 0.601573,0.42066 1.232432,-0.48169 0.630859,-0.90234 -0.709221,-0.49659 -1.560177,-0.91545 -2.554688,-1.18555 -0.05329,-0.0154 -0.108604,-0.0226 -0.164062,-0.0215 z m 4.814453,4.19141 c -0.370377,0.014 -0.621193,0.38283 -0.498047,0.73242 0.0943,0.28097 0.132813,0.5225 0.132813,0.67969 0,0.15896 0.01621,0.32983 0.0059,0.58398 -0.01039,0.25415 -0.04509,0.56394 -0.138672,0.89063 -0.187171,0.65336 -0.583988,1.36714 -1.576172,1.91796 -0.642059,0.35673 -0.106902,1.31962 0.535157,0.96289 1.249156,-0.69348 1.849012,-1.70822 2.097656,-2.57617 0.124322,-0.43397 0.166734,-0.83367 0.179687,-1.15039 0.01295,-0.31671 -0.002,-0.5795 -0.002,-0.6289 0,-0.3203 -0.06792,-0.66136 -0.191406,-1.0293 -0.07498,-0.23555 -0.297898,-0.39215 -0.544922,-0.38281 z"
+ id="path42609-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g106121"
+ style="display:inline;enable-background:new"
+ inkscape:label="Q-3">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.95;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 54.951172,347 c -1.831463,0.10706 -3.628606,0.91857 -4.910156,2.35742 -2.943003,3.30422 -2.532587,8.31019 0.05078,11.44531 a 0.5501659,0.5501659 0 1 0 0.849609,-0.69921 c -2.251956,-2.73294 -2.615242,-7.16516 -0.07813,-10.01368 2.156081,-2.42072 6.066547,-2.73646 8.435547,-0.43164 1.937906,1.88542 2.205459,5.18464 0.267578,7.14453 -1.518438,1.53565 -4.123722,1.73043 -5.623047,0.11133 -1.098553,-1.18629 -1.217866,-3.2114 0.03516,-4.28515 0.40623,-0.34811 0.977609,-0.54432 1.501953,-0.52539 0.524344,0.0189 0.981344,0.22421 1.291015,0.67968 0.145266,0.21367 0.237116,0.58238 0.201172,0.86719 -0.03594,0.28481 -0.127716,0.44479 -0.371094,0.5332 a 0.55049551,0.55049551 0 1 0 0.375,1.03516 c 0.656421,-0.23845 1.015068,-0.85266 1.087891,-1.42969 0.07282,-0.57703 -0.06773,-1.15869 -0.384765,-1.625 -0.517269,-0.76081 -1.34716,-1.12886 -2.160157,-1.1582 -0.812997,-0.0293 -1.63015,0.25121 -2.257812,0.78906 -1.781519,1.52664 -1.618395,4.25452 -0.125,5.86719 1.955333,2.11153 5.283443,1.86538 7.21289,-0.0859 2.400922,-2.4282 2.076076,-6.41165 -0.283203,-8.70703 -1.417731,-1.37933 -3.283772,-1.9762 -5.115234,-1.86914 z"
+ id="path23662-2"
inkscape:connector-curvature="0" />
</g>
<g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24220"
+ transform="translate(-1.85367e-6,63)"
+ inkscape:label="Q-2">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 32.855469,347.00586 c -0.706567,0.052 -1.35787,0.479 -1.669922,1.15234 a 0.50005,0.50005 0 1 0 0.90625,0.42188 c 0.210359,-0.45391 0.713864,-0.68179 1.193359,-0.53906 0.479496,0.14272 0.777196,0.60845 0.705078,1.10351 C 33.918117,349.63959 33.500288,350 33,350 h -5.5 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 33 c 0.98952,0 1.835874,-0.73175 1.978516,-1.71094 0.142642,-0.97918 -0.459806,-1.92277 -1.408204,-2.20508 -0.237099,-0.0706 -0.479321,-0.0955 -0.714843,-0.0781 z M 38.488281,349 c -0.867889,0.005 -1.700579,0.46414 -2.154297,1.25 a 0.5005035,0.5005035 0 1 0 0.867188,0.5 c 0.36563,-0.63329 1.125339,-0.91026 1.8125,-0.66016 0.68716,0.25011 1.089874,0.94977 0.96289,1.66993 C 39.849581,352.47992 39.231261,353 38.5,353 h -11 c -0.676161,-0.01 -0.676161,1.00956 0,1 h 11 c 1.209914,0 2.252791,-0.87487 2.462891,-2.06641 0.210099,-1.19153 -0.470475,-2.36938 -1.607422,-2.7832 C 39.071232,349.04694 38.777578,348.99817 38.488281,349 Z M 27.5,356 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 35.464844 35.5 c 0.74205,0 1.3672,0.53453 1.482422,1.26758 0.115221,0.73305 -0.315216,1.43251 -1.021484,1.66015 -0.706269,0.22765 -1.466229,-0.0896 -1.800782,-0.75195 a 0.50006246,0.50006246 0 1 0 -0.892578,0.45117 c 0.553327,1.09549 1.831882,1.62847 3,1.25196 1.168118,-0.37652 1.891741,-1.55517 1.701172,-2.76758 C 37.778181,356.89891 36.727299,356 35.5,356 Z"
+ transform="translate(1.85367e-6,-63)"
+ id="path24132"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g24588"
+ style="opacity:0.8;fill:#ffffff" />
+ <g
+ id="g24584"
+ style="opacity:0.8;fill:#ffffff" />
+ </g>
+ <g
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
- transform="rotate(90,171,281.00001)"
+ transform="rotate(90,171,281)"
id="g24322"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="Q-1">
<g
style="fill:#ffffff;stroke:#ffffff"
- transform="rotate(-90,244.00797,459)"
+ transform="rotate(-90,244.008,459)"
id="g24320">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
@@ -11590,1100 +12691,1649 @@
</g>
</g>
<g
+ id="g113469"
+ style="display:inline;enable-background:new"
+ inkscape:label="P-26">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 535.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.008,3.00781 c 10e-4,0.27537 0.22463,0.49802 0.5,0.49805 h 5.5 v 5.50195 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -4,4.0039 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 9.00782,0.01 c 0.27689,-3e-5 0.50105,-0.22506 0.5,-0.50195 l -0.008,-3.00586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -5.5 v -5.50196 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path24415-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccc" />
+ </g>
+ <g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24475"
- transform="matrix(-1,0,0,1,551.00038,4.4999696e-6)">
+ id="g25828"
+ transform="translate(-1)"
+ inkscape:label="P-25">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 515.49805,329.98633 c -0.27766,-0.001 -0.50302,0.22429 -0.50196,0.50195 l 0.008,5.00586 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.99805 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path24344-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="translate(188,63)"
- id="g24356">
+ id="g24392-5"
+ transform="translate(-166.996,-1801)"
+ style="display:inline;fill:#ffffff;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 265.26367,347.00781 c -0.18015,-0.0118 -0.36127,-0.0106 -0.54101,0.002 -0.71897,0.05 -1.42538,0.29465 -2.03516,0.72656 -1.07953,0.76463 -1.69855,2.00863 -1.68359,3.31055 -0.73615,0.10606 -1.42713,0.4336 -1.96289,0.96289 -0.64152,0.63369 -1.00529,1.49176 -1.03125,2.39062 A 0.50005,0.50005 0 0 0 258,354.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -0.96484 a 0.50005,0.50005 0 0 0 0,-0.0352 c 0,-0.66852 0.26659,-1.30947 0.74219,-1.7793 0.47558,-0.46982 1.12059,-0.7287 1.78906,-0.7207 a 0.50005,0.50005 0 0 0 0.49609,-0.61914 c -0.14075,-1.09982 0.33186,-2.1861 1.23828,-2.82813 0.9161,-0.64887 2.11612,-0.73246 3.11329,-0.21679 C 267.37607,348.85161 268,349.87739 268,351 a 0.50005,0.50005 0 0 0 0.002,0.043 c -0.15856,-0.001 -0.31755,-0.003 -0.47461,0.0137 -0.85318,0.0929 -1.67617,0.45304 -2.33203,1.06641 a 0.5002238,0.5002238 0 1 0 0.6836,0.73047 c 0.98705,-0.92311 2.4814,-1.08629 3.65234,-0.39649 1.17094,0.6898 1.72204,2.04918 1.35937,3.33399 -0.36266,1.2848 -1.55342,2.17677 -2.92187,2.17578 -1.36845,-10e-4 -2.5592,-0.89437 -2.91992,-2.17969 a 0.50005,0.50005 0 0 0 -0.0469,-0.11719 0.50004997,0.50004997 0 0 0 0,-0.002 0.50004997,0.50004997 0 0 0 -0.0156,-0.0977 c -0.19194,-0.87762 -0.95663,-1.51856 -1.85742,-1.56836 -0.9008,-0.0498 -1.73485,0.50125 -2.02539,1.35157 a 0.50060304,0.50060304 0 0 0 0.94726,0.32421 c 0.14448,-0.42284 0.5581,-0.70333 1.02149,-0.67773 0.46338,0.0256 0.84227,0.34777 0.9375,0.7832 a 0.50004997,0.50004997 0 0 0 0.0566,0.1543 0.50005,0.50005 0 0 0 0.0195,0.11914 c 0.4828,1.72035 2.07532,2.90916 3.88086,2.91016 1.80554,10e-4 3.40131,-1.18467 3.88672,-2.9043 0.4854,-1.71963 -0.26339,-3.55306 -1.81446,-4.4668 -0.33807,-0.19915 -0.69725,-0.33834 -1.06445,-0.43164 A 0.50005,0.50005 0 0 0 269,351 c 0,-1.4945 -0.83461,-2.86624 -2.16211,-3.55273 -0.49781,-0.25748 -1.03377,-0.40392 -1.57422,-0.43946 z"
- transform="matrix(-1,0,0,1,363.00038,-63.000004)"
- id="path24346"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaccc"
+ inkscape:connector-curvature="0"
+ id="rect24376-2"
+ transform="translate(166.996,1801)"
+ d="M 515.00391,325.99609 V 326 H 515 v 2 h 1 v -1.00391 h 1.00391 v -1 z m 4,0 v 1 h 2 v -1 z M 523,326 v 1 h 1 v 1 h 1.00391 v -2.00391 z m 1.00391,3.99609 v 2 h 1 v -2 z m -13,0.002 v 2 h 1 v -1 h 1 v -1 z m 13,3.99804 v 1 h -1 v 1 h 2 v -2 z m -13,0.002 v 2 h 1 v -2 z m 0,4 v 2 h 2 v -1 h -1 v -1 z m 9,0 v 1 h -1 v 1 h 2 v -2 z m -5,1 v 1 h 2 v -1 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g25821"
+ inkscape:label="P-24">
+ <g
+ id="g24262-4"
+ transform="translate(-188.996,-1801)"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="rect24246-3"
+ transform="translate(188.996,1801)"
+ d="m 489.00391,329.99805 v 2 h 1 v -1 h 1 v -1 z m 0,4 v 2 h 1 v -2 z m 0,4 v 2 h 2 v -1 h -1 v -1 z m 9,0 v 1 h -1 v 1 h 2 v -2 z m -5,1 v 1 h 2 v -1 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
</g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 290.99609,357 c -1.09865,0 -2,0.90134 -2,2 0,1.09866 0.90135,2 2,2 1.09866,0 2,-0.90134 2,-2 0,-1.09866 -0.90134,-2 -2,-2 z"
- id="circle24448"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 493.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.008,4.00586 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4.5 v 4.50195 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path24264-0"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ sodipodi:nodetypes="cccccccccccc" />
+ </g>
+ <g
+ id="g113472"
+ style="display:inline;enable-background:new"
+ inkscape:label="P-23">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 472.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.006,3.50586 -3.49804,0.002 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path24338-8"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccc" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24513"
- transform="matrix(0,1,1,0,-152.00318,47.006352)">
+ id="g25815"
+ inkscape:label="P-22">
<g
- id="g24612"
+ transform="translate(-230.996,-1801)"
+ id="g24435-3"
+ style="display:inline;fill:#ffffff;enable-background:new">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccacccaccccc"
+ inkscape:connector-curvature="0"
+ id="rect24419-6"
+ transform="translate(230.996,1801)"
+ d="m 447.00391,325.99805 v 2 h 1 v -1 h 1 v -1 z m 4,0 v 1 h 2 v -1 z m 4,0 v 1 h 2 v -1 z m 4,0 v 1 h 1 v 1 h 1 v -2 z m -12,4 v 2 h 1 v -2 z m 13,0 v 2 h 1 v -2 z m -13,4 v 2 h 1 v -2 z m 13,0 v 2 h 1 v -2 z m -13,4 v 2 h 2 v -1 h -1 v -1 z m 13,0 v 1 h -1 v 1 h 2 v -2 z m -9,1 v 1 h 2 v -1 z m 4,0 v 1 h 2 v -1 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ </g>
+ </g>
+ <g
+ id="g25466"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(624,-1280)"
+ inkscape:label="P-13">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -365.49219,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 2.63867 c 0.0948,-0.3549 0.23771,-0.6892 0.42188,-1 z m 9.92383,0 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -9.92383,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06055 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.34571,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.34571,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
+ id="path25334"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ <circle
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="circle25338"
+ cx="359"
+ cy="-1613.0002"
+ r="1.5"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ transform="scale(-1)" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,-157.001,-1280)"
+ id="g25455"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="P-12">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path25451"
+ d="m -406.5,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 3.93164,3 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 h 7.63867 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0.42188,3 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 8.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -4.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <circle
+ transform="scale(1,-1)"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ r="1.5"
+ cy="-1613.0002"
+ cx="-406"
+ id="circle25453"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ </g>
+ <g
+ id="g25449"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(624,-1280)"
+ inkscape:label="P-11">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -406.5,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 3.93164,3 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 h 7.63867 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0.42188,3 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 8.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -4.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
+ id="path25345"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ <circle
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="circle25349"
+ cx="-406"
+ cy="-1613.0002"
+ r="1.5"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ transform="scale(1,-1)" />
+ </g>
+ <g
+ transform="matrix(1,0,0,-1,645,1946)"
+ id="g25439"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="P-10">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path25435"
+ d="m -449.5,1609 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06836 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.35352,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 3.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <circle
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ r="1.5"
+ cy="1608"
+ cx="-443"
+ id="circle25437"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ </g>
+ <g
+ id="g25433"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(624,-1280)"
+ inkscape:label="P-9">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -449.5,1609 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06836 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.35352,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 3.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
+ id="path25304"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ <circle
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="circle25308"
+ cx="-443"
+ cy="1608"
+ r="1.5"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96" />
+ </g>
+ <g
+ transform="rotate(180,670.505,476.5)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g9316-9"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="P-8">
+ <g
+ transform="translate(438,704)"
+ id="g8254-6"
+ style="fill:#ffffff" />
+ <g
+ style="fill:#ffffff;stroke-width:1.09492"
+ id="g8219-5"
+ transform="matrix(0.992171,0,0,0.840722,457.696,698.426)" />
+ <g
+ id="g8268-6"
+ transform="rotate(90,613.505,483.505)"
style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 142.49609,347.00195 c -1.17351,0 -2.15665,0.82286 -2.42187,1.91797 1.14862,0.70733 2.04128,1.7894 2.50586,3.07422 1.33547,-0.0457 2.41601,-1.14613 2.41601,-2.49219 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 0.50196,8 c -1.65181,0 -3.00196,1.35015 -3.00196,3.00196 0,1.65181 1.35015,3.00195 3.00196,3.00195 1.65181,0 3.00195,-1.35014 3.00195,-3.00195 0,-1.65181 -1.35014,-3.00196 -3.00195,-3.00196 z"
- transform="matrix(0,1,1,0,-47.006352,152.00318)"
- id="circle24338"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 2.503906 l -2.5,0.0039 a 0.50005,0.50005 0 1 0 0,1 l 3,-0.0039 a 0.50005,0.50005 0 0 0 0.5,-0.5 V -90.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 2.00781,3.015624 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m 5,0 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z m -7.00781,1.986329 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.505859 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.505859 z"
+ id="path8265-4"
inkscape:connector-curvature="0" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 160.5,327 c -0.8223,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.6777,1.5 1.5,1.5 h 5 c 0.8224,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.6776,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
+ transform="rotate(180,670.505,476.5)"
+ id="rect8324-7-9-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-1022,-287)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g9304-8"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="P-7">
+ <g
+ transform="translate(419,704)"
+ id="g8292-1"
+ style="fill:#ffffff">
<path
- id="circle24481"
- transform="matrix(0,1,1,0,-47.006347,152.00318)"
- d="m 136.9668,349.03125 c -2.73852,0 -4.97071,2.23218 -4.97071,4.9707 0,2.73853 2.23219,4.96875 4.97071,4.96875 0.74568,0 1.44822,-0.1767 2.08398,-0.47265 -0.0209,-0.16376 -0.0508,-0.32518 -0.0508,-0.49414 0,-0.2598 0.0297,-0.51312 0.0781,-0.75977 -0.60661,0.39452 -1.33048,0.62695 -2.11132,0.62695 -2.14404,0 -3.8711,-1.72509 -3.8711,-3.86914 0,-2.14404 1.72706,-3.87109 3.8711,-3.87109 2.14405,0 3.86914,1.72705 3.86914,3.87109 0,0.23797 -0.0296,0.46946 -0.0703,0.69532 0.35109,-0.23908 0.74721,-0.40722 1.16407,-0.52539 0.002,-0.0568 0.008,-0.11267 0.008,-0.16993 0,-2.73852 -2.23217,-4.9707 -4.9707,-4.9707 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path8290-6"
inkscape:connector-curvature="0" />
</g>
+ <g
+ transform="translate(435,709)"
+ id="g8299-5"
+ style="fill:#ffffff" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 134.5,330 c -0.8224,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.6776,1.5 1.5,1.5 h 5 c 0.8224,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.6776,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
+ transform="translate(1022,287)"
+ id="rect8324-7-9"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g22255"
- transform="translate(-1.8536743e-6,-20.999994)">
+ transform="translate(-1021,-287)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g9296-0"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="P-6">
+ <g
+ id="g8328-6"
+ transform="translate(415,710)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 115.5,331 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 4 c 0,0.82235 0.67765,1.5 1.5,1.5 h 5 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -4 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m 0,5 h 5 a 0.50005,0.50005 0 1 1 0,1 h -5 a 0.50005,0.50005 0 1 1 0,-1 z"
+ transform="translate(606,-423)"
+ id="rect8324-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g8338-5"
+ transform="rotate(90,593.005,462.005)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 746.49219,-91.007812 A 0.50005,0.50005 0 0 0 746,-90.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-85.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 0,5 A 0.50005,0.50005 0 0 0 746,-80.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path8336-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12793"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="P-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40018749;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 521.5,287 c -5.3,0 -9.5,4.7037 -9.5,9.5 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 c 0,-1.05 0.68155,-2.47832 1.73828,-3.59375 C 518.79501,291.79082 520.19444,291 521.5,291 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0,1 h 0.5 v 2 h -0.5 c -1.69444,0 -3.29501,0.95918 -4.48828,2.21875 C 515.81845,293.47832 515,295.05 515,296.5 v 0.5 h -2 v -0.5 c 0,-4.2037 3.8,-8.5 8.5,-8.5 z"
- id="path21998"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 92.496094,325.99414 a 0.50005,0.50005 0 0 0 -0.382813,0.82227 l 4.5,5.5 a 0.50005,0.50005 0 0 0 0.773438,0 l 4.500001,-5.5 a 0.50005,0.50005 0 1 0 -0.77344,-0.63282 L 97,331.21094 92.886719,326.18359 a 0.50005,0.50005 0 0 0 -0.390625,-0.18945 z"
+ id="path10173-4"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 512.5,263 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 6.60938 c 0.29756,-0.51189 0.62592,-1.00687 1,-1.46876 V 264 h 2 v 2.71875 c 0.32103,-0.24305 0.65292,-0.47168 1,-0.67969 V 263.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- transform="translate(1.8536743e-6,20.999994)"
- id="path22786"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 91.25,334 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.683851,0 1.25,-0.56615 1.25,-1.25 v -3.5 C 96,334.56615 95.433851,334 94.75,334 Z m 8,0 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.68385,0 1.25,-0.56615 1.25,-1.25 v -3.5 c 0,-0.68385 -0.56615,-1.25 -1.25,-1.25 z m -7.75,4 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z m 8,0 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z"
+ id="rect13911"
inkscape:connector-curvature="0" />
</g>
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- id="rect40784"
- width="16"
- height="16"
- x="110"
- y="262" />
- <g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g22709"
- transform="matrix(0,-1,-1,0,408.99494,408.99999)">
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g14256"
+ transform="translate(-21)"
+ style="display:inline;opacity:0.4;fill:#ffffff;enable-background:new"
+ inkscape:label="P-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 153.49219,289.73828 A 0.50005,0.50005 0 0 0 153,290.24414 l -0.008,7.26172 a 0.50005,0.50005 0 0 0 0.50195,0.50195 l 7.25586,-0.0137 a 0.50005,0.50005 0 1 0 0,-1 l -6.75781,0.0137 0.008,-6.76172 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path21430-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 92.496094,325.99414 a 0.50005,0.50005 0 0 0 -0.382813,0.82227 l 4.5,5.5 a 0.50005,0.50005 0 0 0 0.773438,0 l 4.500001,-5.5 a 0.50005,0.50005 0 1 0 -0.77344,-0.63282 L 97,331.21094 92.886719,326.18359 a 0.50005,0.50005 0 0 0 -0.390625,-0.18945 z"
+ id="path14250"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 115.04297,242 -4,4 h 9.95117 l 0.006,9.95703 3.85352,-3.85351 L 125,251.95703 124.99414,242 Z m 0.41406,1 h 7.9707 l -2,2 h -7.9707 z m 8.53711,0.56641 0.006,7.97656 -2,2 -0.006,-7.97656 z"
- transform="matrix(0,-1,-1,0,408.99999,408.99494)"
- id="path21432-2"
+ id="path14254"
+ d="m 91.25,334 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.683851,0 1.25,-0.56615 1.25,-1.25 v -3.5 C 96,334.56615 95.433851,334 94.75,334 Z m 8,0 c -0.683851,0 -1.25,0.56615 -1.25,1.25 v 3.5 c 0,0.68385 0.566149,1.25 1.25,1.25 h 3.5 c 0.68385,0 1.25,-0.56615 1.25,-1.25 v -3.5 c 0,-0.68385 -0.56615,-1.25 -1.25,-1.25 z m -7.75,4 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z m 8,0 h 2 1 a 0.50005,0.50005 0 1 1 0,1 h -1 -2 a 0.50005,0.50005 0 1 1 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g22406"
- transform="translate(20.999998,-20.999994)">
+ id="g120746"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-26">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 240.49805,288 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 241,288.5 A 0.50005,0.50005 0 0 0 240.49805,288 Z M 240,289.00195 l -0.008,8.00586 h -2 v -8.00195 z"
- id="path22383"
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 541.77363,306 a 1.0001,1.0001 0 0 0 -0.41211,0.0781 l -4.74024,2 a 1.0004654,1.0004654 0 1 0 0.77735,1.84376 l 1.54883,-0.65235 -2.69532,5.375 -2.78906,-2.30078 a 1.50015,1.50015 0 1 0 -1.9082,2.3125 l 4.24023,3.5 a 1.50015,1.50015 0 0 0 2.29688,-0.48437 l 3.53711,-7.0586 0.41015,1.63086 a 1.0001,1.0001 0 1 0 1.93946,-0.48828 l -1.25977,-5 A 1.0001,1.0001 0 0 0 541.77363,306 Z"
+ id="path25427-8" />
+ </g>
+ <g
+ id="g120749"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-25">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 520.51395,306 a 0.50005,0.50005 0 0 0 -0.23633,0.0527 l -4,2 a 0.50005,0.50005 0 1 0 0.44532,0.89454 l 2.8164,-1.40821 -4.20508,8.1875 -4.52148,-3.61718 a 0.50024018,0.50024018 0 1 0 -0.625,0.78124 l 5,4 a 0.50005,0.50005 0 0 0 0.75781,-0.1621 l 4.4375,-8.64063 0.63281,2.5332 a 0.50005,0.50005 0 1 0 0.96876,-0.24218 l -1,-4 A 0.50005,0.50005 0 0 0 520.51395,306 Z"
+ id="path25488-0"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g120743"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 250.49805,284 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 251,284.5 A 0.50005,0.50005 0 0 0 250.49805,284 Z M 250,285.00195 l -0.008,8.00586 h -2 v -8.00195 z M 245.49805,286 l -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 246,286.5 A 0.50005,0.50005 0 0 0 245.49805,286 Z M 245,287.00195 l -0.008,8.00586 h -2 v -8.00195 z"
- id="path22387"
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 490,307 c -0.55226,6e-5 -0.99994,0.44774 -1,1 v 8 c 6e-5,0.55226 0.44774,0.99994 1,1 h 12 c 0.55226,-6e-5 0.99994,-0.44774 1,-1 v -8 c -6e-5,-0.55226 -0.44774,-0.99994 -1,-1 z m 6,1 a 4,4 0 0 1 4,4 4,4 0 0 1 -4,4 4,4 0 0 1 -4,-4 4,4 0 0 1 4,-4 z"
+ id="path25011-0" />
+ </g>
+ <g
+ transform="translate(1055,731)"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="g25234-0"
+ inkscape:label="O-23">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -580,-424 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z m 0,1 c 2.21506,0 4,1.78494 4,4 0,2.21506 -1.78494,4 -4,4 -2.21506,0 -4,-1.78494 -4,-4 0,-2.21506 1.78494,-4 4,-4 z m -0.52148,1 a 0.50005,0.50005 0 0 0 -0.084,0.0117 c -1.2099,0.24373 -2.15796,1.187 -2.38476,2.38867 a 0.50005,0.50005 0 1 0 0.98242,0.18555 c 0.15048,-0.79727 0.77874,-1.42839 1.59961,-1.59375 A 0.50005,0.50005 0 0 0 -580.52148,-422 Z"
+ id="path25232-0"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g22579"
- transform="matrix(-1,0,0,1,571.99995,-62.999994)">
+ transform="translate(230.768,210.171)"
+ style="display:inline;enable-background:new"
+ id="g4087_GP_lineart"
+ inkscape:label="O-21">
<g
- style="opacity:1;fill:#ffffff"
- id="g22529">
+ id="g4082">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 268.5,242 c -1.88693,0 -3.42464,1.51084 -3.48828,3.38281 -0.009,0.0385 -0.0124,0.0778 -0.0117,0.11719 -4.1e-4,0.0117 -4.1e-4,0.0234 0,0.0352 V 249 h -3.5 c -0.0381,-4.2e-4 -0.0761,0.004 -0.11328,0.0117 C 259.5129,249.07334 258,250.61174 258,252.5 c 0,1.88693 1.51084,3.42464 3.38281,3.48828 0.0385,0.009 0.0778,0.0124 0.11719,0.0117 h 7 c 0.92807,0 1.81837,-0.36915 2.47461,-1.02539 C 271.63085,254.31837 272,253.42807 272,252.5 v -7 c 7.2e-4,-0.0394 -0.003,-0.0787 -0.0117,-0.11719 C 271.92462,243.51084 270.38693,242 268.5,242 Z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 -4.1e-4,0.0117 -4.1e-4,0.0234 0,0.0352 V 252.5 c 0,0.66323 -0.26345,1.2986 -0.73242,1.76758 C 269.7986,254.73655 269.16323,255 268.5,255 h -7 c -1.38663,0 -2.5,-1.11337 -2.5,-2.5 0,-1.38663 1.11337,-2.5 2.5,-2.5 h 3.75 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.14648 l 0.25,-0.25 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -3.75 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z"
- transform="matrix(-1,0,0,1,571.99995,62.999994)"
- id="path22488"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="cccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path12456-6"
+ mask="none"
+ d="m 198.0253,98.27163 v 1.5 h 1 v -1.5 z m 0,2.5 v 2 h 1 v -2 z m 0,3 v 1.2793 l -2.58594,2.35156 0.67188,0.73828 2.60351,-2.36719 0.49027,-0.002 c 0.82475,0 0.82408,-1 0,-1 h -0.17972 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path4185"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.10423;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 207.2397,99.568306 c -0.33768,-0.02992 -0.70751,0.105959 -1.01625,0.406518 l -0.51139,0.495896 c -0.13287,0.12942 -0.13287,0.34092 0,0.47035 l 2.04339,1.98784 c 0.13292,0.12938 0.3479,0.12938 0.48082,0 l 0.50922,-0.49802 c 0.3087,-0.30067 0.44811,-0.65869 0.41741,-0.98755 -0.0307,-0.32884 -0.20718,-0.60186 -0.41741,-0.80663 l -0.67969,-0.661886 c -0.21026,-0.204768 -0.48842,-0.37662 -0.8261,-0.406518 z m -2.31222,1.800554 c -0.0883,9.4e-4 -0.17353,0.0367 -0.23603,0.0979 l -4.25293,4.14168 c -0.0434,0.0426 -0.0749,0.095 -0.0896,0.15324 l -0.67969,2.65189 c -0.0614,0.24217 0.16235,0.46285 0.41088,0.40225 l 2.72308,-0.66402 c 0.0599,-0.0144 0.11363,-0.0428 0.15735,-0.0851 l 4.2551,-4.14382 c 0.13286,-0.12943 0.13286,-0.33881 0,-0.46825 l -2.0434,-1.98784 c -0.0651,-0.0634 -0.15267,-0.0994 -0.24478,-0.0979 z" />
+ <path
+ id="path12458-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 198.52539,94.771484 c -0.1326,2.7e-5 -0.25978,0.05272 -0.35351,0.146485 l -3,3 c -0.0938,0.09376 -0.14646,0.220915 -0.14649,0.353515 v 9.999996 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.50158 c 0.72806,0 0.76638,-1.01916 0,-1 h -2.00158 v -8.999996 h 9 v 0.186392 c 0,0.766385 1,0.767345 1,0 v -0.47936 l 2,-2 v 0.907841 c 0,0.708905 1,0.709935 1,0 v -2.114873 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.20703,1 h 8.58594 l -2,2 h -8.58594 z"
+ sodipodi:nodetypes="ccccccsccccssccsscccccccc" />
</g>
+ </g>
+ <g
+ id="g3380"
+ inkscape:label="O-20"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 303.49219,307.99219 A 0.50005,0.50005 0 0 0 303,308.5 v 6.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 303.58203,316 H 310.5 a 0.50005,0.50005 0 1 0 0,-1 H 304 v -6.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path22537"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ d="m 417.92349,304.73964 c -0.7818,-0.0644 -0.86293,1.09626 -0.0796,1.1383 l 0.41758,0.0202 c 0.78182,0.0644 0.86296,-1.09626 0.0796,-1.13831 z m -7.87437,1.29265 c -0.65325,0.42724 0.0163,1.38626 0.65667,0.94062 l 0.34001,-0.23929 c 0.65327,-0.42727 -0.0163,-1.38631 -0.65662,-0.94061 z m 5.26412,-0.10772 c 0.785,-0.0185 0.73895,-1.18175 -0.0451,-1.14009 -0.6811,-0.0652 -1.43225,-0.0213 -2.22341,0.0851 -0.785,0.0185 -0.73896,1.18176 0.0451,1.14011 0.8585,-0.10954 1.60282,-0.14009 2.22342,-0.0852 z m -5.74172,5.34858 c -0.17789,-0.75187 -1.32618,-0.47161 -1.12597,0.27482 -0.008,0.72815 0.18352,1.43475 0.53595,2.12392 0.17789,0.75187 1.32617,0.47159 1.12598,-0.27483 -0.40688,-0.70818 -0.47775,-1.41605 -0.53596,-2.12391 z m 1.14987,4.81425 c 0.55238,0.5479 1.3799,-0.2833 0.81165,-0.81524 l -0.30437,-0.28193 c -0.55238,-0.54789 -1.37991,0.2833 -0.81163,0.81524 z m 2.55883,0.11471 c -0.78112,0.0716 -0.65484,1.22767 0.12391,1.13446 0.79706,0.0708 1.5429,0.0136 2.2124,-0.23372 0.7811,-0.0716 0.65482,-1.22768 -0.12391,-1.13445 -0.66955,0.35373 -1.42049,0.37687 -2.2124,0.23371 z m 4.35036,-1.24066 c 0.39775,-0.66505 -0.63058,-1.23994 -1.00859,-0.56384 l -0.19953,0.36135 c -0.39776,0.66506 0.63057,1.23995 1.00857,0.56383 z m -1.53457,-4.82813 c -0.44444,-0.63566 -1.409,0.0364 -0.94666,0.65956 0.53116,0.53126 0.99257,1.10609 1.28624,1.78569 0.44445,0.63565 1.40902,-0.0364 0.94667,-0.65956 -0.24301,-0.74231 -0.69323,-1.32054 -1.28625,-1.78569 z m -2.73483,-1.49223 c -0.72218,-0.30138 -1.16808,0.7761 -0.43732,1.05681 l 0.39025,0.14758 c 0.7222,0.30141 1.1681,-0.7761 0.43732,-1.0568 z m -7.60223,1.91562 c -0.52109,0.57678 0.37464,1.33651 0.87855,0.74515 l 0.26685,-0.31654 c 0.52111,-0.57679 -0.37465,-1.33654 -0.87854,-0.74516 z m 1.15912,7.09355 c -0.1906,-0.74845 -1.33363,-0.44917 -1.12109,0.29354 l 0.11543,0.39523 c 0.19062,0.74845 1.33365,0.44917 1.12109,-0.29354 z m -0.68592,-4.36328 c -0.0858,-0.76698 -1.25912,-0.62352 -1.15127,0.14077 -0.065,0.75431 -0.008,1.50847 0.28594,2.26232 0.0859,0.76696 1.25912,0.62352 1.15129,-0.14076 -0.28468,-0.81162 -0.29126,-1.53878 -0.28596,-2.26233 z m 1.97398,-4.7241 c -0.77314,0.13162 -0.55483,1.27463 0.21417,1.12135 0.7762,-0.30633 1.5005,-0.42412 2.18687,-0.40397 0.77313,-0.13163 0.55482,-1.27462 -0.21418,-1.12137 -0.74152,0.0229 -1.4733,0.13255 -2.18686,0.40399 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.15052;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.2;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path4101-2-6-9-1_GP_dotdash" />
+ </g>
+ <g
+ transform="translate(167.426,209.695)"
+ style="display:inline;enable-background:new"
+ id="g7880_GP_lenght"
+ inkscape:label="O-19">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 224.38607,100.78271 c -0.15574,0.005 -0.30353,0.0699 -0.41211,0.18164 l -2.05673,2.00254 c -0.62065,0.56444 0.28322,1.46831 0.84766,0.84765 l 2.05673,-2.00254 c 0.39088,-0.38144 0.1104,-1.04428 -0.43555,-1.02929 z"
+ id="path15289-7-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path15289-7-6-5"
+ d="m 225.6621,95.349988 c -0.67621,-0.0096 -0.67621,1.009611 0,1 h 2.79493 c -1.0479,1.117288 -1.7641,1.668027 -2.82812,2.732043 -0.62065,0.56444 0.28321,1.468319 0.84765,0.847657 1.06063,-1.101282 1.59202,-1.777197 2.68554,-2.870716 v 2.791016 c -0.01,0.676162 1.00956,0.676162 1,0 v -4 c -3e-5,-0.276131 -0.22387,-0.499973 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path15289-7-6-5-2"
+ d="m 221.03217,109.33958 c 0.67621,0.01 0.67621,-1.00961 0,-1 h -2.79493 c 1.0479,-1.11729 1.7641,-1.66802 2.82812,-2.73204 0.62065,-0.56444 -0.28321,-1.46832 -0.84765,-0.84766 -1.06063,1.10128 -1.59202,1.7772 -2.68554,2.87072 v -2.79102 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 4 c 3e-5,0.27613 0.22387,0.49998 0.5,0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g28812"
+ transform="rotate(180,328,312.5)"
+ inkscape:label="O-15">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 319.49219,315 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -4,4 a 0.50005,0.50005 0 0 0 0,0.70704 l 4,4 a 0.50005,0.50005 0 0 0 0.36133,0.14648 0.50005,0.50005 0 0 0 0.34571,-0.14648 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -0.18164,-0.18164 -3.81836,-3.81836 A 0.50005,0.50005 0 0 0 319.49219,315 Z M 319.5,316.20703 322.79297,319.5 319.5,322.79297 316.20703,319.5 Z M 311,319 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 0.5,4 c -0.12794,0 -0.25588,0.0489 -0.35352,0.14648 l -3,3 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.0957,0.0957 0.22603,0.14855 0.36133,0.14648 0.12989,-0.002 0.25387,-0.0546 0.34571,-0.14648 l 3,-3 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 C 313.75588,323.04889 313.62794,323 313.5,323 Z m 4.5,3 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z"
+ transform="rotate(180,333,317.5)"
+ id="path28715"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="matrix(-1,0,0,1,550.99293,-20.999994)"
- id="g22139">
+ id="g6603"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="O-12">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 310.5,287 -10.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 311,287.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,9.00781 h -9 v -9.00195 z"
- id="path22135"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 237.49219,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 306 h 3 v 12 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -1.5 v -12 h 3 v 1.5 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 7,6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 1 0 1,0 V 312 h 2 v 6 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 h -0.5 v -6 h 2 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path6924-7"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g120719"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-11">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 300.5,284 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z m 12.99219,2.99219 A 0.50005,0.50005 0 0 0 313,287.5 l -0.008,10.00586 a 0.50005,0.50005 0 1 0 1,0.002 L 314,287.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path22141"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 216.49219,305 a 0.50005,0.50005 0 1 0 0,1 H 218 v 6.00391 c 0,2.19985 1.79782,3.99206 4,3.99609 h 1 a 0.50005,0.50005 0 0 0 0.002,0 c 2.20199,-0.005 3.998,-1.79624 3.998,-3.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 1 0 0,1 H 226 v 6.00391 c 0,1.65832 -1.33799,2.99265 -3.00195,2.99609 H 222 c -1.66382,-0.003 -3,-1.33777 -3,-2.99609 V 306 h 1.49219 a 0.50005,0.50005 0 1 0 0,-1 z m 1,13 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10901"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g22221"
- transform="translate(20.999998,-20.999994)">
+ id="g120716"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 48.5,267 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 9 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 13 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -6 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 54 v -2.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 0.5,1 h 4 v 2 h -4 z m 0,3 h 2 v 2 h -2 z m 3,0 h 4 v 2 h -4 z m 5,0 h 4 v 2 h -4 z m -8,3 h 4 v 2 h -4 z m 5,0 h 4 v 2 h -4 z m 5,0 h 2 v 2 h -2 z"
- transform="translate(-20.999998,20.999994)"
- id="rect22184"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 201.49219,305 a 0.50005,0.50005 0 1 0 0,1 h 2.5039 l -0.002,0.14258 -4.95898,11.4082 a 0.50005,0.50005 0 0 0 -0.041,0.21289 L 199,318 h -2.50781 a 0.50005,0.50005 0 1 0 0,1 h 6 a 0.50005,0.50005 0 1 0 0,-1 H 200 a 0.50005,0.50005 0 0 0 0,-0.0137 l -0.004,-0.13867 4.95508,-11.39844 a 0.50005,0.50005 0 0 0 0.041,-0.19141 L 204.99609,306 h 2.4961 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10892"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g120740"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 40.5,284 a 0.50005,0.50005 0 0 1 0.5,0.5 v 3 a 0.50005,0.50005 0 0 1 -0.5,0.5 h -5 A 0.50005,0.50005 0 0 1 35,287.5 v -3 a 0.50005,0.50005 0 0 1 0.5,-0.5 z m -0.5,1 h -4 v 2 h 4 z"
- id="rect22200"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 177,305 a 1.0001,1.0001 0 0 0 -1,1 v 5.83203 a 1.0001,1.0001 0 0 0 0,0.32617 V 318 a 1.0001,1.0001 0 0 0 1,1 h 6 c 2.19729,0 4,-1.80271 4,-4 0,-1.76747 -1.1852,-3.22799 -2.78516,-3.75195 C 184.67235,310.59788 185,309.84948 185,309 c 0,-2.19729 -1.80271,-4 -4,-4 z m 1,2 h 3 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -3 z m 0,6 h 3 2 c 1.11641,0 2,0.88359 2,2 0,1.11641 -0.88359,2 -2,2 h -5 z"
+ id="path10949"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g21692"
- transform="translate(-1.8536743e-6,-41.999984)">
+ id="g60277"
+ inkscape:label="O-8">
<g
- transform="translate(-63)"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#f9f9f9;enable-background:new"
- id="g21667">
+ id="g120737"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:6.5999999;stroke-opacity:1;marker:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 145.49219,241.99219 A 0.50005,0.50005 0 0 0 145,242.5 c 0,1.27778 -0.82701,2.37965 -2.66602,3.44141 -1.66335,0.96034 -4.28314,1.19403 -6.30078,1.06054 -0.9786,-0.0647 -1.78811,-0.30625 -2.3125,-0.61133 -0.52058,-0.30284 -0.71591,-0.62257 -0.71875,-0.88476 0.003,-0.26222 0.19817,-0.58387 0.71875,-0.88672 0.5244,-0.30506 1.3339,-0.54463 2.3125,-0.60937 1.74084,-0.11517 3.90302,0.0169 5.24414,0.6875 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 c -1.65888,-0.82943 -3.92118,-0.91239 -5.75586,-0.79101 -1.10098,0.0728 -2.04234,0.3336 -2.74805,0.74414 -0.63776,0.37101 -1.097,0.90981 -1.18359,1.55273 A 0.50005,0.50005 0 0 0 132,245.5 c 0,0.002 0.002,0.004 0.002,0.006 -1e-5,0.002 -0.002,0.004 -0.002,0.006 a 0.50005,0.50005 0 0 0 0.0352,0.18945 0.50005,0.50005 0 0 0 0.002,0.006 c 0.0881,0.64105 0.54525,1.17861 1.18164,1.54883 0.70571,0.41055 1.64707,0.66937 2.74805,0.74219 2.1415,0.14167 4.88621,-0.0477 6.86718,-1.19141 C 144.82884,245.65491 146,244.22222 146,242.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -0.27539,5.25195 a 0.50005,0.50005 0 0 0 -0.4375,0.67578 C 144.90088,248.25504 145,248.58141 145,249 c 0,1.83333 -0.82701,2.87965 -2.66602,3.94141 -1.66335,0.96034 -4.28314,1.19403 -6.30078,1.06054 -0.9786,-0.0647 -1.78811,-0.30625 -2.3125,-0.61133 -0.52058,-0.30284 -0.71591,-0.62257 -0.71875,-0.88476 0.003,-0.26222 0.19817,-0.58387 0.71875,-0.88672 0.5244,-0.30506 1.3339,-0.54463 2.3125,-0.60937 1.74084,-0.11517 3.90302,0.0169 5.24414,0.6875 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 c -1.65888,-0.82943 -3.92118,-0.91239 -5.75586,-0.79101 -1.10098,0.0728 -2.04234,0.3336 -2.74805,0.74414 -0.63776,0.37101 -1.097,0.90981 -1.18359,1.55273 A 0.50005,0.50005 0 0 0 132,252.5 c 0,0.002 0.002,0.004 0.002,0.006 -1e-5,0.002 -0.002,0.004 -0.002,0.006 a 0.50005,0.50005 0 0 0 0.0371,0.19531 c 0.0881,0.64105 0.54525,1.17861 1.18164,1.54883 0.70571,0.41055 1.64707,0.66937 2.74805,0.74219 2.1415,0.14167 4.88621,-0.0477 6.86718,-1.19141 1.96806,-1.13625 3.12917,-2.60303 3.16016,-4.72266 A 0.50005,0.50005 0 0 0 146,249 a 0.50005,0.50005 0 0 0 -0.0137,-0.12695 c -0.0205,-0.51808 -0.14222,-0.95284 -0.26563,-1.29297 a 0.50005,0.50005 0 0 0 -0.5039,-0.33594 z m 0.043,7 a 0.50005,0.50005 0 0 0 -0.4336,0.76953 c 0,0 0.17383,0.35663 0.17383,0.51953 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.59989 -0.32617,-1.04687 -0.32617,-1.04687 a 0.50005,0.50005 0 0 0 -0.41406,-0.24219 z"
- transform="translate(63.000002,41.999984)"
- id="path21655"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 155.49219,314 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path11052"
inkscape:connector-curvature="0" />
</g>
<g
- id="g21673"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#f9f9f9;enable-background:new"
- transform="translate(-63,6)" />
+ id="g120734"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 153.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect11050"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g60283"
+ inkscape:label="O-7">
+ <g
+ id="g120731"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 134.49219,310 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path11048"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g120728"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 132.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect11046"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g60289"
+ inkscape:label="O-6">
+ <g
+ id="g120725"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 113.49219,307 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 8.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10977"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g120722"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 111.5,305 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 13 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 13 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -13 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect10983"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 219.50391,243 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 218.38224,244.61833 217.33333,245 216.5,245 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0996,-0.008 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 225.50391,243 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 224.38224,244.61833 223.33333,245 222.5,245 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 219.50391,243 Z m 1,5 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 219.38224,249.61833 218.33333,250 217.5,250 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0859,-0.006 0.50005,0.50005 0 0 0 0.0137,-0.002 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 226.50391,248 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 225.38224,249.61833 224.33333,250 223.5,250 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 220.50391,248 Z m -1,5 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 218.38224,254.61833 217.33333,255 216.5,255 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0996,-0.008 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 225.50391,253 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 224.38224,254.61833 223.33333,255 222.5,255 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 219.50391,253 Z"
- id="path21858"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 97.689453,242.01172 c -0.394683,0.0302 -0.787753,0.12022 -1.167969,0.27148 C 95.00062,242.88827 94,244.36319 94,246 a 0.50005,0.50005 0 0 0 0.01563,0.13281 c -0.365184,0.0927 -0.722816,0.22834 -1.058594,0.42774 -1.441397,0.85595 -2.170881,2.51688 -1.878906,4.14453 -0.687144,0.57705 -1.108155,1.44799 -1.076172,2.39648 0.05016,1.48769 1.192146,2.71921 2.671875,2.88086 1.398175,0.15274 2.699752,-0.69789 3.152344,-2.00781 0.896041,0.0388 1.769696,-0.22225 2.498047,-0.74609 1.073726,0.85551 2.557876,1.01607 3.789066,0.37695 1.30171,-0.67573 2.04374,-2.09602 1.85742,-3.55078 -0.16328,-1.27499 -1.01006,-2.34261 -2.17968,-2.80664 0.45466,-1.38242 0.13144,-2.9211 -0.88477,-3.9961 -0.56221,-0.59473 -1.277273,-0.98709 -2.042974,-1.15625 -0.38285,-0.0846 -0.779145,-0.11418 -1.173828,-0.084 z m 0.521485,0.99609 c 0.734455,0.0517 1.440532,0.37287 1.968752,0.93164 0.84514,0.89404 1.0593,2.20845 0.54101,3.32422 a 0.50005,0.50005 0 0 0 -0.0527,0.2168 0.50005,0.50005 0 0 0 0.38672,0.58203 c 1.02426,0.23341 1.79232,1.07713 1.92578,2.11914 0.13345,1.04201 -0.39575,2.0531 -1.32813,2.53711 -0.93238,0.48401 -2.064441,0.33572 -2.83984,-0.37305 a 0.50005,0.50005 0 0 0 -0.203125,-0.11914 0.50005,0.50005 0 0 0 -0.28125,-0.0977 0.50005,0.50005 0 0 0 -0.351563,0.1289 c -0.657713,0.57559 -1.533142,0.83597 -2.398437,0.71289 a 0.50008765,0.50008765 0 0 0 -0.542969,0.33008 0.50005,0.50005 0 0 0 -0.09766,0.19727 c -0.248328,0.96717 -1.16166,1.59867 -2.154297,1.49023 -0.992636,-0.10844 -1.747599,-0.92195 -1.78125,-1.91992 -0.02307,-0.68418 0.30371,-1.29829 0.824219,-1.67774 a 0.50005,0.50005 0 0 0 0.166016,-0.11718 c 0.198328,-0.11547 0.417989,-0.19976 0.65625,-0.24219 a 0.50005,0.50005 0 0 0 -0.08984,-0.99414 0.50005,0.50005 0 0 0 -0.08398,0.01 c -0.160251,0.0285 -0.313314,0.0746 -0.46289,0.12695 -0.0646,-1.10299 0.477746,-2.17237 1.457031,-2.75391 1.157707,-0.68748 2.624443,-0.52021 3.599609,0.4082 a 0.50009764,0.50009764 0 0 0 0.689453,-0.7246 c -0.648161,-0.6171 -1.462878,-0.98259 -2.308593,-1.07813 -0.148752,-0.017 -0.299358,-0.0157 -0.449254,-0.0158 A 0.50005,0.50005 0 0 0 95,246 c 0,-1.23027 0.747501,-2.33232 1.890625,-2.78711 0.428672,-0.17055 0.879639,-0.23611 1.320313,-0.20508 z"
- id="path21574"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
+ transform="translate(-462.007,-315)"
+ id="g10872"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23463">
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="O-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 10.492188,241.99219 A 0.50005,0.50005 0 0 0 10.417969,242 H 6.5 A 0.50005,0.50005 0 0 0 6,242.5 v 5 A 0.50005,0.50005 0 0 0 6.5,248 H 8 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 A 0.50005,0.50005 0 0 0 18,255.5 V 248 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 19.5,242 h -3.919922 a 0.50005,0.50005 0 0 0 -0.404297,0.11328 0.50005,0.50005 0 0 0 -0.01953,0.0156 0.50005,0.50005 0 0 0 -0.01758,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.03125,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 15,242.58203 V 243 c 0,0.71532 -0.380592,1.37478 -1,1.73242 -0.619409,0.35765 -1.380591,0.35765 -2,0 -0.619408,-0.35764 -1,-1.0171 -1,-1.73242 v -0.41992 a 0.50005,0.50005 0 0 0 -0.113281,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.03125,-0.0332 0.50005,0.50005 0 0 0 -0.0039,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.0039,-0.002 0.50005,0.50005 0 0 0 -0.320312,-0.11133 z M 7,243 h 3 c 0,1.07096 0.57257,2.06216 1.5,2.59766 0.927429,0.53549 2.072571,0.53549 3,0 0.92743,-0.5355 1.5,-1.5267 1.5,-2.59766 h 3 v 4 H 17.5 A 0.50005,0.50005 0 0 0 17,247.5 V 255 H 9 v -7.5 A 0.50005,0.50005 0 0 0 8.5,247 H 7 Z"
- id="path22384"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.2;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 552.5,621 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z M 552.5,624 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 4.05273,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91797 a 0.50005,0.50005 0 1 0 0,-1 z m 3.94727,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m -11,3 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z M 552.5,630 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 4.05273,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91797 a 0.50005,0.50005 0 1 0 0,-1 z m 3.94727,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m -11,3 a 0.50005,0.50005 0 1 0 0,1 h 1.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 4.02344,0 a 0.50005,0.50005 0 1 0 0,1 h 1.91601 a 0.50005,0.50005 0 1 0 0,-1 z m 3.9707,0 a 0.50005,0.50005 0 1 0 0,1 h 1.99805 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99805,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10870"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g22840"
- transform="translate(-1.8536743e-6,-19.999994)">
+ id="g120704"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 412,286 c 1.65601,0 3,1.37486 3,3.04688 0,1.67201 -1.34399,3.04687 -3,3.04687 -1.65601,0 -3,-1.37486 -3,-3.04687 C 409,287.37486 410.34399,286 412,286 Z m 0,1 c -1.10534,0 -2,0.90526 -2,2.04688 0,1.14161 0.89466,2.04687 2,2.04687 1.10534,0 2,-0.90526 2,-2.04687 C 414,287.90526 413.10534,287 412,287 Z"
- id="circle22836"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 69.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10850"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g120707"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-3">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999982;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 412,283 c -3.5093,0 -6,2.77253 -6,5.91992 V 296 h -0.96094 a 0.50004991,0.50004991 0 1 0 0,1 H 406.5 a 0.50004991,0.50004991 0 0 0 0.5,-0.5 v -7.58008 C 407,286.29196 409.01002,284 412,284 c 2.99076,0 5,2.29197 5,4.91992 V 296.5 a 0.50004991,0.50004991 0 0 0 0.5,0.5 h 1.46094 a 0.50004991,0.50004991 0 1 0 0,-1 H 418 v -7.08008 C 418,285.77251 415.50996,283 412,283 Z"
- id="path22838"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 48.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 7,3 a 0.50005,0.50005 0 1 0 0,1 h 5.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -7,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 7,3 a 0.50005,0.50005 0 1 0 0,1 h 5.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -7,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10852"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.95;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 54.951172,347 c -1.831463,0.10706 -3.628606,0.91857 -4.910156,2.35742 -2.943003,3.30422 -2.532587,8.31019 0.05078,11.44531 a 0.5501659,0.5501659 0 1 0 0.849609,-0.69921 c -2.251956,-2.73294 -2.615242,-7.16516 -0.07813,-10.01368 2.156081,-2.42072 6.066547,-2.73646 8.435547,-0.43164 1.937906,1.88542 2.205459,5.18464 0.267578,7.14453 -1.518438,1.53565 -4.123722,1.73043 -5.623047,0.11133 -1.098553,-1.18629 -1.217866,-3.2114 0.03516,-4.28515 0.40623,-0.34811 0.977609,-0.54432 1.501953,-0.52539 0.524344,0.0189 0.981344,0.22421 1.291015,0.67968 0.145266,0.21367 0.237116,0.58238 0.201172,0.86719 -0.03594,0.28481 -0.127716,0.44479 -0.371094,0.5332 a 0.55049551,0.55049551 0 1 0 0.375,1.03516 c 0.656421,-0.23845 1.015068,-0.85266 1.087891,-1.42969 0.07282,-0.57703 -0.06773,-1.15869 -0.384765,-1.625 -0.517269,-0.76081 -1.34716,-1.12886 -2.160157,-1.1582 -0.812997,-0.0293 -1.63015,0.25121 -2.257812,0.78906 -1.781519,1.52664 -1.618395,4.25452 -0.125,5.86719 1.955333,2.11153 5.283443,1.86538 7.21289,-0.0859 2.400922,-2.4282 2.076076,-6.41165 -0.283203,-8.70703 -1.417731,-1.37933 -3.283772,-1.9762 -5.115234,-1.86914 z"
- id="path23662-2"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 81.492188,347.13672 c -0.442306,0.006 -0.696492,0.5058 -0.441407,0.86719 0.49808,0.72856 0.898438,1.27175 0.898438,2.60351 0,2.36371 -1.912476,5.29297 -6.919922,5.29297 -2.17926,0 -3.451901,-0.37865 -4.130859,-0.79883 -0.678959,-0.42018 -0.798829,-0.80387 -0.798829,-1.10156 0,-0.45749 0.450606,-1.844 3.496094,-2.17969 0.731186,-0.0565 0.647202,-1.15413 -0.08398,-1.09765 -0.01241,9.1e-4 -0.02479,0.002 -0.03711,0.004 C 70.097311,351.09872 69,352.84097 69,354 c 0,0.6737 0.378574,1.45551 1.318359,2.03711 0.939785,0.58159 2.407524,0.96289 4.710938,0.96289 5.452133,0 8.021484,-3.41358 8.021484,-6.39258 0,-1.58243 -0.595669,-2.49605 -1.09375,-3.22461 -0.103149,-0.1556 -0.278176,-0.24826 -0.464843,-0.24609 z M 77.5,350.96875 c -0.645258,0.008 -0.75144,0.92907 -0.125,1.08398 0.86985,0.23625 1.603372,0.59862 2.212891,1.02539 0.601573,0.42066 1.232432,-0.48169 0.630859,-0.90234 -0.709221,-0.49659 -1.560177,-0.91545 -2.554688,-1.18555 -0.05329,-0.0154 -0.108604,-0.0226 -0.164062,-0.0215 z m 4.814453,4.19141 c -0.370377,0.014 -0.621193,0.38283 -0.498047,0.73242 0.0943,0.28097 0.132813,0.5225 0.132813,0.67969 0,0.15896 0.01621,0.32983 0.0059,0.58398 -0.01039,0.25415 -0.04509,0.56394 -0.138672,0.89063 -0.187171,0.65336 -0.583988,1.36714 -1.576172,1.91796 -0.642059,0.35673 -0.106902,1.31962 0.535157,0.96289 1.249156,-0.69348 1.849012,-1.70822 2.097656,-2.57617 0.124322,-0.43397 0.166734,-0.83367 0.179687,-1.15039 0.01295,-0.31671 -0.002,-0.5795 -0.002,-0.6289 0,-0.3203 -0.06792,-0.66136 -0.191406,-1.0293 -0.07498,-0.23555 -0.297898,-0.39215 -0.544922,-0.38281 z"
- id="path42609-7"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 75.492188,347.04102 A 0.50005,0.50005 0 0 0 75,347.54688 V 354.5 a 0.50005,0.50005 0 1 0 1,0 v -6.95312 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z m 0,10.95117 A 0.50005,0.50005 0 0 0 75,358.5 v 2.04688 a 0.50005,0.50005 0 1 0 1,0 V 358.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
- id="rect42619-7"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.79999995;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
- d="m 114.49609,354 a 3.4824922,3.4824822 0 0 0 -3.48242,3.48242 3.4824922,3.4824822 0 0 0 3.48242,3.48242 3.4824922,3.4824822 0 0 0 3.48243,-3.48242 A 3.4824922,3.4824822 0 0 0 114.49609,354 Z m -0.50586,0.98633 h 1.01368 v 1.98633 H 117 v 1.01367 h -1.99609 v 1.98633 h -1.01368 v -1.98633 h -1.99609 v -1.01367 h 1.99609 z"
- id="circle23722"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;opacity:0.6;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.80000001;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
- d="m 121.47461,347 a 3.4883757,3.4883673 0 0 0 -3.48828,3.48828 3.4883757,3.4883673 0 0 0 3.48828,3.48828 3.4883757,3.4883673 0 0 0 3.48828,-3.48828 A 3.4883757,3.4883673 0 0 0 121.47461,347 Z m -2.48047,3 H 124 v 1.01367 h -5.00586 z"
- id="circle23728"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g23638">
+ id="g120710"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 229.49023,351.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -0.74609,0.7461 -1.67773,-0.83985 a 0.50005,0.50005 0 0 0 -0.62305,0.14649 L 225.5,353 h -1 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 A 0.50005,0.50005 0 0 0 223,354.5 v 2.79297 l -1.85352,1.85351 a 0.50005,0.50005 0 0 0 0,0.70704 l 1,1 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -0.64649,-0.64648 1.64649,-1.64648 A 0.50005,0.50005 0 0 0 224,357.5 v -2.79297 L 224.70703,354 H 225.75 a 0.50005,0.50005 0 0 0 0.40039,-0.19922 l 0.5,-0.66601 1.62695,0.8125 a 0.50005,0.50005 0 0 0 0.57618,-0.0937 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
- id="path42208-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 27.492188,306 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 4,3 a 0.50005,0.50005 0 1 0 0,1 h 4.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -4,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z m 4,3 a 0.50005,0.50005 0 1 0 0,1 h 4.99414 a 0.50005,0.50005 0 1 0 0,-1 z m -4,3 a 0.50005,0.50005 0 1 0 0,1 h 12.99414 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10854"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g120713"
+ style="display:inline;enable-background:new"
+ inkscape:label="O-1">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 223.49219,347 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -2,2 A 0.50005,0.50005 0 0 0 221,349.5 v 0.79297 L 220.29297,351 H 218.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 L 218,353.70703 v 2.58594 l -1.85352,1.85351 A 0.50005,0.50005 0 0 0 216,358.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -1.79297 l 1.85352,-1.85351 A 0.50005,0.50005 0 0 0 219,356.5 v -3 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 l -0.64649,-0.64648 0.5,-0.5 H 220.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1,-1 A 0.50005,0.50005 0 0 0 222,350.5 v -0.79297 l 1.5,-1.5 0.64648,0.64649 A 0.50005,0.50005 0 0 0 224.5,349 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 348 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 h -2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -2.29297 l -0.85351,-0.85352 A 0.50005,0.50005 0 0 0 223.49219,347 Z"
- id="path42222-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 6.5,306 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 5.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 5.992188 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 12.992188 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path10856"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(0,636)"
+ id="g28780"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-26">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 228.5,357 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 l 0.64649,0.64648 -0.64649,0.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 0,-0.70704 l -0.64649,-0.64648 0.5,-0.5 H 229.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path23824"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 531.50781,-348.00781 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 531,-338.5 a 0.50005,0.50005 0 0 0 0.5,0.5 l 9.00781,-0.008 a 0.50005,0.50005 0 0 0 0.5,-0.5 c 0,-5.24079 -4.25921,-9.5 -9.5,-9.5 z m 0.5,1.10156 c 4.27858,0.26151 7.63693,3.61986 7.89844,7.89844 L 532,-339 Z"
+ id="path10381"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 542.98047,-351.00977 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -3,3 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 3,-3 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ id="path10384-1"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g24220"
- transform="translate(-1.8536743e-6,63.000006)">
+ transform="translate(43,63)"
+ id="g10379"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-25">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 32.855469,347.00586 c -0.706567,0.052 -1.35787,0.479 -1.669922,1.15234 a 0.50005,0.50005 0 1 0 0.90625,0.42188 c 0.210359,-0.45391 0.713864,-0.68179 1.193359,-0.53906 0.479496,0.14272 0.777196,0.60845 0.705078,1.10351 C 33.918117,349.63959 33.500288,350 33,350 h -5.5 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 33 c 0.98952,0 1.835874,-0.73175 1.978516,-1.71094 0.142642,-0.97918 -0.459806,-1.92277 -1.408204,-2.20508 -0.237099,-0.0706 -0.479321,-0.0955 -0.714843,-0.0781 z M 38.488281,349 c -0.867889,0.005 -1.700579,0.46414 -2.154297,1.25 a 0.5005035,0.5005035 0 1 0 0.867188,0.5 c 0.36563,-0.63329 1.125339,-0.91026 1.8125,-0.66016 0.68716,0.25011 1.089874,0.94977 0.96289,1.66993 C 39.849581,352.47992 39.231261,353 38.5,353 h -11 c -0.676161,-0.01 -0.676161,1.00956 0,1 h 11 c 1.209914,0 2.252791,-0.87487 2.462891,-2.06641 0.210099,-1.19153 -0.470475,-2.36938 -1.607422,-2.7832 C 39.071232,349.04694 38.777578,348.99817 38.488281,349 Z M 27.5,356 c -0.676161,-0.01 -0.676161,1.00956 0,1 H 35.464844 35.5 c 0.74205,0 1.3672,0.53453 1.482422,1.26758 0.115221,0.73305 -0.315216,1.43251 -1.021484,1.66015 -0.706269,0.22765 -1.466229,-0.0896 -1.800782,-0.75195 a 0.50006246,0.50006246 0 1 0 -0.892578,0.45117 c 0.553327,1.09549 1.831882,1.62847 3,1.25196 1.168118,-0.37652 1.891741,-1.55517 1.701172,-2.76758 C 37.778181,356.89891 36.727299,356 35.5,356 Z"
- transform="translate(1.8536743e-6,-63.000006)"
- id="path24132"
+ inkscape:connector-curvature="0"
+ id="path10375"
+ d="m 471.5,221 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 468,224.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 480,231.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 479 v 9.29297 L 476.29297,234 H 469 v -9.29297 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="circle10377"
+ d="m 474,225.99805 c -1.09907,0 -2,0.90288 -2,2.00195 0,1.09907 0.90093,2 2,2 1.09907,0 2.00195,-0.90093 2.00195,-2 0,-1.09907 -0.90288,-2.00195 -2.00195,-2.00195 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(21,615)"
+ id="g10447"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-24">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10443"
+ d="m 478.49609,-323.00781 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.64648,2.64649 -2.64648,2.64648 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10445"
+ d="m 473.4375,-330.97461 c -0.67078,0.0637 -1.33815,0.24001 -1.97461,0.53711 -2.54627,1.1886 -3.92907,3.99498 -3.32031,6.73828 0.60875,2.7433 3.04739,4.69922 5.85742,4.69922 h 2.29297 l -2.14453,2.14453 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 1 0 -0.70703,0.70703 L 476.29688,-320 H 474 c -2.34689,0 -4.37244,-1.62485 -4.88086,-3.91602 -0.50842,-2.29116 0.63902,-4.62253 2.76563,-5.61523 2.12705,-0.99291 4.66398,-0.38512 6.07812,1.48242 l 0.74023,0.97656 C 479.25532,-326.34303 480.1366,-326 481,-326 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 481 c -0.59704,0 -1.17055,-0.2407 -1.5,-0.67578 l -0.74023,-0.97656 c -1.27424,-1.68278 -3.30992,-2.51346 -5.32227,-2.32227 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(0,636)"
+ id="g28776"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-23">
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 447.50977,297.01172 a 0.50005,0.50005 0 1 0 0,1 h 6.2832 c -0.26437,-0.28877 -0.47061,-0.62726 -0.60742,-1 z m 11.29882,0 c -0.13697,0.37274 -0.34281,0.71123 -0.60742,1 h 2.3086 a 0.50005,0.50005 0 1 0 0,-1 z"
+ transform="translate(21,-636)"
+ id="path10435" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 476.99609,-342 c 1.09999,0 2.00391,0.90231 2.00391,2.00195 0,1.09965 -0.90392,2 -2.00391,2 -1.09998,0 -2.00195,-0.90035 -2.00195,-2 0,-1.09964 0.90197,-2.00195 2.00195,-2.00195 z"
+ id="ellipse10439"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 472.49805,-351.99805 c 1.37513,0 2.50195,1.12557 2.50195,2.5 0,1.37444 -1.12682,2.49805 -2.50195,2.49805 -1.37514,0 -2.5,-1.12361 -2.5,-2.49805 0,-1.37443 1.12486,-2.5 2.5,-2.5 z m 0,1 c -0.83537,0 -1.5,0.66668 -1.5,1.5 0,0.83332 0.66463,1.49805 1.5,1.49805 0.83537,0 1.50195,-0.66473 1.50195,-1.49805 0,-0.83332 -0.66658,-1.5 -1.50195,-1.5 z"
+ id="ellipse10441"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 472.50195,-345.99609 a 0.50005,0.50005 0 0 0 -0.49218,0.50781 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50781 z m 0,3 a 0.50005,0.50005 0 0 0 -0.49218,0.50781 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50781 z"
+ id="path10451"
inkscape:connector-curvature="0" />
- <g
- id="g24588"
- style="opacity:0.8;fill:#ffffff" />
- <g
- id="g24584"
- style="opacity:0.8;fill:#ffffff" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22036"
- transform="translate(-21.000002,4.4999696e-6)">
+ transform="translate(105,2.4e-4)"
+ id="g10345"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-22">
<g
- transform="matrix(-1,0,0,1,508.99288,-42.00012)"
- id="g23159"
- style="fill:#ffffff">
+ style="opacity:0.7"
+ id="g10341">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 286.49219,242 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 286,255.50781 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 242.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 4.72656 l -4.7207,10.22852 z M 292,244.77344 v 10.23437 h -4.72266 z"
- transform="matrix(-1,0,0,1,487.99288,42.000116)"
- id="path23171"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path10337-7"
+ d="M 344.49219,287.99219 A 0.50005,0.50005 0 0 0 344,288.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 0,5 A 0.50005,0.50005 0 0 0 344,293.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 1 0 0,-1 H 345 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 348.5,295 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 202.99219,284 v 1 H 208 l -0.008,12.00781 -4.99805,-0.008 -0.002,1 5.5,0.008 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 209,284.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path21181"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="rect10339"
+ d="m 351.5,293 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 3 h -3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="rect10343"
+ d="m 342.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22891"
- transform="translate(443.99999,-274)">
+ transform="translate(-126,636)"
+ id="g10457"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-21">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -141,519.5 v 1.5 h 1 v -1.5 z m 0,2.5 v 2 h 1 v -2 z m 0,3 v 1.2793 l -2.58594,2.35156 0.67188,0.73828 2.60351,-2.36719 L -139,527 v -1 h -1 v -1 z m 3.00781,1 v 1 h 2 v -1 z M -135,526 v 1 h 1.5 v -1 z"
- mask="none"
- id="path12456"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ id="path10453"
+ transform="translate(0,-636)"
+ d="m 554.5,284 c -1.37479,0 -2.5,1.12521 -2.5,2.5 v 2.00781 c 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 v -0.5 h 1.51172 0.49805 l -0.0137,3.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97657,0.21094 0.67528,-3.15139 1.9234,-4.08819 3.51757,-5.42773 1.58398,1.34059 2.83152,2.27746 3.51953,5.42968 0.13318,0.66658 1.13544,0.44609 0.97657,-0.21484 -0.76273,-3.49457 -2.35105,-4.70351 -4.00196,-6.11719 l 0.0137,-3.27539 h 2.21679 3.28516 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04297 C 562.0093,287.6044 561.2975,288 560.5,288 c -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 H 558.51172 557 V 286.5 c 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 6,0.008 c -0.82054,0 -1.49609,0.67557 -1.49609,1.4961 0,0.82054 0.67555,1.49609 1.49609,1.49609 0.82053,0 1.49609,-0.67555 1.49609,-1.49609 0,-0.82053 -0.67556,-1.4961 -1.49609,-1.4961 z m -6,0.992 c 0.83435,0 1.5,0.66565 1.5,1.5 v 2.00781 c 0,0.83435 -0.66565,1.5 -1.5,1.5 -0.83435,0 -1.5,-0.66565 -1.5,-1.5 V 286.5 c 0,-0.83435 0.66565,-1.5 1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(-147,636)"
+ id="g10393"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-20">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 303.5,242 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 300,245.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 314,252.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 h 8.58594 l -2,2 h -8.58594 z M 313,243.70703 v 8.58594 l -2,2 v -8.58594 z M 301,246 h 9 v 9 h -9 z"
- transform="translate(-443.99999,274)"
- id="path12458"
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="ellipse10386"
+ d="m 560.99219,-349.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="ellipse10388"
+ d="m 552,-339.99219 c 0,-1.09609 0.89673,-1.99609 1.99219,-1.99609 1.09546,0 1.99414,0.9 1.99414,1.99609 0,1.09609 -0.89868,1.99805 -1.99414,1.99805 -1.09546,0 -1.99219,-0.90196 -1.99219,-1.99805 z m 1,0 c 0,0.55685 0.43837,0.99805 0.99219,0.99805 0.55382,0 0.99414,-0.4412 0.99414,-0.99805 0,-0.55685 -0.44032,-0.99609 -0.99414,-0.99609 -0.55382,0 -0.99219,0.43924 -0.99219,0.99609 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ d="m 560.36798,-346.98792 a 0.60364676,0.60365756 0 0 0 -0.41654,0.18273 l -0.77413,0.77415 a 0.60366279,0.6036736 0 1 0 0.85273,0.8547 l 0.77609,-0.77611 a 0.60364676,0.60365756 0 0 0 -0.43815,-1.03547 z m -2.99662,2.98989 a 0.61117943,0.61029182 0 0 0 -0.42173,0.18473 l -0.78379,0.78265 a 0.61119567,0.61030804 0 1 0 0.86336,0.8641 l 0.78578,-0.78463 a 0.61117943,0.61029182 0 0 0 -0.44362,-1.04685 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path28690"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22594"
- transform="translate(-1.8536743e-6,21.000005)">
+ transform="translate(42,657)"
+ id="g10415"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-19">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 239.00391,336 c 1.09865,0 2,0.90134 2,2 0,1.09866 -0.90135,2 -2,2 -1.09866,0 -2,-0.90134 -2,-2 0,-1.09866 0.90134,-2 2,-2 z"
- id="circle22541"
+ sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="ellipse10411"
+ d="m 350.99219,-370.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10413-7"
+ d="m 348.4707,-367.9375 c -0.33462,0.0898 -0.64722,0.26623 -0.90039,0.51953 l -4.97851,4.98242 c -0.50693,0.50809 -0.70493,1.24983 -0.51953,1.94336 0.18541,0.69355 0.72692,1.23774 1.41992,1.42383 0.69276,0.18603 1.43437,-0.0128 1.9414,-0.52148 l 4.97852,-4.98047 c 0.50694,-0.50808 0.70495,-1.25177 0.51953,-1.94531 -0.1854,-0.69356 -0.72693,-1.23578 -1.41992,-1.42188 -0.34638,-0.093 -0.70553,-0.09 -1.04102,0 z m 0.78125,0.96484 c 0.34883,0.0937 0.61917,0.3662 0.71289,0.7168 0.0937,0.35062 -0.006,0.72222 -0.26172,0.97852 l -4.97656,4.98046 c -0.25562,0.25646 -0.62555,0.35546 -0.97461,0.26172 -0.3488,-0.0937 -0.62111,-0.36425 -0.71484,-0.71484 -0.0937,-0.35061 0.006,-0.7222 0.26172,-0.97852 l 4.97851,-4.98242 c 0.25563,-0.25646 0.62557,-0.35545 0.97461,-0.26172 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="rotate(180,380.4965,-26.99765)"
+ id="g10433"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-18">
<g
- id="g22585"
- style="fill:#ffffff">
+ transform="translate(1)"
+ id="g10429">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 244.04102,347.03125 c -1.67358,-0.0335 -3.28213,0.6908 -3.99805,2.26758 -0.007,0.016 -0.0126,0.0323 -0.0176,0.0488 l -2,5.99414 c -0.21093,0.63281 0.73829,0.94921 0.94922,0.3164 l 1.98437,-5.95117 c 0.004,-0.009 0.0113,-0.0162 0.0156,-0.0254 l 7.3457,7.3457 c -0.008,0.004 -0.0138,0.008 -0.0215,0.0117 l -5.95703,1.98633 c -0.63281,0.21093 -0.31641,1.16015 0.3164,0.94922 l 6,-2 c 0.0166,-0.006 0.0329,-0.0122 0.0488,-0.0195 1.57453,-0.7157 2.29587,-2.32277 2.26172,-3.9961 -0.0342,-1.67332 -0.77095,-3.46821 -2.11523,-4.8125 -1.34429,-1.34428 -3.13893,-2.08176 -4.8125,-2.11523 z m -0.0195,1 c 1.00796,0.0202 2.11393,0.36656 3.0879,0.99414 -1.6826,0.11569 -2.73353,0.941 -3.59961,1.77734 l -1.94336,-1.94335 c 0.60824,-0.57833 1.46627,-0.84791 2.45507,-0.82813 z M 247.5,350 h 0.5 c 0,6.5e-4 0,10e-4 0,0.002 l 0.002,0.5 c -6.4e-4,1.6083 -0.66875,2.43361 -1.50586,3.28711 l -2.2832,-2.2832 C 245.06632,350.66889 245.89088,350 247.5,350 Z m 1.47656,0.89258 c 0.62645,0.97337 0.97164,2.0788 0.99219,3.08594 0.0202,0.98929 -0.2502,1.84704 -0.82813,2.45507 l -1.9414,-1.9414 c 0.83635,-0.86594 1.6611,-1.91749 1.77734,-3.59961 z"
- transform="translate(1.8536743e-6,-21.000005)"
- id="path24556"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccscccccsccccc" />
+ id="path10423-5"
+ transform="rotate(180,390.4965,-26.99765)"
+ d="m 393.49219,289.00391 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1.73047 l -2.76953,2.76953 h -1.73047 c -0.27613,2e-5 -0.49997,0.22386 -0.5,0.5 v 1.02929 c 3e-5,0.27613 0.22387,0.47068 0.5,0.47071 h 1 c 0.2725,0 0.5,0.17071 0.5,0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.73243 l 2.76758,-2.76757 h 1.73242 c 0.27613,-2e-5 0.49997,-0.22386 0.5,-0.5 v -1.02735 c -3e-5,-0.27613 -0.22387,-0.47262 -0.5,-0.47265 h -1 c -0.2725,0 -0.5,-0.17071 -0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path10431-8"
+ d="m 395.47852,-349.00391 a 0.50004997,0.50004997 0 0 0 -0.32032,0.86914 c 1.10925,1.04157 1.85525,2.61894 1.8418,4.13086 -0.0174,1.95759 -1.00719,3.50006 -2.74023,4.44727 -1.67823,0.91724 -3.81516,0.64624 -5.48829,-0.40625 l 0.0234,0.0156 C 387.83199,-340.63237 386.68507,-341 385.50781,-341 H 384.5 a 0.50004997,0.50004997 0 1 0 0,1 h 1.00586 0.002 c 0.96887,0 1.91412,0.30361 2.70899,0.86914 l 0.0117,0.008 0.0117,0.008 c 1.93164,1.2151 4.44119,1.56274 6.5,0.4375 2.004,-1.0953 3.23927,-3.01733 3.25977,-5.31836 0.0163,-1.83862 -0.84967,-3.64045 -2.1582,-4.86914 a 0.50004997,0.50004997 0 0 0 -0.36328,-0.13868 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22663"
- transform="translate(-126,21.000005)">
+ transform="translate(-210,636)"
+ id="g10409"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.0999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 219.77539,326 c -0.5582,0 -1.07768,0.24943 -1.49219,0.64258 -0.41451,0.39314 -0.75014,0.92623 -1.04101,1.57422 -0.58174,1.29596 -0.98621,3.07228 -1.23828,5.21484 a 0.55005495,0.55005495 0 1 0 1.09179,0.12891 c 0.24409,-2.07475 0.64639,-3.77175 1.15039,-4.89453 0.252,-0.5614 0.52906,-0.97431 0.79297,-1.22461 0.26391,-0.25031 0.48846,-0.3418 0.73633,-0.3418 0.24788,0 0.46416,0.0907 0.7207,0.33398 0.25655,0.24329 0.52547,0.64294 0.77149,1.17579 0.49204,1.06569 0.89452,2.64518 1.18945,4.47851 0.3037,1.88782 0.70794,3.53465 1.27539,4.76367 0.28373,0.61451 0.60805,1.12901 1.01367,1.51367 0.40563,0.38466 0.92032,0.63477 1.47852,0.63477 1.08819,0 1.93098,-0.8296 2.51953,-1.97266 0.58855,-1.14305 0.99634,-2.67751 1.25,-4.45312 a 0.55005495,0.55005495 0 1 0 -1.08789,-0.15625 c -0.2425,1.69747 -0.64149,3.13986 -1.13867,4.10547 -0.49719,0.9656 -1.01901,1.37695 -1.54297,1.37695 -0.24788,0 -0.46416,-0.0907 -0.7207,-0.33398 -0.25655,-0.24329 -0.52547,-0.64294 -0.77149,-1.17579 -0.49204,-1.06569 -0.89451,-2.64518 -1.18945,-4.47851 -0.30369,-1.88783 -0.70794,-3.53465 -1.27539,-4.76367 -0.28373,-0.61451 -0.60805,-1.12901 -1.01367,-1.51367 C 220.84828,326.25011 220.33359,326 219.77539,326 Z"
- id="use22627"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="ellipse10403"
+ d="m 560.99219,-349.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 218.75,333 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 6.5,0 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="rect42619-7-8"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="ellipse10405"
+ d="m 552,-339.99219 c 0,-1.09609 0.89673,-1.99609 1.99219,-1.99609 1.09546,0 1.99414,0.9 1.99414,1.99609 0,1.09609 -0.89868,1.99805 -1.99414,1.99805 -1.09546,0 -1.99219,-0.90196 -1.99219,-1.99805 z m 1,0 c 0,0.55685 0.43837,0.99805 0.99219,0.99805 0.55382,0 0.99414,-0.4412 0.99414,-0.99805 0,-0.55685 -0.44032,-0.99609 -0.99414,-0.99609 -0.55382,0 -0.99219,0.43924 -0.99219,0.99609 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10407-7"
+ d="m 563.50195,-343.01367 a 0.50005,0.50005 0 0 0 -0.49414,0.50586 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50586,-0.50586 z m -5.99414,2.00586 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(62.9759,-41.0395)"
+ id="g10359"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-16">
+ <g
+ transform="translate(0,21)"
+ id="g10357">
+ <path
+ style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
+ d="m 264.02413,311.53945 a 1.5,1.5 0 0 1 -1.5,1.5 1.5,1.5 0 0 1 -1.5,-1.5 1.5,1.5 0 0 1 1.5,-1.5 1.5,1.5 0 0 1 1.5,1.5 z"
+ id="path10347-2"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="circle10349"
+ d="m 269.02344,314.03906 c -1.09865,0 -2,0.90136 -2,2 0,1.09865 0.90135,2 2,2 1.09864,0 2,-0.90135 2,-2 0,-1.09864 -0.90136,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.4418 1,1 0,0.55821 -0.4418,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.5582 0.44179,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10351-7"
+ d="m 258.53125,304.03516 a 0.50005,0.50005 0 1 0 0,1 h 12 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10355-4"
+ d="m 264.79492,304.18164 a 0.60006002,0.60006002 0 0 0 -0.58594,0.4043 l -2.25,6.25 a 0.60006002,0.60006002 0 1 0 1.12891,0.40625 l 2.25,-6.25 a 0.60006002,0.60006002 0 0 0 -0.54297,-0.81055 z m -1.27148,7.75391 a 0.60006002,0.60006002 0 0 0 -0.33594,1.09961 l 4,2.7207 a 0.60006002,0.60006002 0 1 0 0.67383,-0.99219 l -4,-2.7207 a 0.60006002,0.60006002 0 0 0 -0.33789,-0.10742 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
</g>
<g
- transform="translate(41.999999,42.000005)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g22961">
+ transform="translate(0,636)"
+ id="g9298"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 534.49219,599 C 534.2199,599 534,599.223 534,599.5 v 1.5 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 3 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.5 c 0,0.277 0.2199,0.5 0.49219,0.5 h 0.0156 C 534.7801,608 535,607.777 535,607.5 v -8 c 0,-0.277 -0.2199,-0.5 -0.49219,-0.5 z m 1.25781,1 v 7 H 537 c 1.69468,0 3,-1.30532 3,-3 v -1 c 0,-1.69468 -1.30532,-3 -3,-3 z"
- transform="translate(-41.999999,-42.000005)"
- id="path22706-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 306.49219,-348.01172 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 l -1.95704,1.95703 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 306,-346.29883 v 5.79297 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95117,-1.94922 a 0.50005,0.50005 0 0 0 0.008,-0.79883 l -1.95898,-1.95899 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 1.14649,1.14648 H 307 v -5.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.96094,-1.96093 -0.006,-0.008 a 0.50005,0.50005 0 0 0 -0.39453,-0.1836 z"
+ id="path10419-4"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 499.48633,561.02734 c -0.55718,0.017 -0.67407,0.7946 -0.14649,0.97461 1.47614,0.5388 2.51343,1.91841 2.64454,3.53711 0.13105,1.61806 -0.67507,3.15416 -2.04493,3.94532 C 499.32404,569.8398 498.6905,570 498,570 h -9 v 1 h 9 c 0.84916,0 1.67422,-0.20648 2.43945,-0.64844 1.70819,-0.98656 2.70486,-2.89381 2.54297,-4.89258 -0.16183,-1.99811 -1.44941,-3.72267 -3.30078,-4.39843 -0.0622,-0.024 -0.12865,-0.0353 -0.19531,-0.0332 z"
- id="path22783-2-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 306.44531,-351.99805 c -1.16966,-0.043 -2.35048,0.23548 -3.40039,0.84766 -2.09911,1.22396 -3.28024,3.5522 -3.00586,5.94141 0.27491,2.39372 1.98225,4.44954 4.31055,5.18554 a 0.50004997,0.50004997 0 1 0 0.30078,-0.95312 c -1.94954,-0.61628 -3.38871,-2.3582 -3.61719,-4.34766 -0.22899,-1.99397 0.75092,-3.93196 2.51563,-4.96094 1.76401,-1.02856 3.9738,-0.9382 5.67187,0.20118 0.93801,0.62937 1.92387,1.08398 3.2793,1.08398 h 1 a 0.50004997,0.50004997 0 1 0 0,-1 h -1 c -1.14457,0 -1.85649,-0.33615 -2.7207,-0.91602 -1.00565,-0.67477 -2.16433,-1.03898 -3.33399,-1.08203 z"
+ id="path10421-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(11,-136)"
+ id="g10373"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-14">
+ <path
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccc" />
+ id="path10361"
+ d="m 275.4707,427 c -0.42985,0.004 -0.62994,0.5874 -0.31869,0.87125 0.40897,0.54487 0.81793,1.08974 1.2269,1.63461 -0.43981,0.59662 -0.90116,1.17907 -1.32716,1.78476 -0.21053,0.38613 0.24226,0.86663 0.6402,0.67938 0.28682,-0.15751 0.42097,-0.48416 0.63231,-0.72356 0.22655,-0.3022 0.4531,-0.6044 0.67965,-0.9066 0.3916,0.51133 0.76296,1.03993 1.16735,1.54035 0.31222,0.30974 0.89981,0.009 0.83079,-0.42566 -0.0715,-0.31923 -0.34727,-0.53953 -0.51804,-0.80941 -0.28503,-0.37975 -0.57007,-0.75951 -0.8551,-1.13926 0.43981,-0.59662 0.90116,-1.17907 1.32716,-1.78476 0.21053,-0.38613 -0.24226,-0.86663 -0.6402,-0.67938 -0.28682,0.15751 -0.42097,0.48416 -0.63231,0.72356 -0.22655,0.3022 -0.4531,0.6044 -0.67965,0.9066 -0.39082,-0.51197 -0.76442,-1.03847 -1.1661,-1.54128 -0.0981,-0.0907 -0.23371,-0.13896 -0.36711,-0.1306 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- style="display:inline;enable-background:new"
- id="g25540"
- transform="translate(582,-1322)">
- <g
- id="g25433"
- style="display:inline;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -449.5,1609 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06836 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.35352,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 3.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
- id="path25304"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccc" />
- <circle
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="circle25308"
- cx="-443"
- cy="1608"
- r="1.5"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
- </g>
- <g
- id="g25466"
- style="display:inline;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -365.49219,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 2.63867 c 0.0948,-0.3549 0.23771,-0.6892 0.42188,-1 z m 9.92383,0 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -9.92383,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06055 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.34571,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.34571,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 H -352.5 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
- id="path25334"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
- <circle
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="circle25338"
- cx="359"
- cy="-1613.0002"
- r="1.5"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96"
- transform="scale(-1)" />
- </g>
- <g
- id="g25449"
- style="display:inline;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -406.5,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 3.93164,3 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 h 7.63867 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0.42188,3 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 8.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -4.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
- id="path25345"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccc" />
- <circle
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="circle25349"
- cx="-406"
- cy="-1613.0002"
- r="1.5"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96"
- transform="scale(1,-1)" />
- </g>
- <g
- transform="matrix(1,0,0,-1,21,3226.0001)"
- id="g25439"
- style="display:inline;enable-background:new">
- <path
- sodipodi:nodetypes="ccccccccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path25435"
- d="m -449.5,1609 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 3.06836 c -0.18417,-0.3108 -0.32709,-0.6451 -0.42188,-1 z m 10.35352,0 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 3.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -10.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 12.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <circle
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- r="1.5"
- cy="1608"
- cx="-443"
- id="circle25437"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
- </g>
- <g
- transform="matrix(-1,0,0,1,-781.00069,0)"
- id="g25455"
- style="display:inline;enable-background:new">
- <path
- sodipodi:nodetypes="cccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path25451"
- d="m -406.5,1608 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 3.93164,3 c 0.18417,0.3108 0.32709,0.6451 0.42188,1 h 7.63867 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m 0.42188,3 c -0.0948,0.3549 -0.23771,0.6892 -0.42188,1 h 8.06055 c 0.67616,0.01 0.67616,-1.0096 0,-1 z m -4.35352,3 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11.99219 c 0.67616,0.01 0.67616,-1.0096 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <circle
- transform="scale(1,-1)"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- r="1.5"
- cy="-1613.0002"
- cx="-406"
- id="circle25453"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
- </g>
+ id="g10367"
+ transform="translate(116,-73)"
+ style="display:inline;opacity:0.6;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10363"
+ transform="translate(-379,209)"
+ d="m 534.48047,284 a 0.50005,0.50005 0 0 0 -0.38477,0.19727 l -2.92382,2.92578 -0.0254,0.0234 c -4.5e-4,4.6e-4 4.5e-4,0.002 0,0.002 a 0.50005,0.50005 0 0 0 -0.13671,0.25781 c -7.9e-4,0.004 -0.003,0.008 -0.004,0.0117 A 0.50005,0.50005 0 0 0 531,287.50781 V 296.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 1 0 0,-1 H 532 v -8 h 2.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 285 h 6 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -7 a 0.50005,0.50005 0 0 0 -0.0137,0 c -6.7e-4,2e-5 -10e-4,-2e-5 -0.002,0 -10e-4,4e-5 -0.003,-5e-5 -0.004,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
+ <path
+ inkscape:connector-curvature="0"
+ id="path10369"
+ d="m 273.50391,425 c -0.46998,0.0749 -0.80823,0.50172 -1.06635,0.87006 -0.4326,0.65782 -0.45638,1.4618 -0.43756,2.22236 0.008,1.23972 -0.0164,2.48035 0.0134,3.71944 0.0716,0.88933 0.54871,1.83354 1.40415,2.18708 0.42463,0.112 0.78249,-0.44168 0.50598,-0.78285 -0.29758,-0.24384 -0.6397,-0.4766 -0.77031,-0.86624 -0.24243,-0.63283 -0.12529,-1.31954 -0.15325,-1.98084 0.006,-1.03207 -0.0114,-2.06474 0.009,-3.09642 0.0299,-0.56822 0.33188,-1.12862 0.8373,-1.40532 0.33744,-0.28816 0.10108,-0.88712 -0.34243,-0.86727 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10371"
+ d="m 280.48828,425 c -0.4389,-0.0149 -0.66492,0.60436 -0.31958,0.87564 0.63959,0.33681 0.88258,1.10168 0.83716,1.78593 -0.006,1.35522 0.0116,2.71106 -0.009,4.06588 -0.029,0.57068 -0.33398,1.12767 -0.83582,1.41135 -0.3334,0.28584 -0.081,0.8949 0.35685,0.86114 0.46399,-0.0793 0.79448,-0.50451 1.05034,-0.86849 0.42617,-0.65052 0.45767,-1.4445 0.43766,-2.19695 -0.008,-1.24867 0.0164,-2.49826 -0.0134,-3.7463 -0.0691,-0.87707 -0.53296,-1.78778 -1.35661,-2.16868 -0.0478,-0.0138 -0.0978,-0.0204 -0.14755,-0.0195 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="matrix(-0.53033,-0.53033,-0.53033,0.53033,559.864,322.759)"
+ style="display:inline;fill:#5fd38d;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ id="g10335"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="N-13">
<g
- transform="translate(791,-1295)"
- style="display:inline;enable-background:new"
- id="g25378-9">
- <g
- transform="translate(1,-1)"
- id="g26210-2">
- <path
- inkscape:connector-curvature="0"
- id="path24970-9"
- d="m -511.49974,1278.4919 -2.6e-4,-2.1822 c 2e-5,-2.8698 1.14768,-5.4099 3,-6.8448 1.85234,-1.4349 4.14766,-1.4349 6,0 1.85233,1.4349 2.99998,4.0575 3,6.9272 v 2.0998"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
- sodipodi:nodetypes="ccsccc" />
- <g
- transform="translate(-729.00712,939.005)"
- style="opacity:1"
- id="g24984-6">
- <path
- sodipodi:nodetypes="cccccccccc"
- id="path24980-2"
- style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="m 228.50712,326.49495 h 2 v 2 h -2 z m -10.00994,0 h -2 v 2 h 2 z"
- inkscape:connector-curvature="0" />
- <path
- id="path24982-2"
- style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
- d="m 228.5043,327.5 -2.49718,-0.005 M 218.5,327.5 l 2.50712,-0.005"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc" />
- </g>
- <rect
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="rect24986-0"
- width="1.9999762"
- height="2"
- x="-506.5"
- y="1265.5"
- rx="0"
- ry="0" />
- </g>
- <g
- transform="translate(-21,-64)"
- id="g25924-0">
- <path
- sodipodi:nodetypes="ccsccc"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
- d="m -511.49974,1341.4919 -2.6e-4,-2.1822 c 2e-5,-2.8698 1.14768,-5.4099 3,-6.8448 1.85234,-1.4349 4.14766,-1.4349 6,0 1.85233,1.4349 2.99998,4.0575 3,6.9272 v 2.0998"
- id="path25802-2"
- inkscape:connector-curvature="0" />
- <rect
- ry="0"
- rx="0"
- y="1329.5"
- x="-504.5"
- height="2"
- width="1.9999762"
- id="rect25810-8"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
- </g>
- <g
- transform="matrix(1,0,0,-1,-21,2604.9941)"
- id="g25919-9">
- <path
- sodipodi:nodetypes="ccccc"
- id="path25812-9"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m -464.5,1340.5001 v -2 h 2 v 2 z"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccc"
- id="path25814-0"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
- d="m -463.25,1339 5.75,-11.4994 m -6.25,11.4994 -5.75,-11.4994"
- inkscape:connector-curvature="0" />
- </g>
+ style="fill:#5fd38d;stroke:#ffffff;stroke-width:1.33333;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g10333">
<g
- transform="matrix(-1,0,0,1,-968.99001,-84)"
- id="g25915-9">
- <path
- sodipodi:nodetypes="ccccc"
- inkscape:connector-curvature="0"
- d="m -503.5,1348.5 h -2 v 2 h 2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path25851-1" />
+ id="g10331">
<path
- sodipodi:nodetypes="csc"
inkscape:connector-curvature="0"
- id="path25853-8"
- d="m -498.49506,1361.4978 -2.00459,-2.0055 c -2.16266,-2.1636 -3.0003,-5.1361 -3.0003,-7.9852 l 0.01,-1.0071"
- style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal" />
+ id="path10321-5"
+ transform="matrix(-0.942809,-0.942809,-0.942809,0.942809,832.145,223.544)"
+ d="m 262.58789,287.02734 a 0.60006001,0.60006001 0 0 0 -0.47266,0.95899 l 2.14844,3.02929 -2.14844,3.0293 a 0.60024527,0.60024527 0 1 0 0.97852,0.69531 l 1.90625,-2.6875 1.90625,2.6875 a 0.60024527,0.60024527 0 1 0 0.97852,-0.69531 l -2.14844,-3.0293 2.14844,-3.02929 a 0.60005997,0.60005997 0 0 0 -0.041,-0.75781 0.60005997,0.60005997 0 0 0 -0.9375,0.0625 l -1.90625,2.6875 -1.90625,-2.6875 a 0.60006001,0.60006001 0 0 0 -0.0645,-0.0781 0.60006001,0.60006001 0 0 0 -0.44141,-0.18555 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
- d="m -511.5049,1361.4907 c 0,-2.8491 0.8375,-5.8217 3.0003,-7.9852 L -505.5,1350.5"
- id="path25855-4"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="csc" />
- <g
- id="g25861-1"
- transform="translate(-47,-2)">
- <path
- sodipodi:nodetypes="ccccc"
- id="path25857-8"
- style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="m -457.50994,1358.5 h -2 v 2 h 2 z"
- inkscape:connector-curvature="0" />
- <path
- id="path25859-9"
- style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
- d="m -458.5,1358 v -3"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- </g>
- <g
- transform="rotate(90,-479.5,1328.5)"
- id="g25873-3">
- <path
- inkscape:connector-curvature="0"
- d="m -457.50994,1359.5 h -2 v 2 h 2 z"
- style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- id="path25869-0"
- sodipodi:nodetypes="ccccc" />
- <path
- sodipodi:nodetypes="cc"
- inkscape:connector-curvature="0"
- d="m -458.5,1359 v -3"
- style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
- id="path25871-3" />
- </g>
- </g>
- <g
- id="g25347-2">
- <g
- transform="translate(-43,-61)"
- id="g25301-4">
- <path
- sodipodi:nodetypes="ccsccc"
- style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
- d="m -510.49974,1338.4932 -2.6e-4,-0.2387 c 0,-2.5685 1.14768,-5.2795 3,-6.6953 1.85233,-1.4159 4.14765,-1.4159 5.99999,0 1.85233,1.4158 3,4.1268 3,6.6953 v 0.2387"
- id="path25297-7"
- inkscape:connector-curvature="0" />
- <rect
- ry="0"
- rx="0"
- y="1328.5"
- x="-503.5"
- height="2"
- width="1.9999762"
- id="rect25299-7"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
- </g>
- <path
- sodipodi:nodetypes="ccccccccccccccc"
- id="path25355-6-1"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- d="m -554,1265 h 3 v -1 h -3 z m 5,0 h 3 v -1 h -3 z m 5,0 h 3 v -1 h -3 z"
- inkscape:connector-curvature="0" />
+ d="m 310.32458,237.24123 a 0.66673335,0.66673335 0 0 0 -0.58971,-0.19749 c -6.22865,0.92525 -11.88001,6.57661 -12.80526,12.80526 a 0.66680952,0.66680952 0 1 0 1.31891,0.19749 c 0.82395,-5.54666 6.1358,-10.85851 11.68246,-11.68246 a 0.66673335,0.66673335 0 0 0 0.3936,-1.1228 z m 8.44938,8.44937 a 0.66673335,0.66673335 0 0 1 0.19749,0.58972 c -0.92525,6.22865 -6.57661,11.88001 -12.80526,12.80526 a 0.66673335,0.66673335 0 1 1 -0.19611,-1.31753 c 5.54665,-0.82395 10.8585,-6.1358 11.68245,-11.68246 a 0.66673335,0.66673335 0 0 1 1.12143,-0.39499 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path10329-8" />
</g>
</g>
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="rotate(-180,349.00525,417)"
- id="g22180"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ transform="translate(21,573)"
+ id="g10534"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-12">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 324.95117,410.94531 c -0.75176,0.0616 -1.47366,0.37015 -2.05469,0.95117 -1.16941,1.16942 -1.16162,2.91055 -0.28906,4.30664 0.87256,1.3961 2.57397,2.52709 4.83399,2.79297 2.83908,0.33401 5.63985,-1.05664 6.5332,-3.3125 a 0.50005,0.50005 0 1 0 -0.92969,-0.36718 c -0.67177,1.69632 -3.05327,2.97373 -5.48633,2.6875 -1.98998,-0.23411 -3.41357,-1.22813 -4.10351,-2.33203 -0.68994,-1.10391 -0.68215,-2.23778 0.14844,-3.06836 0.83795,-0.83796 1.98844,-0.89361 3.08398,-0.26368 1.09554,0.62994 2.08242,1.9799 2.31641,3.96875 a 0.50005,0.50005 0 1 0 0.99218,-0.11718 c -0.26601,-2.26115 -1.40413,-3.91119 -2.80859,-4.71875 -0.70223,-0.40379 -1.48457,-0.58895 -2.23633,-0.52735 z m 3.54102,9.04883 a 0.50005,0.50005 0 0 0 -0.37696,0.1875 c -0.31249,0.377 -0.92604,0.69672 -1.66015,0.78906 a 0.50005,0.50005 0 1 0 0.125,0.99219 c 0.94034,-0.11828 1.77818,-0.50935 2.30469,-1.14453 a 0.50005,0.50005 0 0 0 -0.39258,-0.82422 z"
- id="path22178"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path10530"
+ d="m 216.5,-282 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 6 v 5 h -6 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 331.50586,410 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -10,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path22182"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccc" />
+ id="path10532"
+ d="m 226.5,-289 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 12 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22365"
- transform="translate(-1.8536743e-6,-25.999995)">
+ transform="translate(-21,615)"
+ style="display:inline;opacity:0.8;enable-background:new"
+ id="g10464"
+ inkscape:label="N-11">
<path
- id="path22215"
- d="m 302,649 v 8 h 4 v -8 z m 1,1 h 2 v 1 h -2 z m 0,2 h 2 v 1 h -2 z m 0,2 h 2 v 1 h -2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path10460"
+ d="m 237.5,-323 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10462"
+ d="m 237.52148,-329 a 0.50005,0.50005 0 0 0 -0.5,0.49805 l -0.0215,4.5 1,0.004 0.0195,-4.00195 H 247 v 9 h -4 v 1 h 4.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ d="m 251,-326 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
+ style="display:inline;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ id="path10466"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g128040"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-10">
+ <path
+ id="path10482"
+ d="m 197.50977,285.99609 a 0.50005,0.50005 0 0 0 -0.31055,0.10547 c -1.78384,1.33863 -2.5833,3.62488 -2.02149,5.78321 0.56181,2.15833 2.37387,3.7674 4.58399,4.0664 2.05389,0.27788 4.06729,-0.6352 5.23828,-2.31445 V 296.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4 a 0.50005,0.50005 0 1 0 0,1 h 2.72656 c -0.95112,1.41787 -2.62038,2.19029 -4.33008,1.95898 -1.8109,-0.24499 -3.29162,-1.5577 -3.75195,-3.32617 -0.46033,-1.76847 0.19267,-3.63559 1.6543,-4.73242 a 0.50005,0.50005 0 0 0 -0.28906,-0.9043 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
- sodipodi:nodetypes="sssssssssccccc"
inkscape:connector-curvature="0"
- id="rect21916"
- d="m 301.5,647 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 9 c 0,0.82235 0.67765,1.5 1.5,1.5 h 11 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -9 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m -0.5,1 h 12 v 10 h -12 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path10488"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 209,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22423">
- <g
- id="g22461"
- style="fill:#ffffff">
- <path
- sodipodi:nodetypes="ssscccssssccsss"
- inkscape:connector-curvature="0"
- id="path22413"
- d="m 175.5,599 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 6 c 0,0.64672 0.42101,1.19773 1,1.40625 V 606.5 v -3 -3 c 0,-0.28564 0.21436,-0.5 0.5,-0.5 h 9 c 0.28564,0 0.5,0.21436 0.5,0.5 v 1.5 h 1 v -1.5 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- id="rect22415"
- transform="translate(0,-50)"
- d="m 177.5,653 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 6 c 0,0.82235 0.67765,1.5 1.5,1.5 h 9 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -6 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 z m 2.00391,2 c 0.1882,0.002 0.35956,0.10882 0.44336,0.27734 l 2,4 c 0.16517,0.33222 -0.0763,0.72229 -0.44727,0.72266 h -4 c -0.37097,-3.7e-4 -0.61244,-0.39044 -0.44727,-0.72266 l 2,-4 c 0.0851,-0.17104 0.26016,-0.27834 0.45118,-0.27734 z m 3.99609,0 h 3 a 0.50005,0.50005 0 1 1 0,1 h -3 a 0.50005,0.50005 0 1 1 0,-1 z m 0,2 h 3 a 0.50005,0.50005 0 1 1 0,1 h -3 a 0.50005,0.50005 0 1 1 0,-1 z m 0,2 h 2 a 0.50005,0.50005 0 1 1 0,1 h -2 a 0.50005,0.50005 0 1 1 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- </g>
+ transform="translate(125,-1)"
+ id="g10480"
+ style="display:inline;opacity:0.8;enable-background:new"
+ inkscape:label="N-9">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10478"
+ d="m 51.492188,285.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 51,287.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 59.292969,295 H 52 v -7.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ d="m 63,290 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
+ style="display:inline;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ id="path10486"
+ inkscape:connector-curvature="0" />
</g>
- <path
- sodipodi:nodetypes="cccccccccccccccscccccccccccccc"
- inkscape:connector-curvature="0"
- id="path22769"
- d="m 517.98438,9.9863345 c -0.55152,0.009 -0.99193,0.4621405 -0.98438,1.0136695 v 7 h -1.10156 l -0.91016,-6.14648 c -0.0643,-0.48249 -0.46671,-0.84859 -0.95312,-0.86719 -0.63083,-0.0229 -1.12488,0.53711 -1.02344,1.16015 L 514,18.816414 v 0.88671 1.296881 h -1 v -1.746091 l -2.58984,-1.16602 c -0.12175,-0.0548 -0.25324,-0.0847 -0.38672,-0.0879 -0.88449,-0.0197 -1.35703,1.03438 -0.75391,1.68164 l 3.5,3.750001 c 1.45044,1.55404 3.38812,2.64316 5.12305,2.55469 2.20226,-0.16055 4.09501,-1.6226 4.80664,-3.71289 l 2.25586,-6.269531 c 0.1808,-0.48082 -0.16432,-0.99701 -0.67774,-1.01368 -0.32862,-0.0101 -0.62553,0.19494 -0.73242,0.50586 l -0.90039,2.50392 h -0.74023 l 1.07812,-5.81836 c 0.12593,-0.63116 -0.36843,-1.215229 -1.01172,-1.19531 -0.47506,0.0156 -0.8735,0.36343 -0.95312,0.83203 l -1.14453,6.18164 H 519 v -7 c 0.008,-0.563769 -0.45189,-1.0224695 -1.01562,-1.0136695 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 264.49219,453.00195 a 0.50005,0.50005 0 0 0 -0.34571,0.14649 l -5,4.99804 a 0.50005,0.50005 0 0 0 0,0.70704 l 5,5 a 0.50005,0.50005 0 0 0 0.70508,0 l 4.99219,-4.97852 a 0.50005,0.50005 0 0 0 0.002,-0.70703 l -4.99218,-5.01953 a 0.50005,0.50005 0 0 0 -0.36133,-0.14649 z m 0.006,1.20703 4.28711,4.31055 -4.2853,4.27344 -4.29297,-4.29297 z"
- id="path22390"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 243.49219,453 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -5,5 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 5,5 c 0.19504,0.19389 0.51004,0.19389 0.70508,0 l 4.99219,-4.97852 c 0.19574,-0.19471 0.19663,-0.51121 0.002,-0.70703 l -4.99218,-5.02149 c -0.0957,-0.0957 -0.22606,-0.14857 -0.36138,-0.14648 z"
- id="path22397"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccc" />
<g
- transform="matrix(-1,0,0,1,384.8323,63.000015)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g23034">
+ id="g128044"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-8">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 310.58203,494 c -1.1875,0 -2.13583,0.69085 -2.52344,1.62109 -0.3876,0.93025 -0.20775,2.10475 0.66993,2.98243 l 2.5,2.5 c 0.62232,0.62232 0.69247,1.32282 0.45507,1.89257 C 311.4462,503.56585 310.89453,504 310.08203,504 l -6.53515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 6.55078,0.008 c 1.1875,0 2.13584,-0.69085 2.52344,-1.62109 0.3876,-0.93025 0.20775,-2.10475 -0.66992,-2.98243 l -2.5,-2.5 c -0.62233,-0.62232 -0.69248,-1.32282 -0.45508,-1.89257 0.2374,-0.56976 0.78906,-1.00391 1.60156,-1.00391 h 4.75 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path23032"
+ id="path10484"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 167,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10490"
+ d="m 160.5,285.99023 a 0.50005,0.50005 0 0 0 -0.34766,0.85743 l 1.14649,1.14648 -6.29297,6.29297 -1.14648,-1.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.14649,-1.14648 6.29297,-6.29297 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 160.5,285.99023 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22949"
- transform="matrix(1,0,0,-1,168,540.00935)">
+ id="g10502"
+ transform="rotate(180,170.503,427.501)"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-7">
+ <path
+ id="path10492"
+ transform="rotate(180,170.503,427.501)"
+ d="m 138.61719,286.00781 a 0.60006002,0.60006002 0 0 0 -0.47657,0.99024 l 1.61133,2.01953 a 1.5007322,1.5007322 0 0 1 1.2461,1.5625 l 0.92773,1.16211 a 0.60006002,0.60006002 0 0 0 0.4668,0.23242 0.60006002,0.60006002 0 0 0 0.4707,-0.98047 l -1.58789,-1.99023 1.58984,-2.00782 a 0.60006002,0.60006002 0 1 0 -0.9414,-0.74414 l -1.41602,1.78907 -1.42969,-1.79102 a 0.60006002,0.60006002 0 0 0 -0.46093,-0.24219 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10496"
+ d="m 201.60938,559.02148 a 0.60006002,0.60006002 0 0 0 -0.47071,0.98243 l 1.59766,2.00195 -1.59766,2.00195 a 0.6002929,0.6002929 0 1 0 0.9375,0.75 l 1.42774,-1.78906 1.42773,1.78906 a 0.6002929,0.6002929 0 1 0 0.9375,-0.75 l -1.59766,-2.00195 1.59766,-2.00195 a 0.6002929,0.6002929 0 1 0 -0.9375,-0.75 l -1.42773,1.78906 -1.42774,-1.78906 a 0.60006002,0.60006002 0 0 0 -0.46679,-0.23243 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10498"
+ d="m 196.50391,561 a 0.50004997,0.50004997 0 0 0 -0.22657,0.0547 c 0,0 -0.3567,0.1843 -0.66796,0.57226 C 195.29811,562.01491 195,562.63889 195,563.5 v 5 c 0,0.86111 0.29839,1.4864 0.60938,1.875 0.31098,0.3886 0.66796,0.57227 0.66796,0.57227 a 0.50004997,0.50004997 0 1 0 0.44532,-0.89454 c 0,0 -0.14302,-0.0665 -0.33204,-0.30273 C 196.20161,569.5138 196,569.13889 196,568.5 v -5 c 0,-0.63889 0.20189,-1.01282 0.39062,-1.24805 0.18874,-0.23523 0.33204,-0.30078 0.33204,-0.30078 A 0.50004997,0.50004997 0 0 0 196.50391,561 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10500"
+ d="m 207.48828,557 a 0.50004997,0.50004997 0 0 0 -0.20508,0.95117 c 0,0 0.14526,0.0655 0.33399,0.30078 0.18873,0.23523 0.38867,0.60916 0.38867,1.24805 v 5 c 0,0.63889 -0.20161,1.0138 -0.39063,1.25 -0.18901,0.2362 -0.33203,0.30273 -0.33203,0.30273 a 0.50006306,0.50006306 0 1 0 0.44727,0.89454 c 0,0 0.35503,-0.18367 0.66601,-0.57227 0.31099,-0.3886 0.60938,-1.01389 0.60938,-1.875 v -5 c 0,-0.86111 -0.29811,-1.48509 -0.60938,-1.87305 -0.31127,-0.38796 -0.66796,-0.57226 -0.66796,-0.57226 A 0.50004997,0.50004997 0 0 0 207.48828,557 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(-25,619)"
+ id="g10474"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-6">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path10468"
+ d="m 137.5,-326 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10470"
+ d="m 137.52148,-331 a 0.50005,0.50005 0 0 0 -0.5,0.49609 l -0.0215,3.5 1,0.008 0.0176,-3.00391 H 145 v 7 h -3 v 1 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path10472"
+ d="m 141.52148,-335 a 0.50005,0.50005 0 0 0 -0.5,0.49609 l -0.0215,2.5 1,0.008 0.0176,-2.00391 H 149 v 7 h -2 v 1 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g63797"
+ inkscape:label="N-5">
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="matrix(0,-1,-1,0,558.00846,761.00467)"
- id="g22540"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ transform="translate(-18,356)"
+ id="g10514"
+ style="display:inline;opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:label="g10514">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 469.00195,355 C 467.90167,355 467,355.90326 467,357.00391 c 0,1.10064 0.90167,2.00391 2.00195,2.0039 1.10028,0 2.00196,-0.90326 2.00196,-2.0039 0,-1.10064 -0.90168,-2.00391 -2.00196,-2.00391 z"
- id="path22508"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sscss" />
+ id="path10510"
+ transform="translate(18,-356)"
+ d="m 95.398438,282.97461 a 0.50004994,0.50004994 0 0 0 -0.05078,0.002 0.50004994,0.50004994 0 0 0 -0.367187,0.20313 c -1.08755,1.44512 -1.289758,3.38123 -0.523438,5.02148 0.76632,1.64025 2.376885,2.71907 4.177735,2.79492 1.781962,0.0751 3.458632,-0.84789 4.365232,-2.38867 V 290.5 a 0.50004997,0.50004997 0 1 0 1,0 v -3 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -3 a 0.50004997,0.50004997 0 1 0 0,1 h 1.70312 a 0.50004994,0.50004994 0 0 0 -0.0391,0.0645 c -0.71624,1.25031 -2.05833,1.99179 -3.486324,1.93164 -1.42799,-0.0601 -2.704083,-0.91231 -3.314453,-2.21875 -0.61036,-1.30644 -0.449354,-2.8462 0.416016,-3.99609 A 0.50004994,0.50004994 0 0 0 95.3984,282.97466 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g10508"
+ transform="translate(-21,467)">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 468.5,349 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
- id="path22516"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="path10504"
+ transform="translate(21,-467)"
+ d="m 91.347656,288.96484 a 0.51005099,0.51005099 0 0 0 -0.376953,0.20899 c -1.08977,1.44807 -1.289364,3.38767 -0.521484,5.03125 0.76787,1.64358 2.380967,2.72477 4.185547,2.80078 1.781016,0.075 3.455174,-0.8442 4.365234,-2.38086 v 1.875 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 99.5,293 h -3 a 0.50005,0.50005 0 1 0 0,1 h 1.693359 a 0.51006897,0.51006897 0 0 0 -0.03906,0.0586 c -0.71442,1.24711 -2.052293,1.98773 -3.476563,1.92774 -1.42426,-0.06 -2.695887,-0.90979 -3.304687,-2.21289 -0.60881,-1.3031 -0.449088,-2.83939 0.414062,-3.98633 a 0.51005099,0.51005099 0 0 0 -0.388671,-0.82227 0.51005099,0.51005099 0 0 0 -0.05078,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g10528"
+ transform="translate(-21,384)"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-4">
+ <g
+ style="display:inline;opacity:0.7;enable-background:new"
+ id="g10520"
+ transform="translate(46,-388)">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 475.5,356 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z"
- id="path22518"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="path10518"
+ d="m 50.492188,287.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 50,289.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 56.292969,295 H 51 v -5.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(42,-384)"
+ id="g10526"
+ style="display:inline;opacity:1;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 474.50195,350.00781 c -0.82202,10e-6 -1.50195,0.67415 -1.50195,1.4961 0,0.82195 0.67993,1.49609 1.50195,1.49609 0.82203,0 1.50195,-0.67414 1.50196,-1.49609 -1e-5,-0.82196 -0.67993,-1.4961 -1.50196,-1.4961 z"
- id="path22520"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="csscc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 468,351.5 v 4 h 1 v -4 z m 5.14648,0.64648 -3.49609,3.50977 0.70899,0.70508 3.49414,-3.50781 z M 470.5,357 v 1 h 4 v -1 z"
- id="path22536"
- inkscape:connector-curvature="0" />
+ id="path10524"
+ d="m 50.492188,287.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 50,289.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 56.292969,295 H 51 v -5.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
+ </g>
+ <g
+ id="g128007"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-3">
+ <path
+ id="path10295"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 61,288 v -2.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 58 v 1 h 2 v 2 z m -13,0 v -2.5 c 2.8e-5,-0.27613 0.223869,-0.49997 0.5,-0.5 H 51 v 1 h -2 v 2 z m 13,7 v 2.5 c -2.8e-5,0.27613 -0.223869,0.49997 -0.5,0.5 H 58 v -1 h 2 v -2 z m -13,0 v 2.5 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 H 51 v -1 h -2 v -2 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path10315"
+ d="m 54,285 v 2 h 1 v -2 z m -2.5,3 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 6 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 5.027344 v 5 H 52 Z m -4,2 v 1 h 2 v -1 z m 11,0 v 1 h 2 v -1 z m -5,5 v 2 h 1 v -2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g10303"
+ transform="matrix(-1,0,0,1,68.0071,83.9999)"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-2">
<g
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- id="g22761"
- transform="matrix(0,-1,-1,0,554.00846,765.00467)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 468.5,349 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z m 0,1 c 0.28207,0 0.5,0.21793 0.5,0.5 0,0.28207 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z m 0.50195,5 C 467.90167,355 467,355.90326 467,357.00391 c 0,1.10064 0.90167,2.00391 2.00195,2.0039 1.10028,0 2.00196,-0.90326 2.00196,-2.0039 0,-1.10064 -0.90168,-2.00391 -2.00196,-2.00391 z m 0,1 c 0.55916,0 1.00196,0.44302 1.00196,1.00391 0,0.56088 -0.4428,1.0039 -1.00196,1.0039 -0.55915,0 -1.00195,-0.44302 -1.00195,-1.0039 C 468,356.44302 468.4428,356 469.00195,356 Z m 6.49805,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
- id="path22750"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 468,351.5 v 4 h 1 v -4 z"
- id="path22755"
- inkscape:connector-curvature="0" />
+ transform="translate(-0.012711,-83.9954)"
+ id="g10299">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 470.5,357 v 1 h 4 v -1 z"
- id="path22757"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path10297"
+ transform="matrix(-1,0,0,1,68.0198,-0.004515)"
+ d="m 36.007812,284 v 2 h -1.5 c -0.27613,3e-5 -0.499969,0.22387 -0.5,0.5 v 1.49805 l -3.988281,0.006 c -0.812117,9.2e-4 -1.516225,0.45838 -1.832031,1.12695 -0.315807,0.66858 -0.189691,1.55835 0.478516,2.22656 l 4,4 c 0.413276,0.41327 0.416416,0.77582 0.271484,1.08789 -0.144932,0.31206 -0.483162,0.5586 -0.917969,0.5586 l -4.513672,0.006 c -0.676088,-0.008 -0.674098,1.01079 0.002,1 l 4.511719,-0.006 c 0.815193,0 1.513263,-0.46717 1.824219,-1.13672 0.310955,-0.66954 0.189571,-1.55652 -0.470703,-2.2168 l -4,-4 c -0.426033,-0.42603 -0.426504,-0.78429 -0.28125,-1.0918 0.145253,-0.30751 0.489852,-0.55418 0.927734,-0.55468 L 34,288.99805 c 0.0026,2e-5 0.0052,2e-5 0.0078,0 V 290.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 2 h 1 v -2 h 1.5 c 0.27613,-3e-5 0.499971,-0.22387 0.5,-0.5 V 289 h 2 v -1 h -2 v -1.5 c -2.9e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.5 v -2 z m -1.027343,3 h 3.027343 v 3 h -3.027343 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g22484"
- transform="translate(-220,-220)">
+ id="g10319"
+ transform="translate(-21,84)"
+ style="display:inline;enable-background:new"
+ inkscape:label="N-1">
<path
- id="path22480"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 334.5,777 c -0.15738,-3e-4 -0.30571,0.0735 -0.40039,0.19922 L 332.75,779 H 332 c -0.54535,0 -1,0.45465 -1,1 v 9 c 0,0.54535 0.45465,1 1,1 h 12 c 0.54535,0 1,-0.45465 1,-1 v -9 c 0,-0.54535 -0.45465,-1 -1,-1 h -3.75 l -1.34961,-1.80078 C 338.80571,777.07351 338.65738,776.9997 338.5,777 Z m 1,1 h 2 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 1 c -3e-5,0.27613 -0.22387,0.49997 -0.5,0.5 h -2 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -1 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 z m -3.5,3 h 9 v 7 h -9 v -6.5 z m 11,1 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m 0,4 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccsssssssscccccccccccccccccccssssssssss" />
+ d="m 29,207 v 1 h -2 v -1 z m 4,4 h 1 v 3 h -1 z m 0,-10 h 1 v 3 h -1 z m -2.5,4 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 208 h 0.335938 l 2.61914,1.9043 c 0.08568,0.0623 0.188958,0.0958 0.294922,0.0957 h 0.25 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -4 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -0.25 c -0.105964,-1.5e-4 -0.209238,0.0334 -0.294922,0.0957 L 37.335938,207 H 37 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 5.027344 v 3 H 31 Z m 9,0.30078 v 2.39844 L 38.349609,207.5 Z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path10313" />
+ </g>
+ <g
+ id="g12836"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-123,459)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="M-26">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.2;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 333.5,782 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z m 0,2 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z m 0,2 a 0.50005006,0.50005006 0 1 0 0,1 h 6.00195 a 0.50005006,0.50005006 0 1 0 0,-1 z"
- id="path22526"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 540.5,263 c -2.47936,0 -4.5,2.02064 -4.5,4.5 0,2.47936 2.02064,4.5 4.5,4.5 2.47936,0 4.5,-2.02064 4.5,-4.5 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 z m 0,1 c 1.93892,0 3.5,1.56108 3.5,3.5 0,1.40621 -0.82672,2.60476 -2.01758,3.16211 -0.16784,-2.48561 -2.15892,-4.47669 -4.64453,-4.64453 C 537.89524,264.82672 539.09379,264 540.5,264 Z"
+ transform="translate(123,-459)"
+ id="path12830"
inkscape:connector-curvature="0" />
<path
- inkscape:connector-curvature="0"
- d="m 342.50195,777 c -0.67617,-0.01 -0.67617,1.00957 0,1 h 1 c 0.67617,0.01 0.67617,-1.00957 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path22529"
- sodipodi:nodetypes="ccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 657.50195,-192.93359 a 0.50004997,0.50004997 0 0 0 -0.22656,0.0508 c -2.27231,1.07327 -3.57921,3.51034 -3.21484,5.99609 0.36436,2.48575 2.31598,4.44563 4.80078,4.82227 2.48479,0.37663 4.92837,-0.91763 6.01367,-3.1836 a 0.50013262,0.50013262 0 1 0 -0.90234,-0.43164 c -0.89704,1.8729 -2.90867,2.93833 -4.96289,2.62696 -2.05422,-0.31138 -3.6598,-1.92406 -3.96094,-3.97852 -0.30115,-2.05446 0.77387,-4.06001 2.65234,-4.94727 a 0.50004997,0.50004997 0 0 0 -0.19922,-0.95507 z"
+ id="path12834"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22589">
+ id="g22255"
+ transform="translate(-1.85367e-6,-21)"
+ inkscape:label="M-25">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 120.85938,263.01172 c -2.71113,-0.14985 -5.132,0.84146 -7.07032,2.78125 -2.61921,2.6212 -3.50441,6.90582 -2.24609,9.9043 0.25386,0.60493 0.66496,1.06469 1.2168,1.20507 0.55183,0.14039 1.13738,-0.0925 1.59375,-0.54882 l 10,-10 a 0.50005,0.50005 0 0 0 0.01,-0.01 c 0.45574,-0.48275 0.74002,-1.03795 0.61133,-1.61328 -0.12869,-0.57533 -0.64203,-0.96413 -1.31445,-1.18164 -0.96105,-0.31088 -1.89708,-0.48716 -2.80078,-0.53711 z m -0.0586,0.98437 c 0.81237,0.051 1.66258,0.21855 2.55078,0.50586 0.49509,0.16015 0.62426,0.33915 0.64844,0.44727 0.0242,0.10812 -0.028,0.35187 -0.36328,0.70703 l -9.99024,9.99023 c -0.29363,0.29364 -0.48952,0.32555 -0.64062,0.28711 -0.1511,-0.0384 -0.36452,-0.20246 -0.54102,-0.62304 -1.05362,-2.51071 -0.27172,-6.50583 2.03125,-8.81055 1.77041,-1.77175 3.86758,-2.65679 6.30469,-2.50391 z M 115.48438,267 a 0.50005,0.50005 0 0 0 -0.34376,0.15234 C 113.75486,268.5381 112.997,270.82305 113,272.5 a 0.50005,0.50005 0 1 0 1,0 c -0.002,-1.34281 0.7435,-3.53647 1.84766,-4.64062 A 0.50005,0.50005 0 0 0 115.48438,267 Z m 7.02343,3 a 0.50005,0.50005 0 1 0 0,1 c 0.67897,0 1.01439,0.13886 1.19922,0.33398 0.18483,0.19513 0.30078,0.54691 0.30078,1.16602 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.74159 -0.136,-1.38882 -0.57617,-1.85352 C 123.99147,270.18179 123.32885,270 122.50781,270 Z m -2.01562,1.99219 A 0.50005,0.50005 0 0 0 120,272.5 c 0,0.86111 0.31215,1.53681 0.80469,1.94727 0.49254,0.41045 1.11198,0.55273 1.69531,0.55273 0.41667,0 0.79723,0.10772 1.05469,0.32227 C 123.81215,275.53681 124,275.86111 124,276.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.86111 -0.31215,-1.53681 -0.80469,-1.94727 C 123.70277,274.14228 123.08333,274 122.5,274 c -0.41667,0 -0.79723,-0.10772 -1.05469,-0.32227 C 121.18785,273.46319 121,273.13889 121,272.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 118,274.5 c 0,0.82103 0.18179,1.48561 0.64648,1.92578 C 119.11118,276.86595 119.75841,277 120.5,277 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 c -0.61911,0 -0.97089,-0.11595 -1.16602,-0.30078 C 119.13886,275.51439 119,275.17897 119,274.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path22545"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40019;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 521.5,287 c -5.3,0 -9.5,4.7037 -9.5,9.5 v 1 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 c 0,-1.05 0.68155,-2.47832 1.73828,-3.59375 C 518.79501,291.79082 520.19444,291 521.5,291 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0,1 h 0.5 v 2 h -0.5 c -1.69444,0 -3.29501,0.95918 -4.48828,2.21875 C 515.81845,293.47832 515,295.05 515,296.5 v 0.5 h -2 v -0.5 c 0,-4.2037 3.8,-8.5 8.5,-8.5 z"
+ id="path21998"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 512.5,263 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 6.60938 c 0.29756,-0.51189 0.62592,-1.00687 1,-1.46876 V 264 h 2 v 2.71875 c 0.32103,-0.24305 0.65292,-0.47168 1,-0.67969 V 263.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ transform="translate(1.85367e-6,21)"
+ id="path22786"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 310.26367,452.0293 c -0.67255,-0.0123 -1.33821,0.3 -1.8789,0.8789 l -0.23829,0.23828 a 0.50004997,0.50004997 0 0 0 -0.084,0.10938 0.50004997,0.50004997 0 0 0 -0.0879,0.0723 l -1.26563,1.25196 c -0.23797,0.23547 -0.44036,0.48356 -0.58984,0.75781 a 0.50004997,0.50004997 0 1 0 0.87695,0.47852 c 0.0885,-0.16243 0.22753,-0.33889 0.41602,-0.52539 l 1.26562,-1.25391 a 0.50004997,0.50004997 0 0 0 0.0899,-0.11523 0.50004997,0.50004997 0 0 0 0.002,-0.002 0.50004997,0.50004997 0 0 0 0.084,-0.0664 l 0.25,-0.25 a 0.50004997,0.50004997 0 0 0 0.0117,-0.0117 c 0.39332,-0.4211 0.76594,-0.57109 1.12891,-0.56446 0.36298,0.007 0.75841,0.18208 1.15234,0.57618 0.39504,0.3952 0.56757,0.78617 0.57422,1.14648 0.007,0.36031 -0.14053,0.73397 -0.56445,1.13672 l -0.26758,0.2539 a 0.50004997,0.50004997 0 0 0 -0.0957,0.12305 0.50004997,0.50004997 0 0 0 -0.0859,0.0684 l -1.25,1.25 a 0.50004997,0.50004997 0 0 0 -0.0137,0.0117 c -0.16233,0.1738 -0.32346,0.30196 -0.48047,0.39063 a 0.50026213,0.50026213 0 1 0 0.49219,0.87109 c 0.25644,-0.14482 0.49753,-0.33919 0.7207,-0.57813 l 1.23828,-1.23828 a 0.50004997,0.50004997 0 0 0 0.0859,-0.11133 0.50004997,0.50004997 0 0 0 0.0781,-0.0625 l 0.26563,-0.25195 c 0.57608,-0.54732 0.88934,-1.2117 0.87695,-1.88281 -0.0124,-0.67111 -0.33835,-1.30493 -0.86718,-1.83399 -0.52994,-0.53015 -1.16729,-0.85488 -1.83985,-0.86718 z m -1.77344,3.96679 a 0.50004997,0.50004997 0 0 0 -0.34375,0.15039 l -4.01367,4.01563 a 0.50004997,0.50004997 0 1 0 0.70703,0.70703 l 4.01368,-4.01562 a 0.50004997,0.50004997 0 0 0 -0.36329,-0.85743 z m -4.94921,2.1836 a 0.50004997,0.50004997 0 0 0 -0.22852,0.0469 c -0.33394,0.14944 -0.64532,0.37928 -0.92773,0.68164 l -1.23829,1.23828 a 0.50004997,0.50004997 0 0 0 -0.0547,0.0645 l -0.18555,0.17578 c -0.57608,0.54731 -0.88934,1.2117 -0.87695,1.88281 0.0124,0.67111 0.33835,1.30494 0.86718,1.83399 0.52994,0.53016 1.16729,0.85489 1.83985,0.86718 0.67255,0.0123 1.33821,-0.3 1.8789,-0.8789 l 0.23829,-0.23828 a 0.50004997,0.50004997 0 0 0 0.0605,-0.0723 0.50004997,0.50004997 0 0 0 0.004,-0.004 l 1.18359,-1.17187 c 0.27971,-0.27677 0.50962,-0.57119 0.66211,-0.9043 a 0.50004997,0.50004997 0 1 0 -0.9082,-0.41601 c -0.0851,0.18591 -0.2355,0.39018 -0.45703,0.60937 l -1.26563,1.25391 a 0.50004997,0.50004997 0 0 0 -0.0664,0.0762 0.50004997,0.50004997 0 0 0 -0.004,0.006 l -0.16602,0.16601 a 0.50004997,0.50004997 0 0 0 -0.0117,0.0117 c -0.39332,0.4211 -0.76594,0.57109 -1.12891,0.56446 -0.36298,-0.007 -0.75841,-0.18208 -1.15234,-0.57618 -0.39505,-0.3952 -0.56758,-0.78617 -0.57422,-1.14648 -0.007,-0.36031 0.14053,-0.73396 0.56445,-1.13672 l 0.26758,-0.2539 a 0.50004997,0.50004997 0 0 0 0.0742,-0.0879 l 1.16797,-1.16796 a 0.50004997,0.50004997 0 0 0 0.0117,-0.0117 c 0.20545,-0.21996 0.40997,-0.36564 0.60547,-0.45313 a 0.50004997,0.50004997 0 0 0 -0.17968,-0.95898 z"
- id="path23240-3"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g23545-6"
- transform="rotate(-90,318.41616,448.41614)">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21627"
+ transform="translate(2.81463e-5,-42)"
+ inkscape:label="M-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 393.99219,462.28516 -2.13867,-2.13868 c -0.318,-0.32528 -0.86991,-0.0915 -0.85743,0.36329 0.004,0.12976 0.0575,0.25303 0.15039,0.34375 l 2.93555,2.93359 0.008,0.01 c 0.0962,0.13317 0.25175,0.21055 0.41602,0.20703 0.003,2e-5 0.005,2e-5 0.008,0 0.0157,-6e-4 0.0313,-0.002 0.0469,-0.004 0.0164,-0.002 0.0327,-0.005 0.0488,-0.008 0.11995,-0.0256 0.2263,-0.0944 0.29882,-0.19336 l 2.94532,-2.94531 c 0.49057,-0.47126 -0.23578,-1.19761 -0.70704,-0.70704 l -2.15429,2.1543 L 395,457.5 c 0,-2.47936 -2.02064,-4.5 -4.5,-4.5 -2.47936,0 -4.5,2.02064 -4.5,4.5 v 6 c -0.01,0.67616 1.00956,0.67616 1,0 v -6 c 0,-1.93892 1.56108,-3.5 3.5,-3.5 1.93826,0 3.49893,1.56005 3.5,3.49902 z"
- transform="rotate(90,318.41616,448.41614)"
- id="path23541-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccssccsscc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 495.5,305 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -3.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 1 0 1,0 V 312 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 308 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 306 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path21618"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 502.5,308 c -5.79307,0 -10.5,4.70693 -10.5,10.5 a 0.50004997,0.50004997 0 1 0 1,0 c 0,-5.25263 4.24737,-9.5 9.5,-9.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ id="circle21622"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-346,-11.999995)"
- id="g24012-1"
- style="display:inline;fill:#ffffff;enable-background:new">
- <g
- style="opacity:0.7;fill:#ffffff;stroke-width:1.18252182"
- transform="matrix(0.84565033,0,0,0.84565033,271.3184,206.1572)"
- id="g24008-0">
- <g
- style="fill:#ffffff;stroke-width:1.18252182"
- transform="translate(829,-385)"
- id="g24002-7" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.18252182;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 480.06836,304.9375 c -0.78863,-0.0147 -1.5648,0.35582 -2.23633,1.02734 l -1.47851,1.47852 a 0.59132004,0.59132004 0 1 0 0.83593,0.83594 l 1.47852,-1.47852 c 0.51101,-0.511 0.96056,-0.68742 1.37695,-0.67969 0.41639,0.008 0.86317,0.20868 1.33399,0.67969 0.4709,0.4711 0.67191,0.91763 0.67968,1.33399 0.008,0.41635 -0.16868,0.86595 -0.67968,1.37695 l -1.47852,1.47851 a 0.59132004,0.59132004 0 1 0 0.83594,0.83594 l 1.47851,-1.47851 c 0.67153,-0.67153 1.04012,-1.44777 1.02539,-2.23633 -0.0147,-0.78856 -0.40379,-1.52464 -1.02539,-2.14649 -0.62168,-0.62194 -1.35785,-1.01269 -2.14648,-1.02734 z m -0.94336,3.50977 a 0.59132004,0.59132004 0 0 0 -0.40625,0.17773 l -1.47852,1.47852 a 0.59132004,0.59132004 0 1 0 0.83594,0.83593 l 1.47852,-1.47851 a 0.59132004,0.59132004 0 0 0 -0.42969,-1.01367 z m -8.27344,4.72851 a 0.59132004,0.59132004 0 0 0 -0.4082,0.17774 l -1.51367,1.49218 a 0.59132004,0.59132004 0 0 0 -0.008,0.006 c -0.65272,0.66501 -1.01668,1.4358 -1.00782,2.22266 0.009,0.78686 0.38697,1.53124 1.01172,2.15625 0.62485,0.62507 1.3751,1.00952 2.16992,1.01953 0.79483,0.01 1.57721,-0.36041 2.25,-1.0332 l 1.47852,-1.47657 a 0.59178867,0.59178867 0 1 0 -0.83594,-0.83789 l -1.47851,1.47852 c -0.50973,0.50972 -0.97241,0.69289 -1.40039,0.6875 -0.42799,-0.005 -0.87805,-0.206 -1.34571,-0.67383 -0.46775,-0.46794 -0.66322,-0.91244 -0.66797,-1.33398 -0.005,-0.42154 0.17763,-0.8773 0.67188,-1.38086 l 1.50586,-1.48438 a 0.59132004,0.59132004 0 0 0 -0.42188,-1.01953 z m 2.65625,0.88867 a 0.59132004,0.59132004 0 0 0 -0.40625,0.17774 l -1.47851,1.47851 a 0.59132004,0.59132004 0 1 0 0.83593,0.83594 l 1.47852,-1.47852 a 0.59132004,0.59132004 0 0 0 -0.42969,-1.01367 z"
- id="path24006-7"
- inkscape:connector-curvature="0" />
- </g>
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g26277"
+ transform="translate(273,-21)"
+ inkscape:label="M-23">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 668.49414,464.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 678.29297,476 H 675.25 a 0.50005,0.50005 0 1 0 0,1 h 4.18945 A 0.50005,0.50005 0 0 0 680,476.43945 V 472.25 a 0.50005,0.50005 0 1 0 -1,0 v 3.04297 l -10.14648,-10.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path24010-2"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 203.5,284 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -8,8 A 0.50005,0.50005 0 0 0 195,292.5 l -0.008,5.00586 a 0.50005,0.50005 0 0 0 0.5,0.50195 L 208.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 208 v 12 l -12.00781,0.008 0.008,-4.30078 z"
+ id="path23052"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 200.5,284 -5.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -4.50195 L 200.5,285 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path23056"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23341"
- transform="translate(62.999998,-41.999995)">
+ id="g22510"
+ transform="translate(-1.85367e-6,21)"
+ inkscape:label="M-22">
<g
- transform="translate(231,-63)"
- id="g23324"
- style="opacity:0.6;fill:#ffffff">
- <g
- transform="translate(430,-112)"
- id="g23301"
- style="fill:#ffffff" />
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g22476"
+ transform="translate(168,-42)">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 79.570312,578.01758 c -0.797869,-0.038 -1.571767,0.27684 -2.160156,0.86523 l -0.486328,0.48828 c -0.615772,0.57533 -0.93433,1.35407 -0.892578,2.1543 a 0.50005,0.50005 0 1 0 0.998047,-0.0508 c -0.02687,-0.51495 0.155664,-0.98016 0.576172,-1.37305 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 l 0.5,-0.5 c 0.411611,-0.41161 0.889666,-0.59872 1.404296,-0.57422 0.514631,0.0245 1.084383,0.26993 1.638672,0.82422 0.554795,0.5548 0.809544,1.13546 0.837891,1.65235 0.02835,0.51688 -0.152405,0.9848 -0.574219,1.3789 a 0.50005,0.50005 0 0 0 -0.01367,0.0117 l -0.5,0.5 c -0.412129,0.41213 -0.876932,0.60352 -1.396484,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.780667,0 1.524905,-0.31788 2.103516,-0.89649 l 0.488281,-0.48828 c 0.617686,-0.57711 0.936606,-1.36125 0.892578,-2.16406 -0.04403,-0.80281 -0.435654,-1.60948 -1.130859,-2.30469 -0.695711,-0.69571 -1.499006,-1.07724 -2.296876,-1.11523 z m -0.830078,3.72851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z m -6.179687,3.27149 c -0.807524,-0.0482 -1.595401,0.26944 -2.175781,0.89062 l -0.488282,0.48828 c -0.588388,0.58839 -0.903228,1.36034 -0.865234,2.15821 0.03799,0.79787 0.419524,1.60311 1.115234,2.29883 0.695206,0.6952 1.503832,1.08487 2.306641,1.1289 0.802809,0.044 1.584996,-0.27294 2.162109,-0.89062 l 0.488282,-0.48828 C 75.682126,590.0249 76,589.28067 76,588.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.191386,0.98436 -0.603516,1.39648 l -0.5,0.5 a 0.50005,0.50005 0 0 0 -0.01172,0.0117 c -0.394107,0.42182 -0.860068,0.60452 -1.376954,0.57618 -0.516885,-0.0283 -1.099502,-0.2831 -1.654296,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.822266,-1.63867 -0.02451,-0.51463 0.160654,-0.99268 0.572266,-1.40429 l 0.5,-0.5 a 0.50005,0.50005 0 0 0 0.01172,-0.0117 c 0.39634,-0.4242 0.866283,-0.60725 1.386719,-0.57618 a 0.50005,0.50005 0 1 0 0.05859,-0.99804 z m 1.679687,1.22851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.363282,-0.85743 z"
- id="path23322"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 447.5,263 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 8 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 276 h 8 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 A 0.50005,0.50005 0 0 0 460.5,274 H 460 v -8 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -8 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z m -9,1 h 8 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 8 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -8 v -0.5 A 0.50005,0.50005 0 0 0 449.5,274 H 449 v -8 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m -2,10 h 1 v 1 h -1 z m 11,0 h 1 v 1 h -1 z"
+ transform="translate(-168,21)"
+ id="path22458"
inkscape:connector-curvature="0" />
</g>
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 301.49414,515.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 312.29297,528 H 309.25 a 0.50005,0.50005 0 1 0 0,1 h 4.18945 A 0.50005,0.50005 0 0 0 314,528.43945 V 524.25 a 0.50005,0.50005 0 1 0 -1,0 v 3.04297 l -11.14648,-11.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path23333"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 451.5,246 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 4 v 4 h -4 z"
+ id="rect22466"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g22284-9"
- transform="translate(168,-252)">
+ id="g22386"
+ transform="translate(-886,80.0001)"
+ inkscape:label="M-21">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 54.75,284 a 0.50004997,0.50004997 0 0 0 -0.431641,0.24805 l -3.646484,6.25 a 0.50004997,0.50004997 0 0 0 -0.002,0.002 c -1.211575,2.0985 -0.741006,4.77251 1.115234,6.33008 1.856239,1.55756 4.573449,1.55756 6.429688,0 1.85624,-1.55757 2.326809,-4.23158 1.115234,-6.33008 a 0.50004997,0.50004997 0 0 0 -0.002,-0.002 l -3.646484,-6.25 A 0.50004997,0.50004997 0 0 0 55.25,284 Z m 0.25,1.06445 3.464844,5.9375 c 0.970958,1.6837 0.594513,3.81305 -0.894532,5.0625 -1.489569,1.2499 -3.651055,1.2499 -5.140624,0 -1.489045,-1.24945 -1.86549,-3.3788 -0.894532,-5.0625 V 291 Z m -0.511719,2.92969 a 0.50004997,0.50004997 0 0 0 -0.429687,0.27148 l -1.697266,3.20704 c -0.166111,0.28617 -0.283806,0.59778 -0.349609,0.92187 a 0.50005872,0.50005872 0 1 0 0.980469,0.19727 c 0.04414,-0.2174 0.122796,-0.42496 0.234374,-0.61719 a 0.50004997,0.50004997 0 0 0 0.0098,-0.0176 l 1.705078,-3.22265 a 0.50004997,0.50004997 0 0 0 -0.453125,-0.74024 z"
- id="path22264-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 433,263 c -3.84758,0 -6.97776,3.12003 -6.99805,6.96289 -6e-5,0.0125 -0.002,0.0246 -0.002,0.0371 a 0.50004994,0.50004994 0 0 0 0.002,0.0488 0.50004994,0.50004994 0 0 0 0,0.002 l -0.01,6.45508 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 432.96484,277 A 0.50004994,0.50004994 0 0 0 433,277 c 0.0171,0 0.0337,-0.002 0.0508,-0.002 a 0.50005,0.50005 0 0 0 0.008,0 C 436.89154,276.96613 440,273.84031 440,270 c 0,-3.86007 -3.1399,-7 -7,-7 z m 0,1 c 3.3196,0 6,2.68037 6,6 0,3.31963 -2.6804,6 -6,6 l -6.00781,0.008 0.01,-6.00781 a 0.50005,0.50005 0 0 0 0,-0.0215 C 427.01364,266.66895 429.68766,264 433,264 Z"
+ transform="translate(886,-80.0001)"
+ id="path22377"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1314.5,189 a 0.50005,0.50005 0 1 0 0,1 h 4.5 v 4.5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path22381"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(189,-210)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23463-9">
+ id="g22840"
+ transform="translate(-1.85367e-6,-20)"
+ inkscape:label="M-20">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 6.5,242 A 0.50005,0.50005 0 0 0 6,242.5 v 5 A 0.50005,0.50005 0 0 0 6.5,248 H 8 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 A 0.50005,0.50005 0 0 0 18,255.5 V 248 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 19.5,242 h -4 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 c 0,0.71532 -0.380592,1.37478 -1,1.73242 -0.619409,0.35765 -1.380591,0.35765 -2,0 -0.619408,-0.35764 -1,-1.0171 -1,-1.73242 v -0.5 A 0.50005,0.50005 0 0 0 10.5,242 Z m 0.5,1 h 3 c 0,1.07096 0.57257,2.06216 1.5,2.59766 0.927429,0.53549 2.072571,0.53549 3,0 0.92743,-0.5355 1.5,-1.5267 1.5,-2.59766 h 3 v 4 H 17.5 A 0.50005,0.50005 0 0 0 17,247.5 V 255 H 9 v -7.5 A 0.50005,0.50005 0 0 0 8.5,247 H 7 Z"
- id="path22384-8"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 412,286 c 1.65601,0 3,1.37486 3,3.04688 0,1.67201 -1.34399,3.04687 -3,3.04687 -1.65601,0 -3,-1.37486 -3,-3.04687 C 409,287.37486 410.34399,286 412,286 Z m 0,1 c -1.10534,0 -2,0.90526 -2,2.04688 0,1.14161 0.89466,2.04687 2,2.04687 1.10534,0 2,-0.90526 2,-2.04687 C 414,287.90526 413.10534,287 412,287 Z"
+ id="circle22836"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 412,283 c -3.5093,0 -6,2.77253 -6,5.91992 V 296 h -0.96094 a 0.50004991,0.50004991 0 1 0 0,1 H 406.5 a 0.50004991,0.50004991 0 0 0 0.5,-0.5 v -7.58008 C 407,286.29196 409.01002,284 412,284 c 2.99076,0 5,2.29197 5,4.91992 V 296.5 a 0.50004991,0.50004991 0 0 0 0.5,0.5 h 1.46094 a 0.50004991,0.50004991 0 1 0 0,-1 H 418 v -7.08008 C 418,285.77251 415.50996,283 412,283 Z"
+ id="path22838"
inkscape:connector-curvature="0" />
</g>
<g
- id="g6342"
- style="fill:#ffffff">
+ id="g135607"
+ style="display:inline;enable-background:new"
+ inkscape:label="M-19">
<path
inkscape:connector-curvature="0"
- id="path8743"
- d="m 31.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 A 0.50005,0.50005 0 0 0 40.5,494 Z m 0.5,1 h 8 v 8 h -8 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path10449"
+ d="m 391.5,263.00781 c -0.82054,0 -1.49609,0.67557 -1.49609,1.4961 0,0.82054 0.67555,1.49609 1.49609,1.49609 0.82053,0 1.49609,-0.67555 1.49609,-1.49609 0,-0.82053 -0.67556,-1.4961 -1.49609,-1.4961 z M 397,264 c -0.71373,0 -1.37556,0.3819 -1.73242,1 -0.19053,0.33001 -0.2484,0.68266 -0.25586,0.99609 v 0.0117 h -1.54297 C 393.0093,266.6044 392.2975,267 391.5,267 c -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 h -0.0195 -5.01563 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 5.01563 0.49805 l -0.0137,3.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.8602,0.89868 0.97657,0.21094 0.67528,-3.15139 1.9234,-4.08819 3.51757,-5.42773 1.58398,1.34059 2.83152,2.27746 3.51953,5.42968 0.13318,0.66658 1.13544,0.44609 0.97657,-0.21484 -0.76273,-3.49457 -2.35105,-4.70351 -4.00196,-6.11719 l 0.0137,-3.27539 h 2.21679 1.78516 v 0.004 c 0.007,0.31344 0.0653,0.66608 0.25586,0.99609 0.35686,0.61811 1.01869,1 1.73242,1 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 397 c -0.35807,0 -0.6862,-0.1899 -0.86523,-0.5 -0.0738,-0.12789 -0.11835,-0.32209 -0.12305,-0.51953 v -0.96875 c 0.005,-0.19744 0.0492,-0.39164 0.12305,-0.51953 0.17903,-0.3101 0.50716,-0.5 0.86523,-0.5 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13692-5-0"
+ transform="translate(316.007,-315)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="M-18">
<path
- id="path8759"
- d="m 38,496 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z m -3.513672,1.05078 c -0.16529,0.005 -0.314526,0.10024 -0.388672,0.24805 l -2.75,5.5 c -0.148607,0.29892 0.06852,0.64991 0.402344,0.65039 h 5.75 c 0.340259,-0.001 0.55634,-0.36474 0.394531,-0.66406 l -3,-5.5 c -0.08111,-0.14873 -0.238867,-0.23931 -0.408203,-0.23438 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 47.5,578 A 0.50005,0.50005 0 0 0 47,578.5 L 46.9922,589 c 0,1.51667 1.219298,3 2.984374,3 1.765077,0 3.015625,-1.475 3.015626,-3 L 53,578.5 A 0.50005,0.50005 0 0 0 52.5,578 Z m 0.5,1 h 4 l -0.0078,10 c 0,0.975 -0.811952,2 -2.015626,2 -1.203673,0 -1.984375,-1.01667 -1.984374,-2 z"
+ id="path13679-7-1"
inkscape:connector-curvature="0" />
<path
- inkscape:connector-curvature="0"
- id="path8807"
- d="M 29.492188,495.99219 A 0.50005,0.50005 0 0 0 29,496.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 30 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 27,498.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 28 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.69300022;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 58.492188,586 a 0.50005,0.50005 0 1 0 0,1 H 60 v 4 h -6.257812 a 0.50005,0.50005 0 1 0 0,1 H 60.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 60.5,586 Z"
+ id="path13681-7-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 56.492188,579 a 0.50005,0.50005 0 0 0 -0.345704,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 56.5,580.20703 58.792969,582.5 l -4.646485,4.64648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 56.492188,579 Z"
+ id="path13684-4-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 50,588 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z"
+ id="circle13686-9-5"
+ inkscape:connector-curvature="0" />
</g>
<g
+ style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
- transform="translate(-21.000002,42.000006)"
- id="g12626"
- style="display:inline;fill:#ffffff;enable-background:new">
+ transform="translate(422.009,-131.007)"
+ id="g22132"
+ inkscape:label="M-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 31.492188,367.99219 A 0.50005,0.50005 0 0 0 31,368.5 v 8.79297 l -3.853516,3.85351 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 31.707031,378 H 40.5 a 0.50005,0.50005 0 1 0 0,-1 H 32 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
- id="path12205"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -76.509766,394.00586 a 0.50005,0.50005 0 0 0 -0.486328,0.38867 l -3.011718,12.98828 a 0.50005,0.50005 0 0 0 0.486328,0.61328 h 9.974609 a 0.50005,0.50005 0 0 0 0.488281,-0.38476 l 3.03711,-12.99024 a 0.50005,0.50005 0 0 0 -0.488282,-0.61523 z m 0.398438,1 h 3.974609 l -1.154297,5 h -3.978515 z m 5,0 h 3.972656 l -1.169922,5 h -3.955078 z m -6.390625,6 h 3.980469 l -1.382813,5.99023 h -3.986328 z m 5.005859,0 h 3.953125 l -1.40039,5.99023 h -3.933594 z"
+ id="path22130"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 433.5,536 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4.98242 8.01758 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -0.5,5.48242 c -0.007,-0.18325 -0.1131,-0.34814 -0.27734,-0.42969 l -2,-1 c -0.24704,-0.12272 -0.54679,-0.0222 -0.66993,0.22461 l -4,8 c -0.12272,0.24704 -0.0222,0.54679 0.22461,0.66993 l 2,1 c 0.24704,0.12272 0.54679,0.0222 0.66993,-0.22461 l 4,-8 c 0.0373,-0.0744 0.0554,-0.15702 0.0527,-0.24024 z M 434,537 h 1 v 12 h -1 z m 3.5,1 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="rect11443"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 157.49219,472.99219 A 0.50005,0.50005 0 0 0 157,473.5 v 8.79297 l -3.85352,3.85351 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 157.70703,483 H 166.5 a 0.50005,0.50005 0 1 0 0,-1 H 158 v -8.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path22612"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-21.000002,4.4999696e-6)"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
+ id="g135604"
+ style="display:inline;enable-background:new"
+ inkscape:label="M-16">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 327.41406,263 a 0.50005,0.50005 0 1 0 0,1 h 1.17969 c 1.54365,0 2.90268,0.42079 3.85937,1.21484 0.9567,0.79406 1.54688,1.95474 1.54688,3.60352 0,1.90166 -0.93943,3.66928 -2.68164,4.99414 -1.74221,1.32486 -4.29199,2.1875 -7.44922,2.1875 h -2.36133 a 0.50005,0.50005 0 1 0 0,1 h 2.36133 c 3.33916,0 6.10577,-0.91054 8.05469,-2.39258 1.94891,-1.48204 3.07617,-3.55426 3.07617,-5.78906 0,-1.89677 -0.72902,-3.39433 -1.9082,-4.37305 C 331.91261,263.46659 330.31821,263 328.59375,263 Z"
+ id="path22657"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22457"
+ transform="translate(21,-21)"
+ inkscape:label="M-15">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 280.5,284 a 0.50004976,0.50004976 0 0 0 -0.5,0.5 v 0.75 7.25 a 0.50004976,0.50004976 0 0 0 0.5,0.5 h 0.5 a 0.50004976,0.50004976 0 0 0 0.2832,-0.0879 l 10.5,-7.25 A 0.50004976,0.50004976 0 0 0 292,285.25 v -0.75 a 0.50004976,0.50004976 0 0 0 -0.5,-0.5 z m 0.5,1 h 9.98242 L 281,291.89258 V 285.25 Z"
+ id="path22322"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 285.25,292 a 0.50004976,0.50004976 0 1 0 0,1 H 291 v 0.15625 l -10,3.80859 V 295.25 a 0.50004976,0.50004976 0 1 0 -1,0 v 2.25 a 0.50004976,0.50004976 0 0 0 0.5,0.5 h 0.5 a 0.50004976,0.50004976 0 0 0 0.17773,-0.0332 l 10.5,-4 A 0.50004976,0.50004976 0 0 0 292,293.5 v -1 a 0.50004976,0.50004976 0 0 0 -0.5,-0.5 z"
+ id="path22334"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22444"
+ transform="translate(-1.85367e-6,-42)"
+ inkscape:label="M-14">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 292.5,305 -9.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.50781 l 0.0391,2.49219 1,-0.0156 -0.0312,-1.98438 8,-0.008 -0.006,8.01172 -2,0.0195 0.01,1 2.49414,-0.0234 a 0.50005,0.50005 0 0 0 0.49414,-0.5 L 293,305.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path22408"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path22122"
+ d="m 279,309 v 2 h 2 v -2 z m 2,2 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 2,0 v 2 h 2 v -2 z m 2,0 h 2 v -2 h -2 z m 0,2 v 2 h 2 v -2 z m 0,2 h -2 v 2 h 2 z m 0,2 v 2 h 2 v -2 z m -2,0 h -2 v 2 h 2 z m -2,0 v -2 h -2 v 2 z m -2,0 h -2 v 2 h 2 z m 0,-2 v -2 h -2 v 2 z m 2,0 h 2 v -2 h -2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22406"
+ transform="translate(21,-21)"
+ inkscape:label="M-13">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 240.49805,288 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 241,288.5 A 0.50005,0.50005 0 0 0 240.49805,288 Z M 240,289.00195 l -0.008,8.00586 h -2 v -8.00195 z"
+ id="path22383"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 250.49805,284 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 251,284.5 A 0.50005,0.50005 0 0 0 250.49805,284 Z M 250,285.00195 l -0.008,8.00586 h -2 v -8.00195 z M 245.49805,286 l -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 246,286.5 A 0.50005,0.50005 0 0 0 245.49805,286 Z M 245,287.00195 l -0.008,8.00586 h -2 v -8.00195 z"
+ id="path22387"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,550.993,-21)"
+ id="g22139"
+ inkscape:label="M-12">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 310.5,287 -10.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 311,287.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,9.00781 h -9 v -9.00195 z"
+ id="path22135"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 300.5,284 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z m 12.99219,2.99219 A 0.50005,0.50005 0 0 0 313,287.5 l -0.008,10.00586 a 0.50005,0.50005 0 1 0 1,0.002 L 314,287.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22141"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-2.85367e-6,-21)"
+ id="g22228"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="M-11">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 225.5,286 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6.5 h -6.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 l -0.008,4.00586 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 229.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 10 l -10.00781,0.008 0.006,-3.00781 H 225.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z"
+ id="path22226"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 222.5,284 a 0.50005,0.50005 0 0 1 0.5,0.5 v 6 a 0.50005,0.50005 0 0 1 -0.5,0.5 h -6 a 0.50005,0.50005 0 0 1 -0.5,-0.5 v -6 a 0.50005,0.50005 0 0 1 0.5,-0.5 z m -0.5,1 h -5 v 5 h 5 z"
+ id="rect22230"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g16957-2"
+ transform="rotate(90,380.0015,176.0065)"
inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- id="g12548">
- <g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="translate(640.00001,-112)"
- id="g7753-3">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -539.42969,690.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -0.48633,0.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 0.5,-0.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -0.5,0.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 0.48828,-0.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -7.00976,7 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -0.48829,0.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 0.48829,-0.48828 C -543.31787,702.0249 -543,701.28067 -543,700.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -0.5,0.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 0.5,-0.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z"
- id="path12469-4"
- inkscape:connector-curvature="0" />
- </g>
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="M-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 94.492188,577.99219 A 0.50005,0.50005 0 0 0 94,578.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2.998047,1.00195 a 0.50005,0.50005 0 0 0 -0.347657,0.85938 l 1,1 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1,-1 a 0.50005,0.50005 0 0 0 -0.359375,-0.15234 z M 90.5,582 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 11,5 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m -2.007812,1.99219 A 0.50005,0.50005 0 0 0 99,589.5 v 2 a 0.50005,0.50005 0 1 0 1,0 v -2 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m 2.001952,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1,1 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path12538"
+ id="path16949-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 479,347 c -1.09865,0 -1.99999,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 -10e-6,-1.09865 -0.90135,-2 -2,-2 z m 0,1 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.55821 0.44179,-1 1,-1 z m 0.5,9 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -10,-11 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z m 0,1 c 0.28207,0 0.5,0.21793 0.5,0.5 0,0.28207 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z m 0,8 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z m 0,1 c 0.83434,0 1.5,0.66566 1.5,1.5 0,0.83434 -0.66566,1.5 -1.5,1.5 -0.83434,0 -1.5,-0.66566 -1.5,-1.5 0,-0.83434 0.66566,-1.5 1.5,-1.5 z"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 469.49219,348.99219 A 0.50005,0.50005 0 0 0 469,349.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7.99804,1.0039 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 473.5,358 a 0.50005,0.50005 0 1 0 0,1 h 5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path16955-3"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8536743e-6,4.4999696e-6)"
- id="g23748"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;enable-background:new"
+ id="g27915"
+ inkscape:label="M-9">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 180.5,263 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 6 v 6 h -2 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 183 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 181 Z"
+ id="path27886"
inkscape:connector-curvature="0"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 49,558 v 3 h 3 v -3 z m 3,3 v 3 h 3 v -3 z m 3,0 h 3 v -3 h -3 z m 3,0 v 3 h 3 v -3 z m 0,3 h -3 v 3 h 3 z m 0,3 v 3 h 3 v -3 z m -3,0 h -3 v 3 h 3 z m -3,0 v -3 h -3 v 3 z"
- id="path10767"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96" />
+ sodipodi:nodetypes="cccccccccccccccccccccccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 48.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 61.5,557 Z m 0.5,1 h 12 v 12 H 49 Z"
- id="rect22625"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 176.50781,262.99414 a 0.50005,0.50005 0 0 0 -0.45508,0.72852 l 1,2 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -1,-2 a 0.50005,0.50005 0 0 0 -0.43946,-0.2832 z m -2.02539,3.00195 a 0.50005,0.50005 0 0 0 -0.20508,0.95118 l 2,1 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 l -2,-1 a 0.50005,0.50005 0 0 0 -0.24024,-0.0566 z m 11,6 a 0.50005,0.50005 0 0 0 -0.20508,0.95118 l 2,1 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 l -2,-1 a 0.50005,0.50005 0 0 0 -0.24024,-0.0566 z m -0.97461,1.99805 a 0.50005,0.50005 0 0 0 -0.45508,0.72852 l 1,2 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -1,-2 a 0.50005,0.50005 0 0 0 -0.43946,-0.2832 z"
+ id="path27898"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 174.5,269 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 l -0.008,-4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.5 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.4961 L 178,269.50391 A 0.50005,0.50005 0 0 0 177.5,269 Z m 0.5,1 h 1.99609 l -0.004,0.49609 a 0.50005,0.50005 0 0 0 0.5,0.50391 h 1.5 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 l 0.008,3 h -6 z"
+ id="path10946"
inkscape:connector-curvature="0" />
</g>
<g
- transform="matrix(-1,0,0,1,593.8323,-41.999985)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g24182">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21555"
+ transform="translate(-1.85367e-6,-21)"
+ inkscape:label="M-8">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 309.83203,496 c -0.79167,0 -1.54903,0.39305 -1.86328,1.11133 -0.31425,0.71827 -0.0786,1.6538 0.75977,2.49219 l 2.5,2.5 c 0.66161,0.66161 0.67598,1.10108 0.55273,1.38281 C 311.658,503.76805 311.29036,504 310.83203,504 l -7.28515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 7.30078,0.008 c 0.79167,0 1.55099,-0.39305 1.86524,-1.11133 0.31424,-0.71827 0.0767,-1.6538 -0.76172,-2.49219 l -2.5,-2.5 c -0.66161,-0.66161 -0.67404,-1.10108 -0.55078,-1.38281 C 309.00802,497.23195 309.3737,497 309.83203,497 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path24180"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 160.50391,263.00391 c -0.82069,0 -1.4961,0.67734 -1.4961,1.49804 1e-5,0.64713 0.422,1.19917 1.00196,1.40625 -0.004,0.17741 -0.01,0.3625 -0.01,0.58594 0,0.8575 0.30572,1.55064 0.73242,2.08984 0.42671,0.53921 0.958,0.94374 1.45313,1.34375 0.99025,0.80003 1.81445,1.48075 1.81445,3.0293 0,1.03964 -0.41467,1.75679 -1.05859,2.26367 C 162.29747,275.72759 161.4016,276 160.5,276 c -0.9016,0 -1.79749,-0.27241 -2.44141,-0.7793 C 157.41467,274.71382 157,273.99667 157,272.95703 v -1.25 l 1.14648,1.14649 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -2,-2 c -0.315,-0.31479 -0.85335,-0.0918 -0.85352,0.35352 v 2.45703 c 0,1.32194 0.58533,2.37688 1.44141,3.05078 0.85608,0.6739 1.96019,0.99219 3.05859,0.99219 1.0984,0 2.20251,-0.31829 3.05859,-0.99219 0.85608,-0.6739 1.44141,-1.72884 1.44141,-3.05078 0,-1.93167 -1.1758,-2.99085 -2.18555,-3.80664 -0.50487,-0.40789 -0.97358,-0.77897 -1.29687,-1.1875 C 161.19428,267.55436 161,267.12816 161,266.49414 c 0,-0.20716 0.005,-0.40692 0.01,-0.58984 0.57393,-0.21035 0.99023,-0.75955 0.99023,-1.40235 0,-0.8207 -0.67541,-1.49804 -1.49609,-1.49804 z m 0,1 c 0.27921,0 0.49609,0.21676 0.49609,0.49804 0,0.28129 -0.21688,0.49805 -0.49609,0.49805 -0.27922,0 -0.4961,-0.21676 -0.4961,-0.49805 0,-0.28128 0.21688,-0.49804 0.4961,-0.49804 z"
+ transform="translate(1.85367e-6,21)"
+ id="path16949-6-5"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(112.05535,339.92702)"
- id="g44391-4"
- style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- id="rect44387-5"
- width="16"
- height="16"
- x="103"
- y="111" />
- <circle
- r="8"
- cy="118"
- cx="132"
- style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- id="circle44389-4"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- transform="matrix(-0.248353,0.02816779,0.02830718,0.248422,140.45214,86.01031)" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22599"
+ transform="translate(-1.85367e-6,-22)"
+ inkscape:label="M-7">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 132.5,285 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="path22722"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 139,287 c -2.75493,0 -5,2.24492 -5,5 0,2.75508 2.24507,5 5,5 2.75493,0 5,-2.24492 5,-5 0,-2.75508 -2.24507,-5 -5,-5 z m 0,1.09961 c 2.1604,0 3.90039,1.73975 3.90039,3.90039 0,2.16064 -1.73999,3.90039 -3.90039,3.90039 -2.1604,0 -3.90039,-1.73975 -3.90039,-3.90039 0,-2.16064 1.73999,-3.90039 3.90039,-3.90039 z"
+ id="ellipse22724"
+ inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23689-9"
- transform="rotate(180,957.9976,414.99747)">
+ id="g22589"
+ inkscape:label="M-6">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1419.4941,588.00195 c 4.1402,0 7.5079,-3.36769 7.5079,-7.50781 a 0.50004997,0.50004997 0 1 0 -1,0 c 0,3.59968 -2.9082,6.50781 -6.5079,6.50781 a 0.50004997,0.50004997 0 1 0 0,1 z"
- id="path23647-2"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 120.85938,263.01172 c -2.71113,-0.14985 -5.132,0.84146 -7.07032,2.78125 -2.61921,2.6212 -3.50441,6.90582 -2.24609,9.9043 0.25386,0.60493 0.66496,1.06469 1.2168,1.20507 0.55183,0.14039 1.13738,-0.0925 1.59375,-0.54882 l 10,-10 a 0.50005,0.50005 0 0 0 0.01,-0.01 c 0.45574,-0.48275 0.74002,-1.03795 0.61133,-1.61328 -0.12869,-0.57533 -0.64203,-0.96413 -1.31445,-1.18164 -0.96105,-0.31088 -1.89708,-0.48716 -2.80078,-0.53711 z m -0.0586,0.98437 c 0.81237,0.051 1.66258,0.21855 2.55078,0.50586 0.49509,0.16015 0.62426,0.33915 0.64844,0.44727 0.0242,0.10812 -0.028,0.35187 -0.36328,0.70703 l -9.99024,9.99023 c -0.29363,0.29364 -0.48952,0.32555 -0.64062,0.28711 -0.1511,-0.0384 -0.36452,-0.20246 -0.54102,-0.62304 -1.05362,-2.51071 -0.27172,-6.50583 2.03125,-8.81055 1.77041,-1.77175 3.86758,-2.65679 6.30469,-2.50391 z M 115.48438,267 a 0.50005,0.50005 0 0 0 -0.34376,0.15234 C 113.75486,268.5381 112.997,270.82305 113,272.5 a 0.50005,0.50005 0 1 0 1,0 c -0.002,-1.34281 0.7435,-3.53647 1.84766,-4.64062 A 0.50005,0.50005 0 0 0 115.48438,267 Z m 7.02343,3 a 0.50005,0.50005 0 1 0 0,1 c 0.67897,0 1.01439,0.13886 1.19922,0.33398 0.18483,0.19513 0.30078,0.54691 0.30078,1.16602 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.74159 -0.136,-1.38882 -0.57617,-1.85352 C 123.99147,270.18179 123.32885,270 122.50781,270 Z m -2.01562,1.99219 A 0.50005,0.50005 0 0 0 120,272.5 c 0,0.86111 0.31215,1.53681 0.80469,1.94727 0.49254,0.41045 1.11198,0.55273 1.69531,0.55273 0.41667,0 0.79723,0.10772 1.05469,0.32227 C 123.81215,275.53681 124,275.86111 124,276.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.86111 -0.31215,-1.53681 -0.80469,-1.94727 C 123.70277,274.14228 123.08333,274 122.5,274 c -0.41667,0 -0.79723,-0.10772 -1.05469,-0.32227 C 121.18785,273.46319 121,273.13889 121,272.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 118,274.5 c 0,0.82103 0.18179,1.48561 0.64648,1.92578 C 119.11118,276.86595 119.75841,277 120.5,277 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 c -0.61911,0 -0.97089,-0.11595 -1.16602,-0.30078 C 119.13886,275.51439 119,275.17897 119,274.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22545"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-336,-84)"
+ id="g28475"
+ style="display:inline;enable-background:new"
+ inkscape:label="M-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1416.4941,585.10156 c 4.1942,0 7.6075,-3.41326 7.6075,-7.60742 a 0.6006,0.6006 0 1 0 -1.2012,0 c 0,3.54564 -2.8606,6.40625 -6.4063,6.40625 a 0.600585,0.600585 0 1 0 0,1.20117 z"
- id="path23668-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 427.5,348 c -1.37479,0 -2.5,1.12521 -2.5,2.5 0,1.17958 0.69047,1.86035 1.13281,2.33984 0.59193,0.64165 1.20449,1.21721 1.66016,1.66016 l -0.89649,0.89648 c -0.91207,0.91207 -1.15649,2.32468 -0.5625,3.35352 0.56456,0.97783 1.72188,1.4563 2.8125,1.16406 C 430.23711,359.62183 431,358.6291 431,357.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.68132 -0.45321,1.27287 -1.11133,1.44922 -0.65811,0.17634 -1.34683,-0.10917 -1.6875,-0.69922 -0.31121,-0.53904 -0.18558,-1.55855 0.40235,-2.14648 l 1.25,-1.25 a 0.50005,0.50005 0 0 0 0,-0.70704 c -0.4316,-0.43159 -1.30799,-1.251 -1.98633,-1.98632 C 426.38701,351.63965 426,351.32042 426,350.5 c 0,-0.83435 0.66565,-1.5 1.5,-1.5 1.16667,0 2.02863,1.23566 2.64648,1.85352 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 C 430.47137,349.76434 429.33333,348 427.5,348 Z"
+ id="path28463"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1413.4941,582.10156 c 4.1942,0 7.6075,-3.41326 7.6075,-7.60742 a 0.6006,0.6006 0 1 0 -1.2012,0 c 0,3.54564 -2.8606,6.40625 -6.4063,6.40625 a 0.600585,0.600585 0 1 0 0,1.20117 z"
- id="path23670-8"
+ id="path28468"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 437.5,348 c -1.83333,0 -2.97137,1.76434 -3.35352,2.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 C 435.47137,350.23566 436.33333,349 437.5,349 c 0.83435,0 1.5,0.66565 1.5,1.5 0,0.82042 -0.38701,1.13965 -0.86719,1.66016 -0.67834,0.73532 -1.55473,1.55473 -1.98633,1.98632 a 0.50005,0.50005 0 0 0 0,0.70704 l 1.25,1.25 c 0.58793,0.58793 0.71356,1.60744 0.40235,2.14648 -0.34067,0.59005 -1.02939,0.87556 -1.6875,0.69922 C 435.45321,358.77287 435,358.18132 435,357.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,1.1291 0.76289,2.12183 1.85352,2.41406 1.09062,0.29224 2.24794,-0.18623 2.8125,-1.16406 0.59399,-1.02884 0.34957,-2.44145 -0.5625,-3.35352 L 437.20703,354.5 c 0.45567,-0.44295 1.06823,-1.01851 1.66016,-1.66016 C 439.30953,352.36035 440,351.67958 440,350.5 c 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m -4.5,4.00005 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z" />
+ </g>
+ <g
+ transform="translate(-168,-21)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g26390"
+ inkscape:label="M-4">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 74.492188,262.99219 a 0.50005,0.50005 0 0 0 -0.09961,0.0117 l -4.90039,0.004 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 5 a 0.50005,0.50005 0 1 0 1,0 V 269 H 74.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4.49805 L 79.5,264 a 0.50005,0.50005 0 1 0 0,-1 l -4.892578,0.004 a 0.50005,0.50005 0 0 0 -0.115234,-0.0117 z M 74,264.00391 V 268 h -4.007812 v -3.99414 z"
+ transform="translate(168,21)"
+ id="path23021"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 250.48438,284 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -13.00781,13.00782 a 0.50005,0.50005 0 0 0 0.35352,0.85351 L 250.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 250.48438,284 Z M 250,285.70703 V 297 l -11.30078,0.008 z"
+ id="path23044"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23935-0"
- transform="translate(-924,-332)">
+ id="g22221"
+ transform="translate(21,-21)"
+ inkscape:label="M-3">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1404.4688,576.96289 a 1.50015,1.50015 0 0 0 -0.1036,0.01 c -4.9348,0.53258 -8.8525,4.44095 -9.3925,9.375 a 1.5001977,1.5001977 0 1 0 2.9824,0.32812 c 0.3887,-3.55095 3.1789,-6.33741 6.7304,-6.7207 a 1.50015,1.50015 0 0 0 -0.2167,-2.99219 z"
- id="path23640-2-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 48.5,267 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 9 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 13 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -6 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 54 v -2.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m 0.5,1 h 4 v 2 h -4 z m 0,3 h 2 v 2 h -2 z m 3,0 h 4 v 2 h -4 z m 5,0 h 4 v 2 h -4 z m -8,3 h 4 v 2 h -4 z m 5,0 h 4 v 2 h -4 z m 5,0 h 2 v 2 h -2 z"
+ transform="translate(-21,21)"
+ id="rect22184"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 40.5,284 a 0.50005,0.50005 0 0 1 0.5,0.5 v 3 a 0.50005,0.50005 0 0 1 -0.5,0.5 h -5 A 0.50005,0.50005 0 0 1 35,287.5 v -3 a 0.50005,0.50005 0 0 1 0.5,-0.5 z m -0.5,1 h -4 v 2 h 4 z"
+ id="rect22200"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21947"
+ transform="matrix(-1,0,0,1,67.9866,-21)"
+ inkscape:label="M-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1405.498,573.99805 c -7.4498,0 -13.5,6.0501 -13.5,13.5 a 0.50004997,0.50004997 0 1 0 1,0 c 0,-6.90946 5.5906,-12.5 12.5,-12.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
- id="path23706-8"
+ id="circle21927"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27.460938,284.01172 a 0.50005,0.50005 0 1 0 0.04297,0.99805 c 3.348416,-0.1388 6.600566,1.12874 8.972656,3.49609 2.372091,2.36735 3.645762,5.61811 3.513672,8.9668 a 0.50038206,0.50038206 0 1 0 1,0.0391 c 0.143077,-3.62723 -1.237239,-7.14863 -3.80664,-9.71289 -2.569402,-2.56427 -6.09572,-3.93745 -9.722656,-3.78711 z m -0.0332,4.00586 a 0.50005,0.50005 0 1 0 0.0625,0.99804 c 2.281784,-0.14542 4.516597,0.69332 6.140625,2.30274 1.62403,1.60942 2.482218,3.83613 2.357422,6.11914 a 0.50005,0.50005 0 1 0 0.998047,0.0547 c 0.140364,-2.5678 -0.823774,-5.07459 -2.65039,-6.88477 -1.826617,-1.81018 -4.341781,-2.75341 -6.908204,-2.58984 z m 0.03711,4.01172 a 0.50005,0.50005 0 1 0 0.107422,0.99414 c 1.199607,-0.12917 2.392346,0.29002 3.248046,1.14062 0.855701,0.8506 1.282148,2.03988 1.160157,3.24024 a 0.50005,0.50005 0 1 0 0.99414,0.10156 c 0.152408,-1.49965 -0.380162,-2.99006 -1.449218,-4.05274 -1.069056,-1.06268 -2.561836,-1.5852 -4.060547,-1.42382 z M 28,296 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g13692-5-0"
- transform="translate(316.0071,-315)"
+ id="g13852"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ inkscape:label="M-1">
+ <g
+ id="g11167"
+ transform="matrix(0,-1,-1,0,688.995,-44.9794)"
+ style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 47.5,578 A 0.50005,0.50005 0 0 0 47,578.5 L 46.9922,589 c 0,1.51667 1.219298,3 2.984374,3 1.765077,0 3.015625,-1.475 3.015626,-3 L 53,578.5 A 0.50005,0.50005 0 0 0 52.5,578 Z m 0.5,1 h 4 l -0.0078,10 c 0,0.975 -0.811952,2 -2.015626,2 -1.203673,0 -1.984375,-1.01667 -1.984374,-2 z"
- id="path13679-7-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 14.505859,263.01562 a 0.55005501,0.55005501 0 0 0 -0.05664,0.004 c -1.480032,0.16258 -2.81124,0.9768 -3.632813,2.21875 -0.754587,1.14068 -0.9438173,2.54615 -0.65039,3.875 l -3.5234379,3.52149 c -0.4164576,0.37981 -0.6354253,0.95498 -0.6601562,1.61328 -0.024627,0.65553 0.1896767,1.40646 0.7832031,2 0.5945619,0.59455 1.3481437,0.80114 1.9980469,0.76953 0.6519363,-0.0317 1.2112985,-0.25543 1.5917971,-0.63672 l 3.533203,-3.54297 c 1.328363,0.29148 2.734045,0.0991 3.873047,-0.6543 1.240498,-0.82051 2.05459,-2.151 2.21875,-3.6289 a 0.55005501,0.55005501 0 0 0 -0.160157,-0.45117 l -0.943359,-0.92969 a 0.55005501,0.55005501 0 0 0 -0.775391,0.002 l -1.80664,1.79883 h -0.589844 l -1.679687,-1.67969 v -0.58984 l 1.804687,-1.80078 a 0.55005501,0.55005501 0 0 0 0.0039,-0.77539 l -0.93164,-0.94727 a 0.55005501,0.55005501 0 0 0 -0.396485,-0.16602 z m -0.15625,1.17383 0.316407,0.32227 -1.580078,1.57617 a 0.55005501,0.55005501 0 0 0 -0.16211,0.39063 l 0.002,1.04687 a 0.55005501,0.55005501 0 0 0 0.16211,0.38672 l 2.001953,2.00195 a 0.55005501,0.55005501 0 0 0 0.388672,0.16211 l 1.046875,-0.002 a 0.55005501,0.55005501 0 0 0 0.386718,-0.16016 l 1.580079,-1.57422 0.318359,0.31446 c -0.183326,1.05859 -0.751902,2.01444 -1.654297,2.61132 -0.970627,0.64202 -2.219467,0.82961 -3.330078,0.49219 a 0.55005501,0.55005501 0 0 0 -0.548828,0.13672 l -3.699219,3.70899 c -0.1021327,0.10234 -0.4754005,0.29532 -0.8691406,0.31445 -0.395773,0.0192 -0.8021096,-0.0834 -1.1660156,-0.44727 -0.3650748,-0.36508 -0.4778317,-0.78393 -0.4628907,-1.18164 0.014838,-0.39496 0.2099663,-0.75541 0.3046875,-0.84179 a 0.55005501,0.55005501 0 0 0 0.017578,-0.0176 l 3.7070314,-3.70508 a 0.55005501,0.55005501 0 0 0 0.136719,-0.54883 c -0.339386,-1.11269 -0.154519,-2.36033 0.488281,-3.33203 0.59791,-0.90384 1.555081,-1.47203 2.615234,-1.6543 z"
+ id="path11179"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24393-7-4"
+ transform="matrix(-1,0,0,1,1912.004,-92)"
+ inkscape:label="L-26">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 58.492188,586 a 0.50005,0.50005 0 1 0 0,1 H 60 v 4 h -6.257812 a 0.50005,0.50005 0 1 0 0,1 H 60.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 60.5,586 Z"
- id="path13681-7-8"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1367.5039,334.00195 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 9.99219 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 9.9961 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -9.99219 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 H 1377 v 8.99219 h -8.9961 z"
+ id="path24368-5-5"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 56.492188,579 a 0.50005,0.50005 0 0 0 -0.345704,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 56.5,580.20703 58.792969,582.5 l -4.646485,4.64648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 56.492188,579 Z"
- id="path13684-4-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1376,338 -4.4961,0.002 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 V 343 h 1 v -3.99805 L 1376,339 Z m 3,0 v 1 l 1,0.002 v 7.99024 h -7.9961 V 346 h -1 v 1.49219 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 8.9961 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -8.99024 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z"
+ id="path24388-3-2"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g18316"
+ transform="translate(21,-63)"
+ inkscape:label="L-25">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 50,588 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z"
- id="circle13686-9-5"
+ d="m 496,305 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
+ id="circle17690"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 496.49219,306.99219 A 0.50005,0.50005 0 0 0 496,307.5 v 5 a 0.50005,0.50005 0 0 0 0.22266,0.41602 l 3,2 a 0.50005,0.50005 0 1 0 0.55468,-0.83204 L 497,312.23242 V 307.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path17692"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 491.5,312 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path17694"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 492.74414,308.24414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1.75,1.75 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.75,-1.75 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path17696"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23993-7"
- transform="matrix(1,0,0,-1,-1008,851.0067)">
+ id="g23689-9"
+ transform="rotate(180,958,414.9975)"
+ inkscape:label="L-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1437,595.60938 c 0,6.25034 4.6305,11.38281 10.4004,11.38281 a 0.60006002,0.60006002 0 1 0 0,-1.19922 c -5.0564,0 -9.2012,-4.52271 -9.2012,-10.18359 a 0.60006002,0.60006002 0 1 0 -1.1992,0 z"
- id="path23981-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1419.4941,588.00195 c 4.1402,0 7.5079,-3.36769 7.5079,-7.50781 a 0.50004997,0.50004997 0 1 0 -1,0 c 0,3.59968 -2.9082,6.50781 -6.5079,6.50781 a 0.50004997,0.50004997 0 1 0 0,1 z"
+ id="path23647-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1416.4941,585.10156 c 4.1942,0 7.6075,-3.41326 7.6075,-7.60742 a 0.6006,0.6006 0 1 0 -1.2012,0 c 0,3.54564 -2.8606,6.40625 -6.4063,6.40625 a 0.600585,0.600585 0 1 0 0,1.20117 z"
+ id="path23668-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1413.4941,582.10156 c 4.1942,0 7.6075,-3.41326 7.6075,-7.60742 a 0.6006,0.6006 0 1 0 -1.2012,0 c 0,3.54564 -2.8606,6.40625 -6.4063,6.40625 a 0.600585,0.600585 0 1 0 0,1.20117 z"
+ id="path23670-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23935-0"
+ transform="translate(-924,-332)"
+ inkscape:label="L-23">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1404.4688,576.96289 a 1.50015,1.50015 0 0 0 -0.1036,0.01 c -4.9348,0.53258 -8.8525,4.44095 -9.3925,9.375 a 1.5001977,1.5001977 0 1 0 2.9824,0.32812 c 0.3887,-3.55095 3.1789,-6.33741 6.7304,-6.7207 a 1.50015,1.50015 0 0 0 -0.2167,-2.99219 z"
+ id="path23640-2-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1405.498,573.99805 c -7.4498,0 -13.5,6.0501 -13.5,13.5 a 0.50004997,0.50004997 0 1 0 1,0 c 0,-6.90946 5.5906,-12.5 12.5,-12.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
+ id="path23706-8"
inkscape:connector-curvature="0" />
- <g
- style="opacity:0.6;fill:#ffffff"
- id="g23987-2">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1444.5,597 c -1.4566,10e-6 -2.897,0.34937 -4.2207,1.02148 a 0.50005,0.50005 0 1 0 0.4531,0.89063 c 1.1877,-0.60305 2.4706,-0.9121 3.7676,-0.91211 a 0.50005,0.50005 0 1 0 0,-1 z m -8.0176,4.01172 a 0.50005,0.50005 0 0 0 -0.4043,0.23242 C 1434.7288,603.30241 1434,605.86102 1434,608.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.45438 0.6833,-4.83156 1.9141,-6.70898 a 0.50005,0.50005 0 0 0 -0.4317,-0.7793 z"
- id="path23983-7"
- inkscape:connector-curvature="0" />
- </g>
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
transform="rotate(180,947.5,425.5)"
- id="g24104-2">
+ id="g24104-2"
+ inkscape:label="L-22">
<g
id="g24094-5"
style="opacity:0.5;fill:#ffffff">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 449,242 c -1.0986,0 -2,0.90135 -2,2 0,0.73315 0.40645,1.37054 1,1.71875 V 250 h 1 v -4 c 1.0986,0 2,-0.90135 2,-2 h 4 v -1 h -4.28125 c -0.34822,-0.59355 -0.98563,-1 -1.71875,-1 z m 0,1 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z"
- transform="rotate(-180,947.5,425.5)"
+ transform="rotate(180,947.5,425.5)"
id="circle24085-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssccccccccssssss" />
@@ -12694,27 +14344,53 @@
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 459,242 c -1.0986,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -7.27735,7.27735 C 449.71022,252.10883 449.36858,252 449,252 c -1.0986,0 -2,0.90135 -2,2 0,1.09865 0.9014,2 2,2 1.0986,0 2,-0.90135 2,-2 0,-0.36859 -0.10883,-0.71022 -0.28516,-1.00781 l 7.27735,-7.27735 C 458.28978,245.89117 458.63142,246 459,246 c 1.0986,0 2,-0.90135 2,-2 0,-1.09865 -0.9014,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z m -10,10 c 0.5582,0 1,0.44179 1,1 0,0.55821 -0.4418,1 -1,1 -0.5582,0 -1,-0.44179 -1,-1 0,-0.55821 0.4418,-1 1,-1 z"
- transform="rotate(-180,947.5,425.5)"
+ transform="rotate(180,947.5,425.5)"
id="path24100-8"
inkscape:connector-curvature="0" />
</g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 416.49023,242.95508 a 0.55005501,0.55005501 0 0 0 -0.55078,0.55078 v 0.77539 l -0.44922,0.45117 -0.61132,-0.61133 a 0.55005501,0.55005501 0 0 0 -0.38868,-0.16211 h -1.77148 l -0.83984,-0.83789 a 0.55005501,0.55005501 0 0 0 -0.77735,0 l -1,1 a 0.55005501,0.55005501 0 0 0 -0.16211,0.38868 v 1.77148 l -0.67773,0.67773 h -0.77149 a 0.55005501,0.55005501 0 0 0 -0.39062,0.16211 l -0.83789,0.8418 h -0.77149 a 0.55005501,0.55005501 0 0 0 -0.55078,0.55078 v 2.00391 a 0.55005501,0.55005501 0 0 0 0.55078,0.55078 h 0.77344 l 0.67578,0.67383 v 0.54492 l -0.67578,0.68164 -0.76758,-0.008 a 0.55005501,0.55005501 0 0 0 -0.55664,0.54883 v 1.21093 0.78907 a 0.550785,0.550785 0 1 0 1.10157,0 v -0.78907 -0.65429 l 0.44336,0.004 a 0.55005501,0.55005501 0 0 0 0.39648,-0.16211 l 1,-1.00781 a 0.55005501,0.55005501 0 0 0 0.16016,-0.38672 v -1 a 0.55005501,0.55005501 0 0 0 -0.16211,-0.39062 l -1,-0.99414 a 0.55005501,0.55005501 0 0 0 -0.38868,-0.16211 h -0.44921 v -0.90235 h 0.44921 a 0.55005501,0.55005501 0 0 0 0.38868,-0.16211 l 0.83984,-0.84375 h 0.77148 a 0.55005501,0.55005501 0 0 0 0.38868,-0.16015 l 1,-1 a 0.55005501,0.55005501 0 0 0 0.16211,-0.38867 v -1.77344 l 0.44921,-0.44922 0.61133,0.61133 a 0.55005501,0.55005501 0 0 0 0.38867,0.16015 h 1.77149 l 0.83984,0.83985 a 0.55005501,0.55005501 0 0 0 0.77735,0 l 1,-1 a 0.55005501,0.55005501 0 0 0 0.16211,-0.38867 v -0.45508 h 1.44921 a 0.55005501,0.55005501 0 1 0 0,-1.09961 z"
- id="path42222-9-3-2"
- inkscape:connector-curvature="0" />
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23993-7"
+ transform="matrix(1,0,0,-1,-1008,851.007)"
+ inkscape:label="L-21">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1437,595.60938 c 0,6.25034 4.6305,11.38281 10.4004,11.38281 a 0.60006002,0.60006002 0 1 0 0,-1.19922 c -5.0564,0 -9.2012,-4.52271 -9.2012,-10.18359 a 0.60006002,0.60006002 0 1 0 -1.1992,0 z"
+ id="path23981-7"
+ inkscape:connector-curvature="0" />
+ <g
+ style="opacity:0.6;fill:#ffffff"
+ id="g23987-2">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1444.5,597 c -1.4566,10e-6 -2.897,0.34937 -4.2207,1.02148 a 0.50005,0.50005 0 1 0 0.4531,0.89063 c 1.1877,-0.60305 2.4706,-0.9121 3.7676,-0.91211 a 0.50005,0.50005 0 1 0 0,-1 z m -8.0176,4.01172 a 0.50005,0.50005 0 0 0 -0.4043,0.23242 C 1434.7288,603.30241 1434,605.86102 1434,608.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.45438 0.6833,-4.83156 1.9141,-6.70898 a 0.50005,0.50005 0 0 0 -0.4317,-0.7793 z"
+ id="path23983-7"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g143023"
+ style="display:inline;enable-background:new"
+ inkscape:label="L-20">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 416.49023,242.95508 a 0.55005501,0.55005501 0 0 0 -0.55078,0.55078 v 0.77539 l -0.44922,0.45117 -0.61132,-0.61133 a 0.55005501,0.55005501 0 0 0 -0.38868,-0.16211 h -1.77148 l -0.83984,-0.83789 a 0.55005501,0.55005501 0 0 0 -0.77735,0 l -1,1 a 0.55005501,0.55005501 0 0 0 -0.16211,0.38868 v 1.77148 l -0.67773,0.67773 h -0.77149 a 0.55005501,0.55005501 0 0 0 -0.39062,0.16211 l -0.83789,0.8418 h -0.77149 a 0.55005501,0.55005501 0 0 0 -0.55078,0.55078 v 2.00391 a 0.55005501,0.55005501 0 0 0 0.55078,0.55078 h 0.77344 l 0.67578,0.67383 v 0.54492 l -0.67578,0.68164 -0.76758,-0.008 a 0.55005501,0.55005501 0 0 0 -0.55664,0.54883 v 1.21093 0.78907 a 0.550785,0.550785 0 1 0 1.10157,0 v -0.78907 -0.65429 l 0.44336,0.004 a 0.55005501,0.55005501 0 0 0 0.39648,-0.16211 l 1,-1.00781 a 0.55005501,0.55005501 0 0 0 0.16016,-0.38672 v -1 a 0.55005501,0.55005501 0 0 0 -0.16211,-0.39062 l -1,-0.99414 a 0.55005501,0.55005501 0 0 0 -0.38868,-0.16211 h -0.44921 v -0.90235 h 0.44921 a 0.55005501,0.55005501 0 0 0 0.38868,-0.16211 l 0.83984,-0.84375 h 0.77148 a 0.55005501,0.55005501 0 0 0 0.38868,-0.16015 l 1,-1 a 0.55005501,0.55005501 0 0 0 0.16211,-0.38867 v -1.77344 l 0.44921,-0.44922 0.61133,0.61133 a 0.55005501,0.55005501 0 0 0 0.38867,0.16015 h 1.77149 l 0.83984,0.83985 a 0.55005501,0.55005501 0 0 0 0.77735,0 l 1,-1 a 0.55005501,0.55005501 0 0 0 0.16211,-0.38867 v -0.45508 h 1.44921 a 0.55005501,0.55005501 0 1 0 0,-1.09961 z"
+ id="path42222-9-3-2"
+ inkscape:connector-curvature="0" />
+ </g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g10865-1-4"
- transform="translate(209.9929,-231)">
+ transform="translate(209.993,-231)"
+ inkscape:label="L-19">
<g
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
id="g12049-3-5"
- transform="translate(126,64.00005)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
+ transform="translate(126,64.0001)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 52.0071,410.99995 v 1 L 61.5,412 c 0.676161,0.01 0.676161,-1.00956 0,-1 z M 48.5,416 c -0.676161,-0.01 -0.676161,1.00956 0,1 l 5.5071,-5e-5 v -1 z m 10.5071,-5e-5 v 1 L 61.5,417 c 0.676161,0.01 0.676161,-1.00956 0,-1 z M 48.5,421 c -0.676161,-0.01 -0.676161,1.00956 0,1 l 9.5071,-5e-5 v -1 z"
@@ -12730,193 +14406,179 @@
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24393-7"
- transform="matrix(-1,0,0,1,1912.004,-92)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1367.5039,334.00195 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 9.99219 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 9.9961 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -9.99219 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.5,1 H 1377 v 8.99219 h -8.9961 z"
- id="path24368-5"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1376,338 -4.4961,0.002 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 V 343 h 1 v -3.99805 L 1376,339 Z m 3,0 v 1 l 1,0.002 v 7.99024 h -7.9961 V 346 h -1 v 1.49219 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 8.9961 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -8.99024 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z"
- id="path24388-3"
- inkscape:connector-curvature="0" />
- </g>
- <g
- transform="translate(112.05535,339.92702)"
- id="g44391"
- style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new">
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- id="rect44387"
- width="16"
- height="16"
- x="103"
- y="111" />
- <path
- transform="matrix(-0.248353,0.02816779,0.02830718,0.248422,140.45214,86.01031)"
- style="display:inline;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
- d="m 140,118 a 8,8 0 0 1 -8,8 8,8 0 0 1 -8,-8 8,8 0 0 1 8,-8 8,8 0 0 1 8,8 z"
- id="circle44389"
- inkscape:connector-curvature="0" />
- </g>
- <g
- transform="matrix(-1,0,0,1,593.8323,-41.99999)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g22538" />
- <g
- id="g15557"
- transform="translate(42)"
- style="fill:#ffffff">
+ id="g22949"
+ transform="matrix(1,0,0,-1,168,540.009)"
+ inkscape:label="L-18">
<g
- transform="matrix(1,0,0,-1,-42,813.00707)"
- id="g15497"
- style="display:inline;fill:#ffffff;enable-background:new">
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="matrix(0,-1,-1,0,558.008,761.005)"
+ id="g22540"
+ style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 346,286.00391 c 0,-1.09977 -0.90081,-2.00196 -2,-2.00196 -1.09919,0 -2,0.90219 -2,2.00196 0,1.09976 0.90081,2.0039 2,2.0039 1.09919,0 2,-0.90414 2,-2.0039 z m -1,0 c 0,0.56041 -0.44233,1.0039 -1,1.0039 -0.55767,0 -1,-0.44349 -1,-1.0039 0,-0.56041 0.44233,-1.00196 1,-1.00196 0.55767,0 1,0.44155 1,1.00196 z"
- id="ellipse15493"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 469.00195,355 C 467.90167,355 467,355.90326 467,357.00391 c 0,1.10064 0.90167,2.00391 2.00195,2.0039 1.10028,0 2.00196,-0.90326 2.00196,-2.0039 0,-1.10064 -0.90168,-2.00391 -2.00196,-2.00391 z"
+ id="path22508"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sscss" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 356,296.00391 c 0,-1.09734 -0.90199,-1.9961 -2,-1.9961 -1.09801,0 -2,0.89876 -2,1.9961 0,1.09733 0.90199,1.99609 2,1.99609 1.09801,0 2,-0.89876 2,-1.99609 z"
- id="ellipse15495"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468.5,349 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
+ id="path22516"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 475.5,356 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z"
+ id="path22518"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 474.50195,350.00781 c -0.82202,10e-6 -1.50195,0.67415 -1.50195,1.4961 0,0.82195 0.67993,1.49609 1.50195,1.49609 0.82203,0 1.50195,-0.67414 1.50196,-1.49609 -1e-5,-0.82196 -0.67993,-1.4961 -1.50196,-1.4961 z"
+ id="path22520"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csscc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468,351.5 v 4 h 1 v -4 z m 5.14648,0.64648 -3.49609,3.50977 0.70899,0.70508 3.49414,-3.50781 z M 470.5,357 v 1 h 4 v -1 z"
+ id="path22536"
+ inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 306.49609,516.00391 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m -2.00976,0.99414 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85937 z m -1.00195,3 a 0.50005,0.50005 0 0 0 -0.34766,0.85937 l 1,1 a 0.50005,0.50005 0 1 0 0.70703,-0.70703 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35937,-0.15234 z m 3.01171,2.00586 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 2.9961,0.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85937 l 1,1 a 0.50005,0.50005 0 1 0 0.70703,-0.70703 l -1,-1 a 0.50005,0.50005 0 0 0 -0.35742,-0.15234 z m 0.99414,3 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1,1 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85937 z m -4.9961,1.00586 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path15483-4"
- inkscape:connector-curvature="0" />
- </g>
- <g
- id="g6238"
- style="fill:#ffffff">
<g
- id="g15734"
- style="fill:#ffffff">
- <g
- style="opacity:0.6;fill:#ffffff"
- id="g15738">
- <path
- inkscape:connector-curvature="0"
- id="path15684"
- d="m 532.57617,472.98047 a 0.55005501,0.55005501 0 0 0 -0.42383,0.18555 c -0.46657,0.51387 -1.20227,1.13094 -1.20312,2.14257 -10e-4,1.1847 0.85571,2.11411 1.94336,2.91797 1.08765,0.80386 2.47935,1.527 3.84765,2.25782 0.44144,0.23578 0.88242,0.47056 1.3086,0.70312 1.11316,0.60746 2.13512,1.2144 2.84375,1.81836 0.70862,0.60396 1.05894,1.15906 1.05859,1.68359 -4e-4,0.48086 -0.32771,1.0064 -0.79492,1.38086 a 0.55027044,0.55027044 0 1 0 0.6875,0.85938 c 0.65297,-0.52334 1.20625,-1.30182 1.20703,-2.23828 6.6e-4,-0.99421 -0.62031,-1.82029 -1.44531,-2.52344 -0.825,-0.70315 -1.89813,-1.32892 -3.03125,-1.94727 -0.43382,-0.23673 -0.87477,-0.47022 -1.31445,-0.70508 -1.37366,-0.73367 -2.73478,-1.45092 -3.71289,-2.17382 -0.97812,-0.72291 -1.49874,-1.40647 -1.49805,-2.03125 3.7e-4,-0.43907 0.39742,-0.83099 0.91797,-1.4043 a 0.55005501,0.55005501 0 0 0 -0.39063,-0.92578 z m 1.92578,7.9668 a 0.55005501,0.55005501 0 0 0 -0.24804,0.0605 c -0.75,0.375 -1.5313,0.75874 -2.16797,1.28907 -0.63668,0.53032 -1.13681,1.26964 -1.13867,2.20312 0,0.98843 0.53602,1.85319 1.19335,2.41797 a 0.55122854,0.55122854 0 1 0 0.71876,-0.83594 c -0.44771,-0.38466 -0.8125,-1.01968 -0.8125,-1.58203 0.002,-0.56635 0.25363,-0.95243 0.74218,-1.35938 0.48909,-0.40739 1.20703,-0.77343 1.95703,-1.14843 a 0.55005501,0.55005501 0 0 0 -0.24414,-1.04492 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- </g>
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g22761"
+ transform="matrix(0,-1,-1,0,554.008,765.005)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
<path
- inkscape:connector-curvature="0"
- id="path15690"
- d="m 533.5,475 a 0.50005,0.50005 0 1 0 0,1 h 2 a 0.50005,0.50005 0 1 0 0,-1 z m 0,9 a 0.50005,0.50005 0 1 0 0,1 h 2 A 0.50005,0.50005 0 0 0 536,484.58008 0.50005,0.50005 0 0 0 536.5,485 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -4 A 0.50005,0.50005 0 0 0 536,484.41992 0.50005,0.50005 0 0 0 535.5,484 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468.5,349 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z m 0,1 c 0.28207,0 0.5,0.21793 0.5,0.5 0,0.28207 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z m 0.50195,5 C 467.90167,355 467,355.90326 467,357.00391 c 0,1.10064 0.90167,2.00391 2.00195,2.0039 1.10028,0 2.00196,-0.90326 2.00196,-2.0039 0,-1.10064 -0.90168,-2.00391 -2.00196,-2.00391 z m 0,1 c 0.55916,0 1.00196,0.44302 1.00196,1.00391 0,0.56088 -0.4428,1.0039 -1.00196,1.0039 -0.55915,0 -1.00195,-0.44302 -1.00195,-1.0039 C 468,356.44302 468.4428,356 469.00195,356 Z m 6.49805,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
+ id="path22750"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 468,351.5 v 4 h 1 v -4 z"
+ id="path22755"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 470.5,357 v 1 h 4 v -1 z"
+ id="path22757"
+ inkscape:connector-curvature="0" />
</g>
- <path
- sodipodi:nodetypes="sssssccccccccccccc"
- inkscape:connector-curvature="0"
- id="path13640-8"
- d="m 540.5,472.25 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g15124-5"
- transform="translate(-558,-200)">
+ id="g22409"
+ inkscape:label="L-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 247.59961,579 a 0.60006002,0.60006002 0 0 0 -0.41797,1.03125 l 2.78711,2.78711 a 0.60076499,0.60076499 0 0 0 0.84961,-0.84961 l -2.78711,-2.78711 A 0.60006002,0.60006002 0 0 0 247.59961,579 Z m -0.11133,2.89453 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z m -3,3 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z m -3,3 a 0.60006002,0.60006002 0 0 0 -0.41211,0.18164 l -1,1 a 0.60006002,0.60006002 0 1 0 0.84766,0.84766 l 1,-1 a 0.60006002,0.60006002 0 0 0 -0.43555,-1.0293 z M 237.59961,589 a 0.60006002,0.60006002 0 0 0 -0.41797,1.03125 l 2.78711,2.78711 a 0.60076499,0.60076499 0 0 0 0.84961,-0.84961 l -2.78711,-2.78711 A 0.60006002,0.60006002 0 0 0 237.59961,589 Z"
- transform="translate(558,200)"
- id="path15289-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 347.75,247 -5.25781,0.002 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.49804 L 351,251.50195 a 0.50005,0.50005 0 1 0 -1,-0.004 l -0.008,3.5039 h -7 v -7 L 347.75,248 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path22405"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 350.49219,241.99219 A 0.50005,0.50005 0 0 0 350,242.5 v 4.59766 c -0.58199,0.20687 -1.00586,0.75933 -1.00586,1.4082 0,0.82235 0.67765,1.5 1.5,1.5 0.36227,0 0.69258,-0.13606 0.95313,-0.35352 l 3.79492,2.27735 a 0.50109829,0.50109829 0 1 0 0.51562,-0.85938 l -3.79297,-2.27734 c 0.0184,-0.0931 0.0293,-0.18901 0.0293,-0.28711 0,-0.10213 -0.0114,-0.20218 -0.0312,-0.29883 l 3.79492,-2.27734 a 0.50109829,0.50109829 0 1 0 -0.51562,-0.85938 l -3.80469,2.28321 C 351.30689,247.24613 351.16128,247.1604 351,247.10156 V 242.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22407"
inkscape:connector-curvature="0" />
</g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g15178-7"
- style="display:inline;opacity:1;fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,580.8635,617.75914)">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(22,18)"
+ id="g22745"
+ inkscape:label="L-16">
<g
- id="g15176-5"
- style="fill:#ffffff;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none">
+ id="g22756"
+ transform="translate(20,-60)"
+ style="fill:#ffffff">
<g
- id="g15174-3"
+ id="g22751"
style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 281.51172,579 a 0.50005002,0.50005002 0 0 0 -0.41797,0.20898 c -2.81255,3.79393 -2.81255,9.78811 0,13.58204 a 0.50005002,0.50005002 0 1 0 0.80273,-0.59571 c -2.50459,-3.37852 -2.50459,-9.0121 0,-12.39062 A 0.50005002,0.50005002 0 0 0 281.51172,579 Z m 8.95898,0 a 0.50005002,0.50005002 0 0 0 -0.38476,0.80469 c 2.50459,3.37852 2.50459,9.0121 0,12.39062 a 0.50059472,0.50059472 0 1 0 0.80468,0.59571 c 2.81256,-3.79393 2.81256,-9.78811 0,-13.58204 A 0.50005002,0.50005002 0 0 0 290.47266,579 a 0.50005002,0.50005002 0 0 1 -0.002,0 z m -6.98047,2.99219 a 0.50005002,0.50005002 0 0 0 -0.39648,0.79883 l 2.29102,3.20898 -2.29297,3.20898 a 0.50131814,0.50131814 0 1 0 0.8164,0.58204 l 2.0918,-2.92969 2.0918,2.92969 a 0.50131814,0.50131814 0 1 0 0.8164,-0.58204 L 286.61523,586 l 2.29102,-3.20898 a 0.50005002,0.50005002 0 0 0 -0.0312,-0.63282 0.50005002,0.50005002 0 0 0 -0.78125,0.0508 l -2.0938,2.92967 -2.09375,-2.92969 a 0.50005002,0.50005002 0 0 0 -0.0527,-0.0664 0.50005002,0.50005002 0 0 0 -0.36329,-0.15039 z"
- transform="matrix(-0.94280903,-0.94280903,-0.94280903,0.94280903,1130.0723,-34.785543)"
- id="path15160-1"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 279.5,288 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.71484 L 283,295.64062 V 297.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.85938 L 288.78516,291 H 289.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 0.5 h -5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 8,0 h 1 v 1 h -1 z m -6,1 h 5 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.11523 l -2.40039,4 h -1.42968 l -2.40039,-4 H 281.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z m 2,6 h 1 v 1 h -1 z"
+ id="path22741"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 283.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.5 h 1 v -3 h 8 v 10 h -3.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path22747"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccc" />
</g>
</g>
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g15242-0"
- transform="translate(-558,-305)">
+ id="g22891"
+ transform="translate(444,-274)"
+ inkscape:label="L-15">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -141,519.5 v 1.5 h 1 v -1.5 z m 0,2.5 v 2 h 1 v -2 z m 0,3 v 1.2793 l -2.58594,2.35156 0.67188,0.73828 2.60351,-2.36719 L -139,527 v -1 h -1 v -1 z m 3.00781,1 v 1 h 2 v -1 z M -135,526 v 1 h 1.5 v -1 z"
+ mask="none"
+ id="path12456"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 303.5,242 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 300,245.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 314,252.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 h 8.58594 l -2,2 h -8.58594 z M 313,243.70703 v 8.58594 l -2,2 v -8.58594 z M 301,246 h 9 v 9 h -9 z"
+ transform="translate(-444,274)"
+ id="path12458"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22036"
+ transform="translate(-21)"
+ inkscape:label="L-14">
<g
- id="g15149-2"
- transform="translate(21,43)"
+ transform="matrix(-1,0,0,1,508.993,-42.0001)"
+ id="g23159"
style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 259.49219,578.99219 A 0.50005,0.50005 0 0 0 259,579.5 v 11.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 259.58203,592 H 271.5 a 0.50005,0.50005 0 1 0 0,-1 H 260 v -11.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 1.94922,3.08593 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3.28515,0.70899 a 0.50005,0.50005 0 0 0 -0.18945,0.96484 l 1,0.41602 a 0.50005,0.50005 0 1 0 0.38477,-0.92188 l -1,-0.41797 a 0.50005,0.50005 0 0 0 -0.19532,-0.041 z m 2.57813,1.99609 a 0.50005,0.50005 0 0 0 -0.45508,0.69922 l 0.41797,1 a 0.50037731,0.50037731 0 0 0 0.92383,-0.38476 l -0.41797,-1 a 0.50005,0.50005 0 0 0 -0.46875,-0.31446 z m 1.16601,3.25 a 0.50005,0.50005 0 0 0 -0.49218,0.50586 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50586 z"
- transform="translate(537,262)"
- id="path15133-4"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 286.49219,242 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 286,255.50781 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 242.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 4.72656 l -4.7207,10.22852 z M 292,244.77344 v 10.23437 h -4.72266 z"
+ transform="matrix(-1,0,0,1,487.993,42.0001)"
+ id="path23171"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 202.99219,284 v 1 H 208 l -0.008,12.00781 -4.99805,-0.008 -0.002,1 5.5,0.008 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 209,284.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path21181"
inkscape:connector-curvature="0" />
</g>
- <g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(555.01703,519.07892)"
- id="g12701-3-4"
- style="display:inline;fill:#ffffff;enable-background:new" />
</g>
<g
- transform="translate(-390.0036,-305.9964)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g15818-1">
- <path
- inkscape:connector-curvature="0"
- id="path15352-4"
- d="m 718.49219,868 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 L 717,869.29297 718.70703,871 l 1.14649,-1.14648 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -1,-1 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z m -2.19922,2 -5.14649,5.14648 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 1,1 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 L 718,871.70703 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- sodipodi:nodetypes="ccccccscccccccc" />
+ id="g22579"
+ transform="matrix(-1,0,0,1,572,-63)"
+ inkscape:label="L-13">
<g
- transform="translate(42)"
- id="g15380-9"
- style="opacity:1;fill:#ffffff">
+ style="opacity:1;fill:#ffffff"
+ id="g22529">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 672.49219,862.99219 A 0.50005,0.50005 0 0 0 672,863.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 866 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 673 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 8,0.5 A 0.50005,0.50005 0 0 0 680,864 v 1 h -1 a 0.50005,0.50005 0 1 0 0,1 h 1 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 0,7.5 A 0.50005,0.50005 0 0 0 680,871.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 874 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 681 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path15378-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 268.5,242 c -1.88693,0 -3.42464,1.51084 -3.48828,3.38281 -0.009,0.0385 -0.0124,0.0778 -0.0117,0.11719 -4.1e-4,0.0117 -4.1e-4,0.0234 0,0.0352 V 249 h -3.5 c -0.0381,-4.2e-4 -0.0761,0.004 -0.11328,0.0117 C 259.5129,249.07334 258,250.61174 258,252.5 c 0,1.88693 1.51084,3.42464 3.38281,3.48828 0.0385,0.009 0.0778,0.0124 0.11719,0.0117 h 7 c 0.92807,0 1.81837,-0.36915 2.47461,-1.02539 C 271.63085,254.31837 272,253.42807 272,252.5 v -7 c 7.2e-4,-0.0394 -0.003,-0.0787 -0.0117,-0.11719 C 271.92462,243.51084 270.38693,242 268.5,242 Z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 -4.1e-4,0.0117 -4.1e-4,0.0234 0,0.0352 V 252.5 c 0,0.66323 -0.26345,1.2986 -0.73242,1.76758 C 269.7986,254.73655 269.16323,255 268.5,255 h -7 c -1.38663,0 -2.5,-1.11337 -2.5,-2.5 0,-1.38663 1.11337,-2.5 2.5,-2.5 h 3.75 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.14648 l 0.25,-0.25 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -3.75 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z"
+ transform="matrix(-1,0,0,1,572,63)"
+ id="path22488"
inkscape:connector-curvature="0" />
</g>
- </g>
- <g
- transform="translate(-126.00356,356.99997)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g15185-9">
<path
- id="circle24228-7-4-8"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 301,99 c -0.54636,0 -1,0.453638 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.546362 -0.45364,-1 -1,-1 z m 0,4 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 0,4 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3.5,-7 c -0.67616,-0.0096 -0.67616,1.00956 0,1 h 2.25977 c -0.20553,-0.30677 -0.35861,-0.64616 -0.48438,-1 z m 0,4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m 0,4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 8 c 0.67616,0.01 0.67616,-1.00956 0,-1 z"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssssssssssssssccccccccccccccc" />
- <path
- sodipodi:nodetypes="sssssccccccccccccc"
- inkscape:connector-curvature="0"
- id="path13640-7-5"
- d="m 310.5,95 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ d="M 303.49219,307.99219 A 0.50005,0.50005 0 0 0 303,308.5 v 6.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 303.58203,316 H 310.5 a 0.50005,0.50005 0 1 0 0,-1 H 304 v -6.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path22537"
+ inkscape:connector-curvature="0" />
</g>
<g
id="g15277"
transform="translate(21,-41)"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="L-12">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 216.49219,286 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 216,297.50781 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 295 h -1 v 2.00781 H 217 L 216.99219,287 H 219 v -1 z"
@@ -12929,1277 +14591,1172 @@
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-541,-51)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g15431-6">
- <path
- inkscape:connector-curvature="0"
- id="rect15415-8"
- d="m 548,653 c -0.54532,0 -1,0.45468 -1,1 v 9 c 0,0.54532 0.45468,1 1,1 h 10 c 0.54532,0 1,-0.45468 1,-1 v -1 h -1 v 1 h -10 v -4 -5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="g143026"
+ style="display:inline;enable-background:new"
+ inkscape:label="L-11">
<path
- inkscape:connector-curvature="0"
- id="rect15379-7"
- d="m 550,650 c -0.54532,0 -1,0.45468 -1,1 v 9 c 0,0.54532 0.45468,1 1,1 h 10 c 0.54532,0 1,-0.45468 1,-1 v -9 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 h -2 z m 0,3 h 10 v 6 h -10 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 219.50391,243 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 218.38224,244.61833 217.33333,245 216.5,245 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0996,-0.008 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 225.50391,243 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 224.38224,244.61833 223.33333,245 222.5,245 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 219.50391,243 Z m 1,5 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 219.38224,249.61833 218.33333,250 217.5,250 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0859,-0.006 0.50005,0.50005 0 0 0 0.0137,-0.002 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 226.50391,248 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 225.38224,249.61833 224.33333,250 223.5,250 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 220.50391,248 Z m -1,5 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 218.38224,254.61833 217.33333,255 216.5,255 a 0.50005,0.50005 0 1 0 0,1 c 1.00319,0 2.15225,-0.6005 3,-1.7832 0.82397,1.14952 1.9314,1.74461 2.91406,1.77734 a 0.50005,0.50005 0 0 0 0.002,0 0.50005,0.50005 0 0 0 0.084,0.006 0.50005,0.50005 0 0 0 0.0996,-0.008 c 0.97927,-0.0378 2.08023,-0.63118 2.90039,-1.77539 0.84775,1.1827 1.99681,1.7832 3,1.7832 a 0.50005,0.50005 0 1 0 0,-1 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 225.50391,253 a 0.50005,0.50005 0 0 0 -0.45118,0.27734 C 224.38224,254.61833 223.33333,255 222.5,255 c -0.83333,0 -1.88224,-0.38167 -2.55273,-1.72266 A 0.50005,0.50005 0 0 0 219.50391,253 Z"
+ id="path21858"
+ inkscape:connector-curvature="0" />
</g>
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 342.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.5,3 c 2.20237,0 4,1.79764 4,4 0,2.20237 -1.79763,4 -4,4 -2.20236,0 -4,-1.79763 -4,-4 0,-2.20236 1.79764,-4 4,-4 z"
- id="rect13348" />
<g
- id="g15500"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22083"
+ transform="translate(-1.85367e-6,-42.0001)"
+ inkscape:label="L-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 384.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 2 h -12 z m -0.5,9 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 2 h -12 z"
- id="path15496"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 205.49805,242 -3.00586,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 5 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 206,252 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 208.5,246 H 206 v -3.5 A 0.50005,0.50005 0 0 0 205.49805,242 Z M 205,243.00195 V 246 h -2.00781 v -2.99414 z M 202.99219,247 H 205 v 4 h -2.00781 z M 206,247 h 2 v 4 h -2 z m -3.00781,5 h 2.00586 l -0.006,3.00781 h -2 z"
+ transform="translate(1.85367e-6,42.0001)"
+ id="path22040"
+ inkscape:connector-curvature="0" />
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="M 393.00001,165 A 2.000005,2.000005 0 0 1 391,167.00001 2.000005,2.000005 0 0 1 388.99999,165 2.000005,2.000005 0 0 1 391,162.99999 2.000005,2.000005 0 0 1 393.00001,165 Z"
- id="circle15498"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 200.53711,284.16992 a 0.50005,0.50005 0 0 0 -0.13477,0.0156 c -3.14392,0.73681 -5.37898,3.53464 -5.40234,6.76367 -0.0234,3.22902 2.17176,6.05956 5.30469,6.8418 a 0.50005,0.50005 0 1 0 0.24219,-0.96875 c -2.69014,-0.67168 -4.56694,-3.09259 -4.54688,-5.86524 0.0201,-2.77265 1.93128,-5.16615 4.63086,-5.79883 a 0.50005,0.50005 0 0 0 -0.0937,-0.98828 z"
+ id="path22034"
inkscape:connector-curvature="0" />
</g>
<g
+ transform="translate(-41,-42)"
+ id="g25194-8-8"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g20455"
- transform="rotate(-180,359.49632,417.00345)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 283.49219,330.00781 c -0.1326,3e-5 -0.25976,0.0527 -0.35352,0.14649 l -2,2 c -0.0938,0.0938 -0.14645,0.22091 -0.14648,0.35351 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.1326,-3e-5 0.25975,-0.0527 0.35351,-0.14648 l 2,-2 c 0.0938,-0.0938 0.14646,-0.22092 0.14649,-0.35352 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path20447"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccc" />
+ inkscape:label="L-9">
+ <circle
+ cx="221"
+ cy="285"
+ id="circle25190-1-7"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ r="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 284.25,326 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -4.75,4.75 A 0.50005,0.50005 0 0 0 279,331.25 l -0.008,8.25586 a 0.50005,0.50005 0 0 0 0.50195,0.50195 L 287.75,340 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 4.75,-4.75 A 0.50005,0.50005 0 0 0 293,334.75 l -0.008,-8.24414 a 0.50005,0.50005 0 0 0 -0.49805,-0.49805 z m 0.20703,1 7.53711,0.006 0.006,7.53711 -4.45703,4.45703 -7.55078,0.008 0.008,-7.55078 z"
- id="path20449"
+ id="circle25383"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 221,284 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3,0 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3,1 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -5.67188,2.04688 c -0.72617,0.0892 -1.40636,0.31348 -2.02343,0.63867 -1.23415,0.65038 -2.22638,1.68758 -2.94922,2.84375 -0.72284,1.15617 -1.1805,2.43169 -1.32227,3.60742 -0.14176,1.17573 0.0178,2.28295 0.6875,3.0293 0.68189,0.75993 1.69067,0.98063 2.61328,0.6914 C 219.35231,297.53818 220,296.54997 220,295.5 c 0,-0.87561 0.22937,-1.10992 0.64258,-1.29297 C 221.05579,294.02398 221.75437,294 222.5,294 c 0.79276,0 1.56488,-0.14919 2.20703,-0.5332 0.52292,-0.31271 0.89501,-0.8382 1.11524,-1.4668 h 1.13281 a 0.50004994,0.50004994 0 0 0 0.002,0 c 1.02746,0 1.90966,-0.75672 2.0293,-1.76953 0.11964,-1.01284 -0.5686,-1.95303 -1.57031,-2.17969 -0.73109,-0.16542 -1.38414,0.17264 -1.8711,0.68945 -0.49389,-0.69239 -1.0864,-1.29918 -1.91601,-1.52148 -0.80279,-0.21511 -1.57461,-0.26104 -2.30079,-0.17187 z m 0.11915,0.98632 c 0.59872,-0.0738 1.23897,-0.0331 1.92382,0.15039 0.66836,0.17909 1.23082,0.75735 1.69727,1.56446 a 0.50004994,0.50004994 0 0 0 0.90234,-0.0781 c 0.17721,-0.4818 0.69836,-0.76361 1.22461,-0.64453 0.52625,0.11908 0.85819,0.58537 0.79883,1.08789 C 227.93478,290.61583 227.49838,291 226.95703,291 H 225.5 a 0.50004994,0.50004994 0 0 0 -0.49219,0.41406 c -0.10308,0.5846 -0.38181,0.93776 -0.8125,1.19532 C 223.76463,292.86693 223.16312,293 222.5,293 c -0.74508,0 -1.54761,-0.0253 -2.26172,0.29102 C 219.52417,293.60735 219,294.37315 219,295.5 c 0,0.63163 -0.40649,1.2273 -0.96484,1.40234 -0.62221,0.19506 -1.12911,0.0874 -1.57032,-0.40429 -0.37675,-0.41988 -0.55858,-1.23603 -0.4375,-2.24024 0.12109,-1.00421 0.53101,-2.16478 1.17774,-3.19922 0.64673,-1.03443 1.52684,-1.94044 2.5664,-2.48828 0.51979,-0.27392 1.07706,-0.46333 1.67579,-0.53711 z"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g15543"
- transform="translate(42,-41.999994)">
+ id="g22354"
+ transform="translate(-26,-443)"
+ inkscape:label="L-8">
<g
- id="g15520"
- transform="translate(231.99999,-397.99995)"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g22339"
+ transform="translate(0,10)"
+ style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 430.48047,53 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -3.94922,3.949218 C 425.83169,57.461484 426.05468,57.99983 426.5,58 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 54 h 6 v 3.5 c -0.01,0.676161 1.00956,0.676161 1,0 v -4 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -7 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z M 426,59.000004 V 66.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 4.25 c 0.67616,0.0096 0.67616,-1.009563 0,-1 H 427 v -6.999996 z"
- transform="translate(-273.99999,439.99994)"
- id="path15514"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 154,242 v 2 h -1 v 4 h 1 v 2 h 2 v -8 z m 10,0 v 8 h 2 v -2 h 1 v -4 h -1 v -2 z m -7,3 v 2 h 6 v -2 z"
+ transform="translate(26,433)"
+ id="path22321"
+ inkscape:connector-curvature="0" />
</g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.25111365;enable-background:new"
- transform="matrix(-0.79928788,0,0,0.79928788,686.43544,-75.73586)"
- id="g12909-3">
+ transform="translate(-268,306.008)"
+ style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;enable-background:new"
+ id="g22352">
<path
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- d="m 435.50195,58 a 0.50005,0.50005 0 0 0 -0.50586,0.507812 L 435,59.847656 c -0.37235,0.07227 -0.71903,0.219786 -1.02148,0.427735 l -1.12696,-1.123047 a 0.50005,0.50005 0 0 0 -0.34375,-0.150391 0.50005,0.50005 0 0 0 -0.36133,0.859375 l 1.12696,1.123047 c -0.20773,0.30118 -0.3566,0.644813 -0.42969,1.015625 l -1.3457,0.002 a 0.5009775,0.5009775 0 0 0 0.002,1.001953 L 432.83789,63 c 0.0676,0.378442 0.20857,0.7312 0.41602,1.039062 l -1.10743,1.109376 a 0.50005,0.50005 0 1 0 0.70508,0.705078 l 1.10352,-1.101563 c 0.30785,0.216541 0.661,0.370975 1.04297,0.445313 l -0.002,1.300781 a 0.50098382,0.50098382 0 1 0 1.00196,0.0039 L 436,65.199219 c 0.38598,-0.06997 0.74484,-0.216649 1.05664,-0.431641 l 1.08203,1.085938 a 0.5000572,0.5000572 0 1 0 0.70899,-0.705078 l -1.08399,-1.087891 C 437.97884,63.747505 438.12621,63.387471 438.19531,63 H 439.5 a 0.50033424,0.50033424 0 1 0 0,-1 h -1.31055 c -0.0748,-0.379778 -0.22985,-0.730801 -0.44531,-1.037109 l 1.10156,-1.103516 A 0.50005,0.50005 0 0 0 438.49805,59 a 0.50005,0.50005 0 0 0 -0.35743,0.154297 l -1.10742,1.105469 C 436.72738,60.053691 436.37559,59.913865 436,59.845703 l -0.004,-1.339844 A 0.50005,0.50005 0 0 0 435.50195,58 Z m -0.002,3.300781 c 0.66274,0 1.19921,0.536481 1.19922,1.199219 0,0.662738 -0.53648,1.199219 -1.19922,1.199219 -0.66274,-8e-6 -1.19922,-0.536481 -1.19922,-1.199219 0,-0.66273 0.53649,-1.199211 1.19922,-1.199219 z"
- transform="matrix(-1.2511137,0,0,1.2511137,911.35554,147.30094)"
- id="path12903-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 452.49219,387 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 V 387.5 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.0053,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66922,0 -1.3386,0 -2.00781,0 z m 4.50781,0.98438 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.0053,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00252,0 -2.00529,0 -3.00781,0 z M 447.5,389 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1,-10e-6 2,10e-6 3,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1,0 -2,0 -3,0 z m 10.5,0.98438 c 0.66922,-10e-6 1.3386,0 2.00781,0 v 2.00781 c -0.66922,0 -1.33859,0 -2.00781,0 z M 448,390 c 0.66667,0 1.33333,0 2,0 v 2 c -0.66667,0 -1.33333,0 -2,0 z"
+ id="path22350"
inkscape:connector-curvature="0" />
</g>
</g>
<g
- transform="translate(-583.99495,-390.00505)"
- id="g15882-7"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 351.50586,598.99414 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.79297 l -2.70703,2.70703 h -2.79297 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -1,1 a 0.50005,0.50005 0 0 0 0,0.70704 l 6,6 a 0.50005,0.50005 0 0 0 0.70704,0 l 1,-1 a 0.50005,0.50005 0 0 0 0.14648,-0.35352 v -2.79297 l 2.70703,-2.70703 h 0.79297 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35352,-0.14648 z m 0.5,1 h 0.29297 l 2.70703,2.70703 v 0.29297 h -0.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 a 0.50005,0.50005 0 0 0 -0.14648,0.35352 v 2.79297 l -0.5,0.5 -5.29297,-5.29297 0.5,-0.5 h 2.79297 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 a 0.50005,0.50005 0 0 0 0.14648,-0.35352 z m -5.75977,8.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3.75,3.75 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3.75,-3.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
- transform="translate(583.99495,390.00505)"
- id="path15847-7"
- inkscape:connector-curvature="0" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g21692"
+ transform="translate(-1.85367e-6,-42)"
+ inkscape:label="L-7">
+ <g
+ transform="translate(-63)"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#f9f9f9;enable-background:new"
+ id="g21667">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:6.6;stroke-opacity:1;marker:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 145.49219,241.99219 A 0.50005,0.50005 0 0 0 145,242.5 c 0,1.27778 -0.82701,2.37965 -2.66602,3.44141 -1.66335,0.96034 -4.28314,1.19403 -6.30078,1.06054 -0.9786,-0.0647 -1.78811,-0.30625 -2.3125,-0.61133 -0.52058,-0.30284 -0.71591,-0.62257 -0.71875,-0.88476 0.003,-0.26222 0.19817,-0.58387 0.71875,-0.88672 0.5244,-0.30506 1.3339,-0.54463 2.3125,-0.60937 1.74084,-0.11517 3.90302,0.0169 5.24414,0.6875 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 c -1.65888,-0.82943 -3.92118,-0.91239 -5.75586,-0.79101 -1.10098,0.0728 -2.04234,0.3336 -2.74805,0.74414 -0.63776,0.37101 -1.097,0.90981 -1.18359,1.55273 A 0.50005,0.50005 0 0 0 132,245.5 c 0,0.002 0.002,0.004 0.002,0.006 -1e-5,0.002 -0.002,0.004 -0.002,0.006 a 0.50005,0.50005 0 0 0 0.0352,0.18945 0.50005,0.50005 0 0 0 0.002,0.006 c 0.0881,0.64105 0.54525,1.17861 1.18164,1.54883 0.70571,0.41055 1.64707,0.66937 2.74805,0.74219 2.1415,0.14167 4.88621,-0.0477 6.86718,-1.19141 C 144.82884,245.65491 146,244.22222 146,242.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -0.27539,5.25195 a 0.50005,0.50005 0 0 0 -0.4375,0.67578 C 144.90088,248.25504 145,248.58141 145,249 c 0,1.83333 -0.82701,2.87965 -2.66602,3.94141 -1.66335,0.96034 -4.28314,1.19403 -6.30078,1.06054 -0.9786,-0.0647 -1.78811,-0.30625 -2.3125,-0.61133 -0.52058,-0.30284 -0.71591,-0.62257 -0.71875,-0.88476 0.003,-0.26222 0.19817,-0.58387 0.71875,-0.88672 0.5244,-0.30506 1.3339,-0.54463 2.3125,-0.60937 1.74084,-0.11517 3.90302,0.0169 5.24414,0.6875 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 c -1.65888,-0.82943 -3.92118,-0.91239 -5.75586,-0.79101 -1.10098,0.0728 -2.04234,0.3336 -2.74805,0.74414 -0.63776,0.37101 -1.097,0.90981 -1.18359,1.55273 A 0.50005,0.50005 0 0 0 132,252.5 c 0,0.002 0.002,0.004 0.002,0.006 -1e-5,0.002 -0.002,0.004 -0.002,0.006 a 0.50005,0.50005 0 0 0 0.0371,0.19531 c 0.0881,0.64105 0.54525,1.17861 1.18164,1.54883 0.70571,0.41055 1.64707,0.66937 2.74805,0.74219 2.1415,0.14167 4.88621,-0.0477 6.86718,-1.19141 1.96806,-1.13625 3.12917,-2.60303 3.16016,-4.72266 A 0.50005,0.50005 0 0 0 146,249 a 0.50005,0.50005 0 0 0 -0.0137,-0.12695 c -0.0205,-0.51808 -0.14222,-0.95284 -0.26563,-1.29297 a 0.50005,0.50005 0 0 0 -0.5039,-0.33594 z m 0.043,7 a 0.50005,0.50005 0 0 0 -0.4336,0.76953 c 0,0 0.17383,0.35663 0.17383,0.51953 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.59989 -0.32617,-1.04687 -0.32617,-1.04687 a 0.50005,0.50005 0 0 0 -0.41406,-0.24219 z"
+ transform="translate(63,42)"
+ id="path21655"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g21673"
+ style="display:inline;opacity:1;fill:#ffffff;stroke:#f9f9f9;enable-background:new"
+ transform="translate(-63,6)" />
</g>
<g
- transform="translate(-583.99495,-390.00505)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g16002-8">
+ id="g22709"
+ transform="matrix(0,-1,-1,0,408.995,409)"
+ inkscape:label="L-6">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 372.50586,598.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 0.79297 l 3.70703,3.70703 h 0.79297 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1 c -2e-5,-0.1326 -0.0527,-0.25975 -0.14648,-0.35352 l -3,-3 c -0.0938,-0.0938 -0.22092,-0.14646 -0.35352,-0.14648 z m -1.20703,2 -2,2 h -2.79297 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 l -1,1 c -0.19519,0.19528 -0.19519,0.51177 0,0.70704 l 6,6 c 0.19527,0.1952 0.51176,0.1952 0.70704,0 l 1,-1 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -2.79297 l 2,-2 z m -4.05274,7.24609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3.75,3.75 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3.75,-3.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
- transform="translate(583.99495,390.00505)"
- id="path15876-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 153.49219,289.73828 A 0.50005,0.50005 0 0 0 153,290.24414 l -0.008,7.26172 a 0.50005,0.50005 0 0 0 0.50195,0.50195 l 7.25586,-0.0137 a 0.50005,0.50005 0 1 0 0,-1 l -6.75781,0.0137 0.008,-6.76172 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path21430-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 115.04297,242 -4,4 h 9.95117 l 0.006,9.95703 3.85352,-3.85351 L 125,251.95703 124.99414,242 Z m 0.41406,1 h 7.9707 l -2,2 h -7.9707 z m 8.53711,0.56641 0.006,7.97656 -2,2 -0.006,-7.97656 z"
+ transform="matrix(0,-1,-1,0,409,408.995)"
+ id="path21432-2"
inkscape:connector-curvature="0" />
</g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(-21,168)"
- id="g15951-6"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ id="g143029"
+ style="display:inline;enable-background:new"
+ inkscape:label="L-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
- id="path15947-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 97.689453,242.01172 c -0.394683,0.0302 -0.787753,0.12022 -1.167969,0.27148 C 95.00062,242.88827 94,244.36319 94,246 a 0.50005,0.50005 0 0 0 0.01563,0.13281 c -0.365184,0.0927 -0.722816,0.22834 -1.058594,0.42774 -1.441397,0.85595 -2.170881,2.51688 -1.878906,4.14453 -0.687144,0.57705 -1.108155,1.44799 -1.076172,2.39648 0.05016,1.48769 1.192146,2.71921 2.671875,2.88086 1.398175,0.15274 2.699752,-0.69789 3.152344,-2.00781 0.896041,0.0388 1.769696,-0.22225 2.498047,-0.74609 1.073726,0.85551 2.557876,1.01607 3.789066,0.37695 1.30171,-0.67573 2.04374,-2.09602 1.85742,-3.55078 -0.16328,-1.27499 -1.01006,-2.34261 -2.17968,-2.80664 0.45466,-1.38242 0.13144,-2.9211 -0.88477,-3.9961 -0.56221,-0.59473 -1.277273,-0.98709 -2.042974,-1.15625 -0.38285,-0.0846 -0.779145,-0.11418 -1.173828,-0.084 z m 0.521485,0.99609 c 0.734455,0.0517 1.440532,0.37287 1.968752,0.93164 0.84514,0.89404 1.0593,2.20845 0.54101,3.32422 a 0.50005,0.50005 0 0 0 -0.0527,0.2168 0.50005,0.50005 0 0 0 0.38672,0.58203 c 1.02426,0.23341 1.79232,1.07713 1.92578,2.11914 0.13345,1.04201 -0.39575,2.0531 -1.32813,2.53711 -0.93238,0.48401 -2.064441,0.33572 -2.83984,-0.37305 a 0.50005,0.50005 0 0 0 -0.203125,-0.11914 0.50005,0.50005 0 0 0 -0.28125,-0.0977 0.50005,0.50005 0 0 0 -0.351563,0.1289 c -0.657713,0.57559 -1.533142,0.83597 -2.398437,0.71289 a 0.50008765,0.50008765 0 0 0 -0.542969,0.33008 0.50005,0.50005 0 0 0 -0.09766,0.19727 c -0.248328,0.96717 -1.16166,1.59867 -2.154297,1.49023 -0.992636,-0.10844 -1.747599,-0.92195 -1.78125,-1.91992 -0.02307,-0.68418 0.30371,-1.29829 0.824219,-1.67774 a 0.50005,0.50005 0 0 0 0.166016,-0.11718 c 0.198328,-0.11547 0.417989,-0.19976 0.65625,-0.24219 a 0.50005,0.50005 0 0 0 -0.08984,-0.99414 0.50005,0.50005 0 0 0 -0.08398,0.01 c -0.160251,0.0285 -0.313314,0.0746 -0.46289,0.12695 -0.0646,-1.10299 0.477746,-2.17237 1.457031,-2.75391 1.157707,-0.68748 2.624443,-0.52021 3.599609,0.4082 a 0.50009764,0.50009764 0 0 0 0.689453,-0.7246 c -0.648161,-0.6171 -1.462878,-0.98259 -2.308593,-1.07813 -0.148752,-0.017 -0.299358,-0.0157 -0.449254,-0.0158 A 0.50005,0.50005 0 0 0 95,246 c 0,-1.23027 0.747501,-2.33232 1.890625,-2.78711 0.428672,-0.17055 0.879639,-0.23611 1.320313,-0.20508 z"
+ id="path21574"
inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 30.5,350 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 7 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 7 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -7 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- id="rect15949-3"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
</g>
<g
+ transform="translate(-231,-84)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g16385"
- transform="translate(-21,21.00001)">
- <path
- id="path16351"
- d="m 118,95.5 c -3.58986,0 -6.5,2.41014 -6.5,6 1,1 3,2.5 6.5,2.5 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 118,95 c -3.86007,0 -7,3.139925 -7,7 0,3.86008 3.13992,7 7,7 3.86008,0 7,-3.13992 7,-7 0,-3.860075 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.680365 6,6 0,3.31964 -2.68036,6 -6,6 -3.31964,0 -6,-2.68036 -6,-6 0,-3.319635 2.68037,-6 6,-6 z"
- id="path16353"
- inkscape:connector-curvature="0" />
+ id="g26345"
+ inkscape:label="L-4">
+ <g
+ id="g22592"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 300.5,326 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="path22548"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 307.49219,326.99219 A 0.50005,0.50005 0 0 0 307,327.5 v 5.5 h -5.5 a 0.50005,0.50005 0 1 0 0,1 h 5.5 v 2 h -5.5 a 0.50005,0.50005 0 1 0 0,1 h 5.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 337 h 2 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 337 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 311 v -2 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 311 v -5.5 a 0.50005,0.50005 0 1 0 -1,0 v 5.5 h -2 v -5.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 308,334 h 2 v 2 h -2 z"
+ id="path22585"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22284"
+ transform="translate(-1.85367e-6,-42)"
+ inkscape:label="L-3">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 123.24414,102.64453 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 0.5,0.5 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -0.5,-0.5 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m -2.25,0.75 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 1.75,1.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -1.75,-1.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m -2.5,0.5 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 2.75,2.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -2.75,-2.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m 0,3 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 0.75,0.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -0.75,-0.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z"
- id="path16355"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 54.75,284 a 0.50004997,0.50004997 0 0 0 -0.431641,0.24805 l -3.646484,6.25 a 0.50004997,0.50004997 0 0 0 -0.002,0.002 c -1.211575,2.0985 -0.741006,4.77251 1.115234,6.33008 1.856239,1.55756 4.573449,1.55756 6.429688,0 1.85624,-1.55757 2.326809,-4.23158 1.115234,-6.33008 a 0.50004997,0.50004997 0 0 0 -0.002,-0.002 l -3.646484,-6.25 A 0.50004997,0.50004997 0 0 0 55.25,284 Z m 0.25,1.06445 3.464844,5.9375 c 0.970958,1.6837 0.594513,3.81305 -0.894532,5.0625 -1.489569,1.2499 -3.651055,1.2499 -5.140624,0 -1.489045,-1.24945 -1.86549,-3.3788 -0.894532,-5.0625 V 291 Z m -0.511719,2.92969 a 0.50004997,0.50004997 0 0 0 -0.429687,0.27148 l -1.697266,3.20704 c -0.166111,0.28617 -0.283806,0.59778 -0.349609,0.92187 a 0.50005872,0.50005872 0 1 0 0.980469,0.19727 c 0.04414,-0.2174 0.122796,-0.42496 0.234374,-0.61719 a 0.50004997,0.50004997 0 0 0 0.0098,-0.0176 l 1.705078,-3.22265 a 0.50004997,0.50004997 0 0 0 -0.453125,-0.74024 z"
+ id="path22264"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-168,-294)"
- id="g16054"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22356"
+ transform="translate(-336,-63)"
+ inkscape:label="L-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 180.82031,32.001953 c -2.53256,0.0762 -4.74925,1.739751 -5.52929,4.150391 -0.66549,2.0566 -0.15791,4.2781 1.25,5.847656 H 176.25 a 0.50005,0.50005 0 0 0 -0.35352,0.146484 l -1.75,1.75 A 0.50005,0.50005 0 0 0 174,44.25 v 1.25 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.25 a 0.50005,0.50005 0 0 0 -0.14648,-0.353516 l -1.75,-1.75 A 0.50005,0.50005 0 0 0 185.75,42 h -0.29492 c 1.50007,-1.670137 1.96594,-4.059297 1.13281,-6.1875 -0.92362,-2.35937 -3.23501,-3.886777 -5.76758,-3.810547 z m 0.0332,1.099609 c 2.07177,-0.0624 3.95341,1.181239 4.70898,3.111329 0.75557,1.9301 0.2178,4.121692 -1.3457,5.482421 A 0.55028534,0.55028534 0 0 0 184.03906,42 H 183.5 a 0.50005,0.50005 0 1 0 0,1 h 2.04297 L 187,44.457031 V 45 H 175 V 44.457031 L 176.45703,43 H 180.5 a 0.50005,0.50005 0 1 0 0,-1 h -2.37695 a 0.55005501,0.55005501 0 0 0 -0.11133,-0.117188 c -1.64252,-1.264239 -2.31195,-3.418585 -1.67383,-5.390624 0.63812,-1.972051 2.44385,-3.328265 4.51563,-3.390626 z"
- transform="translate(168,294)"
- id="path16048"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ sodipodi:nodetypes="ccccc"
+ id="path22236"
+ d="m 363.5,308.5 3,-3 h 6 l -3,3 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 348.55469,328.69141 a 0.50005,0.50005 0 0 0 -0.0859,0.008 c -1.42662,0.22929 -2.54672,1.3539 -2.77148,2.78125 a 0.50012645,0.50012645 0 1 0 0.98828,0.1543 c 0.15806,-1.00378 0.94009,-1.78798 1.94336,-1.94922 a 0.50005,0.50005 0 0 0 -0.0742,-0.99414 z"
- id="path16052"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 366.5,305 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 363.5,309 h 6 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 372.5,305 Z m 0.20703,1 h 4.58594 l -2,2 h -4.58594 z m 9.77735,3 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 373,312.5 v 6 a 0.50005,0.50005 0 0 0 0.85352,0.35352 l 3,-3 A 0.50005,0.50005 0 0 0 377,315.5 v -6 A 0.50005,0.50005 0 0 0 376.48438,309 Z M 376,310.70703 v 4.58594 l -2,2 v -4.58594 z M 369.5,312 l -6.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 6 a 0.50005,0.50005 0 0 0 0.5,-0.5 L 370,312.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -0.5,1 -0.008,5.00781 h -5 v -5.00195 z"
+ id="path22324"
inkscape:connector-curvature="0" />
</g>
<g
- id="g16187"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(462.00505,-96.005057)">
+ id="g23463"
+ inkscape:label="L-1">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 103.49609,556.99023 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.57031,1.57032 c -1.22858,-1.06562 -2.825838,-1.7168 -4.576171,-1.7168 -3.86007,0 -7,3.13993 -7,7 0,1.75033 0.649231,3.34954 1.714844,4.57813 l -1.568359,1.56835 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.568359,-1.56836 c 1.228585,1.06561 2.827793,1.71484 4.578125,1.71484 3.860071,0 7.000001,-3.13993 7.000001,-7 0,-1.75033 -0.65118,-3.34759 -1.7168,-4.57617 l 1.57032,-1.57031 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -6.490231,1.00391 c 3.319631,0 6.000001,2.68037 6.000001,6 0,3.31963 -2.68037,6 -6.000001,6 -3.31963,0 -6,-2.68037 -6,-6 0,-0.88092 0.193846,-1.71405 0.533203,-2.4668 l 0.466797,0.4668 1,1 v 2 h 2 v 1 l 1,1 v 2 h 0.75 1.25 l 1,-1 1.000001,-1 v -1 l -1.000001,-1 h -2 -1 l -1,-1 h -1 l 1,-1 h 1 l 2,-2 -1,-1 h -1 l -1,-1 0.894532,-0.89453 c 0.358617,-0.0666 0.727234,-0.10547 1.105468,-0.10547 z"
- transform="translate(-462.00505,96.005057)"
- id="circle16176"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 10.492188,241.99219 A 0.50005,0.50005 0 0 0 10.417969,242 H 6.5 A 0.50005,0.50005 0 0 0 6,242.5 v 5 A 0.50005,0.50005 0 0 0 6.5,248 H 8 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 A 0.50005,0.50005 0 0 0 18,255.5 V 248 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 19.5,242 h -3.919922 a 0.50005,0.50005 0 0 0 -0.404297,0.11328 0.50005,0.50005 0 0 0 -0.01953,0.0156 0.50005,0.50005 0 0 0 -0.01758,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.03125,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 15,242.58203 V 243 c 0,0.71532 -0.380592,1.37478 -1,1.73242 -0.619409,0.35765 -1.380591,0.35765 -2,0 -0.619408,-0.35764 -1,-1.0171 -1,-1.73242 v -0.41992 a 0.50005,0.50005 0 0 0 -0.113281,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.03125,-0.0332 0.50005,0.50005 0 0 0 -0.0039,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.0039,-0.002 0.50005,0.50005 0 0 0 -0.320312,-0.11133 z M 7,243 h 3 c 0,1.07096 0.57257,2.06216 1.5,2.59766 0.927429,0.53549 2.072571,0.53549 3,0 0.92743,-0.5355 1.5,-1.5267 1.5,-2.59766 h 3 v 4 H 17.5 A 0.50005,0.50005 0 0 0 17,247.5 V 255 H 9 v -7.5 A 0.50005,0.50005 0 0 0 8.5,247 H 7 Z"
+ id="path22384"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g8419-9"
- transform="translate(1279.001,-241)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <rect
- style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="rect8368-4"
- width="16"
- height="16"
- x="-1148"
- y="398" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g18539-5"
+ transform="translate(-699.95,-1104.95)"
+ inkscape:label="K-26">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -1140.8984,400.01367 c -2.0857,0.12882 -4.0362,1.26078 -5.1621,3.1211 -1.5012,2.48042 -1.1755,5.66201 0.7968,7.78711 1.9724,2.12509 5.1198,2.68733 7.7051,1.375 2.5853,-1.31234 3.9907,-4.18482 3.4395,-7.03126 a 0.50030025,0.50030025 0 1 0 -0.9825,0.18946 c 0.4673,2.4126 -0.7188,4.8369 -2.9101,5.94922 -2.1913,1.11231 -4.8478,0.63909 -6.5195,-1.16211 -1.6718,-1.8012 -1.9463,-4.48748 -0.6739,-6.58985 1.2724,-2.10236 3.7774,-3.10263 6.1485,-2.45703 a 0.50104088,0.50104088 0 1 0 0.2636,-0.96679 c -0.6993,-0.19043 -1.4102,-0.25779 -2.1054,-0.21485 z"
- id="ellipse8370-9"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1240.9492,1334.9492 v 5 h 4 v -5 z"
+ id="path18533-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 144.98047,157.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -3.71289,3.71484 c -0.0265,-0.001 -0.0513,-0.008 -0.0781,-0.008 -0.8224,0 -1.5,0.67765 -1.5,1.5 0,0.82235 0.6776,1.5 1.5,1.5 0.8224,0 1.5,-0.67765 1.5,-1.5 0,-0.0274 -0.006,-0.0531 -0.008,-0.0801 l 3.71289,-3.71289 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
- transform="translate(-1279.001,241)"
- id="rect8385-9"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1236.6992,1327.9531 v 1 h 2.25 c 0.4241,0 0.7403,0.2467 0.8828,0.5762 0.1425,0.3295 0.1253,0.7107 -0.2422,1.0781 l -4,4 c -0.6325,0.6326 -0.7433,1.5055 -0.4492,2.1778 0.2941,0.6722 0.9778,1.1757 1.8028,1.1757 l 3.0059,-0.012 v -1 l -3.0058,0.012 c -0.425,0 -0.7434,-0.2484 -0.8868,-0.5761 -0.1434,-0.3278 -0.1271,-0.7029 0.2403,-1.0703 l 4,-4 c 0.6326,-0.6326 0.7446,-1.5077 0.4531,-2.1817 -0.2915,-0.674 -0.9748,-1.1797 -1.8008,-1.1797 z"
+ id="path18537-0"
inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1233.4531,1325.9492 c -0.191,0 -0.3661,0.1064 -0.4511,0.2774 l -2,4 c -0.1651,0.3322 0.076,0.7222 0.4472,0.7226 h 4 c 0.371,-4e-4 0.6124,-0.3904 0.4473,-0.7226 l -2,-4 c -0.084,-0.1686 -0.2552,-0.2758 -0.4434,-0.2774 z"
+ id="path18541-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
</g>
<g
- id="g15336"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="matrix(-1,0,0,1,970.039,-190)"
+ id="g19901"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="K-25">
<path
- sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- id="path13329"
- d="m 369.99998,160.99999 c -2.20236,0 -4,1.79764 -4,4 0,2.20237 1.79764,4 4,4 2.20237,0 4,-1.79763 4,-4 0,-2.20236 -1.79763,-4 -4,-4 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 516.5,223 c -3.27784,-9.4e-4 -5.036,2.7211 -6.36328,4.16211 -0.17644,0.19146 -0.17644,0.48627 0,0.67773 1.32749,1.44124 3.08593,4.16011 6.36328,4.16211 3.27801,0.002 5.03607,-2.72118 6.36328,-4.16211 0.17644,-0.19146 0.17644,-0.48627 0,-0.67773 C 521.53587,225.72096 519.77754,223.00094 516.5,223 Z m 0,1 a 3.4999952,3.4999933 0 0 1 3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,-3.5 3.4999952,3.4999933 0 0 1 3.5,-3.5 z m 0,2 a 1.4999952,1.4999944 0 0 0 -1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,-1.5 1.4999952,1.4999944 0 0 0 -1.5,-1.5 z"
+ transform="matrix(-1,0,0,1,970.039,190)"
+ id="path19890" />
+ </g>
+ <g
+ id="g150601"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 363.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
- id="rect13350"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path19886"
+ d="m 489.50195,227 a 0.50005,0.50005 0 0 0 -0.33203,0.84375 c 1.3239,1.43817 3.0824,4.1582 6.3457,4.1582 3.26331,0 5.02376,-2.72003 6.34766,-4.1582 a 0.50037481,0.50037481 0 1 0 -0.73633,-0.67773 c -1.43556,1.55946 -2.90607,3.83593 -5.61133,3.83593 -2.70525,0 -4.17576,-2.27647 -5.61132,-3.83593 A 0.50005,0.50005 0 0 0 489.50195,227 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
+ transform="translate(315,-0.999996)"
+ id="g13630-2"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23051-0"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
- transform="translate(210,20.999991)">
+ inkscape:label="K-23">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 243.49219,389 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -3,3 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 L 243,390.70703 V 402 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 4 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 244 v -11.29297 l 2.14648,2.14649 c 0.47127,0.49023 1.19727,-0.23577 0.70704,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
- transform="translate(-210,-20.999991)"
- id="path23043-3"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccc" />
+ d="m 164.50781,224 a 0.50004997,0.50004997 0 0 1 0.43164,0.27148 c 1.44011,2.71955 1.43779,6.74164 -0.008,9.45899 a 0.50022794,0.50022794 0 1 1 -0.88281,-0.4707 c 1.24398,-2.33836 1.24519,-6.17912 0.006,-8.51954 A 0.50004997,0.50004997 0 0 1 164.50781,224 Z m -1.99609,1.99805 a 0.50004997,0.50004997 0 0 1 0.49219,0.50586 v 4.99218 a 0.50004997,0.50004997 0 1 1 -1,0 v -4.99218 a 0.50004997,0.50004997 0 0 1 0.50781,-0.50586 z M 159.25,223 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 L 156.04297,226 H 154.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.54297 l 2.85351,2.85352 c 0.0938,0.0938 0.22092,0.14646 0.35352,0.14648 h 0.25 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 223.78125 223.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path13628-2" />
</g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g22966-4"
- transform="translate(-504,167.99288)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ id="g150598"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-22">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 366.5,389 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 363,392.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 377,399.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 h 8.58008 l -1.99414,2 h -8.58594 z M 376,390.70117 v 8.5918 l -2,2 v -8.58789 z M 364,393 h 9 v 9 h -9 z"
- transform="translate(504,-167.99288)"
- id="path22960-9"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path13642-1"
+ d="m 453.5,222 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 450.29297,225 H 448.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 453.5,234 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 222.78125 222.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 454 v 10 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 450.5,230 H 449 v -4 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g27418"
+ transform="translate(84,-84)"
+ inkscape:label="K-21">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 870.49219,220.99219 A 0.50005,0.50005 0 0 0 870,221.5 v 9.79297 l -2.85352,2.86133 a 0.50005,0.50005 0 1 0 0.70704,0.70508 L 870.70703,232 H 880.5 a 0.50005,0.50005 0 1 0 0,-1 H 871 v -9.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path23055-1"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 352.50003,305.0003 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ id="path27589"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssssccccccccccccc" />
+ <g
+ id="g27675-2"
+ transform="rotate(90,232.499,657.496)"
+ style="display:inline;opacity:0.7;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -109.99609,533.99609 -0.004,7.11133 c -1.67885,0.25428 -2.99414,1.64686 -2.99414,3.39453 0,1.92568 1.57041,3.49805 3.49609,3.49805 1.92569,0 3.49805,-1.57236 3.49805,-3.49805 0,-1.74925 -1.31894,-3.14219 -3,-3.39453 l 0.004,-7.11133 z m 0.49804,8.00977 c 1.38524,0 2.49805,1.11085 2.49805,2.49609 0,1.38525 -1.1128,2.49805 -2.49805,2.49805 -1.38524,0 -2.49609,-1.11281 -2.49609,-2.49805 0,-1.38523 1.11086,-2.49609 2.49609,-2.49609 z"
+ id="path27671-7"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -108.5,534 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27673-7"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g27444"
+ transform="translate(-18,-64)"
+ inkscape:label="K-20">
+ <g
+ id="g27675"
+ transform="rotate(90,282.999,687.996)"
+ style="opacity:0.7">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -109.99609,533.99609 -0.004,7.11133 c -1.67885,0.25428 -2.99414,1.64686 -2.99414,3.39453 0,1.92568 1.57041,3.49805 3.49609,3.49805 1.92569,0 3.49805,-1.57236 3.49805,-3.49805 0,-1.74925 -1.31894,-3.14219 -3,-3.39453 l 0.004,-7.11133 z m 0.49804,8.00977 c 1.38524,0 2.49805,1.11085 2.49805,2.49609 0,1.38525 -1.1128,2.49805 -2.49805,2.49805 -1.38524,0 -2.49609,-1.11281 -2.49609,-2.49805 0,-1.38523 1.11086,-2.49609 2.49609,-2.49609 z"
+ id="path27671"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -108.5,534 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27673"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 430.49414,284.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 2.64649,2.64648 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.64648,-2.64649 2.64648,2.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2.64649,-2.64648 2.64649,-2.64648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -2.64648,2.64649 -2.64648,-2.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path27679"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-327,477.99999)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g16423-6">
+ id="g5270-3"
+ transform="translate(497.995,-311.993)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="K-19">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 391,389 c -3.83836,-10e-6 -6.96097,3.10534 -6.99609,6.93555 A 0.50005,0.50005 0 0 0 384,396 c 0,3.86012 3.13988,7.00001 7,7 0.0171,0 0.0337,-0.002 0.0508,-0.002 a 0.50005,0.50005 0 0 0 0.01,-0.002 C 394.89256,402.96308 398,399.83968 398,396 c 0,-0.0171 -0.002,-0.0337 -0.002,-0.0508 a 0.50005,0.50005 0 0 0 -0.002,-0.01 c -0.0328,-3.81095 -3.12289,-6.90166 -6.93359,-6.93554 A 0.50005,0.50005 0 0 0 391,389 Z m 0,1 c 3.31968,0 6,2.68032 6,6 0,0.16955 -0.0858,0.36541 -0.34766,0.60352 -0.26184,0.2381 -0.68795,0.48634 -1.23632,0.69726 C 394.31926,397.72262 392.74298,398 391,398 c -0.65939,0 -1.28221,-0.0509 -1.87695,-0.12305 C 389.05085,397.28221 389,396.65939 389,396 c 0,-1.74298 0.27738,-3.31926 0.69922,-4.41602 0.21092,-0.54837 0.45916,-0.97448 0.69726,-1.23632 C 390.63459,390.08581 390.83045,390 391,390 Z m -1.76367,0.26367 c -0.17337,0.28719 -0.33274,0.60224 -0.47071,0.96094 C 388.28261,392.48043 388,394.15308 388,396 c 0,0.59486 0.0379,1.16229 0.0937,1.71289 -0.55897,-0.113 -1.07951,-0.24662 -1.50977,-0.41211 -0.54837,-0.21092 -0.97448,-0.45916 -1.23632,-0.69726 C 385.08581,396.36541 385,396.16955 385,396 c 0,-2.70567 1.78034,-4.98512 4.23633,-5.73633 z m -3.97266,7.5 c 0.28719,0.17337 0.60224,0.33274 0.96094,0.47071 0.58524,0.22509 1.26802,0.40153 2.00977,0.53124 0.12972,0.74174 0.30616,1.42453 0.53124,2.00977 0.13797,0.3587 0.29734,0.67375 0.47071,0.96094 -1.89863,-0.58074 -3.39192,-2.07402 -3.97266,-3.97266 z m 11.47266,0 C 395.98511,400.21966 393.70566,402 391,402 c -0.16955,0 -0.36541,-0.0858 -0.60352,-0.34766 -0.2381,-0.26184 -0.48634,-0.68795 -0.69726,-1.23632 -0.16549,-0.43026 -0.29911,-0.9508 -0.41211,-1.50977 0.5506,0.0559 1.11803,0.0937 1.71289,0.0937 1.84692,0 3.51957,-0.28262 4.77539,-0.76562 0.3587,-0.13797 0.67375,-0.29734 0.96094,-0.47071 z"
- transform="translate(327,-477.99999)"
- id="path22958-5"
- inkscape:connector-curvature="0" />
+ id="path5169-5"
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+ d="m -115,532 h 16.005051 v 16 H -115 Z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
<g
- transform="translate(327,-415)"
- id="g23066-1"
- style="display:inline;fill:#ffffff;enable-background:new">
+ transform="translate(-1)"
+ id="g5191-5"
+ style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 391,330 c -1.84692,0 -3.51957,0.28261 -4.77539,0.76562 -0.62791,0.24151 -1.15478,0.53052 -1.55078,0.89063 C 384.27783,332.01636 384,332.47917 384,333 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.16955 0.0858,-0.36541 0.34766,-0.60352 0.26184,-0.2381 0.68795,-0.48634 1.23632,-0.69726 C 387.68074,331.27738 389.25702,331 391,331 c 1.74298,0 3.31926,0.27738 4.41602,0.69922 0.54837,0.21092 0.97448,0.45916 1.23632,0.69726 C 396.91419,332.63459 397,332.83045 397,333 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.52083 -0.27783,-0.98364 -0.67383,-1.34375 -0.396,-0.36011 -0.92287,-0.64912 -1.55078,-0.89063 C 394.51957,330.28261 392.84692,330 391,330 Z"
- id="path23061-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 386.48633,221 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 6.55664 C 384.86022,229.298 384,230.30731 384,231.50781 c 0,1.372 1.12214,2.49414 2.49414,2.49414 1.372,0 2.49414,-1.12214 2.49414,-2.49414 0,-1.20116 -0.8593,-2.21054 -1.99414,-2.44336 v -6.55664 -1 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z m 1.00781,1.00781 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -1,8.00586 c 0.83156,0 1.49414,0.66258 1.49414,1.49414 0,0.83156 -0.66258,1.49414 -1.49414,1.49414 -0.83156,0 -1.49414,-0.66258 -1.49414,-1.49414 0,-0.83156 0.66258,-1.49414 1.49414,-1.49414 z"
+ transform="translate(-496.995,311.993)"
+ id="path5112-6"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-3)"
+ style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new"
+ id="g5186-5-5-7">
+ <path
+ id="path5179-0-9-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -97.896484,538.39648 -1.707032,1.70704 0.75,0.75 c 0.195265,0.19518 0.511767,0.19518 0.707032,0 l 0.52539,-0.5254 0.47461,-0.4746 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 z m -0.614086,-1.39969 a 0.50005,0.50005 0 0 0 -0.34376,0.15039 l -4.4121,4.41015 c -0.38435,-0.27257 -0.83195,-0.45926 -1.31446,-0.52734 a 0.50005,0.50005 0 0 0 -0.0996,-0.006 0.50005,0.50005 0 0 0 -0.041,0.99609 c 0.71727,0.10121 1.32147,0.58072 1.58398,1.25586 0.26252,0.67514 0.14019,1.43694 -0.32031,1.9961 -0.46051,0.55917 -1.18354,0.82547 -1.89649,0.69726 a 0.50014796,0.50014796 0 1 0 -0.17773,0.98438 c 1.06733,0.19194 2.15825,-0.20977 2.84766,-1.04688 0.6894,-0.83711 0.87347,-1.98341 0.48047,-2.99414 -0.0911,-0.23424 -0.21129,-0.45079 -0.35352,-0.65039 l 4.41016,-4.4082 a 0.50005,0.50005 0 0 0 -0.36328,-0.85742 z"
inkscape:connector-curvature="0" />
</g>
</g>
<g
- transform="translate(-348,477.99999)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g16413-1">
+ id="g150574"
+ style="display:inline;enable-background:new;stroke-width:1.00038044;stroke-dasharray:none"
+ transform="matrix(0.77770413,0,0,0.77770413,82.359643,50.7947)"
+ inkscape:label="K-18">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 759.5,-89 a 0.50005,0.50005 0 0 0 -0.41406,0.220703 l -5.75,8.5 a 0.50005,0.50005 0 0 0 -0.0254,0.04102 C 753.09798,-79.847634 753,-79.420118 753,-79 c 0,1.217423 0.89627,2.23231 2.16602,2.916016 C 756.43576,-75.400278 758.13235,-75 760,-75 c 1.86765,0 3.56424,-0.400278 4.83398,-1.083984 C 766.10373,-76.76769 767,-77.782577 767,-79 c 0,-0.419749 -0.0968,-0.847195 -0.3125,-1.240234 a 0.50005,0.50005 0 0 0 -0.0234,-0.03906 l -5.75,-8.5 A 0.50005,0.50005 0 0 0 760.5,-89 Z m 0.26562,1 h 0.46876 l 5.58007,8.248047 C 765.94193,-79.51674 766,-79.268361 766,-79 c 0,0.715577 -0.55782,1.452112 -1.64062,2.035156 C 763.27657,-76.3818 761.72215,-76 760,-76 c -1.72215,0 -3.27657,-0.3818 -4.35938,-0.964844 C 754.55782,-77.547888 754,-78.284423 754,-79 c 0,-0.262685 0.0617,-0.522361 0.1875,-0.755859 z"
- id="path22956-5"
- inkscape:connector-curvature="0" />
+ style="display:inline;enable-background:new;color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto"
+ d="m 370.49414,224.00195 a 0.50005,0.50005 0 0 0 -0.34766,0.14649 l -4,3.99804 a 0.50005,0.50005 0 0 0 0,0.70704 l 4,4 a 0.50005,0.50005 0 0 0 0.70508,0 l 3.99219,-3.97852 a 0.50005,0.50005 0 0 0 0.002,-0.70703 l -3.99218,-4.01953 a 0.50005,0.50005 0 0 0 -0.35938,-0.14649 z m 0.004,1.20899 3.28711,3.30859 L 370.5,231.79297 367.20703,228.5 Z"
+ id="path23352-4-7"
+ inkscape:connector-curvature="0"
+ transform="matrix(1.285836,0,0,1.285836,-105.901,-65.313656)" />
+ </g>
+ <g
+ id="g150577"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 760,-82 c -1.85842,0 -3.5402,0.34854 -4.79688,0.898438 -0.62833,0.274948 -1.15274,0.599804 -1.54296,0.982421 C 753.26993,-79.736524 753,-79.270893 753,-78.75 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.169742 0.0937,-0.393844 0.36133,-0.65625 0.26762,-0.262406 0.69425,-0.539532 1.24219,-0.779297 C 756.69939,-80.665077 758.26862,-81 760,-81 c 1.73138,0 3.30061,0.334923 4.39648,0.814453 0.54794,0.239765 0.97457,0.516891 1.24219,0.779297 C 765.90629,-79.143844 766,-78.919742 766,-78.75 a 0.50005,0.50005 0 1 0 1,0 c 0,-0.520893 -0.26993,-0.986524 -0.66016,-1.369141 -0.39022,-0.382617 -0.91463,-0.707473 -1.54296,-0.982421 C 763.5402,-81.65146 761.85842,-82 760,-82 Z"
- id="path23072-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 349.49414,224 c -0.13124,0.001 -0.25681,0.0537 -0.34961,0.14648 l -3.99805,4 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3.99805,4 c 0.19526,0.19518 0.51177,0.19518 0.70703,0 l 3.99219,-3.97852 c 0.19574,-0.19471 0.19663,-0.51121 0.002,-0.70703 l -3.99218,-4.01953 c -0.0949,-0.0959 -0.2245,-0.14948 -0.35943,-0.14844 z"
+ id="path23378-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ </g>
+ <g
+ id="g150580"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-16">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 328.48047,226.75 a 0.50005,0.50005 0 0 0 -0.39063,0.21484 l -3.99023,5.72461 a 0.50005,0.50005 0 0 0 -0.0898,0.27735 L 324,233.49219 A 0.50005,0.50005 0 0 0 324.5,234 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 233 a 0.50005,0.50005 0 0 0 -0.0898,-0.28516 l -4,-5.75 A 0.50005,0.50005 0 0 0 328.48047,226.75 Z m 0.0195,1.375 3.39062,4.875 h -6.78906 z"
+ id="path23380-3"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(147)"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g12973-3-2"
- style="display:inline;fill:#ffffff;enable-background:new">
+ id="g150583"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 178.49219,368 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 178,369.70703 v 7.58594 l -3,3 V 378.5 A 0.50005,0.50005 0 0 0 174.49219,377.99219 0.50005,0.50005 0 0 0 174,378.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -1.79297 l 3,-3 h 7.58594 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 186.29297,377 H 179 v -7.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2,-2 A 0.50005,0.50005 0 0 0 178.49219,368 Z"
- transform="translate(-147)"
- id="path12965-4-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 307.48242,226.75 c -0.15739,0.006 -0.30286,0.0854 -0.39258,0.21484 l -4,5.75 c -0.0583,0.0837 -0.0897,0.18317 -0.0898,0.28516 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27999,2e-5 0.50544,-0.22983 0.5,-0.50977 l -0.01,-0.47461 c -0.002,-0.0985 -0.0321,-0.19425 -0.0879,-0.27539 l -3.99023,-5.77539 c -0.0971,-0.14016 -0.25903,-0.22114 -0.42945,-0.21484 z"
+ id="path23382-9"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccc" />
+ </g>
+ <g
+ id="g150595"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-14">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 285.49219,220.9707 a 0.50005,0.50005 0 0 0 -0.4336,0.29688 l -4,9 a 0.50005,0.50005 0 0 0 0.10352,0.55664 l 4,4 a 0.50005,0.50005 0 0 0 0.70703,0 l 4,-4 a 0.50005,0.50005 0 0 0 0.10352,-0.55664 l -4,-9 a 0.50005,0.50005 0 0 0 -0.48047,-0.29688 z m 0.0234,1.73047 3.4043,7.65821 -3.4043,3.40429 -3.40429,-3.40429 z"
+ id="path20963"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g16957-2"
- transform="rotate(90,380.00189,176.00657)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g150589"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-13">
<path
- id="path16949-6"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 479,347 c -1.09865,0 -1.99999,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 -10e-6,-1.09865 -0.90135,-2 -2,-2 z m 0,1 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.55821 0.44179,-1 1,-1 z m 0.5,9 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -10,-11 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z m 0,1 c 0.28207,0 0.5,0.21793 0.5,0.5 0,0.28207 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z m 0,8 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z m 0,1 c 0.83434,0 1.5,0.66566 1.5,1.5 0,0.83434 -0.66566,1.5 -1.5,1.5 -0.83434,0 -1.5,-0.66566 -1.5,-1.5 0,-0.83434 0.66566,-1.5 1.5,-1.5 z"
+ d="m 264.49219,220.9707 a 0.50005,0.50005 0 0 0 -0.4336,0.29688 l -4,9 a 0.50005,0.50005 0 0 0 0.10352,0.55664 l 4,4 a 0.50005,0.50005 0 0 0 0.70703,0 l 4,-4 a 0.50005,0.50005 0 0 0 0.10352,-0.55664 l -4,-9 a 0.50005,0.50005 0 0 0 -0.48047,-0.29688 z m 0.0234,1.73047 3.4043,7.65821 -3.4043,3.40429 -3.40429,-3.40429 z"
+ id="path14674"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g150586"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-12">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 469.49219,348.99219 A 0.50005,0.50005 0 0 0 469,349.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7.99804,1.0039 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 473.5,358 a 0.50005,0.50005 0 1 0 0,1 h 5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path16955-3"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 243.49219,220.9707 c -0.18907,0.009 -0.3569,0.12383 -0.4336,0.29688 l -4,9 c -0.084,0.18909 -0.0428,0.41038 0.10352,0.55664 l 4,4 c 0.19526,0.19518 0.51177,0.19518 0.70703,0 l 4,-4 c 0.14634,-0.14626 0.1875,-0.36755 0.10352,-0.55664 l -4,-9 c -0.0836,-0.18859 -0.27441,-0.3065 -0.48047,-0.29688 z"
+ id="path13222-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g15967">
+ id="g150672"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-11">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 244,561 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z"
- id="path17035"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 221.50195,227 c -0.35971,-0.001 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0266 -0.12814,-0.0406 -0.19535,-0.041 z"
+ id="path12946-5"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ sodipodi:nodetypes="ccccccccc" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g13384"
+ transform="translate(-21,-105)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <g
+ id="g13382"
+ transform="translate(1)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 238.49414,326.05078 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z m 9,0 c -0.11724,0.001 -0.22936,0.0482 -0.3125,0.13086 l -2,2 c -0.17593,0.17578 -0.17593,0.46094 0,0.63672 l 2,2 c 0.17578,0.17593 0.46094,0.17593 0.63672,0 l 2,-2 c 0.17593,-0.17578 0.17593,-0.46094 0,-0.63672 l -2,-2 c -0.086,-0.0855 -0.20293,-0.13272 -0.32422,-0.13086 z"
+ id="path13378"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccc" />
+ <path
+ style="opacity:0.5;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 240.12109,326 1.43946,1.43945 c 0.58556,0.5858 0.58556,1.5353 0,2.1211 L 240.12109,331 h 5.75782 l -1.43946,-1.43945 c -0.58556,-0.5858 -0.58556,-1.5353 0,-2.1211 L 245.87891,326 Z"
+ id="path13380"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccc" />
+ </g>
+ </g>
+ </g>
+ <g
+ id="g6085"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="K-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 243.92383,557 c -0.2146,0.003 -0.42883,0.0151 -0.64063,0.0371 -2.54151,0.26418 -4.8299,1.914 -5.80664,4.42187 -1.30231,3.34383 0.14236,7.14072 3.33789,8.77344 3.19554,1.63272 7.11991,0.57913 9.06641,-2.43554 a 0.50005,0.50005 0 1 0 -0.83984,-0.54297 c -1.67274,2.59068 -5.02539,3.49293 -7.77149,2.08984 -2.7461,-1.40309 -3.98048,-4.64795 -2.86133,-7.52148 1.11915,-2.87354 4.22361,-4.42733 7.19532,-3.60352 a 0.50036742,0.50036742 0 1 0 0.26562,-0.96484 c -0.64839,-0.17975 -1.3015,-0.26149 -1.94531,-0.25391 z M 249,557 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
- id="path17037"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 199.5,221.00391 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.5 v 1.08789 c -2.83241,0.47934 -5.00001,2.94243 -5,5.9082 0,3.30787 2.69334,6 6.00195,6 3.30861,0 6.00196,-2.69214 6.00196,-6 0,-1.22417 -0.37149,-2.36223 -1.00391,-3.3125 a 0.50005,0.50005 0 0 0 0.10352,-0.0801 l 1.75,-1.75 a 0.50005,0.50005 0 0 0 -0.36329,-0.85937 0.50005,0.50005 0 0 0 -0.34375,0.15234 l -1.75,1.75 a 0.50005,0.50005 0 0 0 -0.0117,0.0137 C 205.28833,223.73959 203.73131,223 202.00195,223 c -6.5e-4,0 -0.001,0 -0.002,0 v -0.99609 h 1.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z M 202.00195,224 c 2.76833,0 5.00196,2.23273 5.00196,5 0,2.76726 -2.23363,5 -5.00196,5 C 199.23362,234 197,231.76727 197,229 c -1e-5,-2.76727 2.23362,-5 5.00195,-5 z"
+ id="path17270"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 201.49219,224.99609 A 0.50005,0.50005 0 0 0 201,225.50391 v 3.91992 a 0.50005,0.50005 0 0 0 0.11328,0.40429 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.39453,0.10352 H 204.5 a 0.50005,0.50005 0 1 0 0,-1 H 202 v -3.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50782 z"
+ id="path17274"
inkscape:connector-curvature="0" />
</g>
<g
- transform="rotate(90,243.5,333.5)"
- id="g12586"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g150607"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 469.5,356 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z"
- id="path12572"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 185.04038,221.99997 c 0.53618,0.022 0.95938,0.4634 0.95898,1 v 10 c -7.2e-4,0.7847 -0.8635,1.2629 -1.5293,0.8477 l -8,-5 c -0.62591,-0.3918 -0.62591,-1.3036 0,-1.6954 l 8,-5 c 0.17045,-0.107 0.36922,-0.1601 0.57032,-0.1523 z"
+ id="path9268"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- <g
- id="g23031"
- style="opacity:0.7;fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 218.5,557 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 V 564.5 c -0.01,0.67616 1.01,0.67616 1,0 v -4.59375 c 0.57903,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 9.5,0 c -1.09865,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -5.13868,5.13867 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 5.13867,-5.13868 C 227.28978,560.89117 227.63141,561 228,561 c 1.09865,-10e-6 2,-0.90135 2,-2 0,-1.09865 -0.90135,-1.99999 -2,-2 z m 0.5,10 c -0.64684,0 -1.19777,0.42097 -1.40625,1 H 222.5 c -0.67616,-0.01 -0.67616,1.01 0,1 h 4.59375 c 0.20848,0.57903 0.75941,1 1.40625,1 0.82251,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
- transform="matrix(0,-1,-1,0,1038,577)"
- id="path12578"
- inkscape:connector-curvature="0" />
- </g>
+ sodipodi:nodetypes="cccccccc" />
</g>
<g
- transform="translate(-21.00225)"
- style="display:inline;fill:#ffffff;stroke:#ffffff;enable-background:new"
- id="g13169-8-6"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12135"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="K-8">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 469.49414,55.992188 A 0.50004982,0.50004982 0 0 0 469.00195,56.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 471.00195,57.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 473.00195,58.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 475.00195,59.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
- id="path13150-5-2"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 158.5,222 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 155.29297,225 H 153.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 158.5,234 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 222.78125 222.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 159 v 10 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 155.5,230 H 154 v -4 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z"
+ id="path12129"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 471.49609,54.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 477.00195,58.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
- id="path13154-7-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 165.4668,223.01562 a 0.50005,0.50005 0 0 0 -0.42188,0.72071 c 1.27607,2.70648 1.27309,5.84072 -0.008,8.54492 a 0.50017783,0.50017783 0 1 0 0.9043,0.42773 c 1.40867,-2.97397 1.41118,-6.42391 0.008,-9.40039 a 0.50005,0.50005 0 0 0 -0.48242,-0.29297 z m -2.86133,0.9375 a 0.50005,0.50005 0 0 0 -0.43359,0.74219 c 1.10287,2.06013 1.10465,4.5334 0.006,6.59571 a 0.50023236,0.50023236 0 1 0 0.88282,0.4707 c 1.25518,-2.35583 1.25203,-5.18378 -0.008,-7.53711 a 0.50005,0.50005 0 0 0 -0.44726,-0.27149 z"
+ id="path12133"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g150610"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-7">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 473.49609,53.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 479.00195,57.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
- id="path13161-0-0"
+ inkscape:connector-curvature="0"
+ id="path27528"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 132.5104,224 c -0.27994,-0.01 -0.50979,0.22 -0.50977,0.5 v 7 c -0.001,0.4307 0.5065,0.6613 0.83008,0.377 l 4,-3.5 c 0.22872,-0.1993 0.22872,-0.5547 0,-0.754 l -4,-3.5 c -0.0889,-0.078 -0.20238,-0.1211 -0.32031,-0.123 z m 9.96289,-1 c -0.13302,0.01 -0.25746,0.068 -0.34571,0.168 l -4,4.5 c -0.16816,0.1894 -0.16816,0.4746 0,0.664 l 4,4.5 c 0.19883,0.2227 0.54727,0.2227 0.7461,0 l 4,-4.5 c 0.16816,-0.1894 0.16816,-0.4746 0,-0.664 l -4,-4.5 c -0.10092,-0.114 -0.24831,-0.1759 -0.40039,-0.168 z" />
+ </g>
+ <g
+ id="g150616"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-6">
+ <path
+ d="m 124.49003,224 c 0.27994,-0.01 0.50979,0.22 0.50977,0.5 v 7 c 0.001,0.4307 -0.5065,0.6613 -0.83008,0.377 l -4,-3.5 c -0.22872,-0.1993 -0.22872,-0.5547 0,-0.754 l 4,-3.5 c 0.0889,-0.078 0.20238,-0.1211 0.32031,-0.123 z m -9.96289,-1 c 0.13302,0.01 0.25746,0.068 0.34571,0.168 l 4,4.5 c 0.16816,0.1894 0.16816,0.4746 0,0.664 l -4,4.5 c -0.19883,0.2227 -0.54727,0.2227 -0.7461,0 l -4,-4.5 c -0.16816,-0.1894 -0.16816,-0.4746 0,-0.664 l 4,-4.5 c 0.10092,-0.114 0.24831,-0.1759 0.40039,-0.168 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9201"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1.09731;enable-background:new"
+ transform="matrix(1,0,0,0.830508,1300,-195.576)"
+ id="g8019-1"
+ inkscape:label="K-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999964;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 475.49609,52.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 481.00195,56.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
- id="path13163-4-8"
+ sodipodi:nodetypes="cccccccccc"
+ inkscape:connector-curvature="0"
+ d="m -1207,502.79592 v 14.44898 h 2 v -14.44898 z m 6,0 v 14.44898 h 2 v -14.44898 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.19461;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path8013-3" />
+ </g>
+ <g
+ id="g150619"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-4">
+ <path
+ d="m 79.49414,224 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z M 73,223 v 10 h -2 v -10 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9203"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 535.5,494 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1 c 2e-5,0.1326 0.0527,0.25976 0.14648,0.35352 L 536,496.70703 v 2.61524 l -4.38672,5.36132 -0.004,0.004 c -0.58889,0.7361 -0.70787,1.57018 -0.44922,2.2168 0.25864,0.64662 0.88151,1.0957 1.58984,1.0957 h 10.5 c 0.70833,0 1.33692,-0.44332 1.60352,-1.0918 0.26614,-0.64736 0.14367,-1.48967 -0.4668,-2.22461 L 540,499.32227 v -2.61524 l 0.85352,-0.85351 c 0.0938,-0.0938 0.14646,-0.22092 0.14648,-0.35352 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 4 v 0.29297 l -0.85352,0.85351 c -0.0938,0.0938 -0.14646,0.22092 -0.14648,0.35352 v 3 c 1.3e-4,0.11538 0.0402,0.22717 0.11328,0.31641 l 4.5,5.5 c 6.6e-4,10e-4 9.5e-4,0.003 0.002,0.004 0.42848,0.51418 0.43133,0.91996 0.3125,1.20899 C 543.80886,506.81822 543.54167,507 543.25,507 h -10.5 c -0.29167,0 -0.5438,-0.17592 -0.66016,-0.4668 -0.11635,-0.29088 -0.11033,-0.7068 0.30078,-1.2207 l 4.4961,-5.49609 c 0.0731,-0.0892 0.11315,-0.20103 0.11328,-0.31641 v -3 c -2e-5,-0.1326 -0.0527,-0.25976 -0.14648,-0.35352 L 536,495.29297 Z m 0,8 c -0.14428,-3.9e-4 -0.2817,0.0616 -0.37695,0.16992 l -1.75,2 c -0.28426,0.32357 -0.0537,0.83118 0.37695,0.83008 h 7.5 c 0.43069,10e-4 0.66121,-0.50651 0.37695,-0.83008 l -1.75,-2 C 540.2817,503.06155 540.14428,502.99961 540,503 Z"
- id="path13700"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g16377"
- transform="translate(-217,44.000001)">
+ id="g150613"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-3">
<path
- id="path16340"
- d="m 589,450 c -1.09935,0 -2,0.90065 -2,2 v 0.42969 c 0.73665,0.57364 1.18952,1.45204 1.23438,2.41601 C 588.47082,454.9447 588.72885,455 589,455 h 1 c 1.09935,0 2,-0.90065 2,-2 v -1 c 0,-1.09935 -0.90065,-2 -2,-2 z m 2.58789,6.00586 c -0.28431,-0.0492 -0.58776,0.16015 -0.58789,0.49414 0,0.25 -0.25,0.5 -0.5,0.5 h -2 c -0.25,0 -0.5,-0.25 -0.5,-0.5 v 0.5 c 0,0.36306 -0.26134,0.68419 -0.44336,0.93555 l 0.004,0.004 c 0.41161,0.41161 0.88215,0.75715 1.375,1.25 0.40738,0.40739 0.86402,1.03976 1.01172,1.81055 H 593.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 459 c 0,-0.66667 -0.3572,-1.18923 -0.77148,-1.60352 -0.41429,-0.41428 -0.90447,-0.77946 -1.375,-1.25 -0.0788,-0.0787 -0.17086,-0.12422 -0.26563,-0.14062 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ssccsssssscccccccsccccsccc" />
+ id="path27544"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 51.506493,224 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z m 6.49414,-1 v 10 h 2 v -10 z" />
+ </g>
+ <g
+ id="g150604"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 584,453 c -1.09935,0 -2,0.90065 -2,2 v 1 c 0,1.09935 0.90065,2 2,2 h 1 c 1.09935,0 2,-0.90065 2,-2 v -1 c 0,-1.09935 -0.90065,-2 -2,-2 z m -1.51562,6 c -0.12717,0.004 -0.248,0.0564 -0.3379,0.14648 -0.47053,0.47054 -0.96071,0.83572 -1.375,1.25 C 580.3572,460.81077 580,461.33333 580,462 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 462 c 0,-0.66667 -0.3572,-1.18923 -0.77148,-1.60352 -0.41429,-0.41428 -0.90447,-0.77946 -1.375,-1.25 -0.32034,-0.32057 -0.86773,-0.0838 -0.85352,0.36914 8.5e-4,0.0269 -0.0479,0.18374 -0.16406,0.30274 C 585.71981,459.93736 585.56612,460 585.5,460 h -2 c -0.0803,0 -0.22193,-0.0571 -0.33203,-0.16797 -0.1101,-0.11083 -0.16786,-0.25596 -0.16797,-0.33203 1.1e-4,-0.28235 -0.23341,-0.50879 -0.51562,-0.5 z"
- id="path16332"
+ sodipodi:nodetypes="cccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ssssssssscccsccccsccccssccc" />
+ id="path27639"
+ d="m 29.959614,221.99997 c -0.53618,0.022 -0.95938,0.4634 -0.95898,1 v 10 c 7.2e-4,0.7847 0.8635,1.2629 1.5293,0.8477 l 8,-5 c 0.625909,-0.3918 0.625909,-1.3036 0,-1.6954 l -8,-5 c -0.17045,-0.107 -0.36922,-0.1601 -0.57032,-0.1523 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 450.32227,452.0625 C 448.61213,452.13527 447,453.5463 447,456 c 0,2.05278 1.07076,4.01178 2.38672,5.71289 1.31595,1.70111 2.90024,3.15481 4.03125,4.16016 A 0.50005,0.50005 0 0 0 453.75,466 h 0.5 a 0.50005,0.50005 0 0 0 0.33203,-0.12695 c 1.13101,-1.00535 2.7153,-2.45905 4.03125,-4.16016 C 459.92924,460.01178 461,458.05278 461,456 c 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z m 0.043,1 c 1.22737,-0.0522 2.55838,0.74689 2.89258,2.5293 A 0.50005,0.50005 0 0 0 453.75,456 h 0.5 a 0.50005,0.50005 0 0 0 0.49219,-0.4082 c 0.3342,-1.78241 1.66521,-2.58153 2.89258,-2.5293 C 458.86213,453.1147 460,453.9537 460,456 c 0,1.69722 -0.92924,3.48822 -2.17578,5.09961 -1.20727,1.56061 -2.67447,2.91135 -3.7832,3.90039 h -0.082 c -1.10873,-0.98904 -2.57593,-2.33978 -3.7832,-3.90039 C 448.92924,459.48822 448,457.69722 448,456 c 0,-2.0463 1.13787,-2.88527 2.36523,-2.9375 z"
- id="path6081"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 471.32227,452.0625 C 469.61213,452.13527 468,453.5463 468,456 c 0,1.29326 0.43161,2.55298 1.07227,3.72852 0.16015,0.29312 0.55714,0.34983 0.79296,0.11328 l 3.63477,-3.63477 1.64648,1.64649 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 2.64648,-2.64649 2.48242,2.48242 c 0.27743,0.27645 0.75058,0.14111 0.83985,-0.24023 C 481.93311,456.97518 482,456.49157 482,456 c 0,-2.4537 -1.61213,-3.86473 -3.32227,-3.9375 -1.52139,-0.0647 -3.0532,0.927 -3.67773,2.69727 -0.62453,-1.77027 -2.15634,-2.76201 -3.67773,-2.69727 z M 478.49219,458 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -2.64648,2.64649 -1.64648,-1.64649 c -0.19527,-0.19519 -0.51177,-0.19519 -0.70704,0 l -2.34765,2.34766 c -0.18257,0.18194 -0.19694,0.47283 -0.0332,0.67188 1.2321,1.49847 2.62304,2.79208 3.65235,3.70703 0.0914,0.0816 0.20953,0.12673 0.33202,0.12695 h 0.5 c 0.12249,-2.2e-4 0.24064,-0.0454 0.33203,-0.12695 1.41546,-1.2582 3.54029,-3.21344 4.96094,-5.48828 0.12374,-0.19754 0.0946,-0.45438 -0.0703,-0.61915 l -1.61914,-1.61914 c -0.0957,-0.0957 -0.22604,-0.14856 -0.36134,-0.14648 z"
- id="path6086"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="csccccccccscccccccccccccccccc" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g16467"
- transform="translate(-221.99998,478)">
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g12626-8"
- transform="translate(726.00003,-499.00001)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 30.492188,367.99219 A 0.50005,0.50005 0 0 0 30,368.5 v 9.79297 l -2.853516,2.85351 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 30.707031,379 H 40.5 a 0.50005,0.50005 0 1 0 0,-1 H 31 v -9.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
- id="path12205-4"
- inkscape:connector-curvature="0" />
- </g>
- <g
- transform="matrix(-1,0,0,1,1420,227.99979)"
- id="g8805-9"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 653.5,-359 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 0.5 h 1 v -0.5 -7.5 h 7.5 0.5 v -1 h -0.5 z"
- id="path8743-5"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 542,349 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -3.48047,2.05078 c -0.16946,-0.008 -0.32881,0.0808 -0.41211,0.22852 l -2.25,4 c -0.17018,0.3004 0.0473,0.67264 0.39258,0.67187 h 4.5 c 0.34528,7.7e-4 0.56276,-0.37147 0.39258,-0.67187 l -2.25,-4 c -0.0765,-0.13552 -0.21755,-0.22152 -0.37305,-0.22852 z"
- transform="matrix(-1,0,0,1,1198,-705.99979)"
- id="path8759-7"
- inkscape:connector-curvature="0" />
- </g>
+ id="g150571"
+ style="display:inline;enable-background:new"
+ inkscape:label="K-1">
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 16.999998,228 a 4,4 0 0 1 -4,4 4,4 0 0 1 -3.9999999,-4 4,4 0 0 1 3.9999999,-4 4,4 0 0 1 4,4 z"
+ id="circle8021-5"
+ inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g16449"
- transform="translate(-284.99998,478)">
- <g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g15951-6-3"
- transform="translate(746.99995,-478)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
- id="path15947-7-2"
- inkscape:connector-curvature="0" />
- </g>
- <g
- transform="matrix(-1,0,0,1,1439,229.99979)"
- id="g8805-98"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 653.5,-359 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 8 h -8 z"
- id="path8743-9"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 656,-357 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3.50391,1 c -0.18479,-10e-4 -0.35529,0.0993 -0.44336,0.26172 l -3,5.5 c -0.1805,0.33311 0.0606,0.73812 0.43945,0.73828 h 5.75 c 0.37101,-3.7e-4 0.61244,-0.39044 0.44727,-0.72266 l -2.75,-5.5 c -0.0838,-0.16852 -0.25516,-0.2757 -0.44336,-0.27734 z"
- id="circle8761-3"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ssssscccccccc" />
- </g>
+ id="g14253"
+ inkscape:label="J-22">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 447.5,200 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 201 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.00781,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.01562,9 A 0.50005,0.50005 0 0 0 447,209.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -3.5 A 0.50005,0.50005 0 0 0 447.49219,209 Z M 460.5,209 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 460.5,209 Z"
+ id="path13927-5"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 449.5,203 a 0.50005,0.50005 0 1 0 0,1 h 1 c 0.39167,0 0.74862,0.27445 1.13672,0.86719 0.3881,0.59273 0.74407,1.4462 1.08594,2.3164 0.34186,0.8702 0.67067,1.75605 1.06836,2.4668 0.19884,0.35538 0.41332,0.66981 0.68554,0.91797 0.27222,0.24816 0.62761,0.43164 1.02344,0.43164 0.625,0 1.13349,-0.27613 1.44727,-0.64648 0.31377,-0.37036 0.47247,-0.79704 0.61523,-1.17774 0.14276,-0.3807 0.2723,-0.71757 0.41406,-0.91016 C 458.11833,208.07304 458.20536,208 458.5,208 a 0.50005,0.50005 0 1 0 0,-1 c -0.58036,0 -1.05583,0.30196 -1.32812,0.67188 -0.2723,0.36991 -0.40839,0.78304 -0.54688,1.15234 -0.13849,0.3693 -0.27667,0.69262 -0.43945,0.88476 C 456.02276,209.90113 455.875,210 455.5,210 c -0.10417,0 -0.20191,-0.0353 -0.34961,-0.16992 -0.1477,-0.13465 -0.31994,-0.3671 -0.48828,-0.66797 -0.33669,-0.60175 -0.66413,-1.4659 -1.00977,-2.3457 -0.34563,-0.8798 -0.70841,-1.77633 -1.17968,-2.4961 C 452.00138,203.60055 451.35833,203 450.5,203 Z"
+ id="path14224"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g16457"
- transform="translate(-284.99998,478)">
- <g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g7406-1-2-5"
- transform="translate(347.99997,-290.00356)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
- <path
- id="path7416-1-8-5"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 453,170 v 2 h -2.5 a 0.50005,0.50005 0 1 0 0,1 h 2.91992 a 0.50005,0.50005 0 0 0 0.16211,0 h 0.83789 a 0.50005,0.50005 0 0 0 0.16211,0 H 457.5 a 0.50005,0.50005 0 1 0 0,-1 H 455 v -2 z m -5.5,-11 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 8 h -12 z"
- inkscape:connector-curvature="0" />
- </g>
- <g
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g16437"
- transform="matrix(-1,0,0,1,1460,227.99979)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 520,349 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -4.50391,1.05078 c -0.16882,0.001 -0.32263,0.0972 -0.39843,0.24805 l -2.75,5.5 c -0.15067,0.29943 0.0671,0.65258 0.40234,0.65234 h 5.75 c 0.34173,-2.4e-4 0.55851,-0.36622 0.39453,-0.66601 l -3,-5.5 c -0.0795,-0.14558 -0.23258,-0.23538 -0.39844,-0.23438 z"
- transform="matrix(-1,0,0,1,1175,-705.99979)"
- id="path16433"
- inkscape:connector-curvature="0" />
- </g>
+ id="g158071"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-21">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 439,201 c -1.59692,0 -2.85915,0.78757 -3.86133,1.88086 -1.00218,1.09329 -1.79297,2.49805 -2.57422,3.87305 -0.78125,1.375 -1.55296,2.72024 -2.4414,3.68945 C 429.2346,211.41257 428.27808,212 427,212 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 1.59692,0 2.85915,-0.78757 3.86133,-1.88086 1.00218,-1.09329 1.79297,-2.49805 2.57422,-3.87305 0.78125,-1.375 1.55296,-2.72024 2.4414,-3.68945 C 436.7654,202.58743 437.72192,202 439,202 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14305"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-189,-42.000004)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g17809-9">
- <g
- id="g17552-8"
- transform="matrix(-1,0,0,1,508.00011,-7e-5)"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 201.49219,94.998047 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.006,0.0059 l -3.95118,3.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707031 L 201,96.712891 v 8.792969 a 0.50005,0.50005 0 1 0 1,0 v -8.792969 l 3.14648,3.146484 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.95508,-3.955078 a 0.50005,0.50005 0 0 0 -0.40625,-0.199219 z"
- id="path14327-2"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 195.49219,104.99219 A 0.50005,0.50005 0 0 0 195,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="rect17542-1"
- inkscape:connector-curvature="0" />
- </g>
- <g
- id="g17548-0"
- transform="matrix(-1,0,0,1,508.00011,-7e-5)"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 222.49219,95.005859 A 0.50005,0.50005 0 0 0 222,95.511719 v 8.792971 l -3.14648,-3.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70703 l 3.95704,3.95704 a 0.50005,0.50005 0 0 0 0.79296,0.002 0.50005,0.50005 0 0 0 0.004,-0.006 l 3.95313,-3.95313 a 0.50005,0.50005 0 1 0 -0.70704,-0.70703 L 223,104.30469 v -8.792971 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
- id="path14329-2"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 216.49219,104.99219 A 0.50005,0.50005 0 0 0 216,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path17546-9"
- inkscape:connector-curvature="0" />
- </g>
+ id="g158086"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-20">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 418.5,201 c -3.54784,0 -5.96871,1.87772 -7.79883,4.18945 -1.7781,2.24603 -3.06678,4.88493 -4.4707,6.81055 H 405.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.40039,-0.19922 c 1.548,-2.064 2.85356,-4.80197 4.58594,-6.99023 C 413.21871,203.62228 415.29784,202 418.5,202 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14049"
+ inkscape:connector-curvature="0" />
</g>
<g
- id="g6601"
- style="fill:#ffffff">
+ id="g158083"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-19">
<path
- style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 61.503909,123 c 0,3.59202 -2.911894,6.50391 -6.503906,6.50391 -3.592012,0 -6.503906,-2.91189 -6.503906,-6.50391 0,-3.59201 2.911894,-6.5039 6.503906,-6.5039 3.592012,0 6.503906,2.91189 6.503906,6.5039 z"
- id="path6589"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 396.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 389.78129,210.37772 387.70216,212 384.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 397.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14011-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g158080"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-18">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 54.999998,115.99609 c -3.862225,0 -7.003902,3.14168 -7.003906,7.00391 -2e-6,3.86223 3.141676,7.00391 7.003906,7.00391 3.86223,0 7.003908,-3.14168 7.003906,-7.00391 -4e-6,-3.86223 -3.141681,-7.00391 -7.003906,-7.00391 z m 0,1 c 3.321786,0 6.003903,2.68212 6.003906,6.00391 2e-6,3.32179 -2.682117,6.00391 -6.003906,6.00391 -3.321789,0 -6.003908,-2.68212 -6.003906,-6.00391 3e-6,-3.32179 2.68212,-6.00391 6.003906,-6.00391 z"
- id="path10735"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 375.5,201 a 0.50005,0.50005 0 0 0 -0.47852,0.35547 c -0.97912,3.26329 -1.65795,6.01658 -2.41406,7.89453 -0.37805,0.93897 -0.77714,1.65307 -1.20117,2.10156 C 370.98222,211.80006 370.56872,212 370,212 c -0.81989,0 -1.77194,-0.85368 -2.74219,-1.84961 -0.48512,-0.49796 -0.97309,-1.01146 -1.49609,-1.41992 C 365.23871,208.32201 364.66174,208 364,208 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 0.32338,0 0.70916,0.17799 1.14648,0.51953 0.43732,0.34154 0.9074,0.82804 1.39649,1.33008 C 367.52115,211.85368 368.58382,213 370,213 c 0.83577,0 1.56694,-0.36242 2.13281,-0.96094 0.56587,-0.59851 1.00027,-1.41738 1.40235,-2.41601 0.7683,-1.90825 1.43134,-4.57357 2.33398,-7.62305 H 376.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path16580-7"
inkscape:connector-curvature="0" />
</g>
<g
- id="g8734"
- transform="translate(231.99999,-418.99995)"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g158077"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 158.48048,492.99995 c -0.15153,0.004 -0.29304,0.0766 -0.38477,0.19727 l -4.94922,4.94921 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.5 h 5 v 12 h -10 v -6 h -1 v 6.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -6 c -0.005,-6e-5 -0.009,-6e-5 -0.0137,0 -6.7e-4,2e-5 -0.001,-2e-5 -0.002,0 -0.001,4e-5 -0.003,-5e-5 -0.004,0 z"
- id="path8730"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.45117,201 a 0.50059574,0.50059574 0 0 0 0.0488,1 c 0.0215,2e-5 0.18225,-1.7e-4 0.33398,0 0.0105,0.42607 0.0502,2.52232 0.33594,5.05664 0.15671,1.39002 0.37504,2.78188 0.69727,3.86719 0.16111,0.54265 0.34457,1.00922 0.59179,1.38086 0.24723,0.37163 0.61429,0.69531 1.09375,0.69531 0.39174,0 0.74881,-0.20864 0.97657,-0.48047 0.22775,-0.27182 0.37091,-0.59987 0.48632,-0.96289 0.23084,-0.72603 0.34622,-1.61436 0.46876,-2.48828 0.12253,-0.87392 0.25275,-1.73314 0.44921,-2.31641 0.0982,-0.29163 0.21467,-0.50852 0.31446,-0.62109 C 348.34784,206.01829 348.39286,206 348.5,206 c 0.16824,0 0.2932,0.0848 0.48633,0.39062 0.19312,0.30582 0.37727,0.78401 0.5625,1.28321 0.18523,0.49919 0.37171,1.01992 0.64453,1.46289 0.27281,0.44297 0.71019,0.86328 1.30664,0.86328 0.41993,0 0.77613,-0.23568 0.99219,-0.49219 0.21606,-0.2565 0.34747,-0.53797 0.4707,-0.78906 0.12323,-0.25109 0.23849,-0.47074 0.33594,-0.58984 C 353.39628,208.0098 353.41651,208 353.5,208 c 0.0859,0 0.18647,0.0811 0.39844,0.32617 0.10598,0.12255 0.22449,0.26923 0.39453,0.40625 C 354.463,208.86945 354.71104,209 355,209 c 0.008,0 0.14542,-2.8e-4 0.27539,0 0.065,1.4e-4 0.13031,6e-5 0.18164,0 0.0513,-6e-5 0.0312,0.005 0.12109,0 a 0.50080138,0.50080138 0 1 0 -0.0566,-1 c 0.0748,-0.004 -0.0172,-5e-5 -0.0664,0 -0.0492,5e-5 -0.11331,1.4e-4 -0.17774,0 -0.12885,-2.8e-4 -0.25041,0 -0.27734,0 -0.0108,0 -0.0173,0.004 -0.0801,-0.0469 -0.0628,-0.0506 -0.15527,-0.15364 -0.26562,-0.28124 C 354.43358,207.41667 354.08387,207 353.5,207 c -0.4167,0 -0.76719,0.23824 -0.97656,0.49414 -0.20937,0.2559 -0.33683,0.53625 -0.45899,0.78516 -0.12215,0.24891 -0.23808,0.46744 -0.33789,0.58593 C 351.62675,208.98373 351.59835,209 351.5,209 c -0.14972,0 -0.26794,-0.0816 -0.45703,-0.38867 -0.18909,-0.30703 -0.37082,-0.78435 -0.55664,-1.28516 -0.18583,-0.5008 -0.37575,-1.02457 -0.65625,-1.46875 C 349.54958,205.41324 349.10136,205 348.5,205 c -0.39664,0 -0.76041,0.19848 -1,0.46875 -0.23959,0.27027 -0.39279,0.60017 -0.51562,0.96484 -0.24567,0.72934 -0.36739,1.61988 -0.49024,2.4961 -0.12285,0.87621 -0.24515,1.73764 -0.43164,2.32422 -0.0933,0.29328 -0.20581,0.51202 -0.29883,0.62304 -0.093,0.11102 -0.1237,0.12305 -0.21094,0.12305 -0.027,0 -0.10877,-0.0201 -0.26171,-0.25 -0.15295,-0.22991 -0.31979,-0.62276 -0.46485,-1.11133 -0.29011,-0.97714 -0.5088,-2.33541 -0.66211,-3.69531 -0.30662,-2.7198 -0.36328,-5.45313 -0.36328,-5.45313 a 0.50005,0.50005 0 0 0 -0.5,-0.49023 c -0.0468,0 -0.74734,5e-5 -0.80078,0 a 0.50005,0.50005 0 0 0 -0.0488,0 z"
+ id="path16468-1"
+ inkscape:connector-curvature="0" />
</g>
- <path
- id="path20685"
- d="m 447.49219,73.99409 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 V 87.49409 c -0.005,0.338081 0.24757,0.509435 0.5,0.507812 l 0.5,-0.0039 v -1.996094 h 2 v 1.996094 h 8 v -1.996094 h 2 v 1.996094 h 0.5 c 0.25244,0 0.50478,-0.169732 0.5,-0.507812 V 74.501902 c 0.005,-0.338081 -0.24762,-0.509415 -0.5,-0.507812 l -0.5,0.0039 v 2.003906 h -2 V 73.99799 h -8 v 2.003906 h -2 V 73.99799 Z M 448,77.001902 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -5.52344,1.003906 c 0.1005,-0.004 0.20016,0.02317 0.28516,0.07617 l 4,2.5 c 0.3129,0.1959 0.3129,0.651757 0,0.847657 l -4,2.5 c -0.3331,0.2087 -0.76573,-0.03073 -0.76563,-0.423829 v -5 c -2e-4,-0.2687 0.21197,-0.489 0.48047,-0.5 z M 448,80.001902 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -10,3 h 2 v 1.992188 h -2 z m 10,0 h 2 v 1.992188 h -2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g18316"
- transform="translate(21,-62.999962)">
+ id="g158074"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-16">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 496,305 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
- id="circle17690"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 321.5,201 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 0.11714,0 0.21825,0.0354 0.36133,0.1582 0.14308,0.12279 0.30922,0.33684 0.46875,0.63282 0.31905,0.59195 0.61443,1.49542 0.87109,2.55468 0.51334,2.11854 0.89163,4.86411 1.30664,7.24024 a 0.50005,0.50005 0 0 0 0.98242,0.008 c 0.24141,-1.26736 0.60565,-2.19557 0.98829,-2.76953 0.38264,-0.57396 0.74023,-0.76172 1.02148,-0.76172 0.28125,0 0.63884,0.18776 1.02148,0.76172 0.38264,0.57396 0.74688,1.50217 0.98829,2.76953 a 0.50005,0.50005 0 0 0 0.96093,0.0762 c 0.24086,-0.66235 0.48023,-1.14224 0.6836,-1.42187 0.20337,-0.27964 0.32487,-0.31055 0.3457,-0.31055 0.0208,0 0.14233,0.0309 0.3457,0.31055 0.20337,0.27963 0.44274,0.75952 0.6836,1.42187 A 0.50005,0.50005 0 0 0 333.5,213 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -0.69141 c -0.20925,-0.52074 -0.41629,-1.01454 -0.65429,-1.3418 -0.29663,-0.40786 -0.67513,-0.7207 -1.1543,-0.7207 -0.47917,0 -0.85767,0.31284 -1.1543,0.7207 -0.10194,0.14017 -0.18655,0.39972 -0.28125,0.57422 -0.21984,-0.70238 -0.40285,-1.50076 -0.71093,-1.96289 -0.49236,-0.73854 -1.13477,-1.20703 -1.85352,-1.20703 -0.71875,0 -1.36116,0.46849 -1.85352,1.20703 -0.20879,0.3132 -0.31334,0.90706 -0.48242,1.33008 -0.30463,-1.87209 -0.5915,-3.83467 -0.99218,-5.48828 -0.26658,-1.10016 -0.56623,-2.0626 -0.96094,-2.79492 -0.19736,-0.36617 -0.41893,-0.67716 -0.69727,-0.91602 C 322.73533,201.16153 322.38008,201 322,201 Z"
+ id="path53380-0"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g158068"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 496.49219,306.99219 A 0.50005,0.50005 0 0 0 496,307.5 v 5 a 0.50005,0.50005 0 0 0 0.22266,0.41602 l 3,2 a 0.50005,0.50005 0 1 0 0.55468,-0.83204 L 497,312.23242 V 307.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path17692"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 312.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,3.43021 -1.19149,5.7903 -3.2168,7.45898 -2.0253,1.66869 -4.93239,2.63003 -8.34375,3.04493 a 0.50005,0.50005 0 1 0 0.1211,0.99218 c 3.52614,-0.42885 6.61905,-1.41978 8.85937,-3.26562 2.13154,-1.75622 3.41037,-4.32825 3.5332,-7.73047 H 313.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14278"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g158065"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-14">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 491.5,312 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path17694"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 291.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,2.47889 -0.15954,4.38104 -0.52734,5.8125 -0.36781,1.43146 -0.92559,2.38009 -1.74024,3.05273 C 287.10312,211.71053 284.21571,212 279.5,212 a 0.50005,0.50005 0 1 0 0,1 c 4.75093,0 7.86511,-0.21053 9.86914,-1.86523 1.00202,-0.82736 1.66924,-2.00373 2.07227,-3.57227 0.36978,-1.43916 0.48747,-3.33151 0.51171,-5.5625 H 292.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14276"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14249"
+ inkscape:label="J-13">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 270.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 c 0,3.44341 -1.07548,6.03173 -3.02344,7.79102 C 265.02861,211.0503 262.16329,212 258.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.83671,0 6.97139,-1.00062 9.14844,-2.9668 2.06597,-1.86586 3.15029,-4.63736 3.26367,-8.0332 H 271.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14273"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 492.74414,308.24414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 1.75,1.75 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.75,-1.75 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path17696"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 258.5,199.99609 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 202.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 c 0.41667,0 1,0.45 1,1.5 0,1.04998 -0.58056,1.4941 -1.00195,1.49609 -0.52634,0.003 -0.86013,-0.33871 -1.05078,-0.72265 a 0.50005,0.50005 0 1 0 -0.89454,0.44531 c 0.30945,0.62316 0.97566,1.28254 1.94922,1.27734 C 261.08054,206.99099 262,205.95002 262,204.5 c 0,-1.45 -0.91667,-2.5 -2,-2.5 h -1 v -1.00391 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14399"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g18539-5"
- transform="translate(-699.95,-1104.9501)">
+ id="g14245"
+ inkscape:label="J-12">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1240.9492,1334.9492 v 5 h 4 v -5 z"
- id="path18533-4"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 249.5,201 a 0.50005,0.50005 0 0 0 -0.49805,0.45508 c -0.24047,2.64524 -1.32572,5.28945 -3.23633,7.25976 C 243.85502,210.68516 241.12778,212 237.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.87222,0 6.89498,-1.43516 8.98438,-3.58984 1.97612,-2.03788 3.06007,-4.712 3.39843,-7.41016 H 250.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14271"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 238.4668,199.99414 c -0.21842,0.0156 -0.40126,0.17156 -0.45118,0.38477 l -1,4 c -0.0786,0.31522 0.15949,0.62057 0.48438,0.62109 h 2.5 v 1.5 c -0.01,0.67616 1.00956,0.67616 1,0 v -4 c -0.009,-0.6573 -0.9907,-0.6573 -1,0 v 1.5 h -1.85938 l 0.84376,-3.37891 c 0.0877,-0.33109 -0.17587,-0.65038 -0.51758,-0.62695 z"
+ id="path14402"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccc" />
+ sodipodi:nodetypes="ccccccccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14241"
+ inkscape:label="J-11">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1236.6992,1327.9531 v 1 h 2.25 c 0.4241,0 0.7403,0.2467 0.8828,0.5762 0.1425,0.3295 0.1253,0.7107 -0.2422,1.0781 l -4,4 c -0.6325,0.6326 -0.7433,1.5055 -0.4492,2.1778 0.2941,0.6722 0.9778,1.1757 1.8028,1.1757 l 3.0059,-0.012 v -1 l -3.0058,0.012 c -0.425,0 -0.7434,-0.2484 -0.8868,-0.5761 -0.1434,-0.3278 -0.1271,-0.7029 0.2403,-1.0703 l 4,-4 c 0.6326,-0.6326 0.7446,-1.5077 0.4531,-2.1817 -0.2915,-0.674 -0.9748,-1.1797 -1.8008,-1.1797 z"
- id="path18537-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 228.5,201 a 0.50005,0.50005 0 0 0 -0.47461,0.3418 c -0.75176,2.25527 -1.61792,4.94183 -3.29101,7.0332 -1.6731,2.09137 -4.11183,3.625 -8.23438,3.625 a 0.50005,0.50005 0 1 0 0,1 c 4.37745,0 7.18872,-1.71637 9.01562,-4 1.74159,-2.17699 2.6089,-4.81175 3.33594,-7 H 229.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14266"
inkscape:connector-curvature="0" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1233.4531,1325.9492 c -0.191,0 -0.3661,0.1064 -0.4511,0.2774 l -2,4 c -0.1651,0.3322 0.076,0.7222 0.4472,0.7226 h 4 c 0.371,-4e-4 0.6124,-0.3904 0.4473,-0.7226 l -2,-4 c -0.084,-0.1686 -0.2552,-0.2758 -0.4434,-0.2774 z"
- id="path18541-3"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
+ d="m 218.99805,199.99609 c -0.79172,0 -1.70536,0.42738 -1.98047,1.35938 a 0.50005,0.50005 0 1 0 0.95898,0.2832 c 0.12417,-0.42064 0.57962,-0.64258 1.02149,-0.64258 0.26387,0 0.51715,0.0894 0.69531,0.24805 0.17816,0.15864 0.30325,0.37905 0.30664,0.75586 0.001,0.39768 -0.25396,0.75725 -0.76367,1.07422 a 0.50005,0.50005 0 0 0 0,0.84766 c 0.51034,0.31737 0.7656,0.67798 0.76367,1.07617 -0.004,0.37528 -0.12888,0.59561 -0.30664,0.7539 -0.17816,0.15864 -0.43144,0.24805 -0.69531,0.24805 -0.44187,0 -0.89732,-0.21999 -1.02149,-0.64062 a 0.50005,0.50005 0 1 0 -0.95898,0.28124 c 0.27511,0.93201 1.18875,1.35938 1.98047,1.35938 0.48612,0 0.97796,-0.16058 1.36133,-0.50195 0.38336,-0.34137 0.63501,-0.871 0.64062,-1.49414 a 0.50005,0.50005 0 0 0 0,-0.002 c 0.003,-0.61795 -0.34308,-1.09989 -0.77734,-1.5039 0.43425,-0.40402 0.78027,-0.88601 0.77734,-1.50391 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.62314 -0.25726,-1.15277 -0.64062,-1.49414 -0.38337,-0.34137 -0.87521,-0.50196 -1.36133,-0.50196 z"
+ id="path14395"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="matrix(-1,0,0,1,1727,-80)"
- id="g17779"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14237"
+ inkscape:label="J-10">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1455.5,512 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 2 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -2 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m 0.5,4 v 6.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 516 Z m 4,1 h 2 c 1.3523,-0.0191 1.3523,2.01913 0,2 h -2 c -1.3523,0.0191 -1.3523,-2.01913 0,-2 z"
- id="path17776"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cssccsscccsccsccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 207.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 200.78129,210.37772 198.70216,212 195.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 208.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14262"
+ inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1468,514 v 0.5 c 0,0.62337 -0.4468,1.06807 -1,1.28906 V 516 v 1 h 1.5 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -2 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m -1,4 v 4.5 c 0,0.8167 -0.6835,1.49991 -1.5,1.5 h -7.5 v 0.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 518 Z"
- id="path17787"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="csccccsscccsccsccscc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 197,199.99609 c -0.79172,0 -1.70536,0.42738 -1.98047,1.35938 a 0.50090117,0.50090117 0 1 0 0.96094,0.2832 c 0.12417,-0.42064 0.57767,-0.64258 1.01953,-0.64258 0.26308,0 0.50603,0.0889 0.67773,0.2461 0.17133,0.15683 0.29488,0.38005 0.29883,0.75976 0.001,0.2095 -0.10056,0.41777 -0.33789,0.6875 -0.23733,0.26973 -0.59584,0.56699 -0.97656,0.90235 -0.76143,0.67072 -1.65792,1.5571 -1.66211,2.90234 a 0.50005,0.50005 0 0 0 0.5,0.50195 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -2.33398 c 0.18416,-0.62502 0.58645,-1.15066 1.1582,-1.65429 0.36326,-0.31999 0.74752,-0.62977 1.0664,-0.99219 0.31889,-0.36243 0.58851,-0.81103 0.58594,-1.35156 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.61869 -0.24656,-1.14755 -0.62304,-1.49218 -0.37648,-0.34464 -0.8666,-0.50782 -1.35352,-0.50782 z"
+ id="path12457-3"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1.8554137e-6,5.18e-5)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13451"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- id="g23046"
- style="opacity:1;fill:#ffffff">
- <path
- style="opacity:0.98999999;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
- d="m 16.501953,536 c -1.926262,0 -3.498047,1.57178 -3.498047,3.49805 0,1.92626 1.571785,3.49804 3.498047,3.49804 C 18.428216,542.99609 20,541.42431 20,539.49805 20,537.57178 18.428216,536 16.501953,536 Z m 0,0.99609 a 0.50005,0.50005 0 1 1 0,1 C 15.666793,537.99609 15,538.66288 15,539.49805 a 0.50005,0.50005 0 1 1 -1,0 c 0,-1.37561 1.126353,-2.50196 2.501953,-2.50196 z"
- transform="translate(1.8554137e-6,-5.18e-5)"
- id="circle12697"
- inkscape:connector-curvature="0" />
- </g>
+ id="g14233"
+ inkscape:label="J-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 10.503906,539.99219 a 0.50005,0.50005 0 0 0 -0.492187,0.39843 L 9.6542969,542 H 7.5 a 0.50005,0.50005 0 1 0 0,1 H 9.4316406 L 8.765625,546 H 6.5 a 0.50005,0.50005 0 1 0 0,1 h 2.0429688 l -0.53125,2.39062 a 0.50038237,0.50038237 0 1 0 0.9765624,0.21876 L 9.5683594,547 H 16.53125 l 0.476562,2.58984 a 0.50032015,0.50032015 0 1 0 0.984376,-0.17968 L 17.546875,547 H 19.5 a 0.50005,0.50005 0 1 0 0,-1 H 17.363281 L 17.0625,544.37109 a 0.50005,0.50005 0 1 0 -0.982422,0.18164 L 16.345703,546 H 9.7910156 l 0.6660154,-3 H 12.5 a 0.50005,0.50005 0 1 0 0,-1 h -1.820312 l 0.308593,-1.39062 a 0.50005,0.50005 0 0 0 -0.484375,-0.61719 z"
- id="path8399"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 186.5,201 a 0.50005,0.50005 0 0 0 -0.40039,0.19922 c -1.548,2.064 -2.85356,4.80197 -4.58594,6.99023 C 179.78129,210.37772 177.70216,212 174.5,212 a 0.50005,0.50005 0 1 0 0,1 c 3.54784,0 5.96871,-1.87772 7.79883,-4.18945 1.7781,-2.24603 3.06678,-4.88493 4.4707,-6.81055 H 187.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14011"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 176.48438,199.99609 a 0.50005,0.50005 0 0 0 -0.3379,0.14649 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70703 L 176,201.70312 V 206.5 a 0.50005,0.50005 0 1 0 1,0 v -6.00391 a 0.50005,0.50005 0 0 0 -0.51562,-0.5 z"
+ id="path12461-0"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g13993"
- transform="translate(-21.000002,-20.999948)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g13432"
+ inkscape:label="J-8">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 132.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 1 0 -1,0 v 7.5 h -12 v -12 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path13936"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 166,201 c -1.59692,0 -2.85915,0.78757 -3.86133,1.88086 -1.00218,1.09329 -1.79297,2.49805 -2.57422,3.87305 -0.78125,1.375 -1.55296,2.72024 -2.4414,3.68945 C 156.2346,211.41257 155.27808,212 154,212 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 c 1.59692,0 2.85915,-0.78757 3.86133,-1.88086 1.00218,-1.09329 1.79297,-2.49805 2.57422,-3.87305 0.78125,-1.375 1.55296,-2.72024 2.4414,-3.68945 C 163.7654,202.58743 164.72192,202 166,202 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14036"
inkscape:connector-curvature="0" />
<path
- sodipodi:nodetypes="ccsssssssssssssccc"
- inkscape:connector-curvature="0"
- id="path12191-1"
- d="m 136.5,557 c -0.25,0 -0.5,0.25 -0.5,0.5 v 5.5 c 0,0.5 0.25,1 1,1 0.75,0 1,-0.5 1,-1 v -1 c 0,-0.5 0.53412,-1 1,-1 0.55229,0 1,0.44772 1,1 v 3.5 c 0,0.82843 0.67157,1.5 1.5,1.5 0.82843,0 1.5,-0.67157 1.5,-1.5 V 562 c 0,-0.55228 0.44772,-1 1,-1 h 0.5 c 0.85547,0 1.5,-0.66406 1.5,-1.5 v -2 c 0,-0.25 -0.25,-0.5 -0.5,-0.5 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 154.5,200 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 202 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 H 157 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 0.41992 a 0.50005,0.50005 0 0 0 0,0.16211 V 202 h -1 z m 8.50781,10 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 v -0.42383 a 0.50005,0.50005 0 0 0 0,-0.15234 z"
+ id="path14257"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(-1141.0001,-747.9999)"
- id="g17971-7">
- <g
- style="fill:#ffffff"
- transform="translate(62,59)"
- id="g17967-7">
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1085.5,1514 c -0.2761,0 -0.5,0.2239 -0.5,0.5 v 13 c 0,0.2761 0.2239,0.5 0.5,0.5 h 0.5 v -2 h 1 v 2 h 9.5 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -13 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 h -9.5 v 2 h -1 v -2 z m 3.5,2 h 6 v 1 h -6 z m -3,1 h 1 v 2 h -1 z m 3,1 h 6 v 1 h -6 z m -3,2 h 1 v 2 h -1 z m 3,0 h 6 v 1 h -6 z m 0,2 h 4 v 1 h -4 z m -3,1 h 1 v 2 h -1 z"
- transform="translate(169,-289)"
- id="path17960-2" />
- </g>
+ id="g158062"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-7">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 144.5,201 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 133.29297,212 H 132.5 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 L 144.70703,202 H 145.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path13875"
+ inkscape:connector-curvature="0" />
</g>
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 134.49999,536.00009 c -1.3764,0 -2.5,1.1236 -2.5,2.5 v 7 c 0,1.3764 1.1236,2.5 2.5,2.5 h 0.5 v 2.5 c -8e-4,0.4686 0.5855,0.6809 0.8848,0.3203 l 2.3496,-2.8203 h 5.2656 c 1.3764,0 2.5,-1.1236 2.5,-2.5 v -7 c 0,-1.3764 -1.1236,-2.5 -2.5,-2.5 z m 3.5,2 h 2 v 2 h -2 z m -1,3 h 3 v 4 h 1 v 1 h -4 v -1 h 1 v -3 h -1 z"
- id="path17991-2" />
<g
- transform="matrix(1,0,0,-1,-167.9929,1043.9931)"
- id="g17666-2"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- transform="rotate(90,475.00001,500.9999)"
- inkscape:transform-center-y="9.9999999e-006"
- inkscape:transform-center-x="-1.2499"
- id="g17664-3"
- style="fill:#ffffff" />
+ id="g158059"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-6">
<path
- inkscape:connector-curvature="0"
- id="path17674"
- d="m 475.00071,508.00091 c -3.8601,0 -7,-3.1399 -7,-7 0,-3.8601 3.1399,-7 7,-7 3.8601,0 7,3.1399 7,7 0,3.8601 -3.1399,7 -7,7 z m 2.96094,-1.99804 a 1.0001,1.0001 0 0 0 1.04102,-0.98633 1.0001,1.0001 0 0 0 -0.20899,-0.62305 l -2.57617,-3.43555 1.60742,-2.41015 a 1.0001,1.0001 0 1 0 -1.66406,-1.10938 l -1.91211,2.86914 a 1.0001,1.0001 0 0 0 -0.26367,0.68164 1.0001,1.0001 0 0 0 0.004,0.0801 1.0001,1.0001 0 0 0 0.30664,0.66016 l 2.89844,3.86328 a 1.0001,1.0001 0 0 0 0.76758,0.41016 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 118.5,201 a 0.50005,0.50005 0 0 0 -0.5,0.5 V 212 h -6.5 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 202 h 5.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path13715"
+ inkscape:connector-curvature="0" />
</g>
<g
- id="g17058"
- transform="translate(-20.839982,-20.882701)"
- style="display:inline;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13322"
+ transform="translate(-1.85367e-6,21)"
+ inkscape:label="J-5">
<g
- id="g7978">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.928338;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 373.21906,563.36205 c -2.04533,0 -3.71335,1.66802 -3.71335,3.71335 0,2.04534 1.66802,3.71336 3.71335,3.71336 2.04534,0 3.71336,-1.66802 3.71336,-3.71336 0,-2.04533 -1.66802,-3.71335 -3.71336,-3.71335 z"
- id="path7726"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:922.783;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 364.3828,556.88974 c -0.8999,0 -1.63379,0.73389 -1.63379,1.6338 0,0.89988 0.73389,1.6338 1.63379,1.6338 0.89991,0 1.6338,-0.7339 1.6338,-1.6338 0,-0.8999 -0.73389,-1.6338 -1.6338,-1.6338 z"
- id="path7808"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:922.783;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 366.50464,561.82783 c -1.31395,0 -2.38552,1.07155 -2.38552,2.3855 0,1.31395 1.07157,2.38555 2.38552,2.38555 1.31396,0 2.38553,-1.07158 2.38553,-2.38555 0,-1.31395 -1.07157,-2.3855 -2.38553,-2.3855 z"
- id="path7890"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1881.46;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 368.88012,557.69285 c -1.06196,0 -1.928,0.86602 -1.928,1.92801 0,1.06192 0.86604,1.92798 1.928,1.92798 1.06195,0 1.92801,-0.86606 1.92801,-1.92798 0,-1.06195 -0.86606,-1.92801 -1.92801,-1.92801 z"
- id="path7972"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="g14281"
+ transform="translate(84,200)"
+ style="opacity:0.6;fill:#ffffff">
+ <g
+ transform="matrix(1,0,0,-1,-294,368)"
+ id="g14276"
+ style="opacity:1;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 9 v 2 h -9 z"
+ id="path14272"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 304.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 8 v 2 h -8 z"
+ id="path14274"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 93.5,179 c -0.412872,-7.2e-4 -0.648693,0.47092 -0.400391,0.80078 l 3,4 c 0.2,0.26732 0.600782,0.26732 0.800782,0 l 3,-4 C 100.14869,179.47092 99.912872,178.99928 99.5,179 Z"
+ id="path14203-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
</g>
<g
- id="g7662"
- style="fill:#ffffff"
- transform="matrix(1,0,0,-1,0,1085.9844)">
+ id="g158089"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-4">
<path
+ id="path9205"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 75.50586,203 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z M 71,203 v 8 h 2 v -8 z"
inkscape:connector-curvature="0"
- id="path17742-5"
- d="m 468.50781,535.99219 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 5.00586 l -1,-0.006 v 2 l 1,0.006 V 546 h -1.00586 l 0.006,-2.00781 h -2 L 478.00195,546 h -2 l 0.006,-2.00781 h -2 L 474.00195,546 h -2 l 0.006,-2.00781 h -2 L 470.00195,546 h -0.99414 v -2.00391 l 1,-0.006 v -2 l -1,0.006 z m 3,7 h 2 v -2 h -2 z m 4,0 h 2 v -2 h -2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
- <path
- id="path17758-8"
- d="m 470.00781,539.99219 v 2 h 2 v -2 z m 4,0 v 2 h 2 v -2 z m 4,0 v 2 h 2 v -2 z"
- style="display:inline;opacity:0.8;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- inkscape:connector-curvature="0" />
+ sodipodi:nodetypes="cccccccccccccc" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g15578-7"
- transform="matrix(1,0,0,-1,894.00002,921)">
+ id="g158092"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-3">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -467.5,287 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 10 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.5 v -1 h -2 v -9 h 9 v 2 h 1 v -2.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path15572-4"
+ d="m 55.49414,203 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z m 4.507668,0 v 8 h -2 v -8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path9208"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccc" />
+ </g>
+ <g
+ id="g158053"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -463.50002,301 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -9 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 9 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 4.5 h -1 v -4 h -8 v 8 h 5 v -2.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 2.5 1 v 0.5 c -2e-5,0.1326 -0.0527,0.25972 -0.14648,0.35352 l -3,3 c -0.0938,0.0938 -0.22092,0.14646 -0.35352,0.14648 z"
- id="path15574-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 33.75,200 c -0.212514,-4.2e-4 -0.402079,0.13353 -0.472656,0.33398 L 31.644531,205 H 27.5 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 0.75 c 4.22e-4,0.17006 0.08724,0.32824 0.230469,0.41992 l 3.166015,2.03711 -1.367187,3.87695 c -0.01909,0.0533 -0.029,0.10942 -0.0293,0.16602 v 0.75 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 0.75 c 0.119714,-2e-5 0.235448,-0.043 0.326172,-0.12109 L 33.935547,211 h 0.128906 l 3.359375,2.87891 c 0.09174,0.079 0.209022,0.12201 0.330078,0.12109 L 38.5,213.99414 c 0.273087,-0.002 0.49394,-0.223 0.496094,-0.49609 L 39,212.75195 c -7.9e-5,-0.0572 -0.01,-0.11407 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 C 40.912757,206.57824 40.999577,206.42006 41,206.25 v -0.75 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -4.144531 l -1.632813,-4.66602 C 34.652079,200.13353 34.462514,199.99958 34.25,200 h -0.251953 z"
+ id="path14398"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccsccc" />
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccc" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g18361">
+ id="g158056"
+ style="display:inline;enable-background:new"
+ inkscape:label="J-1">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 447.49414,577.99023 a 0.50005,0.50005 0 0 0 -0.49219,0.50782 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.6875 c 1.48423,-2.56389 4.60739,-3.65907 7.36719,-2.58008 2.762,1.07985 4.31643,4.00744 3.66406,6.90039 -0.65237,2.89295 -3.31139,4.87021 -6.26953,4.66016 -2.95814,-0.21006 -5.31375,-2.5439 -5.55078,-5.5 a 0.50005,0.50005 0 1 0 -0.99609,0.0801 c 0.27595,3.44157 3.03067,6.17147 6.47461,6.41602 3.44393,0.24455 6.55885,-2.06751 7.31836,-5.43555 0.7595,-3.36803 -1.05982,-6.79554 -4.27539,-8.05273 -0.8039,-0.3143 -1.63664,-0.46878 -2.45899,-0.47852 -2.43307,-0.0288 -4.77966,1.22272 -6.08594,3.40821 v -2.91797 a 0.50005,0.50005 0 0 0 -0.50781,-0.50782 z m 8.98828,3.00391 a 0.50005,0.50005 0 0 0 -0.38281,0.20508 l -3,4 a 0.50005,0.50005 0 0 0 -0.0156,0.57812 l 2,3 a 0.50005,0.50005 0 1 0 0.83204,-0.55468 l -1.80274,-2.70508 2.78711,-3.7168 a 0.50005,0.50005 0 0 0 0.10352,-0.3125 0.50005,0.50005 0 0 0 -0.52149,-0.49414 z"
- id="path13619"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 12.75,200 a 0.50004997,0.50004997 0 0 0 -0.472656,0.33398 L 10.644531,205 H 6.5 A 0.50004997,0.50004997 0 0 0 6,205.5 v 0.75 a 0.50004997,0.50004997 0 0 0 0.2304688,0.41992 l 3.1660156,2.03711 -1.3671875,3.87695 A 0.50004997,0.50004997 0 0 0 8,212.75 v 0.75 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 0.75 a 0.50004997,0.50004997 0 0 0 0.3261719,-0.12109 L 12.935547,211 h 0.128906 l 3.359375,2.87891 A 0.50004997,0.50004997 0 0 0 16.753906,214 L 17.5,213.99414 a 0.50004997,0.50004997 0 0 0 0.496094,-0.49609 L 18,212.75195 a 0.50004997,0.50004997 0 0 0 -0.0293,-0.16797 l -1.367187,-3.87695 3.166015,-2.03711 A 0.50004997,0.50004997 0 0 0 20,206.25 V 205.5 A 0.50004997,0.50004997 0 0 0 19.5,205 h -4.144531 l -1.632813,-4.66602 A 0.50004997,0.50004997 0 0 0 13.25,200 h -0.251953 z m 0.25,1.30078 1.527344,4.36524 A 0.50004997,0.50004997 0 0 0 15,206 h 3.962891 l -3.232422,2.08008 a 0.50004997,0.50004997 0 0 0 -0.201172,0.58594 L 17,212.83398 l -0.002,0.16407 h -0.06445 l -3.357422,-2.87696 A 0.50004997,0.50004997 0 0 0 13.25,210 h -0.5 a 0.50004997,0.50004997 0 0 0 -0.326172,0.12109 L 9.0644531,213 H 9 v -0.16406 l 1.470703,-4.16992 a 0.50004997,0.50004997 0 0 0 -0.201172,-0.58594 L 7.0371094,206 H 11 a 0.50004997,0.50004997 0 0 0 0.472656,-0.33398 z"
+ id="path14401"
inkscape:connector-curvature="0" />
- <g
- transform="matrix(0,-1,-1,0,954.9999,1060.0001)"
- inkscape:transform-center-y="9.9999999e-006"
- inkscape:transform-center-x="-1.2499"
- id="g16343-6"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new" />
</g>
- <path
- id="path14479-6"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 111.51563,74 c -0.27614,2.8e-5 -0.49998,0.223869 -0.5,0.5 v 12 c 2e-5,0.276131 0.22386,0.499972 0.5,0.5 H 114.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -12 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z M 124,81.000005 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z"
- inkscape:connector-curvature="0" />
<g
- transform="matrix(-1,0,0,1,1689,365.99979)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g8530-0-8"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1258.4766,-286 c -0.1708,0.008 -0.3255,0.10335 -0.4102,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.4336,0.74805 h 8 c 0.3836,-4.7e-4 0.6239,-0.41493 0.4336,-0.74805 l -4,-7 c -0.093,-0.16311 -0.2694,-0.26042 -0.457,-0.25195 z"
- id="path8523-4-0"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
+ id="g6932"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="I-26">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
- id="ellipse8525-5-4"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 543.50781,181.99023 a 1.50015,1.50015 0 0 0 -0.67773,0.16797 c -3.41741,1.7087 -5.83009,5.05846 -5.83008,9.3418 a 1.50015,1.50015 0 1 0 3,0 c -10e-6,-3.21666 1.58731,-5.3669 4.16992,-6.6582 a 1.50015,1.50015 0 0 0 -0.66211,-2.85157 z"
+ id="path7270"
+ inkscape:connector-curvature="0" />
<path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z"
- transform="matrix(-1,0,0,1,1290,-302.99979)"
- id="path8528-7-3" />
- </g>
- <rect
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="rect6696"
- width="0"
- height="0"
- x="-18"
- y="-28" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 180.25977,430.99023 c -1.56005,0 -2.83737,0.68503 -4,1.32227 -0.15986,0.0876 -0.25939,0.25522 -0.25977,0.4375 v 1.75 c -0.002,0.58015 0.81953,0.69801 0.98047,0.14062 0.5477,-1.86218 2.26129,-2.69946 3.87109,-2.56445 0.056,0.003 0.0879,0.0161 0.14258,0.0195 C 182.58833,432.2915 184,433.38188 184,435.75 V 437 h -4.17383 c -1.71873,0 -2.95078,0.48602 -3.73828,1.26172 -0.7875,0.77569 -1.09766,1.80326 -1.09766,2.77539 0,1.37482 0.63393,2.43409 1.58008,3.07031 C 177.51646,444.74365 178.73744,445 180,445 c 1.61266,0 3.42658,-0.64151 4.45508,-1.56836 0.43191,0.42904 0.80166,0.78819 1.11328,1.03906 0.38759,0.31203 0.75096,0.5293 1.18164,0.5293 h 0.75 c 0.31531,0 0.5,-0.25 0.5,-0.5 0,-0.25 -0.16406,-0.5 -0.5,-0.5 -0.0833,0 -0.22505,-0.0571 -0.33398,-0.16602 C 187.05708,443.72508 187,443.58333 187,443.5 v -7 c 0,-1.04167 -0.0843,-2.5 -1.08398,-3.57617 -1.37045,-1.47528 -2.91602,-1.9336 -5.65625,-1.9336 z M 181.5,438 h 2.5 v 4.49023 c -0.8549,0.62028 -1.60427,0.95721 -2.2793,1.14844 -0.1561,0.0477 -0.30873,0.061 -0.46679,0.0977 -0.63626,0.10402 -1.2211,0.10508 -1.65821,-0.0742 C 178.58677,443.24823 178,442.20833 178,441 c 0,-0.63889 0.21654,-1.3962 0.74414,-1.97656 C 179.27174,438.44308 180.11111,438 181.5,438 Z"
- id="path7432"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sccccccscccscscssssscsscsscccccsss" />
- <g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="matrix(0.866668,0,0,0.866668,-9.46699,121.39943)"
- id="g5914"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384436;enable-background:new">
- <g
- id="g5912"
- style="fill:#ffffff;stroke-width:1.15384436">
- <path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
- d="m 202,494 c -3.86008,0 -7,3.13992 -7,7 0,3.86008 3.13992,7 7,7 3.86008,0 7,-3.13992 7,-7 0,-3.86008 -3.13992,-7 -7,-7 z m 0,1 c 3.3058,0 5.97583,2.65852 5.99805,5.95898 C 206.88654,501.90262 204.99536,503 202,503 v 4 c -3.31963,0 -6,-2.68037 -6,-6 0,-0.0145 0.002,-0.0285 0.002,-0.043 1.1112,0.94401 3.00099,2.043 5.998,2.043 z"
- transform="matrix(1.1538444,0,0,1.1538444,10.923433,-140.07605)"
- id="path5908"
- inkscape:connector-curvature="0" />
- </g>
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 536.49609,179.00195 a 0.50005,0.50005 0 0 0 -0.35351,0.12891 c -4.08383,3.59037 -5.14329,7.80863 -5.13086,13.36328 a 0.50005,0.50005 0 1 0 1,-0.002 c -0.0122,-5.43221 0.92902,-9.21403 4.79101,-12.60938 a 0.50005,0.50005 0 0 0 -0.30664,-0.88086 z"
+ id="path7282"
+ inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g5920"
- transform="translate(168,-62.999995)">
+ id="g7347"
+ transform="translate(921,-553)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="I-25">
+ <rect
+ transform="scale(-1,1)"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.8;marker:none;enable-background:accumulate"
+ id="rect7240"
+ width="16"
+ height="16"
+ x="396"
+ y="731" />
<path
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="path5916"
- d="m 49,558 v 3 h 3 v -3 z m 3,3 v 3 h 3 v -3 z m 3,0 h 3 v -3 h -3 z m 3,0 v 3 h 3 v -3 z m 0,3 h -3 v 3 h 3 z m 0,3 v 3 h 3 v -3 z m -3,0 h -3 v 3 h 3 z m -3,0 v -3 h -3 v 3 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -408.50391,736.99414 a 0.50005,0.50005 0 0 0 -0.43554,0.26563 c -1.5311,2.80698 -2.01417,5.0457 -2.02149,8.22461 a 0.50005,0.50005 0 1 0 1,0.004 c 0.007,-3.0834 0.43147,-5.05503 1.90039,-7.74805 a 0.50005,0.50005 0 0 0 -0.44336,-0.74609 z m 6.99805,2 a 0.50005,0.50005 0 0 0 -0.37891,0.18555 C -403.15877,740.70849 -404,742.16634 -404,745.5 a 0.50005,0.50005 0 1 0 1,0 c 0,-3.18014 0.65877,-4.20849 1.88477,-5.67969 a 0.50005,0.50005 0 0 0 -0.39063,-0.82617 z"
+ id="path7245"
inkscape:connector-curvature="0" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -407.5,732 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 7,2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path7250"
inkscape:connector-curvature="0"
- id="path5918"
- d="m 48.5,557 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 61.5,557 Z m 0.5,1 h 12 v 12 H 49 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccccccccccc" />
</g>
<g
- transform="translate(420.00505,-159.00506)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g5937">
+ transform="translate(919,-532)"
+ id="g6686"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="I-24">
+ <rect
+ transform="scale(-1,1)"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.8;marker:none;enable-background:accumulate"
+ id="rect6673"
+ width="16"
+ height="16"
+ x="415"
+ y="710" />
<path
- id="path5935"
- transform="translate(-462.00505,96.005057)"
- d="m 103.49609,556.99023 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.57031,1.57032 c -1.22858,-1.06562 -2.825838,-1.7168 -4.576171,-1.7168 -3.86007,0 -7,3.13993 -7,7 0,1.75033 0.649231,3.34954 1.714844,4.57813 l -1.568359,1.56835 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.568359,-1.56836 c 1.228585,1.06561 2.827793,1.71484 4.578125,1.71484 3.860071,0 7.000001,-3.13993 7.000001,-7 0,-1.75033 -0.65118,-3.34759 -1.7168,-4.57617 l 1.57032,-1.57031 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -6.490231,1.00391 c 3.319631,0 6.000001,2.68037 6.000001,6 0,3.31963 -2.68037,6 -6.000001,6 -3.31963,0 -6,-2.68037 -6,-6 0,-0.88092 0.193846,-1.71405 0.533203,-2.4668 l 0.466797,0.4668 1,1 v 2 h 2 v 1 l 1,1 v 2 h 0.75 1.25 l 1,-1 1.000001,-1 v -1 l -1.000001,-1 h -2 -1 l -1,-1 h -1 l 1,-1 h 1 l 2,-2 -1,-1 h -1 l -1,-1 0.894532,-0.89453 c 0.358617,-0.0666 0.727234,-0.10547 1.105468,-0.10547 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -416.49609,713.99609 a 0.50005,0.50005 0 0 0 -0.31055,0.10938 c -0.21339,0.16596 -0.41872,0.33348 -0.61524,0.50195 -4.0339,3.45843 -4.51787,6.50897 -4.57812,9.88281 a 0.50009544,0.50009544 0 1 0 1,0.0195 c 0.059,-3.3038 0.37586,-5.83955 4.22852,-9.14258 0.1842,-0.15793 0.37703,-0.31626 0.57812,-0.47266 a 0.50005,0.50005 0 0 0 -0.30273,-0.89844 z"
+ id="path6675"
inkscape:connector-curvature="0" />
- </g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 202,556.99628 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 198.00799,558.26759 198,559.00268 198,559.49628 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 199,559.99428 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-10e-6 2.78534,-0.23261 3.38867,-0.75196 C 205.99201,569.73274 206,568.99765 206,568.50405 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 a 0.50005,0.50005 0 0 0 -0.0586,-0.004 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 l 2.49595,-0.004 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 -0.27166,-0.2339 -0.26367,-0.49668 -0.26367,-0.99028 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z"
- id="path12249-6"
- inkscape:connector-curvature="0" />
- <g
- id="g5996"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- transform="matrix(-1,0,0,1,552.8323,1.5e-5)">
<path
+ id="path6688"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -427.5,716 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -2,5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 5,-10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
inkscape:connector-curvature="0"
- id="path5994"
- d="m 310.58203,494 c -1.1875,0 -2.13583,0.69085 -2.52344,1.62109 -0.3876,0.93025 -0.20775,2.10475 0.66993,2.98243 l 2.5,2.5 c 0.62232,0.62232 0.69247,1.32282 0.45507,1.89257 C 311.4462,503.56585 310.89453,504 310.08203,504 l -6.53515,-0.008 2.13867,-2.13867 a 0.50005,0.50005 0 1 0 -0.70703,-0.70704 l -2.9336,2.93555 -0.01,0.008 a 0.50005,0.50005 0 0 0 -0.20704,0.41602 0.50005,0.50005 0 0 0 0,0.008 0.50005,0.50005 0 0 0 0.004,0.0469 0.50005,0.50005 0 0 0 0.008,0.0488 0.50005,0.50005 0 0 0 0.19336,0.29882 l 2.94532,2.94532 a 0.50005,0.50005 0 1 0 0.70703,-0.70704 l -2.1543,-2.15429 6.55078,0.008 c 1.1875,0 2.13584,-0.69085 2.52344,-1.62109 0.3876,-0.93025 0.20775,-2.10475 -0.66992,-2.98243 l -2.5,-2.5 c -0.62233,-0.62232 -0.69248,-1.32282 -0.45508,-1.89257 0.2374,-0.56976 0.78906,-1.00391 1.60156,-1.00391 h 4.75 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="ccccccccccccccccccccccccccc" />
</g>
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 90.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.949219 L 95,504.62695 V 507.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.87305 L 102.55078,498 H 103.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -6 v -0.5 A 0.50005,0.50005 0 0 0 93.5,494 Z m 0.5,1 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -7,1 h 6 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.91406 l -3.214841,6 h -2.398438 l -3.214843,-6 H 93.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 2,9 h 2 v 2 h -2 z"
- id="path6000" />
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 115.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 496 h 0.5 c 1.29307,0 2.42587,0.35206 3.21875,1.00977 C 123.51163,497.66747 124,498.62406 124,500 c 0,1.58333 -0.78109,3.05511 -2.24023,4.16406 C 120.30062,505.27301 118.15909,506 115.5,506 H 115 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -3 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 507 h 0.5 c 2.84091,0 5.19938,-0.77301 6.86523,-2.03906 C 124.03109,503.69489 125,501.91667 125,500 c 0,-1.62406 -0.62718,-2.91747 -1.64258,-3.75977 C 122.34202,495.39794 120.97378,495 119.5,495 H 119 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -4,10 h 2 v 2 h -2 z"
- id="path6006" />
<g
- transform="matrix(-1,0,0,1,1290,764.99979)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g8530-0-8-3"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g5294-1-7-1"
+ transform="translate(42,-357)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="I-23">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1258.4766,-286 c -0.1708,0.008 -0.3255,0.10335 -0.4102,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.4336,0.74805 h 8 c 0.3836,-4.7e-4 0.6239,-0.41493 0.4336,-0.74805 l -4,-7 c -0.093,-0.16311 -0.2694,-0.26042 -0.457,-0.25195 z"
- id="path8523-4-0-3"
+ sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
+ id="path5168-0-2-8"
+ d="m 433,541 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
- id="ellipse8525-5-4-7"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
+ id="path5260-6-8-7"
+ d="m 433.08008,537.98438 c -2.77576,0 -5.01953,2.26323 -5.01953,5.01562 0,2.7524 2.24277,5.02307 5.02148,5.01562 L 439.00195,548 a 1.0001,1.0001 0 1 0 -0.004,-2 l -5.91993,0.0156 c -1.70285,0.005 -3.01757,-1.33278 -3.01757,-3.01562 0,-1.68217 1.31272,-3.01459 3.01757,-3.01562 L 438.99805,540 a 1.0001,1.0001 0 1 0 0.004,-2 l -5.91992,-0.0156 a 1.0001,1.0001 0 0 0 -0.002,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z"
- transform="matrix(-1,0,0,1,1290,-302.99979)"
- id="path8528-7-3-1" />
+ id="path12602-0-0"
+ d="m 433,536 c -2.50006,0 -4.81247,1.33488 -6.0625,3.5 -1.25002,2.16512 -1.25002,4.83488 0,7 1.25003,2.16512 3.56244,3.5 6.0625,3.5 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 H 433 c -2.1444,0 -4.12312,-1.1429 -5.19531,-3 -1.0722,-1.8571 -1.0722,-4.1429 0,-6 1.07219,-1.8571 3.05091,-3 5.19531,-3 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g6348"
- transform="translate(41.999953,147)"
+ style="display:inline;fill:#ffffff;stroke-width:1.15385;enable-background:new"
+ id="g12520-1-5"
+ transform="matrix(0.866667,0,0,0.866667,60.5333,-302.8)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="I-22">
<path
inkscape:connector-curvature="0"
- id="path6344"
- d="m 27.5,347 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 A 0.50005,0.50005 0 0 0 40.5,347 Z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 31 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 A 0.50005,0.50005 0 0 0 41,360.5 V 357 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path12513-1-0"
+ d="m 454,555.92383 c -4.45393,0 -8.07617,3.62224 -8.07617,8.07617 0,4.45393 3.62224,8.07617 8.07617,8.07617 4.45393,0 8.07617,-3.62224 8.07617,-8.07617 0,-4.45393 -3.62224,-8.07617 -8.07617,-8.07617 z m 0,1.15234 c 3.83034,0 6.92383,3.09349 6.92383,6.92383 0,3.83034 -3.09349,6.92383 -6.92383,6.92383 -3.83034,0 -6.92383,-3.09349 -6.92383,-6.92383 0,-3.83034 3.09349,-6.92383 6.92383,-6.92383 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15385;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
- id="path6346"
- d="m 30.5,350 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 7 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 7 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -7 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path20498-6"
+ d="m 454,558.23047 c -3.17259,0 -5.76953,2.59694 -5.76953,5.76953 -1e-5,3.1726 2.59693,5.76953 5.76953,5.76953 3.1726,0 5.76954,-2.59693 5.76953,-5.76953 0,-3.17259 -2.59694,-5.76953 -5.76953,-5.76953 z m 0,2.30859 c 1.92542,0 3.46093,1.53552 3.46094,3.46094 0,1.92543 -1.53551,3.46094 -3.46094,3.46094 -1.92543,0 -3.46094,-1.53551 -3.46094,-3.46094 10e-6,-1.92542 1.53552,-3.46094 3.46094,-3.46094 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.30769;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path6351"
- d="m 310.57031,494.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -1.08008,3.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m -4.92968,2.02149 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C 307.68213,505.0249 308,504.28067 308,503.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
+ transform="matrix(0.866667,0,0,0.866667,39.5333,-302.8)"
+ id="g12476-7-0"
+ style="display:inline;fill:#ffffff;stroke-width:1.15385;enable-background:new"
inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g6359"
- transform="rotate(90,306.5,333.5)">
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="I-21">
<path
- sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- id="path6353"
- d="m 469.5,356 c -1.37478,0 -2.5,1.12522 -2.5,2.5 0,1.37478 1.12522,2.5 2.5,2.5 1.37478,0 2.5,-1.12522 2.5,-2.5 0,-1.37478 -1.12522,-2.5 -2.5,-2.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <g
- style="opacity:0.7;fill:#ffffff"
- id="g6357">
- <path
- id="path6355"
- transform="matrix(0,-1,-1,0,1038,577)"
- d="m 218.5,557 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 V 564.5 c -0.01,0.67616 1.01,0.67616 1,0 v -4.59375 c 0.57903,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 9.5,0 c -1.09865,0 -2,0.90135 -2,2 0,0.36859 0.10883,0.71022 0.28516,1.00781 l -5.13868,5.13867 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 l 5.13867,-5.13868 C 227.28978,560.89117 227.63141,561 228,561 c 1.09865,-10e-6 2,-0.90135 2,-2 0,-1.09865 -0.90135,-1.99999 -2,-2 z m 0.5,10 c -0.64684,0 -1.19777,0.42097 -1.40625,1 H 222.5 c -0.67616,-0.01 -0.67616,1.01 0,1 h 4.59375 c 0.20848,0.57903 0.75941,1 1.40625,1 0.82251,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.67749,-1.5 -1.5,-1.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- </g>
+ id="path12470-5-6"
+ d="m 454,555.92383 c -4.45393,0 -8.07617,3.62224 -8.07617,8.07617 0,4.45393 3.62224,8.07617 8.07617,8.07617 4.45393,0 8.07617,-3.62224 8.07617,-8.07617 0,-4.45393 -3.62224,-8.07617 -8.07617,-8.07617 z m 0,1.15234 c 3.83034,0 6.92383,3.09349 6.92383,6.92383 0,3.83034 -3.09349,6.92383 -6.92383,6.92383 -3.83034,0 -6.92383,-3.09349 -6.92383,-6.92383 0,-3.83034 3.09349,-6.92383 6.92383,-6.92383 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15385;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path12474-5-2"
+ d="m 454,561.69141 c -1.26767,-10e-6 -2.3086,1.04092 -2.30859,2.30859 -1e-5,1.26767 1.04092,2.3086 2.30859,2.30859 1.26767,10e-6 2.3086,-1.04092 2.30859,-2.30859 1e-5,-1.26767 -1.04092,-2.3086 -2.30859,-2.30859 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15385;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20496-2"
+ d="m 454,558.23047 c -3.17259,10e-6 -5.76953,2.59694 -5.76953,5.76953 -1e-5,3.17259 2.59694,5.76952 5.76953,5.76953 3.1726,10e-6 5.76954,-2.59693 5.76953,-5.76953 0,-3.1726 -2.59693,-5.76954 -5.76953,-5.76953 z m 0,2.30859 c 1.92543,0 3.46094,1.53551 3.46094,3.46094 0,1.92543 -1.53551,3.46094 -3.46094,3.46094 -1.92542,-1e-5 -3.46094,-1.53552 -3.46094,-3.46094 0,-1.92542 1.53552,-3.46093 3.46094,-3.46094 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.30769;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- style="fill:#ffffff"
- id="g6505"
- transform="translate(84,-21)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 31.5,494 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -9 A 0.50005,0.50005 0 0 0 40.5,494 Z m 0.5,1 h 8 v 8 h -8 z"
- id="path6499"
- inkscape:connector-curvature="0" />
+ id="g21139"
+ style="display:inline;opacity:0.7;fill:#ffffff;enable-background:new"
+ inkscape:label="I-20">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.89999998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 38,496 c -0.546362,0 -1,0.45364 -1,1 0,0.54636 0.453638,1 1,1 0.546362,0 1,-0.45364 1,-1 0,-0.54636 -0.453638,-1 -1,-1 z m -3.513672,1.05078 c -0.16529,0.005 -0.314526,0.10024 -0.388672,0.24805 l -2.75,5.5 c -0.148607,0.29892 0.06852,0.64991 0.402344,0.65039 h 5.75 c 0.340259,-0.001 0.55634,-0.36474 0.394531,-0.66406 l -3,-5.5 c -0.08111,-0.14873 -0.238867,-0.23931 -0.408203,-0.23438 z"
- id="path6501"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 412,179 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
+ id="path12522"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.69300022;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 29.492188,495.99219 A 0.50005,0.50005 0 0 0 29,496.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 30 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z m -2,2 A 0.50005,0.50005 0 0 0 27,498.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 1 0 0,-1 H 28 v -8.5 a 0.50005,0.50005 0 0 0 -0.507812,-0.50781 z"
- id="path6503"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 412,184 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
+ id="path12526"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
</g>
<g
- id="g8734-0"
- transform="translate(-104.00001,-19.99995)"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ transform="matrix(-1,0,0,1,401.984,150.996)"
+ id="g13323"
+ style="display:inline;fill:#ffffff;stroke:#ffffff;enable-background:new"
+ inkscape:label="I-19">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 158.48048,492.99995 c -0.15153,0.004 -0.29304,0.0766 -0.38477,0.19727 l -4.94922,4.94921 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.5 h 5 v 12 h -10 v -6 h -1 v 6.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -6 c -0.005,-6e-5 -0.009,-6e-5 -0.0137,0 -6.7e-4,2e-5 -0.001,-2e-5 -0.002,0 -0.001,4e-5 -0.003,-5e-5 -0.004,0 z"
- id="path8730-7"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccc" />
+ id="path13321"
+ d="M 9.96875,29.048828 C 9.4658605,28.864829 8.9025328,28.986924 8.5410156,29.310547 8.1794984,29.63417 7.9598217,30.084792 7.7695312,30.613281 7.3889504,31.670259 7.1601578,33.086794 6.90625,34.523438 c -0.2539078,1.436643 -0.5324149,2.889409 -0.9414062,3.929687 -0.2044957,0.520139 -0.4424423,0.932648 -0.6894532,1.1875 -0.2470108,0.254852 -0.473033,0.363281 -0.7851562,0.363281 a 0.50005,0.50005 0 1 0 0,1 c 0.5904168,0 1.1159371,-0.267683 1.5039062,-0.667968 0.3879692,-0.400286 0.6690516,-0.922242 0.9023438,-1.515626 0.4665844,-1.186767 0.7390333,-2.679616 0.9941406,-4.123046 0.2551073,-1.443431 0.4935421,-2.842034 0.8183594,-3.744141 0.1624086,-0.451054 0.3541704,-0.76594 0.5,-0.896484 0.1458295,-0.130544 0.1865427,-0.15232 0.4160156,-0.06836 0.057045,0.02087 0.1634141,0.101911 0.2832031,0.296875 0.1197889,0.194965 0.2422649,0.485737 0.3515629,0.826172 0.218596,0.680871 0.393488,1.55941 0.582031,2.373047 0.188543,0.813637 0.358157,1.549689 0.740234,2.082031 0.191039,0.266171 0.511622,0.515788 0.900391,0.50586 0.388769,-0.0099 0.704011,-0.230804 1.001953,-0.542969 0.337514,-0.353626 0.595779,-0.497442 0.722656,-0.529297 0.126878,-0.03186 0.138013,-0.02504 0.242188,0.06836 0.20835,0.186805 0.512485,0.892009 0.740234,1.732422 0.227749,0.840413 0.429042,1.804722 0.716797,2.601563 0.143877,0.39842 0.30542,0.75895 0.542969,1.05664 0.237548,0.297691 0.601614,0.544922 1.027343,0.544922 a 0.50005,0.50005 0 1 0 0,-1 c -0.0724,0 -0.124723,-0.01782 -0.246093,-0.169922 -0.12137,-0.152098 -0.260285,-0.426776 -0.384766,-0.771484 -0.248961,-0.689415 -0.452791,-1.642926 -0.691406,-2.523438 -0.238616,-0.880511 -0.460258,-1.699598 -1.037109,-2.216796 -0.288426,-0.2586 -0.735893,-0.398016 -1.154297,-0.292969 -0.418405,0.105047 -0.794027,0.38192 -1.203125,0.810547 -0.205362,0.215165 -0.318948,0.232836 -0.302735,0.232422 0.01621,-4.14e-4 0.02252,0.02861 -0.0625,-0.08984 C 12.22449,34.745505 11.999507,34.047965 11.816406,33.257812 11.633305,32.46766 11.457527,31.57275 11.210938,30.804688 11.087643,30.420656 10.949285,30.066996 10.761719,29.761719 10.574152,29.456442 10.328076,29.1803 9.96875,29.048828 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 56.515625,452 c 0.752,0 1.453818,0.239 2.023438,0.64453 C 59.424733,453.27508 60,454.31514 60,455.48438 V 458.5 c -3e-5,0.27537 -0.222677,0.4989 -0.498047,0.5 l -4.009765,0.008 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 L 55,452.53516 v -0.002 -0.0352 C 55.001,452.22272 55.22466,452.00003 55.5,452 Z M 54,452 v 1 H 52.484375 C 51.099855,453 50,454.09985 50,455.48438 v 8.03124 C 50,464.90014 51.099855,466 52.484375,466 h 4.03125 C 57.900145,466 59,464.90014 59,463.51562 V 460 h 1 v 3.51562 C 60,465.43685 58.436855,467 56.515625,467 h -4.03125 C 50.563145,467 49,465.43686 49,463.51562 v -8.03124 C 49,453.56315 50.563145,452 52.484375,452 Z"
- id="path6557"
- inkscape:connector-curvature="0" />
- <path
- id="path6596"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 92.484375,452 c -0.752,0 -1.453818,0.239 -2.023438,0.64453 C 89.575267,453.27508 89,454.31514 89,455.48438 V 458.5 c 3e-5,0.27537 0.222677,0.4989 0.498047,0.5 l 4.009765,0.008 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 94,452.53516 v -0.002 -0.0352 C 93.999,452.22272 93.77534,452.00003 93.5,452 Z M 95,452 v 1 h 1.515625 C 97.900145,453 99,454.09985 99,455.48438 v 8.03124 C 99,464.90014 97.900145,466 96.515625,466 h -4.03125 C 91.099855,466 90,464.90014 90,463.51562 V 460 h -1 v 3.51562 C 89,465.43685 90.563145,467 92.484375,467 h 4.03125 C 98.436855,467 100,465.43686 100,463.51562 v -8.03124 C 100,453.56315 98.436855,452 96.515625,452 Z m 6.47656,-0.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 102,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 104,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
- inkscape:connector-curvature="0" />
- <path
- id="path6598"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 113.48438,452 C 111.56315,452 110,453.56315 110,455.48438 v 8.03124 c 0,1.92123 1.56315,3.48438 3.48438,3.48438 h 4.03125 C 119.43685,467 121,465.43685 121,463.51562 v -8.03124 C 121,453.56315 119.43685,452 117.51563,452 Z m 0,1 h 4.03125 c 1.38452,0 2.48437,1.09985 2.48437,2.48438 v 8.03124 C 120,464.90015 118.90015,466 117.51563,466 h -4.03125 C 112.09985,466 111,464.90015 111,463.51562 v -8.03124 C 111,454.09985 112.09985,453 113.48438,453 Z m 1.5625,1 C 114.47554,454 114,454.47555 114,455.04688 v 3.90624 c 0,0.57133 0.47554,1.04688 1.04688,1.04688 h 0.90625 C 116.52446,460 117,459.52445 117,458.95312 v -3.90624 C 117,454.47555 116.52446,454 115.95313,454 Z m 7.42968,-2.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 123,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 125,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
- inkscape:connector-curvature="0" />
- <path
- id="path6600"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 138.51562,452 c 0.752,0 1.45382,0.239 2.02344,0.64453 0.88567,0.63055 1.46094,1.67061 1.46094,2.83985 V 458.5 c -3e-5,0.27537 -0.22268,0.4989 -0.49805,0.5 l -4.00976,0.008 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 L 137,452.53516 v -0.002 -0.0352 c 0.001,-0.27524 0.22466,-0.49793 0.5,-0.49796 z M 136,452 v 1 h -1.51563 C 133.09986,453 132,454.09985 132,455.48438 v 8.03124 c 0,1.38452 1.09986,2.48438 2.48437,2.48438 h 4.03125 C 139.90014,466 141,464.90014 141,463.51562 V 460 h 1 v 3.51562 C 142,465.43685 140.43685,467 138.51562,467 h -4.03125 C 132.56315,467 131,465.43686 131,463.51562 v -8.03124 C 131,453.56315 132.56315,452 134.48437,452 Z m 7.47656,-0.97852 a 0.50005,0.50005 0 0 0 -0.31445,0.8711 c 0.58809,0.54453 0.8418,1.0856 0.8418,1.60156 L 144,459.5 a 0.50005,0.50005 0 1 0 1,0 l 0.004,-6.00586 c 0,-0.8509 -0.43179,-1.65971 -1.16211,-2.33594 a 0.50005,0.50005 0 0 0 -0.36524,-0.13672 z m 3.01563,2.01563 A 0.50005,0.50005 0 0 0 146,453.54297 v 4.05859 a 0.50005,0.50005 0 1 0 1,0 v -4.05859 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g26277"
- transform="translate(273,-20.99999)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 203.5,284 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -8,8 A 0.50005,0.50005 0 0 0 195,292.5 l -0.008,5.00586 a 0.50005,0.50005 0 0 0 0.5,0.50195 L 208.5,298 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 208 v 12 l -12.00781,0.008 0.008,-4.30078 z"
- id="path23052"
- inkscape:connector-curvature="0" />
+ id="g165463"
+ style="display:inline;enable-background:new"
+ inkscape:label="I-18">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 200.5,284 -5.00781,0.008 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -4.50195 L 200.5,285 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path23056"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 363.51562,184 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 185 h 12 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ id="path10187-3-4"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 351.48242,557.01562 -0.96875,0.0156 c -0.0189,2.6e-4 -0.0378,0.002 -0.0566,0.004 -2.58289,0.33067 -4.57988,2.60038 -4.45117,5.21484 0.0288,0.58487 0.23179,1.09854 0.44141,1.5957 l -3.78516,3.78516 c -0.33708,0.30742 -0.60091,0.7293 -0.64063,1.23047 -0.0397,0.50117 0.17261,1.03979 0.625,1.49219 0.45357,0.45356 0.99596,0.65829 1.49219,0.61328 0.49624,-0.045 0.906,-0.30379 1.21485,-0.61328 l 3.80664,-3.80664 c 0.52791,0.22561 1.0693,0.4331 1.69336,0.45117 2.60313,0.0754 4.83493,-1.87377 5.11328,-4.46289 0.001,-0.0136 0.002,-0.0273 0.002,-0.041 l 0.0215,-0.9668 c 0.0105,-0.45102 -0.53451,-0.68424 -0.85351,-0.36523 L 352.29297,564 h -1.58594 L 349,562.29297 v -1.58594 l 2.84375,-2.83789 c 0.31756,-0.31766 0.0878,-0.86042 -0.36133,-0.85352 z"
- id="path18095"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccc" />
<g
- transform="translate(-1162,-873.9944)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g17413-4-0">
+ id="g165451"
+ style="display:inline;enable-background:new"
+ inkscape:label="I-17">
<path
inkscape:connector-curvature="0"
- id="path17404-8-7"
- transform="translate(1162,873.9944)"
- d="m 164.48438,535.00586 a 0.50005,0.50005 0 0 0 -0.1211,0.0195 l -1.36328,0.3887 0.01,2.03906 1.63085,-0.46679 A 0.50005,0.50005 0 0 0 165,536.50586 v -1 a 0.50005,0.50005 0 0 0 -0.51562,-0.5 z M 162,535.70117 l -2,0.57031 0.01,2.03907 2,-0.57227 z m -3,0.85547 -1.63672,0.46875 A 0.50005,0.50005 0 0 0 157,537.50586 v 1 a 0.50005,0.50005 0 0 0 0.63672,0.48047 l 1.36914,-0.39063 z M 157,542 v 1 l 8.5,0.01 c 0.276,-5e-4 0.4995,-0.224 0.5,-0.5 -5e-4,-0.276 -0.224,-0.4995 -0.5,-0.5 z m -3,2.00586 v 5.49219 c 0,0.2761 0.2239,0.5 0.5,0.5 h 11 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -4.99219 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1315.5078,1411.9922 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1.5 1.5 h -1 z"
- id="path17409-0-0"
- inkscape:connector-curvature="0" />
+ id="path10162-3"
+ d="m 349.01758,181.25 a 0.50005,0.50005 0 0 0 -0.41992,0.20312 l -6.48243,8.7461 a 0.50005,0.50005 0 1 0 0.80274,0.5957 L 349,182.58984 l 6.07031,8.20313 a 0.50005,0.50005 0 1 0 0.80469,-0.59375 l -6.47266,-8.7461 A 0.50005,0.50005 0 0 0 349.01758,181.25 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(-574,-936.9944)"
- id="g17429-7-7"
- style="display:inline;fill:#ffffff;enable-background:new">
+ id="g165457"
+ style="display:inline;enable-background:new"
+ inkscape:label="I-16">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1063.5078,1410.9922 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1.5 1.5 h -1 z"
- id="path17417-2-4"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 327.48047,181 a 0.50005,0.50005 0 0 0 -0.46875,0.39453 c -0.73399,3.42527 -2.46804,7.48775 -5.67969,8.63477 a 0.50005,0.50005 0 1 0 0.33594,0.9414 c 3.19373,-1.14062 4.90029,-4.45895 5.83203,-7.61914 0.93174,3.16019 2.6383,6.47852 5.83203,7.61914 a 0.50005,0.50005 0 1 0 0.33594,-0.9414 c -3.21165,-1.14702 -4.9457,-5.2095 -5.67969,-8.63477 A 0.50005,0.50005 0 0 0 327.48047,181 Z"
+ id="path10168-6-7"
inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- d="m 1340,1411 v 2 l 1.5,-0.01 1.75,-2 z m 4.5,-0.01 -1.75,2 h 2.75 l 1.7266,-2 z m 4,0 -1.7266,2 2.7266,0.01 c 0.276,-5e-4 0.4995,-0.224 0.5,-0.5 v -1 c -5e-4,-0.276 -0.224,-0.4995 -0.5,-0.5 z m -8.5,4.01 0.01,1.9922 -3.0098,0.01 v 5.4921 c 0,0.2761 0.2239,0.5 0.5,0.5 h 12 c 0.2761,0 0.5,-0.2239 0.5,-0.5 V 1415.5 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z m 2.5156,1 c 0.084,0 0.1663,0.026 0.2383,0.068 l 4.25,2.5 c 0.33,0.1931 0.33,0.6701 0,0.8632 l -4.25,2.5 c -0.3336,0.1966 -0.7545,-0.044 -0.7539,-0.4316 v -5 c -10e-5,-0.2823 0.2334,-0.51 0.5156,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- transform="translate(-273)"
- id="path17425-5" />
</g>
- <path
- sodipodi:nodetypes="cccccscccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path17971-6"
- d="m 433.60156,411.10938 c -0.0348,2.9e-4 -0.0695,0.004 -0.10351,0.0117 -2.03912,0.46668 -3.49042,2.28707 -3.49219,4.37891 9e-4,0.50625 0.15089,0.99318 0.31836,1.46875 l -2.42774,2.42773 c -1.00968,1.00969 -1.01874,2.3133 -0.3125,3.01954 0.70624,0.70624 2.00985,0.69718 3.01954,-0.3125 l 2.42968,-2.42969 c 0.47476,0.16775 0.9595,0.31841 1.46485,0.32031 6.7e-4,0 0.001,0 0.002,0 2.10425,-9.3e-4 3.93168,-1.46897 4.38672,-3.52344 0.0316,-0.14237 -4.7e-4,-0.29146 -0.0879,-0.4082 l -0.64844,-0.86328 c -0.17598,-0.23372 -0.51414,-0.2671 -0.73242,-0.0723 L 435.31055,417 h -1.08008 L 433,415.56445 v -0.85742 l 1.85352,-1.85351 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -0.89063,-0.89062 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="path18042-5"
- d="m 413.49609,411 c -1.31297,0 -2.2906,0.33758 -3.34961,1.39648 -1.07833,1.0783 -1.34444,2.83666 -0.73437,4.48438 l -2.51563,2.51562 c -1.00968,1.00969 -1.01874,2.3133 -0.3125,3.01954 0.70624,0.70624 2.00985,0.69718 3.01954,-0.3125 l 2.51757,-2.51758 c 1.64574,0.60684 3.4036,0.3464 4.48243,-0.73242 1.05892,-1.05893 1.39668,-2.03818 1.39257,-3.35547 a 0.50005,0.50005 0 0 0 -0.14648,-0.35157 l -1,-1 a 0.50005,0.50005 0 0 0 -0.70703,0 L 414.28906,416 h -0.58594 l -0.70703,-0.70703 v -0.58594 l 1.85352,-1.85351 a 0.50005,0.50005 0 0 0 0,-0.70704 l -1,-1 A 0.50005,0.50005 0 0 0 413.49609,411 Z m -0.18164,1.02539 0.47461,0.47461 -1.64648,1.64648 A 0.50005,0.50005 0 0 0 411.99609,414.5 v 1 a 0.50005,0.50005 0 0 0 0.14649,0.35352 l 1,1 A 0.50005,0.50005 0 0 0 413.49609,417 h 1 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 1.64648,-1.64649 0.47461,0.47461 c -0.0187,1.03267 -0.19304,1.58367 -1.07422,2.46484 -0.83209,0.8321 -2.35353,1.13617 -3.75195,0.47266 a 0.50005,0.50005 0 0 0 -0.56836,0.0977 l -2.67969,2.67968 c -0.74031,0.74032 -1.3117,0.60626 -1.60546,0.3125 -0.29376,-0.29376 -0.42782,-0.86515 0.3125,-1.60546 l 2.67773,-2.67774 a 0.50005,0.50005 0 0 0 0.0977,-0.56836 c -0.66677,-1.39852 -0.3581,-2.92122 0.47461,-3.7539 0.88058,-0.8805 1.43264,-1.05616 2.46093,-1.07813 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
- transform="translate(-104.9941,85.0365)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g19021-7-6">
+ id="g165454"
+ style="display:inline;enable-background:new"
+ inkscape:label="I-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 448.5,284 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -10,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -10,4 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 5,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -10,1 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m 5,0 c 0.28207,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21793,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z"
- id="ellipse19010-6-5"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 307,180 c -1.24829,0 -2.24461,0.83463 -3,1.93555 -0.75539,1.10091 -1.32403,2.51399 -1.76367,3.91601 -0.87928,2.80405 -1.23047,5.58594 -1.23047,5.58594 a 0.50013931,0.50013931 0 1 0 0.99219,0.12695 c 0,0 0.34791,-2.71791 1.19336,-5.41406 0.42272,-1.34808 0.97296,-2.68677 1.63281,-3.64844 C 305.48407,181.54029 306.19904,181 307,181 c 0.80095,0 1.51593,0.54029 2.17578,1.50195 0.65985,0.96167 1.21009,2.30036 1.63281,3.64844 0.84545,2.69615 1.19336,5.41406 1.19336,5.41406 a 0.50013931,0.50013931 0 1 0 0.99219,-0.12695 c 0,0 -0.35119,-2.78189 -1.23047,-5.58594 -0.43964,-1.40202 -1.00828,-2.8151 -1.76367,-3.91601 C 309.24461,180.83464 308.24829,180 307,180 Z"
+ id="path13261"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g19186-9-4"
- transform="translate(-146.9941,85.0365)">
+ style="display:inline;fill:#ffffff;stroke-width:1.03551;enable-background:new"
+ id="g10170-0"
+ transform="matrix(0.930364,0,0,1.00239,257.638,150.908)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="I-14">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 327.49805,368.03711 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -7,7 a 0.50005,0.50005 0 0 0 0,0.70703 l 7,7 a 0.50005,0.50005 0 0 0 0.70704,0 l 7.03124,-7 a 0.50005,0.50005 0 0 0 0,-0.70703 l -7.03124,-7 a 0.50005,0.50005 0 0 0 -0.36133,-0.14648 z m 0.008,1.20703 6.32226,6.29297 -6.32226,6.29297 -6.29297,-6.29297 z m 0,4.79297 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z"
- transform="translate(146.9941,-85.0365)"
- id="path19093-9-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03551;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 23.460938,40.029297 A 0.51780782,0.51780782 0 0 1 22.96875,39.486328 L 23,38.607422 v -0.0039 c 0.0063,-2.697355 1.432558,-5.191614 3.748047,-6.542969 2.32064,-1.354362 5.185219,-1.354362 7.505859,0 2.32064,1.354362 3.748047,3.85629 3.748047,6.560547 v 0.882812 a 0.51780782,0.51780782 0 1 1 -1.035156,0 V 38.6211 c 0,-2.339918 -1.23548,-4.49829 -3.236328,-5.666016 -2.000849,-1.167726 -4.460089,-1.167727 -6.460938,0 -2.000848,1.167726 -3.234375,3.326098 -3.234375,5.666016 a 0.51780782,0.51780782 0 0 1 -0.002,0.01758 l -0.0293,0.882812 a 0.51780782,0.51780782 0 0 1 -0.542968,0.507813 z"
+ id="path10174-7"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g19103-5"
- transform="rotate(-90,394.50012,1587.5001)">
+ id="g165448"
+ style="display:inline;enable-background:new"
+ inkscape:label="I-13">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 457.5,473 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 h -7.5 -0.5 c -0.5244,0 -1.02378,0.21717 -1.39258,0.57617 -0.3688,0.3592 -0.60742,0.86058 -0.60742,1.42578 V 485 c 10e-5,0.5302 0.21104,1.03916 0.58594,1.41406 C 447.96084,486.78896 448.4698,487 449,487 h 2.5 c 0.2762,0 0.5,-0.2238 0.5,-0.5 v -9 c 0,-0.2761 -0.2238,-0.4999 -0.5,-0.5 H 449 c -0.4523,0 -1,-0.47105 -1,-0.99805 0,-0.2635 0.13823,-0.51462 0.33203,-0.69922 C 448.52543,475.11903 448.775,475 449,475 h 8 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v 5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -4 v 1 h 4 v 0.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 460.5,482 H 460 v -5 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 0,9 h 2 v 2 h -2 z"
- transform="rotate(90,394.50012,1587.5001)"
- id="path19040-4"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 265.00049,180.00029 c -0.56524,0 -1.07102,0.24537 -1.44727,0.61718 -0.37625,0.37181 -0.64955,0.85716 -0.88086,1.40821 -0.46263,1.10209 -0.75684,2.49042 -1.08008,3.85937 -0.32324,1.36896 -0.67626,2.7158 -1.17383,3.66406 -0.49757,0.94827 -1.04163,1.45118 -1.91211,1.45118 a 0.50005,0.50005 0 1 0 0,1 c 1.29399,0 2.21222,-0.8721 2.79688,-1.98633 0.58466,-1.11424 0.93562,-2.51739 1.26172,-3.89844 0.32609,-1.38105 0.62614,-2.74272 1.0293,-3.70312 0.20157,-0.48021 0.4296,-0.85424 0.6621,-1.08399 0.2325,-0.22975 0.4436,-0.32812 0.74415,-0.32812 0.30054,0 0.51164,0.0984 0.74414,0.32812 0.23249,0.22975 0.46053,0.60378 0.66211,1.08399 0.40315,0.9604 0.7032,2.32207 1.02929,3.70312 0.3261,1.38105 0.67511,2.7842 1.25977,3.89844 0.58466,1.11423 1.50289,1.98633 2.79687,1.98633 a 0.50005,0.50005 0 1 0 0,-1 c -0.87047,0 -1.41258,-0.50291 -1.91015,-1.45118 -0.49757,-0.94826 -0.85059,-2.2951 -1.17383,-3.66406 -0.32324,-1.36895 -0.61745,-2.75728 -1.08008,-3.85937 -0.23131,-0.55105 -0.50461,-1.0364 -0.88086,-1.40821 -0.37625,-0.37181 -0.88203,-0.61718 -1.44726,-0.61718 z"
+ id="path10124-9"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 428.25,452 c -0.6506,0 -1.23633,0.19727 -1.64453,0.60547 -0.4083,0.4081 -0.60567,0.99393 -0.60547,1.64453 v 9.5 c 2e-4,0.6505 0.19727,1.23643 0.60547,1.64453 C 427.01357,465.80273 427.5994,466 428.25,466 H 429 v -1 h -0.75 c -0.4574,0 -0.7477,-0.1227 -0.9375,-0.3125 -0.1898,-0.1898 -0.3124,-0.48 -0.3125,-0.9375 v -9.5 c -10e-5,-0.4574 0.1227,-0.7477 0.3125,-0.9375 C 427.5023,453.1227 427.7926,453 428.25,453 H 429 v -1 z m 8.75,0 v 1 h 0.75 c 0.4574,0 0.7477,0.1227 0.9375,0.3125 0.1898,0.1898 0.3125,0.4801 0.3125,0.9375 v 9.5 c 0,0.4574 -0.1227,0.7477 -0.3125,0.9375 C 438.4977,464.8773 438.2074,465 437.75,465 H 437 v 1 h 0.75 c 0.6506,0 1.23643,-0.19727 1.64453,-0.60547 C 439.80273,464.98643 440,464.4006 440,463.75 v -9.5 c 0,-0.6506 -0.19727,-1.23643 -0.60547,-1.64453 C 438.98643,452.19727 438.4006,452 437.75,452 Z m -4,4 v 2 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -2 v 1 h 2 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v 2 h 1 v -2 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 461 h 2 v -1 h -2 v -1.5 A 0.50005,0.50005 0 0 0 435.5,458 H 434 v -2 z m -1,3 h 3 v 3 h -3 z"
- id="path19168-3"
- inkscape:connector-curvature="0" />
- <path
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 411,536 v 4 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.5 h -4 v 1 h 4 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v 4 h 1 v -4 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 544 h 4 v -1 h -4 v -2.5 A 0.50005,0.50005 0 0 0 414.5,540 H 412 v -4 z m -2,5 h 5 v 5 h -5 z m 2,2 v 1 h 1 v -1 z"
- id="rect19268-0"
- inkscape:connector-curvature="0" />
<g
- id="g9974-4-9"
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(-84.00001,21.000005)">
- <path
- sodipodi:nodetypes="ccccccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path14003-8"
- transform="translate(84.000014,-21.000005)"
- d="M 308.06055,557 C 307.40848,557.63639 307,558.52103 307,559.5 c 0,1.5 0.75,2.5 2,3.14453 v 0.004 6.85156 c -0.0287,2.02848 3.02869,2.02848 3,0 v -6.85156 -0.002 c 1.28948,-0.66521 2,-1.64648 2,-3.14648 0,-0.97897 -0.40848,-1.86361 -1.06055,-2.5 H 312.91797 312 V 560 l -1,1 h -1 l -1,-1 2e-5,-3 z M 310,569 h 1 v 1 h -1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="matrix(0.930364,0,0,1.00239,215.638,150.908)"
+ id="g19530"
+ style="display:inline;fill:#ffffff;stroke-width:1.03551;enable-background:new"
+ inkscape:label="I-12">
<path
- sodipodi:nodetypes="ccccccccccccccscscsccc"
- id="path14013-6"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 387.00001,542 387,536.5 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 l 10e-6,5.5 z m 0.75,2 H 388.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -4 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 0.75001 v 1 c -0.75,0 -1.25,0.5 -1.25,1.25 L 384,547.5 c -10e-6,0.78517 0.31169,1.44054 0.78516,1.86719 0.47346,0.42664 1.08725,0.63281 1.69726,0.63281 0.61001,0 1.22902,-0.20449 1.71094,-0.62891 0.48192,-0.42441 0.80663,-1.08156 0.80664,-1.87109 l 10e-6,-1.25 c 0,-0.75 -0.5,-1.25 -1.25,-1.25 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03551;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 30.216797,30 a 0.51780782,0.51780782 0 0 0 -0.337891,0.126953 l -3.761718,3.242188 c -1.859424,1.602556 -3.136719,3.536893 -3.136719,6.128906 a 0.51780782,0.51780782 0 1 0 1.035156,0 c 0,-2.262051 1.045193,-3.852838 2.777344,-5.345703 l 3.615234,-3.115235 h 0.152344 l 3.617187,3.115235 a 0.51780782,0.51780782 0 0 0 0,0.002 c 1.732844,1.491631 2.775391,3.081554 2.775391,5.34375 a 0.5185545,0.5185545 0 1 0 1.037109,0 c 0,-2.591868 -1.275948,-4.527155 -3.136718,-6.128906 L 31.091797,30.126953 A 0.51780782,0.51780782 0 0 0 30.753906,30 Z"
+ id="path19532"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-1134,-16.999998)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23520-0">
+ id="g12981"
+ transform="translate(-1.85367e-6,-21)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="I-11">
<path
- inkscape:connector-curvature="0"
- d="m 1461,518 c -1.3523,-0.0191 -1.3523,2.01913 0,2 h 2 c 1.3523,0.0191 1.3523,-2.01913 0,-2 z m -5,-1 v 7.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 517 h -1 v 7 h -10 v -7 z m 12.5,-1 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -3 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 h -13 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 3 c 0,0.27613 0.2239,0.49997 0.5,0.5 z m -12.5,-3 h 12 v 2 h -12 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path23618-7"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 226.5,206.99414 a 0.50004997,0.50004997 0 0 0 -0.34766,0.85938 L 228.29883,210 h -10.5918 l 2.14649,-2.14648 a 0.50004997,0.50004997 0 1 0 -0.70704,-0.70704 l -2.95703,2.95704 a 0.50004997,0.50004997 0 0 0 -0.002,0.79296 0.50004997,0.50004997 0 0 0 0.008,0.006 l 2.95117,2.95118 a 0.50004997,0.50004997 0 1 0 0.70704,-0.70704 L 217.70703,211 h 10.5918 l -2.14649,2.14648 a 0.50004997,0.50004997 0 1 0 0.70704,0.70704 l 2.96484,-2.9668 a 0.50004997,0.50004997 0 0 0 0.0195,-0.0156 l 0.0156,-0.0176 a 0.50004997,0.50004997 0 0 0 0.0234,-0.68164 0.50004997,0.50004997 0 0 0 -0.0234,-0.0254 0.50004997,0.50004997 0 0 0 -0.01,-0.01 l -2.99023,-2.99024 A 0.50004997,0.50004997 0 0 0 226.5,206.99414 Z"
+ id="path12879"
+ inkscape:connector-curvature="0" />
+ <path
+ id="circle12970"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 224.00001,202.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z m 5,0 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z m -10,0 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
+ inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g23658-7-6"
- transform="translate(-1113,-79.999998)">
+ id="g12986"
+ transform="translate(1.16284e-6,-21)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="I-10">
<path
- id="path23654-6-8"
- transform="translate(0,-21)"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1456,538 v 7.5 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 11 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 V 538 Z m 5,1 h 2 a 1.0001,1.0001 0 1 1 0,2 h -2 a 1.0001,1.0001 0 1 1 0,-2 z m -5.5,-6 c -0.2761,3e-5 -0.5,0.22387 -0.5,0.5 v 3 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 13 c 0.2761,-3e-5 0.5,-0.22387 0.5,-0.5 v -3 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 199.5,205 c 2.47936,0 4.5,2.02063 4.5,4.5 0,2.47937 -2.02064,4.5 -4.5,4.5 -2.47936,0 -4.5,-2.02063 -4.5,-4.5 0,-2.47937 2.02064,-4.5 4.5,-4.5 z m 0,1 c -1.93892,0 -3.5,1.56107 -3.5,3.5 0,1.93893 1.56108,3.5 3.5,3.5 1.93892,0 3.5,-1.56107 3.5,-3.5 0,-1.93893 -1.56108,-3.5 -3.5,-3.5 z"
+ id="ellipse12910"
inkscape:connector-curvature="0" />
- </g>
- <g
- id="g19402"
- transform="translate(0,1.9921509e-6)"
- style="fill:#ffffff">
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(-83.999995,42.000004)"
- id="g19210">
- <path
- inkscape:connector-curvature="0"
- d="m 348.48047,347 c -3.16361,0.009 -5.86504,2.31609 -6.39063,5.45117 -0.52558,3.13508 1.27477,6.20467 4.25977,7.25781 a 0.50005,0.50005 0 1 0 0.33203,-0.94336 c -2.52985,-0.89255 -4.05213,-3.48414 -3.60547,-6.14843 0.44666,-2.66429 2.72792,-4.6094 5.40821,-4.61719 2.68028,-0.008 4.97166,1.92234 5.43359,4.58398 0.46193,2.66165 -1.0456,5.26268 -3.57031,6.16993 a 0.50043111,0.50043111 0 1 0 0.33984,0.9414 c 2.9789,-1.07046 4.75841,-4.14926 4.21484,-7.28125 -0.54356,-3.13198 -3.25826,-5.42325 -6.42187,-5.41406 z m 0.0195,4.99999 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.64684 0.42097,1.19777 1,1.40625 v 0.59375 c -0.01,0.67616 1.00956,0.67616 1,0 v -0.59375 c 0.57902,-0.20848 1,-0.75941 1,-1.40625 0,-0.8225 -0.67751,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28206 0.21793,-0.5 0.5,-0.5 z m -0.002,3.98438 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1 c -0.01,0.67616 1.00957,0.67616 1,0 v -1 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z m 0,3 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 1.00195 c -0.01,0.67616 1.00957,0.67616 1,0 v -1.00195 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="circle19208" />
- </g>
- </g>
- <g
- id="g19394"
- transform="translate(0,1.9921509e-6)"
- style="fill:#ffffff">
<path
- inkscape:connector-curvature="0"
- d="m 390.5,416 c -0.98118,0 -1.79306,0.19786 -2.45312,0.51562 -0.008,0.17574 -0.0332,0.34151 -0.0332,0.52149 0,4.06772 2.58548,6.61176 5.30078,6.95117 2.02213,0.29647 2.40413,-2.76745 0.3711,-2.97656 -1.2847,-0.16059 -2.67188,-1.04233 -2.67188,-3.97461 0,-0.37546 0.0235,-0.72058 0.0664,-1.03711 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path19340"
- sodipodi:nodetypes="scsccscs" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 204.86914,200.01562 c 2.18302,0.17973 3.92401,1.9135 4.11328,4.09571 0.18928,2.18221 -1.22622,4.18928 -3.3457,4.74219 a 0.50005,0.50005 0 1 1 -0.25391,-0.9668 c 1.65432,-0.43156 2.75125,-1.98618 2.60352,-3.68945 -0.14774,-1.70328 -1.49531,-3.04527 -3.19922,-3.18555 -1.70391,-0.14028 -3.25342,0.96296 -3.67773,2.61914 a 0.50005,0.50005 0 1 1 -0.96876,-0.24805 c 0.54363,-2.12187 2.5455,-3.54691 4.72852,-3.36719 z"
+ id="path12915"
+ inkscape:connector-curvature="0" />
<path
- id="path5291"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 395,410 c -1.86938,0 -3.40407,0.68718 -4.4375,1.85938 -0.30774,0.34905 -0.56557,0.74269 -0.7832,1.16601 C 390.01692,413.00864 390.25738,413 390.5,413 h 0.44922 c 0.11262,-0.16825 0.23234,-0.32999 0.36328,-0.47852 C 392.15407,411.56692 393.36938,411 395,411 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z m -4.5,4 c -1.84524,0 -3.47115,0.52889 -4.64258,1.5625 C 384.686,416.59611 384,418.13095 384,420 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 420 c 0,-1.63095 0.564,-2.84611 1.51758,-3.6875 C 387.47115,415.47111 388.84524,415 390.5,415 h 1.00781 c 3.27827,0 5.29896,2.17669 5.49805,3.57031 a 0.50005,0.50005 0 1 0 0.98828,-0.14062 C 397.69323,416.32331 395.21551,414 391.50781,414 Z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 201.00001,209.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
+ id="circle12964"
inkscape:connector-curvature="0" />
</g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12992"
+ transform="translate(2.62972e-6,-21)"
inkscape:export-filename="blender_icons.png"
- transform="matrix(0.93036376,0,0,1.0023904,215.63778,150.90833)"
- id="g19530"
- style="display:inline;fill:#ffffff;stroke-width:1.03551209;enable-background:new">
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="I-9">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03551209;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 30.216797,30 a 0.51780782,0.51780782 0 0 0 -0.337891,0.126953 l -3.761718,3.242188 c -1.859424,1.602556 -3.136719,3.536893 -3.136719,6.128906 a 0.51780782,0.51780782 0 1 0 1.035156,0 c 0,-2.262051 1.045193,-3.852838 2.777344,-5.345703 l 3.615234,-3.115235 h 0.152344 l 3.617187,3.115235 a 0.51780782,0.51780782 0 0 0 0,0.002 c 1.732844,1.491631 2.775391,3.081554 2.775391,5.34375 a 0.5185545,0.5185545 0 1 0 1.037109,0 c 0,-2.591868 -1.275948,-4.527155 -3.136718,-6.128906 L 31.091797,30.126953 A 0.51780782,0.51780782 0 0 0 30.753906,30 Z"
- id="path19532"
+ id="path12908"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 183.8125,200.01562 c 2.21359,0.18235 3.97803,1.94071 4.16992,4.1543 0.19189,2.2136 -1.24344,4.25155 -3.39258,4.8125 a 0.5007349,0.5007349 0 1 1 -0.2539,-0.96875 c 1.68376,-0.43948 2.80079,-2.02289 2.65039,-3.75781 -0.1504,-1.73492 -1.52164,-3.10129 -3.25586,-3.24414 -1.73423,-0.14285 -3.31219,0.98104 -3.74414,2.66797 a 0.50005,0.50005 0 1 1 -0.96875,-0.24805 c 0.55114,-2.15241 2.58133,-3.59836 4.79492,-3.41602 z M 178.5,205 a 0.50005,0.50005 0 1 1 0,1 c -1.41705,0 -2.69209,0.85096 -3.23438,2.16016 -0.54228,1.30919 -0.24224,2.81243 0.75977,3.81445 1.00201,1.00201 2.50527,1.30205 3.81445,0.75977 C 181.14903,212.19209 182,210.91706 182,209.5 a 0.50005,0.50005 0 1 1 1,0 c 0,1.81865 -1.09714,3.46223 -2.77734,4.1582 -1.68021,0.69597 -3.61833,0.30942 -4.9043,-0.97656 -1.28598,-1.28598 -1.67253,-3.22408 -0.97656,-4.9043 C 175.03776,206.09713 176.68136,205 178.5,205 Z"
inkscape:connector-curvature="0" />
- </g>
- <g
- transform="translate(-84,22.000001)"
- id="g13033"
- style="display:inline;fill:#ffffff;enable-background:new">
<path
- sodipodi:nodetypes="ccccccccsssss"
- inkscape:connector-curvature="0"
- id="path12959"
- d="m 473.49999,411 -2.99609,0.006 c -0.2754,6.1e-4 -0.49976,0.22265 -0.5,0.49805 l -0.004,8.45884 c 0,1.02328 0.80629,2.03747 2,2.03711 1.19534,0 1.99609,-1.02155 1.99609,-2.04297 l 0.004,-8.45703 c -1.8e-4,-0.27638 -0.22362,-0.50048 -0.5,-0.5 z m -1.5,8 c 0.55228,0 1,0.44772 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55228 0.44772,-1 1,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- sodipodi:nodetypes="cccccccccc"
- inkscape:connector-curvature="0"
- id="path12972"
- d="m 478.14648,418.14648 -3,3 c -0.31399,0.31533 -0.0915,0.85354 0.35352,0.85352 h 3 2 c 0.27591,-1.9e-4 0.49982,-0.22409 0.5,-0.5 v -3 c -7e-5,-0.28163 -0.23215,-0.50794 -0.51367,-0.5 h -2 c -0.12731,0.004 -0.24956,0.0566 -0.33985,0.14648 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- sodipodi:nodetypes="cccccccccc"
- inkscape:connector-curvature="0"
- id="path12974"
- d="m 477.49257,412.00014 c -0.12999,0.002 -0.25408,0.0546 -0.34596,0.14655 l -2.00065,1.99942 c -0.094,0.094 -0.14673,0.22146 -0.14655,0.35436 v 4.0001 c -2e-5,0.4458 0.53925,0.66879 0.85409,0.35316 l 3.99954,-4.00067 c 0.19472,-0.19518 0.19472,-0.51115 0,-0.70633 l -2.00009,-2.00004 c -0.0954,-0.0955 -0.2254,-0.14835 -0.36038,-0.14655 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="M 182.99634,206.50183 A 1.4981741,1.4981725 0 0 1 181.49817,208 a 1.4981741,1.4981725 0 0 1 -1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49817,1.49817 z"
+ id="circle12958"
+ inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g12998"
- transform="translate(1.1628419e-6,-21)"
+ transform="translate(1.16284e-6,-21)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="I-8">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
d="m 157.5,205 c 2.47936,0 4.5,2.02063 4.5,4.5 0,2.47937 -2.02064,4.5 -4.5,4.5 -2.47936,0 -4.5,-2.02063 -4.5,-4.5 0,-2.47937 2.02064,-4.5 4.5,-4.5 z m 0,1 c -1.93892,0 -3.5,1.56107 -3.5,3.5 0,1.93893 1.56108,3.5 3.5,3.5 1.93892,0 3.5,-1.56107 3.5,-3.5 0,-1.93893 -1.56108,-3.5 -3.5,-3.5 z"
@@ -14211,46 +15768,33 @@
id="path12892"
inkscape:connector-curvature="0" />
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
d="m 159.00001,209.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
id="circle12960"
inkscape:connector-curvature="0" />
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
d="m 164.00001,204.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
id="circle12962"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g12986"
- transform="translate(1.1628419e-6,-21)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 199.5,205 c 2.47936,0 4.5,2.02063 4.5,4.5 0,2.47937 -2.02064,4.5 -4.5,4.5 -2.47936,0 -4.5,-2.02063 -4.5,-4.5 0,-2.47937 2.02064,-4.5 4.5,-4.5 z m 0,1 c -1.93892,0 -3.5,1.56107 -3.5,3.5 0,1.93893 1.56108,3.5 3.5,3.5 1.93892,0 3.5,-1.56107 3.5,-3.5 0,-1.93893 -1.56108,-3.5 -3.5,-3.5 z"
- id="ellipse12910"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 204.86914,200.01562 c 2.18302,0.17973 3.92401,1.9135 4.11328,4.09571 0.18928,2.18221 -1.22622,4.18928 -3.3457,4.74219 a 0.50005,0.50005 0 1 1 -0.25391,-0.9668 c 1.65432,-0.43156 2.75125,-1.98618 2.60352,-3.68945 -0.14774,-1.70328 -1.49531,-3.04527 -3.19922,-3.18555 -1.70391,-0.14028 -3.25342,0.96296 -3.67773,2.61914 a 0.50005,0.50005 0 1 1 -0.96876,-0.24805 c 0.54363,-2.12187 2.5455,-3.54691 4.72852,-3.36719 z"
- id="path12915"
- inkscape:connector-curvature="0" />
+ id="g165460"
+ style="display:inline;enable-background:new"
+ inkscape:label="I-7">
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 201.00001,209.49817 a 1.498175,1.498175 0 0 1 -1.49818,1.49817 1.498175,1.498175 0 0 1 -1.49817,-1.49817 1.498175,1.498175 0 0 1 1.49817,-1.49818 1.498175,1.498175 0 0 1 1.49818,1.49818 z"
- id="circle12964"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ d="m 140.99637,186.00011 a 1.99635,1.99635 0 0 1 -1.99635,1.99635 1.99635,1.99635 0 0 1 -1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,1.99635 z m -8.50223,-7.00402 a 0.50005,0.50005 0 0 0 -0.34766,0.85743 l 3,3 C 134.44086,183.71574 134,184.80241 134,186 c 2e-5,1.19757 0.44085,2.28425 1.14648,3.14648 l -3,3 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 C 136.71574,190.55915 137.80243,191 139,191 c 1.19757,0 2.28426,-0.44085 3.14648,-1.14648 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 C 143.55915,188.28425 143.99998,187.19757 144,186 c 0,-1.19759 -0.44086,-2.28426 -1.14648,-3.14648 l 3,-3 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 C 141.28425,181.44086 140.19759,181 139,181 c -1.19759,0 -2.28425,0.44086 -3.14648,1.14648 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15039 z M 139,182 c 2.21506,0 4.00001,1.78494 4,4 -4e-5,2.21502 -1.78498,4 -4,4 -2.21502,0 -3.99996,-1.78498 -4,-4 -1e-5,-2.21506 1.78494,-4 4,-4 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="circle20581-1" />
</g>
<g
- transform="translate(1.1628419e-6)"
style="display:inline;fill:#ffffff;enable-background:new"
id="g13014"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="I-6">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 111.5,179 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 180 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.00781,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.01562,9 A 0.50005,0.50005 0 0 0 111,188.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 112 v -3.5 A 0.50005,0.50005 0 0 0 111.49219,188 Z M 124.5,188 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 124.5,188 Z"
@@ -14263,255 +15807,182 @@
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- id="g22801-1"
- transform="translate(696,857.9975)">
+ id="g165470"
+ style="display:inline;enable-background:new"
+ inkscape:label="I-5">
<path
- id="path22797-9"
- d="m -239.5,-446.99219 c -2.47912,0 -4.5,2.01847 -4.5,4.4961 0,2.47763 2.02088,4.49609 4.5,4.49609 2.47912,0 4.5,-2.01846 4.5,-4.49609 0,-2.47763 -2.02088,-4.4961 -4.5,-4.4961 z m 0,1.1875 c 1.83471,0 3.31055,1.47622 3.31055,3.3086 0,1.83238 -1.47584,3.30859 -3.31055,3.30859 -1.8347,0 -3.31055,-1.47621 -3.31055,-3.30859 0,-1.83238 1.47585,-3.3086 3.31055,-3.3086 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 90.494141,178.99609 a 0.50005,0.50005 0 0 0 -0.347657,0.85743 l 3,3 C 92.440854,183.71574 91.999993,184.80241 92,186 c 2e-5,1.19757 0.440853,2.28425 1.146484,3.14648 l -3,3 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 3,-3 C 94.715742,190.55915 95.802428,191 97,191 c 1.197573,0 2.284258,-0.44085 3.14648,-1.14648 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 C 101.55915,188.28425 101.99998,187.19757 102,186 c 0,-1.19759 -0.44086,-2.28426 -1.14648,-3.14648 l 3,-3 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 C 99.284255,181.44086 98.197592,181 97,181 c -1.19759,0 -2.284254,0.44086 -3.146484,1.14648 l -3,-3 a 0.50005,0.50005 0 0 0 -0.359375,-0.15039 z M 97,182 c 2.21506,0 4.00001,1.78494 4,4 -4e-5,2.21502 -1.784977,4 -4,4 -2.215019,0 -3.999963,-1.78498 -4,-4 -1.2e-5,-2.21506 1.784946,-4 4,-4 z"
+ id="path25165"
inkscape:connector-curvature="0" />
</g>
<g
- id="g22943"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(-105,-21)"
+ id="g24881"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(-2.1686213e-6,9.0033549e-6)">
+ inkscape:label="I-4">
+ <path
+ inkscape:connector-curvature="0"
+ id="path24877"
+ d="m 183.8125,200.01562 c 2.21359,0.18235 3.97803,1.94071 4.16992,4.1543 0.19189,2.2136 -1.24344,4.25155 -3.39258,4.8125 a 0.5007349,0.5007349 0 1 1 -0.2539,-0.96875 c 1.68376,-0.43948 2.80079,-2.02289 2.65039,-3.75781 -0.1504,-1.73492 -1.52164,-3.10129 -3.25586,-3.24414 -1.73423,-0.14285 -3.31219,0.98104 -3.74414,2.66797 a 0.50005,0.50005 0 1 1 -0.96875,-0.24805 c 0.55114,-2.15241 2.58133,-3.59836 4.79492,-3.41602 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
- style="fill:#ffffff"
- id="g12942"
- transform="translate(-20,18)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g24891"
+ transform="matrix(-1,0,0,1,357,0)"
+ style="fill:#ffffff">
<path
inkscape:connector-curvature="0"
- id="path12932"
- d="m 155.50195,121.99414 a 0.50005,0.50005 0 0 0 -0.36133,0.85352 C 156.37329,124.12237 157.775,126 160.5,126 c 2.725,0 4.12681,-1.87774 5.35938,-3.15234 a 0.50005,0.50005 0 1 0 -0.71876,-0.69532 C 163.83477,123.50274 162.775,125 160.5,125 c -2.275,0 -3.33487,-1.49737 -4.64062,-2.84766 a 0.50005,0.50005 0 0 0 -0.35743,-0.1582 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ d="M 176.99634,212.50183 A 1.4981741,1.4981725 0 0 1 175.49817,214 a 1.4981741,1.4981725 0 0 1 -1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49817,1.49817 z m 2.39233,-7.41199 c 0.85602,0.17256 1.66292,0.59211 2.30469,1.23828 1.28353,1.29236 1.66074,3.23682 0.95508,4.91602 -0.70566,1.6792 -2.35829,2.76833 -4.17969,2.75586 a 0.50005,0.50005 0 1 1 0.008,-1 c 1.41921,0.01 2.70016,-0.83611 3.25,-2.14453 0.54985,-1.30842 0.25598,-2.81527 -0.74414,-3.82227 -1.00012,-1.00699 -2.50427,-1.31041 -3.8164,-0.76953 C 175.85388,206.80455 175,208.08075 175,209.5 a 0.50005,0.50005 0 1 1 -1,0 c 0,-1.82144 1.10118,-3.466 2.78516,-4.16016 0.84199,-0.34708 1.7475,-0.42255 2.60351,-0.25 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="ellipse24887" />
</g>
- <path
- sodipodi:nodetypes="ccccccccc"
- inkscape:connector-curvature="0"
- id="path12946"
- d="m 132.50195,143 c -0.35971,-0.001 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0266 -0.12814,-0.0406 -0.19535,-0.041 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- </g>
- <g
- transform="translate(0.99999783,9.0033549e-6)"
- id="g22948"
- style="display:inline;fill:#ffffff;enable-background:new">
- <path
- inkscape:connector-curvature="0"
- id="path12633"
- d="m 155.50195,139.99414 a 0.50005,0.50005 0 0 0 -0.36133,0.85352 C 156.37329,142.12237 157.775,144 160.5,144 c 2.725,0 4.12681,-1.87774 5.35938,-3.15234 a 0.50005,0.50005 0 1 0 -0.71876,-0.69532 C 163.83477,141.50274 162.775,143 160.5,143 c -2.275,0 -3.33487,-1.49737 -4.64062,-2.84766 a 0.50005,0.50005 0 0 0 -0.35743,-0.1582 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="path12645"
- d="m 152.50195,143 a 0.50005,0.50005 0 0 0 -0.46093,0.69727 l 3,7 a 0.50005,0.50005 0 1 0 0.91796,-0.39454 l -2.50781,-5.85156 5.85156,2.50781 a 0.50005,0.50005 0 1 0 0.39454,-0.91796 l -7,-3 A 0.50005,0.50005 0 0 0 152.50195,143 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- id="g14837"
- transform="translate(-210,-315)">
+ id="g165467"
+ style="display:inline;enable-background:new"
+ inkscape:label="I-3">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 48.5,183 c -0.27613,4e-5 -0.49997,0.22388 -0.5,0.5 v 9 c 3e-5,0.27614 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22386 0.5,-0.5 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z"
+ id="path5234"
inkscape:connector-curvature="0"
- id="path14829"
- d="m 415.5,452.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00251,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,10e-6 -2.00781,0 z m -10.5,9 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00251,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,10e-6 -2.00781,0 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="ccccccccc" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 52.49219,179.00781 c -0.1326,4e-5 -0.25976,0.0527 -0.35352,0.1465 l -1.99219,1.99217 C 50.02584,181.26245 50,181.375 50,181.5 v 0.5 h 1 l 0.003,-0.296 1.69618,-1.69619 h 8.29297 v 8.29298 L 59.29548,189.99745 59,190 v 1 h 0.5 c 0.11717,0 0.23766,-0.0261 0.3457,-0.13867 l 2,-2 c 0.0938,-0.0938 0.14646,-0.22091 0.14649,-0.35352 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z"
+ id="path5236"
inkscape:connector-curvature="0"
- id="path22198"
- d="m 411.50391,454 a 0.50005,0.50005 0 0 0 -0.35743,0.14648 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.85156,-0.85157 0.78515,0.006 a 0.50005,0.50005 0 1 0 0.006,-1 z m -3.01368,2.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 A 0.50005,0.50005 0 0 0 407,458.5 v 1.00781 a 0.50005,0.50005 0 1 0 1,0 v -0.80078 l 0.85352,-0.85351 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m 7.99415,0.9961 A 0.50005,0.50005 0 0 0 415.99219,458.5 v 0.80078 l -0.85352,0.85352 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 0.14649,-0.35352 V 458.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -3.00196,4.00976 a 0.50005,0.50005 0 0 0 -0.34375,0.15235 l -0.85156,0.85156 -0.7832,-0.006 a 0.50005,0.50005 0 1 0 -0.008,1 l 0.99219,0.008 a 0.50005,0.50005 0 0 0 0.35742,-0.14648 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85938 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="cccscccccccccscccccc" />
</g>
- <rect
- style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="rect5375"
- width="6"
- height="5"
- x="218"
- y="119" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 303.5,600 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 0.5 h 1 v -0.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 313.5,605 H 307 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 2.5,6 h 7 v 4 h -7 z m 3,1 v 2 h 1 v -2 z"
- id="path19950-6"
- inkscape:connector-curvature="0" />
<g
- transform="matrix(0.86666667,0,0,0.86666667,39.533341,-302.8)"
- id="g12476-7-0"
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384614;enable-background:new"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g26527-9"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- inkscape:connector-curvature="0"
- id="path12470-5-6"
- d="m 454,555.92383 c -4.45393,0 -8.07617,3.62224 -8.07617,8.07617 0,4.45393 3.62224,8.07617 8.07617,8.07617 4.45393,0 8.07617,-3.62224 8.07617,-8.07617 0,-4.45393 -3.62224,-8.07617 -8.07617,-8.07617 z m 0,1.15234 c 3.83034,0 6.92383,3.09349 6.92383,6.92383 0,3.83034 -3.09349,6.92383 -6.92383,6.92383 -3.83034,0 -6.92383,-3.09349 -6.92383,-6.92383 0,-3.83034 3.09349,-6.92383 6.92383,-6.92383 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384614;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ inkscape:export-ydpi="96"
+ transform="matrix(0,-1,-1,0,220.014,219.986)"
+ inkscape:label="I-2">
<path
- sodipodi:nodetypes="ccccc"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 27.486328,183.01367 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 9 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path26523-4"
inkscape:connector-curvature="0"
- id="path12474-5-2"
- d="m 454,561.69141 c -1.26767,-10e-6 -2.3086,1.04092 -2.30859,2.30859 -1e-5,1.26767 1.04092,2.3086 2.30859,2.30859 1.26767,10e-6 2.3086,-1.04092 2.30859,-2.30859 1e-5,-1.26767 -1.04092,-2.3086 -2.30859,-2.30859 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384603;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccccc" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 31.478516,179.02148 c -0.1326,3e-5 -0.259761,0.0527 -0.353516,0.14649 l -1.992188,1.99219 c -0.490839,0.47125 0.235779,1.19787 0.707032,0.70703 l 1.845703,-1.84571 h 8.292969 v 8.29297 l -2.707032,2.70703 h -8.292968 l 0.0072,-4.00727 -1,-0.002 -0.0072,4.50727 c -0.0011,0.27689 0.223106,0.50192 0.5,0.50195 h 9 c 0.132599,-2e-5 0.259759,-0.0527 0.353515,-0.14648 l 3,-3 c 0.09377,-0.0938 0.14646,-0.22092 0.146485,-0.35352 v -9 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path26525-5"
inkscape:connector-curvature="0"
- id="path20496-2"
- d="m 454,558.23047 c -3.17259,10e-6 -5.76953,2.59694 -5.76953,5.76953 -1e-5,3.17259 2.59694,5.76952 5.76953,5.76953 3.1726,10e-6 5.76954,-2.59693 5.76953,-5.76953 0,-3.1726 -2.59693,-5.76954 -5.76953,-5.76953 z m 0,2.30859 c 1.92543,0 3.46094,1.53551 3.46094,3.46094 0,1.92543 -1.53551,3.46094 -3.46094,3.46094 -1.92542,-1e-5 -3.46094,-1.53552 -3.46094,-3.46094 0,-1.92542 1.53552,-3.46093 3.46094,-3.46094 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.30769229;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccccccccccccc" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.15384614;enable-background:new"
- id="g12520-1-5"
- transform="matrix(0.86666667,0,0,0.86666667,60.533341,-302.8)"
- inkscape:export-filename="blender_icons.png"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- inkscape:connector-curvature="0"
- id="path12513-1-0"
- d="m 454,555.92383 c -4.45393,0 -8.07617,3.62224 -8.07617,8.07617 0,4.45393 3.62224,8.07617 8.07617,8.07617 4.45393,0 8.07617,-3.62224 8.07617,-8.07617 0,-4.45393 -3.62224,-8.07617 -8.07617,-8.07617 z m 0,1.15234 c 3.83034,0 6.92383,3.09349 6.92383,6.92383 0,3.83034 -3.09349,6.92383 -6.92383,6.92383 -3.83034,0 -6.92383,-3.09349 -6.92383,-6.92383 0,-3.83034 3.09349,-6.92383 6.92383,-6.92383 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.15384614;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- id="path20498-6"
- d="m 454,558.23047 c -3.17259,0 -5.76953,2.59694 -5.76953,5.76953 -1e-5,3.1726 2.59693,5.76953 5.76953,5.76953 3.1726,0 5.76954,-2.59693 5.76953,-5.76953 0,-3.17259 -2.59694,-5.76953 -5.76953,-5.76953 z m 0,2.30859 c 1.92542,0 3.46093,1.53552 3.46094,3.46094 0,1.92543 -1.53551,3.46094 -3.46094,3.46094 -1.92543,0 -3.46094,-1.53551 -3.46094,-3.46094 10e-6,-1.92542 1.53552,-3.46094 3.46094,-3.46094 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.30769229;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- </g>
- <g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g5294-1-7-1"
- transform="translate(41.999998,-357)"
inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- sodipodi:nodetypes="sssss"
- inkscape:connector-curvature="0"
- id="path5168-0-2-8"
- d="m 433,541 c -1.09865,0 -2,0.90135 -2,2 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 0,-1.09865 -0.90135,-2 -2,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ transform="translate(0.00711,-0.00712)"
+ id="g26453-0"
+ inkscape:label="I-1">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 10.486328,179.01367 c -0.1326,3e-5 -0.259761,0.0527 -0.353516,0.14649 l -1.9941401,1.99414 c -0.4908663,0.47125 0.2357781,1.1979 0.7070312,0.70703 l 1.8476559,-1.84766 h 8.292969 v 8.29297 l -2.707031,2.70703 H 7.9882812 l 0.00461,-3.00655 -1,-0.002 -0.00656,3.5085 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 8.9999998 c 0.132599,-2e-5 0.259759,-0.0527 0.353516,-0.14648 l 3,-3 c 0.09377,-0.0938 0.14646,-0.22092 0.146484,-0.35352 v -9 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path26449-3"
inkscape:connector-curvature="0"
- id="path5260-6-8-7"
- d="m 433.08008,537.98438 c -2.77576,0 -5.01953,2.26323 -5.01953,5.01562 0,2.7524 2.24277,5.02307 5.02148,5.01562 L 439.00195,548 a 1.0001,1.0001 0 1 0 -0.004,-2 l -5.91993,0.0156 c -1.70285,0.005 -3.01757,-1.33278 -3.01757,-3.01562 0,-1.68217 1.31272,-3.01459 3.01757,-3.01562 L 438.99805,540 a 1.0001,1.0001 0 1 0 0.004,-2 l -5.91992,-0.0156 a 1.0001,1.0001 0 0 0 -0.002,0 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccccccccccccc" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 6.4921875,183.00781 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 3 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 3 c 0.2761309,-3e-5 0.4999724,-0.22387 0.5,-0.5 v -3 c -2.76e-5,-0.27613 -0.2238691,-0.49997 -0.5,-0.5 z"
+ id="path26451-7"
inkscape:connector-curvature="0"
- id="path12602-0-0"
- d="m 433,536 c -2.50006,0 -4.81247,1.33488 -6.0625,3.5 -1.25002,2.16512 -1.25002,4.83488 0,7 1.25003,2.16512 3.56244,3.5 6.0625,3.5 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 H 433 c -2.1444,0 -4.12312,-1.1429 -5.19531,-3 -1.0722,-1.8571 -1.0722,-4.1429 0,-6 1.07219,-1.8571 3.05091,-3 5.19531,-3 h 6.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccccc" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path20009-7"
- d="m 328.5,600 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 1.5 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 332 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -5 v -1.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z m -0.5,6 h 1 v 1 1 h -1 v -1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- id="path20615"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 345.50001,453 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 0.5 h 1 v -0.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -6.5 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 2.5,6 h 7 v 4 h -7 z m 3,0.99999 h 1 V 462 h -1 z"
- inkscape:connector-curvature="0" />
<g
- id="g20632"
+ transform="translate(483,-126)"
+ id="g11187"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(696.00001,793)">
- <g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- id="g20623"
- transform="translate(-740.00001,-750)"
- style="display:inline;fill:#ffffff;enable-background:new">
- <path
- inkscape:connector-curvature="0"
- id="path20621"
- transform="translate(594,-43.000004)"
- d="m -179.5,453 c -1.92707,0 -3.5,1.57293 -3.5,3.5 v 1.5 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -0.5 v -1.5 c 0,-1.92707 -1.57293,-3.5 -3.5,-3.5 z m 0,1 c 1.38663,0 2.5,1.11337 2.5,2.5 v 1.5 h -5 v -1.5 c 0,-1.38663 1.11337,-2.5 2.5,-2.5 z m -0.5,6 h 1 v 1 1 h -1 v -1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- </g>
+ inkscape:label="H-26">
+ <path
+ inkscape:connector-curvature="0"
+ id="path10969"
+ transform="translate(-483,126)"
+ d="m 533.49219,157.99219 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 533,159.70703 v 7.57422 c -0.59355,0.34821 -1,0.9856 -1,1.71875 0,1.09865 0.90135,2 2,2 0.73315,0 1.37054,-0.40645 1.71875,-1 h 7.57422 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 543.29297,169 H 536 c 0,-1.09865 -0.90135,-2 -2,-2 v -7.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.95704,-1.95703 a 0.50005,0.50005 0 0 0 -0.40429,-0.19726 z M 534,168 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.55821 0.44179,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
+ transform="matrix(-1,0,0,1,1033.99,42.006)"
+ id="g20880-1"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g11319-4"
- transform="rotate(90,348.9944,289.99188)">
+ inkscape:label="H-25">
<path
- sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
- id="path11311-4"
- d="m 202.98828,114.98828 c -0.55228,0.008 -0.99388,0.46139 -0.98633,1.01367 v 8 c -0.0191,1.35232 2.01913,1.35232 2,0 v -8 c 0.008,-0.56299 -0.45068,-1.02136 -1.01367,-1.01367 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="ellipse20865-9"
+ transform="matrix(-1,0,0,1,483.993,-42.006)"
+ d="m -28.482422,162.00195 a 0.50005,0.50005 0 0 0 -0.365234,0.85743 l 1.146484,1.14648 h -5.585937 c -0.348208,-0.59355 -0.987551,-1 -1.720703,-1 -1.098651,0 -2,0.90135 -2,2 0,1.09865 0.901349,2 2,2 1.09865,0 2,-0.90135 2,-2 h 5.30664 l -1.146484,1.14648 a 0.50064056,0.50064056 0 0 0 0.708984,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 a 0.50005,0.50005 0 0 0 -0.34375,-0.15039 z m -6.52539,2.00391 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.558211,0 -1,-0.44179 -1,-1 0,-0.55821 0.441789,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
- transform="translate(760.99456,-488.99997)"
- id="g11317-7"
+ transform="matrix(0,1,1,0,-94.0025,680.992)"
+ id="g20878-5"
style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
<g
- id="g11315-1"
+ id="g20876-3"
style="fill:#ffffff">
<path
- sodipodi:nodetypes="ccccccccccccccccccccc"
inkscape:connector-curvature="0"
- id="path11313-84"
- d="m -564.5,609 c -0.5954,-0.006 -0.70014,0.84767 -0.12109,0.98633 l -0.28321,-0.0723 1.91992,7.70703 c 0.0555,0.22241 0.25515,0.37858 0.48438,0.37894 h 11 c 0.27461,-2e-5 0.49783,-0.22149 0.5,-0.49609 l 0.01,-0.99805 c 2.2e-4,-0.0476 -0.006,-0.0949 -0.0195,-0.14063 l -2.00585,-7.00195 c -0.0613,-0.21559 -0.25857,-0.36405 -0.4827,-0.36328 l -2.49599,-0.0137 0.002,1 2.11903,0.0157 1.88086,6.56836 -0.002,0.42969 h -10.11328 l -1.74414,-7 3.85953,-0.0138 v -1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path20873-7"
+ d="M -559.99805,608.99609 -564.5,609 a 0.50005,0.50005 0 0 0 -0.5,0.50391 l 0.008,1.00195 a 0.50005,0.50005 0 0 0 0.0195,0.13281 l 1.99219,6.99805 A 0.50005,0.50005 0 0 0 -562.5,618 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.49609 l 0.01,-0.99805 a 0.50005,0.50005 0 0 0 -0.0195,-0.14063 l -2.00585,-7.00195 A 0.50005,0.50005 0 0 0 -553.49609,609 l -3.50196,-0.004 v 1 l 3.125,0.004 1.88086,6.57031 -0.002,0.42969 h -10.12695 l -1.8711,-6.56836 -0.004,-0.43164 3.99804,-0.004 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
</g>
</g>
- <path
- id="path16385"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 515.5,432 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14647 L 513.29297,434 H 510.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6.45312 0.004 c 0.0131,-8.2e-4 0.0261,-0.002 0.0391,-0.004 0.004,5e-5 0.008,5e-5 0.0117,0 0.0143,0.002 0.0286,0.003 0.043,0.004 h 0.006 5.44336 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.79297 l -1.85351,-1.85353 C 518.76,432.05268 518.6327,431.99995 518.5,432 Z m 1.49781,1.99804 c 2.21589,-3.2e-4 4.00185,1.7855 4.00195,4.00196 -9e-4,2.19736 -1.75841,3.97457 -3.95508,4 -0.0131,8.2e-4 -0.0261,0.002 -0.0391,0.004 -0.0149,-0.002 -0.0299,-0.003 -0.0449,-0.004 -10e-4,0 -0.003,0 -0.004,0 -2.19824,-0.0228 -3.95803,-1.80057 -3.95898,-4 9e-5,-2.21578 1.78479,-4.00131 4,-4.00196 z M 516.99805,435 C 515.34742,435 514,436.34922 514,438 c 0,1.65079 1.34742,3 2.99805,3 1.65063,0 3,-1.34921 3,-3 0,-1.65078 -1.34937,-3 -3,-3 z m 0,1 c 1.11009,0 2,0.88955 2,2 0,1.11045 -0.88991,2 -2,2 C 515.88796,440 515,439.11045 515,438 c 0,-1.11045 0.88796,-2 1.99805,-2 z"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- d="m 140.99637,186.00011 a 1.99635,1.99635 0 0 1 -1.99635,1.99635 1.99635,1.99635 0 0 1 -1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,-1.99635 1.99635,1.99635 0 0 1 1.99635,1.99635 z m -8.50223,-7.00402 a 0.50005,0.50005 0 0 0 -0.34766,0.85743 l 3,3 C 134.44086,183.71574 134,184.80241 134,186 c 2e-5,1.19757 0.44085,2.28425 1.14648,3.14648 l -3,3 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 C 136.71574,190.55915 137.80243,191 139,191 c 1.19757,0 2.28426,-0.44085 3.14648,-1.14648 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 C 143.55915,188.28425 143.99998,187.19757 144,186 c 0,-1.19759 -0.44086,-2.28426 -1.14648,-3.14648 l 3,-3 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 C 141.28425,181.44086 140.19759,181 139,181 c -1.19759,0 -2.28425,0.44086 -3.14648,1.14648 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15039 z M 139,182 c 2.21506,0 4.00001,1.78494 4,4 -4e-5,2.21502 -1.78498,4 -4,4 -2.21502,0 -3.99996,-1.78498 -4,-4 -1e-5,-2.21506 1.78494,-4 4,-4 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="circle20581-1" />
- <path
- inkscape:connector-curvature="0"
- id="path22635-0-9"
- d="m 494.5,432 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 492.29297,434 H 489.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.79297 l -1.85351,-1.85352 A 0.50005,0.50005 0 0 0 497.5,432 Z m 0.20703,1 h 2.58594 l 1.85351,1.85352 A 0.50005,0.50005 0 0 0 499.5,435 h 1.5 v 7 h -11 v -7 h 2.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z m -0.46094,2.74414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 l 1.39649,1.39648 -1.39649,1.39648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 496,438.70703 l 1.39648,1.39649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 496.70703,438 l 1.39649,-1.39648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 L 496,437.29297 l -1.39648,-1.39649 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- sodipodi:nodetypes="ccccccccc"
- inkscape:connector-curvature="0"
- id="path19969-0"
- d="m 470.49125,433 c -0.3497,0.006 -0.58488,0.36077 -0.45507,0.68555 l 4,10.00195 c 0.1779,0.45034 0.82806,0.4102 0.94922,-0.0586 l 1.17578,-4.46875 4.46679,-1.17578 c 0.46499,-0.12321 0.50486,-0.76769 0.0586,-0.94727 l -10,-4.00195 c -0.0621,-0.0247 -0.12852,-0.0366 -0.19532,-0.0351 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="path19971-4"
- d="m 449.49078,433 a 0.50005,0.50005 0 0 0 -0.45507,0.68555 l 4,10.00195 a 0.50050292,0.50050292 0 1 0 0.92968,-0.37109 l -3.5664,-8.91797 8.91601,3.5664 a 0.50005,0.50005 0 1 0 0.3711,-0.92773 l -10,-4.00195 A 0.50005,0.50005 0 0 0 449.49078,433 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
- transform="translate(37.00977,-1667.9941)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20897-5"
+ transform="translate(399.01,-125.994)"
+ inkscape:label="H-24">
+ <path
+ inkscape:connector-curvature="0"
+ id="path20888-1"
+ transform="translate(171.99,125.994)"
+ d="m -71.318359,158.00586 a 0.50005,0.50005 0 1 0 0,1 h 1.689453 l -3.382813,4.26953 c -0.291076,-0.16603 -0.621698,-0.26953 -0.978515,-0.26953 -0.733151,0 -1.370542,0.40645 -1.71875,1 h -4.582032 l 1.146485,-1.14648 a 0.50005,0.50005 0 0 0 -0.363281,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 1 0 0.707031,-0.70704 l -1.146485,-1.14648 h 4.300782 c 0,1.09865 0.901352,2 2,2 1.098648,0 2,-0.90135 2,-2 0,-0.37821 -0.113913,-0.72852 -0.298828,-1.03125 l 3.298828,-4.16211 v 1.52148 a 0.50005,0.50005 0 1 0 1,0 v -2.82812 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -2.671875,6 c 0.558208,0 1,0.44179 1,1 0,0.55821 -0.441792,1 -1,1 -0.558208,0 -1,-0.44179 -1,-1 0,-0.55821 0.441792,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path20890-1"
+ d="m 99.244141,291.73828 a 0.50005,0.50005 0 0 0 -0.396485,0.81641 L 102.36133,297 h -1.68945 a 0.50005,0.50005 0 1 0 0,1 H 103.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.82812 a 0.50005,0.50005 0 1 0 -1,0 v 1.52148 l -3.367188,-4.25977 a 0.50005,0.50005 0 0 0 -0.388671,-0.19531 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(37.0098,-1667.99)"
id="g20814-2"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="H-23">
<g
id="g20812-7"
style="fill:#ffffff">
<path
inkscape:connector-curvature="0"
id="path20793-9"
- transform="translate(491.99023,1667.9941)"
+ transform="translate(491.99,1667.99)"
d="m -58.978516,159.00391 c -0.268711,-0.0142 -0.522461,0.007 -0.761718,0.0664 -0.47849,0.1192 -0.892924,0.44895 -1.089844,0.90235 -0.19686,0.4535 -0.203572,0.98669 -0.07617,1.59179 0.50982,2.4202 3.039112,5.6664 6.039062,8.0293 1.49994,1.1815 2.89794,1.95798 4.06836,2.26758 0.58523,0.1549 1.120142,0.1985 1.601562,0.0664 0.48143,-0.1318 0.896965,-0.48805 1.078125,-0.97265 0.36233,-0.9692 -0.01465,-2.1613 -0.732421,-3.5 -0.585772,-1.09244 -1.450912,-2.27994 -2.509766,-3.44922 h 1.695312 a 0.50005,0.50005 0 1 0 0,-1 h -2.828125 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.82812 a 0.50005,0.50005 0 1 0 1,0 v -1.53906 c 0.962773,1.08028 1.742337,2.16783 2.259766,3.13281 0.65736,1.226 0.838188,2.25364 0.679687,2.67774 -0.0793,0.212 -0.1766,0.29452 -0.40625,0.35742 -0.229719,0.063 -0.603428,0.0576 -1.080078,-0.0684 -0.95331,-0.2522 -2.281914,-0.96184 -3.708984,-2.08594 -2.85409,-2.248 -5.274721,-5.54511 -5.675781,-7.44921 -0.10032,-0.47611 -0.06643,-0.80379 0.01367,-0.98829 0.0801,-0.1845 0.178092,-0.26942 0.414062,-0.32812 0.47178,-0.1177 1.518783,0.0927 2.851563,0.85351 a 0.50043231,0.50036032 0 0 0 0.496093,-0.86914 c -1.081755,-0.61755 -2.02199,-0.98079 -2.828125,-1.02343 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
inkscape:connector-curvature="0"
id="path20798-7"
d="m 435.91471,1838.9185 a 0.49989467,0.50020516 0 0 1 -0.10766,0.08 c -1.55117,0.8755 -2.8107,1.2341 -3.77887,0.8468 -0.48409,-0.1937 -0.84555,-0.6327 -0.96369,-1.1577 -0.11806,-0.525 -0.0453,-1.1245 0.17673,-1.8153 0.88827,-2.7631 3.96133,-6.3033 7.15309,-8.3953 1.59595,-1.046 2.94158,-1.5736 4.02185,-1.474 0.5401,0.05 1.04109,0.3065 1.31713,0.757 0.27597,0.4504 0.3235,1.0201 0.20985,1.6633 a 0.50049929,0.50081015 0 1 1 -0.98577,-0.174 c 0.0873,-0.4946 0.0235,-0.8034 -0.076,-0.9657 -0.0994,-0.1623 -0.23754,-0.2538 -0.55637,-0.2832 -0.63756,-0.059 -1.88509,0.331 -3.38253,1.3124 -2.99493,1.9629 -5.99799,5.5314 -6.74857,7.8663 -0.18764,0.5837 -0.21297,1.0235 -0.15327,1.2889 0.0597,0.2653 0.15122,0.3664 0.35757,0.449 0.41277,0.1651 1.48565,0.019 2.91733,-0.7889 a 0.49989467,0.50020516 0 0 1 0.59917,0.7903 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
<g
- transform="translate(378.00977,-125.994)"
+ transform="translate(378.01,-125.994)"
id="g20863-5"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="H-22">
<path
inkscape:connector-curvature="0"
id="path20855-2"
@@ -14520,727 +15991,616 @@
<path
inkscape:connector-curvature="0"
id="path20857-3"
- transform="translate(171.99023,125.994)"
+ transform="translate(171.99,125.994)"
d="m -100.49805,157.99805 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 1.14649,-1.14649 v 7.57422 c -0.59356,0.34821 -1,0.9856 -1,1.71875 0,1.09865 0.90135,2 1.999996,2 0.73315,0 1.370541,-0.40645 1.71875,-1 h 7.574218 l -1.146484,1.14648 a 0.50005,0.50005 0 1 0 0.707031,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 A 0.50005,0.50005 0 0 0 -91.496094,167 a 0.50005,0.50005 0 0 0 -0.347656,0.85938 l 1.146484,1.14648 h -7.292968 c 0,-1.09865 -0.901352,-2 -2,-2 v -7.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707031,-0.70704 l -1.957031,-1.95703 a 0.50005,0.50005 0 0 0 -0.4043,-0.19726 z m 0.507816,10.00781 c 0.558208,0 1,0.44179 1,1 0,0.55821 -0.441792,1 -1,1 -0.558206,0 -0.999996,-0.44179 -0.999996,-1 0,-0.55821 0.44179,-1 0.999996,-1 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="matrix(-1,0,0,1,1033.9931,42.006004)"
- id="g20880-1"
- style="display:inline;fill:#ffffff;enable-background:new">
- <path
- inkscape:connector-curvature="0"
- id="ellipse20865-9"
- transform="matrix(-1,0,0,1,483.9931,-42.006004)"
- d="m -28.482422,162.00195 a 0.50005,0.50005 0 0 0 -0.365234,0.85743 l 1.146484,1.14648 h -5.585937 c -0.348208,-0.59355 -0.987551,-1 -1.720703,-1 -1.098651,0 -2,0.90135 -2,2 0,1.09865 0.901349,2 2,2 1.09865,0 2,-0.90135 2,-2 h 5.30664 l -1.146484,1.14648 a 0.50064056,0.50064056 0 0 0 0.708984,0.70704 l 2,-2 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 a 0.50005,0.50005 0 0 0 -0.34375,-0.15039 z m -6.52539,2.00391 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.558211,0 -1,-0.44179 -1,-1 0,-0.55821 0.441789,-1 1,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ transform="translate(1.74999e-7,23)"
+ id="g21364"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="H-21">
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="matrix(0,1,1,0,-94.00249,680.99203)"
- id="g20878-5"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <g
- id="g20876-3"
- style="fill:#ffffff">
- <path
- inkscape:connector-curvature="0"
- id="path20873-7"
- d="M -559.99805,608.99609 -564.5,609 a 0.50005,0.50005 0 0 0 -0.5,0.50391 l 0.008,1.00195 a 0.50005,0.50005 0 0 0 0.0195,0.13281 l 1.99219,6.99805 A 0.50005,0.50005 0 0 0 -562.5,618 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.49609 l 0.01,-0.99805 a 0.50005,0.50005 0 0 0 -0.0195,-0.14063 l -2.00585,-7.00195 A 0.50005,0.50005 0 0 0 -553.49609,609 l -3.50196,-0.004 v 1 l 3.125,0.004 1.88086,6.57031 -0.002,0.42969 h -10.12695 l -1.8711,-6.56836 -0.004,-0.43164 3.99804,-0.004 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- </g>
+ id="g5447"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 430.49219,134.99219 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70703,0.70704 L 430,136.70703 V 140.5 a 0.50005,0.50005 0 1 0 1,0 v -3.79297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.95704,-1.95703 a 0.50005,0.50005 0 0 0 -0.40429,-0.19726 z m 7.00195,7.00195 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 438.29297,144 H 434.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95313,-1.95313 a 0.50005,0.50005 0 0 0 -0.35937,-0.15234 z m -11.00195,2.99805 A 0.50005,0.50005 0 0 0 426,145.5 v 2.93945 A 0.50005,0.50005 0 0 0 426.56055,149 H 429.5 a 0.50005,0.50005 0 1 0 0,-1 h -1.79297 l 1.14649,-1.14648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 L 427,147.29297 V 145.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path21358"
+ inkscape:connector-curvature="0" />
+ <path
+ id="circle21362"
+ d="M 432.99635,144 A 1.99635,1.99635 0 0 1 431,145.99635 1.99635,1.99635 0 0 1 429.00365,144 1.99635,1.99635 0 0 1 431,142.00365 1.99635,1.99635 0 0 1 432.99635,144 Z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ inkscape:connector-curvature="0" />
</g>
</g>
<g
- transform="translate(122.00977,-1668.9941)"
- id="g20207-3"
- style="fill:#ffffff">
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 346.49414,1805.9941 a 0.50005,0.50005 0 0 0 -0.34766,0.8594 l 3,3 C 348.44086,1810.7157 348,1811.8024 348,1813 c 2e-5,1.197 0.44143,2.2825 1.14648,3.1445 l -3,3 a 0.50005,0.50005 0 1 0 0.70704,0.7071 l 3,-3 c 0.86236,0.7061 1.94846,1.1484 3.14648,1.1484 0.73402,0 1.42595,-0.1693 2.05469,-0.4551 l -0.77344,-0.7734 C 353.87701,1816.9083 353.45144,1817 353,1817 c -2.21502,0 -3.99996,-1.785 -4,-4 -10e-6,-2.2151 1.78494,-4 4,-4 2.21506,0 4.00001,1.7849 4,4 -10e-6,0.4593 -0.093,0.8925 -0.23438,1.3027 l 0.76954,0.7696 c 0.29106,-0.6335 0.46483,-1.3311 0.46484,-2.0723 0,-1.198 -0.44234,-2.2841 -1.14844,-3.1465 l 3.00196,-3.0019 a 0.50005,0.50005 0 0 0 -0.36329,-0.8575 0.50005,0.50005 0 0 0 -0.34375,0.1504 l -3.00195,3.002 C 355.28248,1808.4414 354.19705,1808 353,1808 c -1.19759,0 -2.28425,0.4409 -3.14648,1.1465 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.1524 z"
- id="path20884-9" />
+ id="g4294"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-20">
<path
- inkscape:connector-curvature="0"
- id="path20886-9"
- transform="translate(427.99023,1668.9941)"
- d="m -74.990234,142.01953 c -1.09866,0 -2,0.9013 -2,2 0,1.0986 0.90134,2 2,2 0.381313,0 0.73472,-0.11501 1.039062,-0.30273 a 0.50005,0.50005 0 0 0 0.107422,0.15625 l 4.146484,4.14648 h -1.621093 a 0.50005,0.50005 0 1 0 0,1 h 2.828125 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.82812 a 0.50005,0.50005 0 1 0 -1,0 v 1.62109 l -4.146485,-4.14648 a 0.50005,0.50005 0 0 0 -0.15625,-0.10743 c 0.187715,-0.30434 0.302735,-0.65777 0.302735,-1.03906 0,-1.0987 -0.90134,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.4418 1,1 0,0.5581 -0.4418,1 -1,1 -0.5582,0 -1,-0.4419 -1,-1 0,-0.5582 0.4418,-1 1,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.99;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 414.55664,159.95508 a 0.50005,0.50005 0 0 0 -0.47461,0.61133 L 414.38867,162 h -4.70898 l 0.30859,-1.39062 a 0.5003812,0.5003812 0 1 0 -0.97656,-0.21876 L 408.6543,162 H 406.5 a 0.50005,0.50005 0 1 0 0,1 h 1.93164 l -0.66602,3 H 405.5 a 0.50005,0.50005 0 1 0 0,1 h 2.04297 l -0.53125,2.39062 a 0.5003812,0.5003812 0 1 0 0.97656,0.21876 L 408.56836,167 h 6.88672 l 0.55664,2.60352 a 0.50005,0.50005 0 1 0 0.97656,-0.20704 L 416.47656,167 H 418.5 a 0.50005,0.50005 0 1 0 0,-1 h -2.23633 l -0.63867,-3 h 1.875 a 0.50005,0.50005 0 1 0 0,-1 h -2.08984 l -0.34961,-1.64258 a 0.50005,0.50005 0 0 0 -0.50391,-0.40234 z M 409.45703,163 h 5.14453 l 0.64063,3 h -6.45117 z"
+ id="path13985"
+ inkscape:connector-curvature="0" />
</g>
<g
+ id="g15500"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g20897-5"
- transform="translate(399.00976,-125.9939)">
+ inkscape:label="H-19">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 384.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 2 h -12 z m -0.5,9 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 12 v 2 h -12 z"
+ id="path15496"
inkscape:connector-curvature="0"
- id="path20888-1"
- transform="translate(171.99024,125.9939)"
- d="m -71.318359,158.00586 a 0.50005,0.50005 0 1 0 0,1 h 1.689453 l -3.382813,4.26953 c -0.291076,-0.16603 -0.621698,-0.26953 -0.978515,-0.26953 -0.733151,0 -1.370542,0.40645 -1.71875,1 h -4.582032 l 1.146485,-1.14648 a 0.50005,0.50005 0 0 0 -0.363281,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -2,2 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 1 0 0.707031,-0.70704 l -1.146485,-1.14648 h 4.300782 c 0,1.09865 0.901352,2 2,2 1.098648,0 2,-0.90135 2,-2 0,-0.37821 -0.113913,-0.72852 -0.298828,-1.03125 l 3.298828,-4.16211 v 1.52148 a 0.50005,0.50005 0 1 0 1,0 v -2.82812 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -2.671875,6 c 0.558208,0 1,0.44179 1,1 0,0.55821 -0.441792,1 -1,1 -0.558208,0 -1,-0.44179 -1,-1 0,-0.55821 0.441792,-1 1,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="M 393.00001,165 A 2.000005,2.000005 0 0 1 391,167.00001 2.000005,2.000005 0 0 1 388.99999,165 2.000005,2.000005 0 0 1 391,162.99999 2.000005,2.000005 0 0 1 393.00001,165 Z"
+ id="circle15498"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g15336"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:label="H-18">
<path
+ sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- id="path20890-1"
- d="m 99.244141,291.73828 a 0.50005,0.50005 0 0 0 -0.396485,0.81641 L 102.36133,297 h -1.68945 a 0.50005,0.50005 0 1 0 0,1 H 103.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.82812 a 0.50005,0.50005 0 1 0 -1,0 v 1.52148 l -3.367188,-4.25977 a 0.50005,0.50005 0 0 0 -0.388671,-0.19531 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path13329"
+ d="m 369.99998,160.99999 c -2.20236,0 -4,1.79764 -4,4 0,2.20237 1.79764,4 4,4 2.20237,0 4,-1.79763 4,-4 0,-2.20236 -1.79763,-4 -4,-4 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 363.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect13350"
+ inkscape:connector-curvature="0" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path20072-2"
- d="m 97.917969,157.99219 c -1.58517,-0.0121 -3.159728,0.54254 -4.271485,1.65429 l -3.5,3.5 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 0 0 0.707032,0 l 3.25,-3.25 c 0.584908,-0.58491 1.581654,-0.89809 2.345703,-0.69336 0.801559,0.21477 1.425851,0.83907 1.640621,1.64062 0.20473,0.76404 -0.108435,1.76078 -0.693356,2.3457 l -3.25,3.25 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 0 0 0.707032,0 l 3.474604,-3.47657 a 0.50005,0.50005 0 0 0 0.0254,-0.0234 0.50005,0.50005 0 0 0 0.12109,-0.18946 c 2.06467,-2.25524 2.04105,-6.1641 -0.21875,-8.42383 -1.15788,-1.15791 -2.752722,-1.73596 -4.337891,-1.74804 z m -0.0078,1.0332 c 1.340871,0.01 2.694311,0.47748 3.638671,1.42188 1.8888,1.88873 1.87387,5.423 0.0977,7.19921 L 98.5,170.79297 97.207031,169.5 l 2.896489,-2.89648 c 0.84012,-0.84012 1.27,-2.1299 0.95312,-3.3125 -0.30683,-1.14511 -1.202555,-2.04084 -2.347656,-2.34766 -1.182591,-0.31687 -2.472368,0.11299 -3.3125,0.95312 L 92.5,164.79297 91.207031,163.5 l 3.146485,-3.14648 c 0.888243,-0.88825 2.21577,-1.33772 3.55664,-1.32813 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- id="path20705"
- d="m 34.5,578 c -1.48507,0 -2.8535,0.46731 -3.86133,1.33594 C 29.63084,580.20456 29,581.48473 29,583 v 3.5 c 0,1.66667 0.001,2.82293 -0.89062,3.9375 -0.0709,0.0887 -0.10946,0.19893 -0.10938,0.3125 v 0.75 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 H 29 c 1.04885,0 2.13736,-0.63444 3.45898,-2.04297 l 1.66797,1.875 c 0.19883,0.22274 0.54727,0.22274 0.7461,0 l 1.62695,-1.83008 1.62695,1.83008 c 0.0947,0.10662 0.23044,0.16774 0.37305,0.16797 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 -1 -5.5 c 0,-1.51527 -0.63084,-2.79544 -1.63867,-3.66406 C 37.3535,578.46731 35.98507,578 34.5,578 Z m -3.00781,4 c 0.1353,-0.002 0.26563,0.0508 0.36133,0.14648 l 2,2 c 0.31479,0.315 0.09181,0.85335 -0.35352,0.85352 h -2 c -0.27613,-3e-5 -0.49997,-0.22387 -0.5,-0.5 v -2 c -10e-6,-0.27311 0.21911,-0.496 0.49219,-0.5 z m 5.99219,0 c 0.2822,-0.009 0.51573,0.21765 0.51562,0.5 v 2 c -3e-5,0.27613 -0.22387,0.49997 -0.5,0.5 h -2 c -0.44532,-1.7e-4 -0.66831,-0.53852 -0.35352,-0.85352 l 2,-2 c 0.0899,-0.0901 0.21072,-0.14248 0.3379,-0.14648 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path13646-9"
- d="m 405.50174,437 a 0.50005,0.50005 0 0 0 -0.33203,0.84375 c 1.3239,1.43817 3.0824,4.1582 6.3457,4.1582 3.26331,0 5.02376,-2.72003 6.34766,-4.1582 a 0.50037481,0.50037481 0 1 0 -0.73633,-0.67773 c -1.43556,1.55946 -2.90607,3.83593 -5.61133,3.83593 -2.70525,0 -4.17576,-2.27647 -5.61132,-3.83593 A 0.50005,0.50005 0 0 0 405.50174,437 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
- transform="translate(315,-0.999996)"
- id="g13630-2"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g4304"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-17">
<path
inkscape:connector-curvature="0"
- d="m 164.50781,224 a 0.50004997,0.50004997 0 0 1 0.43164,0.27148 c 1.44011,2.71955 1.43779,6.74164 -0.008,9.45899 a 0.50022794,0.50022794 0 1 1 -0.88281,-0.4707 c 1.24398,-2.33836 1.24519,-6.17912 0.006,-8.51954 A 0.50004997,0.50004997 0 0 1 164.50781,224 Z m -1.99609,1.99805 a 0.50004997,0.50004997 0 0 1 0.49219,0.50586 v 4.99218 a 0.50004997,0.50004997 0 1 1 -1,0 v -4.99218 a 0.50004997,0.50004997 0 0 1 0.50781,-0.50586 z M 159.25,223 c -0.1326,2e-5 -0.25976,0.0527 -0.35352,0.14648 L 156.04297,226 H 154.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.54297 l 2.85351,2.85352 c 0.0938,0.0938 0.22092,0.14646 0.35352,0.14648 h 0.25 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 223.78125 223.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path13628-2" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.5,158 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 6.5,3 c 2.20237,0 4,1.79764 4,4 0,2.20237 -1.79763,4 -4,4 -2.20236,0 -4,-1.79763 -4,-4 0,-2.20236 1.79764,-4 4,-4 z"
+ id="rect13348" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path13642-1"
- d="m 453.5,222 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 450.29297,225 H 448.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.79297 l 2.85351,2.85352 A 0.50005,0.50005 0 0 0 453.5,234 h 1 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 222.78125 222.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 454 v 10 h -0.29297 l -2.85351,-2.85352 A 0.50005,0.50005 0 0 0 450.5,230 H 449 v -4 h 1.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g14825-7"
- transform="translate(-189,-315)">
+ id="g14472"
+ transform="translate(-42)"
+ inkscape:label="H-16">
<path
- sodipodi:nodetypes="cccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path14782-1"
- d="m 415.5,452.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.00781 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.00781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.00781 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -10,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.00781 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.00781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.00781 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000036;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000248;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 373.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -10.5,9 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
+ id="rect14387"
+ inkscape:connector-curvature="0" />
<path
- inkscape:connector-curvature="0"
- id="path14818-4"
- d="m 409.49219,454.00781 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 l 0.008,3 a 0.50005,0.50005 0 1 0 1,-0.002 l -0.006,-2.49805 h 1.49805 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.5 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99804,2.98828 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3.00782 a 0.50005,0.50005 0 1 0 0.70704,0.70508 l 3,-3.00586 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 416.49219,458 A 0.50005,0.50005 0 0 0 416,458.50781 v 2.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.49805 L 411.50195,463 a 0.50005,0.50005 0 1 0 -0.004,1 l 3,0.008 a 0.50005,0.50005 0 0 0 0.50195,-0.5 v -1.5 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 416.49219,458 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 366.49219,160.99219 a 0.50005,0.50005 0 0 0 -0.31641,0.12109 0.50005,0.50005 0 0 0 -0.0195,0.0156 0.50005,0.50005 0 0 0 -0.0176,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 366,161.58203 V 162.5 a 0.50005,0.50005 0 1 0 1,0 V 162 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.008 z m 7,0 A 0.50005,0.50005 0 0 0 373.41797,161 H 372.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.91992 a 0.50005,0.50005 0 0 0 -0.11328,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.11133 z M 369.5,161 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -3.00781,2.99219 A 0.50005,0.50005 0 0 0 366,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7,0 A 0.50005,0.50005 0 0 0 373,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -7,3 A 0.50005,0.50005 0 0 0 366,167.5 v 0.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 366.58203,169 H 367.5 a 0.50005,0.50005 0 1 0 0,-1 H 367 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 7,0 A 0.50005,0.50005 0 0 0 373,167.5 v 0.5 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.0312 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.004 A 0.50005,0.50005 0 0 0 374,168.41797 V 167.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 369.5,168 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14452"
+ inkscape:connector-curvature="0" />
</g>
<g
- id="g19296"
- transform="translate(850,-280)"
- style="fill:#ffffff" />
- <path
- inkscape:connector-curvature="0"
- id="path19316"
- d="m 541.57031,410.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.26368,1.26367 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.26367,-1.26368 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.26368,1.26367 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.25195,-1.25196 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -8.08008,6.97851 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1.25,1.25 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.23829,-1.23828 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -1.25,1.25 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.25,-1.25 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- id="path19349"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 534.23047,436.74023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -1.47656,1.47656 c -0.71563,0.66862 -1.1007,1.61087 -1.04883,2.55664 0.0519,0.94577 0.50998,1.86545 1.27539,2.63086 0.76642,0.76642 1.68942,1.21503 2.6289,1.25977 0.93949,0.0447 1.85838,-0.33299 2.53516,-1.00977 l 1.5,-1.5 a 1.0001,1.0001 0 1 0 -1.41406,-1.41406 l -1.5,1.5 c -0.32323,0.32322 -0.65433,0.4455 -1.02735,0.42773 -0.37301,-0.0178 -0.82501,-0.19415 -1.30859,-0.67773 -0.48459,-0.48459 -0.6709,-0.9542 -0.69141,-1.32813 -0.0205,-0.37392 0.0941,-0.68177 0.41797,-0.98437 a 1.0001,1.0001 0 0 0 0.0234,-0.0234 l 1.5,-1.5 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z m 6.84765,-5.70703 c -0.93948,-0.0447 -1.85838,0.33299 -2.53515,1.00977 l -1.5,1.5 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 1.5,-1.5 c 0.32322,-0.32322 0.65433,-0.4455 1.02734,-0.42773 0.37302,0.0178 0.82502,0.19415 1.3086,0.67773 0.48459,0.48459 0.6709,0.9542 0.6914,1.32813 0.0205,0.37392 -0.0941,0.68177 -0.41796,0.98437 a 1.0001,1.0001 0 0 0 -0.0234,0.0234 l -1.5,1.5 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 1.47656,-1.47656 c 0.71562,-0.66862 1.1007,-1.61087 1.04883,-2.55664 -0.0519,-0.94577 -0.50998,-1.86545 -1.27539,-2.63086 -0.76642,-0.76642 -1.68942,-1.21503 -2.62891,-1.25977 z m -1.09765,3.95703 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -4,4 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 4,-4 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 432.49961,433 c -3.27784,-9.4e-4 -5.036,2.7211 -6.36328,4.16211 -0.17644,0.19146 -0.17644,0.48627 0,0.67773 1.3275,1.44124 3.08593,4.15993 6.36328,4.16211 3.27801,0.002 5.03608,-2.72118 6.36328,-4.16211 0.17644,-0.19146 0.17644,-0.48627 0,-0.67773 -1.32741,-1.44115 -3.08573,-4.16117 -6.36328,-4.16211 z m 0,1 a 3.4999952,3.4999933 0 0 1 3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,-3.5 3.4999952,3.4999933 0 0 1 3.5,-3.5 z m 0,2 a 1.4999952,1.4999944 0 0 0 -1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,-1.5 1.4999952,1.4999944 0 0 0 -1.5,-1.5 z"
- id="path19347-7" />
- <g
- id="g19953"
- transform="translate(823.99998,415.99995)"
- style="display:inline;fill:#ffffff;enable-background:new">
- <path
- inkscape:connector-curvature="0"
- id="path19355-8-8"
- d="m -725.49998,-278.99995 c -2.725,0 -4.12655,1.87775 -5.35938,3.15234 -0.18751,0.19385 -0.18751,0.50147 0,0.69532 1.23247,1.2748 2.63438,3.15234 5.35938,3.15234 2.725,0 4.12648,-1.87882 5.35938,-3.15625 0.18625,-0.1936 0.18624,-0.49976 0,-0.69336 -1.23336,-1.2779 -2.63506,-3.15039 -5.35938,-3.15039 z m 0,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m 0,1 c -0.83435,0 -1.5,0.66565 -1.5,1.5 0,0.83435 0.66565,1.5 1.5,1.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="g4297"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-15">
<path
- sodipodi:nodetypes="cccccccccc"
- inkscape:connector-curvature="0"
- id="path19363-8-5"
- d="m -733.49805,-273 c -0.35971,-10e-4 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0267 -0.12812,-0.0406 -0.19532,-0.041 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 304.5,158 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 4.5,5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -8.5,2 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
+ id="rect13801"
+ inkscape:connector-curvature="0" />
</g>
<g
- id="g19964"
- transform="translate(823.99998,415.99995)"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14467"
+ transform="translate(-63)"
+ inkscape:label="H-14">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 347.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2.5 h -1.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m -2,3 h 2 v 2 h -2 z m 4,1 h 2 v 2 h -2 z"
+ id="rect14393"
inkscape:connector-curvature="0"
- id="path20627-2"
- d="m -704.49998,-278.99995 c -2.725,0 -4.12655,1.87775 -5.35938,3.15234 -0.18751,0.19385 -0.1875,0.50147 0,0.69532 1.23247,1.2748 2.63438,3.15234 5.35938,3.15234 2.725,0 4.12648,-1.87882 5.35938,-3.15625 0.18625,-0.1936 0.18624,-0.49976 0,-0.69336 -1.23336,-1.2779 -2.63506,-3.15039 -5.35938,-3.15039 z m 0,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m 0,1 c -0.83435,0 -1.5,0.66565 -1.5,1.5 0,0.83435 0.66565,1.5 1.5,1.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc" />
<path
- inkscape:connector-curvature="0"
- id="path20671-8"
- d="m -712.49805,-273 a 0.50005,0.50005 0 0 0 -0.46093,0.69727 l 3,7 a 0.50005,0.50005 0 1 0 0.91796,-0.39454 l -2.50781,-5.85156 5.85156,2.50781 a 0.50005,0.50005 0 1 0 0.39454,-0.91796 l -7,-3 a 0.50005,0.50005 0 0 0 -0.19532,-0.041 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 342.49219,157.99219 a 0.50005,0.50005 0 0 0 -0.31641,0.12109 0.50005,0.50005 0 0 0 -0.0195,0.0156 0.50005,0.50005 0 0 0 -0.0176,0.0176 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.004 0.50005,0.50005 0 0 0 -0.0274,0.0371 0.50005,0.50005 0 0 0 -0.002,0.004 A 0.50005,0.50005 0 0 0 342,158.58203 V 159.5 a 0.50005,0.50005 0 1 0 1,0 V 159 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.008 z m 13,0 A 0.50005,0.50005 0 0 0 355.41797,158 H 354.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.91992 a 0.50005,0.50005 0 0 0 -0.11328,-0.4043 0.50005,0.50005 0 0 0 -0.002,-0.004 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.0312 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.11133 z M 345.5,158 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -9.00781,2.99219 A 0.50005,0.50005 0 0 0 342,161.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,161.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,164.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,167.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,167.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -13,3 A 0.50005,0.50005 0 0 0 342,170.5 v 0.91992 a 0.50005,0.50005 0 0 0 0.11328,0.4043 0.50005,0.50005 0 0 0 0.0156,0.0195 0.50005,0.50005 0 0 0 0.0176,0.0176 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.0312 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 342.58203,172 H 343.5 a 0.50005,0.50005 0 1 0 0,-1 H 343 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 355,170.5 v 0.5 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.0312 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.0274,-0.0371 0.50005,0.50005 0 0 0 0.002,-0.004 0.50005,0.50005 0 0 0 0.074,-0.35325 V 170.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 345.5,171 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14460"
+ inkscape:connector-curvature="0" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path19886"
- d="m 489.50195,227 a 0.50005,0.50005 0 0 0 -0.33203,0.84375 c 1.3239,1.43817 3.0824,4.1582 6.3457,4.1582 3.26331,0 5.02376,-2.72003 6.34766,-4.1582 a 0.50037481,0.50037481 0 1 0 -0.73633,-0.67773 c -1.43556,1.55946 -2.90607,3.83593 -5.61133,3.83593 -2.70525,0 -4.17576,-2.27647 -5.61132,-3.83593 A 0.50005,0.50005 0 0 0 489.50195,227 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
- transform="matrix(-1,0,0,1,970.03864,-190)"
- id="g19901"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g28075-6"
+ transform="rotate(180,339.0035,333)"
+ inkscape:label="H-13">
+ <g
+ transform="matrix(1,0,0,-1,0,999)"
+ style="opacity:0.7;fill:#ffffff"
+ id="g28071-5">
+ <path
+ inkscape:connector-curvature="0"
+ id="path28067-0"
+ transform="matrix(-1,0,0,1,358.007,333)"
+ d="m -61.992188,164 v 7 h 1 v -3 h 2 v 1 h 1 v -1 h 2 v 3 h 1 v -3 h 2 v 1 h 1 v -1 h 2 v 3 h 1 v -7 h -1 v 3 h -2 v -1 h -1 v 1 h -2 v -3 h -1 v 3 h -2 v -1 h -1 v 1 h -2 v -3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
<path
+ sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 516.5,223 c -3.27784,-9.4e-4 -5.036,2.7211 -6.36328,4.16211 -0.17644,0.19146 -0.17644,0.48627 0,0.67773 1.32749,1.44124 3.08593,4.16011 6.36328,4.16211 3.27801,0.002 5.03607,-2.72118 6.36328,-4.16211 0.17644,-0.19146 0.17644,-0.48627 0,-0.67773 C 521.53587,225.72096 519.77754,223.00094 516.5,223 Z m 0,1 a 3.4999952,3.4999933 0 0 1 3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,3.5 3.4999952,3.4999933 0 0 1 -3.5,-3.5 3.4999952,3.4999933 0 0 1 3.5,-3.5 z m 0,2 a 1.4999952,1.4999944 0 0 0 -1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,1.5 1.4999952,1.4999944 0 0 0 1.5,-1.5 1.4999952,1.4999944 0 0 0 -1.5,-1.5 z"
- transform="matrix(-1,0,0,1,970.03864,190)"
- id="path19890" />
+ id="path28073-8"
+ d="m 406.5,504 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(1e-5,4e-6)"
- id="g20019-5"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
- <path
- inkscape:connector-curvature="0"
- id="path20013-1"
- d="m 365.5,433 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8.5 c 0,1.09865 0.90135,2 2,2 1.09865,0 2,-0.90135 2,-2 v -8.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 8 c 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="g4316"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-12">
<path
- id="path20015-6"
- transform="translate(718,837)"
- d="m -345.50781,-403 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 L -348,-400.70703 v 1.41406 l 2.5,-2.5 1.29297,1.29297 -3.79297,3.79297 v 1.41406 l 4.85352,-4.85351 a 0.50005,0.50005 0 0 0 0,-0.70704 l -2,-2 A 0.50005,0.50005 0 0 0 -345.50781,-403 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 241.49219,158.00781 c -0.1326,3e-5 -0.25982,0.0527 -0.35352,0.14649 l -4,4 c -0.094,0.0938 -0.14648,0.22091 -0.14648,0.35351 v 9 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.1326,-3e-5 0.25971,-0.0527 0.35351,-0.14648 l 4,-4 c 0.094,-0.0938 0.14649,-0.22092 0.14649,-0.35352 v -9 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m 7.48828,0.98242 a 1.0001,1.0001 0 0 1 0.72656,1.7168 L 247,163.41406 V 170 a 1.0001,1.0001 0 1 1 -2,0 v -6 h -6 a 1.0001,1.0001 0 1 1 0,-2 h 6.58594 l 2.70703,-2.70703 a 1.0001,1.0001 0 0 1 0.6875,-0.30274 z"
+ id="path28084-2"
inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="ccccccccccc"
- inkscape:connector-curvature="0"
- id="path20017-8"
- d="m 373.25,440 -1,1 H 375 v 2 h -4.75 l -1,1 h 6.25 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(483,-126)"
- id="g11187"
- style="display:inline;fill:#ffffff;enable-background:new">
+ id="g4313"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-11">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 217.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path28082-0"
inkscape:connector-curvature="0"
- id="path10969"
- transform="translate(-483,126)"
- d="m 533.49219,157.99219 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 533,159.70703 v 7.57422 c -0.59355,0.34821 -1,0.9856 -1,1.71875 0,1.09865 0.90135,2 2,2 0.73315,0 1.37054,-0.40645 1.71875,-1 h 7.57422 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 543.29297,169 H 536 c 0,-1.09865 -0.90135,-2 -2,-2 v -7.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.95704,-1.95703 a 0.50005,0.50005 0 0 0 -0.40429,-0.19726 z M 534,168 c 0.55821,0 1,0.44179 1,1 0,0.55821 -0.44179,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.55821 0.44179,-1 1,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccccc" />
</g>
<g
- transform="translate(42.000003,4e-6)"
- id="g20430-5"
- style="display:inline;fill:#ffffff;enable-background:new" />
- <g
- id="g6336"
- style="fill:#ffffff">
- <path
- inkscape:connector-curvature="0"
- id="path17349-5"
- d="m 156.49609,393.24609 a 0.50005,0.50005 0 0 0 -0.27343,0.91993 c 0.927,0.618 2.37713,0.83398 3.77734,0.83398 1.39708,0 2.84978,-0.21561 3.77734,-0.83398 a 0.50005,0.50005 0 1 0 -0.55468,-0.83204 C 162.65022,393.71561 161.2722,394 160,394 c -1.27563,0 -2.64966,-0.28402 -3.22266,-0.66602 a 0.50005,0.50005 0 0 0 -0.28125,-0.0879 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="g16810"
+ transform="rotate(90,48.5,-204.5)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="H-10">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 412.5,-364 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 9,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path16808"
inkscape:connector-curvature="0"
- id="path17351"
- d="m 160,389 c -1.5802,0 -3.01318,0.28529 -4.0957,0.77734 -0.54126,0.24603 -0.9977,0.54261 -1.33789,0.90821 C 154.22621,391.05115 154,391.5062 154,392 v 3 5 c 0,0.4938 0.22621,0.94885 0.56641,1.31445 0.34019,0.3656 0.79663,0.66218 1.33789,0.90821 C 156.98682,402.71471 158.4198,403 160,403 c 1.5802,0 3.01318,-0.28529 4.0957,-0.77734 0.54126,-0.24603 0.9977,-0.54261 1.33789,-0.90821 C 165.77379,400.94885 166,400.4938 166,400 v -5 -3 c 0,-0.4938 -0.22621,-0.94885 -0.56641,-1.31445 -0.34019,-0.3656 -0.79663,-0.66218 -1.33789,-0.90821 C 163.01318,389.28529 161.5802,389 160,389 Z m 0,1 c 1.45737,0 2.77356,0.27473 3.68164,0.6875 0.45404,0.20638 0.8031,0.4471 1.01953,0.67969 C 164.9176,391.59978 165,391.80344 165,392 v 3 5 c 0,0.19656 -0.0824,0.40022 -0.29883,0.63281 -0.21643,0.23259 -0.56549,0.47331 -1.01953,0.67969 C 162.77356,401.72527 161.45737,402 160,402 c -1.45737,0 -2.77356,-0.27473 -3.68164,-0.6875 -0.45404,-0.20638 -0.8031,-0.4471 -1.01953,-0.67969 C 155.0824,400.40022 155,400.19656 155,400 v -5 -3 c 0,-0.19656 0.0824,-0.40022 0.29883,-0.63281 0.21643,-0.23259 0.56549,-0.47331 1.01953,-0.67969 C 157.22644,390.27473 158.54263,390 160,390 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="cccccccccccccccccc" />
</g>
<g
- id="g6344"
- style="fill:#ffffff">
- <path
- inkscape:connector-curvature="0"
- id="path17355-2"
- d="m 181,390 c -2.19521,0 -4.16987,0.64081 -5.61914,1.70898 -1.44928,1.06818 -2.38087,2.59156 -2.38086,4.29102 0,1.69945 0.93159,3.22284 2.38086,4.29102 C 176.83013,401.35919 178.80479,402 181,402 c 2.19521,0 4.16987,-0.64081 5.61914,-1.70898 C 188.06841,399.22284 189,397.69945 189,396 c 0,-1.69945 -0.93159,-3.22284 -2.38086,-4.29102 C 185.16987,390.64081 183.19522,390 181,390 Z m 0,1 c 1.99941,0 3.77332,0.59085 5.02539,1.51367 C 187.27746,393.4365 188,394.66345 188,396 c 0,1.33655 -0.72254,2.5635 -1.97461,3.48633 C 184.77332,400.40915 182.99941,401 181,401 c -1.99941,0 -3.77332,-0.59085 -5.02539,-1.51367 C 174.72254,398.5635 174,397.33655 174,396 c 0,-1.33654 0.72254,-2.5635 1.97461,-3.48633 C 177.22668,391.59085 179.00059,391 181,391 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="g4310"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-9">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 175.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -8,8 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path28080-3"
inkscape:connector-curvature="0"
- id="path17357"
- d="M 178.49219,394.49219 A 0.50005,0.50005 0 0 0 178,395.00195 v 0.25 c 5.5e-4,0.26762 0.10104,0.43267 0.23438,0.61719 0.13369,0.18504 0.32089,0.36854 0.5664,0.53516 0.49103,0.33322 1.21831,0.59296 2.19727,0.5957 0.98079,0.003 1.71165,-0.25661 2.20312,-0.5918 0.24574,-0.16759 0.43113,-0.35326 0.56445,-0.53906 0.13296,-0.18529 0.23383,-0.34989 0.23438,-0.61719 v -0.002 -0.24805 a 0.50005,0.50005 0 1 0 -1,-0.004 v 0.2521 c 0,-0.11242 0.009,-0.0414 -0.0469,0.0371 -0.0564,0.0786 -0.16044,0.18856 -0.3164,0.29492 -0.31192,0.21273 -0.83026,0.42022 -1.63477,0.41797 -0.80517,-0.002 -1.32795,-0.21164 -1.64062,-0.42383 -0.15634,-0.10609 -0.26023,-0.21522 -0.31641,-0.29297 C 178.98874,395.20545 179,395.13726 179,395.25 v -0.25195 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
</g>
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
- id="rect17374-9"
- width="12.937499"
- height="12.937502"
- x="111.0625"
- y="390.0625" />
<g
- id="g6320"
- style="fill:#ffffff">
- <path
- inkscape:connector-curvature="0"
- id="rect17377-5"
- d="m 111.4668,389 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13.0957 a 0.50005,0.50005 0 0 0 0.5,0.5 H 124.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 389.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 H 124 v 12.0957 h -12.0332 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(-230.993,-230.993)"
+ id="g27963"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="H-8">
+ <g
+ id="g27959"
+ style="opacity:0.6;fill:#ffffff"
+ transform="translate(126)">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 268.49219,388.99219 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 2.49609 l -2.50586,-0.004 c -0.67605,-0.0108 -0.67808,1.00811 -0.002,1 L 268,392.99609 V 399 h -6.00391 l -0.004,-2.50781 c 0.008,-0.67608 -1.01082,-0.67405 -1,0.002 L 260.99609,399 H 258.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 2.49609 l 0.004,2.5 c -0.01,0.67616 1.00956,0.67616 1,0 l -0.004,-2.5 H 268 v 2.5 c -0.01,0.67616 1.00956,0.67616 1,0 V 400 h 2.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 269 v -6.00391 l 2.5,0.004 c 0.67616,0.01 0.67616,-1.00956 0,-1 l -2.5,-0.004 V 389.5 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z"
+ id="path27957"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ </g>
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 385.5,390 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27961"
inkscape:connector-curvature="0"
- id="path17381"
- d="M 115.49219,390.99219 A 0.50005,0.50005 0 0 0 115,391.5 v 1.5 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 399 h 4 v 1.5 a 0.50005,0.50005 0 1 0 1,0 V 399 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 121 v -4 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 121 v -1.5 a 0.50005,0.50005 0 1 0 -1,0 v 1.5 h -4 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 116,394 h 4 v 4 h -4 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccccc" />
</g>
<g
- id="g6312"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g8419-9"
+ transform="translate(1279,-241)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="H-7">
+ <rect
+ style="display:inline;opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="rect8368-4"
+ width="16"
+ height="16"
+ x="-1148"
+ y="398" />
<path
- inkscape:connector-curvature="0"
- id="path17390-7"
- mask="none"
- d="m 96,389 a 0.50005,0.50005 0 0 0 -0.240234,0.0605 l -5.5,3 A 0.50005,0.50005 0 0 0 90,392.5 v 7 a 0.50005,0.50005 0 0 0 0.259766,0.43945 l 5.5,3 A 0.50005,0.50005 0 0 0 96,403 h 1 a 0.50005,0.50005 0 0 0 0.240234,-0.0605 l 5.499996,-3 A 0.50005,0.50005 0 0 0 103,399.5 v -7 a 0.50005,0.50005 0 0 0 -0.25977,-0.43945 l -5.499996,-3 A 0.50005,0.50005 0 0 0 97,389 Z m 0.126953,1 h 0.746094 L 102,392.79688 v 6.40624 L 96.873047,402 H 96.126953 L 91,399.20312 v -6.40624 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -1140.8984,400.01367 c -2.0857,0.12882 -4.0362,1.26078 -5.1621,3.1211 -1.5012,2.48042 -1.1755,5.66201 0.7968,7.78711 1.9724,2.12509 5.1198,2.68733 7.7051,1.375 2.5853,-1.31234 3.9907,-4.18482 3.4395,-7.03126 a 0.50030025,0.50030025 0 1 0 -0.9825,0.18946 c 0.4673,2.4126 -0.7188,4.8369 -2.9101,5.94922 -2.1913,1.11231 -4.8478,0.63909 -6.5195,-1.16211 -1.6718,-1.8012 -1.9463,-4.48748 -0.6739,-6.58985 1.2724,-2.10236 3.7774,-3.10263 6.1485,-2.45703 a 0.50104088,0.50104088 0 1 0 0.2636,-0.96679 c -0.6993,-0.19043 -1.4102,-0.25779 -2.1054,-0.21485 z"
+ id="ellipse8370-9"
+ inkscape:connector-curvature="0" />
<path
- inkscape:connector-curvature="0"
- id="path17400"
- d="m 92.5,392 a 0.50005,0.50005 0 1 0 0,1 H 98.513672 100.5 a 0.50005,0.50005 0 1 0 0,-1 z m 6.013672,1 a 0.50005,0.50005 0 0 0 -0.404297,0.1875 l -3.595703,4.49609 -2.613281,-3.48437 a 0.50078095,0.50078095 0 1 0 -0.800782,0.60156 l 3,4 A 0.50005,0.50005 0 0 0 94.486328,399 a 0.50005,0.50005 0 0 0 0.404297,-0.1875 l 3.595703,-4.49609 2.613282,3.48437 a 0.50078015,0.50078015 0 1 0 0.80078,-0.60156 l -2.999999,-4 A 0.50005,0.50005 0 0 0 98.513672,393 Z m -4.027344,6 H 92.5 a 0.50005,0.50005 0 1 0 0,1 h 8 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 144.98047,157.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -3.71289,3.71484 c -0.0265,-0.001 -0.0513,-0.008 -0.0781,-0.008 -0.8224,0 -1.5,0.67765 -1.5,1.5 0,0.82235 0.6776,1.5 1.5,1.5 0.8224,0 1.5,-0.67765 1.5,-1.5 0,-0.0274 -0.006,-0.0531 -0.008,-0.0801 l 3.71289,-3.71289 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ transform="translate(-1279,241)"
+ id="rect8385-9"
+ inkscape:connector-curvature="0" />
</g>
- <rect
- y="389"
- x="69"
- height="14"
- width="14"
- id="rect17416-6"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
<g
- id="g6304"
- style="fill:#ffffff">
+ id="g4301"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-6">
<path
- inkscape:connector-curvature="0"
- id="path17418-8"
- d="m 76,388.9375 c -3.894591,0 -7.0625,3.1679 -7.0625,7.0625 0,3.89459 3.167908,7.0625 7.0625,7.0625 3.894592,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.8946 -3.167909,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.354153,0 6.0625,2.70834 6.0625,6.0625 0,3.35415 -2.708348,6.0625 -6.0625,6.0625 -3.354152,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-3.35416 2.708347,-6.0625 6.0625,-6.0625 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 114.49219,166.99219 A 0.50005,0.50005 0 0 0 114,167.5 v 1.5 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 1 0 1,0 V 170 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path4913-5-0"
+ inkscape:connector-curvature="0" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 118.89062,157.9668 c -1.59478,-0.0195 -3.16997,0.53887 -4.2539,1.6914 l -0.74024,0.73828 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.5,-0.5 c 0.5849,-0.58491 1.58165,-0.89809 2.3457,-0.69336 0.80156,0.21477 1.42585,0.83907 1.64062,1.64062 0.20473,0.76404 -0.10844,1.76078 -0.69336,2.3457 l -0.5,0.5 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.75,-0.75 c 2.22378,-2.22379 2.21818,-6.29752 -0.0977,-8.61329 -1.15793,-1.15796 -2.77045,-1.75392 -4.36524,-1.77343 z m -6.14848,3.7832 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -1.25,1.25 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.25,-1.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.226,-0.14854 -0.36128,-0.14648 z m 6.00019,6 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -1.25,1.25 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 2,2 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 1.25,-1.25 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.22612,-0.14859 -0.36147,-0.14648 z"
+ id="path21201-1"
inkscape:connector-curvature="0"
- id="path17424"
- d="m 75.476562,390.74414 a 0.50005,0.50005 0 0 0 -0.40039,0.24024 C 74.184416,392.40936 74,393.97991 74,396 c 0,0.33476 0.05553,0.60654 0.06836,0.92188 -1.166939,-0.0798 -2.112698,-0.42664 -3.201171,-1.52344 a 0.50005,0.50005 0 1 0 -0.710938,0.70312 c 1.257685,1.26731 2.545083,1.75219 3.986328,1.83008 0.125352,1.11893 0.352857,2.1649 0.933594,3.08594 a 0.50122772,0.50122772 0 1 0 0.847656,-0.53516 C 75.471077,399.76437 75.263567,398.92779 75.142578,398 H 76 c 2.575016,3.5e-4 3.847653,-0.61523 4.722656,-1.05273 a 0.50005,0.50005 0 1 0 -0.445312,-0.89454 C 79.402347,396.49023 78.424978,397.00033 76,397 H 75.072266 C 75.055487,396.65897 75,396.38014 75,396 c 0,-1.96025 0.172858,-3.28436 0.923828,-4.48438 a 0.50005,0.50005 0 0 0 -0.447266,-0.77148 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccscccccccccccccccccccccccccccccc" />
</g>
<g
- id="g6296"
- style="fill:#ffffff">
- <path
- inkscape:connector-curvature="0"
- id="path8006-3-4"
- d="m 30.5,389 a 0.50005,0.50005 0 0 0 -0.353516,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 27,392.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 41,399.5 v -10 A 0.50005,0.50005 0 0 0 40.5,389 Z m 0.207031,1 H 40 v 9.29297 L 37.292969,402 H 28 v -9.29297 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="g4307"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-5">
<path
inkscape:connector-curvature="0"
- id="path8009-8"
- d="m 39.490234,389.98828 a 0.50005,0.50005 0 0 0 -0.34375,0.15234 L 37.292969,392 H 29.5 a 0.50005,0.50005 0 1 0 0,1 H 37 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -7.79297 l 1.853516,-1.86133 a 0.50005,0.50005 0 0 0 -0.363282,-0.85742 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path20072-2"
+ d="m 97.917969,157.99219 c -1.58517,-0.0121 -3.159728,0.54254 -4.271485,1.65429 l -3.5,3.5 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 0 0 0.707032,0 l 3.25,-3.25 c 0.584908,-0.58491 1.581654,-0.89809 2.345703,-0.69336 0.801559,0.21477 1.425851,0.83907 1.640621,1.64062 0.20473,0.76404 -0.108435,1.76078 -0.693356,2.3457 l -3.25,3.25 a 0.50005,0.50005 0 0 0 0,0.70704 l 2,2 a 0.50005,0.50005 0 0 0 0.707032,0 l 3.474604,-3.47657 a 0.50005,0.50005 0 0 0 0.0254,-0.0234 0.50005,0.50005 0 0 0 0.12109,-0.18946 c 2.06467,-2.25524 2.04105,-6.1641 -0.21875,-8.42383 -1.15788,-1.15791 -2.752722,-1.73596 -4.337891,-1.74804 z m -0.0078,1.0332 c 1.340871,0.01 2.694311,0.47748 3.638671,1.42188 1.8888,1.88873 1.87387,5.423 0.0977,7.19921 L 98.5,170.79297 97.207031,169.5 l 2.896489,-2.89648 c 0.84012,-0.84012 1.27,-2.1299 0.95312,-3.3125 -0.30683,-1.14511 -1.202555,-2.04084 -2.347656,-2.34766 -1.182591,-0.31687 -2.472368,0.11299 -3.3125,0.95312 L 92.5,164.79297 91.207031,163.5 l 3.146485,-3.14648 c 0.888243,-0.88825 2.21577,-1.33772 3.55664,-1.32813 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- id="g6397"
- style="fill:#ffffff">
+ id="g28061"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(42,63)"
+ inkscape:label="H-4">
<path
- inkscape:connector-curvature="0"
- id="rect12565-1-6"
- d="m 258.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 A 0.50005,0.50005 0 0 0 272,45.5 V 41 h -1 v 4 H 259 V 33 h 12 v 1 h 1 V 32.5 A 0.50005,0.50005 0 0 0 271.5,32 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 40.433594,95 a 0.55005501,0.55005501 0 0 0 -0.378906,0.166016 l -3.44336,3.445312 a 0.55005501,0.55005501 0 1 0 0.777344,0.777344 l 3.445312,-3.44336 A 0.55005501,0.55005501 0 0 0 40.433594,95 Z m -9.445313,9.44531 a 0.55005501,0.55005501 0 0 0 -0.376953,0.16602 l -3.445312,3.44336 a 0.55104336,0.55104336 0 1 0 0.779296,0.77929 l 3.44336,-3.44531 a 0.55005501,0.55005501 0 0 0 -0.400391,-0.94336 z"
+ id="path27971"
+ inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 261.5,35 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z m 0,2 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z m 0,2 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z"
- id="path12613-4-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 32.5,100 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path27982"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccc" />
+ sodipodi:nodetypes="ccccccccc" />
</g>
<g
- id="g6375"
- style="fill:#ffffff">
- <rect
- y="31.999996"
- x="27"
- height="14"
- width="14"
- id="rect12107-7"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
+ id="g27914"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-21)"
+ inkscape:label="H-3">
<path
- inkscape:connector-curvature="0"
- id="path12109-5"
- d="m 34,32 c -3.860074,0 -7,3.139926 -7,7 0,3.860083 3.139927,7 7,7 3.860082,0 7,-3.139918 7,-7 0,-3.860073 -3.139917,-7 -7,-7 z m 0,1 c 3.319643,0 6,2.680365 6,6 0,3.319644 -2.680356,6 -6,6 -3.319635,0 -6,-2.680357 -6,-6 0,-3.319634 2.680366,-6 6,-6 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 69.5,157.98633 a 0.50005,0.50005 0 0 0 -0.492188,0.50586 v 12.9082 a 0.50005,0.50005 0 0 0 0.08203,0.37695 0.50005,0.50005 0 0 0 0.002,0.004 0.50005,0.50005 0 0 0 0.0293,0.0352 0.50005,0.50005 0 0 0 0.002,0.004 0.50005,0.50005 0 0 0 0.03125,0.0332 0.50005,0.50005 0 0 0 0.02539,0.0215 0.50005,0.50005 0 0 0 0.01172,0.0117 0.50005,0.50005 0 0 0 0.0039,0.002 0.50005,0.50005 0 0 0 0.04102,0.0293 0.50005,0.50005 0 0 0 0.353516,0.0742 h 12.917968 a 0.50005,0.50005 0 1 0 0,-1 h -12.5 v -12.5 A 0.50005,0.50005 0 0 0 69.5,157.98633 Z"
+ id="path15133-4-4"
+ inkscape:connector-curvature="0" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 72.5,165 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path22120-2-1"
inkscape:connector-curvature="0"
- id="path12115-8"
- d="M 28.507812,38.244141 A 0.50005,0.50005 0 0 0 28.15625,39.101562 C 29.521925,40.47768 30.901684,41.000009 32.5,41 H 34 c 2.575017,3.52e-4 3.847654,-0.615233 4.722656,-1.052734 A 0.50005,0.50005 0 1 0 38.277344,39.052734 C 37.402346,39.490233 36.424977,40.000332 34,40 h -1.5 c -1.401674,7e-6 -2.403186,-0.362534 -3.632812,-1.601562 a 0.50005,0.50005 0 0 0 -0.359376,-0.154297 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccccc" />
</g>
<g
- id="g6383"
- style="fill:#ffffff">
+ id="g27942"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(-21)"
+ inkscape:label="H-2">
<path
- inkscape:connector-curvature="0"
- id="path12123-3"
- d="m 51.5,32 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -3,3 A 0.50005,0.50005 0 0 0 48,35.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.146484 l 3,-3 A 0.50005,0.50005 0 0 0 62,42.5 v -10 A 0.50005,0.50005 0 0 0 61.5,32 Z m 0.207031,1 H 61 v 9.292969 L 58.292969,45 H 49 v -9.292969 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 49.46875,159 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 11 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 10 h -10 z"
+ id="path26471-6-1"
+ inkscape:connector-curvature="0" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 53.5,163 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ id="path22120-2-1-2"
inkscape:connector-curvature="0"
- id="path12125-1"
- d="m 60.490234,32.988281 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 L 58.292969,35 H 50.5 a 0.50005,0.50005 0 1 0 0,1 H 58 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -7.792969 l 1.853516,-1.861328 a 0.50005,0.50005 0 0 0 -0.363282,-0.857422 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccccc" />
</g>
<g
- id="g6328"
- style="fill:#ffffff">
+ id="g7324"
+ transform="translate(-231.45606,21.458247)"
+ style="display:inline;enable-background:new"
+ inkscape:label="H-1">
<path
- inkscape:connector-curvature="0"
- id="path12377-5"
- d="m 135.5,389 a 0.50004997,0.50004997 0 0 0 -0.33008,0.12305 l -2,1.75 A 0.50004997,0.50004997 0 0 0 133,391.25 V 393 h -1.5 a 0.50004997,0.50004997 0 0 0 -0.5,0.5 v 1.5 c 0,0.98611 0.74054,1.6889 1.56836,1.91992 0.71525,0.19961 1.51421,0.0482 2.18359,-0.38476 L 136,397.93945 V 400.25 c 0,0.88889 0.39419,1.61848 0.96875,2.07812 C 137.54331,402.78777 138.275,403 139,403 c 0.725,0 1.45669,-0.21223 2.03125,-0.67188 C 141.60581,401.86848 142,401.13889 142,400.25 v -2.31055 l 1.24805,-1.40429 c 0.66938,0.43298 1.46834,0.58437 2.18359,0.38476 C 146.25946,396.6889 147,395.98611 147,395 v -1.5 A 0.50004997,0.50004997 0 0 0 146.5,393 H 145 v -1.75 a 0.50004997,0.50004997 0 0 0 -0.16992,-0.37695 l -2,-1.75 A 0.50004997,0.50004997 0 0 0 142.5,389 h -2 a 0.50004997,0.50004997 0 0 0 -0.35352,0.14648 L 139.29297,390 h -0.58594 l -0.85351,-0.85352 A 0.50004997,0.50004997 0 0 0 137.5,389 Z m 0.1875,1 h 1.60547 l 0.85351,0.85352 A 0.50004997,0.50004997 0 0 0 138.5,391 h 1 a 0.50004997,0.50004997 0 0 0 0.35352,-0.14648 L 140.70703,390 h 1.60547 L 144,391.47852 V 393.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1.5 v 1 c 0,0.51389 -0.32196,0.8111 -0.83789,0.95508 -0.39408,0.10997 -0.8212,-0.0629 -1.20703,-0.25 a 0.50004997,0.50004997 0 0 0 -0.82813,-0.53711 l -2,2.25 A 0.50004997,0.50004997 0 0 0 141,397.75 v 2.5 c 0,0.61111 -0.23081,1.00652 -0.59375,1.29688 C 140.04331,401.83723 139.525,402 139,402 c -0.525,0 -1.04331,-0.16277 -1.40625,-0.45312 C 137.23081,401.25652 137,400.86111 137,400.25 v -2.5 a 0.50004997,0.50004997 0 0 0 -0.12695,-0.33203 l -2,-2.25 a 0.50004997,0.50004997 0 0 0 -0.82813,0.53711 c -0.38583,0.18707 -0.81295,0.35997 -1.20703,0.25 C 132.32196,395.8111 132,395.51389 132,395 v -1 h 1.5 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -2.02344 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 244.01184,140.51071 c 1.65601,0 3,1.37486 3,3.04688 0,1.67201 -1.34399,3.04687 -3,3.04687 -1.65601,0 -3,-1.37486 -3,-3.04687 0,-1.67202 1.34399,-3.04688 3,-3.04688 z m 0,1 c -1.10534,0 -2,0.90526 -2,2.04688 0,1.14161 0.89466,2.04687 2,2.04687 1.10534,0 2,-0.90526 2,-2.04687 0,-1.14162 -0.89466,-2.04688 -2,-2.04688 z"
+ id="circle22836-6"
+ inkscape:connector-curvature="0" />
<path
- inkscape:connector-curvature="0"
- id="path12383"
- d="m 137,392 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.5,0.5 A 0.50005,0.50005 0 0 0 136,393 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.29297 L 137.20703,393 H 137.5 a 0.50005,0.50005 0 1 0 0,-1 z m 4,0 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -0.5,0.5 A 0.50005,0.50005 0 0 0 140,393 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.29297 L 141.20703,393 H 141.5 a 0.50005,0.50005 0 1 0 0,-1 z m -2.5,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 244.01184,137.51071 c -3.5093,0 -6,2.77253 -6,5.91992 v 7.08008 h -0.96094 a 0.50004991,0.50004991 0 1 0 0,1 h 1.46094 a 0.50004991,0.50004991 0 0 0 0.5,-0.5 v -7.58008 c 0,-2.62796 2.01002,-4.91992 5,-4.91992 2.99076,0 5,2.29197 5,4.91992 v 7.58008 a 0.50004991,0.50004991 0 0 0 0.5,0.5 h 1.46094 a 0.50004991,0.50004991 0 1 0 0,-1 h -0.96094 v -7.08008 c 0,-3.14741 -2.49004,-5.91992 -6,-5.91992 z"
+ id="path22838-0"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="translate(-15.954521,-1.3298229)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g26501-5-3"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path26499-8-9"
+ d="m 258.49962,136.9993 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 363.51562,184 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 185 h 12 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path10187-3-4"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 70.5,410 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.859375 l -0.824219,3.29883 a 0.50005,0.50005 0 0 0 -0.04102,0.16797 l -1.478516,5.91211 A 0.50005,0.50005 0 0 0 69.5,424 h 4.921875 a 0.50005,0.50005 0 0 0 0.160156,0 h 4.892578 a 0.50005,0.50005 0 0 0 0.484375,-0.37695 l 3.03711,-11.99024 a 0.50005,0.50005 0 0 0 -0.484375,-0.62304 l -4.90625,-0.006 a 0.50005,0.50005 0 0 0 -0.205078,0 L 74,411 v -0.5 A 0.50005,0.50005 0 0 0 73.5,410 Z m 0.5,1 h 2 v 2 h -0.921875 a 0.50005,0.50005 0 0 0 -0.160156,0 H 71 Z m 3,1 2.859375,0.004 -1.25,4.99609 h -3.96875 l 0.75,-3 H 73.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 3.888672,0.004 3.980469,0.006 -1.263672,4.99 H 76.640625 Z M 71.390625,418 h 3.96875 l -1.25,5 h -3.96875 z m 5,0 h 3.960937 l -1.265624,5 h -3.945313 z"
- id="path14034"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 184.49609,623.99414 a 0.50005,0.50005 0 0 0 -0.34961,0.85938 L 186.29297,627 h -10.58594 l 2.14649,-2.14648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -3,3 a 0.50005,0.50005 0 0 0 0,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 175.70703,628 h 10.58594 l -2.14649,2.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70704 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35743,-0.15234 z"
- id="path13677-7"
- inkscape:connector-curvature="0" />
<g
- id="g6391"
- style="fill:#ffffff">
- <path
- inkscape:connector-curvature="0"
- id="path13580-7"
- d="m 72.5,32 a 0.50004997,0.50004997 0 0 0 -0.330078,0.123047 l -2,1.75 A 0.50004997,0.50004997 0 0 0 70,34.25 V 36 H 68.5 A 0.50004997,0.50004997 0 0 0 68,36.5 V 38 c 0,0.986111 0.740543,1.688903 1.568359,1.919922 0.715248,0.199604 1.51421,0.04822 2.183594,-0.384766 L 73,40.939453 V 43.25 c 0,0.888889 0.394191,1.618478 0.96875,2.078125 C 74.543309,45.787772 75.275,46 76,46 76.725,46 77.456691,45.787772 78.03125,45.328125 78.605809,44.868478 79,44.138889 79,43.25 v -2.310547 l 1.248047,-1.404297 c 0.669384,0.432987 1.468346,0.58437 2.183594,0.384766 C 83.259457,39.688903 84,38.986111 84,38 V 36.5 A 0.50004997,0.50004997 0 0 0 83.5,36 H 82 v -1.75 a 0.50004997,0.50004997 0 0 0 -0.169922,-0.376953 l -2,-1.75 A 0.50004997,0.50004997 0 0 0 79.5,32 h -2 a 0.50004997,0.50004997 0 0 0 -0.353516,0.146484 L 76.292969,33 H 75.707031 L 74.853516,32.146484 A 0.50004997,0.50004997 0 0 0 74.5,32 Z m 0.1875,1 h 1.605469 l 0.853515,0.853516 A 0.50004997,0.50004997 0 0 0 75.5,34 h 1 a 0.50004997,0.50004997 0 0 0 0.353516,-0.146484 L 77.707031,33 H 79.3125 L 81,34.478516 V 36.5 A 0.50004997,0.50004997 0 0 0 81.5,37 H 83 v 1 c 0,0.513889 -0.321957,0.811097 -0.837891,0.955078 -0.394082,0.109977 -0.821203,-0.06293 -1.207031,-0.25 a 0.50004997,0.50004997 0 0 0 -0.828125,-0.537109 l -2,2.25 A 0.50004997,0.50004997 0 0 0 78,40.75 v 2.5 c 0,0.611111 -0.230809,1.006522 -0.59375,1.296875 C 77.043309,44.837228 76.525,45 76,45 75.475,45 74.956691,44.837228 74.59375,44.546875 74.230809,44.256522 74,43.861111 74,43.25 v -2.5 a 0.50004997,0.50004997 0 0 0 -0.126953,-0.332031 l -2,-2.25 a 0.50004997,0.50004997 0 0 0 -0.828125,0.537109 c -0.385828,0.187069 -0.812949,0.359977 -1.207031,0.25 C 69.321957,38.811097 69,38.513889 69,38 v -1 h 1.5 A 0.50004997,0.50004997 0 0 0 71,36.5 v -2.023438 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="path13586"
- d="m 74,35 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -0.5,0.5 A 0.50005,0.50005 0 0 0 73,36 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 36.207031 L 74.207031,36 H 74.5 a 0.50005,0.50005 0 1 0 0,-1 z m 4,0 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -0.5,0.5 A 0.50005,0.50005 0 0 0 77,36 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 36.207031 L 78.207031,36 H 78.5 a 0.50005,0.50005 0 1 0 0,-1 z m -2.5,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(357,21)"
+ id="g13370"
+ inkscape:label="G-26">
+ <g
+ id="g13360"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 181.98438,115.98633 A 1.0001,1.0001 0 0 0 181,117 v 4.83203 a 1.0001,1.0001 0 0 0 0.28906,0.88477 1.0001,1.0001 0 0 0 0.006,0.006 1.0001,1.0001 0 0 0 0.0137,0.0137 A 1.0001,1.0001 0 0 0 182.1582,123 H 187 a 1.0001,1.0001 0 1 0 0,-2 h -4 v -4 a 1.0001,1.0001 0 0 0 -1.01562,-1.01367 z"
+ id="path13358"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="matrix(0,-1,-1,0,301.992,326.998)"
+ id="g13368"
+ style="fill:#ffffff">
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g13366"
+ transform="translate(760.995,-489)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g13364"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -563.5,607 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 l 0.006,-5.50781 h -1 L -555,616 h -8 v -8 h 5.00391 v -1 z"
+ id="path13362"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 418.50786,518.99219 a 0.50005,0.50005 0 0 1 0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 1 -1,0 v -2.92578 a 0.50005,0.50005 0 0 1 -0.5,0.41797 h -1 a 0.50005,0.50005 0 1 1 0,-1 h 1 a 0.50005,0.50005 0 0 1 0.5,0.42187 V 519.5 a 0.50005,0.50005 0 0 1 0.50781,-0.50781 z m -13,0 a 0.50005,0.50005 0 0 1 0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 1 -1,0 v -6 a 0.50005,0.50005 0 0 1 0.50781,-0.50781 z m 4.99805,0.002 a 0.50005,0.50005 0 0 1 0.34766,0.85937 l -2.64649,2.64649 2.64649,2.64648 a 0.50005,0.50005 0 1 1 -0.70704,0.70703 l -3,-3 a 0.50005,0.50005 0 0 1 0,-0.70703 l 3,-3 a 0.50005,0.50005 0 0 1 0.35938,-0.15234 z M 414.50005,522 a 0.50005,0.50005 0 1 1 0,1 h -1 a 0.50005,0.50005 0 1 1 0,-1 z m -3,0 a 0.50005,0.50005 0 1 1 0,1 h -1 a 0.50005,0.50005 0 1 1 0,-1 z"
- id="path14267"
- inkscape:connector-curvature="0" />
<g
- id="g6366"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g11319-4"
+ transform="rotate(90,348.99425,289.99175)"
+ inkscape:label="G-25">
<path
+ sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
- id="path14380-1"
- d="m 34,116 c -3.860075,0 -7,3.13992 -7,7 0,3.86007 3.139928,7 7,7 3.860072,0 7,-3.13993 7,-7 0,-3.86008 -3.139925,-7 -7,-7 z m 0,1 c 3.319633,0 6,2.68036 6,6 0,3.31963 -2.680364,6 -6,6 -3.319636,0 -6,-2.68037 -6,-6 0,-3.31964 2.680367,-6 6,-6 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- id="path14287"
- transform="translate(540,10)"
- d="m -506.01562,106.24414 a 0.50005,0.50005 0 0 0 -0.375,0.19336 c -0.70647,0.88308 -1.16919,1.99665 -1.41016,3.5625 H -511.75 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 3.83203 c -0.0522,0.60644 -0.082,1.26334 -0.082,2 0,0.73665 0.0299,1.39356 0.082,2 H -511.75 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 3.94922 c 0.24099,1.56587 0.70375,2.67949 1.41016,3.5625 a 0.50024408,0.50024408 0 0 0 0.78124,-0.625 c -0.56556,-0.70695 -0.96391,-1.59657 -1.18554,-2.9375 h 6.54492 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -6.66797 c -0.0526,-0.59052 -0.082,-1.24749 -0.082,-2 0,-0.75251 0.0294,-1.40947 0.082,-2 h 6.66797 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -6.54492 c 0.22165,-1.34096 0.62004,-2.23062 1.18554,-2.9375 a 0.50005,0.50005 0 0 0 -0.40624,-0.81836 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
+ id="path11311-4"
+ d="m 202.98828,114.98828 c -0.55228,0.008 -0.99388,0.46139 -0.98633,1.01367 v 8 c -0.0191,1.35232 2.01913,1.35232 2,0 v -8 c 0.008,-0.56299 -0.45068,-1.02136 -1.01367,-1.01367 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(760.995,-489)"
+ id="g11317-7"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <g
+ id="g11315-1"
+ style="fill:#ffffff">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path11313-84"
+ d="m -564.5,609 c -0.5954,-0.006 -0.70014,0.84767 -0.12109,0.98633 l -0.28321,-0.0723 1.91992,7.70703 c 0.0555,0.22241 0.25515,0.37858 0.48438,0.37894 h 11 c 0.27461,-2e-5 0.49783,-0.22149 0.5,-0.49609 l 0.01,-0.99805 c 2.2e-4,-0.0476 -0.006,-0.0949 -0.0195,-0.14063 l -2.00585,-7.00195 c -0.0613,-0.21559 -0.25857,-0.36405 -0.4827,-0.36328 l -2.49599,-0.0137 0.002,1 2.11903,0.0157 1.88086,6.56836 -0.002,0.42969 h -10.11328 l -1.74414,-7 3.85953,-0.0138 v -1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ </g>
</g>
- <rect
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
- id="rect14475-9"
- width="14"
- height="14"
- x="468"
- y="389" />
<g
- id="g6259"
- style="fill:#ffffff">
- <path
- inkscape:connector-curvature="0"
- id="path14478-2"
- d="m 475,388.9375 c -3.89459,0 -7.0625,3.1679 -7.0625,7.0625 0,3.89459 3.16791,7.0625 7.0625,7.0625 3.89459,0 7.0625,-3.16791 7.0625,-7.0625 0,-3.8946 -3.16791,-7.0625 -7.0625,-7.0625 z m 0,1 c 3.35415,0 6.0625,2.70834 6.0625,6.0625 0,3.35415 -2.70835,6.0625 -6.0625,6.0625 -3.35415,0 -6.0625,-2.70835 -6.0625,-6.0625 0,-3.35416 2.70835,-6.0625 6.0625,-6.0625 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- id="path14482"
- d="m 474.47656,390.74414 a 0.50005,0.50005 0 0 0 -0.40039,0.24024 C 473.18442,392.40936 473,393.97991 473,396 c 0,1.96736 0.17366,3.58622 1.07617,5.01758 a 0.50122941,0.50122941 0 1 0 0.84766,-0.53516 C 474.1712,399.28878 474,397.90804 474,396 c 0,-1.96025 0.17286,-3.28436 0.92383,-4.48438 a 0.50005,0.50005 0 0 0 -0.44727,-0.77148 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="translate(336,21)"
+ id="g13340"
+ inkscape:label="G-24">
+ <g
+ id="g13324"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 501.98047,136.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -2.7207,2.7207 c -0.0264,-10e-4 -0.0514,-0.008 -0.0781,-0.008 -0.82235,0 -1.5,0.67765 -1.5,1.5 0,0.82235 0.67765,1.5 1.5,1.5 0.82235,0 1.5,-0.67765 1.5,-1.5 0,-0.0267 -0.006,-0.0518 -0.008,-0.0781 l 2.7207,-2.7207 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
+ transform="translate(-336,-21)"
+ id="rect13317"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g13338"
+ transform="translate(717.995,-489)"
+ style="opacity:0.6;fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 489.49414,140 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 5 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -0.50781 h 5 V 150.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.5 v -4 h -1 v 4 h -0.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.49219 h -5 V 148.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -0.5 v -5 h 0.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -0.50781 H 496 v -1 h -4.00586 V 140.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 1 v 1 h -1 z m 0,8 h 1 v 1 h -1 z m 8,0 h 1 v 1 h -1 z"
+ transform="translate(-1053.99,468)"
+ id="path13330"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
<g
- id="g6251"
- style="fill:#ffffff">
+ transform="translate(122.01,-1668.99)"
+ id="g20207-3"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="G-23">
<path
inkscape:connector-curvature="0"
- id="path14492-1-5"
- d="m 452.5,389 c -0.79539,1.6e-4 -1.5587,0.31644 -2.12109,0.87891 l -2.5,2.5 C 447.31644,392.9413 447.00016,393.70461 447,394.5 v 5.5 c 1.7e-4,1.65084 1.34916,2.99983 3,3 h 5.5 c 0.79539,-1.6e-4 1.5587,-0.31644 2.12109,-0.87891 l 2.5,-2.5 c 0.56247,-0.56238 0.87875,-1.3257 0.87891,-2.12109 v -5.75 c -8e-5,-0.79524 -0.25969,-1.50187 -0.75391,-1.99609 C 459.75187,389.25969 459.04524,389.00008 458.25,389 Z m 0,1 h 5.75 c 0.58541,6e-5 1.00348,0.17535 1.28906,0.46094 0.28559,0.28558 0.46088,0.70365 0.46094,1.28906 v 5.75 c -10e-5,0.53061 -0.21073,1.03891 -0.58594,1.41406 l -2.5,2.5 C 456.53889,401.78928 456.03061,401.9999 455.5,402 H 450 c -1.11046,-1.1e-4 -1.99989,-0.88954 -2,-2 v -5.5 c 10e-5,-0.53061 0.21072,-1.03889 0.58594,-1.41406 l 2.5,-2.5 C 451.46111,390.21072 451.96939,390.0001 452.5,390 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 346.49414,1805.9941 a 0.50005,0.50005 0 0 0 -0.34766,0.8594 l 3,3 C 348.44086,1810.7157 348,1811.8024 348,1813 c 2e-5,1.197 0.44143,2.2825 1.14648,3.1445 l -3,3 a 0.50005,0.50005 0 1 0 0.70704,0.7071 l 3,-3 c 0.86236,0.7061 1.94846,1.1484 3.14648,1.1484 0.73402,0 1.42595,-0.1693 2.05469,-0.4551 l -0.77344,-0.7734 C 353.87701,1816.9083 353.45144,1817 353,1817 c -2.21502,0 -3.99996,-1.785 -4,-4 -10e-6,-2.2151 1.78494,-4 4,-4 2.21506,0 4.00001,1.7849 4,4 -10e-6,0.4593 -0.093,0.8925 -0.23438,1.3027 l 0.76954,0.7696 c 0.29106,-0.6335 0.46483,-1.3311 0.46484,-2.0723 0,-1.198 -0.44234,-2.2841 -1.14844,-3.1465 l 3.00196,-3.0019 a 0.50005,0.50005 0 0 0 -0.36329,-0.8575 0.50005,0.50005 0 0 0 -0.34375,0.1504 l -3.00195,3.002 C 355.28248,1808.4414 354.19705,1808 353,1808 c -1.19759,0 -2.28425,0.4409 -3.14648,1.1465 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.1524 z"
+ id="path20884-9" />
<path
inkscape:connector-curvature="0"
- id="path14494-2"
- d="m 458.49023,390.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 450.5,393 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 z m 5.99219,1.99219 A 0.50005,0.50005 0 0 0 456,395.5 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path20886-9"
+ transform="translate(427.99,1668.99)"
+ d="m -74.990234,142.01953 c -1.09866,0 -2,0.9013 -2,2 0,1.0986 0.90134,2 2,2 0.381313,0 0.73472,-0.11501 1.039062,-0.30273 a 0.50005,0.50005 0 0 0 0.107422,0.15625 l 4.146484,4.14648 h -1.621093 a 0.50005,0.50005 0 1 0 0,1 h 2.828125 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -2.82812 a 0.50005,0.50005 0 1 0 -1,0 v 1.62109 l -4.146485,-4.14648 a 0.50005,0.50005 0 0 0 -0.15625,-0.10743 c 0.187715,-0.30434 0.302735,-0.65777 0.302735,-1.03906 0,-1.0987 -0.90134,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.4418 1,1 0,0.5581 -0.4418,1 -1,1 -0.5582,0 -1,-0.4419 -1,-1 0,-0.5582 0.4418,-1 1,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- id="g6275"
- style="fill:#ffffff">
+ transform="translate(876,-1690)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24686-1"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="G-22">
<path
- inkscape:connector-curvature="0"
- id="path14559-8"
- d="m 519.02539,389.05664 c -1.23014,0.0645 -2.42356,0.6345 -3.37891,1.58984 l -4,4 c -0.95534,0.95535 -1.53001,2.15146 -1.59765,3.38477 -0.0676,1.23331 0.38786,2.49571 1.41406,3.50977 1.02392,1.0118 2.28158,1.46686 3.51172,1.40234 1.23014,-0.0645 2.42356,-0.6345 3.37891,-1.58984 l 4,-4 c 0.95534,-0.95535 1.53001,-2.15146 1.59765,-3.38477 0.0676,-1.23331 -0.38786,-2.4957 -1.41406,-3.50977 -1.02392,-1.0118 -2.28158,-1.46686 -3.51172,-1.40234 z m 0.0527,0.99805 c 0.95617,-0.0502 1.91199,0.28134 2.75586,1.11523 0.8416,0.83165 1.17171,1.78562 1.11914,2.74414 -0.0526,0.95853 -0.50462,1.93042 -1.30664,2.73242 l -4,4 c -0.80201,0.80202 -1.76844,1.24868 -2.7246,1.29883 -0.95617,0.0502 -1.91199,-0.28134 -2.75586,-1.11523 -0.8416,-0.83164 -1.17171,-1.78562 -1.11914,-2.74414 0.0526,-0.95853 0.50462,-1.93041 1.30664,-2.73242 l 4,-4 c 0.80201,-0.80202 1.76844,-1.24868 2.7246,-1.29883 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -419.5,1827 a 0.50005,0.50005 0 1 0 0,1 h 2.79492 l -2.96875,2.9688 c 0.24471,0.2267 0.48032,0.4623 0.70703,0.707 L -416,1828.709 v 2.791 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -2.98438,6.7793 -3.50585,3.5059 C -426.28828,1837.1081 -426.63057,1837 -427,1837 c -1.09865,0 -2,0.9013 -2,2 0,1.0986 0.90135,2 2,2 1.09865,0 2,-0.9014 2,-2 0,-0.3677 -0.10771,-0.7107 -0.2832,-1.0078 l 3.50586,-3.5059 c -0.22252,-0.2491 -0.45807,-0.4843 -0.70704,-0.707 z M -427,1838 c 0.55821,0 1,0.4417 1,1 0,0.5582 -0.44179,1 -1,1 -0.55821,0 -1,-0.4418 -1,-1 0,-0.5583 0.44179,-1 1,-1 z"
+ id="path24506-4"
+ inkscape:connector-curvature="0" />
<path
- inkscape:connector-curvature="0"
- id="path14564"
- d="m 517.47266,391.99414 a 0.50005,0.50005 0 0 0 -0.45899,0.62305 c 0.18668,0.77642 0.28491,1.42494 1.14063,2.24414 0.815,0.78022 1.39282,0.94312 2.24023,1.12695 a 0.50005,0.50005 0 1 0 0.21094,-0.97656 c -0.84931,-0.18425 -1.03849,-0.18255 -1.75977,-0.87305 -0.72218,-0.69136 -0.65665,-0.91268 -0.85937,-1.75586 a 0.50005,0.50005 0 0 0 -0.51367,-0.38867 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -428.49556,1829 a 0.4997692,0.49966962 0 1 0 0,0.9993 c 5.80308,0 10.49606,4.6921 10.49606,10.494 a 0.4997692,0.49966962 0 1 0 0.99944,0 c 0,-6.3418 -5.1523,-11.4933 -11.4955,-11.4933 z"
+ id="ellipse24510-0"
+ inkscape:connector-curvature="0" />
</g>
<g
- id="g6267"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g28127"
+ transform="translate(-42,21)"
+ inkscape:label="G-21">
<path
inkscape:connector-curvature="0"
- id="path14468-2"
- d="m 499.91406,389.05664 c -0.77439,-0.15321 -1.63518,-0.1241 -2.51367,0.0664 -1.75698,0.38102 -3.63558,1.4051 -5.25391,3.02343 -1.61833,1.61833 -2.64241,3.49693 -3.02343,5.25391 -0.38103,1.75698 -0.11706,3.43764 0.96093,4.51563 1.07799,1.07798 2.75865,1.34196 4.51563,0.96093 1.75698,-0.38102 3.63558,-1.40511 5.25391,-3.02343 1.61832,-1.61833 2.64241,-3.49693 3.02343,-5.25391 0.38102,-1.75698 0.11705,-3.43764 -0.96093,-4.51563 -0.539,-0.53899 -1.22757,-0.87413 -2.00196,-1.02734 z m -0.21289,0.97656 c 0.61146,0.11888 1.12564,0.37564 1.50781,0.75782 0.76435,0.76434 1.0245,2.05973 0.69141,3.5957 -0.33309,1.53597 -1.26116,3.26702 -2.75391,4.75976 -1.49274,1.49275 -3.22379,2.42081 -4.75976,2.75391 -1.53597,0.3331 -2.83136,0.0729 -3.5957,-0.69141 -0.76435,-0.76434 -1.02451,-2.05973 -0.69141,-3.5957 0.33309,-1.53597 1.26117,-3.26702 2.75391,-4.75976 1.49274,-1.49275 3.22379,-2.42082 4.75976,-2.75391 0.76799,-0.16655 1.47643,-0.18529 2.08789,-0.0664 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="rect28073"
+ d="m 468.5,116 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 1 0 0,-1 H 469 v -9 h 9 v 6.5 a 0.50005,0.50005 0 1 0 1,0 v -7 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
- id="path14550"
- d="m 493.47266,393.99414 a 0.50005,0.50005 0 0 0 -0.45899,0.62305 c 0.22122,0.92011 0.78151,1.92168 1.64063,2.74414 0.81151,0.77689 1.74924,1.41197 2.74023,1.62695 a 0.50005,0.50005 0 1 0 0.21094,-0.97656 c -0.70573,-0.1531 -1.535,-0.67922 -2.25977,-1.37305 -0.71878,-0.6881 -1.19119,-1.55637 -1.35937,-2.25586 a 0.50005,0.50005 0 0 0 -0.51367,-0.38867 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ d="M 475.99635,122 A 1.99635,1.99635 0 0 1 474,123.99635 1.99635,1.99635 0 0 1 472.00365,122 1.99635,1.99635 0 0 1 474,120.00365 1.99635,1.99635 0 0 1 475.99635,122 Z m 0.50756,2.01562 c -0.44709,0.002 -0.6672,0.54472 -0.34766,0.85743 l 4.14648,4.14648 L 477.5,129 c -0.67616,-0.01 -0.67616,1.00956 0,1 l 4.00977,0.0195 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 482,125.5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 l 0.01,2.8125 -4.14649,-4.14648 c -0.0945,-0.0966 -0.22417,-0.15091 -0.35937,-0.1504 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="circle28066" />
</g>
- <path
- inkscape:connector-curvature="0"
- d="m 71.5,536 c -1.3819,0 -2.5,1.1181 -2.5,2.5 v 1 c 0,1.3818 1.118,2.5 2.5,2.5 h 9 c 1.382,0 2.5,-1.1182 2.5,-2.5 v -1 c 0,-1.3857 -1.13452,-2.48443 -2.51172,-2.48633 z m 3.5,1.00586 5.48633,0.008 c 0.8628,0 1.51367,0.63203 1.51367,1.48633 v 1 c 0,0.8578 -0.642,1.5 -1.5,1.5 H 75 Z M 71.5,544 c -1.3819,0 -2.5,1.1181 -2.5,2.5 v 1 c 0,1.3818 1.118,2.5 2.5,2.5 h 9 c 1.382,0 2.5,-1.1182 2.5,-2.5 v -1 c 0,-1.3857 -1.13452,-2.48443 -2.51172,-2.48633 z m 6.50977,1.00977 2.47656,0.004 c 0.8628,0 1.51367,0.63203 1.51367,1.48633 v 1 c 0,0.8578 -0.642,1.5 -1.5,1.5 H 78 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path18055-4" />
<g
- id="g6286"
- style="fill:#ffffff">
+ id="g3386"
+ inkscape:label="G-20"
+ style="display:inline;enable-background:new">
<path
- d="m 303.5,369 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 300,372.5 v 9 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 313,378.5 v -9 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 312 v 8.29297 L 309.29297,381 H 301 v -8.29297 z m 1.79883,5.03711 c -0.82251,0 -1.5,0.67749 -1.5,1.5 0,0.8225 0.67749,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.21793 0.5,0.5 0,0.28206 -0.21794,0.5 -0.5,0.5 -0.28207,0 -0.5,-0.21794 -0.5,-0.5 0,-0.28207 0.21793,-0.5 0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path19061-0-7-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.99;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 418.85321,140.04954 -2.82,-2.82 a 0.62,0.62 0 0 0 -0.4,-0.18 0.6,0.6 0 0 0 -0.6,0.6 0.62,0.62 0 0 0 0.18,0.43 l 1,1 -9.18,9.12 -1,-1 a 0.62,0.62 0 0 0 -0.4,-0.15 0.6,0.6 0 0 0 -0.6,0.6 0.62,0.62 0 0 0 0.18,0.4 l 2.82,2.82 a 0.6,0.6 0 0 0 0.82,-0.82 l -1,-1 9.18,-9.15 1,1 a 0.6,0.6 0 0 0 0.82,-0.85 z"
+ id="path3261"
inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path8009-8-5-8-9-1-5"
- d="M 312.14648,369.14648 309.29297,372 H 300.5 v 1 h 8.5 l 0.006,8.53711 h 1 l -0.006,-8.83008 2.85352,-2.85351 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <path
- id="path18998-9"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 398,581 h -1 v -2 l 0.8535,-0.8535 c 0.091,0.09 0.1465,0.2154 0.1465,0.3535 z m -1,-2 0.8535,-0.8535 C 397.7635,578.0555 397.6381,578 397.5,578 h -9 c -0.1326,0 -0.2598,0.053 -0.3535,0.1465 l -4,4.0078 c -0.094,0.094 -0.1465,0.2209 -0.1465,0.3535 V 591.5 c 0,0.2761 0.2239,0.5 0.5,0.5 h 13 c 0.2761,0 0.5,-0.2239 0.5,-0.5 V 589 c -10e-5,-1.0628 -0.406,-2.084 -1.1367,-2.8438 l -0.01,-0.01 L 394.707,584 h 2.793 c 0.6761,0.01 0.6761,-1.0096 0,-1 h -3.9395 c -0.3255,-0.042 -0.6029,0.235 -0.5605,0.5605 V 587.5 c -0.01,0.6761 1.0096,0.6761 1,0 v -2.793 l 2.1426,2.1426 c 0.5484,0.5702 0.8573,1.3426 0.8574,2.1504 v 2 h -12 v -8.2852 L 388.707,579 Z"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccscccccccssssscccccccccccccccccc" />
- <path
- inkscape:connector-curvature="0"
- id="path20392"
- d="m 154.49904,493.99904 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.86133 l -0.82812,3.30664 a 0.50005,0.50005 0 0 0 -0.002,0.006 0.50005,0.50005 0 0 0 -0.0352,0.14258 0.50005,0.50005 0 0 0 0,0.004 l -1.48047,5.91993 a 0.50005,0.50005 0 0 0 0.48437,0.62304 h 4.92383 a 0.50005,0.50005 0 0 0 0.14453,0 h 4.90821 a 0.50005,0.50005 0 0 0 0.48437,-0.3789 l 3.03711,-11.99024 a 0.50005,0.50005 0 0 0 -0.48437,-0.62109 l -4.91016,-0.006 a 0.50005,0.50005 0 0 0 -0.20117,0 l -3.40235,-0.006 v -0.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -0.92187 a 0.50005,0.50005 0 0 0 -0.14453,0 h -0.9336 z m 3,1 2.85938,0.004 -1.24805,4.99609 h -3.96875 l 0.75,-3 h 1.10742 a 0.50005,0.50005 0 0 0 0.5,-0.5 z m 3.89063,0.006 3.98047,0.006 -1.26367,4.98828 h -3.96485 z m -6.49805,5.99414 h 3.96875 l -1.25195,5.00195 h -3.9668 z m 5,0 h 3.96094 l -1.26758,5.00195 h -3.94336 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 426.49214,518.99219 A 0.50005,0.50005 0 0 0 425.99995,519.5 v 6 a 0.50005,0.50005 0 1 0 1,0 v -2.92578 a 0.50005,0.50005 0 0 0 0.5,0.41797 h 1 a 0.50005,0.50005 0 1 0 0,-1 h -1 a 0.50005,0.50005 0 0 0 -0.5,0.42187 V 519.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 13,0 A 0.50005,0.50005 0 0 0 438.99995,519.5 v 6 a 0.50005,0.50005 0 1 0 1,0 v -6 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -4.99805,0.002 a 0.50005,0.50005 0 0 0 -0.34766,0.85937 l 2.64649,2.64649 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z M 430.49995,522 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path20420"
- inkscape:connector-curvature="0" />
- <path
- id="path19004-3"
- d="m 512,536 c -0.52447,0 -1.0237,0.21715 -1.39258,0.57617 C 510.23866,536.93533 510,537.43678 510,538.00195 V 548 c 8e-5,0.53017 0.21103,1.03915 0.58594,1.41406 C 510.96085,549.78897 511.46978,550 512,550 h 1.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -10 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 512 c -0.45232,0 -1,-0.47106 -1,-0.99805 0,-0.26349 0.1383,-0.51454 0.33203,-0.69922 C 511.52545,537.11905 511.77501,537 512,537 h 6 v 2 h 2 v -2 h 2 v 2.00586 L 520,539 v 2 l 2,0.006 v 2 L 520,543 v 2 l 2,0.006 V 547 h -1.99414 l -0.01,-2 h -2 l 0.01,2 H 515 v 1 h 8.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -11 z m 8,7 v -2 h -2 v 2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cccccccccc"
- inkscape:connector-curvature="0"
- d="m 516,545 h 2 v -2 h -2 z m 0,-4 h 2 v -2 h -2 z"
- style="display:inline;opacity:0.8;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path19014-3-8" />
<g
- transform="translate(42.000006)"
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g6098">
- <path
- id="circle20459-6"
- transform="translate(-42)"
- d="m 469.08398,415.58594 c -0.81593,0.95753 -1.21878,2.22985 -1.04296,3.52148 0.24625,1.80912 1.56436,3.29294 3.33203,3.75 1.43669,0.37149 2.93514,-0.006 4.03515,-0.9414 -0.29636,0.0501 -0.5984,0.084 -0.9082,0.084 -0.38579,0 -0.76279,-0.0423 -1.12695,-0.11914 -0.56283,0.14546 -1.16207,0.15983 -1.75,0.008 -1.37737,-0.35614 -2.39992,-1.50634 -2.5918,-2.91601 -0.0626,-0.45958 -0.0236,-0.91417 0.0879,-1.34571 C 469.04268,417.26409 469,416.88831 469,416.50391 c 0,-0.31305 0.0328,-0.61873 0.084,-0.91797 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="cssccscc"
- id="circle20463-7"
- transform="translate(-42)"
- d="M 473.08594,412.25 C 471.30049,412.84735 470,414.51742 470,416.5 c 0,2.47936 2.02064,4.5 4.5,4.5 0.48878,0 0.95142,-0.0971 1.39258,-0.24219 -0.56289,-0.17378 -1.08535,-0.43906 -1.55664,-0.77343 C 472.47547,419.89744 471,418.3827 471,416.5 c 0,-1.08365 0.4989,-2.0367 1.26758,-2.67773 0.18577,-0.57127 0.46679,-1.09859 0.81836,-1.57227 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
+ style="display:inline;enable-background:new"
+ transform="translate(-0.35812,42.2943)"
+ id="g4073"
+ inkscape:label="G-19">
<path
- inkscape:connector-curvature="0"
- id="circle19345"
- d="m 435.5,411 c -2.47344,0 -4.5,2.02656 -4.5,4.5 0,2.47344 2.02656,4.5 4.5,4.5 2.47344,0 4.5,-2.02656 4.5,-4.5 0,-2.47344 -2.02656,-4.5 -4.5,-4.5 z m 0,2 c 1.39256,0 2.5,1.10744 2.5,2.5 0,1.39256 -1.10744,2.5 -2.5,2.5 -1.39256,0 -2.5,-1.10744 -2.5,-2.5 0,-1.39256 1.10744,-2.5 2.5,-2.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccccccssssccs"
+ d="m 388.17266,99.291166 c -0.27613,4e-5 -0.49997,0.22388 -0.5,0.5 v 1.261304 h -3.16865 v 1.46027 h 3.16865 v 1.27843 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.000004 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z m 2.59221,-4.74807 c 2.50006,0 4.81247,1.33488 6.0625,3.5 1.25002,2.165124 1.25002,4.834884 0,7.000004 -1.25003,2.16512 -3.56244,3.5 -6.0625,3.5 h -6.5 c 0,-4.66667 0,-9.333336 0,-14.000004 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="rect10339-4-1-6" />
</g>
- <path
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- d="m 240.51382,409.98613 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -3,3 a 0.50005,0.50005 0 1 0 0.707,0.707 l 3,-3 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 5,0 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -8,8 a 0.50005,0.50005 0 1 0 0.707,0.707 l 8,-8 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 5,0 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -4.416,4.416 c 0.2729,0.1952 0.5118,0.4341 0.707,0.707 l 4.416,-4.416 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m 0,5 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -8,8 a 0.50005,0.50005 0 1 0 0.707,0.707 l 8,-8 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z m -6.5059,1.0059 a 1.0000001,1 0 0 0 -1,1 1.0000001,1 0 0 0 1,1 1.0000001,1 0 0 0 1,-1 1.0000001,1 0 0 0 -1,-1 z m -2.4375,2.7305 -4.416,4.416 a 0.50005,0.50005 0 1 0 0.707,0.707 l 4.416,-4.416 c -0.2729,-0.1952 -0.5118,-0.4341 -0.707,-0.707 z m 8.9434,1.2636 a 0.50005,0.50005 0 0 0 -0.3594,0.1524 l -3,3 a 0.50005,0.50005 0 1 0 0.707,0.707 l 3,-3 a 0.50005,0.50005 0 0 0 -0.3476,-0.8594 z"
- id="path21556-6"
- inkscape:connector-curvature="0"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="115"
- inkscape:export-ydpi="115" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g19348"
- transform="translate(-252,-1102)">
- <g
- style="fill:#ffffff;stroke:#ffffff"
- id="g19344">
- <g
- id="g19337"
- style="opacity:0;fill:#ffffff" />
- <path
- inkscape:connector-curvature="0"
- id="path19342"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 701,1726 v 7.25 c 0,0.4861 0.17047,0.94 0.49023,1.2598 0.31977,0.3197 0.77366,0.4902 1.25977,0.4902 h 6.5 c 0.48611,0 0.94,-0.1705 1.25977,-0.4902 C 710.82953,1734.19 711,1733.7361 711,1733.25 V 1726 h -1 v 7.25 c 0,0.2639 -0.0795,0.435 -0.19727,0.5527 C 709.685,1733.9205 709.51389,1734 709.25,1734 h -6.5 c -0.26389,0 -0.435,-0.08 -0.55273,-0.1973 C 702.07953,1733.685 702,1733.5139 702,1733.25 V 1726 Z m 3.5,-4 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 1.5 h -3.5 c -0.67616,-0.01 -0.67616,1.0096 0,1 h 11 c 0.67616,0.01 0.67616,-1.0096 0,-1 H 708 v -1.5 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 z m 0.5,1 h 2 v 1 h -2 z"
- sodipodi:nodetypes="cscsscsccscsscscccccccccccccccccc" />
- </g>
+ id="g3383"
+ inkscape:label="G-18"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 704.49219,1726.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 4 c -0.01,0.6762 1.00956,0.6762 1,0 v -4 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z m 3,0 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 4 c -0.01,0.6762 1.00956,0.6762 1,0 v -4 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z"
- id="path19346"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccc" />
+ id="rect10339-4-1-7-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 368.30892,141.58547 c -0.27613,4e-5 -0.49997,0.22388 -0.5,0.5 v 1.26473 h -4.76715 v 1.4911 h 4.76715 v 1.24417 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.63583,0.004 3.43318,-0.006 3.9995,-0.006 0.24106,0 0.46127,-0.0485 0.46127,-0.50967 4e-5,-0.85242 -8.9e-4,-2.98571 -8.9e-4,-3.95935 0,-0.30244 -0.19636,-0.51552 -0.46153,-0.51552 -0.82724,0 -3.36276,-0.009 -3.99823,-0.009 v 2e-5 z m 2.30359,-4.68113 -0.005,4.25868 c 0.48989,0.002 1.39549,0.005 1.88538,0.007 0.44541,0.0357 0.71675,0.47423 0.71675,0.85988 -6.6e-4,1.00616 -0.009,2.97018 -0.009,4.15122 0,0.46073 -0.24756,0.84994 -0.6533,0.84994 -0.48399,0.0143 -1.44986,-1.1e-4 -1.93405,-1.6e-4 v 3.87356 l -7.75691,-0.0669 v -14.00001 z"
+ sodipodi:nodetypes="cccccccccccccccccccccccccc" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path21010-5"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 115.5,442 a 0.50004997,0.50004997 0 1 0 0,1 h 5 a 0.50004997,0.50004997 0 1 0 0,-1 z m 0,2 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 V 445 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z m 2.5,-13 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7222 1.0876,3.2946 2.1465,4.3535 0.094,0.094 0.2209,0.1465 0.3535,0.1465 h 7 c 0.1326,0 0.2598,-0.053 0.3535,-0.1465 0.7109,-0.7108 1.4222,-1.6513 1.8262,-2.7148 C 123.8776,437.6179 124,437.066 124,436.5 c 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m -2.5098,5.0059 c 0.1351,0 0.2662,0.047 0.3633,0.1406 L 116.707,437 h 2.586 l 0.8535,-0.8535 c 0.4712,-0.4506 1.1576,0.2358 0.707,0.707 L 120,437.707 v 1.793 0.5 h -1 v -0.5 -1.5 h -2 v 1.5 0.5 h -1 v -0.5 -1.793 l -0.8535,-0.8535 c -0.302,-0.3119 -0.09,-0.8341 0.3437,-0.8476 z" />
<g
- transform="translate(477,-1375)"
- id="g20978-8"
- style="display:inline;fill:#ffffff;enable-background:new">
- <path
- id="path20982-6"
- transform="translate(42,-42)"
- d="m -377.5,1847 c -2.13972,0 -3.85417,1.5351 -4.30664,3.541 -0.63415,-0.8727 -1.53397,-1.541 -2.69336,-1.541 -1.92708,0 -3.5,1.573 -3.5,3.5 0,1.9271 1.57294,3.5 3.5,3.5 h 7 c 2.47937,0 4.5,-2.0207 4.5,-4.5 0,-2.4793 -2.02063,-4.5 -4.5,-4.5 z m 0,3 c 0.82251,0 1.5,0.6775 1.5,1.5 0,0.8225 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8225 0.67749,-1.5 1.5,-1.5 z m -7,1 c 0.82251,0 1.5,0.6775 1.5,1.5 0,0.8225 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8225 0.67749,-1.5 1.5,-1.5 z m 7,0 c -0.28208,0 -0.5,0.2179 -0.5,0.5 0,0.2821 0.21792,0.5 0.5,0.5 0.28208,0 0.5,-0.2179 0.5,-0.5 0,-0.2821 -0.21792,-0.5 -0.5,-0.5 z m -3.94922,0.998 c 8e-5,7e-4 -8e-5,0 0,0 H -381.5 a 0.50005006,0.50005006 0 0 0 0.0508,0 z m -3.05078,0 c -0.28208,0 -0.5,0.2179 -0.5,0.5 0,0.2821 0.21792,0.5 0.5,0.5 0.28208,0 0.5,-0.2179 0.5,-0.5 0,-0.2821 -0.21792,-0.5 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14495"
+ transform="matrix(-1,0,0,1,719,4.49997e-6)"
+ inkscape:label="G-17">
<path
- id="path20992-7"
- transform="translate(42,-42)"
- d="M -385.50781,1856.9922 A 0.50005,0.50005 0 0 0 -386,1857.5 v 1 1 a 0.50005,0.50005 0 0 0 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -6 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 0.5 h -1 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.5078 z m 11.99219,0.01 c -0.10819,0 -0.21237,0.042 -0.29688,0.1094 l -2.5,2 c -0.25044,0.2002 -0.25044,0.581 0,0.7812 l 2.5,2 c 0.32747,0.2621 0.81265,0.029 0.8125,-0.3906 v -4 c 1.1e-4,-0.2823 -0.23341,-0.5088 -0.51562,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 363.49414,141.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 7.15235,7.15234 H 367.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.006,0 0.50005,0.50005 0 0 0 0.0937,-0.0117 0.50005,0.50005 0 0 0 0.0488,-0.0117 0.50005,0.50005 0 0 0 0.3515,-0.54301 v -3.93359 a 0.50005,0.50005 0 1 0 -1,0 v 2.78711 l -7.14648,-7.14649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path14485"
inkscape:connector-curvature="0" />
- </g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 342.55078,494 a 0.50005,0.50005 0 0 1 0.33593,0.1641 l 2.64844,2.84179 h 1.00781 c 0.45995,0.6015 1.17678,1 1.97852,1 h -3.20312 a 0.50005,0.50005 0 0 1 -0.36719,-0.1582 l -2.79492,-2.99999 A 0.50005,0.50005 0 0 1 342.5,494 a 0.50005,0.50005 0 0 1 0.0508,0 z m 5.9707,4.00589 c 0.80174,0 1.51857,-0.3985 1.97852,-1 h 2.02148 a 0.50005,0.50005 0 0 1 0.35352,0.1465 l 3,3 a 0.50005,0.50005 0 1 1 -0.70704,0.707 l -2.85351,-2.8535 h -2.29297 v 3.832 c 0.96356,1.6489 2.8299,3.71521 5.58203,4.17391 A 0.50086299,0.50086299 0 1 1 355.43945,507 c -2.4267,-0.4044 -4.21553,-1.8644 -5.39844,-3.34761 a 0.50005,0.50005 0 0 1 -0.002,0 c -0.001,0 -0.003,0 -0.004,0 -1.00443,-0.9218 -2.17404,-1 -3.22851,-0.2383 -1.05449,0.76181 -1.78322,2.34671 -1.78321,4.09771 a 0.50005,0.50005 0 1 1 -1,0 c -10e-6,-2.0216 0.80114,-3.89961 2.19727,-4.90821 0.69807,-0.5043 1.49696,-0.7238 2.2832,-0.668 0.17359,0.012 0.34649,0.043 0.51758,0.082 a 0.50005,0.50005 0 0 1 0,-0.01 v -4 z m 0,-3.99999 c 0.8225,0 1.5,0.6775 1.5,1.49999 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.82249 0.6775,-1.49999 1.5,-1.49999 z"
- id="path20567-5"
- inkscape:connector-curvature="0" />
- <path
- sodipodi:nodetypes="scssssssssssssssssssssssssssssccccccccccccscssssssscccccccc"
- inkscape:connector-curvature="0"
- id="path15245-5-5"
- d="m 498.5,10 c -2.1397,0 -3.80728,1.4725 -4.33008,3.2441 C 493.52022,12.4964 492.6594,12 491.5,12 c -1.9271,0 -3.5,1.5729 -3.5,3.5 0,1.927 1.5729,3.5 3.5,3.5 h 7 c 2.4794,0 4.5,-2.0207 4.5,-4.5 0,-2.4794 -2.0206,-4.5 -4.5,-4.5 z m 0,3 c 0.8225,0 1.5,0.6774 1.5,1.5 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8226 0.6775,-1.5 1.5,-1.5 z m -7,1 c 0.8225,0 1.5,0.6774 1.5,1.5 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8226 0.6775,-1.5 1.5,-1.5 z m 7,0 c -0.2821,0 -0.5,0.2179 -0.5,0.5 0,0.282 0.2179,0.5 0.5,0.5 0.2821,0 0.5,-0.218 0.5,-0.5 0,-0.2821 -0.2179,-0.5 -0.5,-0.5 z m -7,1 c -0.2821,0 -0.5,0.2179 -0.5,0.5 0,0.282 0.2179,0.5 0.5,0.5 0.2821,0 0.5,-0.218 0.5,-0.5 0,-0.2821 -0.2179,-0.5 -0.5,-0.5 z m 1,5 c -0.2761,0 -0.5,0.2239 -0.5,0.5 v 1 0.5 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 -0.27615,0 -0.49651,0.2316 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 V 23 h 1 v 0.5 1 c 0,0.1326 0.053,0.2597 0.14648,0.3535 l 1,1 C 493.24048,25.9475 493.3674,26 493.5,26 h 5 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -5 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z m 10.98438,1 c -0.0871,0 -0.17191,0.028 -0.2461,0.074 l -3.25,2 c -0.31714,0.1953 -0.31714,0.6563 0,0.8516 l 3.25,2 c 0.33298,0.2045 0.76131,-0.035 0.76172,-0.4258 v -4 c 1.1e-4,-0.2823 -0.23341,-0.5088 -0.51562,-0.5 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;enable-background:new" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.24999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 302.64518,431.00052 a 1.1251124,1.1233465 0 0 0 -0.7734,0.3412 l -1.5313,1.5269 a 1.1251124,1.1233465 0 1 0 1.5918,1.5874 l 1.5293,-1.5269 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m 5.0977,0 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -6.6289,6.6185 a 1.125572,1.1238054 0 1 0 1.5918,1.5893 l 2.1289,-2.1256 c 0.2384,-1.1729 1.1734,-2.1044 2.3477,-2.344 l 2.1523,-2.1489 a 1.1251124,1.1233465 0 0 0 -0.8183,-1.9286 z m 5.0996,0 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -3.916,3.9099 c 0.7144,0.3005 1.2901,0.8706 1.5996,1.5795 l 3.9063,-3.9001 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m 0,5.0916 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3393 l -2.123,2.1197 c -0.2257,1.2122 -1.1902,2.1751 -2.4043,2.4005 l -2.1016,2.0983 a 1.1251124,1.1233465 0 1 0 1.5918,1.5873 l 6.627,-6.6165 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z m -5.8418,0.9204 c -0.5601,0 -0.9917,0.4296 -0.9981,0.9867 0.01,0.5524 0.4434,0.9887 0.9981,0.9887 0.5547,0 0.9926,-0.4363 0.998,-0.9887 -0.01,-0.5571 -0.438,-0.9867 -0.998,-0.9867 z m -2.7656,2.149 -3.8946,3.8884 a 1.1251124,1.1233465 0 1 0 1.5918,1.5873 l 3.8848,-3.8786 c -0.7095,-0.3088 -1.2808,-0.8846 -1.582,-1.5971 z m 8.6074,2.0202 a 1.1251124,1.1233465 0 0 0 -0.7735,0.3413 l -1.5293,1.5269 a 1.1251124,1.1233465 0 1 0 1.5899,1.5873 l 1.5293,-1.5269 a 1.1251124,1.1233465 0 0 0 -0.8164,-1.9286 z"
- id="path21492-2"
- inkscape:connector-curvature="0" />
- <g
- transform="translate(-329.98994,63.99547)"
- style="display:inline;opacity:0.98999999;fill:#ffffff;enable-background:new"
- id="g21552">
<path
- id="path8055"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 823.98994,430.00453 v 2 h 5 v 3.7086 l 1.8538,-1.85485 c 0.0937,-0.0939 0.14631,-0.22111 0.1462,-0.35375 0.0114,-0.97402 0,-3.0415 0,-3.5 z m -3,3 v 4 h 7 l -4e-5,-4 z m 11.48438,1.125 c -0.12717,0.004 -0.24801,0.0564 -0.3379,0.14648 l -3.72851,3.72852 h -8.91211 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 8.49414 v -4.5 a 0.50005,0.50005 0 0 1 0.49219,-0.50586 0.50005,0.50005 0 0 1 0.50781,0.50586 v 4.33203 l 3.85352,-3.85351 c 0.0938,-0.0938 0.14645,-0.22092 0.14648,-0.35352 v -5 c 1.1e-4,-0.28235 -0.23342,-0.50879 -0.51562,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 368.49414,137 a 0.50005,0.50005 0 0 0 -0.0937,0.01 0.50005,0.50005 0 0 0 -0.0488,0.0117 A 0.50005,0.50005 0 0 0 368,137.56445 V 141.5 a 0.50005,0.50005 0 1 0 1,0 v -2.78711 l 7.14648,7.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 L 369.70117,138 H 372.5 a 0.50005,0.50005 0 1 0 0,-1 h -4 a 0.50005,0.50005 0 0 0 -0.006,0 z"
+ id="path14491"
inkscape:connector-curvature="0" />
</g>
<g
- id="g20181-9"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- transform="translate(-288.99602,63.999021)">
+ transform="translate(251.963,708.01)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g24272-6"
+ inkscape:label="G-16">
<g
- id="g5276"
- style="fill:#ffffff">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 803.49219,433.99219 A 0.50005,0.50005 0 0 0 803,434.5 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 4.99804,4.00586 a 0.50005,0.50005 0 0 0 -0.49414,0.50586 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 a 0.50005,0.50005 0 0 0 -0.50586,-0.50586 z"
- id="path20179-2"
- inkscape:connector-curvature="0" />
+ transform="translate(-189.963,-708.01)"
+ id="g26513-4"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
<path
- id="path20173-5"
- transform="translate(288.99602,-63.999021)"
- d="m 514.5,497.99805 a 0.50004997,0.50004997 0 0 0 -0.35352,0.14453 l -4,4 A 0.50004997,0.50004997 0 0 0 510,502.49805 v 5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 l 9,0.006 a 0.50004997,0.50004997 0 0 0 0.35547,-0.14649 l 4,-4.0039 A 0.50004997,0.50004997 0 0 0 524,503.49805 v -5 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 z m 0.20898,1 h 7.5879 l -3.00391,3.00586 L 511.70312,502 Z M 523,499.70703 v 3.58399 l -3.70703,3.71289 L 511,507 v -4 l 8.5,0.004 a 0.50004997,0.50004997 0 0 0 0.35547,-0.14844 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path24266-1"
+ d="m 259.5,138 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 11.00195 a 0.50005,0.50005 0 0 0 0.5,0.5 l 4,-0.002 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 10 l -3,0.002 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ inkscape:connector-curvature="0"
+ id="path26515-7"
+ d="m 77.537109,-571.00977 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 13 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -13 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 48.5,183 c -0.27613,4e-5 -0.49997,0.22388 -0.5,0.5 v 9 c 3e-5,0.27614 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22386 0.5,-0.5 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z"
- id="path5234"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 52.49219,179.00781 c -0.1326,4e-5 -0.25976,0.0527 -0.35352,0.1465 l -1.99219,1.99217 C 50.02584,181.26245 50,181.375 50,181.5 v 0.5 h 1 l 0.003,-0.296 1.69618,-1.69619 h 8.29297 v 8.29298 L 59.29548,189.99745 59,190 v 1 h 0.5 c 0.11717,0 0.23766,-0.0261 0.3457,-0.13867 l 2,-2 c 0.0938,-0.0938 0.14646,-0.22091 0.14649,-0.35352 v -9 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z"
- id="path5236"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccscccccccccscccccc" />
<g
+ transform="translate(252.007,707.993)"
style="display:inline;fill:#ffffff;enable-background:new"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(0.00711,-0.00712)"
- id="g26453-0">
+ id="g24260-8"
+ inkscape:label="G-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 10.486328,179.01367 c -0.1326,3e-5 -0.259761,0.0527 -0.353516,0.14649 l -1.9941401,1.99414 c -0.4908663,0.47125 0.2357781,1.1979 0.7070312,0.70703 l 1.8476559,-1.84766 h 8.292969 v 8.29297 l -2.707031,2.70703 H 7.9882812 l 0.00461,-3.00655 -1,-0.002 -0.00656,3.5085 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 8.9999998 c 0.132599,-2e-5 0.259759,-0.0527 0.353516,-0.14648 l 3,-3 c 0.09377,-0.0938 0.14646,-0.22092 0.146484,-0.35352 v -9 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- id="path26449-3"
+ sodipodi:nodetypes="ccccccccccccccccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccc" />
+ id="path26507-9"
+ d="m 61.490943,-569.99488 -3.5,0.008 0.0039,1 2.998047,-0.006 v 5 l -3.001953,0.006 0.0039,1 3.5,-0.008 c 0.275368,-0.001 0.498022,-0.22463 0.498047,-0.5 v -6 c -2.6e-5,-0.2769 -0.22506,-0.50105 -0.501953,-0.5 z m -12.498053,9.002 v 3.49219 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3.49219 h -1 v 2.99219 h -5 v -2.99219 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 6.4921875,183.00781 c -0.2761309,3e-5 -0.4999724,0.22387 -0.5,0.5 v 3 c 2.76e-5,0.27613 0.2238691,0.49997 0.5,0.5 h 3 c 0.2761309,-3e-5 0.4999724,-0.22387 0.5,-0.5 v -3 c -2.76e-5,-0.27613 -0.2238691,-0.49997 -0.5,-0.5 z"
- id="path26451-7"
+ sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
+ id="path26509-9"
+ d="m 48.49289,-570.99288 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 8 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 8 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -8 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g26527-9"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96"
- transform="matrix(0,-1,-1,0,220.01421,219.98576)">
+ id="g26539-4"
+ transform="matrix(0,1,1,0,850.052,109.948)"
+ inkscape:label="G-14">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 27.486328,183.01367 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 9 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- id="path26523-4"
+ sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
+ id="path26497-4"
+ d="m 27.544922,-565.04492 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 8 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 31.478516,179.02148 c -0.1326,3e-5 -0.259761,0.0527 -0.353516,0.14649 l -1.992188,1.99219 c -0.490839,0.47125 0.235779,1.19787 0.707032,0.70703 l 1.845703,-1.84571 h 8.292969 v 8.29297 l -2.707032,2.70703 h -8.292968 l 0.0072,-4.00727 -1,-0.002 -0.0072,4.50727 c -0.0011,0.27689 0.223106,0.50192 0.5,0.50195 h 9 c 0.132599,-2e-5 0.259759,-0.0527 0.353515,-0.14648 l 3,-3 c 0.09377,-0.0938 0.14646,-0.22092 0.146485,-0.35352 v -9 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- id="path26525-5"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccc"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccc" />
+ id="path26505-7"
+ d="m 28.544922,-570.04492 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3.5 h 1 v -3 h 5 v 3 h 1 v -3 h 5 v 5 h -3 v 1 h 3.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -6 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m -0.5,9 0.0049,3.49327 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.275371,-3e-5 0.498899,-0.22268 0.5,-0.49805 l 0.0019,-3.5 -1,-0.002 v 3 h -5 l -0.0068,-2.99132 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(252.00711,707.99288)"
+ transform="translate(252.007,707.993)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24277-2">
+ id="g24277-2"
+ inkscape:label="G-13">
<g
- transform="translate(-252.00673,-707.99218)"
+ transform="translate(-252.007,-707.992)"
style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
id="g26501-5"
inkscape:export-filename="blender_icons.png"
@@ -15261,195 +16621,386 @@
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g26539-4"
- transform="matrix(0,1,1,0,850.0517,109.94829)">
+ id="g14825-7"
+ transform="translate(-189,-315)"
+ inkscape:label="G-11">
<path
- sodipodi:nodetypes="ccccccccc"
+ sodipodi:nodetypes="cccccccccccccccccc"
inkscape:connector-curvature="0"
- id="path26497-4"
- d="m 27.544922,-565.04492 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 2 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 8 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -2 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path14782-1"
+ d="m 415.5,452.00781 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.00781 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.00781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.00781 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -10,10 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3.00781 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.00781 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.00781 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- sodipodi:nodetypes="ccccccccccccccccccccccccccccc"
inkscape:connector-curvature="0"
- id="path26505-7"
- d="m 28.544922,-570.04492 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3.5 h 1 v -3 h 5 v 3 h 1 v -3 h 5 v 5 h -3 v 1 h 3.5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -6 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z m -0.5,9 0.0049,3.49327 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.275371,-3e-5 0.498899,-0.22268 0.5,-0.49805 l 0.0019,-3.5 -1,-0.002 v 3 h -5 l -0.0068,-2.99132 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path14818-4"
+ d="m 409.49219,454.00781 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 l 0.008,3 a 0.50005,0.50005 0 1 0 1,-0.002 l -0.006,-2.49805 h 1.49805 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.5 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z m 3.99804,2.98828 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3.00782 a 0.50005,0.50005 0 1 0 0.70704,0.70508 l 3,-3.00586 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z M 416.49219,458 A 0.50005,0.50005 0 0 0 416,458.50781 v 2.5 h -1.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.49805 L 411.50195,463 a 0.50005,0.50005 0 1 0 -0.004,1 l 3,0.008 a 0.50005,0.50005 0 0 0 0.50195,-0.5 v -1.5 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 A 0.50005,0.50005 0 0 0 416.49219,458 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ id="g14837"
+ transform="translate(-210,-315)"
+ inkscape:label="G-10">
+ <path
+ inkscape:connector-curvature="0"
+ id="path14829"
+ d="m 415.5,452.00781 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00251,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,10e-6 -2.00781,0 z m -10.5,9 a 0.50005018,0.50005018 0 0 0 -0.5,0.5 v 3.00781 a 0.50005018,0.50005018 0 0 0 0.5,0.5 c 1.00252,0 2.00529,0 3.00781,0 a 0.50005018,0.50005018 0 0 0 0.5,-0.5 v -3.00781 a 0.50005018,0.50005018 0 0 0 -0.5,-0.5 c -1.00251,0 -2.00529,0 -3.00781,0 z m 0.5,1 c 0.66922,0 1.33859,0 2.00781,0 v 2.00781 c -0.66921,0 -1.33859,10e-6 -2.00781,0 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path22198"
+ d="m 411.50391,454 a 0.50005,0.50005 0 0 0 -0.35743,0.14648 l -1,1 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 0.85156,-0.85157 0.78515,0.006 a 0.50005,0.50005 0 1 0 0.006,-1 z m -3.01368,2.99609 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -1,1 A 0.50005,0.50005 0 0 0 407,458.5 v 1.00781 a 0.50005,0.50005 0 1 0 1,0 v -0.80078 l 0.85352,-0.85351 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z m 7.99415,0.9961 A 0.50005,0.50005 0 0 0 415.99219,458.5 v 0.80078 l -0.85352,0.85352 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 1,-1 a 0.50005,0.50005 0 0 0 0.14649,-0.35352 V 458.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -3.00196,4.00976 a 0.50005,0.50005 0 0 0 -0.34375,0.15235 l -0.85156,0.85156 -0.7832,-0.006 a 0.50005,0.50005 0 1 0 -0.008,1 l 0.99219,0.008 a 0.50005,0.50005 0 0 0 0.35742,-0.14648 l 1,-1 a 0.50005,0.50005 0 0 0 -0.36328,-0.85938 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(252.00711,707.99288)"
+ transform="translate(0.999998)"
+ id="g22948"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24260-8">
+ inkscape:label="G-8">
<path
- sodipodi:nodetypes="ccccccccccccccccccccccc"
inkscape:connector-curvature="0"
- id="path26507-9"
- d="m 61.490943,-569.99488 -3.5,0.008 0.0039,1 2.998047,-0.006 v 5 l -3.001953,0.006 0.0039,1 3.5,-0.008 c 0.275368,-0.001 0.498022,-0.22463 0.498047,-0.5 v -6 c -2.6e-5,-0.2769 -0.22506,-0.50105 -0.501953,-0.5 z m -12.498053,9.002 v 3.49219 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 6 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3.49219 h -1 v 2.99219 h -5 v -2.99219 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.55;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path12633"
+ d="m 155.50195,139.99414 a 0.50005,0.50005 0 0 0 -0.36133,0.85352 C 156.37329,142.12237 157.775,144 160.5,144 c 2.725,0 4.12681,-1.87774 5.35938,-3.15234 a 0.50005,0.50005 0 1 0 -0.71876,-0.69532 C 163.83477,141.50274 162.775,143 160.5,143 c -2.275,0 -3.33487,-1.49737 -4.64062,-2.84766 a 0.50005,0.50005 0 0 0 -0.35743,-0.1582 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
- id="path26509-9"
- d="m 48.49289,-570.99288 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 8 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 8 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -8 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path12645"
+ d="m 152.50195,143 a 0.50005,0.50005 0 0 0 -0.46093,0.69727 l 3,7 a 0.50005,0.50005 0 1 0 0.91796,-0.39454 l -2.50781,-5.85156 5.85156,2.50781 a 0.50005,0.50005 0 1 0 0.39454,-0.91796 l -7,-3 A 0.50005,0.50005 0 0 0 152.50195,143 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(251.96252,708.00986)"
+ id="g22943"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24272-6">
+ inkscape:label="G-7">
<g
- transform="translate(-189.96252,-708.00986)"
- id="g26513-4"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ style="fill:#ffffff"
+ id="g12942"
+ transform="translate(-20,18)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<path
inkscape:connector-curvature="0"
- id="path24266-1"
- d="m 259.5,138 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 11.00195 a 0.50005,0.50005 0 0 0 0.5,0.5 l 4,-0.002 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 10 l -3,0.002 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path12932"
+ d="m 155.50195,121.99414 a 0.50005,0.50005 0 0 0 -0.36133,0.85352 C 156.37329,124.12237 157.775,126 160.5,126 c 2.725,0 4.12681,-1.87774 5.35938,-3.15234 a 0.50005,0.50005 0 1 0 -0.71876,-0.69532 C 163.83477,123.50274 162.775,125 160.5,125 c -2.275,0 -3.33487,-1.49737 -4.64062,-2.84766 a 0.50005,0.50005 0 0 0 -0.35743,-0.1582 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
- id="path26515-7"
- d="m 77.537109,-571.00977 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 13 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 5 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -13 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path12946"
+ d="m 132.50195,143 c -0.35971,-0.001 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0266 -0.12814,-0.0406 -0.19535,-0.041 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
+ id="g19964"
+ transform="translate(824,416)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g12992"
- transform="translate(2.6297176e-6,-20.999997)"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:label="G-6">
<path
- id="path12908"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 183.8125,200.01562 c 2.21359,0.18235 3.97803,1.94071 4.16992,4.1543 0.19189,2.2136 -1.24344,4.25155 -3.39258,4.8125 a 0.5007349,0.5007349 0 1 1 -0.2539,-0.96875 c 1.68376,-0.43948 2.80079,-2.02289 2.65039,-3.75781 -0.1504,-1.73492 -1.52164,-3.10129 -3.25586,-3.24414 -1.73423,-0.14285 -3.31219,0.98104 -3.74414,2.66797 a 0.50005,0.50005 0 1 1 -0.96875,-0.24805 c 0.55114,-2.15241 2.58133,-3.59836 4.79492,-3.41602 z M 178.5,205 a 0.50005,0.50005 0 1 1 0,1 c -1.41705,0 -2.69209,0.85096 -3.23438,2.16016 -0.54228,1.30919 -0.24224,2.81243 0.75977,3.81445 1.00201,1.00201 2.50527,1.30205 3.81445,0.75977 C 181.14903,212.19209 182,210.91706 182,209.5 a 0.50005,0.50005 0 1 1 1,0 c 0,1.81865 -1.09714,3.46223 -2.77734,4.1582 -1.68021,0.69597 -3.61833,0.30942 -4.9043,-0.97656 -1.28598,-1.28598 -1.67253,-3.22408 -0.97656,-4.9043 C 175.03776,206.09713 176.68136,205 178.5,205 Z"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path20627-2"
+ d="m -704.49998,-278.99995 c -2.725,0 -4.12655,1.87775 -5.35938,3.15234 -0.18751,0.19385 -0.1875,0.50147 0,0.69532 1.23247,1.2748 2.63438,3.15234 5.35938,3.15234 2.725,0 4.12648,-1.87882 5.35938,-3.15625 0.18625,-0.1936 0.18624,-0.49976 0,-0.69336 -1.23336,-1.2779 -2.63506,-3.15039 -5.35938,-3.15039 z m 0,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m 0,1 c -0.83435,0 -1.5,0.66565 -1.5,1.5 0,0.83435 0.66565,1.5 1.5,1.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="M 182.99634,206.50183 A 1.4981741,1.4981725 0 0 1 181.49817,208 a 1.4981741,1.4981725 0 0 1 -1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49817,1.49817 z"
- id="circle12958"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path20671-8"
+ d="m -712.49805,-273 a 0.50005,0.50005 0 0 0 -0.46093,0.69727 l 3,7 a 0.50005,0.50005 0 1 0 0.91796,-0.39454 l -2.50781,-5.85156 5.85156,2.50781 a 0.50005,0.50005 0 1 0 0.39454,-0.91796 l -7,-3 a 0.50005,0.50005 0 0 0 -0.19532,-0.041 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- id="g21469-5"
+ id="g19953"
+ transform="translate(824,416)"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(498,-1438)">
+ inkscape:label="G-5">
<path
inkscape:connector-curvature="0"
- id="path21106-9"
- d="m -356.5,1850 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.2179 0.5,0.5 0,0.2821 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.2179 -0.5,-0.5 0,-0.2821 0.21794,-0.5 0.5,-0.5 z m -7,1 a 0.5,0.5 0 0 0 -0.5,0.5 0.5,0.5 0 0 0 0.5,0.5 0.5,0.5 0 0 0 0.5,-0.5 0.5,0.5 0 0 0 -0.5,-0.5 z"
- style="display:inline;opacity:0.7;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ id="path19355-8-8"
+ d="m -725.49998,-278.99995 c -2.725,0 -4.12655,1.87775 -5.35938,3.15234 -0.18751,0.19385 -0.18751,0.50147 0,0.69532 1.23247,1.2748 2.63438,3.15234 5.35938,3.15234 2.725,0 4.12648,-1.87882 5.35938,-3.15625 0.18625,-0.1936 0.18624,-0.49976 0,-0.69336 -1.23336,-1.2779 -2.63506,-3.15039 -5.35938,-3.15039 z m 0,1 c 1.37479,0 2.5,1.12521 2.5,2.5 0,1.37479 -1.12521,2.5 -2.5,2.5 -1.37479,0 -2.5,-1.12521 -2.5,-2.5 0,-1.37479 1.12521,-2.5 2.5,-2.5 z m 0,1 c -0.83435,0 -1.5,0.66565 -1.5,1.5 0,0.83435 0.66565,1.5 1.5,1.5 0.83435,0 1.5,-0.66565 1.5,-1.5 0,-0.83435 -0.66565,-1.5 -1.5,-1.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- sodipodi:nodetypes="csssscccsscccsccccccscccccccccccccccccccccsccsccccccccccccccccccc"
+ sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
- d="m -357.5,1856.0041 h 0.49805 c 3.5943,0 5.00195,-2.5001 5.00195,-4.5001 v 0 c 0,-2.4794 -2.02064,-4.5 -4.5,-4.5 -1.88915,0 -3.45662,1.2594 -4.10547,3 h -0.51758 c -0.64602,-0.6132 -1.47755,-0.9979 -2.375,-1 h -0.002 c -1.92707,0 -3.5,1.5729 -3.5,3.5 0,1.9271 1.57293,3.5 3.5,3.5 z m -6,-1.0041 c -1.38663,0 -2.5,-1.1134 -2.5,-2.5 0,-1.386 1.11233,-2.4989 2.49805,-2.5 0.71036,0 1.38608,0.3048 1.85937,0.834 0.0951,0.1059 0.23074,0.1663 0.37305,0.166 h 0.90234 c 0.22809,10e-5 0.42734,-0.1542 0.48438,-0.375 0.39914,-1.5459 1.78609,-2.6224 3.38281,-2.625 1.93892,0 3.5,1.5611 3.5,3.5 0,1.9279 -1.54523,3.4765 -3.46875,3.4941 -0.0392,0 -0.0785,-6e-4 -0.11719,0.01 H -357.5 Z m -1.00781,1.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -1.5039 h 0.33594 l 2.61914,1.9043 c 0.0852,0.064 0.18852,0.099 0.29492,0.1 h 0.25 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -0.25 c -0.106,-10e-5 -0.20927,0.034 -0.29492,0.096 L -355.66211,1859 H -356 v -2 h -1 v 4 h -4.29297 L -362,1860.293 V 1857 h -1 v 1 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z M -353,1858.3008 v 2.3984 l -1.65039,-1.1992 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path21108-3" />
+ id="path19363-8-5"
+ d="m -733.49805,-273 c -0.35971,-10e-4 -0.6028,0.36671 -0.46093,0.69727 l 3,7 c 0.18151,0.42185 0.78799,0.39645 0.93359,-0.0391 l 0.91992,-2.76367 2.76367,-0.91992 c 0.43555,-0.1456 0.46095,-0.75208 0.0391,-0.93359 l -7,-3 c -0.0617,-0.0267 -0.12812,-0.0406 -0.19532,-0.041 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20375"
+ transform="matrix(-1,0,0,1,131,5.79997e-6)"
+ inkscape:label="G-4">
<path
- id="rect24266"
- d="m -362,1857 h 5 v 1 h -5 z"
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 48.492188,137 A 0.50005,0.50005 0 0 0 48,137.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,137 Z m 0,5 A 0.50005,0.50005 0 0 0 48,142.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,142 Z m 0,5 A 0.50005,0.50005 0 0 0 48,147.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,147 Z"
+ id="path20369"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 51.515625,137 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 V 138 H 50 v 1 h 1.515625 1 H 55 v -0.5 c 0,-0.25267 -0.149085,-0.49526 -0.484375,-0.5 h -1.5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z M 55,139 l 0.01563,0.5 V 140 H 50 v 9 h 6.515625 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -0.35938 l -2.580078,-2.58007 a 1.50015,1.50015 0 1 1 2.121094,-2.1211 l 0.458984,0.45899 V 139.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path20371"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 55.490234,143.99414 a 0.50005,0.50005 0 0 0 -0.349609,0.85938 L 60.287109,150 h -2.792968 a 0.50005,0.50005 0 1 0 0,1 h 3.939453 a 0.50005,0.50005 0 0 0 0.560547,-0.57031 V 146.5 a 0.50005,0.50005 0 1 0 -1,0 v 2.79297 l -5.146485,-5.14649 a 0.50005,0.50005 0 0 0 -0.357422,-0.15234 z"
+ id="path20373"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(624,-1354)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24304">
+ id="g20474"
+ inkscape:label="G-3">
<path
- style="display:inline;opacity:0.7;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:3.70000005;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- d="m -356.5,1850 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,1 c 0.28206,0 0.5,0.2179 0.5,0.5 0,0.2821 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.2179 -0.5,-0.5 0,-0.2821 0.21794,-0.5 0.5,-0.5 z m -7,1 a 0.5,0.5 0 0 0 -0.5,0.5 0.5,0.5 0 0 0 0.5,0.5 0.5,0.5 0 0 0 0.5,-0.5 0.5,0.5 0 0 0 -0.5,-0.5 z"
- id="path24284"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 48.492188,137 A 0.50005,0.50005 0 0 0 48,137.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,137 Z m 0,5 A 0.50005,0.50005 0 0 0 48,142.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,142 Z m 0,5 A 0.50005,0.50005 0 0 0 48,147.50781 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 48.492188,147 Z"
+ id="path8290-6-5"
inkscape:connector-curvature="0" />
<path
- id="path24300"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -357.5,1856.0041 h 0.49805 c 3.5943,0 5.00195,-2.5001 5.00195,-4.5001 v 0 c 0,-2.4794 -2.02064,-4.5 -4.5,-4.5 -1.88915,0 -3.45662,1.2594 -4.10547,3 h -0.51758 c -0.64602,-0.6132 -1.47755,-0.9979 -2.375,-1 h -0.002 c -1.92707,0 -3.5,1.5729 -3.5,3.5 0,1.9271 1.57293,3.5 3.5,3.5 z m -6,-1.0041 c -1.38663,0 -2.5,-1.1134 -2.5,-2.5 0,-1.386 1.11233,-2.4989 2.49805,-2.5 0.71036,0 1.38608,0.3048 1.85937,0.834 0.0951,0.1059 0.23074,0.1663 0.37305,0.166 h 0.90234 c 0.22809,10e-5 0.42734,-0.1542 0.48438,-0.375 0.39914,-1.5459 1.78609,-2.6224 3.38281,-2.625 1.93892,0 3.5,1.5611 3.5,3.5 0,1.9279 -1.54523,3.4765 -3.46875,3.4941 -0.0392,0 -0.0785,-6e-4 -0.11719,0.01 H -357.5 Z m -1.00781,1.9922 c -0.27614,0 -0.4965,0.2317 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 v -0.5 h 1 v 1.5 c 3e-5,0.1326 0.0527,0.2597 0.14648,0.3535 l 1,1 c 0.0937,0.094 0.22092,0.1465 0.35352,0.1465 h 5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -1.5039 h 0.33594 l 2.61914,1.9043 c 0.0852,0.064 0.18852,0.099 0.29492,0.1 h 0.25 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -4 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 h -0.25 c -0.106,-10e-5 -0.20927,0.034 -0.29492,0.096 L -355.66211,1859 H -356 v -2 h -1 v 4 h -4.29297 L -362,1860.293 V 1857 h -1 v 1 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 z M -353,1858.3008 v 2.3984 l -1.65039,-1.1992 z"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="csssscccsscccsccccccscccccccccccccccccccccsccsccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 51.509766,137 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 138 H 50 v 1 h 1.509766 1 2.515625 v -0.5 c 0,-0.24768 -0.186975,-0.495 -0.515625,-0.5 h -1.5 v -0.5 c -4e-5,-0.27613 -0.22388,-0.49997 -0.5,-0.5 z m 3.515625,2 -0.01563,0.5 V 140 H 50 v 9 h 4.009766 v -4.31641 c -0.12178,-0.91601 0.605587,-1.72326 1.529296,-1.69726 0.05424,0.002 0.10831,0.007 0.16211,0.0137 h 1.308594 v -3.5 c -4e-5,-0.27613 -0.22388,-0.49997 -0.5,-0.5 z"
+ id="path20454"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="matrix(-1,0,0,1,-102.974,1.24459e-6)"
+ id="g20458"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
+ id="path20456"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20243"
+ transform="matrix(-1,0,0,1,-102.984,5.79997e-6)"
+ inkscape:label="G-2">
+ <path
+ id="path20230"
+ transform="matrix(-1,0,0,1,-274.984,0)"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -144.5,139 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 2 c 0.10658,-1e-5 0.20011,-0.0408 0.28125,-0.0977 l -3.3418,-3.34179 a 1.50015,1.50015 0 1 1 2.1211,-2.1211 L -135,144.87891 V 139.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.48438 L -137,139.5 v 0.5 h -6 v -0.5 l 0.0156,-0.5 z m 5,-2 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 0.5 h 1.5 c 0.32865,0.005 0.51562,0.25232 0.51562,0.5 v 0.5 h -2.51562 -1 -2.48438 v -0.5 c 0,-0.25267 0.14909,-0.49526 0.48438,-0.5 h 1.5 v -0.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 z"
+ inkscape:connector-curvature="0" />
+ <g
+ transform="rotate(180,-150.985,147.5)"
+ id="g20236"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
+ id="path20234"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g20257"
+ transform="translate(171)"
+ inkscape:label="G-1">
+ <path
+ id="path20203"
+ d="m -156.48438,137 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 v 0.5 h -1.5 c -0.32865,0.005 -0.51562,0.25232 -0.51562,0.5 v 0.5 h 2.51562 1 H -153 v -0.5 c 0,-0.25267 -0.14909,-0.49526 -0.48438,-0.5 h -1.5 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 3.48438,2 0.0156,0.5 v 0.5 h -6 v -0.5 L -159,139 h -1.48438 c -0.27612,3e-5 -0.49996,0.22387 -0.5,0.5 v 3.5 h 2.3086 a 1.50015,1.50015 0 0 1 0.16211,-0.0137 1.50015,1.50015 0 0 1 1.52929,1.69726 V 149 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ <g
+ id="g20226"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -158.49414,143.99609 a 0.50005,0.50005 0 0 0 -0.0508,0.004 h -3.93946 a 0.50005,0.50005 0 1 0 0,1 h 2.79297 l -5.14648,5.14648 a 0.50005,0.50005 0 1 0 0.70703,0.70704 l 5.14648,-5.14649 V 148.5 a 0.50005,0.50005 0 1 0 1,0 v -3.94336 a 0.50005,0.50005 0 0 0 -0.50976,-0.56055 z"
+ id="path20207"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ id="g19387"
+ style="display:inline;enable-background:new"
+ inkscape:label="F-21">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 433,120 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z"
+ id="circle13367"
inkscape:connector-curvature="0"
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m -362,1857 h 5 v 1 h -5 z"
- id="path24302" />
+ sodipodi:nodetypes="sssss" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path12791-5"
- d="m 385,621 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z m 0,5 a 1.0001,1.0001 0 1 0 0,2 h 12 a 1.0001,1.0001 0 1 0 0,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- transform="translate(1.7499929e-7,23.000001)"
- id="g21364"
- style="display:inline;fill:#ffffff;enable-background:new">
+ id="g19384"
+ style="display:inline;enable-background:new"
+ inkscape:label="F-20">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 412,120 c -1.65093,0 -3,1.34907 -3,3 0,1.65093 1.34907,3 3,3 1.65093,0 3,-1.34907 3,-3 0,-1.65093 -1.34907,-3 -3,-3 z m 0,1 c 1.11049,0 2,0.88951 2,2 0,1.11049 -0.88951,2 -2,2 -1.11049,0 -2,-0.88951 -2,-2 0,-1.11049 0.88951,-2 2,-2 z"
+ id="circle14295"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14433"
+ transform="rotate(-90,380.529,134)"
+ inkscape:label="F-19">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 390.04688,140.46484 a 0.50005,0.50005 0 0 0 -0.41797,0.20704 l -2.95508,3.93945 a 0.50005,0.50005 0 0 0 -0.01,0.70703 l 2.96485,3.95312 a 0.50019216,0.50019216 0 1 0 0.80078,-0.5996 l -2.40039,-3.20118 h 7.1914 l -0.63867,1.27735 a 0.50005635,0.50005635 0 1 0 0.89453,0.44726 l 0.96875,-1.93554 a 0.50005,0.50005 0 0 0 -0.006,-0.58399 l -0.96289,-1.92773 a 0.50005635,0.50005635 0 1 0 -0.89453,0.44726 l 0.63867,1.27539 h -7.1914 l 2.40039,-3.19922 a 0.50005,0.50005 0 0 0 -0.38281,-0.80664 z"
+ id="path17796-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g19390"
+ style="display:inline;enable-background:new"
+ inkscape:label="F-18">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 374.4375,121.17773 c -0.55229,-0.19531 -1.19407,-0.23097 -1.84766,0.002 -0.65359,0.23293 -1.30733,0.71399 -1.9707,1.49609 -0.28137,0.33173 -0.45085,0.79694 -0.61914,1.24219 -0.17701,-0.45587 -0.36207,-0.94012 -0.61914,-1.24219 -0.66249,-0.77846 -1.31558,-1.25837 -1.96875,-1.49023 -0.65317,-0.23186 -1.2953,-0.19616 -1.84766,-0.002 -1.10471,0.38842 -1.89002,1.32506 -2.44922,1.9961 a 0.50064603,0.50064603 0 1 0 0.76954,0.64062 c 0.54481,-0.65377 1.26345,-1.43095 2.00976,-1.69336 0.37316,-0.1312 0.7444,-0.1559 1.18359,0 0.4392,0.1559 0.95757,0.51168 1.54102,1.19727 0.19894,0.23376 0.56603,0.91963 0.64063,1.27734 A 0.50005,0.50005 0 0 0 369.75,125 h 0.5 a 0.50005,0.50005 0 0 0 0.49023,-0.40234 c 0.0736,-0.37229 0.37785,-0.96363 0.64063,-1.27344 0.58467,-0.68931 1.10595,-1.04668 1.54492,-1.20313 0.43897,-0.15644 0.80714,-0.13175 1.17969,0 0.74509,0.2635 1.46354,1.04375 2.00976,1.69922 a 0.50064603,0.50064603 0 1 0 0.76954,-0.64062 c -0.55904,-0.67084 -1.34269,-1.61133 -2.44727,-2.00196 z"
+ id="path17826-1"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g19393"
+ style="display:inline;enable-background:new"
+ inkscape:label="F-17">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 348.5,120 c -1.47879,0 -2.81353,0.43206 -3.80469,1.06641 C 343.70416,121.70075 343,122.54357 343,123.5 c 0,1.02778 0.79097,1.88608 1.87891,2.49805 1.08228,0.60878 2.52394,0.99597 4.09765,1 0.0129,9.4e-4 3.75669,0.27336 6.02344,-2.21094 V 127.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4.25 a 0.50005,0.50005 0 1 0 0,1 h 3.10156 c -1.87731,2.16501 -5.32031,2 -5.32031,2 A 0.50005,0.50005 0 0 0 349,126 c -1.41667,0 -2.71684,-0.36001 -3.62891,-0.87305 C 344.45903,124.61392 344,123.97222 344,123.5 c 0,-0.41012 0.41561,-1.06779 1.23438,-1.5918 C 346.05313,121.38419 347.21846,121 348.5,121 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path18766-5"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13321"
+ transform="translate(-42,21)"
+ inkscape:label="F-16">
<g
- id="g5447"
+ id="g13309"
style="fill:#ffffff">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 430.49219,134.99219 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 0.50005,0.50005 0 0 0 -0.004,0.006 l -1.95313,1.95312 a 0.50005,0.50005 0 1 0 0.70703,0.70704 L 430,136.70703 V 140.5 a 0.50005,0.50005 0 1 0 1,0 v -3.79297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.95704,-1.95703 a 0.50005,0.50005 0 0 0 -0.40429,-0.19726 z m 7.00195,7.00195 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 438.29297,144 H 434.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95313,-1.95313 a 0.50005,0.50005 0 0 0 -0.35937,-0.15234 z m -11.00195,2.99805 A 0.50005,0.50005 0 0 0 426,145.5 v 2.93945 A 0.50005,0.50005 0 0 0 426.56055,149 H 429.5 a 0.50005,0.50005 0 1 0 0,-1 h -1.79297 l 1.14649,-1.14648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 L 427,147.29297 V 145.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- id="path21358"
+ d="m 365.49219,94.992188 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.004,0.0059 l -1.95313,1.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707032 L 365,96.707031 V 98.5 a 0.50005,0.50005 0 1 0 1,0 v -1.792969 l 1.14648,1.146485 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 l -1.95704,-1.957031 a 0.50005,0.50005 0 0 0 -0.40429,-0.197265 z m 9.05859,1.941406 a 0.50005,0.50005 0 0 0 -0.0586,0.0059 h -2.93164 a 0.50005,0.50005 0 1 0 0,1 h 1.79297 l -3.14649,3.146486 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3.14649,-3.146485 v 1.792965 a 0.50005,0.50005 0 1 0 1,0 v -2.931637 a 0.50005,0.50005 0 0 0 -0.50977,-0.574218 z m -0.0566,7.060546 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 L 375.29297,106 H 371.5 a 0.50005,0.50005 0 1 0 0,1 h 3.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95703,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.006,-0.004 l -1.95312,-1.95313 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
+ id="path13047-6"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g13313"
+ style="fill:#ffffff">
<path
- id="circle21362"
- d="M 432.99635,144 A 1.99635,1.99635 0 0 1 431,145.99635 1.99635,1.99635 0 0 1 429.00365,144 1.99635,1.99635 0 0 1 431,142.00365 1.99635,1.99635 0 0 1 432.99635,144 Z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 324.5,121 c -1.14583,0 -1.86235,0.56478 -2.18359,1.12695 C 321.99517,122.68912 322,123.25 322,123.25 V 125 h -0.5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 327 v -1.75 c 0,0 0.005,-0.56088 -0.31641,-1.12305 C 326.36235,121.56478 325.64583,121 324.5,121 Z m 0,1 c 0.85417,0 1.13765,0.31022 1.31641,0.62305 C 325.99517,122.93588 326,123.25 326,123.25 V 125 h -3 v -1.75 c 0,0 0.005,-0.31412 0.18359,-0.62695 C 323.36235,122.31022 323.64583,122 324.5,122 Z m -0.5,4 h 1 v 2 h -1 z"
+ transform="translate(42,-21)"
+ id="rect13261"
inkscape:connector-curvature="0" />
</g>
</g>
<g
+ transform="translate(-6.35367e-6,22)"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24264-7"
- transform="translate(-910,-1146)">
+ id="g22568"
+ inkscape:label="F-15">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
- id="path24260-0"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 307.51172,103 c -0.0577,-0.001 -0.11517,0.007 -0.16992,0.0254 l -6,2 c -0.45678,0.15155 -0.45678,0.79767 0,0.94922 l 6,2 c 0.10269,0.0343 0.21371,0.0343 0.3164,0 l 6,-2 c 0.45678,-0.15155 0.45678,-0.79767 0,-0.94922 l -6,-2 c -0.0473,-0.0157 -0.0967,-0.0243 -0.14648,-0.0254 z"
+ id="path14873"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
- id="path24262-3"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 307.49219,93.992188 A 0.50005,0.50005 0 0 0 307,94.5 v 5.88867 l -5.6582,1.88672 a 0.50028181,0.50028181 0 1 0 0.3164,0.94922 l 5.8418,-1.94727 5.8418,1.94727 a 0.50028181,0.50028181 0 1 0 0.3164,-0.94922 L 308,100.38867 V 94.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path14875"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-847,-1062)"
- id="g24813"
- style="display:inline;fill:#ffffff;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,551,21)"
+ id="g14869"
+ inkscape:label="F-14">
<path
- inkscape:connector-curvature="0"
- id="path24809"
- d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 263.49219,94.992188 A 0.50005,0.50005 0 0 0 263,95.5 v 8.91016 l -4.68555,1.875 a 0.50050477,0.50050477 0 1 0 0.3711,0.92968 l 4.82812,-1.93164 7.82422,2.68946 a 0.50005,0.50005 0 1 0 0.32422,-0.94532 L 264,104.39258 V 95.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path14865"
+ inkscape:connector-curvature="0" />
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 265.50586,95.435547 c -0.27842,-0.0032 -0.50585,0.221565 -0.50586,0.5 v 6.884763 c -1.3e-4,0.21757 0.14044,0.41026 0.34766,0.47657 l 6,1.92968 c 0.32275,0.10319 0.65252,-0.13772 0.65234,-0.47656 v -6.884766 c 1.3e-4,-0.217571 -0.14044,-0.410257 -0.34766,-0.476562 l -6,-1.929688 c -0.0474,-0.01505 -0.0968,-0.02295 -0.14648,-0.02344 z"
+ id="path14867"
inkscape:connector-curvature="0"
- id="path24811"
- d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccccccc" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24819"
- transform="translate(-1015,-999)">
+ id="g14854"
+ transform="translate(-70,21)"
+ inkscape:label="F-13">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1028,1556 c -3.2833,0 -6,2.4414 -6,5.5 0,1.7056 0.9046,3.146 2.1523,4.3594 l 0.9942,0.9941 a 0.50004997,0.50004997 0 0 0 0.3027,0.1485 0.50004997,0.50004997 0 0 0 0.051,0.998 h 5 a 0.50004997,0.50004997 0 0 0 0.045,-0.998 0.50004997,0.50004997 0 0 0 0.3086,-0.1485 l 0.9981,-0.998 v 0 c 1.2122,-1.1985 2.1465,-2.6518 2.1465,-4.3535 0,-3.0586 -2.7167,-5.5 -6,-5.5 z m 0,1 c 2.7919,0 5,2.0358 5,4.5 0,1.3342 -0.7428,2.5488 -1.8516,3.6445 l -1,1 a 0.50004997,0.50004997 0 0 0 0.2793,0.8535 h -4.8594 a 0.50004997,0.50004997 0 0 0 0.2871,-0.8535 l -1,-1 a 0.50004997,0.50004997 0 0 0 -0.01,-0.01 c -1.1397,-1.1082 -1.8477,-2.2864 -1.8477,-3.6406 0,-2.4642 2.2081,-4.5 5,-4.5 z m -2.5,12 a 0.50004997,0.50004997 0 1 0 0,1 h 1.5 v 0.5 a 0.50004997,0.50004997 0 0 0 0.5,0.5 h 1 a 0.50004997,0.50004997 0 0 0 0.5,-0.5 v -0.5 h 1.5 a 0.50004997,0.50004997 0 1 0 0,-1 z"
- id="path24815"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 333.49219,94.992188 A 0.50005,0.50005 0 0 0 333,95.5 v 8.91016 l -4.68555,1.875 a 0.50050477,0.50050477 0 1 0 0.3711,0.92968 l 4.82812,-1.93164 7.82422,2.68946 a 0.50005,0.50005 0 1 0 0.32422,-0.94532 L 334,104.39258 V 95.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z"
+ id="path14834"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 1025.4902,1561.0059 a 0.50005,0.50005 0 0 0 -0.3437,0.8476 l 0.8535,0.8535 v 1.543 a 0.50005,0.50005 0 1 0 1,0 V 1563 h 2 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.543 l 0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.707,-0.707 L 1029.293,1562 h -2.586 l -0.8535,-0.8535 a 0.50005,0.50005 0 0 0 -0.3633,-0.1406 z"
- id="path24817"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 335.50586,95.435547 c -0.27842,-0.0032 -0.50585,0.221565 -0.50586,0.5 v 6.884763 c -1.3e-4,0.21757 0.14044,0.41026 0.34766,0.47657 l 6,1.92968 c 0.32275,0.10319 0.65252,-0.13772 0.65234,-0.47656 v -6.884766 c 1.3e-4,-0.217571 -0.14044,-0.410257 -0.34766,-0.476562 l -6,-1.929688 c -0.0474,-0.01505 -0.0968,-0.02295 -0.14648,-0.02344 z"
+ id="path14836"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccc" />
+ </g>
+ <g
+ id="g19400"
+ style="display:inline;enable-background:new"
+ inkscape:label="F-11">
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12957"
+ transform="translate(-42)">
+ <g
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ transform="translate(-188.007,-44.0072)"
+ id="g12922">
+ <path
+ id="path12920"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 451.00718,171.00717 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z M 446.5,161 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 8 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 1 0 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 a 0.50005,0.50005 0 1 0 0,-1 H 452.4707 447.5 Z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ id="path12942"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 269.5,120 c -1.40822,0 -2.5,1.26701 -2.5,2.75195 v 1.5 c 0,1.48181 1.09178,2.74805 2.5,2.74805 1.40823,0 2.5,-1.26624 2.5,-2.74805 v -0.32031 a 0.50004994,0.50004994 0 1 0 -1,0 v 0.32031 c 0,1.00094 -0.69911,1.74805 -1.5,1.74805 -0.80086,0 -1.5,-0.74712 -1.5,-1.74805 v -1.5 C 268,121.7464 268.69914,121 269.5,121 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,-4 c -1.40823,0 -2.5,1.26624 -2.5,2.74805 v 0.32031 a 0.50004994,0.50004994 0 1 0 1,0 v -0.32031 C 268,117.74711 268.69911,117 269.5,117 c 0.80086,0 1.5,0.74712 1.5,1.74805 v 1.5 C 271,121.2536 270.30086,122 269.5,122 a 0.50004994,0.50004994 0 1 0 0,1 c 1.40822,0 2.5,-1.26701 2.5,-2.75195 v -1.5 C 272,117.26624 270.90822,116 269.5,116 Z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <rect
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect5375"
+ width="6"
+ height="5"
+ x="218"
+ y="119" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12950"
+ transform="translate(-42)"
+ inkscape:label="F-10">
+ <g
+ id="g12531-9"
+ transform="translate(-209.007,-44.0072)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 446.5,161 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 447 v -7 h 0.5 4.9707 1.0293 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452.4707 447.5 Z m 4.50718,10.00717 L 451,173 h -1.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 1.91992 c 0.0537,0.009 0.10843,0.009 0.16211,0 H 453.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 452 l 0.007,-1.99283 z"
+ id="path12529-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccc" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 206.5,115.99219 c -1.39025,0 -2.5,1.19177 -2.5,2.61523 V 120.5 a 0.50004994,0.50004994 0 1 0 1,0 v -1.89258 c 0,-0.91233 0.68117,-1.61523 1.5,-1.61523 0.81884,0 1.5,0.70289 1.5,1.61523 V 120.5 a 0.50004994,0.50004994 0 1 0 1,0 v -1.89258 c 0,-1.42345 -1.10974,-2.61523 -2.5,-2.61523 z m -2.00781,9 A 0.50004994,0.50004994 0 0 0 204,125.5 v 1.88477 c 0,1.42346 1.10975,2.61523 2.5,2.61523 1.39026,0 2.5,-1.19178 2.5,-2.61523 V 125.5 a 0.50004994,0.50004994 0 1 0 -1,0 v 1.88477 c 0,0.91234 -0.68116,1.61523 -1.5,1.61523 -0.81883,0 -1.5,-0.7029 -1.5,-1.61523 V 125.5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.50781 z"
+ transform="translate(42)"
+ id="path12537-3"
inkscape:connector-curvature="0" />
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
id="g25431"
- transform="translate(-21)">
+ transform="translate(-21)"
+ inkscape:label="F-7">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 153.5,119 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 9 v 9 h -9 z"
@@ -15473,7 +17024,8 @@
inkscape:export-xdpi="96"
inkscape:export-filename="blender_icons.png"
id="g13935-4"
- transform="translate(83.999996,42)">
+ transform="translate(84,42)"
+ inkscape:label="F-6">
<path
id="path13929-36"
d="m 36,74 c -2.455669,0 -4.49388,1.771475 -4.916016,4.105469 0.482305,-0.09011 0.975221,-0.129499 1.470704,-0.07422 0.662841,0.07415 0.551512,1.068296 -0.111329,0.994141 -0.485685,-0.05419 -0.971969,-0.01789 -1.4375,0.101562 0.06678,2.656434 2.202258,4.79532 4.857422,4.867188 0.121572,-0.473413 0.166164,-0.965209 0.109375,-1.455079 -0.03822,-0.293198 0.18493,-0.555356 0.480469,-0.564453 0.262666,-0.0085 0.487095,0.187762 0.513672,0.449219 0.05787,0.499184 0.03624,1.001242 -0.05469,1.490234 C 39.23754,83.484981 41,81.449595 41,79 41,76.23858 38.761426,74 36,74 Z m -1.568358,4.830076 c 0.100656,9.56e-4 0.198679,0.03227 0.28125,0.08984 0.540828,0.363139 1.00483,0.82779 1.367188,1.369141 0.405708,0.559881 -0.466114,1.144515 -0.830078,0.556641 -0.289893,-0.43309 -0.661079,-0.805188 -1.09375,-1.095703 -0.420141,-0.271725 -0.224948,-0.923754 0.27539,-0.919922 z"
@@ -15488,1027 +17040,1131 @@
</g>
<g
style="display:inline;fill:#ffffff;enable-background:new"
- id="g25821">
- <g
- id="g24262-4"
- transform="translate(-188.99644,-1801.0029)"
- style="display:inline;fill:#ffffff;enable-background:new">
- <path
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="rect24246-3"
- transform="translate(188.99644,1801.0029)"
- d="m 489.00391,329.99805 v 2 h 1 v -1 h 1 v -1 z m 0,4 v 2 h 1 v -2 z m 0,4 v 2 h 2 v -1 h -1 v -1 z m 9,0 v 1 h -1 v 1 h 2 v -2 z m -5,1 v 1 h 2 v -1 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
- </g>
+ id="g16385"
+ transform="translate(-21,21)"
+ inkscape:label="F-5">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 493.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.008,4.00586 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4.5 v 4.50195 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path24264-0"
+ id="path16351"
+ d="m 118,95.5 c -3.58986,0 -6.5,2.41014 -6.5,6 1,1 3,2.5 6.5,2.5 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccc" />
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 118,95 c -3.86007,0 -7,3.139925 -7,7 0,3.86008 3.13992,7 7,7 3.86008,0 7,-3.13992 7,-7 0,-3.860075 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.680365 6,6 0,3.31964 -2.68036,6 -6,6 -3.31964,0 -6,-2.68036 -6,-6 0,-3.319635 2.68037,-6 6,-6 z"
+ id="path16353"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 123.24414,102.64453 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 0.5,0.5 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -0.5,-0.5 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m -2.25,0.75 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 1.75,1.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -1.75,-1.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m -2.5,0.5 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 2.75,2.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -2.75,-2.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z m 0,3 a 0.60006002,0.60006002 0 0 0 -0.41797,1.0293 l 0.75,0.75 a 0.60006002,0.60006002 0 1 0 0.84766,-0.84766 l -0.75,-0.75 a 0.60006002,0.60006002 0 0 0 -0.42969,-0.18164 z"
+ id="path16355"
+ inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 472.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.006,3.50586 -3.49804,0.002 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path24338-8"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccc" />
<g
+ transform="translate(-252,-252)"
+ id="g10731"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g25828"
- transform="translate(-1)">
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="F-4">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 515.49805,329.98633 c -0.27766,-0.001 -0.50302,0.22429 -0.50196,0.50195 l 0.008,5.00586 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.99805 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path24344-9"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 328,368 c -3.86007,0 -7,3.13993 -7,7 0,3.86007 3.13993,7 7,7 3.86007,0 7,-3.13993 7,-7 0,-3.86007 -3.13993,-7 -7,-7 z m 0,1 c 3.31963,0 6,2.68037 6,6 0,3.31963 -2.68037,6 -6,6 -3.31963,0 -6,-2.68037 -6,-6 0,-3.31963 2.68037,-6 6,-6 z"
+ id="path10721"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 327.12891,369.9668 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 c -2.00329,0.41569 -3.57155,1.99062 -3.97656,3.9961 a 1.0003053,1.0003053 0 1 0 1.96093,0.39648 c 0.24758,-1.22589 1.19732,-2.17949 2.42188,-2.43359 a 1.0001,1.0001 0 0 0 -0.23828,-1.98242 z"
+ id="path10723"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 332.49609,373.0957 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -0.75,2.25 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -1.25,1.75 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -1.75,1.25 a 0.40004001,0.40004001 0 0 0 -0.27929,0.6875 l 2,2 a 0.40050528,0.40050528 0 1 0 0.5664,-0.5664 l -2,-2 a 0.40004001,0.40004001 0 0 0 -0.28711,-0.1211 z m -2.23632,0.75 a 0.40004001,0.40004001 0 0 0 -0.27344,0.70508 l 2,1.75 a 0.40004001,0.40004001 0 1 0 0.52734,-0.60156 l -2,-1.75 a 0.40004001,0.40004001 0 0 0 -0.2539,-0.10352 z"
+ id="path10727"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g81315"
+ inkscape:label="F-3">
<g
- id="g24392-5"
- transform="translate(-166.99644,-1801.0029)"
- style="display:inline;fill:#ffffff;enable-background:new">
+ id="g10010"
+ style="display:inline;enable-background:new"
+ inkscape:label="g10010">
<path
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaccc"
inkscape:connector-curvature="0"
- id="rect24376-2"
- transform="translate(166.99644,1801.0029)"
- d="M 515.00391,325.99609 V 326 H 515 v 2 h 1 v -1.00391 h 1.00391 v -1 z m 4,0 v 1 h 2 v -1 z M 523,326 v 1 h 1 v 1 h 1.00391 v -2.00391 z m 1.00391,3.99609 v 2 h 1 v -2 z m -13,0.002 v 2 h 1 v -1 h 1 v -1 z m 13,3.99804 v 1 h -1 v 1 h 2 v -2 z m -13,0.002 v 2 h 1 v -2 z m 0,4 v 2 h 2 v -1 h -1 v -1 z m 9,0 v 1 h -1 v 1 h 2 v -2 z m -5,1 v 1 h 2 v -1 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ id="path6587"
+ d="M 61.503909,123 A 6.5039066,6.5039066 0 0 1 55.000003,129.50391 6.5039066,6.5039066 0 0 1 48.496097,123 6.5039066,6.5039066 0 0 1 55.000003,116.4961 6.5039066,6.5039066 0 0 1 61.503909,123 Z"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- </g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 535.49609,325.98633 c -0.27689,3e-5 -0.50105,0.22506 -0.5,0.50195 l 0.008,3.00781 c 10e-4,0.27537 0.22463,0.49802 0.5,0.49805 h 5.5 v 5.50195 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -4,4.0039 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 9 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 9.00782,0.01 c 0.27689,-3e-5 0.50105,-0.22506 0.5,-0.50195 l -0.008,-3.00586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -5.5 v -5.50196 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path24415-7"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccc" />
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g25815">
<g
- transform="translate(-230.99644,-1801.0029)"
- id="g24435-3"
+ id="g6601"
style="display:inline;fill:#ffffff;enable-background:new">
<path
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccacccaccccc"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 61.503909,123 c 0,3.59202 -2.911894,6.50391 -6.503906,6.50391 -3.592012,0 -6.503906,-2.91189 -6.503906,-6.50391 0,-3.59201 2.911894,-6.5039 6.503906,-6.5039 3.592012,0 6.503906,2.91189 6.503906,6.5039 z"
+ id="path6589"
inkscape:connector-curvature="0"
- id="rect24419-6"
- transform="translate(230.99644,1801.0029)"
- d="m 447.00391,325.99805 v 2 h 1 v -1 h 1 v -1 z m 4,0 v 1 h 2 v -1 z m 4,0 v 1 h 2 v -1 z m 4,0 v 1 h 1 v 1 h 1 v -2 z m -12,4 v 2 h 1 v -2 z m 13,0 v 2 h 1 v -2 z m -13,4 v 2 h 1 v -2 z m 13,0 v 2 h 1 v -2 z m -13,4 v 2 h 2 v -1 h -1 v -1 z m 13,0 v 1 h -1 v 1 h 2 v -2 z m -9,1 v 1 h 2 v -1 z m 4,0 v 1 h 2 v -1 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none" />
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 54.999998,115.99609 c -3.862225,0 -7.003902,3.14168 -7.003906,7.00391 -2e-6,3.86223 3.141676,7.00391 7.003906,7.00391 3.86223,0 7.003908,-3.14168 7.003906,-7.00391 -4e-6,-3.86223 -3.141681,-7.00391 -7.003906,-7.00391 z m 0,1 c 3.321786,0 6.003903,2.68212 6.003906,6.00391 2e-6,3.32179 -2.682117,6.00391 -6.003906,6.00391 -3.321789,0 -6.003908,-2.68212 -6.003906,-6.00391 3e-6,-3.32179 2.68212,-6.00391 6.003906,-6.00391 z"
+ id="path10735"
+ inkscape:connector-curvature="0" />
</g>
</g>
<g
- transform="translate(876,-1690)"
+ id="g6366"
style="display:inline;fill:#ffffff;enable-background:new"
- id="g24686-1"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:label="F-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -419.5,1827 a 0.50005,0.50005 0 1 0 0,1 h 2.79492 l -2.96875,2.9688 c 0.24471,0.2267 0.48032,0.4623 0.70703,0.707 L -416,1828.709 v 2.791 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -2.98438,6.7793 -3.50585,3.5059 C -426.28828,1837.1081 -426.63057,1837 -427,1837 c -1.09865,0 -2,0.9013 -2,2 0,1.0986 0.90135,2 2,2 1.09865,0 2,-0.9014 2,-2 0,-0.3677 -0.10771,-0.7107 -0.2832,-1.0078 l 3.50586,-3.5059 c -0.22252,-0.2491 -0.45807,-0.4843 -0.70704,-0.707 z M -427,1838 c 0.55821,0 1,0.4417 1,1 0,0.5582 -0.44179,1 -1,1 -0.55821,0 -1,-0.4418 -1,-1 0,-0.5583 0.44179,-1 1,-1 z"
- id="path24506-4"
+ inkscape:connector-curvature="0"
+ id="path14380-1"
+ d="m 34,116 c -3.860075,0 -7,3.13992 -7,7 0,3.86007 3.139928,7 7,7 3.860072,0 7,-3.13993 7,-7 0,-3.86008 -3.139925,-7 -7,-7 z m 0,1 c 3.319633,0 6,2.68036 6,6 0,3.31963 -2.680364,6 -6,6 -3.319636,0 -6,-2.68037 -6,-6 0,-3.31964 2.680367,-6 6,-6 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path14287"
+ transform="translate(540,10)"
+ d="m -506.01562,106.24414 a 0.50005,0.50005 0 0 0 -0.375,0.19336 c -0.70647,0.88308 -1.16919,1.99665 -1.41016,3.5625 H -511.75 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 3.83203 c -0.0522,0.60644 -0.082,1.26334 -0.082,2 0,0.73665 0.0299,1.39356 0.082,2 H -511.75 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 3.94922 c 0.24099,1.56587 0.70375,2.67949 1.41016,3.5625 a 0.50024408,0.50024408 0 0 0 0.78124,-0.625 c -0.56556,-0.70695 -0.96391,-1.59657 -1.18554,-2.9375 h 6.54492 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -6.66797 c -0.0526,-0.59052 -0.082,-1.24749 -0.082,-2 0,-0.75251 0.0294,-1.40947 0.082,-2 h 6.66797 c 0.67616,0.01 0.67616,-1.00956 0,-1 h -6.54492 c 0.22165,-1.34096 0.62004,-2.23062 1.18554,-2.9375 a 0.50005,0.50005 0 0 0 -0.40624,-0.81836 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g19381"
+ style="display:inline;enable-background:new"
+ inkscape:label="F-1">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -428.49556,1829 a 0.4997692,0.49966962 0 1 0 0,0.9993 c 5.80308,0 10.49606,4.6921 10.49606,10.494 a 0.4997692,0.49966962 0 1 0 0.99944,0 c 0,-6.3418 -5.1523,-11.4933 -11.4955,-11.4933 z"
- id="ellipse24510-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 6.5,116 A 0.50005,0.50005 0 0 0 6,116.5 v 4 a 0.50005,0.50005 0 1 0 1,0 V 117 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 z m 9.007812,0 a 0.50005,0.50005 0 1 0 0,1 h 3.5 v 3.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -9.0156245,9 A 0.50005,0.50005 0 0 0 6,125.50781 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 H 7 v -3.5 A 0.50005,0.50005 0 0 0 6.4921875,125 Z M 19.5,125 a 0.50005,0.50005 0 0 0 -0.492188,0.50781 v 3.5 h -3.5 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 A 0.50005,0.50005 0 0 0 19.5,125 Z"
+ id="path13927"
inkscape:connector-curvature="0" />
</g>
- <path
- id="path22885-3-7"
- d="m 537.4922,557 c -0.1299,0 -0.2539,0.055 -0.3457,0.1465 -1.4018,1.4018 -2.9571,1.8535 -5.6465,1.8535 -0.2761,0 -0.5,0.2239 -0.5,0.5 v 3 c 0,2.4627 0.6805,4.0682 1.7871,5.2754 1.1066,1.2072 2.5736,2.0242 4.1777,3.1348 0.084,0.058 0.1832,0.09 0.2852,0.09 h 0.5 c 0.102,-2e-4 0.2015,-0.032 0.2852,-0.09 1.6041,-1.1106 3.0711,-1.9276 4.1777,-3.1348 C 543.3195,566.5682 544,564.9627 544,562.5 v -3 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 -2.6894,0 -4.2447,-0.4517 -5.6465,-1.8535 -0.096,-0.096 -0.226,-0.1486 -0.3613,-0.1465 z m 3.4766,3.9902 a 1.0001,1.0001 0 0 1 0.8124,1.6348 l -4,5 a 1.0001,1.0001 0 0 1 -1.4882,0.082 l -2,-2 a 1.0001,1.0001 0 1 1 1.414,-1.414 l 1.209,1.209 3.3028,-4.127 a 1.0001,1.0001 0 0 1 0.75,-0.3848 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 516.49219,557 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 C 514.74469,558.54828 513.18939,559 510.5,559 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 c 0,2.46272 0.6805,4.06818 1.78711,5.27539 1.10661,1.20722 2.57356,2.02419 4.17773,3.13477 A 0.50005,0.50005 0 0 0 516.25,571 h 0.5 a 0.50005,0.50005 0 0 0 0.28516,-0.0898 c 1.60417,-1.11058 3.07112,-1.92755 4.17773,-3.13477 C 522.3195,566.56818 523,564.96272 523,562.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 c -2.68939,0 -4.24469,-0.45172 -5.64648,-1.85352 A 0.50005,0.50005 0 0 0 516.49219,557 Z m 0.008,1.07031 c 1.42533,1.26825 3.16641,1.79779 5.5,1.86524 V 562.5 c 0,2.28728 -0.5695,3.55682 -1.52539,4.59961 -0.92707,1.01135 -2.30655,1.81425 -3.88867,2.90039 h -0.17188 c -1.58212,-1.08614 -2.9616,-1.88904 -3.88867,-2.90039 C 511.5695,566.05682 511,564.78728 511,562.5 v -2.56445 c 2.33359,-0.0675 4.07467,-0.59699 5.5,-1.86524 z"
- id="path22877-22-0"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- d="m 512,414.00018 h 9 v 5 h -9 z m -1.5,-2 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 1 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.6573,-0.009 0.6573,-0.9907 0,-1 H 517 v -1 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 11 v 7 h -11 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="rect22324-2" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 489.5,412 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 8 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5.5 v 1 h -2.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 6 c 0.6573,-0.009 0.6573,-0.9907 0,-1 H 496 v -1 h 5.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -8 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 11 v 7 h -11 z"
- id="path22338-8"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccc" />
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g25476"
- transform="translate(-20)">
+ transform="translate(84,-21)"
+ id="g29069"
+ style="display:inline;enable-background:new"
+ inkscape:label="E-26">
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g25445"
- transform="translate(-218,-111)">
+ id="g29057">
<path
- sodipodi:nodetypes="ssssccccccccssssccs"
+ d="m 454,117 a 6,6 0 0 1 6,6 6,6 0 0 1 -6,6"
+ sodipodi:open="true"
+ sodipodi:end="1.5707963"
+ sodipodi:start="4.712389"
+ sodipodi:ry="6"
+ sodipodi:rx="6"
+ sodipodi:cy="123"
+ sodipodi:cx="454"
+ sodipodi:type="arc"
+ id="path28993"
+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ sodipodi:arc-type="arc" />
+ <g
+ id="g29030">
+ <circle
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="path29001"
+ cx="448"
+ cy="123"
+ r="1" />
+ <circle
+ r="1"
+ cy="120"
+ cx="448.80383"
+ id="circle29003"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ <circle
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="circle29005"
+ cx="451"
+ cy="117.80385"
+ r="1" />
+ <circle
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="circle29014"
+ cx="448.80383"
+ cy="-126"
+ r="1"
+ transform="scale(1,-1)" />
+ <circle
+ r="1"
+ cy="-128.19615"
+ cx="451"
+ id="circle29016"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ transform="scale(1,-1)" />
+ </g>
+ </g>
+ <path
+ id="path16341-3-5"
+ style="display:inline;opacity:0.99;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
+ d="m 456.5,123.5 -3,-4e-5 V 120.5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ </g>
+ <g
+ transform="translate(63,-21)"
+ id="g29117"
+ style="display:inline;enable-background:new"
+ inkscape:label="E-25">
+ <g
+ id="g29100"
+ transform="translate(295,-378)"
+ style="display:inline;opacity:1;stroke:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 152.00001,498.99995 v 4.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -4.5 v 5"
+ id="path29096"
inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 301.5,305 c -0.82235,0 -1.5,0.67765 -1.5,1.5 v 5 c 0,0.82235 1,1.5 1.5,1.5 h 0.5 v -3 h -0.5 c -0.67616,0.01 -0.67616,-1.01 0,-1 h 11 c 0.67616,-0.01 0.67616,1.01 0,1 H 312 v 3 h 0.5 c 0.82235,0 1.5,-0.67765 1.5,-1.5 v -5 c 0,-0.82235 -0.67765,-1.5 -1.5,-1.5 H 312 302 Z"
- transform="translate(70,363)"
- id="path25441" />
+ sodipodi:nodetypes="ccccccccc" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 135,562 v 8.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 562 Z m 6,2 c 0.54636,0 1,0.45364 1,1 0,0.54636 -0.45364,1 -1,1 -0.54636,0 -1,-0.45364 -1,-1 0,-0.54636 0.45364,-1 1,-1 z m -2.50781,2 c 0.16994,-0.003 0.32953,0.0812 0.42383,0.22266 l 2,3 c 0.22142,0.33228 -0.0167,0.77726 -0.41602,0.77734 h -4 c -0.39932,-8e-5 -0.63744,-0.44506 -0.41602,-0.77734 l 2,-3 c 0.0912,-0.13686 0.24381,-0.21966 0.40821,-0.22266 z"
- transform="translate(238,111)"
- id="path25443"
+ sodipodi:nodetypes="cccc"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
+ d="m 152.50001,497.49995 h 3 v -3 z"
+ id="path29098"
inkscape:connector-curvature="0" />
</g>
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="blender_icons.png"
+ id="path29102"
+ d="m 460,120.50004 0.5,2e-5 v 9 h -9 L 451.49999,129"
+ style="display:inline;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ style="display:inline;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
+ d="m 458,118.50004 0.5,2e-5 v 9 h -9 L 449.49999,127"
+ id="path29110"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ inkscape:connector-curvature="0" />
</g>
- <path
- sodipodi:nodetypes="ccccccscsccccccccccccccccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path5256"
- d="m 197.50977,409.99414 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5039 c 0.0205,0.58311 0.0403,1.03618 -0.0488,1.24805 -0.22838,0.54301 -0.5609,0.82668 -1.00781,1.10937 -0.44691,0.28269 -1.00733,0.53131 -1.53711,0.97461 -0.52977,0.4433 -1.00108,1.10059 -1.22656,2.08789 -0.22548,0.9873 -0.2332,2.29903 0.0625,4.16406 0.0385,0.24311 0.24801,0.42203 0.49414,0.42188 h 8.75586 c 0.30739,1.4e-4 0.54213,-0.2745 0.49414,-0.57812 -0.36883,-2.32606 -0.21493,-3.6368 0.12305,-4.40821 0.33798,-0.7714 0.85304,-1.08606 1.49804,-1.45508 0.645,-0.36901 1.43565,-0.7809 1.90821,-1.70703 0.47255,-0.92613 0.59571,-2.25921 0.21289,-4.4375 C 208.70043,411.17484 208.49284,411.0002 208.25,411 h -7.24023 v -0.50586 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z m 3,1.00586 h 6.78125 c 0.25456,1.74951 0.14487,2.81594 -0.15235,3.39844 -0.3247,0.63637 -0.84774,0.91198 -1.51367,1.29297 -0.66593,0.38098 -1.46183,0.87882 -1.91797,1.91992 -0.41222,0.94085 -0.49675,2.35477 -0.23633,4.38867 h -7.73437 c -0.19264,-1.47462 -0.23076,-2.65205 -0.0684,-3.36328 0.18281,-0.80045 0.49635,-1.21142 0.89258,-1.54297 0.39622,-0.33155 0.90291,-0.56523 1.42968,-0.89844 0.52678,-0.33321 1.07351,-0.7985 1.39649,-1.5664 0.22021,-0.52359 0.17686,-1.05487 0.13867,-1.63477 h 0.48438 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="path5262"
- d="m 180.5,410 c -2.08712,0 -3.47816,1.04607 -4.39062,2.1875 a 0.50024408,0.50024408 0 0 0 0.78125,0.625 C 177.69049,411.81193 178.73439,411 180.5,411 c 2.09839,0 3.13411,0.87695 3.75195,1.94531 C 184.8698,414.01367 185,415.31651 185,416 h -5.25 c -1.27344,0 -2.44324,0.36418 -3.31445,1.05469 -0.87121,0.69051 -1.42774,1.72791 -1.42774,2.94531 0,1.2174 0.55653,2.2548 1.42774,2.94531 C 177.30676,423.63582 178.47656,424 179.75,424 h 0.75 c 1.75558,0 3.38771,-0.96684 4.53711,-2.0332 0.0781,0.53303 0.28951,1.00434 0.64062,1.35547 C 186.12862,423.77315 186.775,424 187.5,424 a 0.50005,0.50005 0 1 0 0,-1 c -0.525,0 -0.87862,-0.14815 -1.11523,-0.38477 C 186.14815,422.37862 186,422.025 186,421.5 V 416 c 0,-0.79721 -0.12242,-2.24322 -0.88086,-3.55469 C 184.3607,411.13385 182.89646,410 180.5,410 Z m -0.75,7 H 185 v 3.56055 C 184.04582,421.68473 182.18875,423 180.5,423 h -0.75 c -1.08101,0 -2.03187,-0.31555 -2.69336,-0.83984 -0.66149,-0.52429 -1.04883,-1.23676 -1.04883,-2.16016 0,-0.9234 0.38734,-1.63587 1.04883,-2.16016 C 177.71813,417.31555 178.66899,417 179.75,417 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(-105,-20.999997)"
- id="g24881"
- style="display:inline;fill:#ffffff;enable-background:new">
+ id="g26820"
+ style="display:inline;enable-background:new"
+ inkscape:label="E-24">
<path
+ sodipodi:nodetypes="cccccccccccccccccccccccc"
inkscape:connector-curvature="0"
- id="path24877"
- d="m 183.8125,200.01562 c 2.21359,0.18235 3.97803,1.94071 4.16992,4.1543 0.19189,2.2136 -1.24344,4.25155 -3.39258,4.8125 a 0.5007349,0.5007349 0 1 1 -0.2539,-0.96875 c 1.68376,-0.43948 2.80079,-2.02289 2.65039,-3.75781 -0.1504,-1.73492 -1.52164,-3.10129 -3.25586,-3.24414 -1.73423,-0.14285 -3.31219,0.98104 -3.74414,2.66797 a 0.50005,0.50005 0 1 1 -0.96875,-0.24805 c 0.55114,-2.15241 2.58133,-3.59836 4.79492,-3.41602 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path28780"
+ d="m 495.98438,95 c -0.25978,0.004 -0.50774,0.10921 -0.69141,0.29297 l -6,6 C 489.08739,101.49869 488.99817,101.75204 489,102 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.5 v 5.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.5 v -5.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 3 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 5.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 103 h 0.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 102 c 0.004,-0.25043 -0.0852,-0.49916 -0.29297,-0.70703 l -6,-6 C 496.51571,95.10156 496.25496,94.99586 495.98438,95 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ transform="translate(-0.999993)"
+ id="g4126"
+ style="display:inline;enable-background:new"
+ inkscape:label="E-23">
<g
- id="g24891"
- transform="matrix(-1,0,0,1,356.9996,0)"
- style="fill:#ffffff">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="matrix(0.659143,0,0,0.659143,248.471,-214.895)"
+ id="g12839-3-5">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 352.97527,473.19666 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -0.41128,0.47153 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.41128,-0.47153 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -3.39644,2.7168 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -6.22807,6.22726 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 0,0 6.17898,-6.1737 6.22807,-6.22726 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22605,-0.14856 -0.36137,-0.14648 z"
+ id="path12837-6-3"
inkscape:connector-curvature="0"
- d="M 176.99634,212.50183 A 1.4981741,1.4981725 0 0 1 175.49817,214 a 1.4981741,1.4981725 0 0 1 -1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49818,-1.49817 1.4981741,1.4981725 0 0 1 1.49817,1.49817 z m 2.39233,-7.41199 c 0.85602,0.17256 1.66292,0.59211 2.30469,1.23828 1.28353,1.29236 1.66074,3.23682 0.95508,4.91602 -0.70566,1.6792 -2.35829,2.76833 -4.17969,2.75586 a 0.50005,0.50005 0 1 1 0.008,-1 c 1.41921,0.01 2.70016,-0.83611 3.25,-2.14453 0.54985,-1.30842 0.25598,-2.81527 -0.74414,-3.82227 -1.00012,-1.00699 -2.50427,-1.31041 -3.8164,-0.76953 C 175.85388,206.80455 175,208.08075 175,209.5 a 0.50005,0.50005 0 1 1 -1,0 c 0,-1.82144 1.10118,-3.466 2.78516,-4.16016 0.84199,-0.34708 1.7475,-0.42255 2.60351,-0.25 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="ellipse24887" />
+ sodipodi:nodetypes="cccccccscccccccccccccccc" />
</g>
+ <path
+ sodipodi:nodetypes="csscccccccccccssscccc"
+ style="opacity:0.6;fill:#ffffff"
+ inkscape:connector-curvature="0"
+ id="path2-6"
+ d="m 469,101 v 7.5 c 0,0.276 0.224,0.5 0.5,0.5 h 11 c 0.30423,0 0.5,-0.22782 0.5,-0.5 v -4 c 0,-0.65459 -1,-0.65682 -1,0 v 3.5 h -10 v -7 z m 4.48081,-6 c -0.151,0.004 -0.293,0.077 -0.384,0.197 l -3.95,3.949 c -0.314,0.315 -0.091,0.854 0.354,0.854 h 4 c 0.276,0 0.5,-0.224 0.5,-0.5 V 96 H 480.5 c 0.68512,0 0.64092,-1 0,-1 z" />
</g>
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 490,307 c -0.55226,6e-5 -0.99994,0.44774 -1,1 v 8 c 6e-5,0.55226 0.44774,0.99994 1,1 h 12 c 0.55226,-6e-5 0.99994,-0.44774 1,-1 v -8 c -6e-5,-0.55226 -0.44774,-0.99994 -1,-1 z m 6,1 a 4,4 0 0 1 4,4 4,4 0 0 1 -4,4 4,4 0 0 1 -4,-4 4,4 0 0 1 4,-4 z"
- id="path25011-0" />
<g
- transform="translate(1055,731)"
- style="display:inline;opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="g25234-0">
+ id="g3389"
+ inkscape:label="E-9"
+ style="display:inline;enable-background:new">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -580,-424 c -2.7555,0 -5,2.2445 -5,5 0,2.7555 2.2445,5 5,5 2.7555,0 5,-2.2445 5,-5 0,-2.7555 -2.2445,-5 -5,-5 z m 0,1 c 2.21506,0 4,1.78494 4,4 0,2.21506 -1.78494,4 -4,4 -2.21506,0 -4,-1.78494 -4,-4 0,-2.21506 1.78494,-4 4,-4 z m -0.52148,1 a 0.50005,0.50005 0 0 0 -0.084,0.0117 c -1.2099,0.24373 -2.15796,1.187 -2.38476,2.38867 a 0.50005,0.50005 0 1 0 0.98242,0.18555 c 0.15048,-0.79727 0.77874,-1.42839 1.59961,-1.59375 A 0.50005,0.50005 0 0 0 -580.52148,-422 Z"
- id="path25232-0"
+ d="m 181.13795,94.59407 c -0.39468,0.0302 -0.78775,0.12022 -1.16797,0.27148 -1.52086,0.60507 -2.52148,2.07999 -2.52148,3.716796 a 0.50005,0.50005 0 0 0 0.0156,0.13281 c -0.36519,0.0927 -0.72282,0.22834 -1.0586,0.42774 -1.44139,0.85595 -2.17088,2.516884 -1.8789,4.144534 -0.68715,0.57705 -1.10816,1.44799 -1.07617,2.39648 0.0502,1.48769 1.19214,2.71921 2.67187,2.88086 1.39818,0.15274 2.69975,-0.69789 3.15234,-2.00781 0.89605,0.0388 1.7697,-0.22225 2.49805,-0.74609 1.07373,0.85551 2.55787,1.01607 3.78906,0.37695 1.30171,-0.67573 2.04374,-2.09602 1.85742,-3.55078 -0.16328,-1.27499 -1.01006,-2.34261 -2.17968,-2.806644 0.45466,-1.38242 0.13144,-2.921096 -0.88477,-3.996096 -0.56221,-0.59473 -1.27727,-0.98709 -2.04297,-1.15625 -0.38285,-0.0846 -0.77914,-0.11418 -1.17382,-0.084 z m 0.52149,0.99609 c 0.73445,0.0517 1.44053,0.37287 1.96874,0.93164 0.84514,0.89404 1.0593,2.208446 0.54101,3.324216 a 0.50005,0.50005 0 0 0 -0.0527,0.216804 0.50005,0.50005 0 0 0 0.38672,0.58203 c 1.02426,0.23341 1.79232,1.07713 1.92578,2.11914 0.13345,1.04201 -0.39575,2.0531 -1.32813,2.53711 -0.93238,0.48401 -2.06443,0.33572 -2.83983,-0.37305 a 0.50005,0.50005 0 0 0 -0.20313,-0.11914 0.50005,0.50005 0 0 0 -0.28125,-0.0977 0.50005,0.50005 0 0 0 -0.35156,0.1289 c -0.65771,0.57559 -1.53314,0.83597 -2.39844,0.71289 a 0.50008765,0.50008765 0 0 0 -0.54297,0.33008 0.50005,0.50005 0 0 0 -0.0977,0.19727 c -0.24832,0.96717 -1.16166,1.59867 -2.15429,1.49023 -0.99264,-0.10844 -1.7476,-0.92195 -1.78125,-1.91992 -0.0231,-0.68418 0.30371,-1.29829 0.82422,-1.67774 a 0.50005,0.50005 0 0 0 0.16601,-0.11718 c 0.19833,-0.11547 0.41799,-0.19976 0.65625,-0.24219 a 0.50005,0.50005 0 0 0 -0.0898,-0.99414 0.50005,0.50005 0 0 0 -0.084,0.01 c -0.16025,0.0285 -0.31331,0.0746 -0.46289,0.12695 -0.0646,-1.10299 0.47775,-2.17237 1.45703,-2.75391 1.15771,-0.687484 2.62445,-0.520214 3.59961,0.4082 a 0.50009806,0.50009806 0 0 0 0.68945,-0.724604 c -0.64816,-0.6171 -1.46287,-0.98259 -2.30859,-1.07813 -0.14875,-0.017 -0.29936,-0.0157 -0.44925,-0.0158 a 0.50005,0.50005 0 0 0 0,-0.01 c 0,-1.230266 0.7475,-2.332316 1.89062,-2.787106 0.42867,-0.17055 0.87964,-0.23611 1.32032,-0.20508 z"
+ id="path21574-1-2-7"
inkscape:connector-curvature="0" />
</g>
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 541.77363,306 a 1.0001,1.0001 0 0 0 -0.41211,0.0781 l -4.74024,2 a 1.0004654,1.0004654 0 1 0 0.77735,1.84376 l 1.54883,-0.65235 -2.69532,5.375 -2.78906,-2.30078 a 1.50015,1.50015 0 1 0 -1.9082,2.3125 l 4.24023,3.5 a 1.50015,1.50015 0 0 0 2.29688,-0.48437 l 3.53711,-7.0586 0.41015,1.63086 a 1.0001,1.0001 0 1 0 1.93946,-0.48828 l -1.25977,-5 A 1.0001,1.0001 0 0 0 541.77363,306 Z"
- id="path25427-8" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 520.51395,306 a 0.50005,0.50005 0 0 0 -0.23633,0.0527 l -4,2 a 0.50005,0.50005 0 1 0 0.44532,0.89454 l 2.8164,-1.40821 -4.20508,8.1875 -4.52148,-3.61718 a 0.50024018,0.50024018 0 1 0 -0.625,0.78124 l 5,4 a 0.50005,0.50005 0 0 0 0.75781,-0.1621 l 4.4375,-8.64063 0.63281,2.5332 a 0.50005,0.50005 0 1 0 0.96876,-0.24218 l -1,-4 A 0.50005,0.50005 0 0 0 520.51395,306 Z"
- id="path25488-0"
- inkscape:connector-curvature="0" />
<g
- id="g5381"
- style="fill:#ffffff">
+ id="g3392"
+ inkscape:label="E-8"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03999233px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 329.97518,350.98014 a 0.52004817,0.52004817 0 0 0 -0.38086,0.19532 l -3.61133,4.51562 -3.09179,-3.5332 a 0.52004817,0.52004817 0 1 0 -0.78321,0.68359 l 3.5,4 a 0.52004817,0.52004817 0 0 0 0.79883,-0.0176 l 3.61133,-4.51367 3.08984,3.53125 a 0.52004817,0.52004817 0 1 0 0.78321,-0.68359 l -3.5,-4 a 0.52004817,0.52004817 0 0 0 -0.41602,-0.17774 z"
- id="path4898"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 160.47797,94.72823 c -0.39468,0.0302 -0.78775,0.12022 -1.16797,0.27148 -1.52086,0.60507 -2.52148,2.07999 -2.52148,3.716796 a 0.50005,0.50005 0 0 0 0.0156,0.13281 c -0.36518,0.0927 -0.72282,0.22834 -1.05859,0.42774 -1.4414,0.855954 -2.17089,2.516884 -1.87891,4.144534 -0.68714,0.57705 -1.10816,1.44799 -1.07617,2.39648 0.0502,1.48769 1.19214,2.71921 2.67187,2.88086 1.39818,0.15274 2.69975,-0.69789 3.15235,-2.00781 0.89604,0.0388 1.76969,-0.22225 2.49804,-0.74609 1.07373,0.85551 2.55788,1.01607 3.78907,0.37695 1.30171,-0.67573 2.04374,-2.09602 1.85742,-3.55078 -0.16328,-1.27499 -1.01006,-2.34261 -2.17968,-2.806644 0.45466,-1.38242 0.13144,-2.921096 -0.88477,-3.996096 -0.56221,-0.59473 -1.27727,-0.98709 -2.04297,-1.15625 -0.38285,-0.0846 -0.77915,-0.11418 -1.17383,-0.084 z m 0.52149,0.99609 c 0.73445,0.0517 1.44053,0.37287 1.96875,0.93164 0.84514,0.89404 1.0593,2.208446 0.54101,3.324216 a 0.50005,0.50005 0 0 0 -0.0527,0.216804 0.50005,0.50005 0 0 0 0.38672,0.58203 c 1.02426,0.23341 1.79232,1.07713 1.92578,2.11914 0.13345,1.04201 -0.39575,2.0531 -1.32813,2.53711 -0.93238,0.48401 -2.06444,0.33572 -2.83984,-0.37305 a 0.50005,0.50005 0 0 0 -0.20313,-0.11914 0.50005,0.50005 0 0 0 -0.28125,-0.0977 0.50005,0.50005 0 0 0 -0.35156,0.1289 c -0.65771,0.57559 -1.53314,0.83597 -2.39844,0.71289 a 0.50008765,0.50008765 0 0 0 -0.54296,0.33008 0.50005,0.50005 0 0 0 -0.0977,0.19727 c -0.24833,0.96717 -1.16166,1.59867 -2.1543,1.49023 -0.99264,-0.10844 -1.7476,-0.92195 -1.78125,-1.91992 -0.0231,-0.68418 0.30371,-1.29829 0.82422,-1.67774 a 0.50005,0.50005 0 0 0 0.16601,-0.11718 c 0.19833,-0.11547 0.41799,-0.19976 0.65625,-0.24219 a 0.50005,0.50005 0 0 0 -0.0898,-0.99414 0.50005,0.50005 0 0 0 -0.084,0.01 c -0.16025,0.0285 -0.31331,0.0746 -0.46289,0.12695 -0.0646,-1.10299 0.47775,-2.17237 1.45703,-2.75391 1.15771,-0.687484 2.62445,-0.520214 3.59961,0.4082 a 0.5001015,0.5001015 0 0 0 0.68946,-0.724604 c -0.64816,-0.6171 -1.46288,-0.98259 -2.3086,-1.07813 -0.14875,-0.017 -0.29935,-0.0157 -0.44925,-0.0158 a 0.50005,0.50005 0 0 0 0,-0.01 c 0,-1.230266 0.7475,-2.332316 1.89062,-2.787106 0.42868,-0.17055 0.87964,-0.23611 1.32032,-0.20508 z"
+ id="path21574-1-2"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g3395"
+ inkscape:label="E-7"
+ style="display:inline;enable-background:new">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 139.512,94.8218 c -0.39468,0.0302 -0.78775,0.12022 -1.16797,0.27148 -1.52086,0.60507 -2.52148,2.07999 -2.52148,3.716796 -7.6e-4,0.0448 0.004,0.0894 0.0156,0.13281 -0.36519,0.0927 -0.72282,0.22834 -1.0586,0.42774 -1.44139,0.855954 -2.17088,2.516884 -1.8789,4.144534 -0.68715,0.57705 -1.10816,1.44799 -1.07617,2.39648 0.0502,1.48769 1.19214,2.71921 2.67187,2.88086 1.39818,0.15274 2.69975,-0.69789 3.15234,-2.00781 0.89605,0.0388 1.7697,-0.22225 2.49805,-0.74609 1.07373,0.85551 2.55788,1.01607 3.78907,0.37695 1.3017,-0.67573 2.04373,-2.09602 1.85741,-3.55078 -0.16328,-1.27499 -1.01005,-2.34261 -2.17967,-2.80664 0.45466,-1.382424 0.13144,-2.9211 -0.88477,-3.9961 -0.56221,-0.59473 -1.27728,-0.98709 -2.04298,-1.15625 -0.38285,-0.0846 -0.77914,-0.11418 -1.17382,-0.084 z"
+ id="path21574-1"
inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.03999233px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 321.49219,347.97266 A 0.52004817,0.52004817 0 0 0 320.97852,348.5 v 11 a 0.520505,0.520505 0 0 0 1.04101,0 V 358 h 11.95899 v 1.5 a 0.520505,0.520505 0 0 0 1.04101,0 v -11 a 0.52004817,0.52004817 0 0 0 -0.52734,-0.52734 0.52004817,0.52004817 0 0 0 -0.51367,0.52734 v 1.5 h -11.95899 v -1.5 a 0.52004817,0.52004817 0 0 0 -0.52734,-0.52734 z M 322.01953,351 h 11.95899 v 6 h -11.95899 z"
- id="path4902" />
+ sodipodi:nodetypes="cccccccsccccccccc" />
</g>
<g
- transform="translate(166.89495,43.00791)"
- id="g9160-3"
- style="display:inline;fill:#ffffff;enable-background:new" />
- <g
- id="g5375"
- style="fill:#ffffff">
+ transform="translate(-0.389343,-189.06)"
+ style="display:inline;enable-background:new"
+ id="g4917"
+ inkscape:label="E-6">
<path
inkscape:connector-curvature="0"
- id="path9106-6-2"
- d="m 346.49261,354.99229 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 3 c 0,0.725 0.22685,1.37138 0.67773,1.82226 0.45089,0.45089 1.09727,0.67774 1.82227,0.67774 0.725,0 1.37138,-0.22685 1.82226,-0.67774 0.45089,-0.45088 0.67774,-1.09726 0.67774,-1.82226 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 3 c 0,0.525 -0.14815,0.87862 -0.38477,1.11523 -0.23661,0.23661 -0.59023,0.38477 -1.11523,0.38477 -0.525,0 -0.87862,-0.14816 -1.11524,-0.38477 -0.23661,-0.23661 -0.38476,-0.59023 -0.38476,-1.11523 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.75;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="circle14295-0-2"
+ d="m 114.20361,283.80598 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- d="m 348.49261,349.99229 a 0.50005,0.50005 0 0 0 -0.49219,0.50781 v 6 a 0.50005,0.50005 0 1 0 1,0 v -6 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m -5.99219,-2.99219 a 0.50005,0.50005 0 1 0 0,1 h 2.5 v 1.75 c 0,0.97222 0.53688,1.82801 1.27539,2.19726 a 0.50005635,0.50005635 0 1 0 0.44726,-0.89453 c -0.26148,-0.13074 -0.72265,-0.77495 -0.72265,-1.30273 v -1.75 h 5 v 1.75 c 0,0.52778 -0.46312,1.17199 -0.72461,1.30273 a 0.50005635,0.50005635 0 1 0 0.44726,0.89453 c 0.73852,-0.36925 1.27735,-1.22504 1.27735,-2.19726 v -1.75 h 2.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path9108-6-6"
- inkscape:connector-curvature="0" />
- </g>
- <g
- transform="translate(-40.999997,-42)"
- id="g25194-8-8"
- style="display:inline;fill:#ffffff;enable-background:new">
- <circle
- cx="221"
- cy="285"
- id="circle25190-1-7"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- r="0" />
+ inkscape:connector-curvature="0"
+ id="circle14295-0-3-0-1"
+ d="m 115.59493,291.64794 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- id="circle25383"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 221,284 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3,0 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m 3,1 c -0.54636,0 -1,0.45364 -1,1 0,0.54636 0.45364,1 1,1 0.54636,0 1,-0.45364 1,-1 0,-0.54636 -0.45364,-1 -1,-1 z m -5.67188,2.04688 c -0.72617,0.0892 -1.40636,0.31348 -2.02343,0.63867 -1.23415,0.65038 -2.22638,1.68758 -2.94922,2.84375 -0.72284,1.15617 -1.1805,2.43169 -1.32227,3.60742 -0.14176,1.17573 0.0178,2.28295 0.6875,3.0293 0.68189,0.75993 1.69067,0.98063 2.61328,0.6914 C 219.35231,297.53818 220,296.54997 220,295.5 c 0,-0.87561 0.22937,-1.10992 0.64258,-1.29297 C 221.05579,294.02398 221.75437,294 222.5,294 c 0.79276,0 1.56488,-0.14919 2.20703,-0.5332 0.52292,-0.31271 0.89501,-0.8382 1.11524,-1.4668 h 1.13281 a 0.50004994,0.50004994 0 0 0 0.002,0 c 1.02746,0 1.90966,-0.75672 2.0293,-1.76953 0.11964,-1.01284 -0.5686,-1.95303 -1.57031,-2.17969 -0.73109,-0.16542 -1.38414,0.17264 -1.8711,0.68945 -0.49389,-0.69239 -1.0864,-1.29918 -1.91601,-1.52148 -0.80279,-0.21511 -1.57461,-0.26104 -2.30079,-0.17187 z m 0.11915,0.98632 c 0.59872,-0.0738 1.23897,-0.0331 1.92382,0.15039 0.66836,0.17909 1.23082,0.75735 1.69727,1.56446 a 0.50004994,0.50004994 0 0 0 0.90234,-0.0781 c 0.17721,-0.4818 0.69836,-0.76361 1.22461,-0.64453 0.52625,0.11908 0.85819,0.58537 0.79883,1.08789 C 227.93478,290.61583 227.49838,291 226.95703,291 H 225.5 a 0.50004994,0.50004994 0 0 0 -0.49219,0.41406 c -0.10308,0.5846 -0.38181,0.93776 -0.8125,1.19532 C 223.76463,292.86693 223.16312,293 222.5,293 c -0.74508,0 -1.54761,-0.0253 -2.26172,0.29102 C 219.52417,293.60735 219,294.37315 219,295.5 c 0,0.63163 -0.40649,1.2273 -0.96484,1.40234 -0.62221,0.19506 -1.12911,0.0874 -1.57032,-0.40429 -0.37675,-0.41988 -0.55858,-1.23603 -0.4375,-2.24024 0.12109,-1.00421 0.53101,-2.16478 1.17774,-3.19922 0.64673,-1.03443 1.52684,-1.94044 2.5664,-2.48828 0.51979,-0.27392 1.07706,-0.46333 1.67579,-0.53711 z"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="circle14295-0-3-6"
+ d="m 122.93095,287.85344 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 90.494141,178.99609 a 0.50005,0.50005 0 0 0 -0.347657,0.85743 l 3,3 C 92.440854,183.71574 91.999993,184.80241 92,186 c 2e-5,1.19757 0.440853,2.28425 1.146484,3.14648 l -3,3 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 3,-3 C 94.715742,190.55915 95.802428,191 97,191 c 1.197573,0 2.284258,-0.44085 3.14648,-1.14648 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 C 101.55915,188.28425 101.99998,187.19757 102,186 c 0,-1.19759 -0.44086,-2.28426 -1.14648,-3.14648 l 3,-3 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -3,3 C 99.284255,181.44086 98.197592,181 97,181 c -1.19759,0 -2.284254,0.44086 -3.146484,1.14648 l -3,-3 a 0.50005,0.50005 0 0 0 -0.359375,-0.15039 z M 97,182 c 2.21506,0 4.00001,1.78494 4,4 -4e-5,2.21502 -1.784977,4 -4,4 -2.215019,0 -3.999963,-1.78498 -4,-4 -1.2e-5,-2.21506 1.784946,-4 4,-4 z"
- id="path25165"
- inkscape:connector-curvature="0" />
<g
- id="g10845">
+ transform="translate(-0.389343,-189.06)"
+ style="display:inline;enable-background:new"
+ id="g4912"
+ inkscape:label="E-5">
<path
inkscape:connector-curvature="0"
- d="m 473,628 a 1.0001,1.0001 0 1 0 0,2 h 2 a 1.0001,1.0001 0 1 0 0,-2 z m -4.5,-6 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 0.5 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 a 0.50005,0.50005 0 1 0 -1,0 v 4.5 h -8 v -7 h 3.5 a 0.50005,0.50005 0 1 0 0,-1 H 469 v -2 h 4.5 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path24739-4" />
+ id="circle14295-0"
+ d="m 92.893099,283.6795 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
- sodipodi:nodetypes="sssssccccccccccccc"
inkscape:connector-curvature="0"
- id="path27428"
- d="m 478.50003,620.0003 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new" />
+ id="circle14295-0-3"
+ d="m 101.62043,287.72696 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65092,0 -2.999992,-1.34907 -2.999992,-3 0,-1.65093 1.349072,-3 2.999992,-3 z m 0,1 c -1.11049,0 -1.999992,0.88951 -1.999992,2 0,1.11049 0.889502,2 1.999992,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ inkscape:connector-curvature="0"
+ id="circle14295-0-3-0"
+ d="m 94.284412,291.52146 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -2.999998,-1.34907 -2.999998,-3 0,-1.65093 1.349068,-3 2.999998,-3 z m 0,1 c -1.11049,0 -1.999998,0.88951 -1.999998,2 0,1.11049 0.889508,2 1.999998,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
+ transform="translate(-0.389343,-189.06)"
style="display:inline;enable-background:new"
- id="g27418"
- transform="translate(83.999997,-84)">
+ id="g4907"
+ inkscape:label="E-4">
<path
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- d="m 352.50003,305.0003 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
- id="path27589"
+ sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssssccccccccccccc" />
- <g
- id="g27675-2"
- transform="rotate(90,232.49897,657.49643)"
- style="display:inline;opacity:0.7;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -109.99609,533.99609 -0.004,7.11133 c -1.67885,0.25428 -2.99414,1.64686 -2.99414,3.39453 0,1.92568 1.57041,3.49805 3.49609,3.49805 1.92569,0 3.49805,-1.57236 3.49805,-3.49805 0,-1.74925 -1.31894,-3.14219 -3,-3.39453 l 0.004,-7.11133 z m 0.49804,8.00977 c 1.38524,0 2.49805,1.11085 2.49805,2.49609 0,1.38525 -1.1128,2.49805 -2.49805,2.49805 -1.38524,0 -2.49609,-1.11281 -2.49609,-2.49805 0,-1.38523 1.11086,-2.49609 2.49609,-2.49609 z"
- id="path27671-7"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -108.5,534 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path27673-7"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
- </g>
+ id="circle13367-9"
+ d="m 71.893099,283.6795 c 1.650931,0 3.000001,1.34907 3.000001,3 0,1.65093 -1.34907,3 -3.000001,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="circle13367-9-6"
+ d="m 80.620438,287.72696 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ sodipodi:nodetypes="sssss"
+ inkscape:connector-curvature="0"
+ id="circle13367-9-6-6"
+ d="m 73.284414,291.52146 c 1.650931,0 3.000001,1.34907 3.000001,3 0,1.65093 -1.34907,3 -3.000001,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- style="display:inline;enable-background:new"
- id="g27444"
- transform="translate(-18.000003,-64)">
- <g
- id="g27675"
- transform="rotate(90,282.99897,687.99643)"
- style="opacity:0.7">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -109.99609,533.99609 -0.004,7.11133 c -1.67885,0.25428 -2.99414,1.64686 -2.99414,3.39453 0,1.92568 1.57041,3.49805 3.49609,3.49805 1.92569,0 3.49805,-1.57236 3.49805,-3.49805 0,-1.74925 -1.31894,-3.14219 -3,-3.39453 l 0.004,-7.11133 z m 0.49804,8.00977 c 1.38524,0 2.49805,1.11085 2.49805,2.49609 0,1.38525 -1.1128,2.49805 -2.49805,2.49805 -1.38524,0 -2.49609,-1.11281 -2.49609,-2.49805 0,-1.38523 1.11086,-2.49609 2.49609,-2.49609 z"
- id="path27671"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -108.5,534 v 3 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path27673"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
- </g>
+ id="g3398"
+ inkscape:label="E-3"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 430.49414,284.99414 a 0.50005,0.50005 0 0 0 -0.34766,0.85938 l 2.64649,2.64648 -2.64649,2.64648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 2.64648,-2.64649 2.64648,2.64649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -2.64649,-2.64648 2.64649,-2.64648 a 0.50005,0.50005 0 1 0 -0.70704,-0.70704 l -2.64648,2.64649 -2.64648,-2.64649 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- id="path27679"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 52.942267,94.61165 a 0.50005,0.50005 0 0 0 -0.41797,0.20312 c -2.41605,3.180716 -3.44475,6.00321 -3.85743,8.28711 -0.41267,2.2839 -0.21654,4.04989 -0.21875,5.00586 a 0.50005,0.50005 0 1 0 1,0.004 c 0.002,-1.08433 -0.18374,-2.69094 0.20313,-4.83203 0.38687,-2.1411 1.341,-4.795944 3.66797,-7.85938 a 0.50005,0.50005 0 0 0 -0.37695,-0.80858 z m 4.95507,3.00195 a 0.50005,0.50005 0 0 0 -0.30468,0.12695 c -4.12359,3.58504 -5.17188,7.53635 -5.17188,10.37695 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.60021 0.91362,-6.21978 4.82813,-9.623044 A 0.50005,0.50005 0 0 0 57.897337,97.6136 Z m 4.02539,5.0039 c -3.01703,-0.006 -5.49428,2.47075 -5.50195,5.49805 a 0.50005,0.50005 0 1 0 1,0.004 c 0.006,-2.48438 2.03099,-4.50726 4.5,-4.50195 a 0.50005,0.50005 0 1 0 0.002,-1 z"
+ id="path18476-0-2-5-3"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(4.7134341e-6,4.7134317e-6)"
- style="display:inline;enable-background:new"
- id="g27915">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 180.5,263 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 1.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 6 v 6 h -2 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 183 v -0.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 181 Z"
- id="path27886"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 176.50781,262.99414 a 0.50005,0.50005 0 0 0 -0.45508,0.72852 l 1,2 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -1,-2 a 0.50005,0.50005 0 0 0 -0.43946,-0.2832 z m -2.02539,3.00195 a 0.50005,0.50005 0 0 0 -0.20508,0.95118 l 2,1 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 l -2,-1 a 0.50005,0.50005 0 0 0 -0.24024,-0.0566 z m 11,6 a 0.50005,0.50005 0 0 0 -0.20508,0.95118 l 2,1 a 0.50005,0.50005 0 1 0 0.44532,-0.89454 l -2,-1 a 0.50005,0.50005 0 0 0 -0.24024,-0.0566 z m -0.97461,1.99805 a 0.50005,0.50005 0 0 0 -0.45508,0.72852 l 1,2 a 0.50005,0.50005 0 1 0 0.89454,-0.44532 l -1,-2 a 0.50005,0.50005 0 0 0 -0.43946,-0.2832 z"
- id="path27898"
- inkscape:connector-curvature="0" />
+ id="g3401"
+ inkscape:label="E-2"
+ style="display:inline;enable-background:new">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 174.5,269 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 7 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 l -0.008,-4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.5 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -1.4961 L 178,269.50391 A 0.50005,0.50005 0 0 0 177.5,269 Z m 0.5,1 h 1.99609 l -0.004,0.49609 a 0.50005,0.50005 0 0 0 0.5,0.50391 h 1.5 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 l 0.008,3 h -6 z"
- id="path10946"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 30.560537,94.85135 a 0.50005,0.50005 0 0 0 -0.41797,0.20312 c -2.41605,3.180716 -3.44475,6.00321 -3.85742,8.28711 -0.41267,2.2839 -0.21655,4.04989 -0.21875,5.00586 a 0.50005,0.50005 0 1 0 1,0.004 c 0.002,-1.08433 -0.18375,-2.69094 0.20312,-4.83203 0.38687,-2.1411 1.34101,-4.795944 3.66797,-7.85938 a 0.50005,0.50005 0 0 0 -0.37695,-0.80858 z m 4.95508,3.001946 a 0.50005,0.50005 0 0 0 -0.30469,0.12695 c -4.12358,3.585044 -5.17188,7.536354 -5.17188,10.376954 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.60021 0.91362,-6.21978 4.82813,-9.623044 a 0.50005,0.50005 0 0 0 -0.35156,-0.88086 z m 4.02539,5.003904 c -3.01703,-0.006 -5.49429,2.47075 -5.50196,5.49805 a 0.50005,0.50005 0 1 0 1,0.004 c 0.006,-2.48438 2.031,-4.50726 4.50001,-4.50195 a 0.50005,0.50005 0 1 0 0.002,-1 z"
+ id="path18476-0-2-5"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;enable-background:new"
- id="g27501-8"
- transform="translate(-20.999927,104.99988)">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g7388-6-3"
+ transform="translate(457.495,-616.149)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="E-1">
+ <rect
+ transform="scale(-1,1)"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.8;marker:none;enable-background:accumulate"
+ id="rect7384-9-6"
+ width="16"
+ height="16"
+ x="437"
+ y="710" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 346.54688,478.16016 a 0.50005,0.50005 0 0 0 -0.18165,0.0293 c -1.54898,0.53108 -2.52602,2.0719 -2.34375,3.69922 0.18228,1.62732 1.47542,2.91657 3.10352,3.0918 1.6281,0.17523 3.16703,-0.80811 3.69141,-2.35938 a 0.50005,0.50005 0 1 0 -0.94727,-0.32031 c -0.37611,1.11265 -1.46896,1.81123 -2.63672,1.68555 -1.16775,-0.12568 -2.08606,-1.04179 -2.2168,-2.20899 -0.13073,-1.1672 0.56282,-2.26166 1.67383,-2.64257 a 0.50005,0.50005 0 0 0 -0.14257,-0.97461 z"
- id="path27478-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m -447.96289,710.98828 a 1.0001,1.0001 0 0 0 -0.83789,0.41211 c -3.30626,4.40835 -3.18183,10.96743 -3.18555,12.58399 a 1.0001,1.0001 0 1 0 2,0.006 c 0.004,-1.64212 0.0934,-7.79897 2.78711,-11.39062 a 1.0001,1.0001 0 0 0 -0.76367,-1.61133 z m 4.97461,3.00195 a 1.0001,1.0001 0 0 0 -0.69727,0.28125 c -2.25424,2.12239 -3.3739,3.98924 -3.89062,5.64258 C -448.0929,721.56741 -448,722.96385 -448,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-1.13631 -0.0696,-2.20308 0.33203,-3.48828 0.40167,-1.28521 1.28135,-2.83224 3.35352,-4.7832 a 1.0001,1.0001 0 0 0 -0.67383,-1.73829 z m 3.94531,4.00782 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 C -441.66808,718.54973 -444,720.82862 -444,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-2.17354 1.66808,-3.68979 3.21094,-4.02148 a 1.0001,1.0001 0 0 0 -0.25391,-1.98047 z"
+ id="path7133-7-7"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-801,345)"
+ id="g13204"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="D-26">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 346.52148,476.09375 a 0.50004994,0.50004994 0 0 0 -0.0859,0.01 c -2.69151,0.53044 -4.58334,2.97414 -4.42578,5.71289 0.15755,2.73875 2.31815,4.94772 5.05273,5.16601 2.73458,0.21829 5.21856,-1.61975 5.80859,-4.29883 a 0.50004994,0.50004994 0 1 0 -0.97656,-0.21484 c -0.48423,2.19868 -2.50772,3.69672 -4.75195,3.51758 -2.24424,-0.17915 -4.00546,-1.98086 -4.13477,-4.22852 -0.1293,-2.24766 1.41221,-4.2385 3.6211,-4.67383 a 0.50004994,0.50004994 0 0 0 -0.10743,-0.99023 z"
- id="circle27480-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1339.5,-270 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,3 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m 0,3 a 0.50004994,0.50004994 0 1 0 0,1 h 6 a 0.50004994,0.50004994 0 1 0 0,-1 z m -7,3 a 0.50004994,0.50004994 0 1 0 0,1 h 13 a 0.50004994,0.50004994 0 1 0 0,-1 z m -0.014,3 a 0.50004994,0.50004994 0 1 0 0,1 h 13.0449 a 0.50004994,0.50004994 0 1 0 0,-1 z"
+ id="path13198"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 353.49219,473 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -5,5 c -0.0938,0.0938 -0.14646,0.22092 -0.14648,0.35352 v 1.79297 l -0.85352,0.85351 c -0.49023,0.47127 0.23577,1.19727 0.70704,0.70704 L 348.70703,481 H 350.5 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.14648 l 5,-5 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -2,-2 c -0.0957,-0.0957 -0.22603,-0.14855 -0.36133,-0.14648 z"
- id="path27485-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1332.4922,-263 c -0.2761,-0.004 -0.4965,-0.23166 -0.4922,-0.50781 v -5.08789 c 0,-0.86662 0.4883,-1.66406 1.2578,-2.08789 0.7696,-0.42387 1.709,-0.42387 2.4785,0 0.7695,0.42383 1.2559,1.22127 1.2559,2.08789 v 5.08789 c 0.01,0.67616 -1.0096,0.67616 -1,0 V -266 H 1333 v 2.49219 c 0,0.28226 -0.2255,0.51222 -0.5078,0.50781 z m 0.5078,-4 h 2.9922 v -1.5957 c 0,-0.49379 -0.2728,-0.95455 -0.7383,-1.21094 -0.4655,-0.25638 -1.0482,-0.25638 -1.5137,0 -0.4655,0.25639 -0.7402,0.71715 -0.7402,1.21094 z"
+ id="path13202"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccc" />
+ sodipodi:nodetypes="ccccccccccccccsccsc" />
</g>
- <path
- sodipodi:nodetypes="cccccccc"
- inkscape:connector-curvature="0"
- id="path27639"
- d="m 29.959614,221.99997 c -0.53618,0.022 -0.95938,0.4634 -0.95898,1 v 10 c 7.2e-4,0.7847 0.8635,1.2629 1.5293,0.8477 l 8,-5 c 0.625909,-0.3918 0.625909,-1.3036 0,-1.6954 l -8,-5 c -0.17045,-0.107 -0.36922,-0.1601 -0.57032,-0.1523 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 185.04038,221.99997 c 0.53618,0.022 0.95938,0.4634 0.95898,1 v 10 c -7.2e-4,0.7847 -0.8635,1.2629 -1.5293,0.8477 l -8,-5 c -0.62591,-0.3918 -0.62591,-1.3036 0,-1.6954 l 8,-5 c 0.17045,-0.107 0.36922,-0.1601 0.57032,-0.1523 z"
- id="path9268"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccc" />
- <path
- inkscape:connector-curvature="0"
- id="path27528"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 132.5104,224 c -0.27994,-0.01 -0.50979,0.22 -0.50977,0.5 v 7 c -0.001,0.4307 0.5065,0.6613 0.83008,0.377 l 4,-3.5 c 0.22872,-0.1993 0.22872,-0.5547 0,-0.754 l -4,-3.5 c -0.0889,-0.078 -0.20238,-0.1211 -0.32031,-0.123 z m 9.96289,-1 c -0.13302,0.01 -0.25746,0.068 -0.34571,0.168 l -4,4.5 c -0.16816,0.1894 -0.16816,0.4746 0,0.664 l 4,4.5 c 0.19883,0.2227 0.54727,0.2227 0.7461,0 l 4,-4.5 c 0.16816,-0.1894 0.16816,-0.4746 0,-0.664 l -4,-4.5 c -0.10092,-0.114 -0.24831,-0.1759 -0.40039,-0.168 z" />
- <path
- inkscape:connector-curvature="0"
- id="path27544"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 51.506493,224 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z m 6.49414,-1 v 10 h 2 v -10 z" />
- <path
- d="m 124.49003,224 c 0.27994,-0.01 0.50979,0.22 0.50977,0.5 v 7 c 0.001,0.4307 -0.5065,0.6613 -0.83008,0.377 l -4,-3.5 c -0.22872,-0.1993 -0.22872,-0.5547 0,-0.754 l 4,-3.5 c 0.0889,-0.078 0.20238,-0.1211 0.32031,-0.123 z m -9.96289,-1 c 0.13302,0.01 0.25746,0.068 0.34571,0.168 l 4,4.5 c 0.16816,0.1894 0.16816,0.4746 0,0.664 l -4,4.5 c -0.19883,0.2227 -0.54727,0.2227 -0.7461,0 l -4,-4.5 c -0.16816,-0.1894 -0.16816,-0.4746 0,-0.664 l 4,-4.5 c 0.10092,-0.114 0.24831,-0.1759 0.40039,-0.168 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path9201"
- inkscape:connector-curvature="0" />
- <path
- d="m 79.49414,224 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z M 73,223 v 10 h -2 v -10 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path9203"
- inkscape:connector-curvature="0" />
- <path
- id="path9205"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 75.50586,203 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z M 71,203 v 8 h 2 v -8 z"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccc" />
- <path
- d="m 55.49414,203 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z m 4.507668,0 v 8 h -2 v -8 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path9208"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccc" />
- <path
- inkscape:connector-curvature="0"
- id="path9205-9"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 94.50586,623 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z"
- sodipodi:nodetypes="ccccccccc" />
- <path
- sodipodi:nodetypes="ccccccccc"
- d="m 113.9992,624.50586 c 0,-0.27842 0.2216,-0.50584 0.5,-0.50586 h 7 c 0.4051,-6e-4 0.6427,0.45544 0.4102,0.78711 l -3.5,5 c -0.199,0.28542 -0.6214,0.28542 -0.8204,0 l -3.5,-5 c -0.058,-0.0826 -0.089,-0.1806 -0.09,-0.28125 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path9225"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path9227"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 141.49531,622.99926 c 0.27843,0 0.50584,0.2216 0.50587,0.5 v 7 c 5.9e-4,0.4051 -0.45545,0.6427 -0.78712,0.4102 l -5,-3.5 c -0.28541,-0.199 -0.28541,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z"
- sodipodi:nodetypes="ccccccccc" />
- <path
- inkscape:connector-curvature="0"
- id="path9229"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 156,629.49414 c 0,0.27842 0.2216,0.50584 0.5,0.50586 h 7 c 0.4051,6e-4 0.6427,-0.45544 0.4102,-0.78711 l -3.5,-5 c -0.199,-0.28542 -0.6214,-0.28542 -0.8204,0 l -3.5,5 c -0.058,0.0826 -0.089,0.1806 -0.09,0.28125 z"
- sodipodi:nodetypes="ccccccccc" />
- <path
- inkscape:connector-curvature="0"
- id="path27544-8"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 471.50586,371 c -0.27842,0 -0.50585,0.2216 -0.50586,0.5 v 7 c -6.1e-4,0.4051 0.45544,0.6427 0.78711,0.4102 l 5,-3.5 c 0.28542,-0.199 0.28542,-0.6214 0,-0.8204 l -5,-3.5 c -0.0826,-0.058 -0.1806,-0.089 -0.28125,-0.09 z M 478,371 v 8 h 2 v -8 z"
- sodipodi:nodetypes="cccccccccccccc" />
- <path
- sodipodi:nodetypes="cccccccccccccc"
- d="m 500,371.50586 c 0,-0.27842 -0.2216,-0.50585 -0.5,-0.50586 h -7 c -0.4051,-6.1e-4 -0.6427,0.45544 -0.4102,0.78711 l 3.5,5 c 0.199,0.28542 0.6214,0.28542 0.8204,0 l 3.5,-5 c 0.058,-0.0826 0.089,-0.1806 0.09,-0.28125 z M 500,378 h -8 v 2 h 8 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path9258"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path9260"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 542,379.49414 c 0,0.27842 -0.2216,0.50585 -0.5,0.50586 h -7 c -0.4051,6.1e-4 -0.6427,-0.45544 -0.4102,-0.78711 l 3.5,-5 c 0.199,-0.28542 0.6214,-0.28542 0.8204,0 l 3.5,5 c 0.058,0.0826 0.089,0.1806 0.09,0.28125 z M 542,373 h -8 v -2 h 8 z"
- sodipodi:nodetypes="cccccccccccccc" />
- <path
- sodipodi:nodetypes="cccccccccccccc"
- d="m 520.49414,371 c 0.27842,0 0.50585,0.2216 0.50586,0.5 v 7 c 6.1e-4,0.4051 -0.45544,0.6427 -0.78711,0.4102 l -5,-3.5 c -0.28542,-0.199 -0.28542,-0.6214 0,-0.8204 l 5,-3.5 c 0.0826,-0.058 0.1806,-0.089 0.28125,-0.09 z M 514,371 v 8 h -2 v -8 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path9264"
- inkscape:connector-curvature="0" />
<g
- id="g9217">
- <path
- inkscape:connector-curvature="0"
- id="path24965-8"
- d="m 447.5,599 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 1 0 0,-1 H 448 v -9 h 9 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 9.99219,11.74219 A 0.50005,0.50005 0 0 0 457,611.25 v 1.25 a 0.50005,0.50005 0 1 0 1,0 v -1.25 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(48,90)"
+ id="g28884"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-25">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 521.5,84 c -0.6573,0.0093 -0.6573,0.990704 0,1 h 0.25 c 0.75,0 1.25,0.5 1.25,1.25 v 9.500004 c 0,0.75 -0.5,1.25 -1.25,1.25 h -0.25 c -0.6573,0.0093 -0.6573,0.990704 0,1 h 0.25 5.5 0.25 c 0.6573,-0.0093 0.6573,-0.990704 0,-1 h -0.25 C 526.5,97 526,96.5 526,95.75 V 91 h 2.5 c 0.0833,0 0.22505,0.05708 0.33398,0.166016 C 528.94291,91.274947 529,91.416667 529,91.5 c 0.009,0.657305 0.9907,0.657305 1,0 v -2 c -0.004,-0.281658 -0.24005,-0.504291 -0.52148,-0.492188 -0.26471,0.01138 -0.4746,0.22726 -0.47852,0.492188 0,0.08333 -0.0571,0.225053 -0.16602,0.333984 C 528.72505,89.942915 528.58333,90 528.5,90 H 526 v -5 h 4.75004 c 0.0104,-0.294737 0.61631,0.167956 0.86328,0.433594 C 531.86021,85.699231 532,86.054282 532,86.25 v 0.25 c 0.009,0.657305 0.9907,0.657305 1,0 v -2 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -1.75 -9 z"
+ transform="translate(-58,-100)"
+ id="path28882"
inkscape:connector-curvature="0"
- id="path24881-9"
- d="m 455.5,602 c -0.58333,0 -1.08834,0.16632 -1.52734,0.45898 -0.43901,0.29267 -0.82618,0.6875 -1.32618,1.1875 l -1,1 c -0.5,0.5 -0.86283,0.85517 -1.17382,1.0625 C 450.16166,605.91632 449.91667,606 449.5,606 h -1 v 1 h 1 c 0.58333,0 1.08834,-0.16632 1.52734,-0.45898 0.43901,-0.29267 0.82618,-0.6875 1.32618,-1.1875 l 1,-1 c 0.5,-0.5 0.86283,-0.85517 1.17382,-1.0625 C 454.83834,603.08368 455.08333,603 455.5,603 h 1 v -1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccsccsccccccsscscccccccsccccsccccccc" />
</g>
<g
- id="g9239">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 468.4999,598.99994 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3.5 h 1 v -3 h 3 v -1 z m 9.5,0 v 1 h 3 v 3 h 1 v -3.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -10,10 v 3.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3.5 v -1 h -3 v -3 z m 13,0 v 3 h -3 v 1 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3.5 z"
- id="path24895-4"
- inkscape:connector-curvature="0" />
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ transform="translate(-1.03133,-21.9997)"
+ style="display:inline;enable-background:new"
+ id="g8671-6"
+ inkscape:label="D-24">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 471.4999,601.99994 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1.5 h 1 v -1 h 1 v -1 z m 2.5,0 v 1 h 2 v -1 z m 3,0 v 1 h 1 v 1 h 1 v -1.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -6,3 v 2 h 1 v -2 z m 7,0 v 2 h 1 v -2 z m -7,3 v 1.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 1.5 v -1 h -1 v -1 z m 7,0 v 1 h -1 v 1 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.5 z m -4,1 v 1 h 2 v -1 z"
- id="path24923-3"
- inkscape:connector-curvature="0" />
+ style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.755428px;marker:none;enable-background:accumulate"
+ d="m 503.5,84 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 9.640625 c -0.56586,-0.207564 -1.28645,-0.1813 -1.98242,0.07227 -1.35506,0.496297 -2.23748,1.698783 -1.9707,2.685547 0.26594,0.987121 1.58042,1.385047 2.93554,0.888671 1.1076,-0.40637 1.93122,-1.302825 2.00977,-2.1875 L 503.99805,87 H 512 v 6.140625 c -0.56586,-0.207559 -1.28645,-0.181295 -1.98242,0.07227 -1.35507,0.496303 -2.23748,1.698787 -1.9707,2.685547 0.26596,0.987109 1.58042,1.385032 2.93554,0.888671 1.1076,-0.406375 1.93122,-1.302829 2.00977,-2.1875 L 513,84.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
+ transform="translate(-8.96867,11.9997)"
+ id="ellipse8665-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccc" />
</g>
<g
- transform="translate(1223,668.01218)"
+ transform="translate(63,42)"
+ id="g28683"
style="display:inline;enable-background:new"
- id="g27937-4">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -733.49414,-90.007812 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6.501953 h 1 v -6.001953 h 6 v -1 z m 12.50195,7.001953 v 6 h -6.00195 v 1 h 6.50195 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6.5 z"
- id="path27667-4-6"
- inkscape:connector-curvature="0" />
+ inkscape:label="D-23">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -724.49219,-90.007812 a 0.50005,0.50005 0 1 0 0,1 h 2.78321 l -4.13868,4.148437 a 0.50005,0.50005 0 1 0 0.70899,0.705078 l 4.14648,-4.15625 v 2.802735 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -4.01172,7.998046 a 0.50005,0.50005 0 0 0 -0.34375,0.150391 l -4.14648,4.136719 v -2.783203 a 0.50005,0.50005 0 1 0 -1,0 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.80274 l 4.1543,-4.144532 a 0.50005,0.50005 0 0 0 -0.36133,-0.859375 z"
- id="path27669-6-3"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 483.5,84 c -1.37106,-1e-5 -2.49465,1.119188 -2.5,2.490234 -10e-6,0.0039 -10e-6,0.0078 0,0.01172 10e-4,0.275368 0.22463,0.498022 0.5,0.498047 h 3 c 0.28206,0 0.5,0.217938 0.5,0.5 0,0.282062 -0.21794,0.5 -0.5,0.5 l -3.5,-0.0039 c -0.12499,0 -0.85445,-0.01071 -1.57617,0.36914 C 478.70211,88.745078 478,89.596094 478,90.996094 v 0.996094 c 0,1.40001 0.70038,2.249949 1.42188,2.630859 0.72147,0.38091 1.45054,0.373047 1.57812,0.373047 v 0.507812 c -10e-6,0.0032 -10e-6,0.0065 0,0.0098 0.005,1.371211 1.12894,2.490244 2.5,2.490234 h 3 c 1.37479,0 2.5,-1.125211 2.5,-2.5 v -0.507812 c 0.1276,0 0.85475,0.0079 1.57617,-0.373047 0.72142,-0.380914 1.42358,-1.23089 1.42383,-2.630859 v -0.994141 c 2e-5,-1.567832 -0.66959,-2.346488 -1.13672,-2.841797 -0.0911,-0.09952 -0.21863,-0.157986 -0.35351,-0.162109 -0.45031,-0.01416 -0.68821,0.527665 -0.37305,0.849609 0.47073,0.499131 0.8633,0.831529 0.86328,2.154297 v 0.994141 c -1.9e-4,1.100029 -0.42466,1.502011 -0.89062,1.748046 -0.46599,0.246036 -0.98698,0.25586 -1.10938,0.25586 L 485.5,94 c -0.67616,-0.0096 -0.67616,1.009563 0,1 l 2.5,-0.002 v 0.505859 c 0,0.834349 -0.66565,1.5 -1.5,1.5 h -3 c -0.832,6e-6 -1.49698,-0.662318 -1.5,-1.49414 V 93 c 0,-0.63889 0.20453,-1.122504 0.54102,-1.458984 C 482.8775,91.204526 483.36111,91 484,91 h 2.5 c 0.725,0 1.37138,-0.226854 1.82227,-0.677734 C 488.77315,89.871376 489,89.225 489,88.5 v -2 c 0,-1.374789 -1.12521,-2.5 -2.5,-2.5 z"
+ transform="translate(-73,-52)"
+ id="path28624"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccsscccsscccccssccccccccccccccssccccsscsssc" />
</g>
<g
- transform="translate(1223,668.01218)"
+ id="g34186"
style="display:inline;enable-background:new"
- id="g27941-8">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -699.50391,-90.009766 a 0.50005,0.50005 0 0 0 -0.34375,0.150391 l -4.14648,4.136719 v -2.783203 a 0.50005,0.50005 0 1 0 -1,0 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 1 0 0,-1 h -2.80274 l 4.1543,-4.144532 a 0.50005,0.50005 0 0 0 -0.36133,-0.859375 z m -11.98828,8.001954 a 0.50005,0.50005 0 1 0 0,1 h 2.78321 l -4.13868,4.148437 a 0.50005,0.50005 0 1 0 0.70899,0.705078 l 4.14648,-4.15625 v 2.802735 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- id="path27716-4-8"
- inkscape:connector-curvature="0" />
+ inkscape:label="D-22">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.5;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -710.49414,-88.007812 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4.501953 h 1 v -4.001953 h 4 v -1 z m 8.50195,5.001953 v 4 h -4.00195 v 1 h 4.50195 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4.5 z"
- id="path27721-4-5"
+ id="path20685"
+ d="m 447.49219,73.99409 c -0.27615,0.0043 -0.49651,0.231666 -0.49219,0.507812 V 87.49409 c -0.005,0.338081 0.24757,0.509435 0.5,0.507812 l 0.5,-0.0039 v -1.996094 h 2 v 1.996094 h 8 v -1.996094 h 2 v 1.996094 h 0.5 c 0.25244,0 0.50478,-0.169732 0.5,-0.507812 V 74.501902 c 0.005,-0.338081 -0.24762,-0.509415 -0.5,-0.507812 l -0.5,0.0039 v 2.003906 h -2 V 73.99799 h -8 v 2.003906 h -2 V 73.99799 Z M 448,77.001902 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -5.52344,1.003906 c 0.1005,-0.004 0.20016,0.02317 0.28516,0.07617 l 4,2.5 c 0.3129,0.1959 0.3129,0.651757 0,0.847657 l -4,2.5 c -0.3331,0.2087 -0.76573,-0.03073 -0.76563,-0.423829 v -5 c -2e-4,-0.2687 0.21197,-0.489 0.48047,-0.5 z M 448,80.001902 h 2 v 2 h -2 z m 10,0 h 2 v 2 h -2 z m -10,3 h 2 v 1.992188 h -2 z m 10,0 h 2 v 1.992188 h -2 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.99;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
</g>
- <path
- id="path10295"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 61,288 v -2.5 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 H 58 v 1 h 2 v 2 z m -13,0 v -2.5 c 2.8e-5,-0.27613 0.223869,-0.49997 0.5,-0.5 H 51 v 1 h -2 v 2 z m 13,7 v 2.5 c -2.8e-5,0.27613 -0.223869,0.49997 -0.5,0.5 H 58 v -1 h 2 v -2 z m -13,0 v 2.5 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 H 51 v -1 h -2 v -2 z"
- inkscape:connector-curvature="0" />
- <g
- id="g10303"
- transform="matrix(-1,0,0,1,68.007122,83.99992)">
- <g
- transform="translate(-0.012711,-83.995405)"
- id="g10299">
- <path
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path10297"
- transform="matrix(-1,0,0,1,68.019833,-0.004515)"
- d="m 36.007812,284 v 2 h -1.5 c -0.27613,3e-5 -0.499969,0.22387 -0.5,0.5 v 1.49805 l -3.988281,0.006 c -0.812117,9.2e-4 -1.516225,0.45838 -1.832031,1.12695 -0.315807,0.66858 -0.189691,1.55835 0.478516,2.22656 l 4,4 c 0.413276,0.41327 0.416416,0.77582 0.271484,1.08789 -0.144932,0.31206 -0.483162,0.5586 -0.917969,0.5586 l -4.513672,0.006 c -0.676088,-0.008 -0.674098,1.01079 0.002,1 l 4.511719,-0.006 c 0.815193,0 1.513263,-0.46717 1.824219,-1.13672 0.310955,-0.66954 0.189571,-1.55652 -0.470703,-2.2168 l -4,-4 c -0.426033,-0.42603 -0.426504,-0.78429 -0.28125,-1.0918 0.145253,-0.30751 0.489852,-0.55418 0.927734,-0.55468 L 34,288.99805 c 0.0026,2e-5 0.0052,2e-5 0.0078,0 V 290.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1.5 v 2 h 1 v -2 h 1.5 c 0.27613,-3e-5 0.499971,-0.22387 0.5,-0.5 V 289 h 2 v -1 h -2 v -1.5 c -2.9e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -1.5 v -2 z m -1.027343,3 h 3.027343 v 3 h -3.027343 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- </g>
- </g>
<g
- id="g10319"
- transform="translate(-21,84)">
+ transform="matrix(-1,0,0,1,1689,366)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g8530-0-8"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="D-21">
<path
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccc"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1258.4766,-286 c -0.1708,0.008 -0.3255,0.10335 -0.4102,0.25195 l -4,7 c -0.1903,0.33312 0.05,0.74758 0.4336,0.74805 h 8 c 0.3836,-4.7e-4 0.6239,-0.41493 0.4336,-0.74805 l -4,-7 c -0.093,-0.16311 -0.2694,-0.26042 -0.457,-0.25195 z"
+ id="path8523-4-0"
inkscape:connector-curvature="0"
- d="m 29,207 v 1 h -2 v -1 z m 4,4 h 1 v 3 h -1 z m 0,-10 h 1 v 3 h -1 z m -2.5,4 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 208 h 0.335938 l 2.61914,1.9043 c 0.08568,0.0623 0.188958,0.0958 0.294922,0.0957 h 0.25 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -4 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 h -0.25 c -0.105964,-1.5e-4 -0.209238,0.0334 -0.294922,0.0957 L 37.335938,207 H 37 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 5.027344 v 3 H 31 Z m 9,0.30078 v 2.39844 L 38.349609,207.5 Z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path10313" />
+ sodipodi:nodetypes="cccccccc" />
<path
- id="path10315"
- transform="translate(21,-84)"
- d="m 54,285 v 2 h 1 v -2 z m -2.5,3 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 6 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 6 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -6 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 0.5,1 h 5.027344 v 5 H 52 Z m -4,2 v 1 h 2 v -1 z m 11,0 v 1 h 2 v -1 z m -5,5 v 2 h 1 v -2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- inkscape:connector-curvature="0" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
+ id="ellipse8525-5-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ inkscape:connector-curvature="0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z"
+ transform="matrix(-1,0,0,1,1290,-303)"
+ id="path8528-7-3" />
</g>
<g
- transform="matrix(-0.53033009,-0.53033009,-0.53033009,0.53033009,559.86353,322.75914)"
- style="display:inline;opacity:1;fill:#5fd38d;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
- id="g10335"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ id="g7580"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-20">
<g
- style="fill:#5fd38d;stroke:#ffffff;stroke-width:1.33333337;stroke-miterlimit:4;stroke-dasharray:none"
- id="g10333">
+ id="g905">
<g
- id="g10331">
- <path
- inkscape:connector-curvature="0"
- id="path10321-5"
- transform="matrix(-0.94280903,-0.94280903,-0.94280903,0.94280903,832.14463,223.54416)"
- d="m 262.58789,287.02734 a 0.60006001,0.60006001 0 0 0 -0.47266,0.95899 l 2.14844,3.02929 -2.14844,3.0293 a 0.60024527,0.60024527 0 1 0 0.97852,0.69531 l 1.90625,-2.6875 1.90625,2.6875 a 0.60024527,0.60024527 0 1 0 0.97852,-0.69531 l -2.14844,-3.0293 2.14844,-3.02929 a 0.60005997,0.60005997 0 0 0 -0.041,-0.75781 0.60005997,0.60005997 0 0 0 -0.9375,0.0625 l -1.90625,2.6875 -1.90625,-2.6875 a 0.60006001,0.60006001 0 0 0 -0.0645,-0.0781 0.60006001,0.60006001 0 0 0 -0.44141,-0.18555 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ transform="matrix(0.674038,0,0,0.674038,192.806,-339.682)"
+ style="display:inline;opacity:0.99;fill:#ffffff;stroke-width:1.07692;enable-background:new"
+ id="g8599-6-7"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
<path
+ id="path8597-7-0"
+ d="m 331.87142,629.24052 c 0,0.81936 -0.66423,1.48359 -1.48359,1.48359 -0.81937,0 -1.4836,-0.66422 -1.4836,-1.48359 0,-0.81937 0.66423,-1.4836 1.4836,-1.4836 0.81937,0 1.48359,0.66423 1.48359,1.4836 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.72218;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
inkscape:connector-curvature="0"
- d="m 310.32458,237.24123 a 0.66673335,0.66673335 0 0 0 -0.58971,-0.19749 c -6.22865,0.92525 -11.88001,6.57661 -12.80526,12.80526 a 0.66680952,0.66680952 0 1 0 1.31891,0.19749 c 0.82395,-5.54666 6.1358,-10.85851 11.68246,-11.68246 a 0.66673335,0.66673335 0 0 0 0.3936,-1.1228 z m 8.44938,8.44937 a 0.66673335,0.66673335 0 0 1 0.19749,0.58972 c -0.92525,6.22865 -6.57661,11.88001 -12.80526,12.80526 a 0.66673335,0.66673335 0 1 1 -0.19611,-1.31753 c 5.54665,-0.82395 10.8585,-6.1358 11.68245,-11.68246 a 0.66673335,0.66673335 0 0 1 1.12143,-0.39499 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333337px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path10329-8" />
+ sodipodi:nodetypes="sssss" />
</g>
- </g>
- </g>
- <g
- transform="translate(105.00004,2.4e-4)"
- id="g10345">
- <g
- style="opacity:0.7"
- id="g10341">
- <path
- inkscape:connector-curvature="0"
- id="path10337-7"
- d="M 344.49219,287.99219 A 0.50005,0.50005 0 0 0 344,288.5 v 3 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z m 0,5 A 0.50005,0.50005 0 0 0 344,293.5 v 2 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 1 0 0,-1 H 345 v -1.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z M 348.5,295 a 0.50005,0.50005 0 1 0 0,1 h 3 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
+ sodipodi:nodetypes="cccccccccczzcczzzzz"
inkscape:connector-curvature="0"
- id="rect10339"
- d="m 351.5,293 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 4 a 0.50005,0.50005 0 0 0 0.5,0.5 h 4 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 3 v 3 h -3 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path8595-5-9"
+ d="m 414.93725,78.999996 c -0.65344,-0.653443 -1.58833,0.255453 -0.88297,0.960812 L 415.18167,81 h -4.6057 c -0.88913,-0.01822 -0.88913,1.018254 0,1 l 2.19337,-0.004 -0.006,0.004 -3.27651,2.873468 c -0.64989,0.580999 0.2216,1.555837 0.87149,0.97484 L 412.00004,84.45 c 0,1.651946 1.15621,3.581251 3.47506,3.550001 C 417.79395,87.968751 419,86.250706 419,84.45 c 0,-1.800705 -1.00462,-2.558141 -1.45954,-3.013074 z M 415.5,82.2 c 1.22478,0 2.25,0.945047 2.25,2.25 0,1.304953 -1.05311,2.25 -2.25,2.25 -1.19689,0 -2.25,-0.960585 -2.25,-2.25 0,-1.289415 1.02522,-2.25 2.25,-2.25 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.3066;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
- <path
- sodipodi:nodetypes="ccccccccc"
- inkscape:connector-curvature="0"
- id="rect10343"
- d="m 342.5,284 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- </g>
- <g
- transform="translate(62.97587,-41.03945)"
- id="g10359"
- style="display:inline;enable-background:new">
<g
- transform="translate(0,21)"
- id="g10357">
- <path
- style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.66666663;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
- d="m 264.02413,311.53945 a 1.5,1.5 0 0 1 -1.5,1.5 1.5,1.5 0 0 1 -1.5,-1.5 1.5,1.5 0 0 1 1.5,-1.5 1.5,1.5 0 0 1 1.5,1.5 z"
- id="path10347-2"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="circle10349"
- d="m 269.02344,314.03906 c -1.09865,0 -2,0.90136 -2,2 0,1.09865 0.90135,2 2,2 1.09864,0 2,-0.90135 2,-2 0,-1.09864 -0.90136,-2 -2,-2 z m 0,1 c 0.5582,0 1,0.4418 1,1 0,0.55821 -0.4418,1 -1,1 -0.55821,0 -1,-0.44179 -1,-1 0,-0.5582 0.44179,-1 1,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="path10351-7"
- d="m 258.53125,304.03516 a 0.50005,0.50005 0 1 0 0,1 h 12 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- inkscape:connector-curvature="0"
- id="path10355-4"
- d="m 264.79492,304.18164 a 0.60006002,0.60006002 0 0 0 -0.58594,0.4043 l -2.25,6.25 a 0.60006002,0.60006002 0 1 0 1.12891,0.40625 l 2.25,-6.25 a 0.60006002,0.60006002 0 0 0 -0.54297,-0.81055 z m -1.27148,7.75391 a 0.60006002,0.60006002 0 0 0 -0.33594,1.09961 l 4,2.7207 a 0.60006002,0.60006002 0 1 0 0.67383,-0.99219 l -4,-2.7207 a 0.60006002,0.60006002 0 0 0 -0.33789,-0.10742 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fbfbfb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15543-3-3"
+ transform="translate(21.029,-20.9999)">
+ <g
+ id="g15520-6-5"
+ transform="translate(231.972,-398)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g4103-6">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 430.48047,53 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -3.94922,3.949218 C 425.83169,57.461484 426.05468,57.99983 426.5,58 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 54 h 6 v 2.999953 c -0.01,0.676161 1.00956,0.676161 1,0 V 53.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -7 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z M 426,59.000004 V 66.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 4.49914 c 0.67616,0.0096 0.67616,-1.009563 0,-1 H 427 v -6.999996 z"
+ transform="translate(-274,440)"
+ id="path15514-7-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ </g>
+ </g>
</g>
</g>
<g
- transform="translate(11,-136)"
- id="g10373">
- <path
- inkscape:connector-curvature="0"
- id="path10361"
- d="m 275.4707,427 c -0.42985,0.004 -0.62994,0.5874 -0.31869,0.87125 0.40897,0.54487 0.81793,1.08974 1.2269,1.63461 -0.43981,0.59662 -0.90116,1.17907 -1.32716,1.78476 -0.21053,0.38613 0.24226,0.86663 0.6402,0.67938 0.28682,-0.15751 0.42097,-0.48416 0.63231,-0.72356 0.22655,-0.3022 0.4531,-0.6044 0.67965,-0.9066 0.3916,0.51133 0.76296,1.03993 1.16735,1.54035 0.31222,0.30974 0.89981,0.009 0.83079,-0.42566 -0.0715,-0.31923 -0.34727,-0.53953 -0.51804,-0.80941 -0.28503,-0.37975 -0.57007,-0.75951 -0.8551,-1.13926 0.43981,-0.59662 0.90116,-1.17907 1.32716,-1.78476 0.21053,-0.38613 -0.24226,-0.86663 -0.6402,-0.67938 -0.28682,0.15751 -0.42097,0.48416 -0.63231,0.72356 -0.22655,0.3022 -0.4531,0.6044 -0.67965,0.9066 -0.39082,-0.51197 -0.76442,-1.03847 -1.1661,-1.54128 -0.0981,-0.0907 -0.23371,-0.13896 -0.36711,-0.1306 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <g
- id="g10367"
- transform="translate(115.99999,-73.00002)"
- style="display:inline;opacity:0.6;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- inkscape:connector-curvature="0"
- id="path10363"
- transform="translate(-378.99999,209.00002)"
- d="m 534.48047,284 a 0.50005,0.50005 0 0 0 -0.38477,0.19727 l -2.92382,2.92578 -0.0254,0.0234 c -4.5e-4,4.6e-4 4.5e-4,0.002 0,0.002 a 0.50005,0.50005 0 0 0 -0.13671,0.25781 c -7.9e-4,0.004 -0.003,0.008 -0.004,0.0117 A 0.50005,0.50005 0 0 0 531,287.50781 V 296.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2 a 0.50005,0.50005 0 1 0 0,-1 H 532 v -8 h 2.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 285 h 6 v 2.5 a 0.50005,0.50005 0 1 0 1,0 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -7 a 0.50005,0.50005 0 0 0 -0.0137,0 c -6.7e-4,2e-5 -10e-4,-2e-5 -0.002,0 -10e-4,4e-5 -0.003,-5e-5 -0.004,0 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- </g>
- <path
- inkscape:connector-curvature="0"
- id="path10369"
- d="m 273.50391,425 c -0.46998,0.0749 -0.80823,0.50172 -1.06635,0.87006 -0.4326,0.65782 -0.45638,1.4618 -0.43756,2.22236 0.008,1.23972 -0.0164,2.48035 0.0134,3.71944 0.0716,0.88933 0.54871,1.83354 1.40415,2.18708 0.42463,0.112 0.78249,-0.44168 0.50598,-0.78285 -0.29758,-0.24384 -0.6397,-0.4766 -0.77031,-0.86624 -0.24243,-0.63283 -0.12529,-1.31954 -0.15325,-1.98084 0.006,-1.03207 -0.0114,-2.06474 0.009,-3.09642 0.0299,-0.56822 0.33188,-1.12862 0.8373,-1.40532 0.33744,-0.28816 0.10108,-0.88712 -0.34243,-0.86727 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="g8734"
+ transform="translate(232,-419)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="D-19">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 158.48048,492.99995 c -0.15153,0.004 -0.29304,0.0766 -0.38477,0.19727 l -4.94922,4.94921 c -0.31479,0.315 -0.0918,0.85335 0.35352,0.85352 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.5 h 5 v 12 h -10 v -6 h -1 v 6.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -13 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -6 c -0.005,-6e-5 -0.009,-6e-5 -0.0137,0 -6.7e-4,2e-5 -0.001,-2e-5 -0.002,0 -0.001,4e-5 -0.003,-5e-5 -0.004,0 z"
+ id="path8730"
inkscape:connector-curvature="0"
- id="path10371"
- d="m 280.48828,425 c -0.4389,-0.0149 -0.66492,0.60436 -0.31958,0.87564 0.63959,0.33681 0.88258,1.10168 0.83716,1.78593 -0.006,1.35522 0.0116,2.71106 -0.009,4.06588 -0.029,0.57068 -0.33398,1.12767 -0.83582,1.41135 -0.3334,0.28584 -0.081,0.8949 0.35685,0.86114 0.46399,-0.0793 0.79448,-0.50451 1.05034,-0.86849 0.42617,-0.65052 0.45767,-1.4445 0.43766,-2.19695 -0.008,-1.24867 0.0164,-2.49826 -0.0134,-3.7463 -0.0691,-0.87707 -0.53296,-1.78778 -1.35661,-2.16868 -0.0478,-0.0138 -0.0978,-0.0204 -0.14755,-0.0195 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
</g>
<g
- transform="translate(43,63)"
- id="g10379">
+ style="display:inline;fill:#ffffff;fill-opacity:1;enable-background:new"
+ transform="translate(0,-20)"
+ id="g28092-2"
+ inkscape:label="D-18">
<path
+ sodipodi:nodetypes="cccccccccc"
inkscape:connector-curvature="0"
- id="path10375"
- d="m 471.5,221 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -3,3 A 0.50005,0.50005 0 0 0 468,224.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 8 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 l 3,-3 A 0.50005,0.50005 0 0 0 480,231.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.20703,1 H 479 v 9.29297 L 476.29297,234 H 469 v -9.29297 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path28072-1"
+ d="m 363.5,95 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 99 h 14 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 368 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- sodipodi:nodetypes="sssss"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 363.5,100 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="rect28074-91"
inkscape:connector-curvature="0"
- id="circle10377"
- d="m 474,225.99805 c -1.09907,0 -2,0.90288 -2,2.00195 0,1.09907 0.90093,2 2,2 1.09907,0 2.00195,-0.90093 2.00195,-2 0,-1.09907 -0.90288,-2.00195 -2.00195,-2.00195 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="ccccccccc" />
</g>
<g
- transform="translate(0,636)"
- id="g28780">
+ id="g34174"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 531.50781,-348.00781 a 0.50005,0.50005 0 0 0 -0.5,0.5 L 531,-338.5 a 0.50005,0.50005 0 0 0 0.5,0.5 l 9.00781,-0.008 a 0.50005,0.50005 0 0 0 0.5,-0.5 c 0,-5.24079 -4.25921,-9.5 -9.5,-9.5 z m 0.5,1.10156 c 4.27858,0.26151 7.63693,3.61986 7.89844,7.89844 L 532,-339 Z"
- id="path10381"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 355.49219,73.992188 A 0.50004994,0.50004994 0 0 0 355,74.5 v 3.792969 l -2.11914,-2.117188 a 0.50004994,0.50004994 0 0 0 -0.0234,-0.02539 c -10e-4,-0.0015 -0.002,-0.0024 -0.004,-0.0039 a 0.50004994,0.50004994 0 0 0 -0.1875,-0.121093 c -1.78999,-1.727877 -3.76997,-2.331734 -5.85938,-1.875 -2.1873,0.478135 -3.98484,2.053048 -4.77539,4.175781 a 0.50004994,0.50004994 0 1 0 0.9375,0.347656 c 0.67415,-1.810183 2.19925,-3.142137 4.05078,-3.546875 1.87803,-0.410528 3.46011,0.02939 5.12305,1.722656 a 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.002,0.002 0.50004994,0.50004994 0 0 0 0.0332,0.03125 L 354.29297,79 H 350.5 a 0.50004994,0.50004994 0 1 0 0,1 h 5 a 0.50004994,0.50004994 0 0 0 0.5,-0.5 v -5 a 0.50004994,0.50004994 0 0 0 -0.50781,-0.507812 z"
+ id="path13235"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 542.98047,-351.00977 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 l -3,3 a 1.0001,1.0001 0 1 0 1.41406,1.41406 l 3,-3 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
- id="path10384-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 342.49805,81.992188 a 0.50004994,0.50004994 0 0 0 -0.5,0.5 v 5 a 0.50004994,0.50004994 0 1 0 1,0 v -3.792969 l 2.11914,2.11914 a 0.50004994,0.50004994 0 0 0 0.0234,0.02539 l 0.004,0.002 c 7.2e-4,7.3e-4 0.001,0.0012 0.002,0.002 a 0.50004994,0.50004994 0 0 0 0.18555,0.121094 c 1.78998,1.727877 3.76997,2.331734 5.85938,1.875 2.1873,-0.478136 3.98484,-2.053048 4.77539,-4.175781 a 0.50028327,0.50028327 0 1 0 -0.9375,-0.34961 c -0.67415,1.810184 -2.19925,3.14409 -4.05078,3.548829 -1.87804,0.410528 -3.46011,-0.03135 -5.12305,-1.72461 a 0.50004994,0.50004994 0 0 0 -0.004,-0.0039 l -0.0332,-0.03125 -2.11328,-2.115234 h 3.79297 a 0.50004994,0.50004994 0 1 0 0,-1 z"
+ id="path13252"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-147,636)"
- id="g10393">
- <path
- sodipodi:nodetypes="sssss"
- inkscape:connector-curvature="0"
- id="ellipse10386"
- d="m 560.99219,-349.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="ellipse10388"
- d="m 552,-339.99219 c 0,-1.09609 0.89673,-1.99609 1.99219,-1.99609 1.09546,0 1.99414,0.9 1.99414,1.99609 0,1.09609 -0.89868,1.99805 -1.99414,1.99805 -1.09546,0 -1.99219,-0.90196 -1.99219,-1.99805 z m 1,0 c 0,0.55685 0.43837,0.99805 0.99219,0.99805 0.55382,0 0.99414,-0.4412 0.99414,-0.99805 0,-0.55685 -0.44032,-0.99609 -0.99414,-0.99609 -0.55382,0 -0.99219,0.43924 -0.99219,0.99609 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="g12536"
+ transform="matrix(0,1,1,0,270,-183)"
+ style="display:inline;fill:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="D-16">
<path
- d="m 560.36798,-346.98792 a 0.60364676,0.60365756 0 0 0 -0.41654,0.18273 l -0.77413,0.77415 a 0.60366279,0.6036736 0 1 0 0.85273,0.8547 l 0.77609,-0.77611 a 0.60364676,0.60365756 0 0 0 -0.43815,-1.03547 z m -2.99662,2.98989 a 0.61117943,0.61029182 0 0 0 -0.42173,0.18473 l -0.78379,0.78265 a 0.61119567,0.61030804 0 1 0 0.86336,0.8641 l 0.78578,-0.78463 a 0.61117943,0.61029182 0 0 0 -0.44362,-1.04685 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.19999993;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- id="path28690"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 261.49023,51.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 258.70703,57 H 268.5 c 0.83435,0 1.5,0.665651 1.5,1.5 v 5 a 0.50005,0.50005 0 1 0 1,0 v -5 c 0,-1.374789 -1.12521,-2.5 -2.5,-2.5 h -9.79297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z"
+ id="path12534"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-210,636)"
- id="g10409">
- <path
- sodipodi:nodetypes="sssss"
- inkscape:connector-curvature="0"
- id="ellipse10403"
- d="m 560.99219,-349.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="ellipse10405"
- d="m 552,-339.99219 c 0,-1.09609 0.89673,-1.99609 1.99219,-1.99609 1.09546,0 1.99414,0.9 1.99414,1.99609 0,1.09609 -0.89868,1.99805 -1.99414,1.99805 -1.09546,0 -1.99219,-0.90196 -1.99219,-1.99805 z m 1,0 c 0,0.55685 0.43837,0.99805 0.99219,0.99805 0.55382,0 0.99414,-0.4412 0.99414,-0.99805 0,-0.55685 -0.44032,-0.99609 -0.99414,-0.99609 -0.55382,0 -0.99219,0.43924 -0.99219,0.99609 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="g25642"
+ transform="translate(-63,-20)"
+ style="display:inline;fill:#ffffff;fill-opacity:1;enable-background:new"
+ inkscape:label="D-15">
<path
inkscape:connector-curvature="0"
- id="path10407-7"
- d="m 563.50195,-343.01367 a 0.50005,0.50005 0 0 0 -0.49414,0.50586 v 4 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.50586,-0.50586 z m -5.99414,2.00586 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -33.5,1328 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 11 c 3e-5,0.2761 0.22387,0.5 0.5,0.5 h 2.5 v -3 c 0,-1.645 1.35499,-3 3,-3 h 2.585938 l -1.292969,-1.293 a 1.0001,1.0001 0 0 1 0.726562,-1.7168 1.0001,1.0001 0 0 1 0.6875,0.3028 l 3,3 a 1.0001,1.0001 0 0 1 0,1.414 l -3,3 a 1.0001,1.0001 0 1 1 -1.414062,-1.414 L -25.414062,1336 H -28 c -0.56413,0 -1,0.4359 -1,1 v 3 h 8.5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -9 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 H -29 v -1.5 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 z"
+ transform="translate(397,-1232)"
+ id="path25640" />
</g>
<g
- transform="translate(42,657)"
- id="g10415">
+ transform="translate(-21)"
+ id="g28437"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-14">
<path
- sodipodi:nodetypes="sssss"
+ sodipodi:nodetypes="ccccccccccccccccc"
inkscape:connector-curvature="0"
- id="ellipse10411"
- d="m 350.99219,-370.49609 c 0,-1.37714 1.12676,-2.50391 2.5039,-2.50391 1.37715,0 2.50391,1.12677 2.50391,2.50391 0,1.37713 -1.12676,2.5039 -2.50391,2.5039 -1.37714,0 -2.5039,-1.12677 -2.5039,-2.5039 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 300.5,76 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 12 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5.558594 c -0.31959,0.108004 -0.65516,0.175732 -1,0.212891 V 87 h -11 v -7 c 2.01109,0.01725 4.25811,0.0051 6.54102,0 -0.37613,-0.591554 -0.61026,-1.271947 -0.68946,-2 H 304 v -1.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
+ id="path28389" />
<path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 311.5,74 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
+ id="path28385"
inkscape:connector-curvature="0"
- id="path10413-7"
- d="m 348.4707,-367.9375 c -0.33462,0.0898 -0.64722,0.26623 -0.90039,0.51953 l -4.97851,4.98242 c -0.50693,0.50809 -0.70493,1.24983 -0.51953,1.94336 0.18541,0.69355 0.72692,1.23774 1.41992,1.42383 0.69276,0.18603 1.43437,-0.0128 1.9414,-0.52148 l 4.97852,-4.98047 c 0.50694,-0.50808 0.70495,-1.25177 0.51953,-1.94531 -0.1854,-0.69356 -0.72693,-1.23578 -1.41992,-1.42188 -0.34638,-0.093 -0.70553,-0.09 -1.04102,0 z m 0.78125,0.96484 c 0.34883,0.0937 0.61917,0.3662 0.71289,0.7168 0.0937,0.35062 -0.006,0.72222 -0.26172,0.97852 l -4.97656,4.98046 c -0.25562,0.25646 -0.62555,0.35546 -0.97461,0.26172 -0.3488,-0.0937 -0.62111,-0.36425 -0.71484,-0.71484 -0.0937,-0.35061 0.006,-0.7222 0.26172,-0.97852 l 4.97851,-4.98242 c 0.25563,-0.25646 0.62557,-0.35545 0.97461,-0.26172 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="sssssccccccccccccc" />
</g>
<g
- transform="translate(0,636)"
- id="g9298">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 306.49219,-348.01172 a 0.50005,0.50005 0 0 0 -0.38867,0.19531 l -1.95704,1.95703 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 306,-346.29883 v 5.79297 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.79297 l -1.14649,1.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 1.95117,-1.94922 a 0.50005,0.50005 0 0 0 0.008,-0.79883 l -1.95898,-1.95899 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 1.14649,1.14648 H 307 v -5.29297 l 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.96094,-1.96093 -0.006,-0.008 a 0.50005,0.50005 0 0 0 -0.39453,-0.1836 z"
- id="path10419-4"
- inkscape:connector-curvature="0" />
+ transform="matrix(-1,0,0,1,635,-357)"
+ id="g12824"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="D-13">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 306.44531,-351.99805 c -1.16966,-0.043 -2.35048,0.23548 -3.40039,0.84766 -2.09911,1.22396 -3.28024,3.5522 -3.00586,5.94141 0.27491,2.39372 1.98225,4.44954 4.31055,5.18554 a 0.50004997,0.50004997 0 1 0 0.30078,-0.95312 c -1.94954,-0.61628 -3.38871,-2.3582 -3.61719,-4.34766 -0.22899,-1.99397 0.75092,-3.93196 2.51563,-4.96094 1.76401,-1.02856 3.9738,-0.9382 5.67187,0.20118 0.93801,0.62937 1.92387,1.08398 3.2793,1.08398 h 1 a 0.50004997,0.50004997 0 1 0 0,-1 h -1 c -1.14457,0 -1.85649,-0.33615 -2.7207,-0.91602 -1.00565,-0.67477 -2.16433,-1.03898 -3.33399,-1.08203 z"
- id="path10421-9"
- inkscape:connector-curvature="0" />
+ inkscape:connector-curvature="0"
+ id="path12813"
+ d="m 363.5,431 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 1 a 0.50005,0.50005 0 0 0 0.14648,0.35352 L 368,437.70703 V 441.5 a 0.50005,0.50005 0 0 0 0.14648,0.35352 l 3,3 A 0.50005,0.50005 0 0 0 372,444.5 v -6.79297 l 4.85352,-4.85351 A 0.50005,0.50005 0 0 0 377,432.5 v -1 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 0.29297 l -4.85352,4.85351 A 0.50005,0.50005 0 0 0 371,437.5 v 5.79297 l -2,-2 V 437.5 a 0.50005,0.50005 0 0 0 -0.14648,-0.35352 L 364,432.29297 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="rotate(-180,380.49654,-26.99764)"
- id="g10433">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13177"
+ transform="translate(-1.85367e-6,-21)"
+ inkscape:label="D-12">
<g
- transform="translate(1)"
- id="g10429">
+ id="g13282"
+ transform="translate(20,-21)"
+ style="fill:#ffffff">
<path
- inkscape:connector-curvature="0"
- id="path10423-5"
- transform="rotate(180,390.49654,-26.99764)"
- d="m 393.49219,289.00391 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 1.73047 l -2.76953,2.76953 h -1.73047 c -0.27613,2e-5 -0.49997,0.22386 -0.5,0.5 v 1.02929 c 3e-5,0.27613 0.22387,0.47068 0.5,0.47071 h 1 c 0.2725,0 0.5,0.17071 0.5,0.5 v 1 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 1 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -1.73243 l 2.76758,-2.76757 h 1.73242 c 0.27613,-2e-5 0.49997,-0.22386 0.5,-0.5 v -1.02735 c -3e-5,-0.27613 -0.22387,-0.47262 -0.5,-0.47265 h -1 c -0.2725,0 -0.5,-0.17071 -0.5,-0.5 v -1 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 246.49805,74 c -0.13192,5.4e-4 -0.25829,0.0532 -0.35157,0.146484 C 245.43577,74.857204 244.09848,76 241.5,76 A 0.50005,0.50005 0 0 0 241,76.5 V 79 h -0.5 c -0.75833,0 -1.38671,0.318735 -1.90625,0.734375 -0.51954,0.41563 -0.962,0.926849 -1.44727,1.412109 -0.39648,0.39648 0.31056,1.103512 0.70704,0.707032 0.4558,-0.45581 0.79842,-0.643904 1.18164,-0.746094 C 239.41838,81.005232 239.875,81 240.5,81 h 0.5 v 4.5 c 0,0.75694 -0.56911,1.365513 -1.18359,1.476562 -0.30725,0.0555 -0.62032,0.004 -0.94141,-0.228515 -0.32109,-0.23272 -0.65388,-0.66673 -0.90039,-1.40625 A 0.50005,0.50005 0 0 0 237,85.5 v 1 a 0.50005,0.50005 0 0 0 0.14648,0.353516 C 238.22544,87.932473 239.1944,88.00968 240,88 c 0,0 0.002,0 0.002,0 9.9e-4,0 0.003,10e-7 0.004,0 0.001,-1.6e-5 0.003,1.8e-5 0.004,0 0.36494,-7.26e-4 0.98133,-0.05472 1.67773,-0.203125 0.19213,-0.0454 0.36061,-0.131526 0.54297,-0.197266 0.41443,-0.1248 0.82232,-0.201598 1.24219,-0.449218 C 244.82222,86.354491 246,84.75992 246,82 v -1 h 2.5 c 0.1326,-2e-5 0.25976,-0.0527 0.35352,-0.146484 l 1,-1 C 250.16831,79.538516 249.94532,79.00017 249.5,79 H 246 v -2.529297 c 0.26613,0.242116 0.53257,0.477435 0.83203,0.527344 0.63268,0.10544 1.23725,-0.0679 1.76563,-0.332031 1.05675,-0.52838 1.9005,-1.45715 2.25586,-1.8125 0.45304,-0.47127 -0.23577,-1.160072 -0.70704,-0.707032 -0.31826,0.31827 -0.84181,0.673592 -1.40039,0.763672 -0.55857,0.0901 -1.16912,-0.02339 -1.88867,-0.759765 -0.0945,-0.0967 -0.22417,-0.150901 -0.35937,-0.150391 z m -2.50977,3.013672 c 0.004,-1.62e-4 0.008,1.67e-4 0.0117,0 V 83 c 0,1.65476 -0.45037,2.602541 -1.13477,3.181641 -0.20404,0.172661 -0.46051,0.286861 -0.72656,0.390625 C 242.64927,85.748655 243,84.573733 243,83 v -5.982422 c 0.35078,0.0051 0.69957,0.0073 0.98828,-0.0039 z"
+ transform="translate(-20,42)"
+ id="path13240"
+ inkscape:connector-curvature="0" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path10431-8"
- d="m 395.47852,-349.00391 a 0.50004997,0.50004997 0 0 0 -0.32032,0.86914 c 1.10925,1.04157 1.85525,2.61894 1.8418,4.13086 -0.0174,1.95759 -1.00719,3.50006 -2.74023,4.44727 -1.67823,0.91724 -3.81516,0.64624 -5.48829,-0.40625 l 0.0234,0.0156 C 387.83199,-340.63237 386.68507,-341 385.50781,-341 H 384.5 a 0.50004997,0.50004997 0 1 0 0,1 h 1.00586 0.002 c 0.96887,0 1.91412,0.30361 2.70899,0.86914 l 0.0117,0.008 0.0117,0.008 c 1.93164,1.2151 4.44119,1.56274 6.5,0.4375 2.004,-1.0953 3.23927,-3.01733 3.25977,-5.31836 0.0163,-1.83862 -0.84967,-3.64045 -2.1582,-4.86914 a 0.50004997,0.50004997 0 0 0 -0.36328,-0.13868 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(20.999997,615)"
- id="g10447">
- <path
- inkscape:connector-curvature="0"
- id="path10443"
- d="m 478.49609,-323.00781 a 0.50005,0.50005 0 0 0 -0.34765,0.85937 l 2.64648,2.64649 -2.64648,2.64648 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 0 0 -0.35938,-0.15234 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="g34170"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-11">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 218.5,74 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 1.7e-4,0.445324 0.53852,0.668302 0.85352,0.353516 l 3.64648,-3.646485 3.64648,3.646485 c 0.315,0.314786 0.85335,0.09181 0.85352,-0.353516 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
+ id="rect9857"
inkscape:connector-curvature="0"
- id="path10445"
- d="m 473.4375,-330.97461 c -0.67078,0.0637 -1.33815,0.24001 -1.97461,0.53711 -2.54627,1.1886 -3.92907,3.99498 -3.32031,6.73828 0.60875,2.7433 3.04739,4.69922 5.85742,4.69922 h 2.29297 l -2.14453,2.14453 a 0.50005,0.50005 0 1 0 0.70703,0.70703 l 3,-3 a 0.50005,0.50005 0 0 0 0,-0.70703 l -3,-3 a 0.50005,0.50005 0 1 0 -0.70703,0.70703 L 476.29688,-320 H 474 c -2.34689,0 -4.37244,-1.62485 -4.88086,-3.91602 -0.50842,-2.29116 0.63902,-4.62253 2.76563,-5.61523 2.12705,-0.99291 4.66398,-0.38512 6.07812,1.48242 l 0.74023,0.97656 C 479.25532,-326.34303 480.1366,-326 481,-326 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 H 481 c -0.59704,0 -1.17055,-0.2407 -1.5,-0.67578 l -0.74023,-0.97656 c -1.27424,-1.68278 -3.30992,-2.51346 -5.32227,-2.32227 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccc" />
</g>
- <path
- inkscape:connector-curvature="0"
- id="path10449"
- d="m 391.5,263.00781 c -0.82054,0 -1.49609,0.67557 -1.49609,1.4961 0,0.82054 0.67555,1.49609 1.49609,1.49609 0.82053,0 1.49609,-0.67555 1.49609,-1.49609 0,-0.82053 -0.67556,-1.4961 -1.49609,-1.4961 z M 397,264 c -0.71373,0 -1.37556,0.3819 -1.73242,1 -0.19053,0.33001 -0.2484,0.68266 -0.25586,0.99609 v 0.0117 h -1.54297 C 393.0093,266.6044 392.2975,267 391.5,267 c -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 h -0.0195 -5.01563 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 5.01563 0.49805 l -0.0137,3.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.8602,0.89868 0.97657,0.21094 0.67528,-3.15139 1.9234,-4.08819 3.51757,-5.42773 1.58398,1.34059 2.83152,2.27746 3.51953,5.42968 0.13318,0.66658 1.13544,0.44609 0.97657,-0.21484 -0.76273,-3.49457 -2.35105,-4.70351 -4.00196,-6.11719 l 0.0137,-3.27539 h 2.21679 1.78516 v 0.004 c 0.007,0.31344 0.0653,0.66608 0.25586,0.99609 0.35686,0.61811 1.01869,1 1.73242,1 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 397 c -0.35807,0 -0.6862,-0.1899 -0.86523,-0.5 -0.0738,-0.12789 -0.11835,-0.32209 -0.12305,-0.51953 v -0.96875 c 0.005,-0.19744 0.0492,-0.39164 0.12305,-0.51953 0.17903,-0.3101 0.50716,-0.5 0.86523,-0.5 h 0.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- transform="translate(0,636)"
- id="g28776">
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 447.50977,297.01172 a 0.50005,0.50005 0 1 0 0,1 h 6.2832 c -0.26437,-0.28877 -0.47061,-0.62726 -0.60742,-1 z m 11.29882,0 c -0.13697,0.37274 -0.34281,0.71123 -0.60742,1 h 2.3086 a 0.50005,0.50005 0 1 0 0,-1 z"
- transform="translate(21,-636)"
- id="path10435" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 476.99609,-342 c 1.09999,0 2.00391,0.90231 2.00391,2.00195 0,1.09965 -0.90392,2 -2.00391,2 -1.09998,0 -2.00195,-0.90035 -2.00195,-2 0,-1.09964 0.90197,-2.00195 2.00195,-2.00195 z"
- id="ellipse10439"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 472.49805,-351.99805 c 1.37513,0 2.50195,1.12557 2.50195,2.5 0,1.37444 -1.12682,2.49805 -2.50195,2.49805 -1.37514,0 -2.5,-1.12361 -2.5,-2.49805 0,-1.37443 1.12486,-2.5 2.5,-2.5 z m 0,1 c -0.83537,0 -1.5,0.66668 -1.5,1.5 0,0.83332 0.66463,1.49805 1.5,1.49805 0.83537,0 1.50195,-0.66473 1.50195,-1.49805 0,-0.83332 -0.66658,-1.5 -1.50195,-1.5 z"
- id="ellipse10441"
- inkscape:connector-curvature="0" />
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14370"
+ transform="translate(21)"
+ inkscape:label="D-8">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 472.50195,-345.99609 a 0.50005,0.50005 0 0 0 -0.49218,0.50781 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50781 z m 0,3 a 0.50005,0.50005 0 0 0 -0.49218,0.50781 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50782,-0.50781 z"
- id="path10451"
+ id="rect14323"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 141.51562,82 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 145.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 145.5,82 Z m 0.5,1 H 145 v 4 h -2.98438 z m -9.5,-1 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 136.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 136.5,82 Z m 0.5,1 H 136 v 4 h -2.98438 z m 8.5,-9 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 145.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 145.5,74 Z m 0.5,1 H 145 v 4 h -2.98438 z m -9.5,-1 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5 a 0.50005,0.50005 0 0 0 0.5,0.5 H 136.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 136.5,74 Z m 0.5,1 H 136 v 4 h -2.98438 z"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-126,636)"
- id="g10457">
+ id="g34189"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-6">
<path
- inkscape:connector-curvature="0"
- id="path10453"
- transform="translate(0,-636)"
- d="m 554.5,284 c -1.37479,0 -2.5,1.12521 -2.5,2.5 v 2.00781 c 0,1.37479 1.12521,2.5 2.5,2.5 1.37479,0 2.5,-1.12521 2.5,-2.5 v -0.5 h 1.51172 0.49805 l -0.0137,3.28711 c -1.65939,1.40974 -3.24134,2.62162 -3.98828,6.10742 -0.17787,0.67446 0.86019,0.89868 0.97657,0.21094 0.67528,-3.15139 1.9234,-4.08819 3.51757,-5.42773 1.58398,1.34059 2.83152,2.27746 3.51953,5.42968 0.13318,0.66658 1.13544,0.44609 0.97657,-0.21484 -0.76273,-3.49457 -2.35105,-4.70351 -4.00196,-6.11719 l 0.0137,-3.27539 h 2.21679 3.28516 c 0.6573,-0.009 0.6573,-0.9907 0,-1 h -3.04297 C 562.0093,287.6044 561.2975,288 560.5,288 c -0.79751,0 -1.50931,-0.3956 -1.96875,-0.99219 H 558.51172 557 V 286.5 c 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m 6,0.008 c -0.82054,0 -1.49609,0.67557 -1.49609,1.4961 0,0.82054 0.67555,1.49609 1.49609,1.49609 0.82053,0 1.49609,-0.67555 1.49609,-1.49609 0,-0.82053 -0.67556,-1.4961 -1.49609,-1.4961 z m -6,0.992 c 0.83435,0 1.5,0.66565 1.5,1.5 v 2.00781 c 0,0.83435 -0.66565,1.5 -1.5,1.5 -0.83435,0 -1.5,-0.66565 -1.5,-1.5 V 286.5 c 0,-0.83435 0.66565,-1.5 1.5,-1.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.40000057;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path14479-6"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 111.51563,74 c -0.27614,2.8e-5 -0.49998,0.223869 -0.5,0.5 v 12 c 2e-5,0.276131 0.22386,0.499972 0.5,0.5 H 114.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -12 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z m 0,3 H 114 v 2 h -1.98437 z M 124,81.000005 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m 8,-3 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z m -2,0 h 1 v 1 h -1 z"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-21,615)"
- style="opacity:0.8"
- id="g10464">
+ id="g6448"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="D-5">
<path
- sodipodi:nodetypes="ccccccccc"
- inkscape:connector-curvature="0"
- id="path10460"
- d="m 237.5,-323 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ d="m 103,78.000008 h 1 v 1 h -1 z m 0,-3 h 1 v 1 h -1 z m -8,3 h 1 v 1 h -1 z m 0,3 h 1 v 1 h -1 z m 0,-6 h 1 v 1 h -1 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="rect14452"
+ inkscape:connector-curvature="0" />
<path
+ d="m 98.515625,74 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 6 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 H 101.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -6 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 H 101 v 2 h -1.984375 z m 0,3 H 101 v 2 h -1.984375 z m -8.5,-4 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 12 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 H 93.5 c 0.276131,-2.8e-5 0.499972,-0.223869 0.5,-0.5 v -12 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z m 0.5,1 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z m 0,3 H 93 v 2 h -1.984375 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path14479"
inkscape:connector-curvature="0"
- id="path10462"
- d="m 237.52148,-329 a 0.50005,0.50005 0 0 0 -0.5,0.49805 l -0.0215,4.5 1,0.004 0.0195,-4.00195 H 247 v 9 h -4 v 1 h 4.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -10 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccc" />
</g>
- <path
- d="m 230,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- id="path10466"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-25,619)"
- id="g10474">
- <path
- sodipodi:nodetypes="ccccccccc"
- inkscape:connector-curvature="0"
- id="path10468"
- d="m 137.5,-326 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <path
- inkscape:connector-curvature="0"
- id="path10470"
- d="m 137.52148,-331 a 0.50005,0.50005 0 0 0 -0.5,0.49609 l -0.0215,3.5 1,0.008 0.0176,-3.00391 H 145 v 7 h -3 v 1 h 3.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="g34177"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-4">
<path
- inkscape:connector-curvature="0"
- id="path10472"
- d="m 141.52148,-335 a 0.50005,0.50005 0 0 0 -0.5,0.49609 l -0.0215,2.5 1,0.008 0.0176,-2.00391 H 149 v 7 h -2 v 1 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -8 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 69.5,74 a 0.50005,0.50005 0 1 0 0,1 h 13 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 10 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 4 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path14593"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(125,-1)"
- id="g10480"
- style="display:inline;opacity:0.8;enable-background:new">
+ id="g34183"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-3">
<path
- inkscape:connector-curvature="0"
- id="path10478"
- d="m 51.492188,285.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 51,287.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 59.292969,295 H 52 v -7.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 50.494141,73.992188 A 0.50004997,0.50004997 0 0 0 50.417969,74 H 49.5 a 0.50004997,0.50004997 0 1 0 0,1 H 50 v 1.125 c 0,1.632015 0.971328,2.853007 2.201172,3.775391 L 53,80.5 v 0.5 0.5 l -0.798828,0.599609 C 50.971326,83.021991 50,84.242992 50,85.875 V 87 h -0.5 a 0.50004997,0.50004997 0 1 0 0,1 h 0.921875 a 0.50004997,0.50004997 0 0 0 0.160156,0 h 7.837891 a 0.50004997,0.50004997 0 0 0 0.162109,0 H 59.5 a 0.50004997,0.50004997 0 1 0 0,-1 H 59 v -1.125 c 0,-1.632008 -0.969373,-2.853009 -2.199219,-3.775391 L 56,81.5 V 81.035156 A 0.50004997,0.50004997 0 0 0 56,81 v -0.5 l 0.800781,-0.599609 C 58.030625,78.978007 59,77.757015 59,76.125 V 75 h 0.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -0.919922 a 0.50004997,0.50004997 0 0 0 -0.162109,0 h -7.835938 a 0.50004997,0.50004997 0 0 0 -0.08789,-0.0078 z M 51,75 h 7 v 1.125 c 0,1.245243 -0.698245,2.147707 -1.800781,2.974609 l -1,0.75 A 0.50004997,0.50004997 0 0 0 55,80.25 V 80.964844 81 81.75 a 0.50004997,0.50004997 0 0 0 0.199219,0.400391 l 1,0.75 C 57.301151,83.726838 57.999238,84.628869 58,85.873047 V 87 h -7 v -1.125 -0.002 c 7.62e-4,-1.244178 0.698849,-2.146209 1.800781,-2.972656 l 1,-0.75 A 0.50004997,0.50004997 0 0 0 54,81.75 V 81.035156 A 0.50004997,0.50004997 0 0 0 54,81 v -0.75 a 0.50004997,0.50004997 0 0 0 -0.199219,-0.400391 l -1,-0.75 C 51.698847,78.273158 51.000762,77.371141 51,76.126953 v -0.002 z"
+ id="path14614"
+ inkscape:connector-curvature="0" />
</g>
- <path
- id="path10482"
- d="m 197.50977,285.99609 a 0.50005,0.50005 0 0 0 -0.31055,0.10547 c -1.78384,1.33863 -2.5833,3.62488 -2.02149,5.78321 0.56181,2.15833 2.37387,3.7674 4.58399,4.0664 2.05389,0.27788 4.06729,-0.6352 5.23828,-2.31445 V 296.5 a 0.50005,0.50005 0 1 0 1,0 v -4 a 0.50005,0.50005 0 0 0 -0.5,-0.5 h -4 a 0.50005,0.50005 0 1 0 0,1 h 2.72656 c -0.95112,1.41787 -2.62038,2.19029 -4.33008,1.95898 -1.8109,-0.24499 -3.29162,-1.5577 -3.75195,-3.32617 -0.46033,-1.76847 0.19267,-3.63559 1.6543,-4.73242 a 0.50005,0.50005 0 0 0 -0.28906,-0.9043 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- inkscape:connector-curvature="0" />
- <path
- id="path10484"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- d="m 167,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
- inkscape:connector-curvature="0" />
- <path
- d="m 188,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- id="path10486"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path10488"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- d="m 209,289 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z" />
- <path
- inkscape:connector-curvature="0"
- id="path10490"
- d="m 160.5,285.99023 a 0.50005,0.50005 0 0 0 -0.34766,0.85743 l 1.14649,1.14648 -6.29297,6.29297 -1.14648,-1.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70704 l 3,3 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -1.14649,-1.14648 6.29297,-6.29297 1.14648,1.14649 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 l -3,-3 A 0.50005,0.50005 0 0 0 160.5,285.99023 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.85;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<g
- id="g10502"
- transform="rotate(180,170.50319,427.50118)">
+ id="g34180"
+ style="display:inline;enable-background:new"
+ inkscape:label="D-2">
<path
- id="path10492"
- transform="rotate(-180,170.50319,427.50118)"
- d="m 138.61719,286.00781 a 0.60006002,0.60006002 0 0 0 -0.47657,0.99024 l 1.61133,2.01953 a 1.5007322,1.5007322 0 0 1 1.2461,1.5625 l 0.92773,1.16211 a 0.60006002,0.60006002 0 0 0 0.4668,0.23242 0.60006002,0.60006002 0 0 0 0.4707,-0.98047 l -1.58789,-1.99023 1.58984,-2.00782 a 0.60006002,0.60006002 0 1 0 -0.9414,-0.74414 l -1.41602,1.78907 -1.42969,-1.79102 a 0.60006002,0.60006002 0 0 0 -0.46093,-0.24219 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 30.474609,74.994141 a 0.50004997,0.50004997 0 0 0 -0.40625,0.757812 L 33.128906,81 H 27.5 a 0.50004997,0.50004997 0 1 0 0,1 h 5.628906 l -3.060547,5.248047 a 0.50004997,0.50004997 0 1 0 0.863282,0.503906 L 34,82.492188 l 3.068359,5.259765 a 0.50004997,0.50004997 0 1 0 0.863282,-0.503906 L 34.871094,82 H 40.5 a 0.50004997,0.50004997 0 1 0 0,-1 h -5.628906 l 3.060547,-5.248047 A 0.50004997,0.50004997 0 1 0 37.068359,75.248047 L 34,80.507812 30.931641,75.248047 a 0.50004997,0.50004997 0 0 0 -0.457032,-0.253906 z"
+ id="path14603"
inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14591"
+ inkscape:label="D-1">
<path
- inkscape:connector-curvature="0"
- id="path10496"
- d="m 201.60938,559.02148 a 0.60006002,0.60006002 0 0 0 -0.47071,0.98243 l 1.59766,2.00195 -1.59766,2.00195 a 0.6002929,0.6002929 0 1 0 0.9375,0.75 l 1.42774,-1.78906 1.42773,1.78906 a 0.6002929,0.6002929 0 1 0 0.9375,-0.75 l -1.59766,-2.00195 1.59766,-2.00195 a 0.6002929,0.6002929 0 1 0 -0.9375,-0.75 l -1.42773,1.78906 -1.42774,-1.78906 a 0.60006002,0.60006002 0 0 0 -0.46679,-0.23243 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.20000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 9.25,74 a 0.50005,0.50005 0 0 0 -0.4765625,0.351562 l -2.75,8.820313 A 0.50005,0.50005 0 0 0 6,83.320312 v 0.173829 a 0.50005,0.50005 0 1 0 1,0 v -0.09766 L 7.7460938,81 A 0.50005,0.50005 0 0 0 7.75,81 h 3.5 a 0.50005,0.50005 0 0 0 0.0039,0 L 12,83.396484 v 0.09766 a 0.50005,0.50005 0 1 0 1,0 v -0.173829 a 0.50005,0.50005 0 0 0 -0.02344,-0.148437 l -2.75,-8.820313 A 0.50005,0.50005 0 0 0 9.75,74 Z M 9.5,75.375 10.941406,80 H 8.0585938 Z"
+ id="path14584"
+ inkscape:connector-curvature="0" />
<path
- inkscape:connector-curvature="0"
- id="path10498"
- d="m 196.50391,561 a 0.50004997,0.50004997 0 0 0 -0.22657,0.0547 c 0,0 -0.3567,0.1843 -0.66796,0.57226 C 195.29811,562.01491 195,562.63889 195,563.5 v 5 c 0,0.86111 0.29839,1.4864 0.60938,1.875 0.31098,0.3886 0.66796,0.57227 0.66796,0.57227 a 0.50004997,0.50004997 0 1 0 0.44532,-0.89454 c 0,0 -0.14302,-0.0665 -0.33204,-0.30273 C 196.20161,569.5138 196,569.13889 196,568.5 v -5 c 0,-0.63889 0.20189,-1.01282 0.39062,-1.24805 0.18874,-0.23523 0.33204,-0.30078 0.33204,-0.30078 A 0.50004997,0.50004997 0 0 0 196.50391,561 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 14.5,79 a 0.50005,0.50005 0 1 0 0,1 H 19 v 0.08008 l -4.896484,6.365234 A 0.50005,0.50005 0 0 0 14,86.75 v 0.75 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5 a 0.50005,0.50005 0 1 0 0,-1 H 15 v -0.08008 l 4.896484,-6.365234 A 0.50005,0.50005 0 0 0 20,80.25 V 79.5 A 0.50005,0.50005 0 0 0 19.5,79 Z"
+ id="path14589"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g27713"
+ transform="translate(-80)"
+ inkscape:label="C-26">
<path
- inkscape:connector-curvature="0"
- id="path10500"
- d="m 207.48828,557 a 0.50004997,0.50004997 0 0 0 -0.20508,0.95117 c 0,0 0.14526,0.0655 0.33399,0.30078 0.18873,0.23523 0.38867,0.60916 0.38867,1.24805 v 5 c 0,0.63889 -0.20161,1.0138 -0.39063,1.25 -0.18901,0.2362 -0.33203,0.30273 -0.33203,0.30273 a 0.50006306,0.50006306 0 1 0 0.44727,0.89454 c 0,0 0.35503,-0.18367 0.66601,-0.57227 0.31099,-0.3886 0.60938,-1.01389 0.60938,-1.875 v -5 c 0,-0.86111 -0.29811,-1.48509 -0.60938,-1.87305 -0.31127,-0.38796 -0.66796,-0.57226 -0.66796,-0.57226 A 0.50004997,0.50004997 0 0 0 207.48828,557 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="rect27779"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 618,63 h 1 v 1.999999 h -1 z m -2,0 h 1 v 1.999999 h -1 z m -2,0 h 1 v 1.999999 h -1 z M 613.53711,53 C 612.69436,53 612,53.694362 612,54.537109 v 8 2.925782 C 612,66.305638 612.69436,67 613.53711,67 h 8.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 v -2.925782 -8 C 624,53.694362 623.30564,53 622.46289,53 Z m 0,9 h 8.92578 C 622.76894,62 623,62.231065 623,62.537109 v 2.925782 C 623,65.768935 622.76894,66 622.46289,66 h -8.92578 C 613.23106,66 613,65.768935 613,65.462891 V 62.537109 C 613,62.231065 613.23106,62 613.53711,62 Z"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="opacity:1"
- id="g10508"
- transform="translate(-21,467)">
+ transform="translate(499.001,52.0152)"
+ id="g824"
+ style="display:inline;enable-background:new"
+ inkscape:label="C-25">
+ <g
+ id="g4207"
+ style="display:inline;enable-background:new"
+ transform="translate(-499.001,-52.0072)">
+ <g
+ transform="translate(105,-21.0004)"
+ style="display:inline;enable-background:new"
+ id="g7580-6">
+ <g
+ transform="matrix(0.674038,0,0,0.674038,192.806,-339.682)"
+ style="display:inline;opacity:0.99;fill:#ffffff;stroke-width:1.07692;enable-background:new"
+ id="g8599-6-7-2"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <path
+ id="path8597-7-0-9"
+ d="m 331.87142,629.2294 c 0,0.81936 -0.66423,1.48359 -1.48359,1.48359 -0.81937,0 -1.4836,-0.66422 -1.4836,-1.48359 0,-0.81937 0.66423,-1.4836 1.4836,-1.4836 0.81937,0 1.48359,0.66423 1.48359,1.4836 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.72218;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <path
+ sodipodi:nodetypes="cccccccccczzcczzzzz"
+ inkscape:connector-curvature="0"
+ id="path8595-5-9-1"
+ d="m 414.93725,78.992499 c -0.65344,-0.653443 -1.58833,0.255453 -0.88297,0.960812 l 1.12739,1.039192 h -4.6057 c -0.88913,-0.01822 -0.88913,1.018254 0,1 l 2.19337,-0.004 -0.006,0.004 -3.27651,2.873468 c -0.64989,0.580999 0.2216,1.555837 0.87149,0.97484 l 1.64161,-1.398308 c 0,1.651946 1.15632,3.581251 3.47517,3.550001 2.31885,-0.03125 3.5249,-1.749295 3.5249,-3.550001 0,-1.800705 -1.00462,-2.558141 -1.45954,-3.013074 z M 415.5,82.192503 c 1.22478,0 2.25,0.945047 2.25,2.25 0,1.304953 -1.05311,2.25 -2.25,2.25 -1.19689,0 -2.25,-0.960585 -2.25,-2.25 0,-1.289415 1.02522,-2.25 2.25,-2.25 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.3066;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ transform="translate(19)"
+ id="g28228-3-3"
+ style="display:inline;opacity:0.6;stroke:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ <g
+ id="g28217-6-6"
+ transform="translate(339,-440)"
+ style="display:inline;opacity:0.99;stroke:#ffffff;enable-background:new">
+ <path
+ inkscape:connector-curvature="0"
+ id="path28215-0"
+ transform="translate(-338,440)"
+ d="m 501.49219,52.992188 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m -7.00781,0.0067 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.146484 l -4,4.001116 c -0.10126,0.101337 -0.1304,0.223491 -0.13086,0.345704 L 490,57.507812 v 1.984314 c -0.01,0.676161 1.00956,0.676161 1,0 v -1.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.5 h 1.5 c 0.67616,0.0096 0.67616,-1.002805 0,-0.993242 h -2 v 0.002 c -0.005,-5e-6 -0.0101,-0.0021 -0.0156,-0.002 z m 4.01562,-0.0068 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 2.99219,3.000062 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m -11,5 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m 0,3 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z M 492.5,65.992126 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ style="display:inline;stroke:#ffffff;enable-background:new"
+ id="g28228"
+ transform="translate(-1)"
+ inkscape:label="C-24">
+ <g
+ style="display:inline;opacity:0.99;stroke:#ffffff;enable-background:new"
+ transform="translate(339,-440)"
+ id="g28217">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 501.49219,52.992188 C 501.21604,52.996495 500.99568,53.223854 501,53.5 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z M 495.48438,53 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.146484 l -5,5 c -0.10126,0.101337 -0.1304,0.223491 -0.13086,0.345704 L 490,58.507812 V 60.5 c -0.01,0.676161 1.00956,0.676161 1,0 V 59 h 4.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 54 h 0.5 c 0.67616,0.0096 0.67616,-1.009563 0,-1 h -1 v 0.002 c -0.005,-5e-6 -0.0101,-0.0021 -0.0156,-0.002 z M 498.5,53 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 2.99219,2.992188 C 501.21604,55.996495 500.99568,56.223854 501,56.5 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 0,3 C 501.21604,58.996495 500.99568,59.223854 501,59.5 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m -11,3 C 490.21604,61.996495 489.99568,62.223854 490,62.5 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 11,0 C 501.21604,61.996495 500.99568,62.223854 501,62.5 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m -11,3 C 490.21604,64.996494 489.99568,65.223854 490,65.5 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z m 11,0 C 501.21604,64.996494 500.99568,65.223854 501,65.5 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.512227 -0.50781,-0.507812 z M 492.5,66 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z"
+ transform="translate(-338,440)"
+ id="path28215" />
+ </g>
+ </g>
+ <g
+ transform="translate(-664,-513)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g8745-3"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="C-23">
<path
- id="path10504"
- transform="translate(21,-467)"
- d="m 91.347656,288.96484 a 0.51005099,0.51005099 0 0 0 -0.376953,0.20899 c -1.08977,1.44807 -1.289364,3.38767 -0.521484,5.03125 0.76787,1.64358 2.380967,2.72477 4.185547,2.80078 1.781016,0.075 3.455174,-0.8442 4.365234,-2.38086 v 1.875 a 0.50005,0.50005 0 1 0 1,0 v -3 A 0.50005,0.50005 0 0 0 99.5,293 h -3 a 0.50005,0.50005 0 1 0 0,1 h 1.693359 a 0.51006897,0.51006897 0 0 0 -0.03906,0.0586 c -0.71442,1.24711 -2.052293,1.98773 -3.476563,1.92774 -1.42426,-0.06 -2.695887,-0.90979 -3.304687,-2.21289 -0.60881,-1.3031 -0.449088,-2.83939 0.414062,-3.98633 a 0.51005099,0.51005099 0 0 0 -0.388671,-0.82227 0.51005099,0.51005099 0 0 0 -0.05078,0 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 475.25,53 a 0.50005,0.50005 0 0 0 -0.21289,0.04687 l -5.75391,2.708984 a 0.50005,0.50005 0 0 0 -0.28515,0.453125 v 7.292969 a 0.50005,0.50005 0 0 0 0.27539,0.447266 l 6.00195,3.001953 a 0.50005,0.50005 0 0 0 0.44727,0 l 6.00195,-3.001953 A 0.50005,0.50005 0 0 0 482,63.501953 v -6.916015 a 0.50005,0.50005 0 0 0 0,-0.181641 v -0.195313 a 0.50005,0.50005 0 0 0 -0.28711,-0.453125 l -5.75,-2.707031 A 0.50005,0.50005 0 0 0 475.75,53 Z m 0.11133,1 h 0.27734 l 5.00977,2.359375 -5.14844,2.509766 -5.14844,-2.509766 z M 469.99805,57.298828 475,59.738281 v 5.957031 l -5.00195,-2.501953 z M 481,57.300781 v 5.892578 l -5,2.5 v -5.955078 z"
+ transform="translate(664,513)"
+ id="path8739-6"
inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(-18,356)"
- id="g10514"
- style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke">
+ transform="translate(-21.0023)"
+ style="display:inline;fill:#ffffff;stroke:#ffffff;enable-background:new"
+ id="g13169-8-6"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="C-22">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 469.49414,55.992188 A 0.50004982,0.50004982 0 0 0 469.00195,56.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 471.00195,57.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 473.00195,58.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z m 2,1 A 0.50004982,0.50004982 0 0 0 475.00195,59.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
+ id="path13150-5-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.9;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 471.49609,54.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 477.00195,58.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
+ id="path13154-7-3"
+ inkscape:connector-curvature="0" />
<path
- id="path10510"
- transform="translate(18,-356)"
- d="m 95.398438,282.97461 a 0.50004994,0.50004994 0 0 0 -0.05078,0.002 0.50004994,0.50004994 0 0 0 -0.367187,0.20313 c -1.08755,1.44512 -1.289758,3.38123 -0.523438,5.02148 0.76632,1.64025 2.376885,2.71907 4.177735,2.79492 1.781962,0.0751 3.458632,-0.84789 4.365232,-2.38867 V 290.5 a 0.50004997,0.50004997 0 1 0 1,0 v -3 a 0.50004997,0.50004997 0 0 0 -0.5,-0.5 h -3 a 0.50004997,0.50004997 0 1 0 0,1 h 1.70312 a 0.50004994,0.50004994 0 0 0 -0.0391,0.0645 c -0.71624,1.25031 -2.05833,1.99179 -3.486324,1.93164 -1.42799,-0.0601 -2.704083,-0.91231 -3.314453,-2.21875 -0.61036,-1.30644 -0.449354,-2.8462 0.416016,-3.99609 A 0.50004994,0.50004994 0 0 0 95.3984,282.97466 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 473.49609,53.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 479.00195,57.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
+ id="path13161-0-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 475.49609,52.992188 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 v 0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 v -0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 2,1 a 0.50004982,0.50004982 0 0 0 -0.49414,0.505859 l -0.002,0.25 a 0.50004982,0.50004982 0 1 0 1,0.0039 l 0.002,-0.25 a 0.50004982,0.50004982 0 0 0 -0.50586,-0.509765 z m 1.99805,1 A 0.50004982,0.50004982 0 0 0 481.00195,56.5 v 7 a 0.50004982,0.50004982 0 1 0 1,0 v -7 a 0.50004982,0.50004982 0 0 0 -0.50781,-0.507812 z"
+ id="path13163-4-8"
inkscape:connector-curvature="0" />
</g>
<g
- id="g10528"
- transform="translate(-21,384)">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g15543"
+ transform="translate(42,-42)"
+ inkscape:label="C-21">
<g
- style="display:inline;opacity:0.7;enable-background:new"
- id="g10520"
- transform="translate(46,-388)">
+ id="g15520"
+ transform="translate(232,-398)"
+ style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
<path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 430.48047,53 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -3.94922,3.949218 C 425.83169,57.461484 426.05468,57.99983 426.5,58 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 54 h 6 v 3.5 c -0.01,0.676161 1.00956,0.676161 1,0 v -4 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -7 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z M 426,59.000004 V 66.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 4.25 c 0.67616,0.0096 0.67616,-1.009563 0,-1 H 427 v -6.999996 z"
+ transform="translate(-274,440)"
+ id="path15514"
inkscape:connector-curvature="0"
- id="path10518"
- d="m 50.492188,287.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 50,289.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 56.292969,295 H 51 v -5.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
</g>
<g
- transform="translate(42,-384)"
- id="g10526"
- style="display:inline;opacity:1;enable-background:new">
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ style="display:inline;opacity:1;fill:#ffffff;stroke-width:1.25111;enable-background:new"
+ transform="matrix(-0.799288,0,0,0.799288,686.435,-75.7359)"
+ id="g12909-3">
+ <path
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m 435.50195,58 a 0.50005,0.50005 0 0 0 -0.50586,0.507812 L 435,59.847656 c -0.37235,0.07227 -0.71903,0.219786 -1.02148,0.427735 l -1.12696,-1.123047 a 0.50005,0.50005 0 0 0 -0.34375,-0.150391 0.50005,0.50005 0 0 0 -0.36133,0.859375 l 1.12696,1.123047 c -0.20773,0.30118 -0.3566,0.644813 -0.42969,1.015625 l -1.3457,0.002 a 0.5009775,0.5009775 0 0 0 0.002,1.001953 L 432.83789,63 c 0.0676,0.378442 0.20857,0.7312 0.41602,1.039062 l -1.10743,1.109376 a 0.50005,0.50005 0 1 0 0.70508,0.705078 l 1.10352,-1.101563 c 0.30785,0.216541 0.661,0.370975 1.04297,0.445313 l -0.002,1.300781 a 0.50098382,0.50098382 0 1 0 1.00196,0.0039 L 436,65.199219 c 0.38598,-0.06997 0.74484,-0.216649 1.05664,-0.431641 l 1.08203,1.085938 a 0.5000572,0.5000572 0 1 0 0.70899,-0.705078 l -1.08399,-1.087891 C 437.97884,63.747505 438.12621,63.387471 438.19531,63 H 439.5 a 0.50033424,0.50033424 0 1 0 0,-1 h -1.31055 c -0.0748,-0.379778 -0.22985,-0.730801 -0.44531,-1.037109 l 1.10156,-1.103516 A 0.50005,0.50005 0 0 0 438.49805,59 a 0.50005,0.50005 0 0 0 -0.35743,0.154297 l -1.10742,1.105469 C 436.72738,60.053691 436.37559,59.913865 436,59.845703 l -0.004,-1.339844 A 0.50005,0.50005 0 0 0 435.50195,58 Z m -0.002,3.300781 c 0.66274,0 1.19921,0.536481 1.19922,1.199219 0,0.662738 -0.53648,1.199219 -1.19922,1.199219 -0.66274,-8e-6 -1.19922,-0.536481 -1.19922,-1.199219 0,-0.66273 0.53649,-1.199211 1.19922,-1.199219 z"
+ transform="matrix(-1.25111,0,0,1.25111,911.356,147.301)"
+ id="path12903-0"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ transform="translate(0.99995,117.996)"
+ id="g28591-2"
+ style="display:inline;enable-background:new"
+ inkscape:label="C-20">
+ <g
+ id="g28589-6">
<path
inkscape:connector-curvature="0"
- id="path10524"
- d="m 50.492188,287.99219 a 0.50005,0.50005 0 0 0 -0.388672,0.19531 0.50005,0.50005 0 0 0 -0.0039,0.006 l -1.953125,1.95312 a 0.50005,0.50005 0 1 0 0.707032,0.70704 L 50,289.70703 V 295.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 5.792969 l -1.146485,1.14648 a 0.50005,0.50005 0 1 0 0.707032,0.70704 l 1.957031,-1.95704 a 0.50005,0.50005 0 0 0 0.002,-0.79296 0.50005,0.50005 0 0 0 -0.0059,-0.004 l -1.953125,-1.95313 a 0.50005,0.50005 0 1 0 -0.707032,0.70704 L 56.292969,295 H 51 v -5.29297 l 1.146484,1.14649 a 0.50005,0.50005 0 1 0 0.707032,-0.70704 l -1.957032,-1.95703 a 0.50005,0.50005 0 0 0 -0.404296,-0.19726 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ d="m 411,-65 h 1 v 3 h -1 z m -1,3 h 1 v 3 h -1 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path28575-1" />
+ <path
+ sodipodi:nodetypes="cscccc"
+ inkscape:connector-curvature="0"
+ id="path28581-2"
+ d="m 408.50004,-53.446439 c 0,1.0803 -0.892,1.95 -2,1.95 -1.108,0 -2,-0.8697 -2,-1.95 l 10e-6,-2.05 h 4 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path28583-6"
+ d="m 404.50005,-58.496439 h 4 v 3 h -4 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ <path
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 408.50005,-63.496439 h -2 -1 -1 v 3 h 4 z"
+ id="path28587-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ id="path28596-5"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 414,-65 h 1 v 3 h -1 z m -1,3 h 1 v 3 h -1 z"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 417,-65 h 1 v 3 h -1 z m -1,3 h 1 v 3 h -1 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path28601-3" />
</g>
</g>
<g
- transform="translate(21,573)"
- id="g10534">
+ id="g41646"
+ style="display:inline;enable-background:new"
+ inkscape:label="C-17">
<path
- inkscape:connector-curvature="0"
- id="path10530"
- d="m 216.5,-282 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 6 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -6 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 6 v 5 h -6 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 350.50195,56 a 0.50005,0.50005 0 0 0 -0.34765,0.859375 l 3.14648,3.146484 h -10.79297 a 0.50005,0.50005 0 1 0 0,1 h 10.79297 l -3.14648,3.146485 a 0.50005,0.50005 0 1 0 0.70703,0.707031 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707031 l -4,-4 A 0.50005,0.50005 0 0 0 350.50195,56 Z"
+ id="path9970"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g41643"
+ style="display:inline;enable-background:new"
+ inkscape:label="C-16">
<path
- inkscape:connector-curvature="0"
- id="path10532"
- d="m 226.5,-289 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 12 h -2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 326.49023,56 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707031 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.14649,-3.146485 H 334.5 a 0.50005,0.50005 0 1 0 0,-1 h -10.79297 l 3.14649,-3.146484 A 0.50005,0.50005 0 0 0 326.49023,56 Z"
+ id="path12420"
+ inkscape:connector-curvature="0" />
</g>
<g
+ id="g41649"
style="display:inline;enable-background:new"
- id="g27713"
- transform="translate(-80)">
+ inkscape:label="C-15">
<path
- id="rect27779"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 618,63 h 1 v 1.999999 h -1 z m -2,0 h 1 v 1.999999 h -1 z m -2,0 h 1 v 1.999999 h -1 z M 613.53711,53 C 612.69436,53 612,53.694362 612,54.537109 v 8 2.925782 C 612,66.305638 612.69436,67 613.53711,67 h 8.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 v -2.925782 -8 C 624,53.694362 623.30564,53 622.46289,53 Z m 0,9 h 8.92578 C 622.76894,62 623,62.231065 623,62.537109 v 2.925782 C 623,65.768935 622.76894,66 622.46289,66 h -8.92578 C 613.23106,66 613,65.768935 613,65.462891 V 62.537109 C 613,62.231065 613.23106,62 613.53711,62 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 309.49414,52.994141 a 0.50005,0.50005 0 0 0 -0.34766,0.859375 L 312.29297,57 H 305 c -2.7555,0 -5,2.244499 -5,5 0,2.755501 2.2445,5 5,5 h 1.5 a 0.50005,0.50005 0 1 0 0,-1 H 305 c -2.21506,0 -4,-1.784939 -4,-4 0,-2.215061 1.78494,-4 4,-4 h 7.29297 l -3.14649,3.146484 a 0.50005,0.50005 0 1 0 0.70704,0.707032 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.707032 l -4,-4 a 0.50005,0.50005 0 0 0 -0.35938,-0.152343 z"
+ id="path13229"
inkscape:connector-curvature="0" />
</g>
<g
- id="g27886"
- transform="translate(-123,-21)">
+ id="g41652"
+ style="display:inline;enable-background:new"
+ inkscape:label="C-14">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 283.49023,52.996094 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -4,4 a 0.50005,0.50005 0 0 0 0,0.707032 l 4,4 a 0.50005,0.50005 0 1 0 0.70704,-0.707032 L 280.70703,58 H 288 c 2.21506,0 4,1.784939 4,4 0,2.215061 -1.78494,4 -4,4 h -1.5 a 0.50005,0.50005 0 1 0 0,1 h 1.5 c 2.7555,0 5,-2.244499 5,-5 0,-2.755501 -2.2445,-5 -5,-5 h -7.29297 l 3.14649,-3.146484 a 0.50005,0.50005 0 0 0 -0.36329,-0.857422 z"
+ id="path13225"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ transform="translate(-189,-42)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g17809-9"
+ inkscape:label="C-6">
<g
- style="display:inline;enable-background:new"
- id="g28033"
- transform="translate(21,-21)">
+ id="g17552-8"
+ transform="matrix(-1,0,0,1,508,-7e-5)"
+ style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157475;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="M 516.03711,33 C 514.91694,33 514,33.916938 514,35.037109 V 36 c -0.0409,0.706384 1.0409,0.706384 1,0 V 35.037109 C 515,34.454485 515.45448,34 516.03711,34 h 4.92578 C 521.54552,34 522,34.454485 522,35.037109 v 5.058594 c -0.58287,0.214917 -1,0.784943 -1,1.441406 v 1.925782 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 H 522 V 46 h 1 v -2.037109 h 0.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -1.925782 c 0,-0.656467 -0.41713,-1.22649 -1,-1.441406 V 35.037109 C 523,33.916938 522.08306,33 520.96289,33 Z"
- transform="translate(102,41)"
- id="path28027"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 201.49219,94.998047 a 0.50005,0.50005 0 0 0 -0.38867,0.195312 0.50005,0.50005 0 0 0 -0.006,0.0059 l -3.95118,3.953125 a 0.50005,0.50005 0 1 0 0.70704,0.707031 L 201,96.712891 v 8.792969 a 0.50005,0.50005 0 1 0 1,0 v -8.792969 l 3.14648,3.146484 a 0.50005,0.50005 0 1 0 0.70704,-0.707031 l -3.95508,-3.955078 a 0.50005,0.50005 0 0 0 -0.40625,-0.199219 z"
+ id="path14327-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 195.49219,104.99219 A 0.50005,0.50005 0 0 0 195,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="rect17542-1"
inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;enable-background:new"
- id="g28053-2">
+ id="g17548-0"
+ transform="matrix(-1,0,0,1,508,-7e-5)"
+ style="fill:#ffffff">
<path
- inkscape:connector-curvature="0"
- id="rect28051-4"
- transform="translate(21,-21)"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 616,85 h 1 v 0.999999 h -1 z m -2,0 h 1 v 0.999999 h -1 z m -0.46289,-8 C 612.69436,77 612,77.694362 612,78.537109 v 7.925782 C 612,87.305638 612.69436,88 613.53711,88 h 5.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 V 78.537109 C 621,77.694362 620.30564,77 619.46289,77 Z m 0,7 h 5.92578 C 619.76894,84 620,84.231065 620,84.537109 v 1.925782 C 620,86.768935 619.76894,87 619.46289,87 h -5.92578 C 613.23106,87 613,86.768935 613,86.462891 V 84.537109 C 613,84.231065 613.23106,84 613.53711,84 Z" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 222.49219,95.005859 A 0.50005,0.50005 0 0 0 222,95.511719 v 8.792971 l -3.14648,-3.14649 a 0.50005,0.50005 0 1 0 -0.70704,0.70703 l 3.95704,3.95704 a 0.50005,0.50005 0 0 0 0.79296,0.002 0.50005,0.50005 0 0 0 0.004,-0.006 l 3.95313,-3.95313 a 0.50005,0.50005 0 1 0 -0.70704,-0.70703 L 223,104.30469 v -8.792971 a 0.50005,0.50005 0 0 0 -0.50781,-0.50586 z"
+ id="path14329-2"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 216.49219,104.99219 A 0.50005,0.50005 0 0 0 216,105.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 1 0 -1,0 v 2.5 h -11 v -2.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.50781 z"
+ id="path17546-9"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ transform="translate(42,1)"
+ id="g10697"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="C-5">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 35.744141,52.003906 c -0.89409,0.01843 -1.828792,0.373713 -2.597657,1.142578 l -5,5 c -0.837869,0.83787 -1.178323,2.041781 -1.11914,3.226563 0.05918,1.184782 0.515289,2.376617 1.36914,3.230469 0.852133,0.852132 2.037527,1.314671 3.220704,1.376953 1.183176,0.06228 2.389387,-0.280013 3.236328,-1.126953 l 6,-6 a 0.50005,0.50005 0 1 0 -0.707032,-0.707032 l -6,6 c -0.60312,0.603121 -1.522254,0.886172 -2.476562,0.835938 -0.954308,-0.05023 -1.918539,-0.43807 -2.566406,-1.085938 -0.646149,-0.646148 -1.030262,-1.616046 -1.078125,-2.574218 -0.04786,-0.958173 0.23781,-1.878436 0.828125,-2.46875 l 5,-5 c 1.184971,-1.184974 2.75871,-1.004381 3.554687,-0.248047 0.796393,0.756731 0.863064,2.416231 -0.261719,3.541015 l -4.5,4.5 c -0.592865,0.592866 -1.094745,0.448224 -1.417968,0.125 -0.323224,-0.323223 -0.467866,-0.825103 0.125,-1.417968 l 3.5,-3.5 a 0.50005,0.50005 0 1 0 -0.707032,-0.707032 l -3.5,3.5 c -0.907134,0.907135 -0.801776,2.155255 -0.125,2.832032 0.676777,0.676776 1.924897,0.782134 2.832032,-0.125 l 4.5,-4.5 c 1.483397,-1.483398 1.519845,-3.762437 0.24414,-4.97461 -0.60598,-0.5758 -1.459426,-0.89343 -2.353515,-0.875 z"
+ id="path10693"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect10695"
+ width="16"
+ height="16"
+ x="26"
+ y="52"
+ rx="0.5"
+ ry="0.5" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g10711"
+ transform="translate(598,-637)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="C-4">
+ <g
+ transform="translate(-189)"
+ id="g10709"
+ style="fill:#ffffff">
+ <rect
+ y="214.99997"
+ x="-152"
+ height="16"
+ width="16"
+ id="rect10699"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.8;marker:none;enable-background:accumulate"
+ transform="rotate(-90,-12,565)" />
+ <g
+ id="g10703"
+ style="fill:#ffffff" />
+ <path
+ id="path10707"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -350.42969,690.01758 c -0.79787,-0.038 -1.57177,0.27684 -2.16015,0.86523 l -1.48633,1.48828 c -0.61577,0.57533 -0.93433,1.35407 -0.89258,2.1543 a 0.50005,0.50005 0 1 0 0.99805,-0.0508 c -0.0269,-0.51495 0.15566,-0.98016 0.57617,-1.37305 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 l 1.5,-1.5 c 0.41161,-0.41161 0.88966,-0.59872 1.40429,-0.57422 0.51464,0.0245 1.08439,0.26993 1.63868,0.82422 0.55479,0.5548 0.80954,1.13546 0.83789,1.65235 0.0283,0.51688 -0.15241,0.9848 -0.57422,1.3789 a 0.50005,0.50005 0 0 0 -0.0137,0.0117 l -1.5,1.5 c -0.41213,0.41213 -0.87694,0.60352 -1.39649,0.60352 a 0.50005,0.50005 0 1 0 0,1 c 0.78067,0 1.52491,-0.31788 2.10352,-0.89649 l 1.48828,-1.48828 c 0.61768,-0.57711 0.9366,-1.36125 0.89258,-2.16406 -0.044,-0.80281 -0.43566,-1.60948 -1.13086,-2.30469 -0.69571,-0.69571 -1.49901,-1.07724 -2.29688,-1.11523 z m -6.00976,6 c -0.80753,-0.0482 -1.5954,0.26944 -2.17578,0.89062 l -1.48829,1.48828 c -0.58838,0.58839 -0.90322,1.36034 -0.86523,2.15821 0.038,0.79787 0.41952,1.60311 1.11523,2.29883 0.69521,0.6952 1.50384,1.08487 2.30664,1.1289 0.80281,0.044 1.585,-0.27294 2.16211,-0.89062 l 1.48829,-1.48828 C -353.31787,701.0249 -353,700.28067 -353,699.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.51955 -0.19139,0.98436 -0.60352,1.39648 l -1.5,1.5 a 0.50005,0.50005 0 0 0 -0.0117,0.0117 c -0.39411,0.42182 -0.86007,0.60452 -1.37696,0.57618 -0.51688,-0.0283 -1.0995,-0.2831 -1.65429,-0.8379 -0.55429,-0.55428 -0.79776,-1.12404 -0.82227,-1.63867 -0.0245,-0.51463 0.16065,-0.99268 0.57227,-1.40429 l 1.5,-1.5 a 0.50005,0.50005 0 0 0 0.0117,-0.0117 c 0.39634,-0.4242 0.86629,-0.60725 1.38672,-0.57618 a 0.50005,0.50005 0 1 0 0.0586,-0.99804 z m 4.92968,-2.02149 a 0.50005,0.50005 0 0 0 -0.34375,0.15039 l -5,5 a 0.50005,0.50005 0 1 0 0.70704,0.70704 l 5,-5 a 0.50005,0.50005 0 0 0 -0.36329,-0.85743 z"
+ inkscape:connector-curvature="0" />
</g>
</g>
<g
+ id="g41658"
+ style="display:inline;enable-background:new"
+ inkscape:label="C-3">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 34.492188,54.005859 A 0.50005,0.50005 0 0 0 34,54.511719 v 9.792969 l -3.146484,-3.146485 a 0.50005,0.50005 0 1 0 -0.707032,0.707031 l 4,4 a 0.50005,0.50005 0 0 0 0.707032,0 l 4,-4 A 0.50005,0.50005 0 1 0 38.146484,61.158203 L 35,64.304688 v -9.792969 a 0.50005,0.50005 0 0 0 -0.507812,-0.50586 z"
+ id="path14329"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g41655"
+ style="display:inline;enable-background:new"
+ inkscape:label="C-2">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 13.492188,54.005859 a 0.50005,0.50005 0 0 0 -0.345704,0.146485 l -3.9999996,4 a 0.50005,0.50005 0 1 0 0.7070312,0.707031 L 13,55.712891 v 9.792968 a 0.50005,0.50005 0 1 0 1,0 v -9.792968 l 3.146484,3.146484 a 0.50005,0.50005 0 1 0 0.707032,-0.707031 l -4,-4 a 0.50005,0.50005 0 0 0 -0.361328,-0.146485 z"
+ id="path14327"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;stroke-width:1.14286;enable-background:new"
+ id="g13938"
+ transform="matrix(0.875,0,0,0.875,-254.625,-304.875)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="C-1">
+ <rect
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3.42857;marker:none;enable-background:accumulate"
+ id="rect13853"
+ width="16"
+ height="16"
+ x="299"
+ y="408.99994" />
+ </g>
+ <g
id="g27900"
- transform="translate(-123,-21)">
+ transform="translate(-123,-21)"
+ style="display:inline;enable-background:new"
+ inkscape:label="B-26">
<g
transform="translate(0,-21)"
id="g28156">
@@ -16530,980 +18186,816 @@
inkscape:connector-curvature="0" />
</g>
</g>
- <path
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 511.5,452 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.64684,0 1.19777,-0.42097 1.40625,-1 h 1.1875 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 -0.64637,0 -1.19742,0.42162 -1.40625,1 h -1.1875 c -0.20883,-0.57838 -0.75988,-1 -1.40625,-1 z m 11,0 c -0.64637,0 -1.19742,0.42162 -1.40625,1 H 520.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 L 516.29297,457 h -3.38672 c -0.20883,-0.57838 -0.75988,-1 -1.40625,-1 -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.64684,0 1.19777,-0.42097 1.40625,-1 H 516.5 a 0.50005,0.50005 0 0 0 0.35352,-0.14648 L 520.70703,454 h 0.38672 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.27091,0 0.47782,0.20294 0.49414,0.46875 a 0.50005,0.50005 0 0 0 0,0.0625 C 511.97782,453.79707 511.77091,454 511.5,454 c -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 4,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 515.02218,453.20294 515.22909,453 515.5,453 Z m 7,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 522.02218,453.20294 522.22909,453 522.5,453 Z m 0,3 c -0.64637,0 -1.19742,0.42162 -1.40625,1 H 520.5 a 0.50005,0.50005 0 0 0 -0.35352,0.14648 l -5,5 A 0.50005,0.50005 0 0 0 515,462.5 v 0.59375 c -0.57903,0.20848 -1,0.75941 -1,1.40625 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.64684 -0.42097,-1.19777 -1,-1.40625 v -0.38672 L 520.70703,458 h 0.38672 c 0.20848,0.57903 0.75941,1 1.40625,1 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 11,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.27091,0 -0.47782,-0.20293 -0.49414,-0.46875 a 0.50005,0.50005 0 0 0 0,-0.0625 C 522.02218,457.20294 522.22909,457 522.5,457 Z m -11,3 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 11,0 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.23017 0.0579,0.44679 0.15234,0.64258 a 0.50005,0.50005 0 0 0 -0.006,0.004 l -1,1 a 0.50005,0.50005 0 0 0 -0.004,0.006 C 519.94679,463.05791 519.73016,463 519.5,463 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.23002 -0.058,-0.44493 -0.15234,-0.64062 a 0.50005,0.50005 0 0 0 0.006,-0.006 l 1,-1 a 0.50005,0.50005 0 0 0 0.004,-0.004 c 0.1955,0.0946 0.41225,0.15062 0.64234,0.15062 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -11,1 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m 11,0 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -3,3 c 0.28206,0 0.5,0.21794 0.5,0.5 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.28206 0.21794,-0.5 0.5,-0.5 z m -4.0293,0.006 a 0.50005,0.50005 0 0 0 0.0371,0 0.50005,0.50005 0 0 0 0.0176,0 c 0.26874,0.0134 0.4746,0.22107 0.4746,0.494 0,0.28207 -0.21794,0.5 -0.5,0.5 -0.28206,0 -0.5,-0.21793 -0.5,-0.5 0,-0.27158 0.20391,-0.47876 0.4707,-0.49414 z"
- id="circle28282" />
- <g
- id="g27867"
- transform="translate(41.999996,-83.999998)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 114.5,97 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -3,6 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path27865"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccc" />
- </g>
<g
- id="g28017"
- transform="translate(-42.000004,-83.999998)">
+ id="g27886"
+ transform="translate(-123,-21)"
+ style="display:inline;enable-background:new"
+ inkscape:label="B-25">
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:1;enable-background:new"
- id="g13408-5"
- transform="translate(-357.00711,41.992878)">
- <g
- style="display:inline;opacity:0.98999999;enable-background:new"
- transform="translate(378.99999,-439.99995)"
- id="g12509-8" />
+ style="display:inline;enable-background:new"
+ id="g28033"
+ transform="translate(21,-21)">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 531.49219,52.992188 a 0.50005,0.50005 0 0 0 -0.31641,0.121093 0.50005,0.50005 0 0 0 -0.0195,0.01563 0.50005,0.50005 0 0 0 -0.0176,0.01758 0.50005,0.50005 0 0 0 -0.002,0.0039 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.0039 0.50005,0.50005 0 0 0 -0.0273,0.03711 0.50005,0.50005 0 0 0 -0.002,0.0039 A 0.50005,0.50005 0 0 0 531,53.582031 V 54.5 a 0.50005,0.50005 0 1 0 1,0 V 54 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.0078 z m 13,0 A 0.50005,0.50005 0 0 0 544.41797,53 H 543.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.919922 a 0.50005,0.50005 0 0 0 -0.11328,-0.404297 0.50005,0.50005 0 0 0 -0.002,-0.0039 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.03125 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.111328 z M 534.5,53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -9.00781,2.992188 A 0.50005,0.50005 0 0 0 531,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,65.5 v 0.919922 a 0.50005,0.50005 0 0 0 0.11328,0.404297 0.50005,0.50005 0 0 0 0.0156,0.01953 0.50005,0.50005 0 0 0 0.0176,0.01758 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.03125 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 531.58203,67 H 532.5 a 0.50005,0.50005 0 1 0 0,-1 H 532 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,65.5 V 66 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.113281 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.03125 0.50005,0.50005 0 0 0 0.002,-0.0039 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.0039 A 0.50005,0.50005 0 0 0 545,66.417969 V 65.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z M 534.5,66 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path27987"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00157;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 516.03711,33 C 514.91694,33 514,33.916938 514,35.037109 V 36 c -0.0409,0.706384 1.0409,0.706384 1,0 V 35.037109 C 515,34.454485 515.45448,34 516.03711,34 h 4.92578 C 521.54552,34 522,34.454485 522,35.037109 v 5.058594 c -0.58287,0.214917 -1,0.784943 -1,1.441406 v 1.925782 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 H 522 V 46 h 1 v -2.037109 h 0.5 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -1.925782 c 0,-0.656467 -0.41713,-1.22649 -1,-1.441406 V 35.037109 C 523,33.916938 522.08306,33 520.96289,33 Z"
+ transform="translate(102,41)"
+ id="path28027"
inkscape:connector-curvature="0" />
</g>
<g
- transform="rotate(-180,149.5,102.00001)"
- id="g27919-7"
- style="display:inline;enable-background:new">
+ style="display:inline;enable-background:new"
+ id="g28053-2">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 117.5,98 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -4,5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path27916-5"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccc" />
+ id="rect28051-4"
+ transform="translate(21,-21)"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m 616,85 h 1 v 0.999999 h -1 z m -2,0 h 1 v 0.999999 h -1 z m -0.46289,-8 C 612.69436,77 612,77.694362 612,78.537109 v 7.925782 C 612,87.305638 612.69436,88 613.53711,88 h 5.92578 c 0.73741,0 1.36143,-0.531036 1.50586,-1.228516 0.0206,-0.09964 0.0312,-0.20325 0.0312,-0.308593 V 78.537109 C 621,77.694362 620.30564,77 619.46289,77 Z m 0,7 h 5.92578 C 619.76894,84 620,84.231065 620,84.537109 v 1.925782 C 620,86.768935 619.76894,87 619.46289,87 h -5.92578 C 613.23106,87 613,86.768935 613,86.462891 V 84.537109 C 613,84.231065 613.23106,84 613.53711,84 Z" />
</g>
</g>
- <path
- inkscape:connector-curvature="0"
- id="path27826"
- d="m 226.98047,602.99023 a 1.0001,1.0001 0 0 0 -0.6875,0.30274 L 222,607.58594 l -2.29297,-2.29297 a 1.0001,1.0001 0 1 0 -1.41406,1.41406 l 3,3 a 1.0001,1.0001 0 0 0 1.41406,0 l 5,-5 a 1.0001,1.0001 0 0 0 -0.72656,-1.7168 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
- style="fill:#ffffff"
- id="g28127"
- transform="translate(-42,21)">
+ id="g27905"
+ style="display:inline;enable-background:new"
+ inkscape:label="B-24">
<path
+ sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
- id="rect28073"
- d="m 468.5,116 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 7 a 0.50005,0.50005 0 1 0 0,-1 H 469 v -9 h 9 v 6.5 a 0.50005,0.50005 0 1 0 1,0 v -7 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="path27891-0"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 498,37.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z" />
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ d="m 489.5,45 c -0.0335,5.59e-4 -0.0669,0.0045 -0.0996,0.01172 -0.0322,0.0073 -0.0636,0.01777 -0.0937,0.03125 -0.0309,0.01328 -0.0603,0.02964 -0.0879,0.04883 -0.0136,0.0098 -0.0266,0.02019 -0.0391,0.03125 -0.0129,0.01044 -0.0253,0.02152 -0.0371,0.0332 -0.011,0.01249 -0.0215,0.02553 -0.0312,0.03906 -0.0104,0.01317 -0.0202,0.02686 -0.0293,0.04102 -0.009,0.01393 -0.0163,0.02827 -0.0234,0.04297 -0.007,0.01528 -0.0138,0.03093 -0.0195,0.04687 -0.006,0.01536 -0.0112,0.031 -0.0156,0.04687 -0.004,0.0161 -0.007,0.0324 -0.01,0.04883 -0.008,0.04974 -0.009,0.100447 -0.002,0.150391 0.003,0.01643 0.006,0.03273 0.01,0.04883 0.004,0.01587 0.01,0.03151 0.0156,0.04687 0.005,0.01591 0.011,0.03155 0.0176,0.04687 0.007,0.0147 0.0149,0.02904 0.0234,0.04297 0.009,0.01482 0.0188,0.02916 0.0293,0.04297 0.0197,0.02621 0.0419,0.05042 0.0664,0.07227 0.0754,0.0673 0.16932,0.110201 0.26953,0.123047 0.0188,0.0024 0.0377,0.0037 0.0566,0.0039 h 13 c 0.0335,-5.59e-4 0.0669,-0.0045 0.0996,-0.01172 0.0159,-0.0038 0.0315,-0.0084 0.0469,-0.01367 0.0159,-0.0051 0.0316,-0.01094 0.0469,-0.01758 0.0153,-0.0064 0.0303,-0.01358 0.0449,-0.02148 0.0292,-0.01672 0.0567,-0.03635 0.082,-0.05859 0.0129,-0.01044 0.0253,-0.02152 0.0371,-0.0332 0.011,-0.01249 0.0215,-0.02553 0.0312,-0.03906 0.0305,-0.03975 0.0549,-0.08386 0.0723,-0.13086 0.006,-0.01536 0.0112,-0.031 0.0156,-0.04687 0.009,-0.03259 0.0138,-0.06597 0.0156,-0.09961 8e-4,-0.01627 8e-4,-0.03256 0,-0.04883 -10e-4,-0.03358 -0.006,-0.06695 -0.0137,-0.09961 -0.004,-0.01587 -0.01,-0.03151 -0.0156,-0.04687 -0.005,-0.01591 -0.011,-0.03155 -0.0176,-0.04687 -0.0146,-0.03035 -0.0323,-0.05914 -0.0527,-0.08594 -0.01,-0.01287 -0.0202,-0.02525 -0.0312,-0.03711 -0.0225,-0.02455 -0.0473,-0.0468 -0.0742,-0.06641 -0.0139,-0.0098 -0.0282,-0.01896 -0.043,-0.02734 -0.0139,-0.0085 -0.0283,-0.01633 -0.043,-0.02344 -0.0153,-0.0066 -0.031,-0.01251 -0.0469,-0.01758 -0.016,-0.0054 -0.0323,-0.0099 -0.0488,-0.01367 -0.0161,-0.0041 -0.0324,-0.0073 -0.0488,-0.0098 -0.0188,-0.0024 -0.0377,-0.0037 -0.0566,-0.0039 z m 0,-12 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 10 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 13 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -10 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 h 12 v 9 h -12 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path27901" />
<path
+ d="m 494,41.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z M 493,41 v -1 h -1 v 1 z m 1,-3.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ id="path28826"
inkscape:connector-curvature="0"
- d="M 475.99635,122 A 1.99635,1.99635 0 0 1 474,123.99635 1.99635,1.99635 0 0 1 472.00365,122 1.99635,1.99635 0 0 1 474,120.00365 1.99635,1.99635 0 0 1 475.99635,122 Z m 0.50756,2.01562 c -0.44709,0.002 -0.6672,0.54472 -0.34766,0.85743 l 4.14648,4.14648 L 477.5,129 c -0.67616,-0.01 -0.67616,1.00956 0,1 l 4.00977,0.0195 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 L 482,125.5 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 l 0.01,2.8125 -4.14649,-4.14648 c -0.0945,-0.0966 -0.22417,-0.15091 -0.35937,-0.1504 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="circle28066" />
+ sodipodi:nodetypes="ccccccccccccccccccccccc" />
</g>
<g
- id="g27914"
- style="fill:#ffffff"
- transform="translate(-21)">
+ id="g49143"
+ style="display:inline;enable-background:new"
+ inkscape:label="B-23">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 69.5,157.98633 a 0.50005,0.50005 0 0 0 -0.492188,0.50586 v 12.9082 a 0.50005,0.50005 0 0 0 0.08203,0.37695 0.50005,0.50005 0 0 0 0.002,0.004 0.50005,0.50005 0 0 0 0.0293,0.0352 0.50005,0.50005 0 0 0 0.002,0.004 0.50005,0.50005 0 0 0 0.03125,0.0332 0.50005,0.50005 0 0 0 0.02539,0.0215 0.50005,0.50005 0 0 0 0.01172,0.0117 0.50005,0.50005 0 0 0 0.0039,0.002 0.50005,0.50005 0 0 0 0.04102,0.0293 0.50005,0.50005 0 0 0 0.353516,0.0742 h 12.917968 a 0.50005,0.50005 0 1 0 0,-1 h -12.5 v -12.5 A 0.50005,0.50005 0 0 0 69.5,157.98633 Z"
- id="path15133-4-4"
+ id="path29048-2"
+ d="m 475,32 c -3.86007,0 -7,3.1399 -7,7 0,3.8601 3.13993,7 7,7 3.86007,0 7,-3.1399 7,-7 0,-3.8601 -3.13993,-7 -7,-7 z m 3.48047,2.2344 a 0.50005,0.50005 0 0 1 0.31836,0.125 c 1.24012,1.0149 2.02325,2.4828 2.17383,4.0781 a 0.50005,0.50005 0 0 1 -0.49219,0.5547 0.50005,0.50005 0 0 1 -0.50195,-0.461 c -0.12552,-1.3298 -0.77879,-2.5525 -1.8125,-3.3984 a 0.50005,0.50005 0 0 1 0.31445,-0.8984 z m -1.00977,1.7832 a 0.50005,0.50005 0 0 1 0.35742,0.1543 c 0.60661,0.6066 1.00291,1.3916 1.12891,2.2402 a 0.50005,0.50005 0 0 1 -0.46289,0.5801 0.50005,0.50005 0 0 1 -0.52734,-0.4336 c -0.0945,-0.6365 -0.39067,-1.2247 -0.84571,-1.6797 a 0.50005,0.50005 0 0 1 0.34961,-0.8613 z M 475,37 c 1.09865,0 2,0.9014 2,2 0,1.0986 -0.90135,2 -2,2 -1.09865,0 -2,-0.9014 -2,-2 0,-1.0986 0.90135,-2 2,-2 z m -5.51367,1.9902 a 0.50005,0.50005 0 0 1 0.0508,0 0.50005,0.50005 0 0 1 0.48437,0.4805 c 0.12552,1.3298 0.77879,2.5525 1.8125,3.3984 a 0.50005,0.50005 0 0 1 -0.31054,0.8926 0.50005,0.50005 0 0 1 -0.32227,-0.1191 c -1.24012,-1.0149 -2.02325,-2.4828 -2.17383,-4.0781 a 0.50005,0.50005 0 0 1 0.45899,-0.5743 z m 2.06445,0.024 a 0.50050417,0.50050417 0 0 1 0.48242,0.4277 c 0.0945,0.6365 0.39067,1.2247 0.84571,1.6797 a 0.50005,0.50005 0 0 1 -0.34766,0.8594 0.50005,0.50005 0 0 1 -0.35937,-0.1524 c -0.60661,-0.6066 -1.00291,-1.3916 -1.12891,-2.2402 a 0.50050417,0.50050417 0 0 1 0.50781,-0.5742 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 72.5,165 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- id="path22120-2-1"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
</g>
<g
- id="g27942"
- style="fill:#ffffff"
- transform="translate(-21)">
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g13304"
+ transform="translate(-84,-126)"
+ inkscape:label="B-19">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 49.46875,159 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 11 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -11 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 10 h -10 z"
- id="path26471-6-1"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 475,157.99609 c -1.79823,1e-5 -2.78534,0.23261 -3.38867,0.75196 C 471.00799,159.2674 471,160.00249 471,160.49609 v 0.5 h -0.002 c -0.12828,0 -0.91099,4e-5 -1.63867,0.53711 -0.72848,0.53766 -1.35958,1.60963 -1.35938,3.4668 9e-5,0.84676 0.12547,1.43896 0.35352,1.89453 0.22804,0.45557 0.5457,0.7425 0.81445,0.98047 a 0.50086817,0.50086817 0 1 0 0.66406,-0.75 c -0.2639,-0.23368 -0.44506,-0.40021 -0.58398,-0.67773 -0.13888,-0.27753 -0.24792,-0.69815 -0.248,-1.44727 -1.7e-4,-1.64286 0.494,-2.32325 0.95312,-2.66211 0.45913,-0.33885 0.92388,-0.3418 1.04688,-0.3418 h 0.44336 a 0.50005,0.50005 0 0 0 0.0586,0.004 l 3,-0.01 a 0.50005,0.50005 0 0 0 -0.002,-1 h -0.002 -0.002 L 472,160.99414 v -0.49805 c 0,-0.4936 -0.008,-0.75638 0.26367,-0.99023 0.27167,-0.23385 1.03456,-0.50976 2.73633,-0.50977 1.70177,0 2.46467,0.27592 2.73633,0.50977 0.27166,0.23385 0.26367,0.49663 0.26367,0.99023 v 1.99414 c -6e-5,0.47857 -0.26457,0.78886 -0.8457,1.12891 -0.58114,0.34005 -1.43184,0.62116 -2.30664,0.90234 -0.87481,0.28119 -1.77478,0.56315 -2.50586,0.98829 -0.73108,0.42513 -1.34192,1.08253 -1.3418,1.98046 v 2.01368 c 0,0.4936 0.008,1.22869 0.61133,1.74804 0.60334,0.51936 1.59044,0.75196 3.38867,0.75196 1.79823,-1e-5 2.78534,-0.23261 3.38867,-0.75196 C 478.99201,170.7326 479,169.99751 479,169.50391 v -0.5 c 0.127,0 0.91215,5.4e-4 1.64062,-0.53711 0.72848,-0.53766 1.35958,-1.60963 1.35938,-3.4668 -1.6e-4,-1.56962 -0.66959,-2.34844 -1.13672,-2.84375 a 0.5001364,0.5001364 0 1 0 -0.72656,0.6875 c 0.47073,0.49913 0.86314,0.83133 0.86328,2.15625 1.7e-4,1.64286 -0.494,2.32325 -0.95312,2.66211 -0.45913,0.33885 -0.92388,0.3418 -1.04688,0.3418 h -0.44336 A 0.50005,0.50005 0 0 0 478.49805,168 l -3,0.01 a 0.50005,0.50005 0 0 0 0.002,1 h 0.002 0.002 L 478,169.00586 v 0.49805 c 0,0.4936 0.008,0.75638 -0.26367,0.99023 -0.27167,0.23385 -1.03456,0.50976 -2.73633,0.50977 -1.70177,0 -2.46467,-0.27592 -2.73633,-0.50977 C 471.99201,170.26029 472,169.99751 472,169.50391 v -2.01368 c -6e-5,-0.47218 0.26437,-0.77913 0.8457,-1.11718 0.58133,-0.33805 1.43145,-0.61908 2.30664,-0.90039 0.8752,-0.28132 1.77441,-0.56222 2.50586,-0.99024 0.73146,-0.42801 1.34168,-1.09087 1.3418,-1.99219 v -1.99414 c 0,-0.4936 -0.008,-1.22869 -0.61133,-1.74804 -0.60334,-0.51936 -1.59044,-0.75196 -3.38867,-0.75196 z"
+ id="path13302"
inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 53.5,163 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- id="path22120-2-1-2"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
</g>
<g
- inkscape:export-ydpi="96"
+ transform="translate(-210.007,-588)"
+ id="g12466"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="B-18">
+ <g
+ transform="translate(22)"
+ id="g12463"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 557.5,620 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 6.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path12459"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 553.48438,620 a 0.50005,0.50005 0 0 0 -0.3379,0.14648 l -2,2 a 0.50005,0.50005 0 1 0 0.70704,0.70704 L 553,621.70703 V 625.5 a 0.50005,0.50005 0 1 0 1,0 v -5 A 0.50005,0.50005 0 0 0 553.48438,620 Z M 553,628 c -0.79172,0 -1.70536,0.42737 -1.98047,1.35938 a 0.50062501,0.50062501 0 1 0 0.96094,0.28124 C 552.10464,629.21999 552.55814,629 553,629 c 0.31942,0 0.59941,0.0632 0.75391,0.16602 0.1545,0.10279 0.25034,0.21211 0.2539,0.58789 5.6e-4,0.20689 -0.076,0.32805 -0.29687,0.52148 -0.22152,0.19398 -0.57835,0.40234 -0.9668,0.64453 -0.38845,0.24219 -0.81151,0.52364 -1.1543,0.93555 -0.34278,0.4119 -0.58774,0.96871 -0.58984,1.64258 A 0.50005,0.50005 0 0 0 551.5,634 h 3 a 0.50005,0.50005 0 1 0 0,-1 h -2.32227 c 0.0615,-0.1621 0.068,-0.36972 0.17969,-0.50391 0.22282,-0.26775 0.55267,-0.50197 0.91602,-0.72851 0.36335,-0.22654 0.7571,-0.44007 1.09765,-0.73828 0.34056,-0.29822 0.6393,-0.73918 0.63672,-1.28125 a 0.50005,0.50005 0 0 0 0,-0.002 c -0.006,-0.62417 -0.29003,-1.13985 -0.69922,-1.41211 C 553.89941,628.06173 553.43058,628 553,628 Z"
+ id="path12461"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ <g
+ transform="translate(-231.007,-588)"
+ id="g23192-6"
+ style="display:inline;fill:#ffffff;enable-background:new"
inkscape:export-filename="blender_icons.png"
- transform="translate(-230.99288,-230.99288)"
- id="g27963"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new">
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="B-17">
<g
- id="g27959"
- style="opacity:0.6;fill:#ffffff"
- transform="translate(126)">
+ transform="translate(21)"
+ id="g23190-0"
+ style="fill:#ffffff">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 268.49219,388.99219 c -0.27614,0.004 -0.49651,0.23167 -0.49219,0.50781 v 2.49609 l -2.50586,-0.004 c -0.67605,-0.0108 -0.67808,1.00811 -0.002,1 L 268,392.99609 V 399 h -6.00391 l -0.004,-2.50781 c 0.008,-0.67608 -1.01082,-0.67405 -1,0.002 L 260.99609,399 H 258.5 c -0.67616,-0.01 -0.67616,1.00956 0,1 h 2.49609 l 0.004,2.5 c -0.01,0.67616 1.00956,0.67616 1,0 l -0.004,-2.5 H 268 v 2.5 c -0.01,0.67616 1.00956,0.67616 1,0 V 400 h 2.5 c 0.67616,0.01 0.67616,-1.00956 0,-1 H 269 v -6.00391 l 2.5,0.004 c 0.67616,0.01 0.67616,-1.00956 0,-1 l -2.5,-0.004 V 389.5 c 0.004,-0.28226 -0.22555,-0.51223 -0.50781,-0.50781 z"
- id="path27957"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 553.5,620 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 10.99219 a 0.50005,0.50005 0 1 0 0,-1 z m 0,2 a 0.50005,0.50005 0 1 0 0,1 h 11 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path23186-9"
+ inkscape:connector-curvature="0" />
</g>
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12563-2"
+ transform="translate(-84)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="B-16">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 385.5,390 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 4 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path27961"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
+ id="rect12547-2"
+ d="m 405,32 v 8 h 14 v -8 z m 2.50781,2 h 8.98438 c 0.67616,-0.0096 0.67616,1.009563 0,1 h -8.98438 c -0.67616,0.0096 -0.67616,-1.009563 0,-1 z m 0,3 h 8.98438 c 0.67616,-0.0096 0.67616,1.009563 0,1 h -8.98438 c -0.67616,0.0096 -0.67616,-1.009563 0,-1 z"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:1, 2;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ sodipodi:nodetypes="ccccccccccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 407.50781,42 a 0.50005,0.50005 0 1 0 0,1 h 8.98438 a 0.50005,0.50005 0 1 0 0,-1 z m 0,3 a 0.50005,0.50005 0 1 0 0,1 h 8.98438 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path12541-0"
+ inkscape:connector-curvature="0" />
</g>
<g
- id="g28061"
style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(42,62.999998)">
+ id="g6750-7"
+ transform="translate(-315,-567)"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="B-15">
+ <rect
+ y="598"
+ x="614"
+ height="16"
+ width="16"
+ id="rect6732-0"
+ style="opacity:0;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1;stroke-opacity:1;marker:none" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.10000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 40.433594,95 a 0.55005501,0.55005501 0 0 0 -0.378906,0.166016 l -3.44336,3.445312 a 0.55005501,0.55005501 0 1 0 0.777344,0.777344 l 3.445312,-3.44336 A 0.55005501,0.55005501 0 0 0 40.433594,95 Z m -9.445313,9.44531 a 0.55005501,0.55005501 0 0 0 -0.376953,0.16602 l -3.445312,3.44336 a 0.55104336,0.55104336 0 1 0 0.779296,0.77929 l 3.44336,-3.44531 a 0.55005501,0.55005501 0 0 0 -0.400391,-0.94336 z"
- id="path27971"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 618.74609,599 a 0.50005,0.50005 0 0 0 -0.48437,0.37695 l -3.2461,12.75 A 0.50005,0.50005 0 0 0 615,612.25 v 0.25 a 0.50005,0.50005 0 1 0 1,0 v -0.1875 l 0.84961,-3.33398 A 0.50005,0.50005 0 0 0 617,609 h 4 a 0.50005,0.50005 0 0 0 0.14844,-0.0195 h 0.002 L 622,612.3125 V 612.5 a 0.50005,0.50005 0 1 0 1,0 v -0.25 a 0.50005,0.50005 0 0 0 -0.0156,-0.12305 l -3.25391,-12.75 A 0.50005,0.50005 0 0 0 619.24609,599 Z m 0.25,1.54492 1.90235,7.45508 h -3.80078 z"
+ id="path6736-8"
inkscape:connector-curvature="0" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 32.5,100 c -0.276131,3e-5 -0.499972,0.22387 -0.5,0.5 v 3 c 2.8e-5,0.27613 0.223869,0.49997 0.5,0.5 h 3 c 0.276131,-3e-5 0.499972,-0.22387 0.5,-0.5 v -3 c -2.8e-5,-0.27613 -0.223869,-0.49997 -0.5,-0.5 z"
- id="path27982"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 310,45 v -5 h 1.5 c 0.83481,0 1.5,0.664144 1.5,1.498047 v 2.007812 c 0,0.833914 -0.66519,1.498047 -1.5,1.496094 z m 4,-1.494141 V 41.498047 C 314,40.122764 312.87431,39 311.5,39 H 310 v -6.5 c 0.004,-0.28226 -0.22555,-0.512233 -0.50781,-0.507812 C 309.21605,31.996188 308.99568,32.22386 309,32.5 v 13 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 l 2,0.002 c 1.37431,0.002 2.5,-1.120801 2.5,-2.496094 z"
+ transform="translate(315,567)"
+ id="path6744-7"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
+ sodipodi:nodetypes="ccsccccccsccccccccc" />
</g>
<g
- id="g28078-6"
- transform="rotate(90,48.5,-204.5)"
- style="fill:#ffffff">
+ id="g49131"
+ style="display:inline;enable-background:new"
+ inkscape:label="B-14">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 412.5,-364 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 9,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path28076-4"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 279.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 292.5,32 Z m 0.5,1 h 12 v 12 h -12 z"
+ id="rect12615-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 282.56641,35 a 0.50005,0.50005 0 1 0 -0.008,1 l 4.9375,0.03125 a 0.50005,0.50005 0 1 0 0.008,-1 z m 0,2 a 0.50005,0.50005 0 1 0 -0.008,1 l 3.9375,0.03125 a 0.50005,0.50005 0 1 0 0.008,-1 z m 0.004,2 a 0.50006099,0.50006099 0 1 0 -0.0156,1 l 1.9375,0.03125 a 0.50006099,0.50006099 0 1 0 0.0156,-1 z m -0.006,2 a 0.50005,0.50005 0 1 0 -0.004,1 l 5.9375,0.03125 a 0.50005,0.50005 0 1 0 0.004,-1 z"
+ id="path12623-2"
+ inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 175.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m -8,8 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z m 8,0 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path28080-3"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000024;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 217.5,159 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 11 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -11 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="path28082-0"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 241.49219,158.00781 c -0.1326,3e-5 -0.25982,0.0527 -0.35352,0.14649 l -4,4 c -0.094,0.0938 -0.14648,0.22091 -0.14648,0.35351 v 9 c 0,0.27613 0.2239,0.49997 0.5,0.5 h 9 c 0.1326,-3e-5 0.25971,-0.0527 0.35351,-0.14648 l 4,-4 c 0.094,-0.0938 0.14649,-0.22092 0.14649,-0.35352 v -9 c 0,-0.27613 -0.2239,-0.49997 -0.5,-0.5 z m 7.48828,0.98242 a 1.0001,1.0001 0 0 1 0.72656,1.7168 L 247,163.41406 V 170 a 1.0001,1.0001 0 1 1 -2,0 v -6 h -6 a 1.0001,1.0001 0 1 1 0,-2 h 6.58594 l 2.70703,-2.70703 a 1.0001,1.0001 0 0 1 0.6875,-0.30274 z"
- id="path28084-2"
- inkscape:connector-curvature="0" />
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g28075-6"
- transform="rotate(-180,339.00356,333)">
- <g
- transform="matrix(1,0,0,-1,0,999)"
- style="opacity:0.7;fill:#ffffff"
- id="g28071-5">
- <path
- inkscape:connector-curvature="0"
- id="path28067-0"
- transform="matrix(-1,0,0,1,358.00712,333)"
- d="m -61.992188,164 v 7 h 1 v -3 h 2 v 1 h 1 v -1 h 2 v 3 h 1 v -3 h 2 v 1 h 1 v -1 h 2 v 3 h 1 v -7 h -1 v 3 h -2 v -1 h -1 v 1 h -2 v -3 h -1 v 3 h -2 v -1 h -1 v 1 h -2 v -3 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- </g>
+ id="g6397"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="B-13">
<path
- sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
- id="path28073-8"
- d="m 406.5,504 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ id="rect12565-1-6"
+ d="m 258.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 A 0.50005,0.50005 0 0 0 272,45.5 V 41 h -1 v 4 H 259 V 33 h 12 v 1 h 1 V 32.5 A 0.50005,0.50005 0 0 0 271.5,32 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 261.5,35 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z m 0,2 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z m 0,2 c -0.67616,-0.0096 -0.67616,1.009563 0,1 H 272 v -1 z"
+ id="path12613-4-1"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccc" />
</g>
<g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- style="display:inline;opacity:1;stroke:#ffffff;enable-background:new"
- id="g28228"
- transform="translate(-0.99999996)">
- <g
- style="display:inline;opacity:0.98999999;stroke:#ffffff;enable-background:new"
- transform="translate(338.99999,-439.99995)"
- id="g28217">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="M 501.49219 52.992188 C 501.21604 52.996495 500.99568 53.223854 501 53.5 L 501 54.5 C 500.99 55.176161 502.00956 55.176161 502 54.5 L 502 53.5 C 502.004 53.217735 501.77446 52.987773 501.49219 52.992188 z M 495.48438 53 C 495.3572 53.004 495.23638 53.056404 495.14648 53.146484 L 490.14648 58.146484 C 490.04522 58.247821 490.01608 58.369975 490.01562 58.492188 L 490 58.507812 L 490 60.5 C 489.99 61.176161 491.00956 61.176161 491 60.5 L 491 59 L 495.5 59 C 495.77613 58.99997 495.99997 58.77613 496 58.5 L 496 54 L 496.5 54 C 497.17616 54.0096 497.17616 52.990437 496.5 53 L 495.5 53 L 495.5 53.001953 C 495.49455 53.001948 495.48986 52.999829 495.48438 53 z M 498.5 53 C 497.82384 52.9904 497.82384 54.009563 498.5 54 L 499.5 54 C 500.17616 54.0096 500.17616 52.990437 499.5 53 L 498.5 53 z M 501.49219 55.992188 C 501.21604 55.996495 500.99568 56.223854 501 56.5 L 501 57.5 C 500.99 58.176161 502.00956 58.176161 502 57.5 L 502 56.5 C 502.004 56.217735 501.77446 55.987773 501.49219 55.992188 z M 501.49219 58.992188 C 501.21604 58.996495 500.99568 59.223854 501 59.5 L 501 60.5 C 500.99 61.176161 502.00956 61.176161 502 60.5 L 502 59.5 C 502.004 59.217735 501.77446 58.987773 501.49219 58.992188 z M 490.49219 61.992188 C 490.21604 61.996495 489.99568 62.223854 490 62.5 L 490 63.5 C 489.99 64.176161 491.00956 64.176161 491 63.5 L 491 62.5 C 491.004 62.217735 490.77446 61.987773 490.49219 61.992188 z M 501.49219 61.992188 C 501.21604 61.996495 500.99568 62.223854 501 62.5 L 501 63.5 C 500.99 64.176161 502.00956 64.176161 502 63.5 L 502 62.5 C 502.004 62.217735 501.77446 61.987773 501.49219 61.992188 z M 490.49219 64.992188 C 490.21604 64.996494 489.99568 65.223854 490 65.5 L 490 66.5 C 489.99 67.176161 491.00956 67.176161 491 66.5 L 491 65.5 C 491.004 65.217735 490.77446 64.987773 490.49219 64.992188 z M 501.49219 64.992188 C 501.21604 64.996494 500.99568 65.223854 501 65.5 L 501 66.5 C 500.99 67.176161 502.00956 67.176161 502 66.5 L 502 65.5 C 502.004 65.217735 501.77446 64.987773 501.49219 64.992188 z M 492.5 66 C 491.82384 65.9904 491.82384 67.009563 492.5 67 L 493.5 67 C 494.17616 67.0096 494.17616 65.990437 493.5 66 L 492.5 66 z M 495.5 66 C 494.82384 65.9904 494.82384 67.009563 495.5 67 L 496.5 67 C 497.17616 67.0096 497.17616 65.990437 496.5 66 L 495.5 66 z M 498.5 66 C 497.82384 65.9904 497.82384 67.009563 498.5 67 L 499.5 67 C 500.17616 67.0096 500.17616 65.990437 499.5 66 L 498.5 66 z "
- transform="translate(-337.99999,439.99995)"
- id="path28215" />
- </g>
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g22284-9"
+ transform="translate(168,-252)"
+ inkscape:label="B-11">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 54.75,284 a 0.50004997,0.50004997 0 0 0 -0.431641,0.24805 l -3.646484,6.25 a 0.50004997,0.50004997 0 0 0 -0.002,0.002 c -1.211575,2.0985 -0.741006,4.77251 1.115234,6.33008 1.856239,1.55756 4.573449,1.55756 6.429688,0 1.85624,-1.55757 2.326809,-4.23158 1.115234,-6.33008 a 0.50004997,0.50004997 0 0 0 -0.002,-0.002 l -3.646484,-6.25 A 0.50004997,0.50004997 0 0 0 55.25,284 Z m 0.25,1.06445 3.464844,5.9375 c 0.970958,1.6837 0.594513,3.81305 -0.894532,5.0625 -1.489569,1.2499 -3.651055,1.2499 -5.140624,0 -1.489045,-1.24945 -1.86549,-3.3788 -0.894532,-5.0625 V 291 Z m -0.511719,2.92969 a 0.50004997,0.50004997 0 0 0 -0.429687,0.27148 l -1.697266,3.20704 c -0.166111,0.28617 -0.283806,0.59778 -0.349609,0.92187 a 0.50005872,0.50005872 0 1 0 0.980469,0.19727 c 0.04414,-0.2174 0.122796,-0.42496 0.234374,-0.61719 a 0.50004997,0.50004997 0 0 0 0.0098,-0.0176 l 1.705078,-3.22265 a 0.50004997,0.50004997 0 0 0 -0.453125,-0.74024 z"
+ id="path22264-7"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;enable-background:new"
- id="g28876">
- <g
- transform="translate(-336,-84)"
- id="g28475">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 427.5,348 c -1.37479,0 -2.5,1.12521 -2.5,2.5 0,1.17958 0.69047,1.86035 1.13281,2.33984 0.59193,0.64165 1.20449,1.21721 1.66016,1.66016 l -0.89649,0.89648 c -0.91207,0.91207 -1.15649,2.32468 -0.5625,3.35352 0.56456,0.97783 1.72188,1.4563 2.8125,1.16406 C 430.23711,359.62183 431,358.6291 431,357.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,0.68132 -0.45321,1.27287 -1.11133,1.44922 -0.65811,0.17634 -1.34683,-0.10917 -1.6875,-0.69922 -0.31121,-0.53904 -0.18558,-1.55855 0.40235,-2.14648 l 1.25,-1.25 a 0.50005,0.50005 0 0 0 0,-0.70704 c -0.4316,-0.43159 -1.30799,-1.251 -1.98633,-1.98632 C 426.38701,351.63965 426,351.32042 426,350.5 c 0,-0.83435 0.66565,-1.5 1.5,-1.5 1.16667,0 2.02863,1.23566 2.64648,1.85352 a 0.50005,0.50005 0 1 0 0.70704,-0.70704 C 430.47137,349.76434 429.33333,348 427.5,348 Z"
- id="path28463"
- inkscape:connector-curvature="0" />
- <path
- id="path28468"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 437.5,348 c -1.83333,0 -2.97137,1.76434 -3.35352,2.14648 a 0.50005,0.50005 0 1 0 0.70704,0.70704 C 435.47137,350.23566 436.33333,349 437.5,349 c 0.83435,0 1.5,0.66565 1.5,1.5 0,0.82042 -0.38701,1.13965 -0.86719,1.66016 -0.67834,0.73532 -1.55473,1.55473 -1.98633,1.98632 a 0.50005,0.50005 0 0 0 0,0.70704 l 1.25,1.25 c 0.58793,0.58793 0.71356,1.60744 0.40235,2.14648 -0.34067,0.59005 -1.02939,0.87556 -1.6875,0.69922 C 435.45321,358.77287 435,358.18132 435,357.5 a 0.50005,0.50005 0 1 0 -1,0 c 0,1.1291 0.76289,2.12183 1.85352,2.41406 1.09062,0.29224 2.24794,-0.18623 2.8125,-1.16406 0.59399,-1.02884 0.34957,-2.44145 -0.5625,-3.35352 L 437.20703,354.5 c 0.45567,-0.44295 1.06823,-1.01851 1.66016,-1.66016 C 439.30953,352.36035 440,351.67958 440,350.5 c 0,-1.37479 -1.12521,-2.5 -2.5,-2.5 z m -4.5,4.00005 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,12 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z m 0,-3 v -2 h -1 v 2 z" />
- </g>
- <g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(-1.031325,-21.999745)"
- style="display:inline;opacity:1;enable-background:new"
- id="g8671-6">
- <path
- style="display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.75542808px;marker:none;enable-background:accumulate"
- d="m 503.5,84 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 9.640625 c -0.56586,-0.207564 -1.28645,-0.1813 -1.98242,0.07227 -1.35506,0.496297 -2.23748,1.698783 -1.9707,2.685547 0.26594,0.987121 1.58042,1.385047 2.93554,0.888671 1.1076,-0.40637 1.93122,-1.302825 2.00977,-2.1875 L 503.99805,87 H 512 v 6.140625 c -0.56586,-0.207559 -1.28645,-0.181295 -1.98242,0.07227 -1.35507,0.496303 -2.23748,1.698787 -1.9707,2.685547 0.26596,0.987109 1.58042,1.385032 2.93554,0.888671 1.1076,-0.406375 1.93122,-1.302829 2.00977,-2.1875 L 513,84.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
- transform="translate(-8.968675,11.999745)"
- id="ellipse8665-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccc" />
- </g>
- <g
- id="g27905">
- <path
- sodipodi:nodetypes="ccccccccc"
- inkscape:connector-curvature="0"
- id="path27891-0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.65;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 498,37.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z" />
- <path
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
- inkscape:connector-curvature="0"
- d="m 489.5,45 c -0.0335,5.59e-4 -0.0669,0.0045 -0.0996,0.01172 -0.0322,0.0073 -0.0636,0.01777 -0.0937,0.03125 -0.0309,0.01328 -0.0603,0.02964 -0.0879,0.04883 -0.0136,0.0098 -0.0266,0.02019 -0.0391,0.03125 -0.0129,0.01044 -0.0253,0.02152 -0.0371,0.0332 -0.011,0.01249 -0.0215,0.02553 -0.0312,0.03906 -0.0104,0.01317 -0.0202,0.02686 -0.0293,0.04102 -0.009,0.01393 -0.0163,0.02827 -0.0234,0.04297 -0.007,0.01528 -0.0138,0.03093 -0.0195,0.04687 -0.006,0.01536 -0.0112,0.031 -0.0156,0.04687 -0.004,0.0161 -0.007,0.0324 -0.01,0.04883 -0.008,0.04974 -0.009,0.100447 -0.002,0.150391 0.003,0.01643 0.006,0.03273 0.01,0.04883 0.004,0.01587 0.01,0.03151 0.0156,0.04687 0.005,0.01591 0.011,0.03155 0.0176,0.04687 0.007,0.0147 0.0149,0.02904 0.0234,0.04297 0.009,0.01482 0.0188,0.02916 0.0293,0.04297 0.0197,0.02621 0.0419,0.05042 0.0664,0.07227 0.0754,0.0673 0.16932,0.110201 0.26953,0.123047 0.0188,0.0024 0.0377,0.0037 0.0566,0.0039 h 13 c 0.0335,-5.59e-4 0.0669,-0.0045 0.0996,-0.01172 0.0159,-0.0038 0.0315,-0.0084 0.0469,-0.01367 0.0159,-0.0051 0.0316,-0.01094 0.0469,-0.01758 0.0153,-0.0064 0.0303,-0.01358 0.0449,-0.02148 0.0292,-0.01672 0.0567,-0.03635 0.082,-0.05859 0.0129,-0.01044 0.0253,-0.02152 0.0371,-0.0332 0.011,-0.01249 0.0215,-0.02553 0.0312,-0.03906 0.0305,-0.03975 0.0549,-0.08386 0.0723,-0.13086 0.006,-0.01536 0.0112,-0.031 0.0156,-0.04687 0.009,-0.03259 0.0138,-0.06597 0.0156,-0.09961 8e-4,-0.01627 8e-4,-0.03256 0,-0.04883 -10e-4,-0.03358 -0.006,-0.06695 -0.0137,-0.09961 -0.004,-0.01587 -0.01,-0.03151 -0.0156,-0.04687 -0.005,-0.01591 -0.011,-0.03155 -0.0176,-0.04687 -0.0146,-0.03035 -0.0323,-0.05914 -0.0527,-0.08594 -0.01,-0.01287 -0.0202,-0.02525 -0.0312,-0.03711 -0.0225,-0.02455 -0.0473,-0.0468 -0.0742,-0.06641 -0.0139,-0.0098 -0.0282,-0.01896 -0.043,-0.02734 -0.0139,-0.0085 -0.0283,-0.01633 -0.043,-0.02344 -0.0153,-0.0066 -0.031,-0.01251 -0.0469,-0.01758 -0.016,-0.0054 -0.0323,-0.0099 -0.0488,-0.01367 -0.0161,-0.0041 -0.0324,-0.0073 -0.0488,-0.0098 -0.0188,-0.0024 -0.0377,-0.0037 -0.0566,-0.0039 z m 0,-12 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 10 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 13 c 0.27613,-2.8e-5 0.49997,-0.223869 0.5,-0.5 v -10 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.5,1 h 12 v 9 h -12 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path27901" />
- <path
- d="m 494,41.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z M 493,41 v -1 h -1 v 1 z m 1,-3.5 c -3e-5,0.276131 -0.22387,0.499972 -0.5,0.5 h -2 c -0.27613,-2.8e-5 -0.49997,-0.223869 -0.5,-0.5 v -2 c 3e-5,-0.276131 0.22387,-0.499972 0.5,-0.5 h 2 c 0.27613,2.8e-5 0.49997,0.223869 0.5,0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path28826"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccc" />
- </g>
- <g
- style="fill:#ffffff;fill-opacity:1"
- transform="translate(0,-20)"
- id="g28092-2">
- <path
- sodipodi:nodetypes="cccccccccc"
- inkscape:connector-curvature="0"
- id="path28072-1"
- d="m 363.5,95 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 99 h 14 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 368 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 363.5,100 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="rect28074-91"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
- </g>
- <g
- style="display:inline;fill:#ffffff;enable-background:new"
- transform="translate(-273,442)"
- id="g28092-0-4">
- <path
- sodipodi:nodetypes="cccccccccc"
- inkscape:connector-curvature="0"
- id="path28072-2-7"
- d="m 363.5,95 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 V 99 h 14 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 H 368 v -1.5 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 363.5,100 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 7 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 13 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -7 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
- id="rect28074-9-1"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
- </g>
- <g
- id="g28614"
- transform="translate(-147,357)">
- <path
- inkscape:connector-curvature="0"
- id="path28606"
- transform="translate(42)"
- d="m 263.50391,94.996094 c -0.25245,0 -0.505,0.169732 -0.5,0.507812 L 263,97 h -2.5 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 2.5 l -1.49414,-0.002 c -0.67616,-0.0096 -0.67616,1.01 0,1 L 260,101 v 2 l -1.49414,-0.002 c -0.67616,-0.01 -0.67616,1.01 0,1 L 260,104 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 l 0.004,1.49609 c -0.01,0.67616 1.00956,0.67616 1,0 L 264,107 h 2 l 0.004,1.49609 c -0.01,0.67616 1.00956,0.67616 1,0 L 267,107 h 2.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 104 l 1.49805,-0.002 c 0.67616,0.01 0.67616,-1.00956 0,-1 L 270,103 v -2 l 1.49805,-0.002 c 0.67616,0.01 0.67616,-1.009563 0,-1.000003 L 270,100 V 97.5 A 0.50005,0.50005 0 0 0 269.5,97 H 267 l 0.004,-1.496094 c 0.01,-0.67616 -1.01,-0.67616 -1,0 L 266,97 h -2 l 0.004,-1.496094 c 0.005,-0.33808 -0.24756,-0.507812 -0.5,-0.507812 z M 261,98 h 8 v 8 h -8 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- <g
- id="g28608"
- transform="rotate(180,370.00356,70.5)" />
- <path
- inkscape:connector-curvature="0"
- id="rect28616"
- d="m 305.5,100 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 3 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 2 v 2 h -2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- </g>
- <path
- sodipodi:nodetypes="cccccccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path28780"
- d="m 495.98438,95 c -0.25978,0.004 -0.50774,0.10921 -0.69141,0.29297 l -6,6 C 489.08739,101.49869 488.99817,101.75204 489,102 v 0.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 0.5 v 5.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 3.5 v -5.5 c 3e-5,-0.27613 0.22387,-0.49997 0.5,-0.5 h 3 c 0.27613,3e-5 0.49997,0.22387 0.5,0.5 v 5.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 103 h 0.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 102 c 0.004,-0.25043 -0.0852,-0.49916 -0.29297,-0.70703 l -6,-6 C 496.51571,95.10156 496.25496,94.99586 495.98438,95 Z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
- <g
- transform="translate(63,-21)"
- id="g29117">
- <g
- id="g29100"
- transform="translate(294.99999,-377.99995)"
- style="display:inline;opacity:1;stroke:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 152.00001,498.99995 v 4.5 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 9 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -9 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 h -4.5 v 5"
- id="path29096"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccc" />
- <path
- sodipodi:nodetypes="cccc"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
- d="m 152.50001,497.49995 h 3 v -3 z"
- id="path29098"
- inkscape:connector-curvature="0" />
- </g>
- <path
- inkscape:connector-curvature="0"
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="blender_icons.png"
- id="path29102"
- d="m 460,120.50004 0.5,2e-5 v 9 h -9 L 451.49999,129"
- style="display:inline;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
- sodipodi:nodetypes="ccccc" />
- <path
- sodipodi:nodetypes="ccccc"
- style="display:inline;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
- d="m 458,118.50004 0.5,2e-5 v 9 h -9 L 449.49999,127"
- id="path29110"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:connector-curvature="0" />
- </g>
- <g
- transform="translate(-21)"
- id="g28437">
- <path
- sodipodi:nodetypes="ccccccccccccccccc"
- inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 300.5,76 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 11 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 12 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -5.558594 c -0.31959,0.108004 -0.65516,0.175732 -1,0.212891 V 87 h -11 v -7 c 2.01109,0.01725 4.25811,0.0051 6.54102,0 -0.37613,-0.591554 -0.61026,-1.271947 -0.68946,-2 H 304 v -1.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z"
- id="path28389" />
- <path
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
- d="m 311.5,74 c -1.933,0 -3.5,1.567 -3.5,3.5 0,1.933 1.567,3.5 3.5,3.5 1.933,0 3.5,-1.567 3.5,-3.5 0,-1.933 -1.567,-3.5 -3.5,-3.5 z m -0.5,1 h 1 v 2 h 2 v 1 h -2 v 2 h -1 v -2 h -2 v -1 h 2 z"
- id="path28385"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssssccccccccccccc" />
- </g>
- <g
- transform="translate(0.99995,117.99644)"
- id="g28591-2"
- style="display:inline;enable-background:new">
- <g
- id="g28589-6">
- <path
- inkscape:connector-curvature="0"
- d="m 411,-65 h 1 v 3 h -1 z m -1,3 h 1 v 3 h -1 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path28575-1" />
- <path
- sodipodi:nodetypes="cscccc"
- inkscape:connector-curvature="0"
- id="path28581-2"
- d="m 408.50004,-53.446439 c 0,1.0803 -0.892,1.95 -2,1.95 -1.108,0 -2,-0.8697 -2,-1.95 l 10e-6,-2.05 h 4 z"
- style="display:inline;opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
- <path
- sodipodi:nodetypes="ccccc"
- inkscape:connector-curvature="0"
- id="path28583-6"
- d="m 404.50005,-58.496439 h 4 v 3 h -4 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
- <path
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 408.50005,-63.496439 h -2 -1 -1 v 3 h 4 z"
- id="path28587-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
- <path
- id="path28596-5"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 414,-65 h 1 v 3 h -1 z m -1,3 h 1 v 3 h -1 z"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- d="m 417,-65 h 1 v 3 h -1 z m -1,3 h 1 v 3 h -1 z"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- id="path28601-3" />
- </g>
- </g>
- <g
- transform="translate(63,42)"
- id="g28683">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 483.5,84 c -1.37106,-1e-5 -2.49465,1.119188 -2.5,2.490234 -10e-6,0.0039 -10e-6,0.0078 0,0.01172 10e-4,0.275368 0.22463,0.498022 0.5,0.498047 h 3 c 0.28206,0 0.5,0.217938 0.5,0.5 0,0.282062 -0.21794,0.5 -0.5,0.5 l -3.5,-0.0039 c -0.12499,0 -0.85445,-0.01071 -1.57617,0.36914 C 478.70211,88.745078 478,89.596094 478,90.996094 v 0.996094 c 0,1.40001 0.70038,2.249949 1.42188,2.630859 0.72147,0.38091 1.45054,0.373047 1.57812,0.373047 v 0.507812 c -10e-6,0.0032 -10e-6,0.0065 0,0.0098 0.005,1.371211 1.12894,2.490244 2.5,2.490234 h 3 c 1.37479,0 2.5,-1.125211 2.5,-2.5 v -0.507812 c 0.1276,0 0.85475,0.0079 1.57617,-0.373047 0.72142,-0.380914 1.42358,-1.23089 1.42383,-2.630859 v -0.994141 c 2e-5,-1.567832 -0.66959,-2.346488 -1.13672,-2.841797 -0.0911,-0.09952 -0.21863,-0.157986 -0.35351,-0.162109 -0.45031,-0.01416 -0.68821,0.527665 -0.37305,0.849609 0.47073,0.499131 0.8633,0.831529 0.86328,2.154297 v 0.994141 c -1.9e-4,1.100029 -0.42466,1.502011 -0.89062,1.748046 -0.46599,0.246036 -0.98698,0.25586 -1.10938,0.25586 L 485.5,94 c -0.67616,-0.0096 -0.67616,1.009563 0,1 l 2.5,-0.002 v 0.505859 c 0,0.834349 -0.66565,1.5 -1.5,1.5 h -3 c -0.832,6e-6 -1.49698,-0.662318 -1.5,-1.49414 V 93 c 0,-0.63889 0.20453,-1.122504 0.54102,-1.458984 C 482.8775,91.204526 483.36111,91 484,91 h 2.5 c 0.725,0 1.37138,-0.226854 1.82227,-0.677734 C 488.77315,89.871376 489,89.225 489,88.5 v -2 c 0,-1.374789 -1.12521,-2.5 -2.5,-2.5 z"
- transform="translate(-73,-52)"
- id="path28624"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccsscccsscccccssccccccccccccccssccccsscsssc" />
- </g>
- <g
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="translate(47.999998,90)"
- id="g28884"
- style="display:inline;opacity:1;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 521.5,84 c -0.6573,0.0093 -0.6573,0.990704 0,1 h 0.25 c 0.75,0 1.25,0.5 1.25,1.25 v 9.500004 c 0,0.75 -0.5,1.25 -1.25,1.25 h -0.25 c -0.6573,0.0093 -0.6573,0.990704 0,1 h 0.25 5.5 0.25 c 0.6573,-0.0093 0.6573,-0.990704 0,-1 h -0.25 C 526.5,97 526,96.5 526,95.75 V 91 h 2.5 c 0.0833,0 0.22505,0.05708 0.33398,0.166016 C 528.94291,91.274947 529,91.416667 529,91.5 c 0.009,0.657305 0.9907,0.657305 1,0 v -2 c -0.004,-0.281658 -0.24005,-0.504291 -0.52148,-0.492188 -0.26471,0.01138 -0.4746,0.22726 -0.47852,0.492188 0,0.08333 -0.0571,0.225053 -0.16602,0.333984 C 528.72505,89.942915 528.58333,90 528.5,90 H 526 v -5 h 4.75004 c 0.0104,-0.294737 0.61631,0.167956 0.86328,0.433594 C 531.86021,85.699231 532,86.054282 532,86.25 v 0.25 c 0.009,0.657305 0.9907,0.657305 1,0 v -2 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -1.75 -9 z"
- transform="translate(-57.999998,-100)"
- id="path28882"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccsccsccccccsscscccccccsccccsccccccc" />
- </g>
- <g
- transform="translate(84,-21)"
- id="g29069">
- <g
- id="g29057">
- <path
- d="m 454,117 a 6,6 0 0 1 6,6 6,6 0 0 1 -6,6"
- sodipodi:open="true"
- sodipodi:end="1.5707963"
- sodipodi:start="4.712389"
- sodipodi:ry="6"
- sodipodi:rx="6"
- sodipodi:cy="123"
- sodipodi:cx="454"
- sodipodi:type="arc"
- id="path28993"
- style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
- <g
- id="g29030">
- <circle
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="path29001"
- cx="448"
- cy="123"
- r="1" />
- <circle
- r="1"
- cy="120"
- cx="448.80383"
- id="circle29003"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
- <circle
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="circle29005"
- cx="451"
- cy="117.80385"
- r="1" />
- <circle
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- id="circle29014"
- cx="448.80383"
- cy="-126"
- r="1"
- transform="scale(1,-1)" />
- <circle
- r="1"
- cy="-128.19615"
- cx="451"
- id="circle29016"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- transform="scale(1,-1)" />
- </g>
- </g>
- <path
- id="path16341-3-5"
- style="display:inline;opacity:0.98999999;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
- d="m 456.5,123.5 -3,-4e-5 V 120.5"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc" />
- </g>
- <g
- transform="translate(539.9929,-999)"
- id="g36643-9"
- style="display:inline;enable-background:new">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -359.5,1474 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z m 0,5 a 0.50005,0.50005 0 1 0 0,1 h 7 a 0.50005,0.50005 0 1 0 0,-1 z"
- id="path36414-1"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -364.5,1473 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 0,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z"
- id="circle36422-1"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssssssssssssss" />
- </g>
- <g
- id="g36632-6"
- transform="translate(771.00702,-831)"
- style="display:inline;enable-background:new">
- <g
- id="g36628-4">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -272.5,1452 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m -5,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z m 3,5 c -0.8225,0 -1.5,0.6775 -1.5,1.5 0,0.8225 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.6775 1.5,-1.5 0,-0.8225 -0.6775,-1.5 -1.5,-1.5 z"
- id="circle36626-0"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssssssssssssss" />
- </g>
- <path
- id="path9540"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -268.5,1463 c 0.6573,0.01 0.6573,0.9907 0,1 h -3.5 v -1 z m -8.50781,0 v 1 h -4.5 c -0.6573,-0.01 -0.6573,-0.9907 0,-1 z m -4.5,-10 c -0.6573,0.01 -0.6573,0.9907 0,1 h 6.5 v -1 z M -270,1453 v 1 h 1.5 c 0.6573,-0.01 0.6573,-0.9907 0,-1 z m -11.50781,5 c -0.6573,0.01 -0.6573,0.9907 0,1 h 1.5 v -1 z m 6.50781,0 v 1 h 6.5 c 0.6573,-0.01 0.6573,-0.9907 0,-1 z"
- inkscape:connector-curvature="0" />
- </g>
+ transform="translate(189,-210)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g23463-9"
+ inkscape:label="B-10">
<path
- id="path29048-2"
- d="m 475,32 c -3.86007,0 -7,3.1399 -7,7 0,3.8601 3.13993,7 7,7 3.86007,0 7,-3.1399 7,-7 0,-3.8601 -3.13993,-7 -7,-7 z m 3.48047,2.2344 a 0.50005,0.50005 0 0 1 0.31836,0.125 c 1.24012,1.0149 2.02325,2.4828 2.17383,4.0781 a 0.50005,0.50005 0 0 1 -0.49219,0.5547 0.50005,0.50005 0 0 1 -0.50195,-0.461 c -0.12552,-1.3298 -0.77879,-2.5525 -1.8125,-3.3984 a 0.50005,0.50005 0 0 1 0.31445,-0.8984 z m -1.00977,1.7832 a 0.50005,0.50005 0 0 1 0.35742,0.1543 c 0.60661,0.6066 1.00291,1.3916 1.12891,2.2402 a 0.50005,0.50005 0 0 1 -0.46289,0.5801 0.50005,0.50005 0 0 1 -0.52734,-0.4336 c -0.0945,-0.6365 -0.39067,-1.2247 -0.84571,-1.6797 a 0.50005,0.50005 0 0 1 0.34961,-0.8613 z M 475,37 c 1.09865,0 2,0.9014 2,2 0,1.0986 -0.90135,2 -2,2 -1.09865,0 -2,-0.9014 -2,-2 0,-1.0986 0.90135,-2 2,-2 z m -5.51367,1.9902 a 0.50005,0.50005 0 0 1 0.0508,0 0.50005,0.50005 0 0 1 0.48437,0.4805 c 0.12552,1.3298 0.77879,2.5525 1.8125,3.3984 a 0.50005,0.50005 0 0 1 -0.31054,0.8926 0.50005,0.50005 0 0 1 -0.32227,-0.1191 c -1.24012,-1.0149 -2.02325,-2.4828 -2.17383,-4.0781 a 0.50005,0.50005 0 0 1 0.45899,-0.5743 z m 2.06445,0.024 a 0.50050417,0.50050417 0 0 1 0.48242,0.4277 c 0.0945,0.6365 0.39067,1.2247 0.84571,1.6797 a 0.50005,0.50005 0 0 1 -0.34766,0.8594 0.50005,0.50005 0 0 1 -0.35937,-0.1524 c -0.60661,-0.6066 -1.00291,-1.3916 -1.12891,-2.2402 a 0.50050417,0.50050417 0 0 1 0.50781,-0.5742 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:7.4;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 6.5,242 A 0.50005,0.50005 0 0 0 6,242.5 v 5 A 0.50005,0.50005 0 0 0 6.5,248 H 8 v 7.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 9 A 0.50005,0.50005 0 0 0 18,255.5 V 248 h 1.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -5 A 0.50005,0.50005 0 0 0 19.5,242 h -4 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 0.5 c 0,0.71532 -0.380592,1.37478 -1,1.73242 -0.619409,0.35765 -1.380591,0.35765 -2,0 -0.619408,-0.35764 -1,-1.0171 -1,-1.73242 v -0.5 A 0.50005,0.50005 0 0 0 10.5,242 Z m 0.5,1 h 3 c 0,1.07096 0.57257,2.06216 1.5,2.59766 0.927429,0.53549 2.072571,0.53549 3,0 0.92743,-0.5355 1.5,-1.5267 1.5,-2.59766 h 3 v 4 H 17.5 A 0.50005,0.50005 0 0 0 17,247.5 V 255 H 9 v -7.5 A 0.50005,0.50005 0 0 0 8.5,247 H 7 Z"
+ id="path22384-8"
inkscape:connector-curvature="0" />
- <g
- style="display:inline;enable-background:new"
- id="g28812"
- transform="rotate(-180,328.00001,312.49999)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 319.49219,315 a 0.50005,0.50005 0 0 0 -0.34571,0.14648 l -4,4 a 0.50005,0.50005 0 0 0 0,0.70704 l 4,4 a 0.50005,0.50005 0 0 0 0.36133,0.14648 0.50005,0.50005 0 0 0 0.34571,-0.14648 l 4,-4 a 0.50005,0.50005 0 0 0 0,-0.70704 l -0.18164,-0.18164 -3.81836,-3.81836 A 0.50005,0.50005 0 0 0 319.49219,315 Z M 319.5,316.20703 322.79297,319.5 319.5,322.79297 316.20703,319.5 Z M 311,319 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 0.5,4 c -0.12794,0 -0.25588,0.0489 -0.35352,0.14648 l -3,3 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.0957,0.0957 0.22603,0.14855 0.36133,0.14648 0.12989,-0.002 0.25387,-0.0546 0.34571,-0.14648 l 3,-3 c 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 C 313.75588,323.04889 313.62794,323 313.5,323 Z m 4.5,3 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z m 2,0 v 1 h 1 v -1 z"
- transform="rotate(180,333.00001,317.49999)"
- id="path28715"
- inkscape:connector-curvature="0" />
- </g>
</g>
<g
- style="display:inline;enable-background:new"
- id="g28909-7"
- transform="rotate(-180,535.5,631.5)">
+ transform="translate(-168,-294)"
+ id="g16054"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="B-9">
<path
- style="opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 7,654 v 8 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -8 h -1 v 8 H 8 v -8 z"
- transform="translate(540,1)"
- id="path28905-8"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="csssscccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 180.82031,32.001953 c -2.53256,0.0762 -4.74925,1.739751 -5.52929,4.150391 -0.66549,2.0566 -0.15791,4.2781 1.25,5.847656 H 176.25 a 0.50005,0.50005 0 0 0 -0.35352,0.146484 l -1.75,1.75 A 0.50005,0.50005 0 0 0 174,44.25 v 1.25 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -1.25 a 0.50005,0.50005 0 0 0 -0.14648,-0.353516 l -1.75,-1.75 A 0.50005,0.50005 0 0 0 185.75,42 h -0.29492 c 1.50007,-1.670137 1.96594,-4.059297 1.13281,-6.1875 -0.92362,-2.35937 -3.23501,-3.886777 -5.76758,-3.810547 z m 0.0332,1.099609 c 2.07177,-0.0624 3.95341,1.181239 4.70898,3.111329 0.75557,1.9301 0.2178,4.121692 -1.3457,5.482421 A 0.55028534,0.55028534 0 0 0 184.03906,42 H 183.5 a 0.50005,0.50005 0 1 0 0,1 h 2.04297 L 187,44.457031 V 45 H 175 V 44.457031 L 176.45703,43 H 180.5 a 0.50005,0.50005 0 1 0 0,-1 h -2.37695 a 0.55005501,0.55005501 0 0 0 -0.11133,-0.117188 c -1.64252,-1.264239 -2.31195,-3.418585 -1.67383,-5.390624 0.63812,-1.972051 2.44385,-3.328265 4.51563,-3.390626 z"
+ transform="translate(168,294)"
+ id="path16048"
+ inkscape:connector-curvature="0" />
<path
- sodipodi:nodetypes="cssssccccccccc"
- inkscape:connector-curvature="0"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 27,680 v 3 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -3 H 40 28 Z m 1,1 h 2 v 2 h -2 z"
- transform="matrix(1,0,0,-1,520,1334)"
- id="path28907-4" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 348.55469,328.69141 a 0.50005,0.50005 0 0 0 -0.0859,0.008 c -1.42662,0.22929 -2.54672,1.3539 -2.77148,2.78125 a 0.50012645,0.50012645 0 1 0 0.98828,0.1543 c 0.15806,-1.00378 0.94009,-1.78798 1.94336,-1.94922 a 0.50005,0.50005 0 0 0 -0.0742,-0.99414 z"
+ id="path16052"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;enable-background:new"
- transform="translate(-58,-51)"
- id="g28915-2">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13175"
+ inkscape:label="B-8">
<path
- sodipodi:nodetypes="csssscccccc"
- inkscape:connector-curvature="0"
- id="path28911-6"
- transform="translate(540,1)"
- d="m 7,654 v 8 c 0,0.54532 0.45468,1 1,1 h 12 c 0.54532,0 1,-0.45468 1,-1 v -8 h -1 v 8 H 8 v -8 z"
- style="opacity:0.6;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ id="path34600-2"
+ d="m 162.47852,32 c -0.75576,10e-7 -1.40256,0.282822 -1.83399,0.75 -0.30821,0.333747 -0.37373,0.80118 -0.46094,1.25 H 159.25 c -1.74879,0 -3.25,1.267585 -3.25,3 0,0.03444 0.0105,0.06555 0.0117,0.09961 C 156.33181,37.034347 156.66178,37 157,37 c 2.03325,0 3.79424,1.241664 4.57227,3 H 164.25 c 0.73055,0 1.4115,-0.231259 1.91992,-0.667969 C 166.67834,38.895322 167,38.242126 167,37.5 c 0,-1.192468 -0.94634,-2.062761 -2.04297,-2.306641 -0.002,-0.488483 0.0124,-1.101037 -0.24609,-1.74414 C 164.40699,32.693065 163.65613,32.000002 162.47852,32 Z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ inkscape:connector-curvature="0" />
<path
- sodipodi:nodetypes="ssccccsssccccc"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 157,38 c -2.20322,0 -4,1.796783 -4,4 0,2.203217 1.79678,4 4,4 2.20322,0 4,-1.796783 4,-4 0,-2.203217 -1.79678,-4 -4,-4 z m 0,1 c 1.66278,0 3,1.337223 3,3 0,1.662777 -1.33722,3 -3,3 -1.66278,0 -3,-1.337223 -3,-3 0,-1.662777 1.33722,-3 3,-3 z"
+ id="ellipse13733"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 154.5,32 c 0.8225,0 1.5,0.677496 1.5,1.5 0,0.822504 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.677496 -1.5,-1.5 0,-0.822504 0.6775,-1.5 1.5,-1.5 z"
+ id="ellipse12632-2"
inkscape:connector-curvature="0"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- d="m 8,670 c -0.54532,0 -1,0.45468 -1,1 v 3 h 1 12 1 v -3 c 0,-0.54532 -0.45468,-1 -1,-1 z m 0,1 h 2 v 2 H 8 Z"
- transform="translate(540,-20)"
- id="path28913-4" />
+ sodipodi:nodetypes="sssss" />
</g>
<g
- style="display:inline;opacity:1;fill:#ffffff;enable-background:new"
- id="g7388-6-3"
- transform="translate(457.49535,-616.1486)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g12105"
+ transform="translate(-147,-567)"
inkscape:export-filename="blender_icons.png"
inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
+ inkscape:export-ydpi="96"
+ inkscape:label="B-7">
<rect
- transform="scale(-1,1)"
- style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.79999995;marker:none;enable-background:accumulate"
- id="rect7384-9-6"
- width="16"
+ y="597.99994"
+ x="278"
height="16"
- x="437"
- y="710" />
+ width="16"
+ id="rect12101"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0;fill:#ffffff;stroke:none;stroke-width:3;marker:none;enable-background:accumulate" />
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -447.96289,710.98828 a 1.0001,1.0001 0 0 0 -0.83789,0.41211 c -3.30626,4.40835 -3.18183,10.96743 -3.18555,12.58399 a 1.0001,1.0001 0 1 0 2,0.006 c 0.004,-1.64212 0.0934,-7.79897 2.78711,-11.39062 a 1.0001,1.0001 0 0 0 -0.76367,-1.61133 z m 4.97461,3.00195 a 1.0001,1.0001 0 0 0 -0.69727,0.28125 c -2.25424,2.12239 -3.3739,3.98924 -3.89062,5.64258 C -448.0929,721.56741 -448,722.96385 -448,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-1.13631 -0.0696,-2.20308 0.33203,-3.48828 0.40167,-1.28521 1.28135,-2.83224 3.35352,-4.7832 a 1.0001,1.0001 0 0 0 -0.67383,-1.73829 z m 3.94531,4.00782 a 1.0001,1.0001 0 0 0 -0.16797,0.0234 C -441.66808,718.54973 -444,720.82862 -444,724 a 1.0001,1.0001 0 1 0 2,0 c 0,-2.17354 1.66808,-3.68979 3.21094,-4.02148 a 1.0001,1.0001 0 0 0 -0.25391,-1.98047 z"
- id="path7133-7-7"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 286,599 c -3.8542,0 -7,3.1458 -7,7 0,3.8542 3.1458,7 7,7 3.8542,0 7,-3.1458 7,-7 0,-3.8542 -3.1458,-7 -7,-7 z m 0,2 c 2.77332,0 5,2.22668 5,5 0,2.77332 -2.22668,5 -5,5 -2.77332,0 -5,-2.22668 -5,-5 0,-2.77332 2.22668,-5 5,-5 z"
+ id="path12103"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 30.560537,94.85135 a 0.50005,0.50005 0 0 0 -0.41797,0.20312 c -2.41605,3.180716 -3.44475,6.00321 -3.85742,8.28711 -0.41267,2.2839 -0.21655,4.04989 -0.21875,5.00586 a 0.50005,0.50005 0 1 0 1,0.004 c 0.002,-1.08433 -0.18375,-2.69094 0.20312,-4.83203 0.38687,-2.1411 1.34101,-4.795944 3.66797,-7.85938 a 0.50005,0.50005 0 0 0 -0.37695,-0.80858 z m 4.95508,3.001946 a 0.50005,0.50005 0 0 0 -0.30469,0.12695 c -4.12358,3.585044 -5.17188,7.536354 -5.17188,10.376954 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.60021 0.91362,-6.21978 4.82813,-9.623044 a 0.50005,0.50005 0 0 0 -0.35156,-0.88086 z m 4.02539,5.003904 c -3.01703,-0.006 -5.49429,2.47075 -5.50196,5.49805 a 0.50005,0.50005 0 1 0 1,0.004 c 0.006,-2.48438 2.031,-4.50726 4.50001,-4.50195 a 0.50005,0.50005 0 1 0 0.002,-1 z"
- id="path18476-0-2-5"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 52.942267,94.61165 a 0.50005,0.50005 0 0 0 -0.41797,0.20312 c -2.41605,3.180716 -3.44475,6.00321 -3.85743,8.28711 -0.41267,2.2839 -0.21654,4.04989 -0.21875,5.00586 a 0.50005,0.50005 0 1 0 1,0.004 c 0.002,-1.08433 -0.18374,-2.69094 0.20313,-4.83203 0.38687,-2.1411 1.341,-4.795944 3.66797,-7.85938 a 0.50005,0.50005 0 0 0 -0.37695,-0.80858 z m 4.95507,3.00195 a 0.50005,0.50005 0 0 0 -0.30468,0.12695 c -4.12359,3.58504 -5.17188,7.53635 -5.17188,10.37695 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.60021 0.91362,-6.21978 4.82813,-9.623044 A 0.50005,0.50005 0 0 0 57.897337,97.6136 Z m 4.02539,5.0039 c -3.01703,-0.006 -5.49428,2.47075 -5.50195,5.49805 a 0.50005,0.50005 0 1 0 1,0.004 c 0.006,-2.48438 2.03099,-4.50726 4.5,-4.50195 a 0.50005,0.50005 0 1 0 0.002,-1 z"
- id="path18476-0-2-5-3"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 139.512,94.8218 c -0.39468,0.0302 -0.78775,0.12022 -1.16797,0.27148 -1.52086,0.60507 -2.52148,2.07999 -2.52148,3.716796 -7.6e-4,0.0448 0.004,0.0894 0.0156,0.13281 -0.36519,0.0927 -0.72282,0.22834 -1.0586,0.42774 -1.44139,0.855954 -2.17088,2.516884 -1.8789,4.144534 -0.68715,0.57705 -1.10816,1.44799 -1.07617,2.39648 0.0502,1.48769 1.19214,2.71921 2.67187,2.88086 1.39818,0.15274 2.69975,-0.69789 3.15234,-2.00781 0.89605,0.0388 1.7697,-0.22225 2.49805,-0.74609 1.07373,0.85551 2.55788,1.01607 3.78907,0.37695 1.3017,-0.67573 2.04373,-2.09602 1.85741,-3.55078 -0.16328,-1.27499 -1.01005,-2.34261 -2.17967,-2.80664 0.45466,-1.382424 0.13144,-2.9211 -0.88477,-3.9961 -0.56221,-0.59473 -1.27728,-0.98709 -2.04298,-1.15625 -0.38285,-0.0846 -0.77914,-0.11418 -1.17382,-0.084 z"
- id="path21574-1"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccsccccccccc" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 160.47797,94.72823 c -0.39468,0.0302 -0.78775,0.12022 -1.16797,0.27148 -1.52086,0.60507 -2.52148,2.07999 -2.52148,3.716796 a 0.50005,0.50005 0 0 0 0.0156,0.13281 c -0.36518,0.0927 -0.72282,0.22834 -1.05859,0.42774 -1.4414,0.855954 -2.17089,2.516884 -1.87891,4.144534 -0.68714,0.57705 -1.10816,1.44799 -1.07617,2.39648 0.0502,1.48769 1.19214,2.71921 2.67187,2.88086 1.39818,0.15274 2.69975,-0.69789 3.15235,-2.00781 0.89604,0.0388 1.76969,-0.22225 2.49804,-0.74609 1.07373,0.85551 2.55788,1.01607 3.78907,0.37695 1.30171,-0.67573 2.04374,-2.09602 1.85742,-3.55078 -0.16328,-1.27499 -1.01006,-2.34261 -2.17968,-2.806644 0.45466,-1.38242 0.13144,-2.921096 -0.88477,-3.996096 -0.56221,-0.59473 -1.27727,-0.98709 -2.04297,-1.15625 -0.38285,-0.0846 -0.77915,-0.11418 -1.17383,-0.084 z m 0.52149,0.99609 c 0.73445,0.0517 1.44053,0.37287 1.96875,0.93164 0.84514,0.89404 1.0593,2.208446 0.54101,3.324216 a 0.50005,0.50005 0 0 0 -0.0527,0.216804 0.50005,0.50005 0 0 0 0.38672,0.58203 c 1.02426,0.23341 1.79232,1.07713 1.92578,2.11914 0.13345,1.04201 -0.39575,2.0531 -1.32813,2.53711 -0.93238,0.48401 -2.06444,0.33572 -2.83984,-0.37305 a 0.50005,0.50005 0 0 0 -0.20313,-0.11914 0.50005,0.50005 0 0 0 -0.28125,-0.0977 0.50005,0.50005 0 0 0 -0.35156,0.1289 c -0.65771,0.57559 -1.53314,0.83597 -2.39844,0.71289 a 0.50008765,0.50008765 0 0 0 -0.54296,0.33008 0.50005,0.50005 0 0 0 -0.0977,0.19727 c -0.24833,0.96717 -1.16166,1.59867 -2.1543,1.49023 -0.99264,-0.10844 -1.7476,-0.92195 -1.78125,-1.91992 -0.0231,-0.68418 0.30371,-1.29829 0.82422,-1.67774 a 0.50005,0.50005 0 0 0 0.16601,-0.11718 c 0.19833,-0.11547 0.41799,-0.19976 0.65625,-0.24219 a 0.50005,0.50005 0 0 0 -0.0898,-0.99414 0.50005,0.50005 0 0 0 -0.084,0.01 c -0.16025,0.0285 -0.31331,0.0746 -0.46289,0.12695 -0.0646,-1.10299 0.47775,-2.17237 1.45703,-2.75391 1.15771,-0.687484 2.62445,-0.520214 3.59961,0.4082 a 0.50010005,0.50010005 0 0 0 0.68946,-0.724604 c -0.64816,-0.6171 -1.46288,-0.98259 -2.3086,-1.07813 -0.14875,-0.017 -0.29935,-0.0157 -0.44925,-0.0158 a 0.50005,0.50005 0 0 0 0,-0.01 c 0,-1.230266 0.7475,-2.332316 1.89062,-2.787106 0.42868,-0.17055 0.87964,-0.23611 1.32032,-0.20508 z"
- id="path21574-1-2"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 181.13795,94.59407 c -0.39468,0.0302 -0.78775,0.12022 -1.16797,0.27148 -1.52086,0.60507 -2.52148,2.07999 -2.52148,3.716796 a 0.50005,0.50005 0 0 0 0.0156,0.13281 c -0.36519,0.0927 -0.72282,0.22834 -1.0586,0.42774 -1.44139,0.85595 -2.17088,2.516884 -1.8789,4.144534 -0.68715,0.57705 -1.10816,1.44799 -1.07617,2.39648 0.0502,1.48769 1.19214,2.71921 2.67187,2.88086 1.39818,0.15274 2.69975,-0.69789 3.15234,-2.00781 0.89605,0.0388 1.7697,-0.22225 2.49805,-0.74609 1.07373,0.85551 2.55787,1.01607 3.78906,0.37695 1.30171,-0.67573 2.04374,-2.09602 1.85742,-3.55078 -0.16328,-1.27499 -1.01006,-2.34261 -2.17968,-2.806644 0.45466,-1.38242 0.13144,-2.921096 -0.88477,-3.996096 -0.56221,-0.59473 -1.27727,-0.98709 -2.04297,-1.15625 -0.38285,-0.0846 -0.77914,-0.11418 -1.17382,-0.084 z m 0.52149,0.99609 c 0.73445,0.0517 1.44053,0.37287 1.96874,0.93164 0.84514,0.89404 1.0593,2.208446 0.54101,3.324216 a 0.50005,0.50005 0 0 0 -0.0527,0.216804 0.50005,0.50005 0 0 0 0.38672,0.58203 c 1.02426,0.23341 1.79232,1.07713 1.92578,2.11914 0.13345,1.04201 -0.39575,2.0531 -1.32813,2.53711 -0.93238,0.48401 -2.06443,0.33572 -2.83983,-0.37305 a 0.50005,0.50005 0 0 0 -0.20313,-0.11914 0.50005,0.50005 0 0 0 -0.28125,-0.0977 0.50005,0.50005 0 0 0 -0.35156,0.1289 c -0.65771,0.57559 -1.53314,0.83597 -2.39844,0.71289 a 0.50008765,0.50008765 0 0 0 -0.54297,0.33008 0.50005,0.50005 0 0 0 -0.0977,0.19727 c -0.24832,0.96717 -1.16166,1.59867 -2.15429,1.49023 -0.99264,-0.10844 -1.7476,-0.92195 -1.78125,-1.91992 -0.0231,-0.68418 0.30371,-1.29829 0.82422,-1.67774 a 0.50005,0.50005 0 0 0 0.16601,-0.11718 c 0.19833,-0.11547 0.41799,-0.19976 0.65625,-0.24219 a 0.50005,0.50005 0 0 0 -0.0898,-0.99414 0.50005,0.50005 0 0 0 -0.084,0.01 c -0.16025,0.0285 -0.31331,0.0746 -0.46289,0.12695 -0.0646,-1.10299 0.47775,-2.17237 1.45703,-2.75391 1.15771,-0.687484 2.62445,-0.520214 3.59961,0.4082 a 0.50009764,0.50009764 0 0 0 0.68945,-0.724604 c -0.64816,-0.6171 -1.46287,-0.98259 -2.30859,-1.07813 -0.14875,-0.017 -0.29936,-0.0157 -0.44925,-0.0158 a 0.50005,0.50005 0 0 0 0,-0.01 c 0,-1.230266 0.7475,-2.332316 1.89062,-2.787106 0.42867,-0.17055 0.87964,-0.23611 1.32032,-0.20508 z"
- id="path21574-1-2-7"
- inkscape:connector-curvature="0" />
<g
- transform="translate(-0.38934274,-189.0602)"
+ id="g49137"
style="display:inline;enable-background:new"
- id="g4912">
+ inkscape:label="B-6">
<path
- inkscape:connector-curvature="0"
- id="circle14295-0"
- d="m 92.893099,283.6795 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ d="m 115,32 v 2 h 6 v -2 z m 6,2 v 2 h 2 v -2 z m 2,2 v 6 h 2 v -6 z m 0,6 h -2 v 2 h 2 z m -2,2 h -6 v 2 h 6 z m -6,0 v -2 h -2 v 2 z m -2,-2 v -6 h -2 v 6 z m 0,-6 h 2 v -2 h -2 z"
+ id="rect23113-8"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g49140"
+ style="display:inline;enable-background:new"
+ inkscape:label="B-5">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 94.513672,32 a 0.50005,0.50005 0 0 0 -0.417969,0.203125 c -2.416051,3.180716 -3.444751,6.003207 -3.857422,8.287109 -0.412671,2.283903 -0.216543,4.049887 -0.21875,5.00586 a 0.50005,0.50005 0 1 0 1,0.0039 c 0.0025,-1.084327 -0.183742,-2.690936 0.203125,-4.832031 0.386868,-2.141095 1.341004,-4.795942 3.667969,-7.859375 A 0.50005,0.50005 0 0 0 94.513672,32 Z m 4.955078,3.001953 a 0.50005,0.50005 0 0 0 -0.304688,0.126953 c -4.123582,3.585034 -5.171874,7.536346 -5.171874,10.376953 a 0.50005,0.50005 0 1 0 1,0 c 0,-2.600212 0.913619,-6.219783 4.828124,-9.623047 A 0.50005,0.50005 0 0 0 99.46875,35.001953 Z m 4.02539,5.003906 c -3.01703,-0.0065 -5.494281,2.470749 -5.501952,5.498047 a 0.50005,0.50005 0 1 0 1,0.0039 c 0.0063,-2.484383 2.030992,-4.507263 4.500002,-4.501953 a 0.50005,0.50005 0 1 0 0.002,-1 z"
+ id="path18476-0-2"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g6391"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="B-4">
<path
inkscape:connector-curvature="0"
- id="circle14295-0-3"
- d="m 101.62043,287.72696 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65092,0 -2.999992,-1.34907 -2.999992,-3 0,-1.65093 1.349072,-3 2.999992,-3 z m 0,1 c -1.11049,0 -1.999992,0.88951 -1.999992,2 0,1.11049 0.889502,2 1.999992,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path13580-7"
+ d="m 72.5,32 a 0.50004997,0.50004997 0 0 0 -0.330078,0.123047 l -2,1.75 A 0.50004997,0.50004997 0 0 0 70,34.25 V 36 H 68.5 A 0.50004997,0.50004997 0 0 0 68,36.5 V 38 c 0,0.986111 0.740543,1.688903 1.568359,1.919922 0.715248,0.199604 1.51421,0.04822 2.183594,-0.384766 L 73,40.939453 V 43.25 c 0,0.888889 0.394191,1.618478 0.96875,2.078125 C 74.543309,45.787772 75.275,46 76,46 76.725,46 77.456691,45.787772 78.03125,45.328125 78.605809,44.868478 79,44.138889 79,43.25 v -2.310547 l 1.248047,-1.404297 c 0.669384,0.432987 1.468346,0.58437 2.183594,0.384766 C 83.259457,39.688903 84,38.986111 84,38 V 36.5 A 0.50004997,0.50004997 0 0 0 83.5,36 H 82 v -1.75 a 0.50004997,0.50004997 0 0 0 -0.169922,-0.376953 l -2,-1.75 A 0.50004997,0.50004997 0 0 0 79.5,32 h -2 a 0.50004997,0.50004997 0 0 0 -0.353516,0.146484 L 76.292969,33 H 75.707031 L 74.853516,32.146484 A 0.50004997,0.50004997 0 0 0 74.5,32 Z m 0.1875,1 h 1.605469 l 0.853515,0.853516 A 0.50004997,0.50004997 0 0 0 75.5,34 h 1 a 0.50004997,0.50004997 0 0 0 0.353516,-0.146484 L 77.707031,33 H 79.3125 L 81,34.478516 V 36.5 A 0.50004997,0.50004997 0 0 0 81.5,37 H 83 v 1 c 0,0.513889 -0.321957,0.811097 -0.837891,0.955078 -0.394082,0.109977 -0.821203,-0.06293 -1.207031,-0.25 a 0.50004997,0.50004997 0 0 0 -0.828125,-0.537109 l -2,2.25 A 0.50004997,0.50004997 0 0 0 78,40.75 v 2.5 c 0,0.611111 -0.230809,1.006522 -0.59375,1.296875 C 77.043309,44.837228 76.525,45 76,45 75.475,45 74.956691,44.837228 74.59375,44.546875 74.230809,44.256522 74,43.861111 74,43.25 v -2.5 a 0.50004997,0.50004997 0 0 0 -0.126953,-0.332031 l -2,-2.25 a 0.50004997,0.50004997 0 0 0 -0.828125,0.537109 c -0.385828,0.187069 -0.812949,0.359977 -1.207031,0.25 C 69.321957,38.811097 69,38.513889 69,38 v -1 h 1.5 A 0.50004997,0.50004997 0 0 0 71,36.5 v -2.023438 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
<path
inkscape:connector-curvature="0"
- id="circle14295-0-3-0"
- d="m 94.284412,291.52146 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -2.999998,-1.34907 -2.999998,-3 0,-1.65093 1.349068,-3 2.999998,-3 z m 0,1 c -1.11049,0 -1.999998,0.88951 -1.999998,2 0,1.11049 0.889508,2 1.999998,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path13586"
+ d="m 74,35 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -0.5,0.5 A 0.50005,0.50005 0 0 0 73,36 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 36.207031 L 74.207031,36 H 74.5 a 0.50005,0.50005 0 1 0 0,-1 z m 4,0 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -0.5,0.5 A 0.50005,0.50005 0 0 0 77,36 v 0.5 a 0.50005,0.50005 0 1 0 1,0 V 36.207031 L 78.207031,36 H 78.5 a 0.50005,0.50005 0 1 0 0,-1 z m -2.5,3 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
</g>
<g
- transform="translate(-0.38934274,-189.0602)"
- style="display:inline;enable-background:new"
- id="g4907">
+ id="g6383"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="B-3">
<path
- sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- id="circle13367-9"
- d="m 71.893099,283.6795 c 1.650931,0 3.000001,1.34907 3.000001,3 0,1.65093 -1.34907,3 -3.000001,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path12123-3"
+ d="m 51.5,32 a 0.50005,0.50005 0 0 0 -0.353516,0.146484 l -3,3 A 0.50005,0.50005 0 0 0 48,35.5 v 10 a 0.50005,0.50005 0 0 0 0.5,0.5 h 10 a 0.50005,0.50005 0 0 0 0.353516,-0.146484 l 3,-3 A 0.50005,0.50005 0 0 0 62,42.5 v -10 A 0.50005,0.50005 0 0 0 61.5,32 Z m 0.207031,1 H 61 v 9.292969 L 58.292969,45 H 49 v -9.292969 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
- sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- id="circle13367-9-6"
- d="m 80.620438,287.72696 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path12125-1"
+ d="m 60.490234,32.988281 a 0.50005,0.50005 0 0 0 -0.34375,0.152344 L 58.292969,35 H 50.5 a 0.50005,0.50005 0 1 0 0,1 H 58 v 7.5 a 0.50005,0.50005 0 1 0 1,0 v -7.792969 l 1.853516,-1.861328 a 0.50005,0.50005 0 0 0 -0.363282,-0.857422 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <g
+ id="g6375"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="B-2">
<path
- sodipodi:nodetypes="sssss"
inkscape:connector-curvature="0"
- id="circle13367-9-6-6"
- d="m 73.284414,291.52146 c 1.650931,0 3.000001,1.34907 3.000001,3 0,1.65093 -1.34907,3 -3.000001,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path12109-5"
+ d="m 34,32 c -3.860074,0 -7,3.139926 -7,7 0,3.860083 3.139927,7 7,7 3.860082,0 7,-3.139918 7,-7 0,-3.860073 -3.139917,-7 -7,-7 z m 0,1 c 3.319643,0 6,2.680365 6,6 0,3.319644 -2.680356,6 -6,6 -3.319635,0 -6,-2.680357 -6,-6 0,-3.319634 2.680366,-6 6,-6 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path12115-8"
+ d="M 28.507812,38.244141 A 0.50005,0.50005 0 0 0 28.15625,39.101562 C 29.521925,40.47768 30.901684,41.000009 32.5,41 H 34 c 2.575017,3.52e-4 3.847654,-0.615233 4.722656,-1.052734 A 0.50005,0.50005 0 1 0 38.277344,39.052734 C 37.402346,39.490233 36.424977,40.000332 34,40 h -1.5 c -1.401674,7e-6 -2.403186,-0.362534 -3.632812,-1.601562 a 0.50005,0.50005 0 0 0 -0.359376,-0.154297 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(-0.38934274,-189.0602)"
+ id="g49134"
style="display:inline;enable-background:new"
- id="g4917">
+ inkscape:label="B-1">
<path
- inkscape:connector-curvature="0"
- id="circle14295-0-2"
- d="m 114.20361,283.80598 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 6.5,32 A 0.50005,0.50005 0 0 0 6,32.5 v 13 A 0.50005,0.50005 0 0 0 6.5,46 h 13 A 0.50005,0.50005 0 0 0 20,45.5 v -13 A 0.50005,0.50005 0 0 0 19.5,32 Z M 7,33 H 19 V 45 H 7 Z"
+ id="rect12121"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g30732"
+ inkscape:label="A-26">
+ <path
+ id="path15447"
+ d="m 539.5,10.000005 c -3.5682,0 -6.5,2.931819 -6.5,6.499999 0,1.42599 0.4737,2.74606 1.2637,3.822271 l -3.9707,3.9707 a 1.0001,1.0001 0 1 0 1.414,1.41406 l 3.9707,-3.9707 c 1.0762,0.78998 2.3963,1.26367 3.8223,1.26367 3.5682,0 6.5,-2.93182 6.5,-6.500001 0,-3.56818 -2.9318,-6.499999 -6.5,-6.499999 z m 0,2.999999 c 0.051,0 0.098,0.0135 0.1484,0.0156 a 0.50005,0.50005 0 0 1 0.3516,0.4844 v 2.5 h 2.5 a 0.50005,0.50005 0 0 1 0.4863,0.35742 0.50005,0.50005 0 0 1 0,0.002 c 0,0.0477 0.014,0.0925 0.014,0.14062 0,0.0488 -0.012,0.0942 -0.014,0.14258 A 0.50005,0.50005 0 0 1 542.5,17.000004 H 540 v 2.5 a 0.50005,0.50005 0 0 1 -0.3574,0.486331 c -0.048,0.002 -0.092,0.0137 -0.1406,0.0137 -0.049,0 -0.094,-0.0117 -0.1426,-0.0137 A 0.50005,0.50005 0 0 1 539,19.500004 v -2.5 h -2.5 a 0.50005,0.50005 0 0 1 -0.4863,-0.35742 0.50005,0.50005 0 0 1 0,-0.002 c 0,-0.0476 -0.014,-0.0925 -0.014,-0.14062 0,-0.0488 0.012,-0.0942 0.014,-0.14258 a 0.50005,0.50005 0 0 1 0.4863,-0.35738 h 2.5 v -2.5 a 0.50005,0.50005 0 0 1 0.3516,-0.48438 c 0.05,-0.002 0.098,-0.0156 0.1484,-0.0156 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:7.17647;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g30744"
+ inkscape:label="A-25">
<path
+ sodipodi:nodetypes="cccccccccccccccscccccccccccccc"
inkscape:connector-curvature="0"
- id="circle14295-0-3-0-1"
- d="m 115.59493,291.64794 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path22769"
+ d="m 517.98438,9.9863345 c -0.55152,0.009 -0.99193,0.4621405 -0.98438,1.0136695 v 7 h -1.10156 l -0.91016,-6.14648 c -0.0643,-0.48249 -0.46671,-0.84859 -0.95312,-0.86719 -0.63083,-0.0229 -1.12488,0.53711 -1.02344,1.16015 L 514,18.816414 v 0.88671 1.296881 h -1 v -1.746091 l -2.58984,-1.16602 c -0.12175,-0.0548 -0.25324,-0.0847 -0.38672,-0.0879 -0.88449,-0.0197 -1.35703,1.03438 -0.75391,1.68164 l 3.5,3.750001 c 1.45044,1.55404 3.38812,2.64316 5.12305,2.55469 2.20226,-0.16055 4.09501,-1.6226 4.80664,-3.71289 l 2.25586,-6.269531 c 0.1808,-0.48082 -0.16432,-0.99701 -0.67774,-1.01368 -0.32862,-0.0101 -0.62553,0.19494 -0.73242,0.50586 l -0.90039,2.50392 h -0.74023 l 1.07812,-5.81836 c 0.12593,-0.63116 -0.36843,-1.215229 -1.01172,-1.19531 -0.47506,0.0156 -0.8735,0.36343 -0.95312,0.83203 l -1.14453,6.18164 H 519 v -7 c 0.008,-0.563769 -0.45189,-1.0224695 -1.01562,-1.0136695 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new" />
+ </g>
+ <g
+ id="g30741"
+ inkscape:label="A-24">
<path
+ sodipodi:nodetypes="scssssssssssssssssssssssssssssccccccccccccscssssssscccccccc"
inkscape:connector-curvature="0"
- id="circle14295-0-3-6"
- d="m 122.93095,287.85344 c 1.65093,0 3,1.34907 3,3 0,1.65093 -1.34907,3 -3,3 -1.65093,0 -3,-1.34907 -3,-3 0,-1.65093 1.34907,-3 3,-3 z m 0,1 c -1.11049,0 -2,0.88951 -2,2 0,1.11049 0.88951,2 2,2 1.11049,0 2,-0.88951 2,-2 0,-1.11049 -0.88951,-2 -2,-2 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ id="path15245-5-5"
+ d="m 498.5,10 c -2.1397,0 -3.80728,1.4725 -4.33008,3.2441 C 493.52022,12.4964 492.6594,12 491.5,12 c -1.9271,0 -3.5,1.5729 -3.5,3.5 0,1.927 1.5729,3.5 3.5,3.5 h 7 c 2.4794,0 4.5,-2.0207 4.5,-4.5 0,-2.4794 -2.0206,-4.5 -4.5,-4.5 z m 0,3 c 0.8225,0 1.5,0.6774 1.5,1.5 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8226 0.6775,-1.5 1.5,-1.5 z m -7,1 c 0.8225,0 1.5,0.6774 1.5,1.5 0,0.8225 -0.6775,1.5 -1.5,1.5 -0.8225,0 -1.5,-0.6775 -1.5,-1.5 0,-0.8226 0.6775,-1.5 1.5,-1.5 z m 7,0 c -0.2821,0 -0.5,0.2179 -0.5,0.5 0,0.282 0.2179,0.5 0.5,0.5 0.2821,0 0.5,-0.218 0.5,-0.5 0,-0.2821 -0.2179,-0.5 -0.5,-0.5 z m -7,1 c -0.2821,0 -0.5,0.2179 -0.5,0.5 0,0.282 0.2179,0.5 0.5,0.5 0.2821,0 0.5,-0.218 0.5,-0.5 0,-0.2821 -0.2179,-0.5 -0.5,-0.5 z m 1,5 c -0.2761,0 -0.5,0.2239 -0.5,0.5 v 1 0.5 h -1 v -0.5 c 0.004,-0.2823 -0.22555,-0.5122 -0.50781,-0.5078 -0.27615,0 -0.49651,0.2316 -0.49219,0.5078 v 1 1 c 0.009,0.6573 0.9907,0.6573 1,0 V 23 h 1 v 0.5 1 c 0,0.1326 0.053,0.2597 0.14648,0.3535 l 1,1 C 493.24048,25.9475 493.3674,26 493.5,26 h 5 c 0.2761,0 0.5,-0.2239 0.5,-0.5 v -5 c 0,-0.2761 -0.2239,-0.5 -0.5,-0.5 z m 10.98438,1 c -0.0871,0 -0.17191,0.028 -0.2461,0.074 l -3.25,2 c -0.31714,0.1953 -0.31714,0.6563 0,0.8516 l 3.25,2 c 0.33298,0.2045 0.76131,-0.035 0.76172,-0.4258 v -4 c 1.1e-4,-0.2823 -0.23341,-0.5088 -0.51562,-0.5 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;enable-background:new" />
</g>
<g
- id="g25642"
- transform="translate(-63,-20)"
- style="display:inline;fill:#ffffff;fill-opacity:1;enable-background:new">
+ id="g30735"
+ inkscape:label="A-23">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 467.5,10.000005 a 0.50005006,0.50005006 0 0 0 -0.5,0.5 v 15 a 0.50005006,0.50005006 0 0 0 0.5,0.5 h 15 a 0.50005006,0.50005006 0 0 0 0.5,-0.5 v -15 a 0.50005006,0.50005006 0 0 0 -0.5,-0.5 z m 0.5,0.999999 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m -10,5 h 4 v 4.000001 h -4 z m 5,0 h 4 v 4.000001 h -4 z m 5,0 h 4 v 4.000001 h -4 z m -10,5.000001 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z m 5,0 h 4 v 4 h -4 z"
+ id="rect15343"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g30738"
+ inkscape:label="A-22">
<path
inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m -33.5,1328 c -0.27613,0 -0.49997,0.2239 -0.5,0.5 v 11 c 3e-5,0.2761 0.22387,0.5 0.5,0.5 h 2.5 v -3 c 0,-1.645 1.35499,-3 3,-3 h 2.585938 l -1.292969,-1.293 a 1.0001,1.0001 0 0 1 0.726562,-1.7168 1.0001,1.0001 0 0 1 0.6875,0.3028 l 3,3 a 1.0001,1.0001 0 0 1 0,1.414 l -3,3 a 1.0001,1.0001 0 1 1 -1.414062,-1.414 L -25.414062,1336 H -28 c -0.56413,0 -1,0.4359 -1,1 v 3 h 8.5 c 0.27613,0 0.49997,-0.2239 0.5,-0.5 v -9 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 H -29 v -1.5 c -3e-5,-0.2761 -0.22387,-0.5 -0.5,-0.5 z"
- transform="translate(397,-1232)"
- id="path25640" />
+ id="path15369"
+ d="m 449.75,12.000004 a 0.50005006,0.50005006 0 0 0 -0.4824,0.36914 l -3.25,12.000001 a 0.50005006,0.50005006 0 0 0 0.4824,0.63086 h 15 a 0.50005006,0.50005006 0 0 0 0.4824,-0.63086 l -3.25,-12.000001 a 0.50005006,0.50005006 0 0 0 -0.4824,-0.36914 z m 0.3828,1 h 2.086 l -0.2169,2 h -2.4121 z m 3.0938,0 h 1.5468 l 0.2168,2 h -1.9804 z m 2.5547,0 h 2.0859 l 0.541,2 h -2.4101 z m -6.461,3 h 2.5723 l -0.3262,3 h -3.0586 z m 3.5801,0 h 2.1992 l 0.3262,3 h -2.8516 z m 3.207,0 h 2.5723 l 0.8125,3 h -3.0586 z m -7.8711,4.000001 h 3.2207 l -0.4336,4 h -3.8711 z m 4.2305,0 h 3.0664 l 0.4356,4 h -3.9375 z m 4.0762,0 h 3.2207 l 1.084,4 h -3.8711 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.5;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
- transform="translate(712,-665)"
- style="display:inline;enable-background:new"
- id="g25686">
+ transform="matrix(-1,0,0,1,-135.99001,-1337)"
+ id="g25915-9"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="A-18">
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ d="m -503.5,1348.5 h -2 v 2 h 2 z"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ id="path25851-1" />
+ <path
+ sodipodi:nodetypes="csc"
+ inkscape:connector-curvature="0"
+ id="path25853-8"
+ d="m -498.49506,1361.4978 -2.00459,-2.0055 c -2.16266,-2.1636 -3.0003,-5.1361 -3.0003,-7.9852 l 0.01,-1.0071"
+ style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal" />
+ <path
+ style="opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
+ d="m -511.5049,1361.4907 c 0,-2.8491 0.8375,-5.8217 3.0003,-7.9852 L -505.5,1350.5"
+ id="path25855-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="csc" />
<g
- transform="rotate(-180,-177.49644,1250.0035)"
- id="g25671">
+ id="g25861-1"
+ transform="translate(-47,-2)">
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path25857-8"
+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="m -457.50994,1358.5 h -2 v 2 h 2 z"
+ inkscape:connector-curvature="0" />
<path
+ id="path25859-9"
+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
+ d="m -458.5,1358 v -3"
inkscape:connector-curvature="0"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -242.00195,1242.9922 c -0.58284,0 -1.10871,0.154 -1.47657,0.5215 -0.36785,0.3675 -0.52148,0.8952 -0.52148,1.4785 V 1248 h 6 v -2.4863 c -0.002,-0.3369 0.17839,-0.7279 0.47461,-1.0254 0.29622,-0.2975 0.68988,-0.4819 1.0293,-0.4844 0.65765,-0.012 0.6539,-0.9937 -0.004,-1 h -0.004 L -239,1243 v 0.4863 c 0.01,0.6762 -1.00956,0.6762 -1,0 v -0.4883 h -1 v 0.4903 c 0.01,0.6762 -1.00956,0.6762 -1,0 v -0.4922 h -0.002 z M -244,1249 v 0.5 c 0,0.2521 0.16407,0.4981 0.5,0.4863 l 1.50195,0.01 -0.002,5.9941 c -0.0191,1.3523 2.01913,1.3523 2,0 l -0.002,-5.9941 1.50195,-0.01 c 0.32137,0 0.5,-0.2464 0.5,-0.4863 v -0.5 z"
- transform="rotate(180,-208.99644,1250.0035)"
- id="path25652" />
- <g
- transform="matrix(1,0,0,-1,-61.992879,2500.0212)"
- id="g25669">
- <g
- id="g25662"
- transform="translate(-17)">
- <g
- transform="translate(-2,-2)"
- id="g25660" />
- </g>
- </g>
+ sodipodi:nodetypes="cc" />
</g>
<g
- id="g25684"
- transform="matrix(1,0,0,-1,0,2500.0142)">
+ transform="rotate(90,-479.5,1328.5)"
+ id="g25873-3">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m -232,1242.9863 c -0.50478,0 -1.00956,0.3375 -1,1.0137 v 7 h 2 v -7 c 0.01,-0.6762 -0.49522,-1.0137 -1,-1.0137 z m 0,9.0274 c -1.09865,0 -2,0.9013 -2,2 0,0.8274 -0.13264,1.3367 -0.33203,1.5937 -0.1994,0.257 -0.49978,0.3926 -1.16797,0.3926 -0.11793,0 -0.23139,0.046 -0.32031,0.123 -0.0251,0.022 -0.048,0.046 -0.0684,0.072 -0.0409,0.053 -0.0708,0.1132 -0.0879,0.1777 -0.004,0.016 -0.007,0.033 -0.01,0.049 -0.003,0.017 -0.005,0.034 -0.006,0.051 -0.002,0.033 -7.6e-4,0.067 0.004,0.1 0.005,0.033 0.0138,0.065 0.0254,0.096 0.0107,0.031 0.0244,0.061 0.041,0.09 0.009,0.015 0.0188,0.029 0.0293,0.043 0.0403,0.053 0.0907,0.098 0.14844,0.1308 0.0742,0.043 0.15827,0.067 0.24414,0.068 2.01924,0 3.30957,-0.2641 4.16992,-0.7461 0.85624,-0.4797 1.23067,-1.2322 1.30078,-1.918 0.0175,-0.1066 0.0293,-0.2142 0.0293,-0.3222 0,-1.0987 -0.90135,-2 -2,-2 z"
- transform="matrix(1,0,0,-1,62.999999,2500.0142)"
- id="path25673"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="sccccssscscccccccccccccss" />
- <g
- transform="matrix(-1,0,0,1,-263.99995,0)"
- id="g25682" />
+ d="m -457.50994,1359.5 h -2 v 2 h 2 z"
+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="path25869-0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ inkscape:connector-curvature="0"
+ d="m -458.5,1359 v -3"
+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
+ id="path25871-3" />
</g>
</g>
<g
- transform="translate(-1602.05,188)"
- style="display:inline;enable-background:new"
- id="g26614">
+ transform="matrix(1,0,0,-1,812,1351.9941)"
+ id="g25919-9"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="A-17">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.7;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 1796.5,348 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 5.5 h 1 v -5 h 2 v -1 z m 7.5,0 v 1 h 7 v 5 h 1 v -5.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m -8,11 v 2.5 a 0.50005,0.50005 0 0 0 0.5,0.5 h 2.5 v -1 h -2 v -2 z m 15,0 v 2 h -7 v 1 h 7.5 a 0.50005,0.50005 0 0 0 0.5,-0.5 V 359 Z"
- id="path33581"
+ sodipodi:nodetypes="ccccc"
+ id="path25812-9"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
+ d="m -464.5,1340.5001 v -2 h 2 v 2 z"
inkscape:connector-curvature="0" />
<path
- sodipodi:nodetypes="cccccccccc"
- id="path33583"
- style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;enable-background:new"
- d="m 1800,348 h 3 v 14 h -3 z m -4,7 h 16 v 3 h -16 z"
+ sodipodi:nodetypes="cccc"
+ id="path25814-0"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.7;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m -463.25,1339 5.75,-11.4994 m -6.25,11.4994 -5.75,-11.4994"
inkscape:connector-curvature="0" />
</g>
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.98999999;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 418.85321,140.04954 -2.82,-2.82 a 0.62,0.62 0 0 0 -0.4,-0.18 0.6,0.6 0 0 0 -0.6,0.6 0.62,0.62 0 0 0 0.18,0.43 l 1,1 -9.18,9.12 -1,-1 a 0.62,0.62 0 0 0 -0.4,-0.15 0.6,0.6 0 0 0 -0.6,0.6 0.62,0.62 0 0 0 0.18,0.4 l 2.82,2.82 a 0.6,0.6 0 0 0 0.82,-0.82 l -1,-1 9.18,-9.15 1,1 a 0.6,0.6 0 0 0 0.82,-0.85 z"
- id="path3261"
- inkscape:connector-curvature="0" />
<g
- style="display:inline;enable-background:new"
- transform="translate(-0.35812,42.294299)"
- id="g4073">
+ transform="translate(834,-1254)"
+ id="g26210-2"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="A-16">
<path
- sodipodi:nodetypes="cccccccccccccssssccs"
- d="m 388.17266,99.291166 c -0.27613,4e-5 -0.49997,0.22388 -0.5,0.5 v 1.261304 h -3.16865 v 1.46027 h 3.16865 v 1.27843 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -4.000004 c -3e-5,-0.27612 -0.22387,-0.49996 -0.5,-0.5 z m 2.59221,-4.74807 c 2.50006,0 4.81247,1.33488 6.0625,3.5 1.25002,2.165124 1.25002,4.834884 0,7.000004 -1.25003,2.16512 -3.56244,3.5 -6.0625,3.5 h -6.5 c 0,-4.66667 0,-9.333336 0,-14.000004 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="rect10339-4-1-6" />
- </g>
- <path
- id="rect10339-4-1-7-3"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 368.30892,141.58547 c -0.27613,4e-5 -0.49997,0.22388 -0.5,0.5 v 1.26473 h -4.76715 v 1.4911 h 4.76715 v 1.24417 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 0.63583,0.004 3.43318,-0.006 3.9995,-0.006 0.24106,0 0.46127,-0.0485 0.46127,-0.50967 4e-5,-0.85242 -8.9e-4,-2.98571 -8.9e-4,-3.95935 0,-0.30244 -0.19636,-0.51552 -0.46153,-0.51552 -0.82724,0 -3.36276,-0.009 -3.99823,-0.009 v 2e-5 z m 2.30359,-4.68113 -0.005,4.25868 c 0.48989,0.002 1.39549,0.005 1.88538,0.007 0.44541,0.0357 0.71675,0.47423 0.71675,0.85988 -6.6e-4,1.00616 -0.009,2.97018 -0.009,4.15122 0,0.46073 -0.24756,0.84994 -0.6533,0.84994 -0.48399,0.0143 -1.44986,-1.1e-4 -1.93405,-1.6e-4 v 3.87356 l -7.75691,-0.0669 v -14.00001 z"
- sodipodi:nodetypes="cccccccccccccccccccccccccc" />
- <g
- transform="translate(230.76791,210.17135)"
- style="display:inline;enable-background:new"
- id="g4087_GP_lineart">
+ inkscape:connector-curvature="0"
+ id="path24970-9"
+ d="m -511.49974,1278.4919 -2.6e-4,-2.1822 c 2e-5,-2.8698 1.14768,-5.4099 3,-6.8448 1.85234,-1.4349 4.14766,-1.4349 6,0 1.85233,1.4349 2.99998,4.0575 3,6.9272 v 2.0998"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ sodipodi:nodetypes="ccsccc" />
<g
- id="g4082">
+ transform="translate(-729.00712,939.005)"
+ style="opacity:1"
+ id="g24984-6">
<path
- sodipodi:nodetypes="cccccccccccccccccccc"
- inkscape:connector-curvature="0"
- id="path12456-6"
- mask="none"
- d="m 198.0253,98.27163 v 1.5 h 1 v -1.5 z m 0,2.5 v 2 h 1 v -2 z m 0,3 v 1.2793 l -2.58594,2.35156 0.67188,0.73828 2.60351,-2.36719 0.49027,-0.002 c 0.82475,0 0.82408,-1 0,-1 h -0.17972 v -1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="cccccccccc"
+ id="path24980-2"
+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="m 228.50712,326.49495 h 2 v 2 h -2 z m -10.00994,0 h -2 v 2 h 2 z"
+ inkscape:connector-curvature="0" />
<path
- id="path4185"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.10423;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 207.2397,99.568306 c -0.33768,-0.02992 -0.70751,0.105959 -1.01625,0.406518 l -0.51139,0.495896 c -0.13287,0.12942 -0.13287,0.34092 0,0.47035 l 2.04339,1.98784 c 0.13292,0.12938 0.3479,0.12938 0.48082,0 l 0.50922,-0.49802 c 0.3087,-0.30067 0.44811,-0.65869 0.41741,-0.98755 -0.0307,-0.32884 -0.20718,-0.60186 -0.41741,-0.80663 l -0.67969,-0.661886 c -0.21026,-0.204768 -0.48842,-0.37662 -0.8261,-0.406518 z m -2.31222,1.800554 c -0.0883,9.4e-4 -0.17353,0.0367 -0.23603,0.0979 l -4.25293,4.14168 c -0.0434,0.0426 -0.0749,0.095 -0.0896,0.15324 l -0.67969,2.65189 c -0.0614,0.24217 0.16235,0.46285 0.41088,0.40225 l 2.72308,-0.66402 c 0.0599,-0.0144 0.11363,-0.0428 0.15735,-0.0851 l 4.2551,-4.14382 c 0.13286,-0.12943 0.13286,-0.33881 0,-0.46825 l -2.0434,-1.98784 c -0.0651,-0.0634 -0.15267,-0.0994 -0.24478,-0.0979 z" />
+ id="path24982-2"
+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:normal"
+ d="m 228.5043,327.5 -2.49718,-0.005 M 218.5,327.5 l 2.50712,-0.005"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ </g>
+ <rect
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
+ id="rect24986-0"
+ width="1.9999762"
+ height="2"
+ x="-506.5"
+ y="1265.5"
+ rx="0"
+ ry="0" />
+ </g>
+ <g
+ transform="translate(812,-1317)"
+ id="g25924-0"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="A-15">
+ <path
+ sodipodi:nodetypes="ccsccc"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m -511.49974,1341.4919 -2.6e-4,-2.1822 c 2e-5,-2.8698 1.14768,-5.4099 3,-6.8448 1.85234,-1.4349 4.14766,-1.4349 6,0 1.85233,1.4349 2.99998,4.0575 3,6.9272 v 2.0998"
+ id="path25802-2"
+ inkscape:connector-curvature="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="1329.5"
+ x="-504.5"
+ height="2"
+ width="1.9999762"
+ id="rect25810-8"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
+ </g>
+ <g
+ id="g25347-2"
+ transform="translate(833,-1253)"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ inkscape:label="A-14">
+ <g
+ transform="translate(-43,-61)"
+ id="g25301-4">
<path
- id="path12458-7"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 198.52539,94.771484 c -0.1326,2.7e-5 -0.25978,0.05272 -0.35351,0.146485 l -3,3 c -0.0938,0.09376 -0.14646,0.220915 -0.14649,0.353515 v 9.999996 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 2.50158 c 0.72806,0 0.76638,-1.01916 0,-1 h -2.00158 v -8.999996 h 9 v 0.186392 c 0,0.766385 1,0.767345 1,0 v -0.47936 l 2,-2 v 0.907841 c 0,0.708905 1,0.709935 1,0 v -2.114873 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 0.20703,1 h 8.58594 l -2,2 h -8.58594 z"
- sodipodi:nodetypes="ccccccsccccssccsscccccccc" />
+ sodipodi:nodetypes="ccsccc"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.7;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ d="m -510.49974,1338.4932 -2.6e-4,-0.2387 c 0,-2.5685 1.14768,-5.2795 3,-6.6953 1.85233,-1.4159 4.14765,-1.4159 5.99999,0 1.85233,1.4158 3,4.1268 3,6.6953 v 0.2387"
+ id="path25297-7"
+ inkscape:connector-curvature="0" />
+ <rect
+ ry="0"
+ rx="0"
+ y="1328.5"
+ x="-503.5"
+ height="2"
+ width="1.9999762"
+ id="rect25299-7"
+ style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke" />
</g>
+ <path
+ sodipodi:nodetypes="ccccccccccccccc"
+ id="path25355-6-1"
+ style="display:inline;opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:new"
+ d="m -554,1265 h 3 v -1 h -3 z m 5,0 h 3 v -1 h -3 z m 5,0 h 3 v -1 h -3 z"
+ inkscape:connector-curvature="0" />
</g>
<g
- transform="translate(167.42608,209.69482)"
- style="display:inline;enable-background:new"
- id="g7880_GP_lenght">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14668"
+ transform="matrix(-1,0,0,1,530,30.000005)"
+ inkscape:label="A-13">
<path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 224.38607,100.78271 c -0.15574,0.005 -0.30353,0.0699 -0.41211,0.18164 l -2.05673,2.00254 c -0.62065,0.56444 0.28322,1.46831 0.84766,0.84765 l 2.05673,-2.00254 c 0.39088,-0.38144 0.1104,-1.04428 -0.43555,-1.02929 z"
- id="path15289-7-6"
inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccc" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 258.5,-19 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 3e-5,0.2761309 0.22387,0.4999724 0.5,0.5 h 13 c 0.27613,-2.76e-5 0.49997,-0.2238691 0.5,-0.5 v -13 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m 1.5,2 h 6 v 4 h 4 v 6 h -6 v -4 h -4 z"
+ id="path14664" />
<path
- sodipodi:nodetypes="ccccccccccc"
+ style="display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.9;marker:none;enable-background:accumulate"
+ d="m 260,-17 h 6 v 4 h -2 v 2 h -4 z"
+ id="path14666"
inkscape:connector-curvature="0"
- id="path15289-7-6-5"
- d="m 225.6621,95.349988 c -0.67621,-0.0096 -0.67621,1.009611 0,1 h 2.79493 c -1.0479,1.117288 -1.7641,1.668027 -2.82812,2.732043 -0.62065,0.56444 0.28321,1.468319 0.84765,0.847657 1.06063,-1.101282 1.59202,-1.777197 2.68554,-2.870716 v 2.791016 c -0.01,0.676162 1.00956,0.676162 1,0 v -4 c -3e-5,-0.276131 -0.22387,-0.499973 -0.5,-0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccc" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ transform="matrix(1,0,0,-1,-1.8536743e-6,6.0000045)"
+ id="g13398"
+ inkscape:label="A-12">
<path
- sodipodi:nodetypes="ccccccccccc"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 237.5,-19 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="path13392"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 237.5,-19 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 13 c 1.7e-4,0.4453235 0.53852,0.6683012 0.85352,0.3535156 l 13,-12.9999996 C 251.1683,-18.461483 250.94532,-18.99983 250.5,-19 Z"
+ id="path13396"
inkscape:connector-curvature="0"
- id="path15289-7-6-5-2"
- d="m 221.03217,109.33958 c 0.67621,0.01 0.67621,-1.00961 0,-1 h -2.79493 c 1.0479,-1.11729 1.7641,-1.66802 2.82812,-2.73204 0.62065,-0.56444 -0.28321,-1.46832 -0.84765,-0.84766 -1.06063,1.10128 -1.59202,1.7772 -2.68554,2.87072 v -2.79102 c 0.01,-0.67616 -1.00956,-0.67616 -1,0 v 4 c 3e-5,0.27613 0.22387,0.49998 0.5,0.5 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ sodipodi:nodetypes="ccccccc"
+ inkscape:label="path13396" />
</g>
- <path
- sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
- d="m 417.92349,304.73964 c -0.7818,-0.0644 -0.86293,1.09626 -0.0796,1.1383 l 0.41758,0.0202 c 0.78182,0.0644 0.86296,-1.09626 0.0796,-1.13831 z m -7.87437,1.29265 c -0.65325,0.42724 0.0163,1.38626 0.65667,0.94062 l 0.34001,-0.23929 c 0.65327,-0.42727 -0.0163,-1.38631 -0.65662,-0.94061 z m 5.26412,-0.10772 c 0.785,-0.0185 0.73895,-1.18175 -0.0451,-1.14009 -0.6811,-0.0652 -1.43225,-0.0213 -2.22341,0.0851 -0.785,0.0185 -0.73896,1.18176 0.0451,1.14011 0.8585,-0.10954 1.60282,-0.14009 2.22342,-0.0852 z m -5.74172,5.34858 c -0.17789,-0.75187 -1.32618,-0.47161 -1.12597,0.27482 -0.008,0.72815 0.18352,1.43475 0.53595,2.12392 0.17789,0.75187 1.32617,0.47159 1.12598,-0.27483 -0.40688,-0.70818 -0.47775,-1.41605 -0.53596,-2.12391 z m 1.14987,4.81425 c 0.55238,0.5479 1.3799,-0.2833 0.81165,-0.81524 l -0.30437,-0.28193 c -0.55238,-0.54789 -1.37991,0.2833 -0.81163,0.81524 z m 2.55883,0.11471 c -0.78112,0.0716 -0.65484,1.22767 0.12391,1.13446 0.79706,0.0708 1.5429,0.0136 2.2124,-0.23372 0.7811,-0.0716 0.65482,-1.22768 -0.12391,-1.13445 -0.66955,0.35373 -1.42049,0.37687 -2.2124,0.23371 z m 4.35036,-1.24066 c 0.39775,-0.66505 -0.63058,-1.23994 -1.00859,-0.56384 l -0.19953,0.36135 c -0.39776,0.66506 0.63057,1.23995 1.00857,0.56383 z m -1.53457,-4.82813 c -0.44444,-0.63566 -1.409,0.0364 -0.94666,0.65956 0.53116,0.53126 0.99257,1.10609 1.28624,1.78569 0.44445,0.63565 1.40902,-0.0364 0.94667,-0.65956 -0.24301,-0.74231 -0.69323,-1.32054 -1.28625,-1.78569 z m -2.73483,-1.49223 c -0.72218,-0.30138 -1.16808,0.7761 -0.43732,1.05681 l 0.39025,0.14758 c 0.7222,0.30141 1.1681,-0.7761 0.43732,-1.0568 z m -7.60223,1.91562 c -0.52109,0.57678 0.37464,1.33651 0.87855,0.74515 l 0.26685,-0.31654 c 0.52111,-0.57679 -0.37465,-1.33654 -0.87854,-0.74516 z m 1.15912,7.09355 c -0.1906,-0.74845 -1.33363,-0.44917 -1.12109,0.29354 l 0.11543,0.39523 c 0.19062,0.74845 1.33365,0.44917 1.12109,-0.29354 z m -0.68592,-4.36328 c -0.0858,-0.76698 -1.25912,-0.62352 -1.15127,0.14077 -0.065,0.75431 -0.008,1.50847 0.28594,2.26232 0.0859,0.76696 1.25912,0.62352 1.15129,-0.14076 -0.28468,-0.81162 -0.29126,-1.53878 -0.28596,-2.26233 z m 1.97398,-4.7241 c -0.77314,0.13162 -0.55483,1.27463 0.21417,1.12135 0.7762,-0.30633 1.5005,-0.42412 2.18687,-0.40397 0.77313,-0.13163 0.55482,-1.27462 -0.21418,-1.12137 -0.74152,0.0229 -1.4733,0.13255 -2.18686,0.40399 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.15052;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.2;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- id="path4101-2-6-9-1_GP_dotdash" />
<g
- id="g7580"
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g13454"
+ transform="translate(41.999998,-20.999995)"
+ inkscape:label="A-11">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 174.5,32 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 13 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -13 A 0.50005,0.50005 0 0 0 187.5,32 Z m 0.5,1 h 12 v 12 h -12 z"
+ id="path13377"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 174.58789,32.005859 C 174.30358,31.956646 174.00013,32.166007 174,32.5 v 13 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 13 c 0.44532,-1.7e-4 0.6683,-0.538517 0.35352,-0.853516 l -13,-13 c -0.0788,-0.0787 -0.17086,-0.12422 -0.26563,-0.140625 z M 178.49609,38 c 0.191,-10e-4 0.36608,0.106304 0.45118,0.277344 l 3,6 C 182.11247,44.609574 181.8713,44.99965 181.5,45 h -6 c -0.371,-3.5e-4 -0.61247,-0.390426 -0.44727,-0.722656 l 3,-6 c 0.084,-0.16853 0.25516,-0.275714 0.44336,-0.277344 z"
+ id="path13379"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 178.50391,37.999995 c -0.19102,-0.0013 -0.36611,0.106306 -0.45118,0.277344 l -3,6 c -0.16516,0.332221 0.0763,0.722286 0.44727,0.722656 h 6 c 0.37101,-3.7e-4 0.61243,-0.390435 0.44727,-0.722656 l -3,-6 c -0.0838,-0.168518 -0.25516,-0.2757 -0.44336,-0.277344 z"
+ id="path13331-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.99;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 184.5,35 c 0.82251,0 1.5,0.677494 1.5,1.5 0,0.822506 -0.67749,1.5 -1.5,1.5 -0.82251,0 -1.5,-0.677494 -1.5,-1.5 0,-0.822506 0.67749,-1.5 1.5,-1.5 z"
+ id="ellipse13420"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ </g>
+ <g
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ id="g13337"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ transform="matrix(-1,0,0,1,1458,302.99979)"
+ inkscape:label="A-10">
+ <path
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.3;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1262.5,-278.49979 h -13 v -13 h 13 v 13"
+ id="path14450"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1257.5039,-287 c -0.191,-10e-4 -0.3661,0.1063 -0.4512,0.27734 l -3,6 c -0.1652,0.33223 0.076,0.72231 0.4473,0.72266 h 6 c 0.371,-3.5e-4 0.6125,-0.39043 0.4473,-0.72266 l -3,-6 c -0.084,-0.16853 -0.2552,-0.27571 -0.4434,-0.27734 z"
+ id="path13331"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccc" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1252.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
+ id="ellipse13333"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 1249.5,-292 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 13 a 0.50005,0.50005 0 0 0 0.5,0.5 h 12.9199 a 0.50005,0.50005 0 0 0 0.4043,-0.11328 0.50005,0.50005 0 0 0 0,-0.002 0.50005,0.50005 0 0 0 0.033,-0.0312 0.50005,0.50005 0 0 0 0,-0.004 0.50005,0.50005 0 0 0 0.031,-0.0332 0.50005,0.50005 0 0 0 0,-0.004 0.50005,0.50005 0 0 0 0.1035,-0.39453 V -291.5 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 12 v 12 h -12 z"
+ id="path13335"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g27867"
+ transform="translate(41.999996,-83.999998)"
+ inkscape:label="A-8"
style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 114.5,97 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -3,6 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 3 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 10 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27865"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
+ </g>
+ <g
+ id="g28017"
+ transform="translate(-42.000004,-83.999998)"
+ style="display:inline;enable-background:new"
+ inkscape:label="A-7">
<g
- id="g905">
+ inkscape:export-ydpi="96"
+ inkscape:export-xdpi="96"
+ inkscape:export-filename="blender_icons.png"
+ style="display:inline;opacity:1;enable-background:new"
+ id="g13408-5"
+ transform="translate(-357.00711,41.992878)">
<g
- transform="matrix(0.6740384,0,0,0.6740384,192.80592,-339.68227)"
- style="display:inline;opacity:0.99;fill:#ffffff;stroke-width:1.07692;enable-background:new"
- id="g8599-6-7"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- id="path8597-7-0"
- d="m 331.87142,629.24052 c 0,0.81936 -0.66423,1.48359 -1.48359,1.48359 -0.81937,0 -1.4836,-0.66422 -1.4836,-1.48359 0,-0.81937 0.66423,-1.4836 1.4836,-1.4836 0.81937,0 1.48359,0.66423 1.48359,1.4836 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.72218;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- </g>
+ style="display:inline;opacity:0.99;enable-background:new"
+ transform="translate(378.99999,-439.99995)"
+ id="g12509-8" />
<path
- sodipodi:nodetypes="cccccccccczzcczzzzz"
- inkscape:connector-curvature="0"
- id="path8595-5-9"
- d="m 414.93725,78.999996 c -0.65344,-0.653443 -1.58833,0.255453 -0.88297,0.960812 L 415.18167,81 h -4.6057 c -0.88913,-0.01822 -0.88913,1.018254 0,1 l 2.19337,-0.004 -0.006,0.004 -3.27651,2.873468 c -0.64989,0.580999 0.2216,1.555837 0.87149,0.97484 L 412.00004,84.45 c 0,1.651946 1.15621,3.581251 3.47506,3.550001 C 417.79395,87.968751 419,86.250706 419,84.45 c 0,-1.800705 -1.00462,-2.558141 -1.45954,-3.013074 z M 415.5,82.2 c 1.22478,0 2.25,0.945047 2.25,2.25 0,1.304953 -1.05311,2.25 -2.25,2.25 -1.19689,0 -2.25,-0.960585 -2.25,-2.25 0,-1.289415 1.02522,-2.25 2.25,-2.25 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.3066;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 531.49219,52.992188 a 0.50005,0.50005 0 0 0 -0.31641,0.121093 0.50005,0.50005 0 0 0 -0.0195,0.01563 0.50005,0.50005 0 0 0 -0.0176,0.01758 0.50005,0.50005 0 0 0 -0.002,0.0039 0.50005,0.50005 0 0 0 -0.0312,0.0332 0.50005,0.50005 0 0 0 -0.002,0.0039 0.50005,0.50005 0 0 0 -0.0273,0.03711 0.50005,0.50005 0 0 0 -0.002,0.0039 A 0.50005,0.50005 0 0 0 531,53.582031 V 54.5 a 0.50005,0.50005 0 1 0 1,0 V 54 h 0.5 a 0.50005,0.50005 0 1 0 0,-1 h -0.91992 a 0.50005,0.50005 0 0 0 -0.0879,-0.0078 z m 13,0 A 0.50005,0.50005 0 0 0 544.41797,53 H 543.5 a 0.50005,0.50005 0 1 0 0,1 h 0.5 v 0.5 a 0.50005,0.50005 0 1 0 1,0 v -0.919922 a 0.50005,0.50005 0 0 0 -0.11328,-0.404297 0.50005,0.50005 0 0 0 -0.002,-0.0039 0.50005,0.50005 0 0 0 -0.0312,-0.0332 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.0332,-0.03125 0.50005,0.50005 0 0 0 -0.004,-0.002 0.50005,0.50005 0 0 0 -0.32031,-0.111328 z M 534.5,53 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m -9.00781,2.992188 A 0.50005,0.50005 0 0 0 531,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,56.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,59.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,62.5 v 1 a 0.50005,0.50005 0 1 0 1,0 v -1 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m -13,3 A 0.50005,0.50005 0 0 0 531,65.5 v 0.919922 a 0.50005,0.50005 0 0 0 0.11328,0.404297 0.50005,0.50005 0 0 0 0.0156,0.01953 0.50005,0.50005 0 0 0 0.0176,0.01758 0.50005,0.50005 0 0 0 0.004,0.002 0.50005,0.50005 0 0 0 0.0332,0.03125 0.50005,0.50005 0 0 0 0.004,0.002 A 0.50005,0.50005 0 0 0 531.58203,67 H 532.5 a 0.50005,0.50005 0 1 0 0,-1 H 532 v -0.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z m 13,0 A 0.50005,0.50005 0 0 0 544,65.5 V 66 h -0.5 a 0.50005,0.50005 0 1 0 0,1 h 0.91992 a 0.50005,0.50005 0 0 0 0.4043,-0.113281 0.50005,0.50005 0 0 0 0.004,-0.002 0.50005,0.50005 0 0 0 0.0332,-0.03125 0.50005,0.50005 0 0 0 0.002,-0.0039 0.50005,0.50005 0 0 0 0.0312,-0.0332 0.50005,0.50005 0 0 0 0.002,-0.0039 A 0.50005,0.50005 0 0 0 545,66.417969 V 65.5 a 0.50005,0.50005 0 0 0 -0.50781,-0.507812 z M 534.5,66 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z m 3,0 a 0.50005,0.50005 0 1 0 0,1 h 1 a 0.50005,0.50005 0 1 0 0,-1 z"
+ id="path27987"
+ inkscape:connector-curvature="0" />
</g>
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- id="g15543-3-3"
- transform="translate(21.029034,-20.999943)">
- <g
- id="g15520-6-5"
- transform="translate(231.97182,-397.99995)"
- style="display:inline;opacity:0.6;fill:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- id="g4103-6">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 430.48047,53 c -0.15153,0.004 -0.29304,0.07659 -0.38477,0.197266 l -3.94922,3.949218 C 425.83169,57.461484 426.05468,57.99983 426.5,58 h 4 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 V 54 h 6 v 2.999953 c -0.01,0.676161 1.00956,0.676161 1,0 V 53.5 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 h -7 c -0.005,-6.2e-5 -0.009,-6.2e-5 -0.0137,0 -6.7e-4,1.8e-5 -0.001,-2.1e-5 -0.002,0 -0.001,4.1e-5 -0.003,-5e-5 -0.004,0 z M 426,59.000004 V 66.5 c 3e-5,0.276131 0.22387,0.499972 0.5,0.5 h 4.49914 c 0.67616,0.0096 0.67616,-1.009563 0,-1 H 427 v -6.999996 z"
- transform="translate(-273.99999,439.99994)"
- id="path15514-7-2"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccccccccccccccccccccc" />
- </g>
- </g>
+ transform="rotate(180,149.5,102.00001)"
+ id="g27919-7"
+ style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 117.5,98 c -0.27613,2.8e-5 -0.49997,0.223869 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.276131 -0.22387,-0.499972 -0.5,-0.5 z m -4,5 c -0.27613,3e-5 -0.49997,0.22387 -0.5,0.5 v 2 c 3e-5,0.27613 0.22387,0.49997 0.5,0.5 h 7 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -2 c -3e-5,-0.27613 -0.22387,-0.49997 -0.5,-0.5 z"
+ id="path27916-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccc" />
</g>
</g>
<g
- transform="translate(499.00086,52.015151)"
- id="g824"
- style="display:inline;enable-background:new">
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14588"
+ transform="translate(-42.000002,25.000005)"
+ inkscape:label="A-6">
+ <path
+ id="path14541"
+ d="m 153.5,-9 c -0.27613,2.76e-5 -0.49997,0.2238691 -0.5,0.5 v 8 c 3e-5,0.27613094 0.22387,0.499972391047 0.5,0.5 h 8 c 0.27613,-2.7608953e-5 0.49997,-0.22386906 0.5,-0.5 v -8 c -3e-5,-0.2761309 -0.22387,-0.4999724 -0.5,-0.5 z m 6.5,1 c 0.54636,0 1,0.4536376 1,1 0,0.5463624 -0.45364,1 -1,1 -0.54636,0 -1,-0.4536376 -1,-1 0,-0.5463624 0.45364,-1 1,-1 z m -2.98047,1.75 c 0.17034,0.00643 0.32566,0.099184 0.41211,0.2460938 l 2.5,4.25 C 160.12825,-1.4202448 159.88728,-0.99936558 159.5,-1 h -5 c -0.38728,6.3442e-4 -0.62825,-0.4202448 -0.43164,-0.7539062 l 2.5,-4.25 c 0.0935,-0.1589489 0.26691,-0.2535338 0.45117,-0.2460938 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ inkscape:connector-curvature="0" />
<g
- id="g4207"
- style="display:inline;enable-background:new"
- transform="translate(-499.00079,-52.007172)">
- <g
- transform="translate(105,-21.000376)"
- style="display:inline;enable-background:new"
- id="g7580-6">
- <g
- transform="matrix(0.6740384,0,0,0.6740384,192.80592,-339.68227)"
- style="display:inline;opacity:0.99;fill:#ffffff;stroke-width:1.07692;enable-background:new"
- id="g8599-6-7-2"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <path
- id="path8597-7-0-9"
- d="m 331.87142,629.2294 c 0,0.81936 -0.66423,1.48359 -1.48359,1.48359 -0.81937,0 -1.4836,-0.66422 -1.4836,-1.48359 0,-0.81937 0.66423,-1.4836 1.4836,-1.4836 0.81937,0 1.48359,0.66423 1.48359,1.4836 z"
- style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.72218;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="sssss" />
- </g>
- <path
- sodipodi:nodetypes="cccccccccczzcczzzzz"
- inkscape:connector-curvature="0"
- id="path8595-5-9-1"
- d="m 414.93725,78.992499 c -0.65344,-0.653443 -1.58833,0.255453 -0.88297,0.960812 l 1.12739,1.039192 h -4.6057 c -0.88913,-0.01822 -0.88913,1.018254 0,1 l 2.19337,-0.004 -0.006,0.004 -3.27651,2.873468 c -0.64989,0.580999 0.2216,1.555837 0.87149,0.97484 l 1.64161,-1.398308 c 0,1.651946 1.15632,3.581251 3.47517,3.550001 2.31885,-0.03125 3.5249,-1.749295 3.5249,-3.550001 0,-1.800705 -1.00462,-2.558141 -1.45954,-3.013074 z M 415.5,82.192503 c 1.22478,0 2.25,0.945047 2.25,2.25 0,1.304953 -1.05311,2.25 -2.25,2.25 -1.19689,0 -2.25,-0.960585 -2.25,-2.25 0,-1.289415 1.02522,-2.25 2.25,-2.25 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.3066;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;paint-order:fill markers stroke;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
- </g>
- <g
- transform="translate(19.000003)"
- id="g28228-3-3"
- style="display:inline;opacity:0.6;stroke:#ffffff;enable-background:new"
- inkscape:export-filename="blender_icons.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <g
- id="g28217-6-6"
- transform="translate(338.99999,-439.99995)"
- style="display:inline;opacity:0.99;stroke:#ffffff;enable-background:new">
- <path
- inkscape:connector-curvature="0"
- id="path28215-0"
- transform="translate(-337.99999,439.99995)"
- d="m 501.49219,52.992188 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m -7.00781,0.0067 c -0.12718,0.004 -0.248,0.0564 -0.3379,0.146484 l -4,4.001116 c -0.10126,0.101337 -0.1304,0.223491 -0.13086,0.345704 L 490,57.507812 v 1.984314 c -0.01,0.676161 1.00956,0.676161 1,0 v -1.5 h 3.5 c 0.27613,-3e-5 0.49997,-0.22387 0.5,-0.5 v -3.5 h 1.5 c 0.67616,0.0096 0.67616,-1.002805 0,-0.993242 h -2 v 0.002 c -0.005,-5e-6 -0.0101,-0.0021 -0.0156,-0.002 z m 4.01562,-0.0068 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 2.99219,3.000062 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m -11,5 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z m 0,3 c -0.27615,0.0043 -0.49651,0.223792 -0.49219,0.499938 v 1 c -0.01,0.676161 1.00956,0.676161 1,0 v -1 c 0.004,-0.282265 -0.22554,-0.504353 -0.50781,-0.499938 z M 492.5,65.992126 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z m 3,0 c -0.67616,-0.0096 -0.67616,1.009563 0,1 h 1 c 0.67616,0.0096 0.67616,-1.009563 0,-1 z"
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
- </g>
- </g>
+ id="g14560"
+ transform="translate(147)"
+ style="fill:#ffffff">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.6;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 10.5,-14 c -0.276131,2.8e-5 -0.499972,0.223869 -0.5,0.5 v 3 c 2.8e-5,0.276131 0.223869,0.499972 0.5,0.5 h 9 c 0.276131,-2.8e-5 0.499972,-0.223869 0.5,-0.5 v -3 c -2.8e-5,-0.276131 -0.223869,-0.499972 -0.5,-0.5 z m 0.5,1 h 8 v 2 h -8 z m 5,7 v 1 h 3 v 2 h -3 v 1 h 3.5 c 0.276131,-2.76e-5 0.499972,-0.2238691 0.5,-0.5 v -3 c -2.8e-5,-0.2761309 -0.223869,-0.4999724 -0.5,-0.5 z"
+ id="path14558"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
</g>
</g>
<g
- transform="translate(-0.999993)"
- id="g4126"
+ id="g30726"
+ inkscape:label="A-5"
+ style="display:inline;enable-background:new">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path14394"
+ d="m 98.999998,11.000004 v 4.000002 h -1 -1 v 3 h -1 v -2 h -1 v 5.000001 h -1 v -2.000001 h -1 v 3.560548 h -1 v -2.085938 h -1 v 2.525389 h -1 v 2 L 104,25.000007 v -2.421875 h -1 v -4.578126 h -1 v 2.000001 h -1 v -6.000003 h -1.000002 v -3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new" />
+ </g>
+ <g
+ id="g30729"
+ inkscape:label="A-4"
style="display:inline;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 76,11 c -0.08389,-2.87e-4 -0.166503,0.02054 -0.240234,0.06055 l -5.5,3 C 70.099297,14.148474 69.999666,14.317023 70,14.5 v 7 c -3.35e-4,0.182978 0.0993,0.351528 0.259766,0.439453 l 5.5,3 C 75.833498,24.979467 75.916111,25.000288 76,25 h 1 c 0.08389,2.87e-4 0.166503,-0.02053 0.240234,-0.06055 l 5.5,-3 C 82.900703,21.851526 83.000334,21.682977 83,21.5 v -7 c 3.35e-4,-0.182978 -0.0993,-0.351528 -0.259766,-0.439453 l -5.5,-3 C 77.166502,11.020533 77.083889,10.999712 77,11 Z m 0.382812,2 h 0.240235 L 81,15.390625 v 5.21875 L 76.617188,23 H 76.382812 L 72,20.609375 v -5.21875 z"
+ id="path14426"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccc" />
+ </g>
+ <g
+ id="g30723"
+ inkscape:label="A-3"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 48,11 v 2 h 2 v -2 z m 2,4 v 2 h 2 v -2 z m 2,3 v 2 h 2 v -2 z m 3,3 v 2 h 1.5 v 1 H 59 v 1 h 3 v -2 h -3 v -1 h -2 v -1 z"
+ id="path14341"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
+ </g>
+ <g
+ transform="matrix(-1,0,0,1,1290,302.99979)"
+ style="display:inline;opacity:0.99;fill:#ffffff;enable-background:new"
+ id="g8530-0"
+ inkscape:export-filename="blender_icons.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ inkscape:label="A-2">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1258.4766,-286 a 0.50005,0.50005 0 0 0 -0.4102,0.25195 l -4,7 A 0.50005,0.50005 0 0 0 1254.5,-278 h 8 a 0.50005,0.50005 0 0 0 0.4336,-0.74805 l -4,-7 A 0.50005,0.50005 0 0 0 1258.4766,-286 Z m 0.023,1.50781 3.1387,5.49219 h -6.2774 z"
+ id="path8523-4"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 1253.5,-289 c -0.8225,0 -1.5,0.67749 -1.5,1.5 0,0.82251 0.6775,1.5 1.5,1.5 0.8225,0 1.5,-0.67749 1.5,-1.5 0,-0.82251 -0.6775,-1.5 -1.5,-1.5 z"
+ id="ellipse8525-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="sssss" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="M 27.5,11 A 0.50005,0.50005 0 0 0 27,11.5 v 10.851562 l 1,-1.75 V 12 h 12 v 12 h -3.099609 c 0.122248,0.339531 0.117057,0.686553 0.0039,1 H 40.5 A 0.50005,0.50005 0 0 0 41,24.5 v -13 A 0.50005,0.50005 0 0 0 40.5,11 Z"
+ id="path8528-7"
+ inkscape:connector-curvature="0"
+ transform="matrix(-1,0,0,1,1290,-302.99979)" />
+ </g>
+ <g
+ style="display:inline;fill:#ffffff;enable-background:new"
+ id="g14475"
+ transform="translate(-1.8536743e-6,25.000005)"
+ inkscape:label="A-1">
<g
- style="display:inline;fill:#ffffff;enable-background:new"
- inkscape:export-ydpi="96"
- inkscape:export-xdpi="96"
- inkscape:export-filename="blender_icons.png"
- transform="matrix(0.65914281,0,0,0.65914281,248.47102,-214.89549)"
- id="g12839-3-5">
+ transform="matrix(1,0,0,-1,-294,368)"
+ id="g4806-1"
+ style="opacity:1;fill:#ffffff">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
- d="m 352.97527,473.19666 c -0.49613,-0.0451 -1.03862,0.15972 -1.49219,0.61328 l -0.41128,0.47153 c -0.19519,0.19527 -0.19519,0.51177 0,0.70704 l 3,3 c 0.19527,0.19519 0.51177,0.19519 0.70704,0 l 0.41128,-0.47153 c 0.45356,-0.45357 0.65838,-0.99606 0.61328,-1.49219 -0.0451,-0.49613 -0.30436,-0.90592 -0.61328,-1.21485 l -1,-1 c -0.30893,-0.30892 -0.71872,-0.56817 -1.21485,-0.61328 z m -3.39644,2.7168 c -0.12989,0.002 -0.25387,0.0546 -0.34571,0.14648 l -6.22807,6.22726 c -0.0639,0.0642 -0.10909,0.14453 -0.13086,0.23243 l -1,4 c -0.0904,0.36537 0.2401,0.69582 0.60547,0.60547 l 4,-1 c 0.0879,-0.0218 0.16823,-0.067 0.23243,-0.13086 0,0 6.17898,-6.1737 6.22807,-6.22726 0.19519,-0.19527 0.19519,-0.51177 0,-0.70704 l -3,-3 c -0.0957,-0.0957 -0.22605,-0.14856 -0.36137,-0.14648 z"
- id="path12837-6-3"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccccccscccccccccccccccc" />
+ d="m 300.5,375 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 2 h -10 z"
+ id="path4801-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="m 302.5,378 a 0.50005,0.50005 0 0 0 -0.5,0.5 v 3 a 0.50005,0.50005 0 0 0 0.5,0.5 h 11 a 0.50005,0.50005 0 0 0 0.5,-0.5 v -3 a 0.50005,0.50005 0 0 0 -0.5,-0.5 z m 0.5,1 h 10 v 2 h -10 z"
+ id="path4804-1"
+ inkscape:connector-curvature="0" />
</g>
<path
- sodipodi:nodetypes="csscccccccccccssscccc"
- style="opacity:0.6;fill:#ffffff"
- inkscape:connector-curvature="0"
- id="path2-6"
- d="m 469,101 v 7.5 c 0,0.276 0.224,0.5 0.5,0.5 h 11 c 0.30423,0 0.5,-0.22782 0.5,-0.5 v -4 c 0,-0.65459 -1,-0.65682 -1,0 v 3.5 h -10 v -7 z m 4.48081,-6 c -0.151,0.004 -0.293,0.077 -0.384,0.197 l -3.95,3.949 c -0.314,0.315 -0.091,0.854 0.354,0.854 h 4 c 0.276,0 0.5,-0.224 0.5,-0.5 V 96 H 480.5 c 0.68512,0 0.64092,-1 0,-1 z" />
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
+ d="M 8.5,-4 A 0.50005,0.50005 0 0 0 8,-3.5 v 3 A 0.50005,0.50005 0 0 0 8.5,0 h 11 A 0.50005,0.50005 0 0 0 20,-0.5 v -3 A 0.50005,0.50005 0 0 0 19.5,-4 Z M 9,-3 h 10 v 2 H 9 Z"
+ id="path4817-4"
+ inkscape:connector-curvature="0" />
</g>
</g>
<g
diff --git a/release/datafiles/blender_icons16/icon16_snap_face_nearest.dat b/release/datafiles/blender_icons16/icon16_snap_face_nearest.dat
new file mode 100644
index 00000000000..eade810d41a
--- /dev/null
+++ b/release/datafiles/blender_icons16/icon16_snap_face_nearest.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_snap_face_nearest.dat b/release/datafiles/blender_icons32/icon32_snap_face_nearest.dat
new file mode 100644
index 00000000000..19ca9d38995
--- /dev/null
+++ b/release/datafiles/blender_icons32/icon32_snap_face_nearest.dat
Binary files differ
diff --git a/release/datafiles/blender_icons_geom_update.py b/release/datafiles/blender_icons_geom_update.py
index 6f7508a8e7c..3fd3164c324 100755
--- a/release/datafiles/blender_icons_geom_update.py
+++ b/release/datafiles/blender_icons_geom_update.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This script updates icons from the BLEND file
import os
import subprocess
diff --git a/release/datafiles/blender_icons_update.py b/release/datafiles/blender_icons_update.py
index c1cf8d6fcb0..e2c72e1d0b7 100755
--- a/release/datafiles/blender_icons_update.py
+++ b/release/datafiles/blender_icons_update.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This script updates icons from the SVG file
import os
import subprocess
diff --git a/release/datafiles/brushicons/curves_sculpt_add.png b/release/datafiles/brushicons/curves_sculpt_add.png
new file mode 100644
index 00000000000..e8b81b73919
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_add.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_comb.png b/release/datafiles/brushicons/curves_sculpt_comb.png
new file mode 100644
index 00000000000..bdf49e413e3
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_comb.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_cut.png b/release/datafiles/brushicons/curves_sculpt_cut.png
new file mode 100644
index 00000000000..7f9e116fcd1
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_cut.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_delete.png b/release/datafiles/brushicons/curves_sculpt_delete.png
new file mode 100644
index 00000000000..361b8e335a5
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_delete.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_density.png b/release/datafiles/brushicons/curves_sculpt_density.png
new file mode 100644
index 00000000000..305fa02298f
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_density.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_grow_shrink.png b/release/datafiles/brushicons/curves_sculpt_grow_shrink.png
new file mode 100644
index 00000000000..e4a76c6d6e4
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_grow_shrink.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_pinch.png b/release/datafiles/brushicons/curves_sculpt_pinch.png
new file mode 100644
index 00000000000..cc98203ef57
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_pinch.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_puff.png b/release/datafiles/brushicons/curves_sculpt_puff.png
new file mode 100644
index 00000000000..e5b48b8a96c
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_puff.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_slide.png b/release/datafiles/brushicons/curves_sculpt_slide.png
new file mode 100644
index 00000000000..7627cf76791
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_slide.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_smooth.png b/release/datafiles/brushicons/curves_sculpt_smooth.png
new file mode 100644
index 00000000000..7c7fd8fef4a
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_smooth.png
Binary files differ
diff --git a/release/datafiles/brushicons/curves_sculpt_snake_hook.png b/release/datafiles/brushicons/curves_sculpt_snake_hook.png
new file mode 100644
index 00000000000..468abe66c08
--- /dev/null
+++ b/release/datafiles/brushicons/curves_sculpt_snake_hook.png
Binary files differ
diff --git a/release/datafiles/brushicons/paint_select.png b/release/datafiles/brushicons/paint_select.png
new file mode 100644
index 00000000000..38f9a1250b2
--- /dev/null
+++ b/release/datafiles/brushicons/paint_select.png
Binary files differ
diff --git a/release/datafiles/colormanagement/config.ocio b/release/datafiles/colormanagement/config.ocio
index df359d6c86c..8f7f2b9aaf4 100644
--- a/release/datafiles/colormanagement/config.ocio
+++ b/release/datafiles/colormanagement/config.ocio
@@ -162,7 +162,7 @@ colorspaces:
equalitygroup:
bitdepth: 32f
description: |
- Standard RGB Display Space
+ sRGB display space
isdata: false
to_reference: !<FileTransform> {src: srgb.spi1d, interpolation: linear}
from_reference: !<FileTransform> {src: srgb_inv.spi1d, interpolation: linear}
@@ -193,11 +193,11 @@ colorspaces:
- !<ColorSpace>
name: Filmic sRGB
- family: display
+ family:
equalitygroup:
bitdepth: 32f
description: |
- Filmic sRGB view transform
+ sRGB display space with Filmic view transform
isdata: false
from_reference: !<GroupTransform>
children:
diff --git a/release/datafiles/ctodata.py b/release/datafiles/ctodata.py
index dabdd6d4ea6..b6420d5c9a2 100755
--- a/release/datafiles/ctodata.py
+++ b/release/datafiles/ctodata.py
@@ -2,8 +2,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2009 Blender Foundation. All rights reserved.
-# <pep8 compliant>
-
import sys
argv = sys.argv[:]
diff --git a/release/datafiles/icons/ops.curves.sculpt_density.dat b/release/datafiles/icons/ops.curves.sculpt_density.dat
new file mode 100644
index 00000000000..f336de79082
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_density.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_slide.dat b/release/datafiles/icons/ops.curves.sculpt_slide.dat
new file mode 100644
index 00000000000..7f143ad92cc
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_slide.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_smooth.dat b/release/datafiles/icons/ops.curves.sculpt_smooth.dat
new file mode 100644
index 00000000000..ba4bd081f33
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_smooth.dat
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 647c85462d87c3a9d3a189d28d72d1bd93f4d4a
+Subproject a2eb507891449a0b67582be9561840075513661
diff --git a/release/datafiles/prvicons_update.py b/release/datafiles/prvicons_update.py
index d93a2cec113..0092942ea3b 100755
--- a/release/datafiles/prvicons_update.py
+++ b/release/datafiles/prvicons_update.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This script updates icons from the SVG file
import os
import subprocess
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index fba3c7882c6..b4a1ab6d5f8 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -174,7 +174,6 @@ const UserDef U_default = {
.pie_menu_confirm = 0,
.pie_menu_radius = 100,
.pie_menu_threshold = 12,
- .opensubdiv_compute_type = 0,
.factor_display_type = USER_FACTOR_AS_FACTOR,
.render_display_type = USER_RENDER_DISPLAY_WINDOW,
.filebrowser_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW,
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject d936e4c01fa263a71a7d0665628ae621283b15e
+Subproject 7a8502871c34db0343cc7de52d6b49b15a84238
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 61e45814503f51963c91c51aaf764612e7c5dc7
+Subproject 95107484d076bc965239942e857c83433bfa86d
diff --git a/release/scripts/freestyle/modules/freestyle/shaders.py b/release/scripts/freestyle/modules/freestyle/shaders.py
index d2b10206b9f..f3e4a58d38e 100644
--- a/release/scripts/freestyle/modules/freestyle/shaders.py
+++ b/release/scripts/freestyle/modules/freestyle/shaders.py
@@ -726,7 +726,7 @@ class pyDiffusion2Shader(StrokeShader):
self._curvatureInfo = Curvature2DAngleF0D()
def shade(self, stroke):
- for i in range(1, self._nbIter):
+ for _i in range(1, self._nbIter):
it = Interface0DIterator(stroke)
for svert in it:
svert.point += self._normalInfo(it) * self._lambda * self._curvatureInfo(it)
@@ -911,7 +911,7 @@ class pyBluePrintCirclesShader(StrokeShader):
it = iter(stroke)
- for j in range(self.__turns):
+ for _j in range(self.__turns):
prev_radius = radius
prev_center = center
radius += randint(-R, R)
@@ -952,7 +952,7 @@ class pyBluePrintEllipsesShader(StrokeShader):
# for description of the line below, see pyBluePrintCirclesShader
directions = phase_to_direction(sv_nb)
it = iter(stroke)
- for j in range(self.__turns):
+ for _j in range(self.__turns):
prev_radius = radius
prev_center = center
radius = radius + Vector((randint(-R, R), randint(-R, R)))
@@ -1030,7 +1030,7 @@ class pyBluePrintSquaresShader(StrokeShader):
it = iter(stroke)
verticesToRemove = list()
- for j in range(self.__turns):
+ for _j in range(self.__turns):
for i, svert in zip(range(num_segments), it):
if i < first:
svert.point = points[0] + old_vecs[0] * i / (first - 1)
@@ -1125,7 +1125,7 @@ class pyBluePrintDirectedSquaresShader(StrokeShader):
it = iter(stroke)
verticesToRemove = list()
- for j in range(self.__turns):
+ for _j in range(self.__turns):
for i, svert in zip(range(num_segments), it):
if i < first:
svert.point = points[0] + old_vecs[0] * i / (first - 1)
diff --git a/release/scripts/freestyle/modules/freestyle/utils.py b/release/scripts/freestyle/modules/freestyle/utils.py
index 152dbca6f5e..309497430a8 100644
--- a/release/scripts/freestyle/modules/freestyle/utils.py
+++ b/release/scripts/freestyle/modules/freestyle/utils.py
@@ -151,7 +151,7 @@ def normal_at_I0D(it: Interface0DIterator) -> Vector:
# this case sometimes has a small difference with Normal2DF0D (1e-3 -ish)
it.decrement()
a = it.object
- curr, b = next(it), next(it)
+ _curr, b = next(it), next(it)
# give iterator back in original state
it.decrement()
return (b.point - a.point).orthogonal().normalized()
@@ -229,8 +229,6 @@ def simplifyDouglasPeucker(points, tolerance):
first_stack = []
last_stack = []
- new_points = []
-
markers[first] = 1
markers[last] = 1
diff --git a/release/scripts/freestyle/modules/parameter_editor.py b/release/scripts/freestyle/modules/parameter_editor.py
index 5940f4f5cc8..d07532dfe54 100644
--- a/release/scripts/freestyle/modules/parameter_editor.py
+++ b/release/scripts/freestyle/modules/parameter_editor.py
@@ -1028,7 +1028,7 @@ class DashedLineShader(StrokeShader):
it = stroke.stroke_vertices_begin(sampling)
pattern_cycle = cycle(self.pattern)
pattern = next(pattern_cycle)
- for svert in it:
+ for _svert in it:
pos = it.t # curvilinear abscissa
if pos - start + sampling > pattern:
diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py
index 3e823f2b6b7..9d820b8c9de 100644
--- a/release/scripts/modules/addon_utils.py
+++ b/release/scripts/modules/addon_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"paths",
"modules",
diff --git a/release/scripts/modules/animsys_refactor.py b/release/scripts/modules/animsys_refactor.py
index 35072885deb..0ab486efa11 100644
--- a/release/scripts/modules/animsys_refactor.py
+++ b/release/scripts/modules/animsys_refactor.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
This module has utility functions for renaming
rna values in fcurves and drivers.
diff --git a/release/scripts/modules/bl_app_override/__init__.py b/release/scripts/modules/bl_app_override/__init__.py
index e60c123ead5..4d6194e71cd 100644
--- a/release/scripts/modules/bl_app_override/__init__.py
+++ b/release/scripts/modules/bl_app_override/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
Module to manage overriding various parts of Blender.
diff --git a/release/scripts/modules/bl_app_override/helpers.py b/release/scripts/modules/bl_app_override/helpers.py
index dd17e8aa7c6..4759e0ae8e5 100644
--- a/release/scripts/modules/bl_app_override/helpers.py
+++ b/release/scripts/modules/bl_app_override/helpers.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# -----------------------------------------------------------------------------
# AppOverrideState
diff --git a/release/scripts/modules/bl_app_template_utils.py b/release/scripts/modules/bl_app_template_utils.py
index 9d71664e513..985dbc22be6 100644
--- a/release/scripts/modules/bl_app_template_utils.py
+++ b/release/scripts/modules/bl_app_template_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
Similar to ``addon_utils``, except we can only have one active at a time.
diff --git a/release/scripts/modules/bl_console_utils/__init__.py b/release/scripts/modules/bl_console_utils/__init__.py
index 78800fa5703..ab95fe1e68a 100644
--- a/release/scripts/modules/bl_console_utils/__init__.py
+++ b/release/scripts/modules/bl_console_utils/__init__.py
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
"""
-Utilities relating to text mode console interations.
+Utilities relating to text mode console interactions.
"""
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/__init__.py b/release/scripts/modules/bl_console_utils/autocomplete/__init__.py
index 5fa5b11f4bf..0da40331835 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/__init__.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/__init__.py
@@ -2,6 +2,4 @@
# Copyright (c) 2009 www.stani.be
-# <pep8 compliant>
-
"""Package for console specific modules."""
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py b/release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py
index 6c7b0611ee2..07ccac81f91 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/complete_calltip.py
@@ -2,8 +2,6 @@
# Copyright (c) 2009 www.stani.be
-# <pep8-80 compliant>
-
import inspect
import re
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py b/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py
index 2339e79c8f1..2f321fee0b2 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/complete_import.py
@@ -10,8 +10,6 @@
# the file COPYING, distributed as part of this software.
# ****************************************************************************
-# <pep8 compliant>
-
"""Completer for import statements
Original code was from IPython/Extensions/ipy_completers.py. The following
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py b/release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py
index 7bfa2aac1c1..4ba446d6832 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/complete_namespace.py
@@ -2,8 +2,6 @@
# Copyright (c) 2009 www.stani.be
-# <pep8-80 compliant>
-
"""Autocomplete with the standard library"""
import re
diff --git a/release/scripts/modules/bl_console_utils/autocomplete/intellisense.py b/release/scripts/modules/bl_console_utils/autocomplete/intellisense.py
index 9484f825f9f..e53e38dbc53 100644
--- a/release/scripts/modules/bl_console_utils/autocomplete/intellisense.py
+++ b/release/scripts/modules/bl_console_utils/autocomplete/intellisense.py
@@ -2,8 +2,6 @@
# Copyright (c) 2009 www.stani.be
-# <pep8-80 compliant>
-
"""This module provides intellisense features such as:
* autocompletion
diff --git a/release/scripts/modules/bl_i18n_utils/__init__.py b/release/scripts/modules/bl_i18n_utils/__init__.py
index b07a993c12e..d4af1270369 100644
--- a/release/scripts/modules/bl_i18n_utils/__init__.py
+++ b/release/scripts/modules/bl_i18n_utils/__init__.py
@@ -1,5 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""Package for translation (i18n) tools."""
diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
index 604a577eec9..bfc111dd3c1 100644
--- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
+++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Populate a template file (POT format currently) from Blender RNA/py/C data.
# XXX: This script is meant to be used from inside Blender!
# You should not directly use this script, rather use update_msg.py!
@@ -805,20 +803,21 @@ def dump_src_messages(msgs, reports, settings):
line += data[pos:m.start()].count('\n')
msgsrc = rel_path + ":" + str(line)
_msgid = d.get("msg_raw")
- # First, try the "multi-contexts" stuff!
- _msgctxts = tuple(d.get("ctxt_raw{}".format(i)) for i in range(settings.PYGETTEXT_MAX_MULTI_CTXT))
- if _msgctxts[0]:
- for _msgctxt in _msgctxts:
- if not _msgctxt:
- break
+ if _msgid not in {'""', "''"}:
+ # First, try the "multi-contexts" stuff!
+ _msgctxts = tuple(d.get("ctxt_raw{}".format(i)) for i in range(settings.PYGETTEXT_MAX_MULTI_CTXT))
+ if _msgctxts[0]:
+ for _msgctxt in _msgctxts:
+ if not _msgctxt:
+ break
+ msgctxt, msgid = process_entry(_msgctxt, _msgid)
+ process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt_src, settings)
+ reports["src_messages"].append((msgctxt, msgid, msgsrc))
+ else:
+ _msgctxt = d.get("ctxt_raw")
msgctxt, msgid = process_entry(_msgctxt, _msgid)
process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt_src, settings)
reports["src_messages"].append((msgctxt, msgid, msgsrc))
- else:
- _msgctxt = d.get("ctxt_raw")
- msgctxt, msgid = process_entry(_msgctxt, _msgid)
- process_msg(msgs, msgctxt, msgid, msgsrc, reports, check_ctxt_src, settings)
- reports["src_messages"].append((msgctxt, msgid, msgsrc))
pos = m.end()
line += data[m.start():pos].count('\n')
@@ -963,7 +962,12 @@ def dump_addon_messages(module_name, do_checks, settings):
# and make the diff!
for key in minus_msgs:
if key != settings.PO_HEADER_KEY:
- del msgs[key]
+ if key in msgs:
+ del msgs[key]
+ else:
+ # This should not happen, but some messages seem to have
+ # leaked on add-on unregister and register?
+ print(f"Key not found in msgs: {key}")
if check_ctxt:
_diff_check_ctxt(check_ctxt, minus_check_ctxt)
diff --git a/release/scripts/modules/bl_i18n_utils/merge_po.py b/release/scripts/modules/bl_i18n_utils/merge_po.py
index d048f8f5c42..3cc5046fe3c 100755
--- a/release/scripts/modules/bl_i18n_utils/merge_po.py
+++ b/release/scripts/modules/bl_i18n_utils/merge_po.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Merge one or more .po files into the first dest one.
# If a msgkey is present in more than one merged po, the one in the first file wins, unless
# it’s marked as fuzzy and one later is not.
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index 57722d06ce5..3b69f8a6bf7 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Global settings used by all scripts in this dir.
# XXX Before any use of the tools in this dir, please make a copy of this file
# named "setting.py"
@@ -58,7 +56,7 @@ LANGUAGES = (
(21, "Arabic (ﺔﻴﺑﺮﻌﻟﺍ)", "ar_EG"),
(22, "Bulgarian (Български)", "bg_BG"),
(23, "Greek (Ελληνικά)", "el_GR"),
- (24, "Korean (한국 언어)", "ko_KR"),
+ (24, "Korean (한국어)", "ko_KR"),
(25, "Nepali (नेपाली)", "ne_NP"),
# Using the utf8 flipped form of Persian (فارسی).
(26, "Persian (ﯽﺳﺭﺎﻓ)", "fa_IR"),
@@ -250,9 +248,14 @@ PYGETTEXT_KEYWORDS = (() +
tuple(("{}\\((?:[^\"',]+,){{3}}\\s*" + _msg_re + r"\s*\)").format(it)
for it in ("BMO_error_raise",)) +
- tuple(("{}\\((?:[^\"',]+,)\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
+ tuple(("{}\\((?:[^\"',]+,){{2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
for it in ("BKE_modifier_set_error",)) +
+ # This one is a tad more risky, but in practice would not expect a name/uid string parameter
+ # (the second one in those functions) to ever have a comma in it, so think this is fine.
+ tuple(("{}\\((?:[^,]+,){{2}}\\s*" + _msg_re + r"\s*(?:\)|,)").format(it)
+ for it in ("modifier_subpanel_register", "gpencil_modifier_subpanel_register")) +
+
# bUnitDef unit names.
# NOTE: regex is a bit more complex than it would need too. Since the actual
# identifier (`B_UNIT_DEF_`) is at the end, if it's simpler/too general it
@@ -299,6 +302,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"ascii",
"author", # Addons' field. :/
"bItasc",
+ "blender.org",
"color_index is invalid",
"cos(A)",
"cosh(A)",
@@ -314,6 +318,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"glTF 2.0 (.glb/.gltf)",
"glTF Binary (.glb)",
"glTF Embedded (.gltf)",
+ "glTF Original PBR data",
"glTF Separate (.gltf + .bin + textures)",
"invoke() needs to be called before execute()",
"iScale",
@@ -332,6 +337,7 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"mp3",
"normal",
"ogg",
+ "oneAPI",
"p0",
"px",
"re",
@@ -342,6 +348,8 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"sinh(A)",
"sqrt(x*x+y*y+z*z)",
"sRGB",
+ "sRGB display space",
+ "sRGB display space with Filmic view transform",
"tan(A)",
"tanh(A)",
"utf-8",
@@ -358,7 +366,9 @@ WARN_MSGID_NOT_CAPITALIZED_ALLOWED = {
"all and invert unselected",
"and AMD driver version 22.10 or newer",
"and AMD Radeon Pro 21.Q4 driver or newer",
+ "and Linux driver version xx.xx.28000 or newer",
"and NVIDIA driver version 470 or newer",
+ "and Windows driver version 101.1660 or newer",
"available with",
"brown fox",
"can't save image while rendering",
@@ -433,6 +443,7 @@ WARN_MSGID_END_POINT_ALLOWED = {
"The program will now close.",
"Your graphics card or driver has limited support. It may work, but with issues.",
"Your graphics card or driver is not supported.",
+ "Invalid surface UVs on %d curves.",
}
PARSER_CACHE_HASH = 'sha1'
diff --git a/release/scripts/modules/bl_i18n_utils/settings_user.py b/release/scripts/modules/bl_i18n_utils/settings_user.py
index a7aa8a80af8..3c29a0d743a 100644
--- a/release/scripts/modules/bl_i18n_utils/settings_user.py
+++ b/release/scripts/modules/bl_i18n_utils/settings_user.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import settings
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index ec5465549b3..324c3ea261d 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Some misc utilities...
import collections
@@ -156,7 +154,7 @@ def get_po_files_from_dir(root_dir, langs=set()):
else:
continue
if uid in found_uids:
- printf("WARNING! {} id has been found more than once! only first one has been loaded!".format(uid))
+ print("WARNING! {} id has been found more than once! only first one has been loaded!".format(uid))
continue
found_uids.add(uid)
yield uid, po_file
@@ -1242,8 +1240,8 @@ class I18n:
return os.path.join(os.path.dirname(path), uid + ".po")
elif kind == 'PY':
if not path.endswith(".py"):
- if self.src.get(self.settings.PARSER_PY_ID):
- return self.src[self.settings.PARSER_PY_ID]
+ if os.path.isdir(path):
+ return os.path.join(path, "translations.py")
return os.path.join(os.path.dirname(path), "translations.py")
return path
@@ -1394,15 +1392,15 @@ class I18n:
if langs set is void, all languages found are loaded.
"""
default_context = self.settings.DEFAULT_CONTEXT
- self.src[self.settings.PARSER_PY_ID], msgs = self.check_py_module_has_translations(src, self.settings)
+ self.py_file, msgs = self.check_py_module_has_translations(src, self.settings)
if msgs is None:
- self.src[self.settings.PARSER_PY_ID] = src
+ self.py_file = src
msgs = ()
for key, (sources, gen_comments), *translations in msgs:
if self.settings.PARSER_TEMPLATE_ID not in self.trans:
self.trans[self.settings.PARSER_TEMPLATE_ID] = I18nMessages(self.settings.PARSER_TEMPLATE_ID,
settings=self.settings)
- self.src[self.settings.PARSER_TEMPLATE_ID] = self.src[self.settings.PARSER_PY_ID]
+ self.src[self.settings.PARSER_TEMPLATE_ID] = self.py_file
if key in self.trans[self.settings.PARSER_TEMPLATE_ID].msgs:
print("ERROR! key {} is defined more than once! Skipping re-definitions!")
continue
@@ -1418,7 +1416,7 @@ class I18n:
for uid, msgstr, (is_fuzzy, user_comments) in translations:
if uid not in self.trans:
self.trans[uid] = I18nMessages(uid, settings=self.settings)
- self.src[uid] = self.src[self.settings.PARSER_PY_ID]
+ self.src[uid] = self.py_file
comment_lines = [self.settings.PO_COMMENT_PREFIX + c for c in user_comments] + common_comment_lines
self.trans[uid].msgs[key] = I18nMessage(ctxt, [key[1]], [msgstr], comment_lines, False, is_fuzzy,
settings=self.settings)
@@ -1481,7 +1479,7 @@ class I18n:
if langs:
translations &= langs
translations = [('"' + lng + '"', " " * (len(lng) + 6), self.trans[lng]) for lng in sorted(translations)]
- print(k for k in keys.keys())
+ print(*(k for k in keys.keys()))
for key in keys.keys():
if ref.msgs[key].is_commented:
continue
@@ -1567,25 +1565,9 @@ class I18n:
# We completely replace the text found between start and end markers...
txt = _gen_py(self, langs)
else:
- printf("Creating python file {} containing translations.".format(dst))
+ print("Creating python file {} containing translations.".format(dst))
txt = [
- "# ***** 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 *****",
+ "# SPDX-License-Identifier: GPL-2.0-or-later",
"",
self.settings.PARSER_PY_MARKER_BEGIN,
"",
diff --git a/release/scripts/modules/bl_i18n_utils/utils_cli.py b/release/scripts/modules/bl_i18n_utils/utils_cli.py
index dd75ac11ac4..4b00816d132 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_cli.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_cli.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Some useful operations from utils' I18nMessages class exposed as a CLI.
import os
diff --git a/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py b/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
index da4183d457c..833c46a732e 100755
--- a/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_languages_menu.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Update "languages" text file used by Blender at runtime to build translations menu.
diff --git a/release/scripts/modules/bl_i18n_utils/utils_rtl.py b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
index beec2659df8..6e3d25cfc3f 100755
--- a/release/scripts/modules/bl_i18n_utils/utils_rtl.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_rtl.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Pre-process right-to-left languages.
# You can use it either standalone, or through import_po_from_branches or
# update_trunk.
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index f9208bbe3ee..462c954d54a 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import enchant
import os
import pickle
@@ -435,6 +433,7 @@ class SpellChecker:
"polyline", "polylines",
"probabilistically",
"pulldown", "pulldowns",
+ "quadratically",
"quantized",
"quartic",
"quaternion", "quaternions",
@@ -503,6 +502,7 @@ class SpellChecker:
"luminance",
"mantaflow",
"matcap",
+ "microfacet",
"midtones",
"mipmap", "mipmaps", "mip",
"ngon", "ngons",
@@ -510,6 +510,7 @@ class SpellChecker:
"nurb", "nurbs",
"perlin",
"phong",
+ "photorealistic",
"pinlight",
"posterize",
"qi",
@@ -677,7 +678,7 @@ class SpellChecker:
"ascii",
"atrac",
"avx",
- "bsdf",
+ "bsdf", "bsdfs",
"bssrdf",
"bw",
"ccd",
@@ -710,14 +711,17 @@ class SpellChecker:
"hdc",
"hdr", "hdri", "hdris",
"hh", "mm", "ss", "ff", # hh:mm:ss:ff timecode
+ "hpg", # Intel Xe-HPG architecture
"hsv", "hsva", "hsl",
"id",
"ies",
"ior",
"itu",
"jonswap",
+ "lfe",
"lhs",
"lmb", "mmb", "rmb",
+ "lscm",
"kb",
"mocap",
"msgid", "msgids",
diff --git a/release/scripts/modules/bl_keymap_utils/__init__.py b/release/scripts/modules/bl_keymap_utils/__init__.py
index e00776d3466..950314cd74c 100644
--- a/release/scripts/modules/bl_keymap_utils/__init__.py
+++ b/release/scripts/modules/bl_keymap_utils/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"io",
"keymap_from_toolbar",
diff --git a/release/scripts/modules/bl_keymap_utils/io.py b/release/scripts/modules/bl_keymap_utils/io.py
index 6631461eaba..5d74ffbcf56 100644
--- a/release/scripts/modules/bl_keymap_utils/io.py
+++ b/release/scripts/modules/bl_keymap_utils/io.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# -----------------------------------------------------------------------------
# Export Functions
diff --git a/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py b/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
index 2cfba52d688..f75a38c1c66 100644
--- a/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
+++ b/release/scripts/modules/bl_keymap_utils/keymap_from_toolbar.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Dynamically create a keymap which is used by the popup toolbar
# for accelerator key access.
diff --git a/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py b/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py
index 6389efba049..7172d7809f2 100644
--- a/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py
+++ b/release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"generate",
)
@@ -90,6 +88,10 @@ _km_hierarchy = [
_km_expand_from_toolsystem('VIEW_3D', 'SCULPT'),
]),
+ ('Sculpt Curves', 'EMPTY', 'WINDOW', [
+ _km_expand_from_toolsystem('VIEW_3D', 'CURVES_SCULPT'),
+ ]),
+
('Particle', 'EMPTY', 'WINDOW', [
_km_expand_from_toolsystem('VIEW_3D', 'PARTICLE'),
]),
diff --git a/release/scripts/modules/bl_keymap_utils/versioning.py b/release/scripts/modules/bl_keymap_utils/versioning.py
index ba83892c12c..65febf2c399 100644
--- a/release/scripts/modules/bl_keymap_utils/versioning.py
+++ b/release/scripts/modules/bl_keymap_utils/versioning.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Update Blender version this key-map was written in:
#
# When the version is `(0, 0, 0)`, the key-map being loaded didn't contain any versioning information.
diff --git a/release/scripts/modules/bl_previews_utils/bl_previews_render.py b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
index bf2b9fe1a76..bafc62330ea 100644
--- a/release/scripts/modules/bl_previews_utils/bl_previews_render.py
+++ b/release/scripts/modules/bl_previews_utils/bl_previews_render.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Populate a template file (POT format currently) from Blender RNA/py/C data.
# Note: This script is meant to be used from inside Blender!
diff --git a/release/scripts/modules/bl_rna_utils/data_path.py b/release/scripts/modules/bl_rna_utils/data_path.py
index e15d9bc2d1c..d0c1fa57db8 100644
--- a/release/scripts/modules/bl_rna_utils/data_path.py
+++ b/release/scripts/modules/bl_rna_utils/data_path.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"property_definition_from_data_path",
"decompose_data_path",
diff --git a/release/scripts/modules/bl_ui_utils/bug_report_url.py b/release/scripts/modules/bl_ui_utils/bug_report_url.py
index 28af7aaa013..6755c2bad9d 100644
--- a/release/scripts/modules/bl_ui_utils/bug_report_url.py
+++ b/release/scripts/modules/bl_ui_utils/bug_report_url.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
def url_prefill_from_blender(*, addon_info=None):
import bpy
diff --git a/release/scripts/modules/blend_render_info.py b/release/scripts/modules/blend_render_info.py
index f8d22052290..6b45a6f7e72 100755
--- a/release/scripts/modules/blend_render_info.py
+++ b/release/scripts/modules/blend_render_info.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# This module can get render info without running from inside blender.
#
# This struct won't change according to Ton.
@@ -14,24 +12,65 @@
# int SDNAnr, nr;
# } BHead;
+__all__ = (
+ "read_blend_rend_chunk",
+)
+
+
+class RawBlendFileReader:
+ """
+ Return a file handle to the raw blend file data (abstracting compressed formats).
+ """
+ __slots__ = (
+ # The path to load.
+ "_filepath",
+ # The file base file handler or None (only set for compressed formats).
+ "_blendfile_base",
+ # The file handler to return to the caller (always uncompressed data).
+ "_blendfile",
+ )
+
+ def __init__(self, filepath):
+ self._filepath = filepath
+ self._blendfile_base = None
+ self._blendfile = None
+
+ def __enter__(self):
+ blendfile = open(self._filepath, "rb")
+ blendfile_base = None
+ head = blendfile.read(4)
+ blendfile.seek(0)
+ if head[0:2] == b'\x1f\x8b': # GZIP magic.
+ import gzip
+ blendfile_base = blendfile
+ blendfile = gzip.open(blendfile, "rb")
+ elif head[0:4] == b'\x28\xb5\x2f\xfd': # Z-standard magic.
+ import zstandard
+ blendfile_base = blendfile
+ blendfile = zstandard.open(blendfile, "rb")
-def read_blend_rend_chunk(path):
+ self._blendfile_base = blendfile_base
+ self._blendfile = blendfile
- import struct
+ return self._blendfile
- blendfile = open(path, "rb")
+ def __exit__(self, exc_type, exc_value, exc_traceback):
+ self._blendfile.close()
+ if self._blendfile_base is not None:
+ self._blendfile_base.close()
- head = blendfile.read(7)
+ return False
- if head[0:2] == b'\x1f\x8b': # gzip magic
- import gzip
- blendfile.seek(0)
- blendfile = gzip.open(blendfile, "rb")
- head = blendfile.read(7)
+def _read_blend_rend_chunk_from_file(blendfile, filepath):
+ import struct
+ import sys
+
+ from os import SEEK_CUR
+
+ head = blendfile.read(7)
if head != b'BLENDER':
- print("not a blend file:", path)
- blendfile.close()
+ sys.stderr.write("Not a blend file: %s\n" % filepath)
return []
is_64_bit = (blendfile.read(1) == b'-')
@@ -39,47 +78,67 @@ def read_blend_rend_chunk(path):
# true for PPC, false for X86
is_big_endian = (blendfile.read(1) == b'V')
- # Now read the bhead chunk!!!
- blendfile.read(3) # skip the version
+ # Now read the bhead chunk!
+ blendfile.seek(3, SEEK_CUR) # Skip the version.
scenes = []
sizeof_bhead = 24 if is_64_bit else 20
- while blendfile.read(4) == b'REND':
- sizeof_bhead_left = sizeof_bhead - 4
+ # Should always be 4, but a malformed/corrupt file may be less.
+ while (bhead_id := blendfile.read(4)) != b'ENDB':
+
+ if len(bhead_id) != 4:
+ sys.stderr.write("Unable to read until ENDB block (corrupt file): %s\n" % filepath)
+ break
- struct.unpack('>i' if is_big_endian else '<i', blendfile.read(4))[0]
- sizeof_bhead_left -= 4
+ sizeof_data_left = struct.unpack('>i' if is_big_endian else '<i', blendfile.read(4))[0]
+ if sizeof_data_left < 0:
+ # Very unlikely, but prevent other errors.
+ sys.stderr.write("Negative block size found (corrupt file): %s\n" % filepath)
+ break
- # We don't care about the rest of the bhead struct
- blendfile.read(sizeof_bhead_left)
+ # 4 from the `head_id`, another 4 for the size of the BHEAD.
+ sizeof_bhead_left = sizeof_bhead - 8
- # Now we want the scene name, start and end frame. this is 32bites long
- start_frame, end_frame = struct.unpack('>2i' if is_big_endian else '<2i', blendfile.read(8))
+ # The remainder of the BHEAD struct is not used.
+ blendfile.seek(sizeof_bhead_left, SEEK_CUR)
- scene_name = blendfile.read(64)
+ if bhead_id == b'REND':
+ # Now we want the scene name, start and end frame. this is 32bits long.
+ start_frame, end_frame = struct.unpack('>2i' if is_big_endian else '<2i', blendfile.read(8))
+ sizeof_data_left -= 8
- scene_name = scene_name[:scene_name.index(b'\0')]
+ scene_name = blendfile.read(64)
+ sizeof_data_left -= 64
- try:
- scene_name = str(scene_name, "utf8")
- except TypeError:
- pass
+ scene_name = scene_name[:scene_name.index(b'\0')]
+ # It's possible old blend files are not UTF8 compliant, use `surrogateescape`.
+ scene_name = scene_name.decode("utf8", errors='surrogateescape')
- scenes.append((start_frame, end_frame, scene_name))
+ scenes.append((start_frame, end_frame, scene_name))
- blendfile.close()
+ if sizeof_data_left > 0:
+ blendfile.seek(sizeof_data_left, SEEK_CUR)
+ elif sizeof_data_left < 0:
+ # Very unlikely, but prevent attempting to further parse corrupt data.
+ sys.stderr.write("Error calculating next block (corrupt file): %s\n" % filepath)
+ break
return scenes
+def read_blend_rend_chunk(filepath):
+ with RawBlendFileReader(filepath) as blendfile:
+ return _read_blend_rend_chunk_from_file(blendfile, filepath)
+
+
def main():
import sys
- for arg in sys.argv[1:]:
- if arg.lower().endswith('.blend'):
- for value in read_blend_rend_chunk(arg):
- print("%d %d %s" % value)
+
+ for filepath in sys.argv[1:]:
+ for value in read_blend_rend_chunk(filepath):
+ print("%d %d %s" % value)
if __name__ == '__main__':
diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py
index 35848602f9d..fd7a573dc06 100644
--- a/release/scripts/modules/bpy/__init__.py
+++ b/release/scripts/modules/bpy/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
Give access to blender data and utility functions.
"""
diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py
index e19128e41a9..cb6ea0318a4 100644
--- a/release/scripts/modules/bpy/ops.py
+++ b/release/scripts/modules/bpy/ops.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# for slightly faster access
from _bpy import ops as _ops_module
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index 88c34be6906..60b8159b896 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
This module has a similar scope to os.path, containing utility
functions for dealing with paths in Blender.
diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py
index 5cd2bd2f076..54fcb4cdc67 100644
--- a/release/scripts/modules/bpy/utils/__init__.py
+++ b/release/scripts/modules/bpy/utils/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
This module contains utility functions specific to blender but
not associated with blenders internal data.
diff --git a/release/scripts/modules/bpy/utils/previews.py b/release/scripts/modules/bpy/utils/previews.py
index 1f398176643..5826de725c8 100644
--- a/release/scripts/modules/bpy/utils/previews.py
+++ b/release/scripts/modules/bpy/utils/previews.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
This module contains utility functions to handle custom previews.
diff --git a/release/scripts/modules/bpy/utils/toolsystem.py b/release/scripts/modules/bpy/utils/toolsystem.py
index dbcf56900a1..6aa7f885239 100644
--- a/release/scripts/modules/bpy/utils/toolsystem.py
+++ b/release/scripts/modules/bpy/utils/toolsystem.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Until we untangle ToolDef from bl_ui internals,
# use this module to document ToolDef.
from bl_ui.space_toolsystem_common import ToolDef
diff --git a/release/scripts/modules/bpy_extras/__init__.py b/release/scripts/modules/bpy_extras/__init__.py
index 15a8d00cddc..f018789d858 100644
--- a/release/scripts/modules/bpy_extras/__init__.py
+++ b/release/scripts/modules/bpy_extras/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
Utility modules associated with the bpy module.
"""
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py
index 1b1df41d2c6..f66dfd6eb0a 100644
--- a/release/scripts/modules/bpy_extras/anim_utils.py
+++ b/release/scripts/modules/bpy_extras/anim_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"bake_action",
"bake_action_objects",
diff --git a/release/scripts/modules/bpy_extras/asset_utils.py b/release/scripts/modules/bpy_extras/asset_utils.py
index 70c02272fd2..a6f2a709977 100644
--- a/release/scripts/modules/bpy_extras/asset_utils.py
+++ b/release/scripts/modules/bpy_extras/asset_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Helpers for asset management tasks.
"""
diff --git a/release/scripts/modules/bpy_extras/id_map_utils.py b/release/scripts/modules/bpy_extras/id_map_utils.py
index cf39f2185c6..9aa7cc9e07c 100644
--- a/release/scripts/modules/bpy_extras/id_map_utils.py
+++ b/release/scripts/modules/bpy_extras/id_map_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from typing import Dict, Set
import bpy
from bpy.types import ID
diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py
index eaf5922a199..48a50d52e60 100644
--- a/release/scripts/modules/bpy_extras/image_utils.py
+++ b/release/scripts/modules/bpy_extras/image_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"load_image",
)
diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py
index 3a73603ba85..0497d69162e 100644
--- a/release/scripts/modules/bpy_extras/io_utils.py
+++ b/release/scripts/modules/bpy_extras/io_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"ExportHelper",
"ImportHelper",
diff --git a/release/scripts/modules/bpy_extras/keyconfig_utils.py b/release/scripts/modules/bpy_extras/keyconfig_utils.py
index 1b8f3ac3fd8..b87641874cd 100644
--- a/release/scripts/modules/bpy_extras/keyconfig_utils.py
+++ b/release/scripts/modules/bpy_extras/keyconfig_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# -----------------------------------------------------------------------------
# Add-on helpers to properly (un)register their own keymaps.
diff --git a/release/scripts/modules/bpy_extras/mesh_utils.py b/release/scripts/modules/bpy_extras/mesh_utils.py
index a6f71dc0a2a..f6dc33e4f02 100644
--- a/release/scripts/modules/bpy_extras/mesh_utils.py
+++ b/release/scripts/modules/bpy_extras/mesh_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"mesh_linked_uv_islands",
"mesh_linked_triangles",
diff --git a/release/scripts/modules/bpy_extras/node_shader_utils.py b/release/scripts/modules/bpy_extras/node_shader_utils.py
index 522357296fd..cda291c6c90 100644
--- a/release/scripts/modules/bpy_extras/node_shader_utils.py
+++ b/release/scripts/modules/bpy_extras/node_shader_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from mathutils import Color, Vector
__all__ = (
diff --git a/release/scripts/modules/bpy_extras/node_utils.py b/release/scripts/modules/bpy_extras/node_utils.py
index 639ebc46e16..3fec65db5a5 100644
--- a/release/scripts/modules/bpy_extras/node_utils.py
+++ b/release/scripts/modules/bpy_extras/node_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"find_node_input",
)
diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py
index 6829aed5565..ab678ba27c8 100644
--- a/release/scripts/modules/bpy_extras/object_utils.py
+++ b/release/scripts/modules/bpy_extras/object_utils.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
__all__ = (
diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py
index 7de363483e5..c661d017ca0 100644
--- a/release/scripts/modules/bpy_extras/view3d_utils.py
+++ b/release/scripts/modules/bpy_extras/view3d_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
__all__ = (
"region_2d_to_vector_3d",
"region_2d_to_origin_3d",
diff --git a/release/scripts/modules/bpy_extras/wm_utils/progress_report.py b/release/scripts/modules/bpy_extras/wm_utils/progress_report.py
index da9ef735e0d..637d60838db 100644
--- a/release/scripts/modules/bpy_extras/wm_utils/progress_report.py
+++ b/release/scripts/modules/bpy_extras/wm_utils/progress_report.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import time
diff --git a/release/scripts/modules/bpy_restrict_state.py b/release/scripts/modules/bpy_restrict_state.py
index 78d4b4be972..31a0c52ecf5 100644
--- a/release/scripts/modules/bpy_restrict_state.py
+++ b/release/scripts/modules/bpy_restrict_state.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
"""
This module contains RestrictBlend context manager.
"""
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 4c6e2508859..df0631ec26d 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
from _bpy import types as bpy_types
StructRNA = bpy_types.bpy_struct
@@ -58,6 +56,21 @@ class Context(StructRNA):
if value is None:
return value
+ # If the attribute is a list property, apply subscripting.
+ if isinstance(value, list) and path_rest.startswith("["):
+ index_str, div, index_tail = path_rest[1:].partition("]")
+ if not div:
+ raise ValueError("Path index is not terminated: %s%s" % (attr, path_rest))
+ try:
+ index = int(index_str)
+ except ValueError:
+ raise ValueError("Path index is invalid: %s[%s]" % (attr, index_str))
+ if 0 <= index < len(value):
+ path_rest = index_tail
+ value = value[index]
+ else:
+ raise IndexError("Path index out of range: %s[%s]" % (attr, index_str))
+
# Resolve the rest of the path if necessary.
if path_rest:
path_resolve_fn = getattr(value, "path_resolve", None)
diff --git a/release/scripts/modules/console_python.py b/release/scripts/modules/console_python.py
index b7e86d5c673..2aa4caab7f6 100644
--- a/release/scripts/modules/console_python.py
+++ b/release/scripts/modules/console_python.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
import sys
import bpy
diff --git a/release/scripts/modules/console_shell.py b/release/scripts/modules/console_shell.py
index ff8a30557d2..194f636a97e 100644
--- a/release/scripts/modules/console_shell.py
+++ b/release/scripts/modules/console_shell.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import os
import bpy
diff --git a/release/scripts/modules/graphviz_export.py b/release/scripts/modules/graphviz_export.py
index a121cc3ed06..b6e73590386 100644
--- a/release/scripts/modules/graphviz_export.py
+++ b/release/scripts/modules/graphviz_export.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
header = '''
diff --git a/release/scripts/modules/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py
index e48be9a95ea..b566889bfb9 100644
--- a/release/scripts/modules/keyingsets_utils.py
+++ b/release/scripts/modules/keyingsets_utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# This file defines a set of methods that are useful for various
# Relative Keying Set (RKS) related operations, such as: callbacks
# for polling, iterator callbacks, and also generate callbacks.
diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py
index 819deec8cc0..231720ea519 100644
--- a/release/scripts/modules/nodeitems_utils.py
+++ b/release/scripts/modules/nodeitems_utils.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 04120508df5..e2bbc4077a1 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# classes for extracting info from blenders internal classes
import bpy
@@ -242,6 +240,7 @@ class InfoPropertyRNA:
"default_str",
"default",
"enum_items",
+ "enum_pointer",
"min",
"max",
"array_length",
@@ -285,9 +284,17 @@ class InfoPropertyRNA:
else:
self.fixed_type = None
+ self.enum_pointer = 0
if self.type == "enum":
- self.enum_items[:] = [(item.identifier, item.name, item.description) for item in rna_prop.enum_items]
+ items = tuple(rna_prop.enum_items)
+ items_static = tuple(rna_prop.enum_items_static)
+ self.enum_items[:] = [(item.identifier, item.name, item.description) for item in items]
self.is_enum_flag = rna_prop.is_enum_flag
+ # Prioritize static items as this is never going to be allocated data and is therefor
+ # will be a stable match to compare against.
+ item = (items_static or items)
+ if item:
+ self.enum_pointer = item[0].as_pointer()
else:
self.is_enum_flag = False
@@ -342,7 +349,19 @@ class InfoPropertyRNA:
return "%s=%s" % (self.identifier, default)
return self.identifier
- def get_type_description(self, as_ret=False, as_arg=False, class_fmt="%s", collection_id="Collection"):
+ def get_type_description(
+ self, *,
+ as_ret=False,
+ as_arg=False,
+ class_fmt="%s",
+ collection_id="Collection",
+ enum_descr_override=None,
+ ):
+ """
+ :arg enum_descr_override: Optionally override items for enum.
+ Otherwise expand the literal items.
+ :type enum_descr_override: string or None when unset.
+ """
type_str = ""
if self.fixed_type is None:
type_str += self.type
@@ -357,10 +376,17 @@ class InfoPropertyRNA:
if self.type in {"float", "int"}:
type_str += " in [%s, %s]" % (range_str(self.min), range_str(self.max))
elif self.type == "enum":
+ enum_descr = enum_descr_override
+ if not enum_descr:
+ if self.is_enum_flag:
+ enum_descr = "{%s}" % ", ".join(("'%s'" % s[0]) for s in self.enum_items)
+ else:
+ enum_descr = "[%s]" % ", ".join(("'%s'" % s[0]) for s in self.enum_items)
if self.is_enum_flag:
- type_str += " set in {%s}" % ", ".join(("'%s'" % s[0]) for s in self.enum_items)
+ type_str += " set in %s" % enum_descr
else:
- type_str += " in [%s]" % ", ".join(("'%s'" % s[0]) for s in self.enum_items)
+ type_str += " in %s" % enum_descr
+ del enum_descr
if not (as_arg or as_ret):
# write default property, ignore function args for this
diff --git a/release/scripts/modules/rna_keymap_ui.py b/release/scripts/modules/rna_keymap_ui.py
index 5da98cd783d..a7ad162ba66 100644
--- a/release/scripts/modules/rna_keymap_ui.py
+++ b/release/scripts/modules/rna_keymap_ui.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
__all__ = (
"draw_entry",
"draw_km",
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index 9896bd3e281..cfce84f84e3 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -189,6 +189,7 @@ url_manual_mapping = (
("bpy.types.rendersettings_simplify_gpencil_view_fill*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-fill"),
("bpy.types.sequencertoolsettings.snap_to_hold_offset*", "video_editing/edit/montage/editing.html#bpy-types-sequencertoolsettings-snap-to-hold-offset"),
("bpy.types.toolsettings.use_mesh_automerge_and_split*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-mesh-automerge-and-split"),
+ ("bpy.ops.scene.view_layer_remove_unused_lightgroups*", "render/layers/passes.html#bpy-ops-scene-view-layer-remove-unused-lightgroups"),
("bpy.types.animvizmotionpaths.show_keyframe_numbers*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-keyframe-numbers"),
("bpy.types.brush.cloth_constraint_softbody_strength*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-constraint-softbody-strength"),
("bpy.types.brush.elastic_deform_volume_preservation*", "sculpt_paint/sculpting/tools/elastic_deform.html#bpy-types-brush-elastic-deform-volume-preservation"),
@@ -302,11 +303,13 @@ url_manual_mapping = (
("bpy.types.rigidbodyconstraint.breaking_threshold*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-breaking-threshold"),
("bpy.types.spaceclipeditor.use_manual_calibration*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-manual-calibration"),
("bpy.types.spacedopesheeteditor.show_pose_markers*", "animation/markers.html#bpy-types-spacedopesheeteditor-show-pose-markers"),
+ ("bpy.types.spaceimageoverlay.show_grid_background*", "editors/uv/overlays.html#bpy-types-spaceimageoverlay-show-grid-background"),
+ ("bpy.types.spacenodeoverlay.show_named_attributes*", "modeling/geometry_nodes/inspection.html#bpy-types-spacenodeoverlay-show-named-attributes"),
("bpy.types.spaceoutliner.use_filter_object_camera*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-camera"),
("bpy.types.spaceoutliner.use_filter_object_others*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-others"),
("bpy.types.spacesequenceeditor.overlay_frame_type*", "editors/video_sequencer/preview/sidebar.html#bpy-types-spacesequenceeditor-overlay-frame-type"),
("bpy.types.spacesequenceeditor.show_strip_overlay*", "editors/video_sequencer/sequencer/display.html#bpy-types-spacesequenceeditor-show-strip-overlay"),
- ("bpy.types.spaceuveditor.custom_grid_subdivisions*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-custom-grid-subdivisions"),
+ ("bpy.types.spaceuveditor.custom_grid_subdivisions*", "editors/uv/overlays.html#bpy-types-spaceuveditor-custom-grid-subdivisions"),
("bpy.types.toolsettings.proportional_edit_falloff*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-proportional-edit-falloff"),
("bpy.types.toolsettings.use_edge_path_live_unwrap*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-edge-path-live-unwrap"),
("bpy.types.toolsettings.use_gpencil_draw_additive*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-additive"),
@@ -388,6 +391,7 @@ url_manual_mapping = (
("bpy.types.geometrynodecurvehandletypeselection*", "modeling/geometry_nodes/curve/handle_type_selection.html#bpy-types-geometrynodecurvehandletypeselection"),
("bpy.types.geometrynodeinputmeshvertexneighbors*", "modeling/geometry_nodes/mesh/vertex_neighbors.html#bpy-types-geometrynodeinputmeshvertexneighbors"),
("bpy.types.greasepencil.curve_edit_corner_angle*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-corner-angle"),
+ ("bpy.types.imageformatsettings.color_management*", "render/output/properties/output.html#bpy-types-imageformatsettings-color-management"),
("bpy.types.lineartgpencilmodifier.source_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-source-camera"),
("bpy.types.lineartgpencilmodifier.use_face_mark*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark"),
("bpy.types.linestylegeometrymodifier_tipremover*", "render/freestyle/view_layer/line_style/modifiers/geometry/tip_remover.html#bpy-types-linestylegeometrymodifier-tipremover"),
@@ -404,6 +408,7 @@ url_manual_mapping = (
("bpy.types.viewlayer.use_pass_cryptomatte_asset*", "render/layers/passes.html#bpy-types-viewlayer-use-pass-cryptomatte-asset"),
("bpy.ops.outliner.collection_indirect_only_set*", "render/layers/introduction.html#bpy-ops-outliner-collection-indirect-only-set"),
("bpy.ops.scene.freestyle_geometry_modifier_add*", "render/freestyle/view_layer/line_style/geometry.html#bpy-ops-scene-freestyle-geometry-modifier-add"),
+ ("bpy.ops.scene.view_layer_add_used_lightgroups*", "render/layers/passes.html#bpy-ops-scene-view-layer-add-used-lightgroups"),
("bpy.ops.sequencer.deinterlace_selected_movies*", "video_editing/edit/montage/editing.html#bpy-ops-sequencer-deinterlace-selected-movies"),
("bpy.types.bakesettings.use_selected_to_active*", "render/cycles/baking.html#bpy-types-bakesettings-use-selected-to-active"),
("bpy.types.brush.surface_smooth_current_vertex*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-surface-smooth-current-vertex"),
@@ -420,6 +425,7 @@ url_manual_mapping = (
("bpy.types.cyclesworldsettings.sampling_method*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings-sampling-method"),
("bpy.types.cyclesworldsettings.volume_sampling*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings-volume-sampling"),
("bpy.types.editbone.bbone_handle_use_scale_end*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-handle-use-scale-end"),
+ ("bpy.types.ffmpegsettings.constant_rate_factor*", "render/output/properties/output.html#bpy-types-ffmpegsettings-constant-rate-factor"),
("bpy.types.fluiddomainsettings.adapt_threshold*", "physics/fluid/type/domain/gas/adaptive_domain.html#bpy-types-fluiddomainsettings-adapt-threshold"),
("bpy.types.fluiddomainsettings.cache_directory*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-directory"),
("bpy.types.fluiddomainsettings.cache_frame_end*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-cache-frame-end"),
@@ -510,12 +516,14 @@ url_manual_mapping = (
("bpy.types.spaceclipeditor.show_green_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-green-channel"),
("bpy.types.spacenodeoverlay.show_context_path*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeoverlay-show-context-path"),
("bpy.types.spaceoutliner.show_restrict_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-restrict-column"),
+ ("bpy.types.spacesequenceeditor.use_clamp_view*", "editors/video_sequencer/sequencer/navigating.html#bpy-types-spacesequenceeditor-use-clamp-view"),
("bpy.types.spacespreadsheet.object_eval_state*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-object-eval-state"),
("bpy.types.spaceuveditor.display_stretch_type*", "editors/uv/overlays.html#bpy-types-spaceuveditor-display-stretch-type"),
("bpy.types.toolsettings.transform_pivot_point*", "editors/3dview/controls/pivot_point/index.html#bpy-types-toolsettings-transform-pivot-point"),
("bpy.types.toolsettings.use_proportional_edit*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-edit"),
("bpy.types.toolsettings.uv_sticky_select_mode*", "editors/uv/selecting.html#bpy-types-toolsettings-uv-sticky-select-mode"),
("bpy.types.volumedisplay.interpolation_method*", "modeling/volumes/properties.html#bpy-types-volumedisplay-interpolation-method"),
+ ("bpy.ops.geometry.color_attribute_render_set*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-render-set"),
("bpy.types.brushgpencilsettings.angle_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle-factor"),
("bpy.types.brushgpencilsettings.pen_strength*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-pen-strength"),
("bpy.types.clothsettings.use_pressure_volume*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-use-pressure-volume"),
@@ -538,6 +546,7 @@ url_manual_mapping = (
("bpy.types.freestylelinestyle.use_length_max*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-use-length-max"),
("bpy.types.freestylelinestyle.use_length_min*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-use-length-min"),
("bpy.types.geometrynodeinputmeshedgevertices*", "modeling/geometry_nodes/mesh/edge_vertices.html#bpy-types-geometrynodeinputmeshedgevertices"),
+ ("bpy.types.geometrynodeinputmeshfaceisplanar*", "modeling/geometry_nodes/mesh/face_is_planar.html#bpy-types-geometrynodeinputmeshfaceisplanar"),
("bpy.types.geometrynodeinputsplineresolution*", "modeling/geometry_nodes/curve/spline_resolution.html#bpy-types-geometrynodeinputsplineresolution"),
("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"),
("bpy.types.materialgpencilstyle.stroke_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-stroke-style"),
@@ -561,11 +570,14 @@ url_manual_mapping = (
("bpy.types.toolsettings.use_snap_peel_object*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-peel-object"),
("bpy.types.view3doverlay.fade_inactive_alpha*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-fade-inactive-alpha"),
("bpy.types.view3doverlay.wireframe_threshold*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-wireframe-threshold"),
+ ("bpy.types.viewlayer.active_lightgroup_index*", "render/layers/passes.html#bpy-types-viewlayer-active-lightgroup-index"),
+ ("bpy.ops.ed.lib_id_override_editable_toggle*", "editors/outliner/interface.html#bpy-ops-ed-lib-id-override-editable-toggle"),
("bpy.ops.object.constraint_add_with_targets*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-constraint-add-with-targets"),
("bpy.ops.object.material_slot_remove_unused*", "scene_layout/object/editing/cleanup.html#bpy-ops-object-material-slot-remove-unused"),
("bpy.ops.outliner.collection_disable_render*", "editors/outliner/editing.html#bpy-ops-outliner-collection-disable-render"),
("bpy.ops.scene.freestyle_alpha_modifier_add*", "render/freestyle/view_layer/line_style/alpha.html#bpy-ops-scene-freestyle-alpha-modifier-add"),
("bpy.ops.scene.freestyle_color_modifier_add*", "render/freestyle/view_layer/line_style/color.html#bpy-ops-scene-freestyle-color-modifier-add"),
+ ("bpy.ops.scene.view_layer_remove_lightgroup*", "render/layers/passes.html#bpy-ops-scene-view-layer-remove-lightgroup"),
("bpy.types.brush.cloth_simulation_area_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-simulation-area-type"),
("bpy.types.brushgpencilsettings.eraser_mode*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-mode"),
("bpy.types.brushgpencilsettings.fill_factor*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-factor"),
@@ -599,6 +611,7 @@ url_manual_mapping = (
("bpy.types.freestylesettings.use_smoothness*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-use-smoothness"),
("bpy.types.geometrynodecurveprimitivecircle*", "modeling/geometry_nodes/curve_primitives/curve_circle.html#bpy-types-geometrynodecurveprimitivecircle"),
("bpy.types.geometrynodecurvequadraticbezier*", "modeling/geometry_nodes/curve_primitives/quadratic_bezier.html#bpy-types-geometrynodecurvequadraticbezier"),
+ ("bpy.types.geometrynoderemovenamedattribute*", "modeling/geometry_nodes/attribute/remove_named_attribute.html#bpy-types-geometrynoderemovenamedattribute"),
("bpy.types.gpencillayer.use_viewlayer_masks*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-viewlayer-masks"),
("bpy.types.greasepencil.onion_keyframe_type*", "grease_pencil/properties/onion_skinning.html#bpy-types-greasepencil-onion-keyframe-type"),
("bpy.types.lineartgpencilmodifier.use_cache*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-cache"),
@@ -642,6 +655,7 @@ url_manual_mapping = (
("bpy.types.cyclesrendersettings.time_limit*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-time-limit"),
("bpy.types.cyclesvisibilitysettings.camera*", "render/cycles/world_settings.html#bpy-types-cyclesvisibilitysettings-camera"),
("bpy.types.cyclesworldsettings.max_bounces*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings-max-bounces"),
+ ("bpy.types.ffmpegsettings.use_max_b_frames*", "render/output/properties/output.html#bpy-types-ffmpegsettings-use-max-b-frames"),
("bpy.types.fluiddomainsettings.domain_type*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-domain-type"),
("bpy.types.fluiddomainsettings.flame_smoke*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-flame-smoke"),
("bpy.types.fluiddomainsettings.fluid_group*", "physics/fluid/type/domain/collections.html#bpy-types-fluiddomainsettings-fluid-group"),
@@ -657,6 +671,7 @@ url_manual_mapping = (
("bpy.types.freestylesettings.sphere_radius*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-sphere-radius"),
("bpy.types.geometrynodeattributedomainsize*", "modeling/geometry_nodes/attribute/domain_size.html#bpy-types-geometrynodeattributedomainsize"),
("bpy.types.geometrynodesetsplineresolution*", "modeling/geometry_nodes/curve/set_spline_resolution.html#bpy-types-geometrynodesetsplineresolution"),
+ ("bpy.types.geometrynodestorenamedattribute*", "modeling/geometry_nodes/attribute/store_named_attribute.html#bpy-types-geometrynodestorenamedattribute"),
("bpy.types.gpencillayer.annotation_opacity*", "interface/annotate_tool.html#bpy-types-gpencillayer-annotation-opacity"),
("bpy.types.gpencillayer.use_onion_skinning*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-use-onion-skinning"),
("bpy.types.gpencilsculptguide.use_snapping*", "grease_pencil/modes/draw/guides.html#bpy-types-gpencilsculptguide-use-snapping"),
@@ -747,6 +762,8 @@ url_manual_mapping = (
("bpy.types.linestyle*modifier_alongstroke*", "render/freestyle/view_layer/line_style/modifiers/color/along_stroke.html#bpy-types-linestyle-modifier-alongstroke"),
("bpy.types.linestyle*modifier_creaseangle*", "render/freestyle/view_layer/line_style/modifiers/color/crease_angle.html#bpy-types-linestyle-modifier-creaseangle"),
("bpy.types.linestylecolormodifier_tangent*", "render/freestyle/view_layer/line_style/modifiers/color/tangent.html#bpy-types-linestylecolormodifier-tangent"),
+ ("bpy.types.material.show_transparent_back*", "render/eevee/materials/settings.html#bpy-types-material-show-transparent-back"),
+ ("bpy.types.material.use_screen_refraction*", "render/eevee/materials/settings.html#bpy-types-material-use-screen-refraction"),
("bpy.types.materialgpencilstyle.mix_color*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-mix-color"),
("bpy.types.materialgpencilstyle.show_fill*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-show-fill"),
("bpy.types.mesh.use_customdata_edge_bevel*", "modeling/meshes/properties/custom_data.html#bpy-types-mesh-use-customdata-edge-bevel"),
@@ -774,6 +791,7 @@ url_manual_mapping = (
("bpy.types.volumedisplay.wireframe_detail*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-detail"),
("bpy.types.windowmanager.asset_path_dummy*", "editors/asset_browser.html#bpy-types-windowmanager-asset-path-dummy"),
("bpy.ops.armature.rigify_add_bone_groups*", "addons/rigging/rigify/metarigs.html#bpy-ops-armature-rigify-add-bone-groups"),
+ ("bpy.ops.geometry.color_attribute_remove*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-remove"),
("bpy.ops.object.assign_property_defaults*", "animation/armatures/posing/editing/apply.html#bpy-ops-object-assign-property-defaults"),
("bpy.ops.object.vertex_group_limit_total*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-limit-total"),
("bpy.ops.object.vertex_group_remove_from*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-remove-from"),
@@ -783,6 +801,7 @@ url_manual_mapping = (
("bpy.ops.outliner.collection_show_inside*", "editors/outliner/editing.html#bpy-ops-outliner-collection-show-inside"),
("bpy.ops.poselib.restore_previous_action*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-restore-previous-action"),
("bpy.ops.preferences.reset_default_theme*", "editors/preferences/themes.html#bpy-ops-preferences-reset-default-theme"),
+ ("bpy.ops.scene.view_layer_add_lightgroup*", "render/layers/passes.html#bpy-ops-scene-view-layer-add-lightgroup"),
("bpy.ops.sequencer.strip_transform_clear*", "video_editing/edit/montage/editing.html#bpy-ops-sequencer-strip-transform-clear"),
("bpy.ops.spreadsheet.add_row_filter_rule*", "editors/spreadsheet.html#bpy-ops-spreadsheet-add-row-filter-rule"),
("bpy.types.animdata.action_extrapolation*", "editors/nla/sidebar.html#bpy-types-animdata-action-extrapolation"),
@@ -800,6 +819,7 @@ url_manual_mapping = (
("bpy.types.cyclesrendersettings.caustics*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-caustics"),
("bpy.types.cyclesrendersettings.denoiser*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-denoiser"),
("bpy.types.editbone.use_inherit_rotation*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-use-inherit-rotation"),
+ ("bpy.types.ffmpegsettings.audio_channels*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio-channels"),
("bpy.types.fileselectparams.display_size*", "editors/file_browser.html#bpy-types-fileselectparams-display-size"),
("bpy.types.fileselectparams.display_type*", "editors/file_browser.html#bpy-types-fileselectparams-display-type"),
("bpy.types.fluiddomainsettings.use_guide*", "physics/fluid/type/domain/guides.html#bpy-types-fluiddomainsettings-use-guide"),
@@ -818,12 +838,14 @@ url_manual_mapping = (
("bpy.types.freestylelinestyle.split_dash*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-split-dash"),
("bpy.types.freestylesettings.use_culling*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-use-culling"),
("bpy.types.geometrynodeattributetransfer*", "modeling/geometry_nodes/attribute/transfer_attribute.html#bpy-types-geometrynodeattributetransfer"),
+ ("bpy.types.geometrynodeduplicateelements*", "modeling/geometry_nodes/geometry/duplicate_elements.html#bpy-types-geometrynodeduplicateelements"),
("bpy.types.geometrynodeinputmeshfacearea*", "modeling/geometry_nodes/mesh/face_area.html#bpy-types-geometrynodeinputmeshfacearea"),
("bpy.types.geometrynodeinputsplinecyclic*", "modeling/geometry_nodes/curve/is_spline_cyclic.html#bpy-types-geometrynodeinputsplinecyclic"),
("bpy.types.geometrynodeinstancestopoints*", "modeling/geometry_nodes/instances/instances_to_points.html#bpy-types-geometrynodeinstancestopoints"),
("bpy.types.gpencillayer.viewlayer_render*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-viewlayer-render"),
("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"),
("bpy.types.layercollection.indirect_only*", "editors/outliner/interface.html#bpy-types-layercollection-indirect-only"),
+ ("bpy.types.material.use_backface_culling*", "render/eevee/materials/settings.html#bpy-types-material-use-backface-culling"),
("bpy.types.material.use_sss_translucency*", "render/eevee/materials/settings.html#bpy-types-material-use-sss-translucency"),
("bpy.types.materiallineart.mat_occlusion*", "render/materials/line_art.html#bpy-types-materiallineart-mat-occlusion"),
("bpy.types.movietrackingcamera.principal*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-principal"),
@@ -841,7 +863,8 @@ url_manual_mapping = (
("bpy.types.spacetexteditor.margin_column*", "editors/text_editor.html#bpy-types-spacetexteditor-margin-column"),
("bpy.types.spacetexteditor.use_find_wrap*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-wrap"),
("bpy.types.spaceuveditor.pixel_snap_mode*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-pixel-snap-mode"),
- ("bpy.types.spaceuveditor.use_custom_grid*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-use-custom-grid"),
+ ("bpy.types.spaceuveditor.tile_grid_shape*", "editors/uv/overlays.html#bpy-types-spaceuveditor-tile-grid-shape"),
+ ("bpy.types.spaceuveditor.use_custom_grid*", "editors/uv/overlays.html#bpy-types-spaceuveditor-use-custom-grid"),
("bpy.types.spaceuveditor.use_live_unwrap*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-use-live-unwrap"),
("bpy.types.toolsettings.double_threshold*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-double-threshold"),
("bpy.types.toolsettings.lock_object_mode*", "interface/window_system/topbar.html#bpy-types-toolsettings-lock-object-mode"),
@@ -870,6 +893,11 @@ url_manual_mapping = (
("bpy.types.compositornodedoubleedgemask*", "compositing/types/matte/double_edge_mask.html#bpy-types-compositornodedoubleedgemask"),
("bpy.types.cyclesrendersettings.samples*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-samples"),
("bpy.types.dopesheet.show_only_selected*", "editors/dope_sheet/introduction.html#bpy-types-dopesheet-show-only-selected"),
+ ("bpy.types.ffmpegsettings.audio_bitrate*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio-bitrate"),
+ ("bpy.types.ffmpegsettings.audio_mixrate*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio-mixrate"),
+ ("bpy.types.ffmpegsettings.ffmpeg_preset*", "render/output/properties/output.html#bpy-types-ffmpegsettings-ffmpeg-preset"),
+ ("bpy.types.ffmpegsettings.use_autosplit*", "render/output/properties/output.html#bpy-types-ffmpegsettings-use-autosplit"),
+ ("bpy.types.ffmpegsettings.video_bitrate*", "render/output/properties/output.html#bpy-types-ffmpegsettings-video-bitrate"),
("bpy.types.fileselectparams.show_hidden*", "editors/file_browser.html#bpy-types-fileselectparams-show-hidden"),
("bpy.types.fileselectparams.sort_method*", "editors/file_browser.html#bpy-types-fileselectparams-sort-method"),
("bpy.types.fluiddomainsettings.clipping*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-clipping"),
@@ -898,10 +926,14 @@ url_manual_mapping = (
("bpy.types.rendersettings.use_sequencer*", "render/output/properties/post_processing.html#bpy-types-rendersettings-use-sequencer"),
("bpy.types.sceneeevee.volumetric_shadow*", "render/eevee/render_settings/volumetrics.html#bpy-types-sceneeevee-volumetric-shadow"),
("bpy.types.sequenceeditor.overlay_frame*", "editors/video_sequencer/preview/sidebar.html#bpy-types-sequenceeditor-overlay-frame"),
+ ("bpy.types.sequencetimelinechannel.lock*", "editors/video_sequencer/sequencer/channels.html#bpy-types-sequencetimelinechannel-lock"),
+ ("bpy.types.sequencetimelinechannel.mute*", "editors/video_sequencer/sequencer/channels.html#bpy-types-sequencetimelinechannel-mute"),
+ ("bpy.types.sequencetimelinechannel.name*", "editors/video_sequencer/sequencer/channels.html#bpy-types-sequencetimelinechannel-name"),
("bpy.types.shadernodebsdfhairprincipled*", "render/shader_nodes/shader/hair_principled.html#bpy-types-shadernodebsdfhairprincipled"),
("bpy.types.shadernodevectordisplacement*", "render/shader_nodes/vector/vector_displacement.html#bpy-types-shadernodevectordisplacement"),
("bpy.types.spacegrapheditor.show_cursor*", "editors/graph_editor/introduction.html#bpy-types-spacegrapheditor-show-cursor"),
("bpy.types.spaceimageeditor.show_repeat*", "editors/image/sidebar.html#bpy-types-spaceimageeditor-show-repeat"),
+ ("bpy.types.spacenodeoverlay.show_timing*", "modeling/geometry_nodes/inspection.html#bpy-types-spacenodeoverlay-show-timing"),
("bpy.types.spaceoutliner.use_sort_alpha*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-sort-alpha"),
("bpy.types.spacepreferences.filter_text*", "editors/preferences/keymap.html#bpy-types-spacepreferences-filter-text"),
("bpy.types.spacepreferences.filter_type*", "editors/preferences/keymap.html#bpy-types-spacepreferences-filter-type"),
@@ -934,6 +966,7 @@ url_manual_mapping = (
("bpy.types.bakesettings.cage_extrusion*", "render/cycles/baking.html#bpy-types-bakesettings-cage-extrusion"),
("bpy.types.bakesettings.use_pass_color*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-color"),
("bpy.types.brush.boundary_falloff_type*", "sculpt_paint/sculpting/tools/boundary.html#bpy-types-brush-boundary-falloff-type"),
+ ("bpy.types.brush.cursor_color_subtract*", "sculpt_paint/brush/cursor.html#bpy-types-brush-cursor-color-subtract"),
("bpy.types.brush.texture_overlay_alpha*", "sculpt_paint/brush/cursor.html#bpy-types-brush-texture-overlay-alpha"),
("bpy.types.brushgpencilsettings.aspect*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-aspect"),
("bpy.types.brushgpencilsettings.dilate*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-dilate"),
@@ -947,6 +980,8 @@ url_manual_mapping = (
("bpy.types.compositornodesetalpha.mode*", "compositing/types/converter/set_alpha.html#bpy-types-compositornodesetalpha-mode"),
("bpy.types.dopesheet.use_filter_invert*", "editors/graph_editor/channels.html#bpy-types-dopesheet-use-filter-invert"),
("bpy.types.editbone.use_local_location*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-use-local-location"),
+ ("bpy.types.ffmpegsettings.audio_volume*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio-volume"),
+ ("bpy.types.ffmpegsettings.max_b_frames*", "render/output/properties/output.html#bpy-types-ffmpegsettings-max-b-frames"),
("bpy.types.fileselectparams.use_filter*", "editors/file_browser.html#bpy-types-fileselectparams-use-filter"),
("bpy.types.fluiddomainsettings.gravity*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-gravity"),
("bpy.types.fluidflowsettings.flow_type*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-flow-type"),
@@ -1001,6 +1036,7 @@ url_manual_mapping = (
("bpy.ops.anim.channels_fcurves_enable*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-fcurves-enable"),
("bpy.ops.anim.channels_setting_toggle*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-setting-toggle"),
("bpy.ops.clip.set_viewport_background*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-set-viewport-background"),
+ ("bpy.ops.geometry.color_attribute_add*", "modeling/meshes/properties/object_data.html#bpy-ops-geometry-color-attribute-add"),
("bpy.ops.gpencil.interpolate_sequence*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-interpolate-sequence"),
("bpy.ops.mesh.normals_make_consistent*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-mesh-normals-make-consistent"),
("bpy.ops.mesh.offset_edge_loops_slide*", "modeling/meshes/editing/edge/offset_edge_slide.html#bpy-ops-mesh-offset-edge-loops-slide"),
@@ -1031,6 +1067,7 @@ url_manual_mapping = (
("bpy.types.compositornodecolorbalance*", "compositing/types/color/color_balance.html#bpy-types-compositornodecolorbalance"),
("bpy.types.compositornodekeyingscreen*", "compositing/types/matte/keying_screen.html#bpy-types-compositornodekeyingscreen"),
("bpy.types.dynamicpaintcanvassettings*", "physics/dynamic_paint/canvas.html#bpy-types-dynamicpaintcanvassettings"),
+ ("bpy.types.ffmpegsettings.audio_codec*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio-codec"),
("bpy.types.fileselectparams.directory*", "editors/file_browser.html#bpy-types-fileselectparams-directory"),
("bpy.types.fluidflowsettings.use_flow*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-use-flow"),
("bpy.types.fmodifierfunctiongenerator*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierfunctiongenerator"),
@@ -1038,6 +1075,7 @@ url_manual_mapping = (
("bpy.types.geometrynodedeletegeometry*", "modeling/geometry_nodes/geometry/delete_geometry.html#bpy-types-geometrynodedeletegeometry"),
("bpy.types.geometrynodeinputcurvetilt*", "modeling/geometry_nodes/curve/curve_tilt.html#bpy-types-geometrynodeinputcurvetilt"),
("bpy.types.geometrynodeinputscenetime*", "modeling/geometry_nodes/input/scene_time.html#bpy-types-geometrynodeinputscenetime"),
+ ("bpy.types.geometrynodenamedattribute*", "modeling/geometry_nodes/input/named_attribute.html#bpy-types-geometrynodenamedattribute"),
("bpy.types.geometrynodepointstovolume*", "modeling/geometry_nodes/point/points_to_volume.html#bpy-types-geometrynodepointstovolume"),
("bpy.types.geometrynodescaleinstances*", "modeling/geometry_nodes/instances/scale_instances.html#bpy-types-geometrynodescaleinstances"),
("bpy.types.geometrynodesetcurveradius*", "modeling/geometry_nodes/curve/set_curve_radius.html#bpy-types-geometrynodesetcurveradius"),
@@ -1067,6 +1105,7 @@ url_manual_mapping = (
("bpy.types.spaceuveditor.show_stretch*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-stretch"),
("bpy.types.toolsettings.keyframe_type*", "editors/timeline.html#bpy-types-toolsettings-keyframe-type"),
("bpy.types.toolsettings.snap_elements*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-snap-elements"),
+ ("bpy.types.toolsettings.use_snap_node*", "interface/controls/nodes/arranging.html#bpy-types-toolsettings-use-snap-node"),
("bpy.types.toolsettings.use_snap_self*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-self"),
("bpy.types.viewlayer.active_aov_index*", "render/layers/passes.html#bpy-types-viewlayer-active-aov-index"),
("bpy.ops.anim.channels_enable_toggle*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-enable-toggle"),
@@ -1086,6 +1125,7 @@ url_manual_mapping = (
("bpy.ops.object.material_slot_assign*", "render/materials/assignment.html#bpy-ops-object-material-slot-assign"),
("bpy.ops.object.material_slot_select*", "render/materials/assignment.html#bpy-ops-object-material-slot-select"),
("bpy.ops.object.multires_unsubdivide*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-unsubdivide"),
+ ("bpy.ops.object.parent_inverse_apply*", "scene_layout/object/editing/apply.html#bpy-ops-object-parent-inverse-apply"),
("bpy.ops.object.paths_update_visible*", "animation/motion_paths.html#bpy-ops-object-paths-update-visible"),
("bpy.ops.object.transforms_to_deltas*", "scene_layout/object/editing/apply.html#bpy-ops-object-transforms-to-deltas"),
("bpy.ops.outliner.collection_disable*", "editors/outliner/editing.html#bpy-ops-outliner-collection-disable"),
@@ -1116,6 +1156,8 @@ url_manual_mapping = (
("bpy.types.cyclesrendersettings.seed*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-seed"),
("bpy.types.dynamicpaintbrushsettings*", "physics/dynamic_paint/brush.html#bpy-types-dynamicpaintbrushsettings"),
("bpy.types.editbone.use_scale_easing*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-use-scale-easing"),
+ ("bpy.types.ffmpegsettings.buffersize*", "render/output/properties/output.html#bpy-types-ffmpegsettings-buffersize"),
+ ("bpy.types.ffmpegsettings.packetsize*", "render/output/properties/output.html#bpy-types-ffmpegsettings-packetsize"),
("bpy.types.fileselectparams.filename*", "editors/file_browser.html#bpy-types-fileselectparams-filename"),
("bpy.types.fluiddomainsettings.alpha*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-alpha"),
("bpy.types.fluidflowsettings.density*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-density"),
@@ -1135,6 +1177,7 @@ url_manual_mapping = (
("bpy.types.greasepencil.pixel_factor*", "grease_pencil/properties/strokes.html#bpy-types-greasepencil-pixel-factor"),
("bpy.types.keyframe.handle_left_type*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-handle-left-type"),
("bpy.types.light.use_custom_distance*", "render/eevee/lighting.html#bpy-types-light-use-custom-distance"),
+ ("bpy.types.material.refraction_depth*", "render/eevee/materials/settings.html#bpy-types-material-refraction-depth"),
("bpy.types.materialgpencilstyle.flip*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-flip"),
("bpy.types.materialgpencilstyle.mode*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-mode"),
("bpy.types.meshsequencecachemodifier*", "modeling/modifiers/modify/mesh_sequence_cache.html#bpy-types-meshsequencecachemodifier"),
@@ -1197,6 +1240,7 @@ url_manual_mapping = (
("bpy.ops.sequencer.export_subtitles*", "editors/video_sequencer/preview/header.html#bpy-ops-sequencer-export-subtitles"),
("bpy.ops.transform.edge_bevelweight*", "modeling/meshes/editing/edge/edge_data.html#bpy-ops-transform-edge-bevelweight"),
("bpy.ops.wm.previews_batch_generate*", "files/blend/previews.html#bpy-ops-wm-previews-batch-generate"),
+ ("bpy.types.animvizmotionpaths.range*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-range"),
("bpy.types.assetmetadata.active_tag*", "editors/asset_browser.html#bpy-types-assetmetadata-active-tag"),
("bpy.types.bakesettings.cage_object*", "render/cycles/baking.html#bpy-types-bakesettings-cage-object"),
("bpy.types.bakesettings.margin_type*", "render/cycles/baking.html#bpy-types-bakesettings-margin-type"),
@@ -1243,6 +1287,7 @@ url_manual_mapping = (
("bpy.types.imagepaint.interpolation*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-types-imagepaint-interpolation"),
("bpy.types.linestyle*modifier_noise*", "render/freestyle/view_layer/line_style/modifiers/color/noise.html#bpy-types-linestyle-modifier-noise"),
("bpy.types.maintainvolumeconstraint*", "animation/constraints/transform/maintain_volume.html#bpy-types-maintainvolumeconstraint"),
+ ("bpy.types.material.alpha_threshold*", "render/eevee/materials/settings.html#bpy-types-material-alpha-threshold"),
("bpy.types.mesh.use_mirror_topology*", "modeling/meshes/tools/tool_settings.html#bpy-types-mesh-use-mirror-topology"),
("bpy.types.movieclip.display_aspect*", "editors/clip/display/clip_display.html#bpy-types-movieclip-display-aspect"),
("bpy.types.nodesocketinterface.name*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-name"),
@@ -1251,6 +1296,7 @@ url_manual_mapping = (
("bpy.types.rendersettings.hair_type*", "render/eevee/render_settings/hair.html#bpy-types-rendersettings-hair-type"),
("bpy.types.rendersettings.tile_size*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-tile-size"),
("bpy.types.sequencertimelineoverlay*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay"),
+ ("bpy.types.sequencetransform.filter*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-sequencetransform-filter"),
("bpy.types.sequencetransform.offset*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-sequencetransform-offset"),
("bpy.types.shadernodebrightcontrast*", "render/shader_nodes/color/bright_contrast.html#bpy-types-shadernodebrightcontrast"),
("bpy.types.shadernodebsdfprincipled*", "render/shader_nodes/shader/principled.html#bpy-types-shadernodebsdfprincipled"),
@@ -1368,6 +1414,7 @@ url_manual_mapping = (
("bpy.types.rigidbodyobject.enabled*", "physics/rigid_body/properties/settings.html#bpy-types-rigidbodyobject-enabled"),
("bpy.types.sceneeevee.use_overscan*", "render/eevee/render_settings/film.html#bpy-types-sceneeevee-use-overscan"),
("bpy.types.sequencerpreviewoverlay*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay"),
+ ("bpy.types.sequencetimelinechannel*", "editors/video_sequencer/sequencer/channels.html#bpy-types-sequencetimelinechannel"),
("bpy.types.sequencetransform.scale*", "editors/video_sequencer/sequencer/sidebar/strip.html#bpy-types-sequencetransform-scale"),
("bpy.types.shadernodeeeveespecular*", "render/shader_nodes/shader/specular_bsdf.html#bpy-types-shadernodeeeveespecular"),
("bpy.types.shadernodehuesaturation*", "render/shader_nodes/color/hue_saturation.html#bpy-types-shadernodehuesaturation"),
@@ -1453,6 +1500,10 @@ url_manual_mapping = (
("bpy.types.editbone.bbone_rollout*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-rollout"),
("bpy.types.editbone.bbone_scalein*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-scalein"),
("bpy.types.editbone.inherit_scale*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-inherit-scale"),
+ ("bpy.types.ffmpegsettings.gopsize*", "render/output/properties/output.html#bpy-types-ffmpegsettings-gopsize"),
+ ("bpy.types.ffmpegsettings.maxrate*", "render/output/properties/output.html#bpy-types-ffmpegsettings-maxrate"),
+ ("bpy.types.ffmpegsettings.minrate*", "render/output/properties/output.html#bpy-types-ffmpegsettings-minrate"),
+ ("bpy.types.ffmpegsettings.muxrate*", "render/output/properties/output.html#bpy-types-ffmpegsettings-muxrate"),
("bpy.types.freestylelinestyle.gap*", "render/freestyle/view_layer/line_style/strokes.html#bpy-types-freestylelinestyle-gap"),
("bpy.types.freestylesettings.mode*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-mode"),
("bpy.types.functionnodefloattoint*", "modeling/geometry_nodes/utilities/float_to_integer.html#bpy-types-functionnodefloattoint"),
@@ -1472,7 +1523,9 @@ url_manual_mapping = (
("bpy.types.keyframe.interpolation*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-interpolation"),
("bpy.types.latticegpencilmodifier*", "grease_pencil/modifiers/deform/lattice.html#bpy-types-latticegpencilmodifier"),
("bpy.types.lineartgpencilmodifier*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier"),
+ ("bpy.types.material.diffuse_color*", "render/materials/settings.html#bpy-types-material-diffuse-color"),
("bpy.types.material.line_priority*", "render/freestyle/material.html#bpy-types-material-line-priority"),
+ ("bpy.types.material.shadow_method*", "render/eevee/materials/settings.html#bpy-types-material-shadow-method"),
("bpy.types.mesh.auto_smooth_angle*", "modeling/meshes/structure.html#bpy-types-mesh-auto-smooth-angle"),
("bpy.types.modifier.show_viewport*", "modeling/modifiers/introduction.html#bpy-types-modifier-show-viewport"),
("bpy.types.motionpath.frame_start*", "animation/motion_paths.html#bpy-types-motionpath-frame-start"),
@@ -1516,6 +1569,7 @@ url_manual_mapping = (
("bpy.ops.graph.snap_cursor_value*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-snap-cursor-value"),
("bpy.ops.image.save_all_modified*", "editors/image/editing.html#bpy-ops-image-save-all-modified"),
("bpy.ops.marker.make_links_scene*", "animation/markers.html#bpy-ops-marker-make-links-scene"),
+ ("bpy.ops.marker.select_leftright*", "animation/markers.html#bpy-ops-marker-select-leftright"),
("bpy.ops.mesh.extrude_edges_move*", "modeling/meshes/editing/edge/extrude_edges.html#bpy-ops-mesh-extrude-edges-move"),
("bpy.ops.mesh.extrude_faces_move*", "modeling/meshes/editing/face/extrude_individual_faces.html#bpy-ops-mesh-extrude-faces-move"),
("bpy.ops.mesh.faces_shade_smooth*", "modeling/meshes/editing/face/shading.html#bpy-ops-mesh-faces-shade-smooth"),
@@ -1551,6 +1605,7 @@ url_manual_mapping = (
("bpy.ops.transform.rotate_normal*", "modeling/meshes/editing/mesh/normals.html#bpy-ops-transform-rotate-normal"),
("bpy.ops.transform.shrink_fatten*", "modeling/meshes/editing/mesh/transform/shrink-fatten.html#bpy-ops-transform-shrink-fatten"),
("bpy.ops.transform.vertex_random*", "modeling/meshes/editing/mesh/transform/randomize.html#bpy-ops-transform-vertex-random"),
+ ("bpy.ops.ui.reset_default_button*", "interface/controls/buttons/menus.html#bpy-ops-ui-reset-default-button"),
("bpy.ops.uv.shortest_path_select*", "editors/uv/selecting.html#bpy-ops-uv-shortest-path-select"),
("bpy.ops.wm.operator_cheat_sheet*", "advanced/operators.html#bpy-ops-wm-operator-cheat-sheet"),
("bpy.ops.wm.previews_batch_clear*", "files/blend/previews.html#bpy-ops-wm-previews-batch-clear"),
@@ -1583,6 +1638,7 @@ url_manual_mapping = (
("bpy.types.editbone.bbone_easein*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-easein"),
("bpy.types.editbone.bbone_rollin*", "animation/armatures/bones/properties/bendy_bones.html#bpy-types-editbone-bbone-rollin"),
("bpy.types.fcurve.auto_smoothing*", "editors/graph_editor/fcurves/properties.html#bpy-types-fcurve-auto-smoothing"),
+ ("bpy.types.ffmpegsettings.format*", "render/output/properties/output.html#bpy-types-ffmpegsettings-format"),
("bpy.types.fluideffectorsettings*", "physics/fluid/type/effector.html#bpy-types-fluideffectorsettings"),
("bpy.types.followtrackconstraint*", "animation/constraints/motion_tracking/follow_track.html#bpy-types-followtrackconstraint"),
("bpy.types.functionnodeinputbool*", "modeling/geometry_nodes/input/boolean.html#bpy-types-functionnodeinputbool"),
@@ -1639,6 +1695,7 @@ url_manual_mapping = (
("bpy.ops.geometry.attribute_add*", "modeling/geometry_nodes/attributes_reference.html#bpy-ops-geometry-attribute-add"),
("bpy.ops.gpencil.duplicate_move*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-duplicate-move"),
("bpy.ops.gpencil.stroke_arrange*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-arrange"),
+ ("bpy.ops.graph.blend_to_default*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-blend-to-default"),
("bpy.ops.graph.equalize_handles*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-equalize-handles"),
("bpy.ops.mesh.bridge-edge-loops*", "modeling/meshes/editing/edge/bridge_edge_loops.html#bpy-ops-mesh-bridge-edge-loops"),
("bpy.ops.mesh.intersect_boolean*", "modeling/meshes/editing/face/intersect_boolean.html#bpy-ops-mesh-intersect-boolean"),
@@ -1683,7 +1740,7 @@ url_manual_mapping = (
("bpy.types.datatransfermodifier*", "modeling/modifiers/modify/data_transfer.html#bpy-types-datatransfermodifier"),
("bpy.types.dynamicpaintmodifier*", "physics/dynamic_paint/index.html#bpy-types-dynamicpaintmodifier"),
("bpy.types.editbone.use_connect*", "animation/armatures/bones/properties/relations.html#bpy-types-editbone-use-connect"),
- ("bpy.types.ffmpegsettings.audio*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio"),
+ ("bpy.types.ffmpegsettings.codec*", "render/output/properties/output.html#bpy-types-ffmpegsettings-codec"),
("bpy.types.followpathconstraint*", "animation/constraints/relationship/follow_path.html#bpy-types-followpathconstraint"),
("bpy.types.functionnodeinputint*", "modeling/geometry_nodes/input/integer.html#bpy-types-functionnodeinputint"),
("bpy.types.gaussianblursequence*", "video_editing/edit/montage/strips/effects/blur.html#bpy-types-gaussianblursequence"),
@@ -1823,6 +1880,7 @@ url_manual_mapping = (
("bpy.types.imageformatsettings*", "files/media/image_formats.html#bpy-types-imageformatsettings"),
("bpy.types.kinematicconstraint*", "animation/constraints/tracking/ik_solver.html#bpy-types-kinematicconstraint"),
("bpy.types.material.line_color*", "render/freestyle/material.html#bpy-types-material-line-color"),
+ ("bpy.types.material.pass_index*", "render/materials/settings.html#bpy-types-material-pass-index"),
("bpy.types.mesh.use_paint_mask*", "sculpt_paint/brush/introduction.html#bpy-types-mesh-use-paint-mask"),
("bpy.types.movietrackingcamera*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera"),
("bpy.types.object.display_type*", "scene_layout/object/properties/display.html#bpy-types-object-display-type"),
@@ -1916,6 +1974,7 @@ url_manual_mapping = (
("bpy.ops.transform.edge_slide*", "modeling/meshes/editing/edge/edge_slide.html#bpy-ops-transform-edge-slide"),
("bpy.ops.transform.vert_slide*", "modeling/meshes/editing/vertex/slide_vertices.html#bpy-ops-transform-vert-slide"),
("bpy.ops.uv.project_from_view*", "modeling/meshes/editing/uv.html#bpy-ops-uv-project-from-view"),
+ ("bpy.ops.view3d.view_selected*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-view-selected"),
("bpy.ops.wm.memory_statistics*", "advanced/operators.html#bpy-ops-wm-memory-statistics"),
("bpy.ops.wm.recover_auto_save*", "files/blend/open_save.html#bpy-ops-wm-recover-auto-save"),
("bpy.types.adjustmentsequence*", "video_editing/edit/montage/strips/adjustment.html#bpy-types-adjustmentsequence"),
@@ -1924,7 +1983,7 @@ url_manual_mapping = (
("bpy.types.armature.show_axes*", "animation/armatures/properties/display.html#bpy-types-armature-show-axes"),
("bpy.types.armatureconstraint*", "animation/constraints/relationship/armature.html#bpy-types-armatureconstraint"),
("bpy.types.compositornodeblur*", "compositing/types/filter/blur_node.html#bpy-types-compositornodeblur"),
- ("bpy.types.compositornodecomb*", "editors/texture_node/types/color/combine_separate.html#bpy-types-compositornodecomb"),
+ ("bpy.types.compositornodecomb*", "compositing/types/converter/combine_separate.html#bpy-types-compositornodecomb"),
("bpy.types.compositornodecrop*", "compositing/types/distort/crop.html#bpy-types-compositornodecrop"),
("bpy.types.compositornodeflip*", "compositing/types/distort/flip.html#bpy-types-compositornodeflip"),
("bpy.types.compositornodemask*", "compositing/types/input/mask.html#bpy-types-compositornodemask"),
@@ -1949,6 +2008,7 @@ url_manual_mapping = (
("bpy.types.huecorrectmodifier*", "editors/video_sequencer/sequencer/sidebar/modifiers.html#bpy-types-huecorrectmodifier"),
("bpy.types.image.is_multiview*", "editors/image/image_settings.html#bpy-types-image-is-multiview"),
("bpy.types.imagepaint.stencil*", "sculpt_paint/texture_paint/tool_settings/mask.html#bpy-types-imagepaint-stencil"),
+ ("bpy.types.material.roughness*", "render/materials/settings.html#bpy-types-material-roughness"),
("bpy.types.meshdeformmodifier*", "modeling/modifiers/deform/mesh_deform.html#bpy-types-meshdeformmodifier"),
("bpy.types.movietrackingtrack*", "movie_clip/tracking/clip/sidebar/track/index.html#bpy-types-movietrackingtrack"),
("bpy.types.nodeoutputfileslot*", "compositing/types/output/file.html#bpy-types-nodeoutputfileslot"),
@@ -2056,7 +2116,7 @@ url_manual_mapping = (
("bpy.types.collisionmodifier*", "physics/collision.html#bpy-types-collisionmodifier"),
("bpy.types.collisionsettings*", "physics/collision.html#bpy-types-collisionsettings"),
("bpy.types.compositornodergb*", "compositing/types/input/rgb.html#bpy-types-compositornodergb"),
- ("bpy.types.compositornodesep*", "editors/texture_node/types/color/combine_separate.html#bpy-types-compositornodesep"),
+ ("bpy.types.compositornodesep*", "compositing/types/converter/combine_separate.html#bpy-types-compositornodesep"),
("bpy.types.curve.bevel_depth*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-depth"),
("bpy.types.curve.use_stretch*", "modeling/curves/properties/shape.html#bpy-types-curve-use-stretch"),
("bpy.types.edgesplitmodifier*", "modeling/modifiers/generate/edge_split.html#bpy-types-edgesplitmodifier"),
@@ -2069,6 +2129,7 @@ url_manual_mapping = (
("bpy.types.gpencillayer.hide*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-hide"),
("bpy.types.gpencillayer.lock*", "grease_pencil/properties/layers.html#bpy-types-gpencillayer-lock"),
("bpy.types.imagepaint.dither*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-dither"),
+ ("bpy.types.material.metallic*", "render/materials/settings.html#bpy-types-material-metallic"),
("bpy.types.materialslot.link*", "render/materials/assignment.html#bpy-types-materialslot-link"),
("bpy.types.mesh.texture_mesh*", "modeling/meshes/uv/uv_texture_spaces.html#bpy-types-mesh-texture-mesh"),
("bpy.types.mesh.use_mirror_x*", "modeling/meshes/tools/tool_settings.html#bpy-types-mesh-use-mirror-x"),
@@ -2078,6 +2139,7 @@ url_manual_mapping = (
("bpy.types.movieclipsequence*", "video_editing/edit/montage/strips/clip.html#bpy-types-movieclipsequence"),
("bpy.types.object.dimensions*", "scene_layout/object/properties/transforms.html#bpy-types-object-dimensions"),
("bpy.types.object.is_holdout*", "scene_layout/object/properties/visibility.html#bpy-types-object-is-holdout"),
+ ("bpy.types.object.lightgroup*", "render/cycles/object_settings/object_data.html#bpy-types-object-lightgroup"),
("bpy.types.object.pass_index*", "scene_layout/object/properties/relations.html#bpy-types-object-pass-index"),
("bpy.types.object.track_axis*", "scene_layout/object/properties/relations.html#bpy-types-object-track-axis"),
("bpy.types.pose.use_mirror_x*", "animation/armatures/posing/tool_settings.html#bpy-types-pose-use-mirror-x"),
@@ -2151,12 +2213,13 @@ url_manual_mapping = (
("bpy.ops.sculpt.mask_filter*", "sculpt_paint/sculpting/editing/mask.html#bpy-ops-sculpt-mask-filter"),
("bpy.ops.transform.tosphere*", "modeling/meshes/editing/mesh/transform/to_sphere.html#bpy-ops-transform-tosphere"),
("bpy.ops.view3d.clip_border*", "editors/3dview/navigate/regions.html#bpy-ops-view3d-clip-border"),
+ ("bpy.ops.view3d.zoom_border*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-zoom-border"),
("bpy.ops.wm.previews_ensure*", "files/blend/previews.html#bpy-ops-wm-previews-ensure"),
("bpy.ops.wm.properties_edit*", "files/data_blocks.html#bpy-ops-wm-properties-edit"),
("bpy.ops.wm.search_operator*", "interface/controls/templates/operator_search.html#bpy-ops-wm-search-operator"),
("bpy.types.actionconstraint*", "animation/constraints/relationship/action.html#bpy-types-actionconstraint"),
("bpy.types.addonpreferences*", "editors/preferences/addons.html#bpy-types-addonpreferences"),
- ("bpy.types.arealight.spread*", "render/lights/light_object.html#bpy-types-arealight-spread"),
+ ("bpy.types.arealight.spread*", "render/cycles/light_settings.html#bpy-types-arealight-spread"),
("bpy.types.armaturemodifier*", "modeling/modifiers/deform/armature.html#bpy-types-armaturemodifier"),
("bpy.types.bone.head_radius*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-head-radius"),
("bpy.types.bone.tail_radius*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-tail-radius"),
@@ -2220,7 +2283,7 @@ url_manual_mapping = (
("bpy.types.texturenodegroup*", "editors/texture_node/types/groups.html#bpy-types-texturenodegroup"),
("bpy.types.texturenodeimage*", "editors/texture_node/types/input/image.html#bpy-types-texturenodeimage"),
("bpy.types.texturenodescale*", "editors/texture_node/types/distort/scale.html#bpy-types-texturenodescale"),
- ("bpy.types.viewlayer.use_ao*", "render/layers/introduction.html#bpy-types-viewlayer-use-ao"),
+ ("bpy.types.world.lightgroup*", "render/cycles/world_settings.html#bpy-types-world-lightgroup"),
("bpy.ops.armature.dissolve*", "animation/armatures/bones/editing/delete.html#bpy-ops-armature-dissolve"),
("bpy.ops.armature.separate*", "animation/armatures/bones/editing/separate_bones.html#bpy-ops-armature-separate"),
("bpy.ops.clip.clean_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-clean-tracks"),
@@ -2237,6 +2300,7 @@ url_manual_mapping = (
("bpy.ops.gpencil.reproject*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-reproject"),
("bpy.ops.graph.easing_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-easing-type"),
("bpy.ops.graph.handle_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-handle-type"),
+ ("bpy.ops.marker.select_all*", "animation/markers.html#bpy-ops-marker-select-all"),
("bpy.ops.mask.parent_clear*", "movie_clip/masking/editing.html#bpy-ops-mask-parent-clear"),
("bpy.ops.mask.select_lasso*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-lasso"),
("bpy.ops.mesh.bevel.vertex*", "modeling/meshes/editing/vertex/bevel_vertices.html#bpy-ops-mesh-bevel-vertex"),
@@ -2296,6 +2360,7 @@ url_manual_mapping = (
("bpy.types.preferencesview*", "editors/preferences/interface.html#bpy-types-preferencesview"),
("bpy.types.rigidbodyobject*", "physics/rigid_body/index.html#bpy-types-rigidbodyobject"),
("bpy.types.scene.frame_end*", "render/output/properties/frame_range.html#bpy-types-scene-frame-end"),
+ ("bpy.types.scene.sync_mode*", "editors/timeline.html#bpy-types-scene-sync-mode"),
("bpy.types.sceneeevee.gtao*", "render/eevee/render_settings/ambient_occlusion.html#bpy-types-sceneeevee-gtao"),
("bpy.types.screen.use_play*", "editors/timeline.html#bpy-types-screen-use-play"),
("bpy.types.shadernodebevel*", "render/shader_nodes/input/bevel.html#bpy-types-shadernodebevel"),
@@ -2351,6 +2416,7 @@ url_manual_mapping = (
("bpy.ops.uv.snap_selected*", "modeling/meshes/uv/editing.html#bpy-ops-uv-snap-selected"),
("bpy.ops.view3d.localview*", "editors/3dview/navigate/local_view.html#bpy-ops-view3d-localview"),
("bpy.ops.view3d.view_axis*", "editors/3dview/navigate/viewpoint.html#bpy-ops-view3d-view-axis"),
+ ("bpy.ops.view3d.view_roll*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-view-roll"),
("bpy.ops.wm.open_mainfile*", "files/blend/open_save.html#bpy-ops-wm-open-mainfile"),
("bpy.ops.wm.owner_disable*", "interface/window_system/workspaces.html#bpy-ops-wm-owner-disable"),
("bpy.ops.wm.save_mainfile*", "files/blend/open_save.html#bpy-ops-wm-save-mainfile"),
@@ -2430,6 +2496,7 @@ url_manual_mapping = (
("bpy.ops.uv.cube_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-cube-project"),
("bpy.ops.uv.pack_islands*", "modeling/meshes/uv/editing.html#bpy-ops-uv-pack-islands"),
("bpy.ops.uv.select_split*", "modeling/meshes/uv/editing.html#bpy-ops-uv-select-split"),
+ ("bpy.ops.view3d.view_all*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-view-all"),
("bpy.ops.view3d.view_pan*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-view-pan"),
("bpy.ops.wm.app_template*", "advanced/app_templates.html#bpy-ops-wm-app-template"),
("bpy.ops.wm.batch_rename*", "files/blend/rename.html#bpy-ops-wm-batch-rename"),
@@ -2523,6 +2590,7 @@ url_manual_mapping = (
("bpy.ops.sequencer.swap*", "video_editing/edit/montage/editing.html#bpy-ops-sequencer-swap"),
("bpy.ops.transform.bend*", "modeling/meshes/editing/mesh/transform/bend.html#bpy-ops-transform-bend"),
("bpy.ops.transform.tilt*", "modeling/curves/editing/control_points.html#bpy-ops-transform-tilt"),
+ ("bpy.ops.uv.select_mode*", "editors/uv/selecting.html#bpy-ops-uv-select-mode"),
("bpy.ops.uv.snap_cursor*", "modeling/meshes/uv/editing.html#bpy-ops-uv-snap-cursor"),
("bpy.ops.wm.search_menu*", "interface/controls/templates/operator_search.html#bpy-ops-wm-search-menu"),
("bpy.types.bakesettings*", "render/cycles/baking.html#bpy-types-bakesettings"),
@@ -2575,7 +2643,6 @@ url_manual_mapping = (
("bpy.ops.image.replace*", "editors/image/editing.html#bpy-ops-image-replace"),
("bpy.ops.image.save_as*", "editors/image/editing.html#bpy-ops-image-save-as"),
("bpy.ops.marker.delete*", "animation/markers.html#bpy-ops-marker-delete"),
- ("bpy.ops.marker.rename*", "animation/markers.html#bpy-ops-marker-rename"),
("bpy.ops.marker.select*", "animation/markers.html#bpy-ops-marker-select"),
("bpy.ops.material.copy*", "render/materials/assignment.html#bpy-ops-material-copy"),
("bpy.ops.mesh.decimate*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-decimate"),
@@ -2594,6 +2661,7 @@ url_manual_mapping = (
("bpy.ops.view3d.select*", "editors/3dview/selecting.html#bpy-ops-view3d-select"),
("bpy.ops.wm.debug_menu*", "advanced/operators.html#bpy-ops-wm-debug-menu"),
("bpy.ops.wm.obj_export*", "files/import_export/obj.html#bpy-ops-wm-obj-export"),
+ ("bpy.ops.wm.obj_import*", "files/import_export/obj.html#bpy-ops-wm-obj-import"),
("bpy.ops.wm.properties*", "files/data_blocks.html#bpy-ops-wm-properties"),
("bpy.ops.wm.usd_export*", "files/import_export/usd.html#bpy-ops-wm-usd-export"),
("bpy.types.addsequence*", "video_editing/edit/montage/strips/effects/add.html#bpy-types-addsequence"),
@@ -2642,6 +2710,7 @@ url_manual_mapping = (
("bpy.ops.object.quick*", "physics/introduction.html#bpy-ops-object-quick"),
("bpy.ops.text.replace*", "editors/text_editor.html#bpy-ops-text-replace"),
("bpy.ops.uv.mark_seam*", "modeling/meshes/uv/unwrapping/seams.html#bpy-ops-uv-mark-seam"),
+ ("bpy.ops.view3d.dolly*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-dolly"),
("bpy.ops.view3d.ruler*", "editors/3dview/toolbar/measure.html#bpy-ops-view3d-ruler"),
("bpy.types.areaspaces*", "interface/window_system/areas.html#bpy-types-areaspaces"),
("bpy.types.bonegroups*", "animation/armatures/properties/bone_groups.html#bpy-types-bonegroups"),
@@ -2738,6 +2807,7 @@ url_manual_mapping = (
("bpy.types.facemaps*", "modeling/meshes/properties/object_data.html#bpy-types-facemaps"),
("bpy.types.keyframe*", "animation/keyframes/index.html#bpy-types-keyframe"),
("bpy.types.linesets*", "render/freestyle/view_layer/line_set.html#bpy-types-linesets"),
+ ("bpy.types.material*", "render/materials/index.html#bpy-types-material"),
("bpy.types.metaball*", "modeling/metas/index.html#bpy-types-metaball"),
("bpy.types.modifier*", "modeling/modifiers/index.html#bpy-types-modifier"),
("bpy.types.nlastrip*", "editors/nla/strips.html#bpy-types-nlastrip"),
@@ -2751,6 +2821,7 @@ url_manual_mapping = (
("bpy.types.spacenla*", "editors/nla/index.html#bpy-types-spacenla"),
("bpy.types.sunlight*", "render/lights/light_object.html#bpy-types-sunlight"),
("bpy.ops.clip.open*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-open"),
+ ("bpy.ops.curve.pen*", "modeling/curves/tools/pen.html#bpy-ops-curve-pen"),
("bpy.ops.file.next*", "editors/file_browser.html#bpy-ops-file-next"),
("bpy.ops.image.new*", "editors/image/editing.html#bpy-ops-image-new"),
("bpy.ops.mesh.fill*", "modeling/meshes/editing/face/fill.html#bpy-ops-mesh-fill"),
@@ -2776,7 +2847,7 @@ url_manual_mapping = (
("bpy.ops.armature*", "animation/armatures/index.html#bpy-ops-armature"),
("bpy.ops.geometry*", "modeling/index.html#bpy-ops-geometry"),
("bpy.ops.material*", "render/materials/index.html#bpy-ops-material"),
- ("bpy.ops.nla.bake*", "animation/actions.html#bpy-ops-nla-bake"),
+ ("bpy.ops.nla.bake*", "editors/nla/editing.html#bpy-ops-nla-bake"),
("bpy.ops.nla.snap*", "editors/nla/editing.html#bpy-ops-nla-snap"),
("bpy.ops.nla.swap*", "editors/nla/editing.html#bpy-ops-nla-swap"),
("bpy.ops.outliner*", "editors/outliner/index.html#bpy-ops-outliner"),
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index a6842dc0005..8b8cfaaccc5 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from mathutils import Vector
diff --git a/release/scripts/modules/rna_xml.py b/release/scripts/modules/rna_xml.py
index d576aeec860..9e3e1a3430b 100644
--- a/release/scripts/modules/rna_xml.py
+++ b/release/scripts/modules/rna_xml.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py
index 80f518e4aee..a5bae1b97af 100644
--- a/release/scripts/modules/sys_info.py
+++ b/release/scripts/modules/sys_info.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# classes for extracting info from blenders internal classes
diff --git a/release/scripts/presets/cycles/performance/Default.py b/release/scripts/presets/cycles/performance/Default.py
new file mode 100644
index 00000000000..5c25f23eca0
--- /dev/null
+++ b/release/scripts/presets/cycles/performance/Default.py
@@ -0,0 +1,12 @@
+import bpy
+render = bpy.context.scene.render
+cycles = bpy.context.scene.cycles
+
+render.threads_mode = 'AUTO'
+render.use_persistent_data = False
+cycles.debug_use_spatial_splits = False
+cycles.debug_use_compact_bvh = False
+cycles.debug_use_hair_bvh = True
+cycles.debug_bvh_time_steps = 0
+cycles.use_auto_tile = True
+cycles.tile_size = 2048
diff --git a/release/scripts/presets/cycles/performance/Faster_Render.py b/release/scripts/presets/cycles/performance/Faster_Render.py
new file mode 100644
index 00000000000..7f1e3c68f1f
--- /dev/null
+++ b/release/scripts/presets/cycles/performance/Faster_Render.py
@@ -0,0 +1,12 @@
+import bpy
+render = bpy.context.scene.render
+cycles = bpy.context.scene.cycles
+
+render.threads_mode = 'AUTO'
+render.use_persistent_data = True
+cycles.debug_use_spatial_splits = True
+cycles.debug_use_compact_bvh = False
+cycles.debug_use_hair_bvh = True
+cycles.debug_bvh_time_steps = 2
+cycles.use_auto_tile = True
+cycles.tile_size = 2048
diff --git a/release/scripts/presets/cycles/performance/Lower_Memory.py b/release/scripts/presets/cycles/performance/Lower_Memory.py
new file mode 100644
index 00000000000..d1a45f1888d
--- /dev/null
+++ b/release/scripts/presets/cycles/performance/Lower_Memory.py
@@ -0,0 +1,12 @@
+import bpy
+render = bpy.context.scene.render
+cycles = bpy.context.scene.cycles
+
+render.threads_mode = 'AUTO'
+render.use_persistent_data = False
+cycles.debug_use_spatial_splits = False
+cycles.debug_use_compact_bvh = True
+cycles.debug_use_hair_bvh = True
+cycles.debug_bvh_time_steps = 0
+cycles.use_auto_tile = True
+cycles.tile_size = 512
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index a4bac916946..f5f71e414d6 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -463,6 +463,7 @@ def _template_items_tool_select(
# Always use the cursor operator where possible,
# needed for time-line views where we always want to be able to scrub time.
cursor_prioritize=False,
+ operator_props=(),
fallback=False,
):
if not params.legacy and not fallback:
@@ -479,11 +480,11 @@ def _template_items_tool_select(
if select_passthrough:
return [
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS'},
- {"properties": [("deselect_all", True), ("select_passthrough", True)]}),
+ {"properties": [("deselect_all", True), ("select_passthrough", True), *operator_props]}),
(operator, {"type": 'LEFTMOUSE', "value": 'CLICK'},
- {"properties": [("deselect_all", True)]}),
+ {"properties": [("deselect_all", True), *operator_props]}),
(operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
- {"properties": [("deselect_all", False), ("toggle", True)]}),
+ {"properties": [("deselect_all", False), ("toggle", True), *operator_props]}),
("transform.translate", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
{"properties": [("release_confirm", True)]}),
]
@@ -497,9 +498,9 @@ def _template_items_tool_select(
# the tool without selecting elements under the cursor.
return [
(operator, {"type": 'LEFTMOUSE', "value": 'CLICK' if fallback else 'PRESS'},
- {"properties": [("deselect_all", True)]}),
+ {"properties": [("deselect_all", True), *operator_props]}),
(operator, {"type": 'LEFTMOUSE', "value": 'CLICK' if fallback else 'PRESS', "shift": True},
- {"properties": [("toggle", True)]}),
+ {"properties": [("toggle", True), *operator_props]}),
# Fallback key-map must transform as the primary tool is expected
# to be accessed via gizmos in this case. See: T96885.
@@ -1026,7 +1027,7 @@ def km_markers(params):
("marker.select_box", {"type": 'B', "value": 'PRESS'}, None),
*_template_items_select_actions(params, "marker.select_all"),
("marker.delete", {"type": 'X', "value": 'PRESS'}, None),
- ("marker.delete", {"type": 'DEL', "value": 'PRESS'}, None),
+ ("marker.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("confirm", False)]}),
op_panel("TOPBAR_PT_name_marker", {"type": 'F2', "value": 'PRESS'}, [("keep_open", False)]),
("marker.move", {"type": 'G', "value": 'PRESS'}, None),
("marker.camera_bind", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
@@ -1264,6 +1265,7 @@ def km_uv_editor(params):
{"properties": [("deselect", True)]}),
("uv.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
("uv.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
+ ("uv.select_similar", {"type": 'G', "value": 'PRESS', "shift": True}, None),
*_template_items_select_actions(params, "uv.select_all"),
*_template_items_hide_reveal_actions("uv.hide", "uv.reveal"),
("uv.select_pinned", {"type": 'P', "value": 'PRESS', "shift": True}, None),
@@ -2221,6 +2223,7 @@ def km_file_browser(params):
("file.smoothscroll", {"type": 'TIMER1', "value": 'ANY', "any": True}, None),
("file.bookmark_add", {"type": 'B', "value": 'PRESS', "ctrl": True}, None),
("file.start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
+ ("file.edit_directory_path", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "repeat": True},
{"properties": [("increment", 1)]}),
("file.filenum", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "shift": True, "repeat": True},
@@ -2596,10 +2599,8 @@ def km_nla_editor(params):
("nla.soundclip_add", {"type": 'K', "value": 'PRESS', "shift": True}, None),
("nla.meta_add", {"type": 'G', "value": 'PRESS', "ctrl": True}, None),
("nla.meta_remove", {"type": 'G', "value": 'PRESS', "ctrl": True, "alt": True}, None),
- ("nla.duplicate", {"type": 'D', "value": 'PRESS', "shift": True},
- {"properties": [("linked", False)]}),
- ("nla.duplicate", {"type": 'D', "value": 'PRESS', "alt": True},
- {"properties": [("linked", True)]}),
+ ("nla.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
+ ("nla.duplicate_linked_move", {"type": 'D', "value": 'PRESS', "alt": True}, None),
("nla.make_single_user", {"type": 'U', "value": 'PRESS'}, None),
("nla.delete", {"type": 'X', "value": 'PRESS'}, None),
("nla.delete", {"type": 'DEL', "value": 'PRESS'}, None),
@@ -3033,7 +3034,7 @@ def km_sequencerpreview(params):
return keymap
-def km_sequencer_channels(params):
+def km_sequencer_channels(_params):
items = []
keymap = (
"Sequencer Channels",
@@ -4415,7 +4416,7 @@ def km_face_mask(params):
items.extend([
*_template_items_select_actions(params, "paint.face_select_all"),
- *_template_items_hide_reveal_actions("paint.face_select_hide", "paint.face_select_reveal"),
+ *_template_items_hide_reveal_actions("paint.face_select_hide", "paint.face_vert_reveal"),
("paint.face_select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("paint.face_select_linked_pick", {"type": 'L', "value": 'PRESS'},
{"properties": [("deselect", False)]}),
@@ -4436,6 +4437,7 @@ def km_weight_paint_vertex_selection(params):
items.extend([
*_template_items_select_actions(params, "paint.vert_select_all"),
+ *_template_items_hide_reveal_actions("paint.vert_select_hide", "paint.face_vert_reveal"),
("view3d.select_box", {"type": 'B', "value": 'PRESS'}, None),
("view3d.select_lasso", {"type": params.action_mouse, "value": 'CLICK_DRAG', "ctrl": True},
{"properties": [("mode", 'ADD')]}),
@@ -4741,6 +4743,10 @@ def _template_view3d_select(*, type, value, legacy, select_passthrough, exclude_
# NOTE: `exclude_mod` is needed since we don't want this tool to exclude Control-RMB actions when this is used
# as a tool key-map with RMB-select and `use_fallback_tool_rmb` is enabled. See T92467.
+ props_vert_without_handles = ()
+ if select_passthrough:
+ props_vert_without_handles = ("vert_without_handles",)
+
# See: `use_tweak_select_passthrough` doc-string.
if select_passthrough and (value in {'CLICK', 'RELEASE'}):
select_passthrough = False
@@ -4750,9 +4756,9 @@ def _template_view3d_select(*, type, value, legacy, select_passthrough, exclude_
{"type": type, "value": value, **{m: True for m in mods}},
{"properties": [(c, True) for c in props]},
) for props, mods in (
- ((("deselect_all", "select_passthrough") if select_passthrough else
- ("deselect_all",)) if not legacy else (), ()),
- (("toggle",), ("shift",)),
+ ((("deselect_all", "select_passthrough", *props_vert_without_handles) if select_passthrough else
+ ("deselect_all", *props_vert_without_handles)) if not legacy else (), ()),
+ (("toggle", *props_vert_without_handles), ("shift",)),
(("center", "object"), ("ctrl",)),
(("enumerate",), ("alt",)),
(("toggle", "center"), ("shift", "ctrl")),
@@ -4767,7 +4773,10 @@ def _template_view3d_select(*, type, value, legacy, select_passthrough, exclude_
items.append((
"view3d.select",
{"type": type, "value": 'CLICK'},
- {"properties": [("deselect_all", True)]},
+ {"properties": [
+ (c, True)
+ for c in ("deselect_all", *props_vert_without_handles)
+ ]},
))
return items
@@ -4979,6 +4988,7 @@ def km_vertex_paint(params):
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
("wm.context_menu_enum", {"type": 'E', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.vertex_paint.brush.stroke_method')]}),
+ ("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
*_template_items_context_panel("VIEW3D_PT_paint_vertex_context_menu", params.context_menu_event),
])
@@ -5026,6 +5036,7 @@ def km_weight_paint(params):
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.weight_paint.brush.use_smooth_stroke')]}),
op_menu_pie("VIEW3D_MT_wpaint_vgroup_lock_pie", {"type": 'K', "value": 'PRESS'}),
+ ("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
*_template_items_context_panel("VIEW3D_PT_paint_weight_context_menu", params.context_menu_event),
])
@@ -5602,6 +5613,18 @@ def km_font(params):
return keymap
+# Curves edit mode.
+def km_curves(params):
+ items = []
+ keymap = (
+ "Curves",
+ {"space_type": 'EMPTY', "region_type": 'WINDOW'},
+ {"items": items},
+ )
+
+ return keymap
+
+
def km_sculpt_curves(params):
items = []
keymap = (
@@ -5615,7 +5638,16 @@ def km_sculpt_curves(params):
{"properties": [("mode", 'NORMAL')]}),
("sculpt_curves.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
{"properties": [("mode", 'INVERT')]}),
+ ("sculpt_curves.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+ {"properties": [("mode", 'SMOOTH')]}),
+ ("curves.set_selection_domain", {"type": 'ONE', "value": 'PRESS'}, {"properties": [("domain", 'POINT')]}),
+ ("curves.set_selection_domain", {"type": 'TWO', "value": 'PRESS'}, {"properties": [("domain", 'CURVE')]}),
+ ("curves.disable_selection", {"type": 'ONE', "value": 'PRESS', "alt": True}, None),
+ ("curves.disable_selection", {"type": 'TWO', "value": 'PRESS', "alt": True}, None),
*_template_paint_radial_control("curves_sculpt"),
+ *_template_items_select_actions(params, "sculpt_curves.select_all"),
+ ("sculpt_curves.min_distance_edit", {"type": 'R', "value": 'PRESS', "shift": True}, {}),
+ ("sculpt_curves.select_grow", {"type": 'A', "value": 'PRESS', "shift": True}, {}),
])
return keymap
@@ -5930,6 +5962,8 @@ def km_standard_modal_map(_params):
("APPLY", {"type": 'NUMPAD_ENTER', "value": 'PRESS', "any": True}, None),
("SNAP", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None),
("SNAP_OFF", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None),
+ ("SNAP", {"type": 'RIGHT_CTRL', "value": 'PRESS', "any": True}, None),
+ ("SNAP_OFF", {"type": 'RIGHT_CTRL', "value": 'RELEASE', "any": True}, None),
])
return keymap
@@ -6076,10 +6110,16 @@ def km_view3d_fly_modal(_params):
("AXIS_LOCK_Z", {"type": 'Z', "value": 'PRESS'}, None),
("PRECISION_ENABLE", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("PRECISION_DISABLE", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
+ ("PRECISION_ENABLE", {"type": 'RIGHT_ALT', "value": 'PRESS', "any": True}, None),
+ ("PRECISION_DISABLE", {"type": 'RIGHT_ALT', "value": 'RELEASE', "any": True}, None),
("PRECISION_ENABLE", {"type": 'LEFT_SHIFT', "value": 'PRESS', "any": True}, None),
("PRECISION_DISABLE", {"type": 'LEFT_SHIFT', "value": 'RELEASE', "any": True}, None),
+ ("PRECISION_ENABLE", {"type": 'RIGHT_SHIFT', "value": 'PRESS', "any": True}, None),
+ ("PRECISION_DISABLE", {"type": 'RIGHT_SHIFT', "value": 'RELEASE', "any": True}, None),
("FREELOOK_ENABLE", {"type": 'LEFT_CTRL', "value": 'PRESS', "any": True}, None),
("FREELOOK_DISABLE", {"type": 'LEFT_CTRL', "value": 'RELEASE', "any": True}, None),
+ ("FREELOOK_ENABLE", {"type": 'RIGHT_CTRL', "value": 'PRESS', "any": True}, None),
+ ("FREELOOK_DISABLE", {"type": 'RIGHT_CTRL', "value": 'RELEASE', "any": True}, None),
])
return keymap
@@ -6101,8 +6141,12 @@ def km_view3d_walk_modal(_params):
("CONFIRM", {"type": 'NUMPAD_ENTER', "value": 'PRESS', "any": True}, None),
("FAST_ENABLE", {"type": 'LEFT_SHIFT', "value": 'PRESS', "any": True}, None),
("FAST_DISABLE", {"type": 'LEFT_SHIFT', "value": 'RELEASE', "any": True}, None),
+ ("FAST_ENABLE", {"type": 'RIGHT_SHIFT', "value": 'PRESS', "any": True}, None),
+ ("FAST_DISABLE", {"type": 'RIGHT_SHIFT', "value": 'RELEASE', "any": True}, None),
("SLOW_ENABLE", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("SLOW_DISABLE", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
+ ("SLOW_ENABLE", {"type": 'RIGHT_ALT', "value": 'PRESS', "any": True}, None),
+ ("SLOW_DISABLE", {"type": 'RIGHT_ALT', "value": 'RELEASE', "any": True}, None),
("FORWARD", {"type": 'W', "value": 'PRESS', "any": True}, None),
("BACKWARD", {"type": 'S', "value": 'PRESS', "any": True}, None),
("LEFT", {"type": 'A', "value": 'PRESS', "any": True}, None),
@@ -6152,6 +6196,8 @@ def km_view3d_rotate_modal(_params):
("CONFIRM", {"type": 'ESC', "value": 'PRESS', "any": True}, None),
("AXIS_SNAP_ENABLE", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
("AXIS_SNAP_DISABLE", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
+ ("AXIS_SNAP_ENABLE", {"type": 'RIGHT_ALT', "value": 'PRESS', "any": True}, None),
+ ("AXIS_SNAP_DISABLE", {"type": 'RIGHT_ALT', "value": 'RELEASE', "any": True}, None),
])
return keymap
@@ -6241,6 +6287,7 @@ def km_sculpt_expand_modal(_params):
*((e, {"type": NUMBERS_1[i], "value": 'PRESS', "any": True}, None) for i, e in enumerate(
("FALLOFF_GEODESICS", "FALLOFF_TOPOLOGY", "FALLOFF_TOPOLOGY_DIAGONALS", "FALLOFF_SPHERICAL"))),
("SNAP_TOGGLE", {"type": 'LEFT_CTRL', "value": 'ANY'}, None),
+ ("SNAP_TOGGLE", {"type": 'RIGHT_CTRL', "value": 'ANY'}, None),
("LOOP_COUNT_INCREASE", {"type": 'W', "value": 'PRESS', "any": True, "repeat": True}, None),
("LOOP_COUNT_DECREASE", {"type": 'Q', "value": 'PRESS', "any": True, "repeat": True}, None),
("BRUSH_GRADIENT_TOGGLE", {"type": 'B', "value": 'PRESS', "any": True}, None),
@@ -6578,7 +6625,10 @@ def km_node_editor_tool_select(params, *, fallback):
_fallback_id("Node Tool: Tweak", fallback),
{"space_type": 'NODE_EDITOR', "region_type": 'WINDOW'},
{"items": [
- *([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else
+ # The node key-map already selects, leave this empty.
+ # NOTE: intentionally don't check `fallback` here (unlike other tweak tool checks).
+ # as this should only be used on LMB select which would otherwise activate on click, not press.
+ *([] if (params.select_mouse == 'RIGHTMOUSE') else
_template_node_select(type=params.select_mouse, value='PRESS', select_passthrough=True)),
]},
)
@@ -6659,12 +6709,17 @@ def km_3d_view_tool_cursor(params):
def km_3d_view_tool_select(params, *, fallback):
+ if params.use_tweak_select_passthrough:
+ operator_props = (("vert_without_handles", True),)
+ else:
+ operator_props = ()
+
return (
_fallback_id("3D View Tool: Tweak", fallback),
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
*([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else _template_items_tool_select(
- params, "view3d.select", "view3d.cursor3d", fallback=fallback)),
+ params, "view3d.select", "view3d.cursor3d", operator_props=operator_props, fallback=fallback)),
*([] if (not params.use_fallback_tool_rmb) else _template_view3d_select(
type=params.select_mouse,
value=params.select_mouse_value,
@@ -7997,6 +8052,7 @@ def generate_keymaps(params=None):
km_lattice(params),
km_particle(params),
km_font(params),
+ km_curves(params),
km_sculpt_curves(params),
km_object_non_modal(params),
diff --git a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
index 1b6abe23897..a052eb7bc34 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -844,7 +844,7 @@ def km_markers(params):
"shift": True}, {"properties": [("action", 'DESELECT')]}),
("marker.select_all", {"type": 'I', "value": 'PRESS', "ctrl": True}, {"properties": [("action", 'INVERT')]}),
("marker.delete", {"type": 'BACK_SPACE', "value": 'PRESS'}, None),
- ("marker.delete", {"type": 'DEL', "value": 'PRESS'}, None),
+ ("marker.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("confirm", False)]}),
op_panel("TOPBAR_PT_name_marker", {"type": 'RET', "value": 'PRESS'}, [("keep_open", False)]),
("marker.move", {"type": 'W', "value": 'PRESS'}, None),
])
@@ -1246,8 +1246,7 @@ def km_file_browser_main(params):
# The two refresh operators have polls excluding each other (so only one is available depending on context).
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("asset.library_refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
- ("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
- ("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
+ ("file.select", {"type": 'LEFTMOUSE', "value": 'PRESS'},
{"properties": [("open", False), ("deselect_all", True)]}),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "ctrl": True},
{"properties": [("extend", True), ("open", False)]}),
@@ -2949,7 +2948,7 @@ def km_face_mask(params):
{"properties": [("unselected", False)]}),
("paint.face_select_hide", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
- ("paint.face_select_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
+ ("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
("paint.face_select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("paint.face_select_linked_pick", {"type": 'L', "value": 'PRESS'},
{"properties": [("deselect", False)]}),
@@ -2970,6 +2969,9 @@ def km_weight_paint_vertex_selection(params):
items.extend([
("paint.vert_select_all", {"type": 'A', "value": 'PRESS', "ctrl": True}, None),
+ ("paint.vert_select_hide", {"type": 'H', "value": 'PRESS', "shift": True},
+ {"properties": [("unselected", True)]}),
+ ("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
])
return keymap
@@ -3331,6 +3333,7 @@ def km_vertex_paint(params):
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.vertex_paint.brush.use_smooth_stroke')]}),
op_menu("VIEW3D_MT_angle_control", {"type": 'R', "value": 'PRESS'}),
+ ("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
*_template_items_context_panel("VIEW3D_PT_paint_vertex_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Tools
("paint.brush_select", {"type": 'D', "value": 'PRESS'},
@@ -3363,6 +3366,7 @@ def km_weight_paint(params):
{"properties": [("data_path", 'weight_paint_object.data.use_paint_mask')]}),
("wm.context_toggle", {"type": 'S', "value": 'PRESS', "shift": True},
{"properties": [("data_path", 'tool_settings.weight_paint.brush.use_smooth_stroke')]}),
+ ("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
*_template_items_context_panel("VIEW3D_PT_paint_weight_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}),
# Bone selection for combined weight paint + pose mode.
("view3d.select", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True}, None),
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index bf7783ef958..14dc72336f6 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from __future__ import annotations
# support reloading sub-modules
diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py
index be5ce60af2f..90d1326e1a2 100644
--- a/release/scripts/startup/bl_operators/add_mesh_torus.py
+++ b/release/scripts/startup/bl_operators/add_mesh_torus.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
import bpy
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index dfe3b3ba57c..539cf838f9c 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
if "bpy" in locals():
diff --git a/release/scripts/startup/bl_operators/assets.py b/release/scripts/startup/bl_operators/assets.py
index eaf44442c8a..088f4189ca5 100644
--- a/release/scripts/startup/bl_operators/assets.py
+++ b/release/scripts/startup/bl_operators/assets.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/release/scripts/startup/bl_operators/bmesh/find_adjacent.py b/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
index 5e8b125e060..a6c4a3169d5 100644
--- a/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
+++ b/release/scripts/startup/bl_operators/bmesh/find_adjacent.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Utilities to detect the next matching element (vert/edge/face)
# based on an existing pair of elements.
diff --git a/release/scripts/startup/bl_operators/clip.py b/release/scripts/startup/bl_operators/clip.py
index 23bf8a5cb60..71617a76243 100644
--- a/release/scripts/startup/bl_operators/clip.py
+++ b/release/scripts/startup/bl_operators/clip.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Operator
from bpy.props import FloatProperty
diff --git a/release/scripts/startup/bl_operators/console.py b/release/scripts/startup/bl_operators/console.py
index 3982f140fec..eb8c4c371c5 100644
--- a/release/scripts/startup/bl_operators/console.py
+++ b/release/scripts/startup/bl_operators/console.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
import bpy
diff --git a/release/scripts/startup/bl_operators/constraint.py b/release/scripts/startup/bl_operators/constraint.py
index 444452ad2c5..6d040c29b62 100644
--- a/release/scripts/startup/bl_operators/constraint.py
+++ b/release/scripts/startup/bl_operators/constraint.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
from bpy.types import (
diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py
index 0fafb09f672..490fab113c6 100644
--- a/release/scripts/startup/bl_operators/file.py
+++ b/release/scripts/startup/bl_operators/file.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Operator,
diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py
index c5eda7249e1..02b784357b0 100644
--- a/release/scripts/startup/bl_operators/freestyle.py
+++ b/release/scripts/startup/bl_operators/freestyle.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py
index 42f7b1730a8..97308b6894f 100644
--- a/release/scripts/startup/bl_operators/image.py
+++ b/release/scripts/startup/bl_operators/image.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
from bpy.props import StringProperty
diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py
index f3f69530c87..f68df9845ef 100644
--- a/release/scripts/startup/bl_operators/mesh.py
+++ b/release/scripts/startup/bl_operators/mesh.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
diff --git a/release/scripts/startup/bl_operators/node.py b/release/scripts/startup/bl_operators/node.py
index 60a684ae5e8..df4ca9ef170 100644
--- a/release/scripts/startup/bl_operators/node.py
+++ b/release/scripts/startup/bl_operators/node.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
from __future__ import annotations
import bpy
@@ -16,6 +14,8 @@ from bpy.props import (
StringProperty,
)
+from bpy.app.translations import pgettext_tip as tip_
+
class NodeSetting(PropertyGroup):
value: StringProperty(
@@ -131,6 +131,15 @@ class NodeAddOperator:
return result
+ @classmethod
+ def description(cls, _context, properties):
+ nodetype = properties["type"]
+ bl_rna = bpy.types.Node.bl_rna_get_subclass(nodetype)
+ if bl_rna is not None:
+ return tip_(bl_rna.description)
+ else:
+ return ""
+
# Simple basic operator for adding a node
class NODE_OT_add_node(NodeAddOperator, Operator):
diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py
index 0b146d689f5..6e08d557353 100644
--- a/release/scripts/startup/bl_operators/object.py
+++ b/release/scripts/startup/bl_operators/object.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
from bpy.props import (
@@ -598,6 +596,8 @@ class MakeDupliFace(Operator):
for obj in context.selected_objects:
if obj.type == 'MESH':
linked[obj.data].append(obj)
+ elif obj.type == 'EMPTY' and obj.instance_type == 'COLLECTION' and obj.instance_collection:
+ linked[obj.instance_collection].append(obj)
for data, objects in linked.items():
face_verts = [axis for obj in objects
@@ -623,7 +623,12 @@ class MakeDupliFace(Operator):
ob_new = bpy.data.objects.new(mesh.name, mesh)
context.collection.objects.link(ob_new)
- ob_inst = bpy.data.objects.new(data.name, data)
+ if type(data) is bpy.types.Collection:
+ ob_inst = bpy.data.objects.new(data.name, None)
+ ob_inst.instance_type = 'COLLECTION'
+ ob_inst.instance_collection = data
+ else:
+ ob_inst = bpy.data.objects.new(data.name, data)
context.collection.objects.link(ob_inst)
ob_new.instance_type = 'FACES'
@@ -857,6 +862,37 @@ class DupliOffsetFromCursor(Operator):
return {'FINISHED'}
+class DupliOffsetToCursor(Operator):
+ """Set cursor position to the offset used for collection instances"""
+ bl_idname = "object.instance_offset_to_cursor"
+ bl_label = "Set Cursor to Offset"
+ bl_options = {'INTERNAL', 'UNDO'}
+
+ def execute(self, context):
+ scene = context.scene
+ collection = context.collection
+ scene.cursor.location = collection.instance_offset
+ return {'FINISHED'}
+
+
+class DupliOffsetFromObject(Operator):
+ """Set offset used for collection instances based on the active object position"""
+ bl_idname = "object.instance_offset_from_object"
+ bl_label = "Set Offset from Object"
+ bl_options = {'INTERNAL', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.active_object is not None)
+
+ def execute(self, context):
+ ob_eval = context.active_object.evaluated_get(context.view_layer.depsgraph)
+ world_loc = ob_eval.matrix_world.to_translation()
+ collection = context.collection
+ collection.instance_offset = world_loc
+ return {'FINISHED'}
+
+
class LoadImageAsEmpty:
bl_options = {'REGISTER', 'UNDO'}
@@ -978,6 +1014,8 @@ class OBJECT_OT_assign_property_defaults(Operator):
classes = (
ClearAllRestrictRender,
DupliOffsetFromCursor,
+ DupliOffsetToCursor,
+ DupliOffsetFromObject,
IsolateTypeRender,
JoinUVs,
LoadBackgroundImage,
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index f645d8618da..5171f088dd2 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
from bpy.types import Operator
from mathutils import Vector
diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py
index 9f3dd75a316..cd9fd9af472 100644
--- a/release/scripts/startup/bl_operators/object_quick_effects.py
+++ b/release/scripts/startup/bl_operators/object_quick_effects.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
from mathutils import Vector
import bpy
from bpy.types import Operator
diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py
index f1864174db7..0b8b2868349 100644
--- a/release/scripts/startup/bl_operators/object_randomize_transform.py
+++ b/release/scripts/startup/bl_operators/object_randomize_transform.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
from bpy.types import Operator
from mathutils import Vector
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 704693a1469..cde4348977f 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Menu,
diff --git a/release/scripts/startup/bl_operators/rigidbody.py b/release/scripts/startup/bl_operators/rigidbody.py
index 5aab842d672..fffd010b768 100644
--- a/release/scripts/startup/bl_operators/rigidbody.py
+++ b/release/scripts/startup/bl_operators/rigidbody.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
from bpy.props import (
diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
index 78efe9c4af0..39c95e3ed5e 100644
--- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
+++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# Originally written by Matt Ebb
import bpy
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index 0d4cc53173d..8b12bbb78a9 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Operator
diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py
index 49bc2d0a2da..54de9c28144 100644
--- a/release/scripts/startup/bl_operators/userpref.py
+++ b/release/scripts/startup/bl_operators/userpref.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Operator,
diff --git a/release/scripts/startup/bl_operators/uvcalc_follow_active.py b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
index fd5cf5303b3..a5c91f238d2 100644
--- a/release/scripts/startup/bl_operators/uvcalc_follow_active.py
+++ b/release/scripts/startup/bl_operators/uvcalc_follow_active.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import Operator
from bpy.props import (
diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
index f62b98462dc..93c72c97129 100644
--- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py
+++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Operator
import mathutils
diff --git a/release/scripts/startup/bl_operators/vertexpaint_dirt.py b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
index 8089a65960c..74c20a774a3 100644
--- a/release/scripts/startup/bl_operators/vertexpaint_dirt.py
+++ b/release/scripts/startup/bl_operators/vertexpaint_dirt.py
@@ -1,17 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright Campbell Barton.
-# <pep8 compliant>
-
-def get_vcolor_layer_data(me):
- for lay in me.vertex_colors:
- if lay.active:
- return lay.data
-
- lay = me.vertex_colors.new()
- lay.active = True
- return lay.data
+def ensure_active_color_attribute(me):
+ if me.attributes.active_color:
+ return me.attributes.active_color
+ return me.color_attributes.new("Color", 'BYTE_COLOR', 'FACE_CORNER')
def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean, dirt_only, normalize):
@@ -101,17 +95,21 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
else:
tone_range = 1.0 / tone_range
- active_col_layer = get_vcolor_layer_data(me)
- if not active_col_layer:
+ active_color_attribute = ensure_active_color_attribute(me)
+ if not active_color_attribute:
return {'CANCELLED'}
+ point_domain = active_color_attribute.domain == 'POINT'
+
+ attribute_data = active_color_attribute.data
+
use_paint_mask = me.use_paint_mask
for i, p in enumerate(me.polygons):
if not use_paint_mask or p.select:
for loop_index in p.loop_indices:
loop = me.loops[loop_index]
v = loop.vertex_index
- col = active_col_layer[loop_index].color
+ col = attribute_data[v if point_domain else loop_index].color
tone = vert_tone[v]
tone = (tone - min_tone) * tone_range
diff --git a/release/scripts/startup/bl_operators/view3d.py b/release/scripts/startup/bl_operators/view3d.py
index 50cdf1a530e..59e668d81ea 100644
--- a/release/scripts/startup/bl_operators/view3d.py
+++ b/release/scripts/startup/bl_operators/view3d.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Operator
from bpy.props import (
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index 37d7ef19a28..3ab124bf4cf 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
@@ -20,6 +18,7 @@ from bpy.props import (
FloatVectorProperty,
)
from bpy.app.translations import pgettext_iface as iface_
+from bpy.app.translations import pgettext_tip as tip_
def _rna_path_prop_search_for_context_impl(context, edit_text, unique_attrs):
@@ -1062,31 +1061,31 @@ class WM_OT_url_open_preset(Operator):
# Allow dynamically extending.
preset_items = [
# Dynamic URL's.
- (('BUG', "Bug",
- "Report a bug with pre-filled version information"),
+ (('BUG', iface_("Bug"),
+ tip_("Report a bug with pre-filled version information")),
_url_from_bug),
- (('BUG_ADDON', "Add-on Bug",
- "Report a bug in an add-on"),
+ (('BUG_ADDON', iface_("Add-on Bug"),
+ tip_("Report a bug in an add-on")),
_url_from_bug_addon),
- (('RELEASE_NOTES', "Release Notes",
- "Read about what's new in this version of Blender"),
+ (('RELEASE_NOTES', iface_("Release Notes"),
+ tip_("Read about what's new in this version of Blender")),
_url_from_release_notes),
- (('MANUAL', "User Manual",
- "The reference manual for this version of Blender"),
+ (('MANUAL', iface_("User Manual"),
+ tip_("The reference manual for this version of Blender")),
_url_from_manual),
- (('API', "Python API Reference",
- "The API reference manual for this version of Blender"),
+ (('API', iface_("Python API Reference"),
+ tip_("The API reference manual for this version of Blender")),
_url_from_api),
# Static URL's.
- (('FUND', "Development Fund",
- "The donation program to support maintenance and improvements"),
+ (('FUND', iface_("Development Fund"),
+ tip_("The donation program to support maintenance and improvements")),
"https://fund.blender.org"),
- (('BLENDER', "blender.org",
- "Blender's official web-site"),
+ (('BLENDER', iface_("blender.org"),
+ tip_("Blender's official web-site")),
"https://www.blender.org"),
- (('CREDITS', "Credits",
- "Lists committers to Blender's source code"),
+ (('CREDITS', iface_("Credits"),
+ tip_("Lists committers to Blender's source code")),
"https://www.blender.org/about/credits/"),
]
@@ -1354,7 +1353,7 @@ class WM_OT_properties_edit(Operator):
items=rna_custom_property_type_items,
)
is_overridable_library: BoolProperty(
- name="Is Library Overridable",
+ name="Library Overridable",
description="Allow the property to be overridden when the data-block is linked",
default=False,
)
@@ -1365,7 +1364,7 @@ class WM_OT_properties_edit(Operator):
# Shared for integer and string properties.
use_soft_limits: BoolProperty(
- name="Use Soft Limits",
+ name="Soft Limits",
description=(
"Limits the Property Value slider to a range, "
"values outside the range must be inputted numerically"
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 9975d84f368..2e04bc04e02 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# note, properties_animviz is a helper module only.
# support reloading sub-modules
@@ -131,8 +129,8 @@ def register():
return items
WindowManager.addon_search = StringProperty(
- name="Search",
- description="Search within the selected filter",
+ name="Filter",
+ description="Filter by add-on name, author & category",
options={'TEXTEDIT_UPDATE'},
)
WindowManager.addon_filter = EnumProperty(
diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py
index 9aac33eb5de..3062b84bd70 100644
--- a/release/scripts/startup/bl_ui/properties_animviz.py
+++ b/release/scripts/startup/bl_ui/properties_animviz.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Generic Panels (Independent of DataType)
# NOTE:
diff --git a/release/scripts/startup/bl_ui/properties_collection.py b/release/scripts/startup/bl_ui/properties_collection.py
index 88c6a4c217d..95debb259b0 100644
--- a/release/scripts/startup/bl_ui/properties_collection.py
+++ b/release/scripts/startup/bl_ui/properties_collection.py
@@ -1,7 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-from bpy.types import Panel
+from bpy.types import (
+ Collection,
+ Menu,
+ Panel,
+)
+
+from rna_prop_ui import PropertyPanel
class CollectionButtonsPanel:
@@ -44,6 +49,16 @@ class COLLECTION_PT_collection_flags(CollectionButtonsPanel, Panel):
col.prop(vlc, "indirect_only", toggle=False)
+class COLLECTION_MT_context_menu_instance_offset(Menu):
+ bl_label = "Instance Offset"
+
+ def draw(self, _context):
+ layout = self.layout
+ layout.operator("object.instance_offset_from_cursor")
+ layout.operator("object.instance_offset_from_object")
+ layout.operator("object.instance_offset_to_cursor")
+
+
class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
bl_label = "Instancing"
@@ -53,8 +68,9 @@ class COLLECTION_PT_instancing(CollectionButtonsPanel, Panel):
layout.use_property_decorate = False
collection = context.collection
- row = layout.row()
+ row = layout.row(align=True)
row.prop(collection, "instance_offset")
+ row.menu("COLLECTION_MT_context_menu_instance_offset", icon='DOWNARROW_HLT', text="")
class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
@@ -80,11 +96,24 @@ class COLLECTION_PT_lineart_collection(CollectionButtonsPanel, Panel):
if i == 3:
row = col.row(align=True)
+ row = layout.row(heading="Intersection Priority")
+ row.prop(collection, "use_lineart_intersection_priority", text="")
+ subrow = row.row()
+ subrow.active = collection.use_lineart_intersection_priority
+ subrow.prop(collection, "lineart_intersection_priority", text="")
+
+
+class COLLECTION_PT_collection_custom_props(CollectionButtonsPanel, PropertyPanel, Panel):
+ _context_path = "collection"
+ _property_type = Collection
+
classes = (
+ COLLECTION_MT_context_menu_instance_offset,
COLLECTION_PT_collection_flags,
COLLECTION_PT_instancing,
COLLECTION_PT_lineart_collection,
+ COLLECTION_PT_collection_custom_props,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index bd63368bdfd..d949ee779e1 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py
index 58ccaffaf50..22d6a45c48c 100644
--- a/release/scripts/startup/bl_ui/properties_data_armature.py
+++ b/release/scripts/startup/bl_ui/properties_data_armature.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_bone.py b/release/scripts/startup/bl_ui/properties_data_bone.py
index 9a790663581..c842af9af88 100644
--- a/release/scripts/startup/bl_ui/properties_data_bone.py
+++ b/release/scripts/startup/bl_ui/properties_data_bone.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py
index 696143494fe..a9a032ac4a3 100644
--- a/release/scripts/startup/bl_ui/properties_data_camera.py
+++ b/release/scripts/startup/bl_ui/properties_data_camera.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
@@ -220,6 +218,8 @@ class DATA_PT_camera_dof(CameraButtonsPanel, Panel):
col = layout.column()
col.prop(dof, "focus_object", text="Focus on Object")
+ if dof.focus_object and dof.focus_object.type == 'ARMATURE':
+ col.prop_search(dof, "focus_subtarget", dof.focus_object.data, "bones", text="Focus on Bone")
sub = col.column()
sub.active = (dof.focus_object is None)
sub.prop(dof, "focus_distance", text="Focus Distance")
diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index a421428c067..4da7cd0283b 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_curves.py b/release/scripts/startup/bl_ui/properties_data_curves.py
index 4eefd5a0e0c..4a11c5edde6 100644
--- a/release/scripts/startup/bl_ui/properties_data_curves.py
+++ b/release/scripts/startup/bl_ui/properties_data_curves.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
@@ -46,6 +44,7 @@ class DATA_PT_curves_surface(DataButtonsPanel, Panel):
layout.use_property_split = True
layout.prop(ob.data, "surface")
+ layout.prop(ob.data, "surface_uv_map", text="UV Map")
class CURVES_MT_add_attribute(Menu):
@@ -78,6 +77,16 @@ class CURVES_MT_add_attribute(Menu):
class CURVES_UL_attributes(UIList):
+ def filter_items(self, _context, data, property):
+ attributes = getattr(data, property)
+ flags = []
+ indices = [i for i in range(len(attributes))]
+
+ for item in attributes:
+ flags.append(self.bitflag_filter_item if item.is_internal else 0)
+
+ return flags, indices
+
def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index):
data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type]
domain = attribute.bl_rna.properties['domain'].enum_items[attribute.domain]
diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py
index 6c5c94e9d6a..8dd7f8312ae 100644
--- a/release/scripts/startup/bl_ui/properties_data_empty.py
+++ b/release/scripts/startup/bl_ui/properties_data_empty.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py
index df72b1182df..9d95332a901 100644
--- a/release/scripts/startup/bl_ui/properties_data_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_lattice.py b/release/scripts/startup/bl_ui/properties_data_lattice.py
index b4bf09107c5..618f73ecc06 100644
--- a/release/scripts/startup/bl_ui/properties_data_lattice.py
+++ b/release/scripts/startup/bl_ui/properties_data_lattice.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_light.py b/release/scripts/startup/bl_ui/properties_data_light.py
index aab37ff89ad..df3ad43e6de 100644
--- a/release/scripts/startup/bl_ui/properties_data_light.py
+++ b/release/scripts/startup/bl_ui/properties_data_light.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_lightprobe.py b/release/scripts/startup/bl_ui/properties_data_lightprobe.py
index 64ef4c17150..60f8dcc0946 100644
--- a/release/scripts/startup/bl_ui/properties_data_lightprobe.py
+++ b/release/scripts/startup/bl_ui/properties_data_lightprobe.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 050bf56966f..80b9b773d9b 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
@@ -60,12 +58,29 @@ class MESH_MT_shape_key_context_menu(Menu):
layout.operator("object.join_shapes")
layout.operator("object.shape_key_transfer")
layout.separator()
- layout.operator("object.shape_key_remove", icon='X', text="Delete All Shape Keys").all = True
+ op = layout.operator("object.shape_key_remove", icon='X', text="Delete All Shape Keys")
+ op.all = True
+ op.apply_mix = False
+ op = layout.operator("object.shape_key_remove", text="Apply All Shape Keys")
+ op.all = True
+ op.apply_mix = True
layout.separator()
layout.operator("object.shape_key_move", icon='TRIA_UP_BAR', text="Move to Top").type = 'TOP'
layout.operator("object.shape_key_move", icon='TRIA_DOWN_BAR', text="Move to Bottom").type = 'BOTTOM'
+class MESH_MT_color_attribute_context_menu(Menu):
+ bl_label = "Color Attribute Specials"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator(
+ "geometry.color_attribute_duplicate",
+ icon='DUPLICATE',
+ )
+
+
class MESH_MT_attribute_context_menu(Menu):
bl_label = "Attribute Specials"
@@ -401,6 +416,8 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
row.active = enable_edit_value
row.prop(key, "eval_time")
+ layout.prop(ob, "add_rest_position_attribute")
+
class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
bl_label = "UV Maps"
@@ -497,6 +514,16 @@ class MESH_UL_attributes(UIList):
'CORNER': "Face Corner",
}
+ def filter_items(self, _context, data, property):
+ attributes = getattr(data, property)
+ flags = []
+ indices = [i for i in range(len(attributes))]
+
+ for item in attributes:
+ flags.append(self.bitflag_filter_item if item.is_internal else 0)
+
+ return flags, indices
+
def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index):
data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type]
@@ -584,7 +611,8 @@ class ColorAttributesListBase():
for idx, item in enumerate(attrs):
skip = (
(item.domain not in {"POINT", "CORNER"}) or
- (item.data_type not in {"FLOAT_COLOR", "BYTE_COLOR"})
+ (item.data_type not in {"FLOAT_COLOR", "BYTE_COLOR"}) or
+ (not item.is_internal)
)
ret.append(self.bitflag_filter_item if not skip else 0)
idxs.append(idx)
@@ -651,12 +679,17 @@ class DATA_PT_vertex_colors(DATA_PT_mesh_attributes, Panel):
col.operator("geometry.color_attribute_add", icon='ADD', text="")
col.operator("geometry.color_attribute_remove", icon='REMOVE', text="")
+ col.separator()
+
+ col.menu("MESH_MT_color_attribute_context_menu", icon='DOWNARROW_HLT', text="")
+
self.draw_attribute_warnings(context, layout)
classes = (
MESH_MT_vertex_group_context_menu,
MESH_MT_shape_key_context_menu,
+ MESH_MT_color_attribute_context_menu,
MESH_MT_attribute_context_menu,
MESH_UL_vgroups,
MESH_UL_fmaps,
diff --git a/release/scripts/startup/bl_ui/properties_data_metaball.py b/release/scripts/startup/bl_ui/properties_data_metaball.py
index 6c56b44bcb2..defb6d55169 100644
--- a/release/scripts/startup/bl_ui/properties_data_metaball.py
+++ b/release/scripts/startup/bl_ui/properties_data_metaball.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py
index 8750bce5923..a2f0e3d410a 100644
--- a/release/scripts/startup/bl_ui/properties_data_modifier.py
+++ b/release/scripts/startup/bl_ui/properties_data_modifier.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_pointcloud.py b/release/scripts/startup/bl_ui/properties_data_pointcloud.py
index 4f065a9ecfb..8ef6ad63bba 100644
--- a/release/scripts/startup/bl_ui/properties_data_pointcloud.py
+++ b/release/scripts/startup/bl_ui/properties_data_pointcloud.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
@@ -67,6 +65,16 @@ class POINTCLOUD_MT_add_attribute(Menu):
class POINTCLOUD_UL_attributes(UIList):
+ def filter_items(self, _context, data, property):
+ attributes = getattr(data, property)
+ flags = []
+ indices = [i for i in range(len(attributes))]
+
+ for item in attributes:
+ flags.append(self.bitflag_filter_item if item.is_internal else 0)
+
+ return flags, indices
+
def draw_item(self, _context, layout, _data, attribute, _icon, _active_data, _active_propname, _index):
data_type = attribute.bl_rna.properties['data_type'].enum_items[attribute.data_type]
diff --git a/release/scripts/startup/bl_ui/properties_data_shaderfx.py b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
index 4883a9a2a03..4bf41865177 100644
--- a/release/scripts/startup/bl_ui/properties_data_shaderfx.py
+++ b/release/scripts/startup/bl_ui/properties_data_shaderfx.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
diff --git a/release/scripts/startup/bl_ui/properties_data_speaker.py b/release/scripts/startup/bl_ui/properties_data_speaker.py
index 449ae9f1d25..7934aa0bc92 100644
--- a/release/scripts/startup/bl_ui/properties_data_speaker.py
+++ b/release/scripts/startup/bl_ui/properties_data_speaker.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py
index 98855d4b516..460fcd7124b 100644
--- a/release/scripts/startup/bl_ui/properties_data_volume.py
+++ b/release/scripts/startup/bl_ui/properties_data_volume.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel, UIList
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_freestyle.py b/release/scripts/startup/bl_ui/properties_freestyle.py
index 98fcf3247a1..e74e1725aa2 100644
--- a/release/scripts/startup/bl_ui/properties_freestyle.py
+++ b/release/scripts/startup/bl_ui/properties_freestyle.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index f186fca0849..44d82be8ab0 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Menu, UIList, Operator
from bpy.app.translations import pgettext_iface as iface_
@@ -236,6 +234,11 @@ class GPENCIL_MT_move_to_layer(Menu):
layout = self.layout
gpd = context.gpencil_data
if gpd:
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("gpencil.move_to_layer", text="New Layer", icon='ADD').layer = -1
+
+ layout.separator()
+
gpl_active = context.active_gpencil_layer
tot_layers = len(gpd.layers)
i = tot_layers - 1
@@ -248,10 +251,6 @@ class GPENCIL_MT_move_to_layer(Menu):
layout.operator("gpencil.move_to_layer", text=gpl.info, icon=icon, translate=False).layer = i
i -= 1
- layout.separator()
-
- layout.operator("gpencil.move_to_layer", text="New Layer", icon='ADD').layer = -1
-
class GPENCIL_MT_layer_active(Menu):
bl_label = "Change Active Layer"
@@ -262,6 +261,10 @@ class GPENCIL_MT_layer_active(Menu):
gpd = context.gpencil_data
if gpd:
+ layout.operator("gpencil.layer_add", text="New Layer", icon='ADD')
+
+ layout.separator()
+
gpl_active = context.active_gpencil_layer
tot_layers = len(gpd.layers)
i = tot_layers - 1
@@ -274,10 +277,6 @@ class GPENCIL_MT_layer_active(Menu):
layout.operator("gpencil.layer_active", text=gpl.info, icon=icon).layer = i
i -= 1
- layout.separator()
-
- layout.operator("gpencil.layer_add", text="New Layer", icon='ADD')
-
class GPENCIL_MT_material_active(Menu):
bl_label = "Change Active Material"
@@ -297,7 +296,7 @@ class GPENCIL_MT_material_active(Menu):
for slot in ob.material_slots:
mat = slot.material
- if mat:
+ if mat and mat.id_data and mat.id_data.preview:
icon = mat.id_data.preview.icon_id
layout.operator("gpencil.material_set", text=mat.name, icon_value=icon).slot = mat.name
diff --git a/release/scripts/startup/bl_ui/properties_mask_common.py b/release/scripts/startup/bl_ui/properties_mask_common.py
index d9f833e391e..9dc1ef3cc4b 100644
--- a/release/scripts/startup/bl_ui/properties_mask_common.py
+++ b/release/scripts/startup/bl_ui/properties_mask_common.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
# panels get subclassed (not registered directly)
# menus are referenced `as is`
@@ -233,14 +231,20 @@ class MASK_PT_display:
layout = self.layout
space_data = context.space_data
+
row = layout.row(align=True)
- row.prop(space_data, "show_mask_smooth", text="Smooth")
- row.prop(space_data, "mask_display_type", text="")
+ row.prop(space_data, "show_mask_spline", text="Spline")
+ sub = row.row()
+ sub.active = space_data.show_mask_spline
+ sub.prop(space_data, "mask_display_type", text="")
row = layout.row(align=True)
row.prop(space_data, "show_mask_overlay", text="Overlay")
sub = row.row()
sub.active = space_data.show_mask_overlay
sub.prop(space_data, "mask_overlay_mode", text="")
+ row = layout.row()
+ row.active = (space_data.mask_overlay_mode in ['COMBINED'] and space_data.show_mask_overlay)
+ row.prop(space_data, "blend_factor", text="Blending Factor")
class MASK_PT_transforms:
diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py
index 9532d1d4ab0..ba6ed9ae6a2 100644
--- a/release/scripts/startup/bl_ui/properties_material.py
+++ b/release/scripts/startup/bl_ui/properties_material.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
@@ -289,6 +287,12 @@ class MATERIAL_PT_lineart(MaterialButtonsPanel, Panel):
row = layout.row(align=True, heading="Custom Occlusion")
row.prop(lineart, "mat_occlusion", text="Levels")
+ row = layout.row(heading="Intersection Priority")
+ row.prop(lineart, "use_intersection_priority_override", text="")
+ subrow = row.row()
+ subrow.active = lineart.use_intersection_priority_override
+ subrow.prop(lineart, "intersection_priority", text="")
+
classes = (
MATERIAL_MT_context_menu,
diff --git a/release/scripts/startup/bl_ui/properties_material_gpencil.py b/release/scripts/startup/bl_ui/properties_material_gpencil.py
index 47c61984cbe..de1df732b7e 100644
--- a/release/scripts/startup/bl_ui/properties_material_gpencil.py
+++ b/release/scripts/startup/bl_ui/properties_material_gpencil.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from rna_prop_ui import PropertyPanel
diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py
index 44c30cf4372..7afa2f81b97 100644
--- a/release/scripts/startup/bl_ui/properties_object.py
+++ b/release/scripts/startup/bl_ui/properties_object.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bl_ui.properties_animviz import (
MotionPathButtonsPanel,
MotionPathButtonsPanel_display,
@@ -319,6 +317,12 @@ class OBJECT_PT_lineart(ObjectButtonsPanel, Panel):
subrow.active = lineart.use_crease_override
subrow.prop(lineart, "crease_threshold", slider=True, text="")
+ row = layout.row(heading="Intersection Priority")
+ row.prop(lineart, "use_intersection_priority_override", text="")
+ subrow = row.row()
+ subrow.active = lineart.use_intersection_priority_override
+ subrow.prop(lineart, "intersection_priority", text="")
+
class OBJECT_PT_motion_paths(MotionPathButtonsPanel, Panel):
#bl_label = "Object Motion Paths"
diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py
index 312a580bf7d..b80a49cddbb 100644
--- a/release/scripts/startup/bl_ui/properties_output.py
+++ b/release/scripts/startup/bl_ui/properties_output.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel, UIList
from bl_ui.utils import PresetPanel
diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py
index d5b106635ab..9b1cf11f6e7 100644
--- a/release/scripts/startup/bl_ui/properties_paint_common.py
+++ b/release/scripts/startup/bl_ui/properties_paint_common.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Menu
@@ -784,7 +782,6 @@ def brush_settings(layout, context, brush, popover=False):
elif mode == 'SCULPT_CURVES':
if brush.curves_sculpt_tool == 'ADD':
layout.prop(brush.curves_sculpt_settings, "add_amount")
- layout.prop(brush.curves_sculpt_settings, "curve_length")
col = layout.column(heading="Interpolate", align=True)
col.prop(brush.curves_sculpt_settings, "interpolate_length", text="Length")
col.prop(brush.curves_sculpt_settings, "interpolate_shape", text="Shape")
@@ -859,7 +856,7 @@ def brush_shared_settings(layout, context, brush, popover=False):
if mode == 'SCULPT_CURVES':
size = True
strength = True
- direction = brush.curves_sculpt_tool == 'GROW_SHRINK'
+ direction = brush.curves_sculpt_tool in {'GROW_SHRINK', 'SELECTION_PAINT'}
### Draw settings. ###
ups = context.scene.tool_settings.unified_paint_settings
@@ -1318,7 +1315,11 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
def brush_basic_gpencil_sculpt_settings(layout, _context, brush, *, compact=False):
+ if brush is None:
+ return
gp_settings = brush.gpencil_settings
+ if gp_settings is None:
+ return
tool = brush.gpencil_sculpt_tool
row = layout.row(align=True)
diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py
index 3d6ad2ece9b..ae94accf5c7 100644
--- a/release/scripts/startup/bl_ui/properties_particle.py
+++ b/release/scripts/startup/bl_ui/properties_particle.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
@@ -74,7 +72,7 @@ class PARTICLE_MT_context_menu(Menu):
props.use_active = False
props.remove_target_particles = True
- if experimental.use_new_curves_type and psys.settings.type == 'HAIR':
+ if psys.settings.type == 'HAIR':
layout.operator(
"curves.convert_from_particle_system",
text="Convert to Curves")
diff --git a/release/scripts/startup/bl_ui/properties_physics_cloth.py b/release/scripts/startup/bl_ui/properties_physics_cloth.py
index c041534a652..dd1a1fb59d6 100644
--- a/release/scripts/startup/bl_ui/properties_physics_cloth.py
+++ b/release/scripts/startup/bl_ui/properties_physics_cloth.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_common.py b/release/scripts/startup/bl_ui/properties_physics_common.py
index e9df4622cde..bb9fe6e114a 100644
--- a/release/scripts/startup/bl_ui/properties_physics_common.py
+++ b/release/scripts/startup/bl_ui/properties_physics_common.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Panel,
diff --git a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
index d9d2a529693..5ab96bdd2c5 100644
--- a/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
UIList,
diff --git a/release/scripts/startup/bl_ui/properties_physics_field.py b/release/scripts/startup/bl_ui/properties_physics_field.py
index 2e7e68f02ef..8a1bd1a0c54 100644
--- a/release/scripts/startup/bl_ui/properties_physics_field.py
+++ b/release/scripts/startup/bl_ui/properties_physics_field.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_fluid.py b/release/scripts/startup/bl_ui/properties_physics_fluid.py
index 88f8658035b..f1162d8935a 100644
--- a/release/scripts/startup/bl_ui/properties_physics_fluid.py
+++ b/release/scripts/startup/bl_ui/properties_physics_fluid.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Panel
from bl_ui.utils import PresetPanel
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
index bf8ab90147b..ad8f539d62c 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
index 21c3b8b0805..5dc98674b99 100644
--- a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_physics_softbody.py b/release/scripts/startup/bl_ui/properties_physics_softbody.py
index 1b941100db2..bde7778e54c 100644
--- a/release/scripts/startup/bl_ui/properties_physics_softbody.py
+++ b/release/scripts/startup/bl_ui/properties_physics_softbody.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Panel,
)
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 2a904bf1084..148dd3ce22d 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Panel
from bl_ui.space_view3d import (
VIEW3D_PT_shading_lighting,
@@ -392,6 +390,27 @@ class RENDER_PT_eevee_sampling(RenderButtonsPanel, Panel):
col.prop(props, "use_taa_reprojection")
+class RENDER_PT_eevee_next_sampling(RenderButtonsPanel, Panel):
+ bl_label = "Sampling"
+ COMPAT_ENGINES = {'BLENDER_EEVEE_NEXT'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+
+ scene = context.scene
+ props = scene.eevee
+
+ col = layout.column(align=True)
+ col.prop(props, "taa_render_samples", text="Render")
+ col.prop(props, "taa_samples", text="Viewport")
+
+
class RENDER_PT_eevee_indirect_lighting(RenderButtonsPanel, Panel):
bl_label = "Indirect Lighting"
bl_options = {'DEFAULT_CLOSED'}
@@ -484,6 +503,27 @@ class RENDER_PT_eevee_film(RenderButtonsPanel, Panel):
sub.prop(props, "overscan_size", text="")
+class RENDER_PT_eevee_next_film(RenderButtonsPanel, Panel):
+ bl_label = "Film"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE_NEXT'}
+
+ @classmethod
+ def poll(cls, context):
+ return (context.engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.use_property_split = True
+
+ scene = context.scene
+ rd = scene.render
+ props = scene.eevee
+
+ col = layout.column()
+ col.prop(rd, "filter_size")
+
+
def draw_curves_settings(self, context):
layout = self.layout
scene = context.scene
@@ -704,6 +744,9 @@ classes = (
RENDER_PT_eevee_indirect_lighting_display,
RENDER_PT_eevee_film,
+ RENDER_PT_eevee_next_sampling,
+ RENDER_PT_eevee_next_film,
+
RENDER_PT_gpencil,
RENDER_PT_opengl_sampling,
RENDER_PT_opengl_lighting,
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index 912f0c8bcaf..2e2d7fbe261 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Panel,
diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py
index 1f9362f02b5..106ea76ccc8 100644
--- a/release/scripts/startup/bl_ui/properties_texture.py
+++ b/release/scripts/startup/bl_ui/properties_texture.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Menu,
diff --git a/release/scripts/startup/bl_ui/properties_view_layer.py b/release/scripts/startup/bl_ui/properties_view_layer.py
index 44d764f1a2d..01ded1ceb9b 100644
--- a/release/scripts/startup/bl_ui/properties_view_layer.py
+++ b/release/scripts/startup/bl_ui/properties_view_layer.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Menu, Panel, UIList
diff --git a/release/scripts/startup/bl_ui/properties_workspace.py b/release/scripts/startup/bl_ui/properties_workspace.py
index cb4f768ac4f..1a245b33cd2 100644
--- a/release/scripts/startup/bl_ui/properties_workspace.py
+++ b/release/scripts/startup/bl_ui/properties_workspace.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Panel,
@@ -30,6 +28,8 @@ class WORKSPACE_PT_main(WorkSpaceButtonsPanel, Panel):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
+
+ layout.prop(workspace, "use_pin_scene")
layout.prop(workspace, "object_mode", text="Mode")
diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py
index 47e990e8573..b0ea36abd6b 100644
--- a/release/scripts/startup/bl_ui/properties_world.py
+++ b/release/scripts/startup/bl_ui/properties_world.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Panel
from rna_prop_ui import PropertyPanel
@@ -21,7 +19,7 @@ class WorldButtonsPanel:
class WORLD_PT_context_world(WorldButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
@@ -43,17 +41,12 @@ class WORLD_PT_context_world(WorldButtonsPanel, Panel):
class EEVEE_WORLD_PT_mist(WorldButtonsPanel, Panel):
bl_label = "Mist Pass"
bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_EEVEE'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}
@classmethod
def poll(cls, context):
engine = context.engine
- if context.world and (engine in cls.COMPAT_ENGINES):
- for view_layer in context.scene.view_layers:
- if view_layer.use_pass_mist:
- return True
-
- return False
+ return context.world and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -70,14 +63,14 @@ class EEVEE_WORLD_PT_mist(WorldButtonsPanel, Panel):
class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH'}
_context_path = "world"
_property_type = bpy.types.World
class EEVEE_WORLD_PT_surface(WorldButtonsPanel, Panel):
bl_label = "Surface"
- COMPAT_ENGINES = {'BLENDER_EEVEE'}
+ COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}
@classmethod
def poll(cls, context):
diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py
index c1ecfaceee7..c337e8018e6 100644
--- a/release/scripts/startup/bl_ui/space_clip.py
+++ b/release/scripts/startup/bl_ui/space_clip.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import bpy
from bpy.types import Panel, Header, Menu, UIList
from bpy.app.translations import pgettext_iface as iface_
@@ -201,7 +199,8 @@ class CLIP_HT_header(Header):
row = layout.row(align=True)
row.prop(dopesheet, "sort_method", text="")
row.prop(dopesheet, "use_invert_sort",
- text="Invert", toggle=True)
+ text="", toggle=True,
+ icon='SORT_DESC' if dopesheet.use_invert_sort else 'SORT_ASC')
def _draw_masking(self, context):
layout = self.layout
@@ -772,8 +771,10 @@ class CLIP_PT_plane_track(CLIP_PT_tracking_panel, Panel):
layout.prop(active_track, "name")
layout.prop(active_track, "use_auto_keying")
- layout.template_ID(
+ row = layout.row()
+ row.template_ID(
active_track, "image", new="image.new", open="image.open")
+ row.menu("CLIP_MT_plane_track_image_context_menu", icon='DOWNARROW_HLT', text="")
row = layout.row()
row.active = active_track.image is not None
@@ -1484,6 +1485,10 @@ class CLIP_MT_track(Menu):
layout.operator("clip.create_plane_track")
layout.separator()
+ layout.operator("clip.new_image_from_plane_marker")
+ layout.operator("clip.update_image_from_plane_marker")
+
+ layout.separator()
layout.operator(
"clip.solve_camera",
@@ -1635,6 +1640,16 @@ class CLIP_MT_tracking_context_menu(Menu):
draw_mask_context_menu(layout, context)
+class CLIP_MT_plane_track_image_context_menu(Menu):
+ bl_label = "Plane Track Image Specials"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("clip.new_image_from_plane_marker")
+ layout.operator("clip.update_image_from_plane_marker")
+
+
class CLIP_PT_camera_presets(PresetPanel, Panel):
"""Predefined tracking camera intrinsics"""
bl_label = "Camera Presets"
@@ -1936,6 +1951,7 @@ classes = (
CLIP_MT_select,
CLIP_MT_select_grouped,
CLIP_MT_tracking_context_menu,
+ CLIP_MT_plane_track_image_context_menu,
CLIP_PT_camera_presets,
CLIP_PT_track_color_presets,
CLIP_PT_tracking_settings_presets,
diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py
index 323bee8a125..e9d1fc516ae 100644
--- a/release/scripts/startup/bl_ui/space_console.py
+++ b/release/scripts/startup/bl_ui/space_console.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Header, Menu
diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py
index 437f20b9473..a2e691c2d9f 100644
--- a/release/scripts/startup/bl_ui/space_dopesheet.py
+++ b/release/scripts/startup/bl_ui/space_dopesheet.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import (
Header,
@@ -17,6 +15,8 @@ from bl_ui.properties_grease_pencil_common import (
GreasePencilLayerDisplayPanel,
)
+from rna_prop_ui import PropertyPanel
+
#######################################
# DopeSheet Filtering - Header Buttons
@@ -546,16 +546,29 @@ class DopesheetActionPanelBase:
col.prop(action, "use_cyclic")
+class DOPESHEET_PT_custom_props_action(PropertyPanel, Panel):
+ bl_space_type = 'DOPESHEET_EDITOR'
+ bl_category = "Action"
+ bl_region_type = 'UI'
+ bl_context = 'data'
+ _context_path = "active_action"
+ _property_type = bpy.types.Action
+
+ @classmethod
+ def poll(cls, context):
+ return bool(context.active_action)
+
+
class DOPESHEET_PT_action(DopesheetActionPanelBase, Panel):
bl_space_type = 'DOPESHEET_EDITOR'
- bl_category = "Item"
+ bl_category = "Action"
@classmethod
def poll(cls, context):
- return bool(context.selected_visible_actions)
+ return bool(context.active_action)
def draw(self, context):
- action = context.selected_visible_actions[0]
+ action = context.active_action
self.draw_generic_panel(context, self.layout, action)
@@ -819,6 +832,7 @@ classes = (
DOPESHEET_PT_gpencil_layer_adjustments,
DOPESHEET_PT_gpencil_layer_relations,
DOPESHEET_PT_gpencil_layer_display,
+ DOPESHEET_PT_custom_props_action,
)
if __name__ == "__main__": # only for live edit.
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index 92cfa7e8219..bcaa0d88f5b 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
from bpy.types import Header, Panel, Menu, UIList
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index a78ad72cada..a5ad13ad5d8 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import Header, Menu, Panel
from bl_ui.space_dopesheet import (
DopesheetFilterPopoverBase,
diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py
index d61055c9024..ab3c863ea2d 100644
--- a/release/scripts/startup/bl_ui/space_image.py
+++ b/release/scripts/startup/bl_ui/space_image.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import (
Header,
Menu,
@@ -161,6 +159,7 @@ class IMAGE_MT_select(Menu):
layout.operator("uv.select_pinned")
layout.menu("IMAGE_MT_select_linked")
+ layout.operator("uv.select_similar")
layout.separator()
@@ -307,6 +306,7 @@ class IMAGE_MT_uvs_snap(Menu):
layout.operator("uv.snap_cursor", text="Cursor to Pixels").target = 'PIXELS'
layout.operator("uv.snap_cursor", text="Cursor to Selected").target = 'SELECTED'
+ layout.operator("uv.snap_cursor", text="Cursor to Origin").target = 'ORIGIN'
class IMAGE_MT_uvs_mirror(Menu):
@@ -573,6 +573,11 @@ class IMAGE_MT_uvs_snap_pie(Menu):
text="Selected to Adjacent Unselected",
icon='RESTRICT_SELECT_OFF',
).target = 'ADJACENT_UNSELECTED'
+ pie.operator(
+ "uv.snap_cursor",
+ text="Cursor to Origin",
+ icon='PIVOT_CURSOR',
+ ).target = 'ORIGIN'
class IMAGE_MT_view_pie(Menu):
diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py
index 41c8b99b78c..3a9e4841749 100644
--- a/release/scripts/startup/bl_ui/space_info.py
+++ b/release/scripts/startup/bl_ui/space_info.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Header, Menu
diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py
index 77a472d844e..5157a215f34 100644
--- a/release/scripts/startup/bl_ui/space_nla.py
+++ b/release/scripts/startup/bl_ui/space_nla.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import Header, Menu, Panel
from bpy.app.translations import contexts as i18n_contexts
from bl_ui.space_dopesheet import (
@@ -153,7 +151,7 @@ class NLA_MT_marker(Menu):
class NLA_MT_marker_select(Menu):
bl_label = 'Select'
- def draw(self, context):
+ def draw(self, _context):
layout = self.layout
layout.operator("marker.select_all", text="All").action = 'SELECT'
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 813a799db24..427d0696c20 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index f953095b9bb..011a430a1ec 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
@@ -57,7 +55,7 @@ class OUTLINER_HT_header(Header):
layout.operator("outliner.collection_new", text="", icon='COLLECTION_NEW').nested = True
elif display_mode == 'ORPHAN_DATA':
- layout.operator("outliner.orphans_purge", text="Purge")
+ layout.operator("outliner.orphans_purge", text="Purge").do_recursive = True
elif space.display_mode == 'DATA_API':
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py
index c15611fd375..28342d28ac8 100644
--- a/release/scripts/startup/bl_ui/space_properties.py
+++ b/release/scripts/startup/bl_ui/space_properties.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Header, Panel
diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py
index 40da0b03f76..a99df1164a0 100644
--- a/release/scripts/startup/bl_ui/space_sequencer.py
+++ b/release/scripts/startup/bl_ui/space_sequencer.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Header,
@@ -1652,7 +1650,7 @@ class SEQUENCER_PT_source(SequencerButtonsPanel, Panel):
if sound.samplerate <= 0:
split.label(text="Unknown")
else:
- split.label(text="%d Hz." % sound.samplerate, translate=False)
+ split.label(text="%d Hz" % sound.samplerate, translate=False)
split = col.split(factor=0.5, align=False)
split.alignment = 'RIGHT'
@@ -1872,6 +1870,12 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
split.label(text="Channel")
split.prop(strip, "channel", text="")
+ if not is_effect:
+ split = layout.split(factor=0.5 + max_factor)
+ split.alignment = 'RIGHT'
+ split.label(text="Speed Factor")
+ split.prop(strip, "speed_factor", text="")
+
sub = layout.column(align=True)
split = sub.split(factor=0.5 + max_factor, align=True)
split.alignment = 'RIGHT'
@@ -1984,11 +1988,6 @@ class SEQUENCER_PT_adjust_sound(SequencerButtonsPanel, Panel):
split.label(text="Volume")
split.prop(strip, "volume", text="")
- split = col.split(factor=0.4)
- split.alignment = 'RIGHT'
- split.label(text="Pitch")
- split.prop(strip, "pitch", text="")
-
audio_channels = context.scene.render.ffmpeg.audio_channels
pan_enabled = sound.use_mono and audio_channels != 'MONO'
pan_text = "%.2f°" % (strip.pan * 90)
@@ -2089,10 +2088,9 @@ class SEQUENCER_PT_adjust_transform(SequencerButtonsPanel, Panel):
col = layout.column(align=True)
col.prop(strip.transform, "origin")
- row = layout.row(heading="Mirror")
- sub = row.row(align=True)
- sub.prop(strip, "use_flip_x", text="X", toggle=True)
- sub.prop(strip, "use_flip_y", text="Y", toggle=True)
+ col = layout.column(heading="Mirror", align=True)
+ col.prop(strip, "use_flip_x", text="X", toggle=True)
+ col.prop(strip, "use_flip_y", text="Y", toggle=True)
class SEQUENCER_PT_adjust_video(SequencerButtonsPanel, Panel):
diff --git a/release/scripts/startup/bl_ui/space_statusbar.py b/release/scripts/startup/bl_ui/space_statusbar.py
index 90e685ac559..a281492aba8 100644
--- a/release/scripts/startup/bl_ui/space_statusbar.py
+++ b/release/scripts/startup/bl_ui/space_statusbar.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Header
diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py
index 18c309a3456..52d66e48d1c 100644
--- a/release/scripts/startup/bl_ui/space_text.py
+++ b/release/scripts/startup/bl_ui/space_text.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8-80 compliant>
import bpy
from bpy.types import Header, Menu, Panel
from bpy.app.translations import pgettext_iface as iface_
diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py
index 13ab6e67b00..115f61a7c19 100644
--- a/release/scripts/startup/bl_ui/space_time.py
+++ b/release/scripts/startup/bl_ui/space_time.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Menu, Panel
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py
index 36d801154ca..0c796b899af 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_common.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Menu,
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
index 5c6ca13776e..02abbd43986 100644
--- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# For documentation on tool definitions: see "bl_ui.space_toolsystem_common.ToolDef"
# where there are comments for each field and their use.
@@ -263,9 +261,15 @@ class _defs_annotate:
class _defs_transform:
+ def draw_transform_sculpt_tool_settings(context, layout):
+ if context.mode != 'SCULPT':
+ return
+ layout.prop(context.tool_settings.sculpt, "transform_mode")
+
@ToolDef.from_fn
def translate():
def draw_settings(context, layout, _tool):
+ _defs_transform.draw_transform_sculpt_tool_settings(context, layout)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 1)
return dict(
idname="builtin.move",
@@ -281,6 +285,7 @@ class _defs_transform:
@ToolDef.from_fn
def rotate():
def draw_settings(context, layout, _tool):
+ _defs_transform.draw_transform_sculpt_tool_settings(context, layout)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 2)
return dict(
idname="builtin.rotate",
@@ -296,6 +301,7 @@ class _defs_transform:
@ToolDef.from_fn
def scale():
def draw_settings(context, layout, _tool):
+ _defs_transform.draw_transform_sculpt_tool_settings(context, layout)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 3)
return dict(
idname="builtin.scale",
@@ -351,6 +357,7 @@ class _defs_transform:
props = tool.gizmo_group_properties("VIEW3D_GGT_xform_gizmo")
layout.prop(props, "drag_action")
+ _defs_transform.draw_transform_sculpt_tool_settings(context, layout)
_template_widget.VIEW3D_GGT_xform_gizmo.draw_settings_with_index(context, layout, 1)
return dict(
@@ -2316,14 +2323,103 @@ class _defs_gpencil_weight:
class _defs_curves_sculpt:
- @staticmethod
- def generate_from_brushes(context):
- return generate_from_enum_ex(
- context,
- idname_prefix="builtin_brush.",
- icon_prefix="ops.curves.sculpt_",
- type=bpy.types.Brush,
- attr="curves_sculpt_tool",
+ @ToolDef.from_fn
+ def selection_paint():
+ return dict(
+ idname="builtin_brush.selection_paint",
+ label="Selection Paint",
+ icon="ops.generic.select_paint",
+ data_block="SELECTION_PAINT"
+ )
+
+ @ToolDef.from_fn
+ def comb():
+ return dict(
+ idname="builtin_brush.comb",
+ label="Comb",
+ icon="ops.curves.sculpt_comb",
+ data_block='COMB'
+ )
+
+ @ToolDef.from_fn
+ def add():
+ return dict(
+ idname="builtin_brush.add",
+ label="Add",
+ icon="ops.curves.sculpt_add",
+ data_block='ADD'
+ )
+
+ @ToolDef.from_fn
+ def delete():
+ return dict(
+ idname="builtin_brush.delete",
+ label="Delete",
+ icon="ops.curves.sculpt_delete",
+ data_block='DELETE'
+ )
+
+ @ToolDef.from_fn
+ def snake_hook():
+ return dict(
+ idname="builtin_brush.snake_hook",
+ label="Snake Hook",
+ icon="ops.curves.sculpt_snake_hook",
+ data_block='SNAKE_HOOK'
+ )
+
+ @ToolDef.from_fn
+ def grow_shrink():
+ return dict(
+ idname="builtin_brush.grow_shrink",
+ label="Grow/Shrink",
+ icon="ops.curves.sculpt_grow_shrink",
+ data_block='GROW_SHRINK'
+ )
+
+ @ToolDef.from_fn
+ def pinch():
+ return dict(
+ idname="builtin_brush.pinch",
+ label="Pinch",
+ icon="ops.curves.sculpt_pinch",
+ data_block='PINCH'
+ )
+
+ @ToolDef.from_fn
+ def smooth():
+ return dict(
+ idname="builtin_brush.smooth",
+ label="Smooth",
+ icon="ops.curves.sculpt_smooth",
+ data_block='SMOOTH'
+ )
+
+ @ToolDef.from_fn
+ def puff():
+ return dict(
+ idname="builtin_brush.puff",
+ label="Puff",
+ icon="ops.curves.sculpt_puff",
+ data_block='PUFF'
+ )
+
+ @ToolDef.from_fn
+ def density():
+ return dict(
+ idname="builtin_brush.density",
+ label="Density",
+ icon="ops.curves.sculpt_density",
+ data_block="DENSITY"
+ )
+
+ @ToolDef.from_fn
+ def slide():
+ return dict(
+ idname="builtin_brush.slide",
+ label="Slide",
+ icon="ops.curves.sculpt_slide",
+ data_block="SLIDE"
)
@@ -3076,7 +3172,20 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
),
],
'SCULPT_CURVES': [
- _defs_curves_sculpt.generate_from_brushes,
+ _defs_curves_sculpt.selection_paint,
+ None,
+ _defs_curves_sculpt.comb,
+ _defs_curves_sculpt.add,
+ _defs_curves_sculpt.delete,
+ _defs_curves_sculpt.snake_hook,
+ _defs_curves_sculpt.grow_shrink,
+ _defs_curves_sculpt.pinch,
+ _defs_curves_sculpt.smooth,
+ _defs_curves_sculpt.puff,
+ _defs_curves_sculpt.density,
+ _defs_curves_sculpt.slide,
+ None,
+ *_tools_annotate,
],
}
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 2cf50bdbf95..31ecd67eb08 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import Header, Menu, Panel
@@ -455,8 +453,13 @@ class TOPBAR_MT_file_import(Menu):
self.layout.operator(
"wm.usd_import", text="Universal Scene Description (.usd, .usdc, .usda)")
- self.layout.operator("wm.gpencil_import_svg", text="SVG as Grease Pencil")
- self.layout.operator("wm.obj_import", text="Wavefront (.obj) (experimental)")
+ if bpy.app.build_options.io_gpencil:
+ self.layout.operator("wm.gpencil_import_svg", text="SVG as Grease Pencil")
+
+ if bpy.app.build_options.io_wavefront_obj:
+ self.layout.operator("wm.obj_import", text="Wavefront (.obj)")
+ if bpy.app.build_options.io_stl:
+ self.layout.operator("wm.stl_import", text="STL (.stl) (experimental)")
class TOPBAR_MT_file_export(Menu):
@@ -473,14 +476,16 @@ class TOPBAR_MT_file_export(Menu):
self.layout.operator(
"wm.usd_export", text="Universal Scene Description (.usd, .usdc, .usda)")
- # Pugixml lib dependency
- if bpy.app.build_options.pugixml:
- self.layout.operator("wm.gpencil_export_svg", text="Grease Pencil as SVG")
- # Haru lib dependency
- if bpy.app.build_options.haru:
- self.layout.operator("wm.gpencil_export_pdf", text="Grease Pencil as PDF")
+ if bpy.app.build_options.io_gpencil:
+ # Pugixml lib dependency
+ if bpy.app.build_options.pugixml:
+ self.layout.operator("wm.gpencil_export_svg", text="Grease Pencil as SVG")
+ # Haru lib dependency
+ if bpy.app.build_options.haru:
+ self.layout.operator("wm.gpencil_export_pdf", text="Grease Pencil as PDF")
- self.layout.operator("wm.obj_export", text="Wavefront (.obj) (experimental)")
+ if bpy.app.build_options.io_wavefront_obj:
+ self.layout.operator("wm.obj_export", text="Wavefront (.obj)")
class TOPBAR_MT_file_external_data(Menu):
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 3a2eb97fdba..0ebb501f2f4 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Header,
@@ -591,12 +589,6 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
addon.preferences.draw_impl(col, context)
del addon
- # NOTE: Disabled for until GPU side of OpenSubdiv is brought back.
- # system = prefs.system
- # if hasattr(system, "opensubdiv_compute_type"):
- # col.label(text="OpenSubdiv compute:")
- # col.row().prop(system, "opensubdiv_compute_type", text="")
-
class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
bl_label = "Operating System Settings"
@@ -1486,11 +1478,13 @@ class USERPREF_PT_saveload_file_browser(SaveLoadPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
paths = prefs.filepaths
+ col = layout.column(heading="Show Locations")
+ col.prop(paths, "show_recent_locations", text="Recent")
+ col.prop(paths, "show_system_bookmarks", text="System")
+
col = layout.column(heading="Defaults")
col.prop(paths, "use_filter_files")
col.prop(paths, "show_hidden_files_datablocks")
- col.prop(paths, "show_recent_locations")
- col.prop(paths, "show_system_bookmarks")
# -----------------------------------------------------------------------------
@@ -2095,7 +2089,7 @@ class StudioLightPanelMixin:
for studio_light in lights:
self.draw_studio_light(flow, studio_light)
else:
- layout.label(text="No custom %s configured" % self.bl_label)
+ layout.label(text=iface_("No custom %s configured") % self.bl_label)
def draw_studio_light(self, layout, studio_light):
box = layout.box()
@@ -2273,13 +2267,13 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
def draw(self, context):
self._draw_items(
context, (
- ({"property": "use_new_curves_type"}, "T68981"),
({"property": "use_new_curves_tools"}, "T68981"),
({"property": "use_new_point_cloud_type"}, "T75717"),
({"property": "use_sculpt_texture_paint"}, "T96225"),
({"property": "use_full_frame_compositor"}, "T88150"),
({"property": "enable_eevee_next"}, "T93220"),
({"property": "use_draw_manager_acquire_lock"}, "T98016"),
+ ({"property": "use_override_new_fully_editable"}, None),
),
)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 1af70895be9..1a30c666bcb 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
from bpy.types import (
Header,
@@ -97,7 +95,7 @@ class VIEW3D_HT_tool_header(Header):
elif tool_mode == 'PAINT_GPENCIL':
if is_valid_context:
brush = context.tool_settings.gpencil_paint.brush
- if brush.gpencil_tool != 'ERASE':
+ if brush and brush.gpencil_tool != 'ERASE':
if brush.gpencil_tool != 'TINT':
layout.popover("VIEW3D_PT_tools_grease_pencil_brush_advanced")
@@ -108,10 +106,11 @@ class VIEW3D_HT_tool_header(Header):
elif tool_mode == 'SCULPT_GPENCIL':
if is_valid_context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
- tool = brush.gpencil_sculpt_tool
- if tool != 'CLONE':
- layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover")
- layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
+ if brush:
+ tool = brush.gpencil_sculpt_tool
+ if tool != 'CLONE':
+ layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover")
+ layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'WEIGHT_GPENCIL':
if is_valid_context:
layout.popover("VIEW3D_PT_tools_grease_pencil_weight_appearance")
@@ -512,28 +511,55 @@ class _draw_tool_settings_context_mode:
header=True,
)
- if brush.curves_sculpt_tool == 'COMB':
+ curves_tool = brush.curves_sculpt_tool
+
+ if curves_tool == 'COMB':
layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_tools_brush_falloff")
-
- if brush.curves_sculpt_tool == 'ADD':
+ elif curves_tool == 'ADD':
layout.prop(brush, "falloff_shape", expand=True)
layout.prop(brush.curves_sculpt_settings, "add_amount")
layout.popover("VIEW3D_PT_curves_sculpt_add_shape", text="Curve Shape")
layout.prop(brush, "use_frontface", text="Front Faces Only")
-
- if brush.curves_sculpt_tool == 'GROW_SHRINK':
+ elif curves_tool == 'GROW_SHRINK':
layout.prop(brush, "direction", expand=True, text="")
layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_curves_sculpt_grow_shrink_scaling", text="Scaling")
layout.popover("VIEW3D_PT_tools_brush_falloff")
-
- if brush.curves_sculpt_tool == 'SNAKE_HOOK':
+ elif curves_tool == 'SNAKE_HOOK':
layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_tools_brush_falloff")
-
- if brush.curves_sculpt_tool == 'DELETE':
+ elif curves_tool == 'DELETE':
+ layout.prop(brush, "falloff_shape", expand=True)
+ elif curves_tool == 'SELECTION_PAINT':
+ layout.prop(brush, "direction", expand=True, text="")
+ layout.prop(brush, "falloff_shape", expand=True)
+ layout.popover("VIEW3D_PT_tools_brush_falloff")
+ elif curves_tool == 'PINCH':
+ layout.prop(brush, "direction", expand=True, text="")
layout.prop(brush, "falloff_shape", expand=True)
+ layout.popover("VIEW3D_PT_tools_brush_falloff")
+ elif curves_tool == 'SMOOTH':
+ layout.prop(brush, "falloff_shape", expand=True)
+ layout.popover("VIEW3D_PT_tools_brush_falloff")
+ elif curves_tool == 'PUFF':
+ layout.prop(brush, "falloff_shape", expand=True)
+ layout.popover("VIEW3D_PT_tools_brush_falloff")
+ elif curves_tool == 'DENSITY':
+ layout.prop(brush, "falloff_shape", expand=True)
+ row = layout.row(align=True)
+ row.prop(brush.curves_sculpt_settings, "density_mode", text="", expand=True)
+ row = layout.row(align=True)
+ row.prop(brush.curves_sculpt_settings, "minimum_distance", text="Distance Min")
+ row.operator_context = 'INVOKE_REGION_WIN'
+ row.operator("sculpt_curves.min_distance_edit", text="", icon='DRIVER_DISTANCE')
+ row = layout.row(align=True)
+ row.enabled = brush.curves_sculpt_settings.density_mode != 'REMOVE'
+ row.prop(brush.curves_sculpt_settings, "density_add_attempts", text="Count Max")
+ layout.popover("VIEW3D_PT_tools_brush_falloff")
+ layout.popover("VIEW3D_PT_curves_sculpt_add_shape", text="Curve Shape")
+ elif curves_tool == "SLIDE":
+ layout.popover("VIEW3D_PT_tools_brush_falloff")
class VIEW3D_HT_header(Header):
@@ -577,8 +603,8 @@ class VIEW3D_HT_header(Header):
show_snap = True
else:
if (object_mode not in {
- 'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT',
- 'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL', 'VERTEX_GPENCIL'
+ 'SCULPT', 'SCULPT_CURVES', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT',
+ 'PAINT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL', 'VERTEX_GPENCIL',
}) or has_pose_mode:
show_snap = True
else:
@@ -687,6 +713,22 @@ class VIEW3D_HT_header(Header):
if object_mode == 'PARTICLE_EDIT':
row = layout.row()
row.prop(tool_settings.particle_edit, "select_mode", text="", expand=True)
+ elif object_mode == 'SCULPT_CURVES' and obj.type == 'CURVES':
+ curves = obj.data
+
+ row = layout.row(align=True)
+
+ # Combine the "use selection" toggle with the "set domain" operators
+ # to allow turning selection off directly.
+ domain = curves.selection_domain
+ if domain == 'POINT':
+ row.prop(curves, "use_sculpt_selection", text="", icon='CURVE_BEZCIRCLE')
+ else:
+ row.operator("curves.set_selection_domain", text="", icon='CURVE_BEZCIRCLE').domain = 'POINT'
+ if domain == 'CURVE':
+ row.prop(curves, "use_sculpt_selection", text="", icon='CURVE_PATH')
+ else:
+ row.operator("curves.set_selection_domain", text="", icon='CURVE_PATH').domain = 'CURVE'
# Grease Pencil
if obj and obj.type == 'GPENCIL' and context.gpencil_data:
@@ -939,6 +981,7 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_mask")
layout.menu("VIEW3D_MT_face_sets")
if mode_string == 'SCULPT_CURVES':
+ layout.menu("VIEW3D_MT_select_sculpt_curves")
layout.menu("VIEW3D_MT_sculpt_curves")
else:
@@ -1976,6 +2019,20 @@ class VIEW3D_MT_select_edit_curves(Menu):
pass
+class VIEW3D_MT_select_sculpt_curves(Menu):
+ bl_label = "Select"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("sculpt_curves.select_all", text="All").action = 'SELECT'
+ layout.operator("sculpt_curves.select_all", text="None").action = 'DESELECT'
+ layout.operator("sculpt_curves.select_all", text="Invert").action = 'INVERT'
+ layout.operator("sculpt_curves.select_random", text="Random")
+ layout.operator("sculpt_curves.select_end", text="Endpoints")
+ layout.operator("sculpt_curves.select_grow", text="Grow")
+
+
class VIEW3D_MT_angle_control(Menu):
bl_label = "Angle Control"
@@ -2052,14 +2109,13 @@ class VIEW3D_MT_curve_add(Menu):
layout.operator("curve.primitive_nurbs_circle_add", text="Nurbs Circle", icon='CURVE_NCIRCLE')
layout.operator("curve.primitive_nurbs_path_add", text="Path", icon='CURVE_PATH')
- experimental = context.preferences.experimental
- if experimental.use_new_curves_type:
- layout.separator()
+ layout.separator()
- layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA')
+ layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA')
- if experimental.use_new_curves_tools:
- layout.operator("object.curves_random_add", text="Random", icon='CURVES_DATA')
+ experimental = context.preferences.experimental
+ if experimental.use_new_curves_tools:
+ layout.operator("object.curves_random_add", text="Random", icon='CURVES_DATA')
class VIEW3D_MT_surface_add(Menu):
@@ -2295,8 +2351,6 @@ class VIEW3D_MT_object_relations(Menu):
layout = self.layout
layout.operator("object.make_override_library", text="Make Library Override...")
- layout.operator("object.make_override_library",
- text="Make Library Override - Fully Editable...").do_fully_editable = True
layout.operator("object.make_dupli_face")
@@ -6590,6 +6644,30 @@ class VIEW3D_PT_overlay_sculpt(Panel):
row.prop(overlay, "sculpt_mode_face_sets_opacity", text="Face Sets")
+class VIEW3D_PT_overlay_sculpt_curves(Panel):
+ bl_space_type = 'VIEW_3D'
+ bl_context = ".curves_sculpt"
+ bl_region_type = 'HEADER'
+ bl_parent_id = 'VIEW3D_PT_overlay'
+ bl_label = "Sculpt"
+
+ @classmethod
+ def poll(cls, context):
+ return context.mode == 'SCULPT_CURVES' and (context.object)
+
+ def draw(self, context):
+ layout = self.layout
+ tool_settings = context.tool_settings
+ sculpt = tool_settings.sculpt
+
+ view = context.space_data
+ overlay = view.overlay
+
+ row = layout.row(align=True)
+ row.active = overlay.show_overlays
+ row.prop(overlay, "sculpt_mode_mask_opacity", text="Selection Opacity")
+
+
class VIEW3D_PT_overlay_bones(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'HEADER'
@@ -6742,23 +6820,53 @@ class VIEW3D_PT_snapping(Panel):
col.prop(tool_settings, "use_snap_grid_absolute")
if snap_elements != {'INCREMENT'}:
- col.label(text="Snap With")
- row = col.row(align=True)
- row.prop(tool_settings, "snap_target", expand=True)
-
- col.prop(tool_settings, "use_snap_backface_culling")
+ if snap_elements != {'FACE_NEAREST'}:
+ col.label(text="Snap With")
+ row = col.row(align=True)
+ row.prop(tool_settings, "snap_target", expand=True)
if obj:
+ col.label(text="Target Selection")
+ col_targetsel = col.column(align=True)
if object_mode == 'EDIT' and obj.type not in {'LATTICE', 'META', 'FONT'}:
- sub = col.column()
- sub.active = not (tool_settings.use_proportional_edit and obj.type == 'MESH')
- sub.prop(tool_settings, "use_snap_self")
+ col_targetsel.prop(
+ tool_settings,
+ "use_snap_self",
+ text="Include Active",
+ icon='EDITMODE_HLT',
+ )
+ col_targetsel.prop(
+ tool_settings,
+ "use_snap_edit",
+ text="Include Edited",
+ icon='OUTLINER_DATA_MESH',
+ )
+ col_targetsel.prop(
+ tool_settings,
+ "use_snap_nonedit",
+ text="Include Non-Edited",
+ icon='OUTLINER_OB_MESH',
+ )
+ col_targetsel.prop(
+ tool_settings,
+ "use_snap_selectable",
+ text="Exclude Non-Selectable",
+ icon='RESTRICT_SELECT_OFF',
+ )
+
if object_mode in {'OBJECT', 'POSE', 'EDIT', 'WEIGHT_PAINT'}:
col.prop(tool_settings, "use_snap_align_rotation")
+ col.prop(tool_settings, "use_snap_backface_culling")
+
if 'FACE' in snap_elements:
col.prop(tool_settings, "use_snap_project")
+ if 'FACE_NEAREST' in snap_elements:
+ col.prop(tool_settings, 'use_snap_to_same_target')
+ if object_mode == 'EDIT':
+ col.prop(tool_settings, 'snap_face_nearest_steps')
+
if 'VOLUME' in snap_elements:
col.prop(tool_settings, "use_snap_peel_object")
@@ -7703,6 +7811,7 @@ classes = (
VIEW3D_MT_select_paint_mask,
VIEW3D_MT_select_paint_mask_vertex,
VIEW3D_MT_select_edit_curves,
+ VIEW3D_MT_select_sculpt_curves,
VIEW3D_MT_angle_control,
VIEW3D_MT_mesh_add,
VIEW3D_MT_curve_add,
@@ -7876,6 +7985,7 @@ classes = (
VIEW3D_PT_overlay_weight_paint,
VIEW3D_PT_overlay_bones,
VIEW3D_PT_overlay_sculpt,
+ VIEW3D_PT_overlay_sculpt_curves,
VIEW3D_PT_snapping,
VIEW3D_PT_proportional_edit,
VIEW3D_PT_gpencil_origin,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 1b714a40d03..892dc9a1e42 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
from bpy.types import Menu, Panel, UIList
from bl_ui.properties_grease_pencil_common import (
GreasePencilSculptAdvancedPanel,
diff --git a/release/scripts/startup/bl_ui/utils.py b/release/scripts/startup/bl_ui/utils.py
index 02d2448af66..87f44601ff3 100644
--- a/release/scripts/startup/bl_ui/utils.py
+++ b/release/scripts/startup/bl_ui/utils.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
from bpy.types import Menu
diff --git a/release/scripts/startup/keyingsets_builtins.py b/release/scripts/startup/keyingsets_builtins.py
index fb287183c99..4390e6f0959 100644
--- a/release/scripts/startup/keyingsets_builtins.py
+++ b/release/scripts/startup/keyingsets_builtins.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Built-In Keying Sets
None of these Keying Sets should be removed, as these are needed by various parts of Blender in order for them
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index f5282123ce8..6f3054100f8 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
import bpy
import nodeitems_utils
from nodeitems_utils import (
@@ -75,6 +73,7 @@ def curve_node_items(context):
yield NodeItem("GeometryNodeCurveLength")
yield NodeItem("GeometryNodeCurveToMesh")
yield NodeItem("GeometryNodeCurveToPoints")
+ yield NodeItem("GeometryNodeDeformCurvesOnSurface")
yield NodeItem("GeometryNodeFillCurve")
yield NodeItem("GeometryNodeFilletCurve")
yield NodeItem("GeometryNodeResampleCurve")
@@ -115,6 +114,7 @@ def mesh_node_items(context):
yield NodeItem("GeometryNodeMeshBoolean")
yield NodeItem("GeometryNodeMeshToCurve")
yield NodeItem("GeometryNodeMeshToPoints")
+ yield NodeItem("GeometryNodeMeshToVolume")
yield NodeItem("GeometryNodeSplitEdges")
yield NodeItem("GeometryNodeSubdivideMesh")
yield NodeItem("GeometryNodeSubdivisionSurface")
@@ -158,6 +158,17 @@ def geometry_node_items(context):
yield NodeItem("GeometryNodeSetPosition")
+# Custom Menu for UV Nodes.
+def uv_node_items(context):
+ if context is None:
+ return
+ space = context.space_data
+ if not space:
+ return
+ yield NodeItem("GeometryNodeUVPackIslands")
+ yield NodeItem("GeometryNodeUVUnwrap")
+
+
# Custom Menu for Geometry Node Input Nodes.
def geometry_input_node_items(context):
if context is None:
@@ -185,6 +196,24 @@ def geometry_input_node_items(context):
yield NodeItem("GeometryNodeInputSceneTime")
+# Custom Menu for Geometry Node Instance Nodes.
+def geometry_instance_node_items(context):
+ if context is None:
+ return
+ space = context.space_data
+ if not space:
+ return
+ yield NodeItem("GeometryNodeInstanceOnPoints")
+ yield NodeItem("GeometryNodeInstancesToPoints")
+ yield NodeItem("GeometryNodeRealizeInstances")
+ yield NodeItem("GeometryNodeRotateInstances")
+ yield NodeItem("GeometryNodeScaleInstances")
+ yield NodeItem("GeometryNodeTranslateInstances")
+ yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+ yield NodeItem("GeometryNodeInputInstanceRotation")
+ yield NodeItem("GeometryNodeInputInstanceScale")
+
+
# Custom Menu for Material Nodes.
def geometry_material_node_items(context):
if context is None:
@@ -209,6 +238,7 @@ def point_node_items(context):
if not space:
return
yield NodeItem("GeometryNodeDistributePointsOnFaces")
+ yield NodeItem("GeometryNodePoints")
yield NodeItem("GeometryNodePointsToVertices")
yield NodeItem("GeometryNodePointsToVolume")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
@@ -637,14 +667,7 @@ geometry_node_categories = [
]),
GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=geometry_node_items),
GeometryNodeCategory("GEO_INPUT", "Input", items=geometry_input_node_items),
- GeometryNodeCategory("GEO_INSTANCE", "Instances", items=[
- NodeItem("GeometryNodeInstanceOnPoints"),
- NodeItem("GeometryNodeInstancesToPoints"),
- NodeItem("GeometryNodeRealizeInstances"),
- NodeItem("GeometryNodeRotateInstances"),
- NodeItem("GeometryNodeScaleInstances"),
- NodeItem("GeometryNodeTranslateInstances"),
- ]),
+ GeometryNodeCategory("GEO_INSTANCE", "Instances", items=geometry_instance_node_items),
GeometryNodeCategory("GEO_MATERIAL", "Material", items=geometry_material_node_items),
GeometryNodeCategory("GEO_MESH", "Mesh", items=mesh_node_items),
GeometryNodeCategory("GEO_PRIMITIVES_MESH", "Mesh Primitives", items=[
@@ -685,6 +708,7 @@ geometry_node_categories = [
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
NodeItem("GeometryNodeAccumulateField"),
NodeItem("GeometryNodeFieldAtIndex"),
+ NodeItem("GeometryNodeFieldOnDomain"),
NodeItem("ShaderNodeMapRange"),
NodeItem("ShaderNodeFloatCurve"),
NodeItem("ShaderNodeClamp"),
@@ -697,6 +721,7 @@ geometry_node_categories = [
NodeItem("FunctionNodeRandomValue"),
NodeItem("FunctionNodeAlignEulerToVector"),
]),
+ GeometryNodeCategory("GEO_UV", "UV", items=uv_node_items),
GeometryNodeCategory("GEO_VECTOR", "Vector", items=[
NodeItem("ShaderNodeVectorCurve"),
NodeItem("ShaderNodeSeparateXYZ"),
@@ -705,6 +730,7 @@ geometry_node_categories = [
NodeItem("ShaderNodeVectorRotate"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
+ NodeItem("GeometryNodeVolumeCube"),
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
diff --git a/release/windows/manifest/blender.exe.manifest.in b/release/windows/manifest/blender.exe.manifest.in
index b516efe24cb..95a238f775b 100644
--- a/release/windows/manifest/blender.exe.manifest.in
+++ b/release/windows/manifest/blender.exe.manifest.in
@@ -7,6 +7,11 @@
</requestedPrivileges>
</security>
</trustInfo>
+ <application>
+ <windowsSettings>
+ <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
+ </windowsSettings>
+ </application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index efa2be9e48c..8ba6e7318bb 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -96,15 +96,15 @@ set(SRC_DNA_DEFAULTS_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_cachefile_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_camera_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_collection_defaults.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curves_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curve_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curves_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fluid_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lattice_defaults.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lightprobe_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_light_defaults.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lightprobe_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_linestyle_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_material_defaults.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_mesh_defaults.h
diff --git a/source/blender/blendthumb/src/blendthumb_extract.cc b/source/blender/blendthumb/src/blendthumb_extract.cc
index de1f50dfdce..163197c8b67 100644
--- a/source/blender/blendthumb/src/blendthumb_extract.cc
+++ b/source/blender/blendthumb/src/blendthumb_extract.cc
@@ -121,6 +121,9 @@ static eThumbStatus blendthumb_extract_from_file_impl(FileReader *file,
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);
+ if (UNLIKELY(block_size < 0)) {
+ return BT_INVALID_THUMB;
+ }
/* We're looking for the thumbnail, so skip any other block. */
switch (*((int32_t *)bhead_data)) {
@@ -134,7 +137,8 @@ static eThumbStatus blendthumb_extract_from_file_impl(FileReader *file,
/* 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;
+ const uint64_t expected_size = static_cast<uint64_t>(thumb->width) *
+ static_cast<uint64_t>(thumb->height) * 4;
if (thumb->width < 0 || thumb->height < 0 || data_size != expected_size) {
return BT_INVALID_THUMB;
}
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index e5e2b1711b1..83ca9158efc 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -14,6 +14,15 @@
extern "C" {
#endif
+/* Name of subfolder inside BLENDER_DATAFILES that contains font files. */
+#define BLF_DATAFILES_FONTS_DIR "fonts"
+
+/* File name of the default variable-width font. */
+#define BLF_DEFAULT_PROPORTIONAL_FONT "droidsans.ttf"
+
+/* File name of the default fixed-pitch font. */
+#define BLF_DEFAULT_MONOSPACED_FONT "bmonofont-i18n.ttf"
+
/* enable this only if needed (unused circa 2016) */
#define BLF_BLUR_ENABLE 0
@@ -37,12 +46,14 @@ void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void));
*/
int BLF_load(const char *name) ATTR_NONNULL();
int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
+bool BLF_is_loaded(const char *name) ATTR_NONNULL();
int BLF_load_unique(const char *name) ATTR_NONNULL();
int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
void BLF_unload(const char *name) ATTR_NONNULL();
void BLF_unload_id(int fontid);
+void BLF_unload_all(void);
char *BLF_display_name_from_file(const char *filepath);
@@ -312,25 +323,35 @@ int BLF_set_default(void);
int BLF_load_default(bool unique);
int BLF_load_mono_default(bool unique);
+void BLF_load_font_stack(void);
#ifdef DEBUG
void BLF_state_print(int fontid);
#endif
-/* font->flags. */
-#define BLF_ROTATION (1 << 0)
-#define BLF_CLIPPING (1 << 1)
-#define BLF_SHADOW (1 << 2)
-// #define BLF_FLAG_UNUSED_3 (1 << 3) /* dirty */
-#define BLF_MATRIX (1 << 4)
-#define BLF_ASPECT (1 << 5)
-#define BLF_WORD_WRAP (1 << 6)
-#define BLF_MONOCHROME (1 << 7) /* no-AA */
-#define BLF_HINTING_NONE (1 << 8)
-#define BLF_HINTING_SLIGHT (1 << 9)
-#define BLF_HINTING_FULL (1 << 10)
-#define BLF_BOLD (1 << 11)
-#define BLF_ITALIC (1 << 12)
+/** #FontBLF.flags. */
+enum {
+ BLF_ROTATION = 1 << 0,
+ BLF_CLIPPING = 1 << 1,
+ BLF_SHADOW = 1 << 2,
+ // BLF_FLAG_UNUSED_3 = 1 << 3, /* dirty */
+ BLF_MATRIX = 1 << 4,
+ BLF_ASPECT = 1 << 5,
+ BLF_WORD_WRAP = 1 << 6,
+ /** No anti-aliasing. */
+ BLF_MONOCHROME = 1 << 7,
+ BLF_HINTING_NONE = 1 << 8,
+ BLF_HINTING_SLIGHT = 1 << 9,
+ BLF_HINTING_FULL = 1 << 10,
+ BLF_BOLD = 1 << 11,
+ BLF_ITALIC = 1 << 12,
+ /** Intended USE is monospaced, regardless of font type. */
+ BLF_MONOSPACED = 1 << 13,
+ /** A font within the default stack of fonts. */
+ BLF_DEFAULT = 1 << 14,
+ /** Must only be used as last font in the stack. */
+ BLF_LAST_RESORT = 1 << 15,
+};
#define BLF_DRAW_STR_DUMMY_MAX 1024
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index a944ab332bd..a1fcc17ca3f 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -34,13 +34,6 @@
#include "blf_internal.h"
#include "blf_internal_types.h"
-/* Max number of font in memory.
- * Take care that now every font have a glyph cache per size/dpi,
- * so we don't need load the same font with different size, just
- * load one and call BLF_size.
- */
-#define BLF_MAX_FONT 16
-
#define BLF_RESULT_CHECK_INIT(r_info) \
if (r_info) { \
memset(r_info, 0, sizeof(*(r_info))); \
@@ -48,7 +41,7 @@
((void)0)
/* Font array. */
-static FontBLF *global_font[BLF_MAX_FONT] = {NULL};
+FontBLF *global_font[BLF_MAX_FONT] = {NULL};
/* XXX: should these be made into global_font_'s too? */
@@ -134,6 +127,11 @@ bool BLF_has_glyph(int fontid, unsigned int unicode)
return false;
}
+bool BLF_is_loaded(const char *name)
+{
+ return blf_search(name) >= 0;
+}
+
int BLF_load(const char *name)
{
/* check if we already load this font. */
@@ -255,6 +253,20 @@ void BLF_unload_id(int fontid)
}
}
+void BLF_unload_all(void)
+{
+ for (int i = 0; i < BLF_MAX_FONT; i++) {
+ FontBLF *font = global_font[i];
+ if (font) {
+ blf_font_free(font);
+ global_font[i] = NULL;
+ }
+ }
+ blf_mono_font = -1;
+ blf_mono_font_render = -1;
+ BLF_default_set(-1);
+}
+
void BLF_enable(int fontid, int option)
{
FontBLF *font = blf_get(fontid);
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index a170f27d247..038e73cc928 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -18,6 +18,8 @@
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
+#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
#include "MEM_guardedalloc.h"
@@ -1284,10 +1286,33 @@ FontBLF *blf_font_new(const char *name, const char *filepath)
MEM_freeN(mfile);
}
+ if (FT_HAS_MULTIPLE_MASTERS(font->face)) {
+ FT_Get_MM_Var(font->face, &(font->variations));
+ }
+
font->name = BLI_strdup(name);
font->filepath = BLI_strdup(filepath);
blf_font_fill(font);
+ /* Save TrueType table with bits to quickly test most unicode block coverage. */
+ TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
+ if (os2_table) {
+ font->UnicodeRanges[0] = (uint)os2_table->ulUnicodeRange1;
+ font->UnicodeRanges[1] = (uint)os2_table->ulUnicodeRange2;
+ font->UnicodeRanges[2] = (uint)os2_table->ulUnicodeRange3;
+ font->UnicodeRanges[3] = (uint)os2_table->ulUnicodeRange4;
+ }
+
+ /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
+ if (font->UnicodeRanges[0] == 0xffffffffU && font->UnicodeRanges[1] == 0xffffffffU &&
+ font->UnicodeRanges[2] == 0xffffffffU && font->UnicodeRanges[3] >= 0x7FFFFFFU) {
+ font->flags |= BLF_LAST_RESORT;
+ }
+
+ if (FT_IS_FIXED_WIDTH(font->face)) {
+ font->flags |= BLF_MONOSPACED;
+ }
+
if (FT_HAS_KERNING(font->face)) {
/* Create kerning cache table and fill with value indicating "unset". */
font->kerning_cache = MEM_mallocN(sizeof(KerningCacheBLF), __func__);
@@ -1331,6 +1356,10 @@ FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int m
return NULL;
}
+ if (FT_HAS_MULTIPLE_MASTERS(font->face)) {
+ FT_Get_MM_Var(font->face, &(font->variations));
+ }
+
font->name = BLI_strdup(name);
font->filepath = NULL;
blf_font_fill(font);
@@ -1345,6 +1374,10 @@ void blf_font_free(FontBLF *font)
MEM_freeN(font->kerning_cache);
}
+ if (font->variations) {
+ FT_Done_MM_Var(ft_lib, font->variations);
+ }
+
FT_Done_Face(font->face);
if (font->filepath) {
MEM_freeN(font->filepath);
diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c
index 3a68423e64e..1bde25b5776 100644
--- a/source/blender/blenfont/intern/blf_font_default.c
+++ b/source/blender/blenfont/intern/blf_font_default.c
@@ -11,13 +11,14 @@
#include "BLF_api.h"
+#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BKE_appdir.h"
static int blf_load_font_default(const char *filename, const bool unique)
{
- const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "fonts");
+ const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR);
if (dir == NULL) {
fprintf(stderr,
"%s: 'fonts' data path not found for '%s', will not be able to display text\n",
@@ -34,10 +35,46 @@ static int blf_load_font_default(const char *filename, const bool unique)
int BLF_load_default(const bool unique)
{
- return blf_load_font_default("droidsans.ttf", unique);
+ int font_id = blf_load_font_default(BLF_DEFAULT_PROPORTIONAL_FONT, unique);
+ BLF_enable(font_id, BLF_DEFAULT);
+ return font_id;
}
int BLF_load_mono_default(const bool unique)
{
- return blf_load_font_default("bmonofont-i18n.ttf", unique);
+ int font_id = blf_load_font_default(BLF_DEFAULT_MONOSPACED_FONT, unique);
+ BLF_enable(font_id, BLF_MONOSPACED | BLF_DEFAULT);
+ return font_id;
+}
+
+void BLF_load_font_stack()
+{
+ /* Load these if not already, might have been replaced by user custom. */
+ BLF_load_default(false);
+ BLF_load_mono_default(false);
+
+ const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR SEP_STR);
+ if (path && BLI_exists(path)) {
+ struct direntry *dir;
+ uint num_files = BLI_filelist_dir_contents(path, &dir);
+ for (int f = 0; f < num_files; f++) {
+ if (!FILENAME_IS_CURRPAR(dir[f].relname) && !BLI_is_dir(dir[f].path)) {
+ if (!BLF_is_loaded(dir[f].path)) {
+ int font_id = BLF_load(dir[f].path);
+ if (font_id == -1) {
+ fprintf(stderr, "Unable to load font: %s\n", dir[f].path);
+ }
+ else {
+ BLF_enable(font_id, BLF_DEFAULT);
+ /* TODO: FontBLF will later load FT_Face on demand. When this is in
+ * place we can drop this face now since we have all needed data. */
+ }
+ }
+ }
+ }
+ BLI_filelist_free(dir, num_files);
+ }
+ else {
+ fprintf(stderr, "Fonts not found at %s\n", path);
+ }
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 2694b179a11..215f79e6795 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -18,7 +18,8 @@
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_BITMAP_H
-#include FT_ADVANCES_H /* For FT_Get_Advance. */
+#include FT_ADVANCES_H /* For FT_Get_Advance. */
+#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
#include "MEM_guardedalloc.h"
@@ -39,6 +40,7 @@
#include "BLI_math_vector.h"
#include "BLI_strict_flags.h"
+#include "BLI_string_utf8.h"
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
@@ -63,7 +65,9 @@ static GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned i
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))) {
+ (gc->italic == ((font->flags & BLF_ITALIC) != 0)) &&
+ (gc->char_weight == font->char_weight) && (gc->char_slant == font->char_slant) &&
+ (gc->char_width == font->char_width) && (gc->char_spacing == font->char_spacing)) {
return gc;
}
gc = gc->next;
@@ -81,6 +85,10 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
gc->dpi = font->dpi;
gc->bold = ((font->flags & BLF_BOLD) != 0);
gc->italic = ((font->flags & BLF_ITALIC) != 0);
+ gc->char_weight = font->char_weight;
+ gc->char_slant = font->char_slant;
+ gc->char_width = font->char_width;
+ gc->char_spacing = font->char_spacing;
memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table));
memset(gc->bucket, 0, sizeof(gc->bucket));
@@ -222,6 +230,335 @@ static GlyphBLF *blf_glyph_cache_add_glyph(
return g;
}
+/* This table can be used to find a coverage bit based on a charcode. later we can get default
+ * language and script from codepoint. */
+
+typedef struct eUnicodeBlock {
+ unsigned int first;
+ unsigned int last;
+ int coverage_bit; /* 0-122. -1 is N/A. */
+ /* Later we add primary script and language for Harfbuzz, data from
+ * https://en.wikipedia.org/wiki/Unicode_block */
+} eUnicodeBlock;
+
+static eUnicodeBlock unicode_blocks[] = {
+ /* Must be in ascending order by start of range. */
+ {0x0, 0x7F, 0}, /* Basic Latin. */
+ {0x80, 0xFF, 1}, /* Latin-1 Supplement. */
+ {0x100, 0x17F, 2}, /* Latin Extended-A. */
+ {0x180, 0x24F, 3}, /* Latin Extended-B. */
+ {0x250, 0x2AF, 4}, /* IPA Extensions. */
+ {0x2B0, 0x2FF, 5}, /* Spacing Modifier Letters. */
+ {0x300, 0x36F, 6}, /* Combining Diacritical Marks. */
+ {0x370, 0x3FF, 7}, /* Greek. */
+ {0x400, 0x52F, 9}, /* Cyrillic. */
+ {0x530, 0x58F, 10}, /* Armenian. */
+ {0x590, 0x5FF, 11}, /* Hebrew. */
+ {0x600, 0x6FF, 13}, /* Arabic. */
+ {0x700, 0x74F, 71}, /* Syriac. */
+ {0x750, 0x77F, 13}, /* Arabic Supplement. */
+ {0x780, 0x7BF, 72}, /* Thaana. */
+ {0x7C0, 0x7FF, 14}, /* NKo. */
+ {0x800, 0x83F, -1}, /* Samaritan. */
+ {0x840, 0x85F, -1}, /* Mandaic. */
+ {0x900, 0x97F, 15}, /* Devanagari. */
+ {0x980, 0x9FF, 16}, /* Bengali. */
+ {0xA00, 0xA7F, 17}, /* Gurmukhi. */
+ {0xA80, 0xAFF, 18}, /* Gujarati. */
+ {0xB00, 0xB7F, 19}, /* Oriya. */
+ {0xB80, 0xBFF, 20}, /* Tamil. */
+ {0xC00, 0xC7F, 21}, /* Telugu. */
+ {0xC80, 0xCFF, 22}, /* Kannada. */
+ {0xD00, 0xD7F, 23}, /* Malayalam. */
+ {0xD80, 0xDFF, 73}, /* Sinhala. */
+ {0xE00, 0xE7F, 24}, /* Thai. */
+ {0xE80, 0xEFF, 25}, /* Lao. */
+ {0xF00, 0xFFF, 70}, /* Tibetan. */
+ {0x1000, 0x109F, 74}, /* Myanmar. */
+ {0x10A0, 0x10FF, 26}, /* Georgian. */
+ {0x1100, 0x11FF, 28}, /* Hangul Jamo. */
+ {0x1200, 0x139F, 75}, /* Ethiopic. */
+ {0x13A0, 0x13FF, 76}, /* Cherokee. */
+ {0x1400, 0x167F, 77}, /* Canadian Aboriginal. */
+ {0x1680, 0x169F, 78}, /* Ogham. */
+ {0x16A0, 0x16FF, 79}, /* unic. */
+ {0x1700, 0x171F, 84}, /* Tagalog. */
+ {0x1720, 0x173F, 84}, /* Hanunoo. */
+ {0x1740, 0x175F, 84}, /* Buhid. */
+ {0x1760, 0x177F, 84}, /* Tagbanwa. */
+ {0x1780, 0x17FF, 80}, /* Khmer. */
+ {0x1800, 0x18AF, 81}, /* Mongolian. */
+ {0x1900, 0x194F, 93}, /* Limbu. */
+ {0x1950, 0x197F, 94}, /* Tai Le. */
+ {0x1980, 0x19DF, 95}, /* New Tai Lue". */
+ {0x19E0, 0x19FF, 80}, /* Khmer. */
+ {0x1A00, 0x1A1F, 96}, /* Buginese. */
+ {0x1A20, 0x1AAF, -1}, /* Tai Tham. */
+ {0x1B00, 0x1B7F, 27}, /* Balinese. */
+ {0x1B80, 0x1BBF, 112}, /* Sundanese. */
+ {0x1BC0, 0x1BFF, -1}, /* Batak. */
+ {0x1C00, 0x1C4F, 113}, /* Lepcha. */
+ {0x1C50, 0x1C7F, 114}, /* Ol Chiki. */
+ {0x1D00, 0x1DBF, 4}, /* IPA Extensions. */
+ {0x1DC0, 0x1DFF, 6}, /* Combining Diacritical Marks. */
+ {0x1E00, 0x1EFF, 29}, /* Latin Extended Additional. */
+ {0x1F00, 0x1FFF, 30}, /* Greek Extended. */
+ {0x2000, 0x206F, 31}, /* General Punctuation. */
+ {0x2070, 0x209F, 32}, /* Superscripts And Subscripts. */
+ {0x20A0, 0x20CF, 33}, /* Currency Symbols. */
+ {0x20D0, 0x20FF, 34}, /* Combining Diacritical Marks For Symbols. */
+ {0x2100, 0x214F, 35}, /* Letterlike Symbols. */
+ {0x2150, 0x218F, 36}, /* Number Forms. */
+ {0x2190, 0x21FF, 37}, /* Arrows. */
+ {0x2200, 0x22FF, 38}, /* Mathematical Operators. */
+ {0x2300, 0x23FF, 39}, /* Miscellaneous Technical. */
+ {0x2400, 0x243F, 40}, /* Control Pictures. */
+ {0x2440, 0x245F, 41}, /* Optical Character Recognition. */
+ {0x2460, 0x24FF, 42}, /* Enclosed Alphanumerics. */
+ {0x2500, 0x257F, 43}, /* Box Drawing. */
+ {0x2580, 0x259F, 44}, /* Block Elements. */
+ {0x25A0, 0x25FF, 45}, /* Geometric Shapes. */
+ {0x2600, 0x26FF, 46}, /* Miscellaneous Symbols. */
+ {0x2700, 0x27BF, 47}, /* Dingbats. */
+ {0x27C0, 0x27EF, 38}, /* Mathematical Operators. */
+ {0x27F0, 0x27FF, 37}, /* Arrows. */
+ {0x2800, 0x28FF, 82}, /* Braille. */
+ {0x2900, 0x297F, 37}, /* Arrows. */
+ {0x2980, 0x2AFF, 38}, /* Mathematical Operators. */
+ {0x2B00, 0x2BFF, 37}, /* Arrows. */
+ {0x2C00, 0x2C5F, 97}, /* Glagolitic. */
+ {0x2C60, 0x2C7F, 29}, /* Latin Extended Additional. */
+ {0x2C80, 0x2CFF, 8}, /* Coptic. */
+ {0x2D00, 0x2D2F, 26}, /* Georgian. */
+ {0x2D30, 0x2D7F, 98}, /* Tifinagh. */
+ {0x2D80, 0x2DDF, 75}, /* Ethiopic. */
+ {0x2DE0, 0x2DFF, 9}, /* Cyrillic. */
+ {0x2E00, 0x2E7F, 31}, /* General Punctuation. */
+ {0x2E80, 0x2FFF, 59}, /* CJK Unified Ideographs. */
+ {0x3000, 0x303F, 48}, /* CJK Symbols And Punctuation. */
+ {0x3040, 0x309F, 49}, /* Hiragana. */
+ {0x30A0, 0x30FF, 50}, /* Katakana. */
+ {0x3100, 0x312F, 51}, /* Bopomofo. */
+ {0x3130, 0x318F, 52}, /* Hangul Compatibility Jamo. */
+ {0x3190, 0x319F, 59}, /* CJK Unified Ideographs. */
+ {0x31A0, 0x31BF, 51}, /* Bopomofo. */
+ {0x31C0, 0x31EF, 59}, /* CJK Unified Ideographs. */
+ {0x31F0, 0x31FF, 50}, /* Katakana. */
+ {0x3200, 0x32FF, 54}, /* Enclosed CJK Letters And Months. */
+ {0x3300, 0x33FF, 55}, /* CJK Compatibility. */
+ {0x3400, 0x4DBF, 59}, /* CJK Unified Ideographs. */
+ {0x4DC0, 0x4DFF, 99}, /* Yijing. */
+ {0x4E00, 0x9FFF, 59}, /* CJK Unified Ideographs. */
+ {0xA000, 0xA4CF, 83}, /* Yi. */
+ {0xA4D0, 0xA4FF, -1}, /* Lisu. */
+ {0xA500, 0xA63F, 12}, /* Vai. */
+ {0xA640, 0xA69F, 9}, /* Cyrillic. */
+ {0xA6A0, 0xA6FF, -1}, /* Bamum. */
+ {0xA700, 0xA71F, 5}, /* Spacing Modifier Letters. */
+ {0xA720, 0xA7FF, 29}, /* Latin Extended Additional. */
+ {0xA800, 0xA82F, 100}, /* Syloti Nagri. */
+ {0xA840, 0xA87F, 53}, /* Phags-pa. */
+ {0xA880, 0xA8DF, 115}, /* Saurashtra. */
+ {0xA900, 0xA92F, 116}, /* Kayah Li. */
+ {0xA930, 0xA95F, 117}, /* Rejang. */
+ {0xA960, 0xA97F, 56}, /* Hangul Syllables. */
+ {0xA980, 0xA9DF, -1}, /* Javanese. */
+ {0xA9E0, 0xA9FF, 74}, /* Myanmar. */
+ {0xAA00, 0xAA5F, 118}, /* Cham. */
+ {0xAA60, 0xAA7F, 74}, /* Myanmar. */
+ {0xAA80, 0xAADF, -1}, /* Tai Viet. */
+ {0xAAE0, 0xAAFF, -1}, /* Meetei Mayek. */
+ {0xAB00, 0xAB2F, 75}, /* Ethiopic. */
+ {0xAB70, 0xABBF, 76}, /* Cherokee. */
+ {0xABC0, 0xABFF, -1}, /* Meetei Mayek. */
+ {0xAC00, 0xD7AF, 56}, /* Hangul Syllables. */
+ {0xD800, 0xDFFF, 57}, /* Non-Plane 0. */
+ {0xE000, 0xF6FF, 60}, /* Private Use Area. */
+ {0xE700, 0xEFFF, -1}, /* MS Wingdings. */
+ {0xF000, 0xF8FF, -1}, /* MS Symbols. */
+ {0xF900, 0xFAFF, 61}, /* CJK Compatibility Ideographs. */
+ {0xFB00, 0xFB4F, 62}, /* Alphabetic Presentation Forms. */
+ {0xFB50, 0xFDFF, 63}, /* Arabic Presentation Forms-A. */
+ {0xFE00, 0xFE0F, 91}, /* Variation Selectors. */
+ {0xFE10, 0xFE1F, 65}, /* CJK Compatibility Forms. */
+ {0xFE20, 0xFE2F, 64}, /* Combining Half Marks. */
+ {0xFE30, 0xFE4F, 65}, /* CJK Compatibility Forms. */
+ {0xFE50, 0xFE6F, 66}, /* Small Form Variants. */
+ {0xFE70, 0xFEFF, 67}, /* Arabic Presentation Forms-B. */
+ {0xFF00, 0xFFEF, 68}, /* Half-width And Full-width Forms. */
+ {0xFFF0, 0xFFFF, 69}, /* Specials. */
+ {0x10000, 0x1013F, 101}, /* Linear B. */
+ {0x10140, 0x1018F, 102}, /* Ancient Greek Numbers. */
+ {0x10190, 0x101CF, 119}, /* Ancient Symbols. */
+ {0x101D0, 0x101FF, 120}, /* Phaistos Disc. */
+ {0x10280, 0x1029F, 121}, /* Lycian. */
+ {0x102A0, 0x102DF, 121}, /* Carian. */
+ {0x10300, 0x1032F, 85}, /* Old Italic. */
+ {0x10330, 0x1034F, 86}, /* Gothic. */
+ {0x10350, 0x1037F, -1}, /* Old Permic. */
+ {0x10380, 0x1039F, 103}, /* Ugaritic. */
+ {0x103A0, 0x103DF, 104}, /* Old Persian. */
+ {0x10400, 0x1044F, 87}, /* Deseret. */
+ {0x10450, 0x1047F, 105}, /* Shavian. */
+ {0x10480, 0x104AF, 106}, /* Osmanya. */
+ {0x104B0, 0x104FF, -1}, /* Osage. */
+ {0x10500, 0x1052F, -1}, /* Elbasan. */
+ {0x10530, 0x1056F, -1}, /* Caucasian Albanian. */
+ {0x10570, 0x105BF, -1}, /* Vithkuqi. */
+ {0x10600, 0x1077F, -1}, /* Linear A. */
+ {0x10780, 0x107BF, 3}, /* Latin Extended-B. */
+ {0x10800, 0x1083F, 107}, /* Cypriot Syllabary. */
+ {0x10840, 0x1085F, -1}, /* Imperial Aramaic. */
+ {0x10860, 0x1087F, -1}, /* Palmyrene. */
+ {0x10880, 0x108AF, -1}, /* Nabataean. */
+ {0x108E0, 0x108FF, -1}, /* Hatran. */
+ {0x10900, 0x1091F, 58}, /* Phoenician. */
+ {0x10920, 0x1093F, 121}, /* Lydian. */
+ {0x10980, 0x1099F, -1}, /* Meroitic Hieroglyphs. */
+ {0x109A0, 0x109FF, -1}, /* Meroitic Cursive. */
+ {0x10A00, 0x10A5F, 108}, /* Kharoshthi. */
+ {0x10A60, 0x10A7F, -1}, /* Old South Arabian. */
+ {0x10A80, 0x10A9F, -1}, /* Old North Arabian. */
+ {0x10AC0, 0x10AFF, -1}, /* Manichaean. */
+ {0x10B00, 0x10B3F, -1}, /* Avestan. */
+ {0x10B40, 0x10B5F, -1}, /* Inscriptional Parthian. */
+ {0x10B60, 0x10B7F, -1}, /* Inscriptional Pahlavi. */
+ {0x10B80, 0x10BAF, -1}, /* Psalter Pahlavi. */
+ {0x10C00, 0x10C4F, -1}, /* Old Turkic. */
+ {0x10C80, 0x10CFF, -1}, /* Old Hungarian. */
+ {0x10D00, 0x10D3F, -1}, /* Hanifi Rohingya. */
+ {0x108E0, 0x10E7F, -1}, /* Rumi Numeral Symbols. */
+ {0x10E80, 0x10EBF, -1}, /* Yezidi. */
+ {0x10F00, 0x10F2F, -1}, /* Old Sogdian. */
+ {0x10F30, 0x10F6F, -1}, /* Sogdian. */
+ {0x10F70, 0x10FAF, -1}, /* Old Uyghur. */
+ {0x10FB0, 0x10FDF, -1}, /* Chorasmian. */
+ {0x10FE0, 0x10FFF, -1}, /* Elymaic. */
+ {0x11000, 0x1107F, -1}, /* Brahmi. */
+ {0x11080, 0x110CF, -1}, /* Kaithi. */
+ {0x110D0, 0x110FF, -1}, /* Sora Sompeng. */
+ {0x11100, 0x1114F, -1}, /* Chakma. */
+ {0x11150, 0x1117F, -1}, /* Mahajani. */
+ {0x11180, 0x111DF, -1}, /* Sharada. */
+ {0x111E0, 0x111FF, -1}, /* Sinhala Archaic Numbers. */
+ {0x11200, 0x1124F, -1}, /* Khojki. */
+ {0x11280, 0x112AF, -1}, /* Multani. */
+ {0x112B0, 0x112FF, -1}, /* Khudawadi. */
+ {0x11300, 0x1137F, -1}, /* Grantha. */
+ {0x11400, 0x1147F, -1}, /* Newa. */
+ {0x11480, 0x114DF, -1}, /* Tirhuta. */
+ {0x11580, 0x115FF, -1}, /* Siddham. */
+ {0x11600, 0x1165F, -1}, /* Modi. */
+ {0x11660, 0x1167F, 81}, /* Mongolian. */
+ {0x11680, 0x116CF, -1}, /* Takri. */
+ {0x11700, 0x1174F, -1}, /* Ahom. */
+ {0x11800, 0x1184F, -1}, /* Dogra. */
+ {0x118A0, 0x118FF, -1}, /* Warang Citi. */
+ {0x11900, 0x1195F, -1}, /* Dives Akuru. */
+ {0x119A0, 0x119FF, -1}, /* Nandinagari. */
+ {0x11A00, 0x11A4F, -1}, /* Zanabazar Square. */
+ {0x11A50, 0x11AAF, -1}, /* Soyombo. */
+ {0x11AB0, 0x11ABF, 77}, /* Canadian Aboriginal Syllabics. */
+ {0x11AC0, 0x11AFF, -1}, /* Pau Cin Hau. */
+ {0x11C00, 0x11C6F, -1}, /* Bhaiksuki. */
+ {0x11C70, 0x11CBF, -1}, /* Marchen. */
+ {0x11D00, 0x11D5F, -1}, /* Masaram Gondi. */
+ {0x11D60, 0x11DAF, -1}, /* Gunjala Gondi. */
+ {0x11EE0, 0x11EFF, -1}, /* Makasar. */
+ {0x11FB0, 0x11FBF, -1}, /* Lisu. */
+ {0x11FC0, 0x11FFF, 20}, /* Tamil. */
+ {0x12000, 0x1254F, 110}, /* Cuneiform. */
+ {0x12F90, 0x12FFF, -1}, /* Cypro-Minoan. */
+ {0x13000, 0x1343F, -1}, /* Egyptian Hieroglyphs. */
+ {0x14400, 0x1467F, -1}, /* Anatolian Hieroglyphs. */
+ {0x16800, 0x16A3F, -1}, /* Bamum. */
+ {0x16A40, 0x16A6F, -1}, /* Mro. */
+ {0x16A70, 0x16ACF, -1}, /* Tangsa. */
+ {0x16AD0, 0x16AFF, -1}, /* Bassa Vah. */
+ {0x16B00, 0x16B8F, -1}, /* Pahawh Hmong. */
+ {0x16E40, 0x16E9F, -1}, /* Medefaidrin. */
+ {0x16F00, 0x16F9F, -1}, /* Miao. */
+ {0x16FE0, 0x16FFF, -1}, /* Ideographic Symbols. */
+ {0x17000, 0x18AFF, -1}, /* Tangut. */
+ {0x1B170, 0x1B2FF, -1}, /* Nushu. */
+ {0x1BC00, 0x1BC9F, -1}, /* Duployan. */
+ {0x1D000, 0x1D24F, 88}, /* Musical Symbols. */
+ {0x1D2E0, 0x1D2FF, -1}, /* Mayan Numerals. */
+ {0x1D300, 0x1D35F, 109}, /* Tai Xuan Jing. */
+ {0x1D360, 0x1D37F, 111}, /* Counting Rod Numerals. */
+ {0x1D400, 0x1D7FF, 89}, /* Mathematical Alphanumeric Symbols. */
+ {0x1E2C0, 0x1E2FF, -1}, /* Wancho. */
+ {0x1E800, 0x1E8DF, -1}, /* Mende Kikakui. */
+ {0x1E900, 0x1E95F, -1}, /* Adlam. */
+ {0x1EC70, 0x1ECBF, -1}, /* Indic Siyaq Numbers. */
+ {0x1F000, 0x1F02F, 122}, /* Mahjong Tiles. */
+ {0x1F030, 0x1F09F, 122}, /* Domino Tiles. */
+ {0x1F600, 0x1F64F, -1}, /* Emoticons. */
+ {0x20000, 0x2A6DF, 59}, /* CJK Unified Ideographs. */
+ {0x2F800, 0x2FA1F, 61}, /* CJK Compatibility Ideographs. */
+ {0xE0000, 0xE007F, 92}, /* Tags. */
+ {0xE0100, 0xE01EF, 91}, /* Variation Selectors. */
+ {0xF0000, 0x10FFFD, 90}}; /* Private Use Supplementary. */
+
+/* Find a unicode block that a charcode belongs to. */
+static eUnicodeBlock *blf_charcode_to_unicode_block(uint charcode)
+{
+ if (charcode < 0x80) {
+ /* Shortcut to Basic Latin. */
+ return &unicode_blocks[0];
+ }
+
+ /* Binary search for other blocks. */
+
+ int min = 0;
+ int max = ARRAY_SIZE(unicode_blocks) - 1;
+ int mid;
+
+ if (charcode < unicode_blocks[0].first || charcode > unicode_blocks[max].last) {
+ return NULL;
+ }
+
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (charcode > unicode_blocks[mid].last) {
+ min = mid + 1;
+ }
+ else if (charcode < unicode_blocks[mid].first) {
+ max = mid - 1;
+ }
+ else {
+ return &unicode_blocks[mid];
+ }
+ }
+
+ return NULL;
+}
+
+static int blf_charcode_to_coverage_bit(uint charcode)
+{
+ int coverage_bit = -1;
+ eUnicodeBlock *block = blf_charcode_to_unicode_block(charcode);
+ if (block) {
+ coverage_bit = block->coverage_bit;
+ }
+
+ if (coverage_bit < 0 && charcode > 0xFFFF) {
+ /* No coverage bit, but OpenType specs v.1.3+ says bit 57 implies that there
+ * are codepoints supported beyond the BMP, so only check fonts with this set. */
+ coverage_bit = 57;
+ }
+
+ return coverage_bit;
+}
+
+static bool blf_font_has_coverage_bit(FontBLF *font, int coverage_bit)
+{
+ if (coverage_bit < 0) {
+ return false;
+ }
+ return (font->UnicodeRanges[(uint)coverage_bit >> 5] & (1u << ((uint)coverage_bit % 32)));
+}
+
/**
* 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.
@@ -229,8 +566,42 @@ static GlyphBLF *blf_glyph_cache_add_glyph(
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;
+ if (glyph_index) {
+ return glyph_index;
+ }
+
+ /* Not found in main font, so look in the others. */
+ FontBLF *last_resort = NULL;
+ int coverage_bit = blf_charcode_to_coverage_bit(charcode);
+ for (int i = 0; i < BLF_MAX_FONT; i++) {
+ FontBLF *f = global_font[i];
+ if (!f || f == *font || !(f->flags & BLF_DEFAULT)) {
+ continue;
+ }
+
+ if (f->flags & BLF_LAST_RESORT) {
+ last_resort = f;
+ continue;
+ }
+ if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) {
+ glyph_index = FT_Get_Char_Index(f->face, charcode);
+ if (glyph_index) {
+ *font = f;
+ return glyph_index;
+ }
+ }
+ }
+
+ /* Not found in the stack, return from Last Resort if there is one. */
+ if (last_resort) {
+ glyph_index = FT_Get_Char_Index(last_resort->face, charcode);
+ if (glyph_index) {
+ *font = last_resort;
+ return glyph_index;
+ }
+ }
+
+ return 0;
}
/**
@@ -310,6 +681,96 @@ static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Variations (Multiple Masters) support
+ * \{ */
+
+/**
+ * Return a design axis that matches an identifying tag.
+ *
+ * \param variations: Variation descriptors from `FT_Get_MM_Var`.
+ * \param tag: Axis tag (4-character string as uint), like 'wght'
+ * \param axis_index: returns index of axis in variations array.
+ */
+static FT_Var_Axis *blf_var_axis_by_tag(FT_MM_Var *variations, uint tag, int *axis_index)
+{
+ *axis_index = -1;
+ if (!variations) {
+ return NULL;
+ }
+ for (int i = 0; i < (int)variations->num_axis; i++) {
+ if (variations->axis[i].tag == tag) {
+ *axis_index = i;
+ return &(variations->axis)[i];
+ break;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Convert a float factor to a fixed-point design coordinate.
+ *
+ * \param axis: Pointer to a design space axis structure.
+ * \param factor: -1 to 1 with 0 meaning "default"
+ */
+static FT_Fixed blf_factor_to_coordinate(FT_Var_Axis *axis, float factor)
+{
+ FT_Fixed value = axis->def;
+ if (factor > 0) {
+ /* Map 0-1 to axis->def - axis->maximum */
+ value += (FT_Fixed)((double)(axis->maximum - axis->def) * factor);
+ }
+ else if (factor < 0) {
+ /* Map -1-0 to axis->minimum - axis->def */
+ value += (FT_Fixed)((double)(axis->def - axis->minimum) * factor);
+ }
+ return value;
+}
+
+/**
+ * Alter a face variation axis by a factor
+ *
+ * \param coords: array of design coordinates, per axis.
+ * \param tag: Axis tag (4-character string as uint), like 'wght'
+ * \param factor: -1 to 1 with 0 meaning "default"
+ */
+static bool blf_glyph_set_variation_normalized(FontBLF *font,
+ FT_Fixed coords[],
+ uint tag,
+ float factor)
+{
+ int axis_index;
+ FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index);
+ if (axis && (axis_index < BLF_VARIATIONS_MAX)) {
+ coords[axis_index] = blf_factor_to_coordinate(axis, factor);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Set a face variation axis to an exact float value
+ *
+ * \param coords: array of design coordinates, per axis.
+ * \param tag: Axis tag (4-character string as uint), like 'opsz'
+ * \param value: New float value. Converted to 16.16 and clamped within allowed range.
+ */
+static bool blf_glyph_set_variation_float(FontBLF *font, FT_Fixed coords[], uint tag, float value)
+{
+ int axis_index;
+ FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index);
+ if (axis && (axis_index < BLF_VARIATIONS_MAX)) {
+ FT_Fixed int_value = to_16dot16(value);
+ CLAMP(int_value, axis->minimum, axis->maximum);
+ coords[axis_index] = int_value;
+ return true;
+ }
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Glyph Transformations
* \{ */
@@ -362,7 +823,7 @@ static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor)
*
* \param factor: -1 (min width) <= 0 (normal) => 1 (max width).
*/
-static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float factor)
+static bool 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 */
@@ -375,26 +836,41 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float
}
/**
+ * Change glyph advance to alter letter-spacing (tracking).
+ *
+ * \param factor: -1 (min tightness) <= 0 (normal) => 1 (max looseness).
+ */
+static bool blf_glyph_transform_spacing(FT_GlyphSlot glyph, float factor)
+{
+ if (glyph->advance.x > 0) {
+ const long int size = glyph->face->size->metrics.height;
+ glyph->advance.x += (FT_Pos)(factor * (float)size / 6.0f);
+ return true;
+ }
+ return false;
+}
+
+/**
* Transform glyph to fit nicely within a fixed column width.
*/
-static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, int width)
+static bool 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_Fixed current = glyph->linearHoriAdvance;
+ FT_Fixed target = width << 16; /* Do math in 16.16 values. */
+ if (target < current) {
+ const FT_Pos embolden = (FT_Pos)((current - target) >> 13);
+ /* Horizontally widen strokes to counteract narrowing. */
+ FT_Outline_EmboldenXY(&glyph->outline, embolden, 0);
+ const float scale = (float)(target - (embolden << 9)) / (float)current;
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);
+ else if (target > current) {
+ /* Center narrow glyphs. */
+ FT_Outline_Translate(&glyph->outline, (FT_Pos)((target - current) >> 11), 0);
}
+ glyph->advance.x = width << 6;
return true;
}
return false;
@@ -411,7 +887,9 @@ static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, i
*/
static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
FontBLF *glyph_font,
- FT_UInt glyph_index)
+ FT_UInt glyph_index,
+ uint charcode,
+ int fixed_width)
{
if (glyph_font != settings_font) {
FT_Set_Char_Size(glyph_font->face,
@@ -423,24 +901,70 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
glyph_font->dpi = settings_font->dpi;
}
+ /* We need to keep track if changes are still needed. */
+ bool weight_done = false;
+ bool slant_done = false;
+ bool width_done = false;
+ bool spacing_done = false;
+
+ /* 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. */
+ float weight = (settings_font->flags & BLF_BOLD) ? 0.7f : settings_font->char_weight;
+
+ /* 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. */
+ float slant = (settings_font->flags & BLF_ITALIC) ? 0.375f : settings_font->char_slant;
+
+ float width = settings_font->char_width;
+ float spacing = settings_font->char_spacing;
+
+ /* Font variations need to be set before glyph loading. Even if new value is zero. */
+
+ if (glyph_font->variations) {
+ FT_Fixed coords[BLF_VARIATIONS_MAX];
+ /* Load current design coordinates. */
+ FT_Get_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
+ /* Update design coordinates with new values. */
+ weight_done = blf_glyph_set_variation_normalized(
+ glyph_font, coords, blf_variation_axis_weight, weight);
+ slant_done = blf_glyph_set_variation_normalized(
+ glyph_font, coords, blf_variation_axis_slant, slant);
+ width_done = blf_glyph_set_variation_normalized(
+ glyph_font, coords, blf_variation_axis_width, width);
+ spacing_done = blf_glyph_set_variation_normalized(
+ glyph_font, coords, blf_variation_axis_spacing, spacing);
+ /* Optical size, if available, is set to current font size. */
+ blf_glyph_set_variation_float(
+ glyph_font, coords, blf_variation_axis_optsize, settings_font->size);
+ /* Save updated design coordinates. */
+ FT_Set_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
+ }
+
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_MONOSPACED) && (settings_font != glyph_font)) {
+ blf_glyph_transform_monospace(glyph, BLI_wcwidth((char32_t)charcode) * fixed_width);
}
- 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);
+ /* Fallback glyph transforms, but only if required and not yet done. */
+
+ if (weight != 0.0f && !weight_done) {
+ blf_glyph_transform_weight(glyph, weight, glyph->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
+ }
+ if (slant != 0.0f && !slant_done) {
+ blf_glyph_transform_slant(glyph, slant);
+ }
+ if (width != 0.0f && !width_done) {
+ blf_glyph_transform_width(glyph, width);
+ }
+ if (spacing != 0.0f && !spacing_done) {
+ blf_glyph_transform_spacing(glyph, spacing);
}
if (blf_glyph_render_bitmap(glyph_font, glyph)) {
@@ -466,7 +990,8 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode)
* 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);
+ FT_GlyphSlot glyph = blf_glyph_render(
+ font, font_with_glyph, glyph_index, charcode, gc->fixed_width);
if (glyph) {
/* Save this glyph in the initial font's cache. */
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 7754f960043..84037ff4bd0 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -14,6 +14,12 @@ struct ResultBLF;
struct rctf;
struct rcti;
+/* Max number of fonts in memory. Take care that every font has a glyph cache per size/dpi,
+ * so we don't need load the same font with different size, just load one and call BLF_size. */
+#define BLF_MAX_FONT 32
+
+extern struct FontBLF *global_font[BLF_MAX_FONT];
+
void blf_batch_draw_begin(struct FontBLF *font);
void blf_batch_draw(void);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 9dfcb1a4ad6..5b55f4af0b8 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -10,6 +10,19 @@
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
+#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
+
+#define BLF_VARIATIONS_MAX 16 /* Maximum variation axes per font. */
+
+#define MAKE_DVAR_TAG(a, b, c, d) \
+ (((uint32_t)a << 24u) | ((uint32_t)b << 16u) | ((uint32_t)c << 8u) | ((uint32_t)d))
+
+#define blf_variation_axis_weight MAKE_DVAR_TAG('w', 'g', 'h', 't') /* 'wght' weight axis. */
+#define blf_variation_axis_slant MAKE_DVAR_TAG('s', 'l', 'n', 't') /* 'slnt' slant axis. */
+#define blf_variation_axis_width MAKE_DVAR_TAG('w', 'd', 't', 'h') /* 'wdth' width axis. */
+#define blf_variation_axis_spacing MAKE_DVAR_TAG('s', 'p', 'a', 'c') /* 'spac' spacing axis. */
+#define blf_variation_axis_optsize MAKE_DVAR_TAG('o', 'p', 's', 'z') /* 'opsz' optical size. */
+
/* -------------------------------------------------------------------- */
/** \name Sub-Pixel Offset & Utilities
*
@@ -125,6 +138,10 @@ typedef struct GlyphCacheBLF {
/* and DPI. */
unsigned int dpi;
+ float char_weight;
+ float char_slant;
+ float char_width;
+ float char_spacing;
bool bold;
bool italic;
@@ -226,6 +243,11 @@ typedef struct FontBLF {
/** File-path or NULL. */
char *filepath;
+ /* Copied from the SFNT OS/2 table. Bit flags for unicode blocks and ranges
+ * considered "functional". Cached here because face might not always exist.
+ * See: https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur */
+ uint UnicodeRanges[4];
+
/* aspect ratio or scale. */
float aspect[3];
@@ -270,6 +292,15 @@ typedef struct FontBLF {
/* font size. */
float size;
+ /* Axes data for Adobe MM, TrueType GX, or OpenType variation fonts. */
+ FT_MM_Var *variations;
+
+ /* Character variation; 0=default, -1=min, +1=max. */
+ float char_weight;
+ float char_slant;
+ float char_width;
+ float char_spacing;
+
/* 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 a75072f854f..9460e9413d1 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -87,7 +87,7 @@ void BLF_thumb_preview(const char *filepath,
font->pos[1] -= (int)((float)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,
+ * font for given translated string (useful in non-Latin i18n context, like Chinese,
* since many fonts will then show nothing but ugly 'missing char' in their preview).
* Does not handle all cases, but much better than nothing.
*/
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 59f0c86684d..4274ca97fd1 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -68,8 +68,8 @@ struct Object;
struct Scene;
/*
- * NOTE: all mface interfaces now officially operate on tessellated data.
- * Also, the mface origindex layer indexes mpolys, not mfaces.
+ * NOTE: all #MFace interfaces now officially operate on tessellated data.
+ * Also, the #MFace orig-index layer indexes #MPoly, not #MFace.
*/
/* keep in sync with MFace/MPoly types */
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index d5487b3558a..79d0fe6e20a 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -92,6 +92,11 @@ bool action_has_motion(const struct bAction *act);
*/
bool BKE_action_is_cyclic(const struct bAction *act);
+/**
+ * Remove all fcurves from the action.
+ */
+void BKE_action_fcurves_clear(struct bAction *act);
+
/* Action Groups API ----------------- */
/**
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 888de38dcc7..ee0f41937e2 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -158,9 +158,13 @@ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob);
* or the custom object's bounds (if the bone uses a custom object).
* Visual elements such as the envelopes radius & bendy-bone spline segments are *not* included,
* making this not so useful for viewport culling.
+ *
+ * \param use_empty_drawtype: When enabled, the draw type of empty custom-objects is taken into
+ * account when calculating the bounds.
*/
void BKE_pchan_minmax(const struct Object *ob,
const struct bPoseChannel *pchan,
+ const bool use_empty_drawtype,
float r_min[3],
float r_max[3]);
/**
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index f3a29736bc8..13eefd27bec 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -22,7 +22,7 @@ struct ID;
struct ReportList;
/** #Attribute.domain */
-typedef enum AttributeDomain {
+typedef enum eAttrDomain {
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Curve or Point Cloud Point */
ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */
@@ -30,52 +30,64 @@ typedef enum AttributeDomain {
ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */
ATTR_DOMAIN_CURVE = 4, /* A single curve in a larger curve data-block */
ATTR_DOMAIN_INSTANCE = 5, /* Instance */
+} eAttrDomain;
+#define ATTR_DOMAIN_NUM 6
- ATTR_DOMAIN_NUM
-} AttributeDomain;
-
-typedef enum AttributeDomainMask {
+typedef enum eAttrDomainMask {
ATTR_DOMAIN_MASK_POINT = (1 << 0),
ATTR_DOMAIN_MASK_EDGE = (1 << 1),
ATTR_DOMAIN_MASK_FACE = (1 << 2),
ATTR_DOMAIN_MASK_CORNER = (1 << 3),
ATTR_DOMAIN_MASK_CURVE = (1 << 4),
ATTR_DOMAIN_MASK_ALL = (1 << 5) - 1
-} AttributeDomainMask;
+} eAttrDomainMask;
+
+#define ATTR_DOMAIN_AS_MASK(domain) ((eAttrDomainMask)((1 << (int)(domain))))
/* All domains that support color attributes. */
#define ATTR_DOMAIN_MASK_COLOR \
- ((AttributeDomainMask)((ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER)))
+ ((eAttrDomainMask)((ATTR_DOMAIN_MASK_POINT | ATTR_DOMAIN_MASK_CORNER)))
/* Attributes. */
-bool BKE_id_attributes_supported(struct ID *id);
+bool BKE_id_attributes_supported(const struct ID *id);
+bool BKE_attribute_allow_procedural_access(const char *attribute_name);
/**
* Create a new attribute layer.
*/
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 ID *id, const char *name, int type, eAttrDomain domain, struct ReportList *reports);
+bool BKE_id_attribute_remove(struct ID *id, const char *name, struct ReportList *reports);
+
+/**
+ * Creates a duplicate attribute layer.
+ */
+struct CustomDataLayer *BKE_id_attribute_duplicate(struct ID *id,
+ const char *name,
+ struct ReportList *reports);
struct CustomDataLayer *BKE_id_attribute_find(const struct ID *id,
const char *name,
int type,
- AttributeDomain domain);
+ eAttrDomain domain);
+
+struct CustomDataLayer *BKE_id_attribute_search(struct ID *id,
+ const char *name,
+ eCustomDataMask type,
+ eAttrDomainMask domain_mask);
-AttributeDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer);
+eAttrDomain BKE_id_attribute_domain(const struct ID *id, const struct CustomDataLayer *layer);
int BKE_id_attribute_data_length(struct ID *id, struct CustomDataLayer *layer);
-bool BKE_id_attribute_required(struct ID *id, struct CustomDataLayer *layer);
+bool BKE_id_attribute_required(const struct ID *id, const char *name);
bool BKE_id_attribute_rename(struct ID *id,
- struct CustomDataLayer *layer,
+ const char *old_name,
const char *new_name,
struct ReportList *reports);
int BKE_id_attributes_length(const struct ID *id,
- AttributeDomainMask domain_mask,
- CustomDataMask mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask);
struct CustomDataLayer *BKE_id_attributes_active_get(struct ID *id);
void BKE_id_attributes_active_set(struct ID *id, struct CustomDataLayer *layer);
@@ -84,24 +96,24 @@ int *BKE_id_attributes_active_index_p(struct ID *id);
CustomData *BKE_id_attributes_iterator_next_domain(struct ID *id, struct CustomDataLayer *layers);
CustomDataLayer *BKE_id_attribute_from_index(struct ID *id,
int lookup_index,
- AttributeDomainMask domain_mask,
- CustomDataMask layer_mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask layer_mask);
/** Layer is allowed to be nullptr; if so -1 (layer not found) will be returned. */
int BKE_id_attribute_to_index(const struct ID *id,
const CustomDataLayer *layer,
- AttributeDomainMask domain_mask,
- CustomDataMask layer_mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask layer_mask);
struct CustomDataLayer *BKE_id_attribute_subset_active_get(const struct ID *id,
int active_flag,
- AttributeDomainMask domain_mask,
- CustomDataMask mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask);
void BKE_id_attribute_subset_active_set(struct ID *id,
struct CustomDataLayer *layer,
int active_flag,
- AttributeDomainMask domain_mask,
- CustomDataMask mask);
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask);
/**
* Sets up a temporary ID with arbitrary CustomData domains. `r_id` will
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
new file mode 100644
index 00000000000..108993d91c0
--- /dev/null
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -0,0 +1,834 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_color.hh"
+#include "BLI_function_ref.hh"
+#include "BLI_generic_span.hh"
+#include "BLI_generic_virtual_array.hh"
+#include "BLI_math_vec_types.hh"
+#include "BLI_set.hh"
+
+#include "BKE_anonymous_attribute.hh"
+#include "BKE_attribute.h"
+
+struct Mesh;
+struct PointCloud;
+
+namespace blender::bke {
+
+/**
+ * Identifies an attribute that is either named or anonymous.
+ * It does not own the identifier, so it is just a reference.
+ */
+class AttributeIDRef {
+ private:
+ StringRef name_;
+ const AnonymousAttributeID *anonymous_id_ = nullptr;
+
+ public:
+ 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);
+};
+
+/**
+ * Contains information about an attribute in a geometry component.
+ * More information can be added in the future. E.g. whether the attribute is builtin and how it is
+ * stored (uv map, vertex group, ...).
+ */
+struct AttributeMetaData {
+ eAttrDomain domain;
+ eCustomDataType data_type;
+
+ constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b)
+ {
+ return (a.domain == b.domain) && (a.data_type == b.data_type);
+ }
+};
+
+struct AttributeKind {
+ eAttrDomain domain;
+ eCustomDataType data_type;
+};
+
+/**
+ * Base class for the attribute initializer types described below.
+ */
+struct AttributeInit {
+ enum class Type {
+ Default,
+ VArray,
+ MoveArray,
+ };
+ Type type;
+ AttributeInit(const Type type) : type(type)
+ {
+ }
+};
+
+/**
+ * Create an attribute using the default value for the data type.
+ * The default values may depend on the attribute provider implementation.
+ */
+struct AttributeInitDefault : public AttributeInit {
+ AttributeInitDefault() : AttributeInit(Type::Default)
+ {
+ }
+};
+
+/**
+ * Create an attribute by copying data from an existing virtual array. The virtual array
+ * must have the same type as the newly created attribute.
+ *
+ * Note that this can be used to fill the new attribute with the default
+ */
+struct AttributeInitVArray : public AttributeInit {
+ blender::GVArray varray;
+
+ AttributeInitVArray(blender::GVArray varray)
+ : AttributeInit(Type::VArray), varray(std::move(varray))
+ {
+ }
+};
+
+/**
+ * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data.
+ * Sometimes data is created before a geometry component is available. In that case, it's
+ * preferable to move data directly to the created attribute to avoid a new allocation and a copy.
+ *
+ * Note that this will only have a benefit for attributes that are stored directly as contiguous
+ * arrays, so not for some built-in attributes.
+ *
+ * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it
+ * can't be used directly, and that is generally how Blender expects custom data to be allocated.
+ */
+struct AttributeInitMove : public AttributeInit {
+ void *data = nullptr;
+
+ AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data)
+ {
+ }
+};
+
+/* Returns false when the iteration should be stopped. */
+using AttributeForeachCallback =
+ FunctionRef<bool(const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data)>;
+
+/**
+ * Result when looking up an attribute from some geometry with the intention of only reading from
+ * it.
+ */
+template<typename T> struct AttributeReader {
+ /**
+ * Virtual array that provides access to the attribute data. This may be empty.
+ */
+ VArray<T> varray;
+ /**
+ * Domain where the attribute is stored. This also determines the size of the virtual array.
+ */
+ eAttrDomain domain;
+
+ operator bool() const
+ {
+ return this->varray;
+ }
+};
+
+/**
+ * Result when looking up an attribute from some geometry with read an write access. After writing
+ * to the attribute, the #finish method has to be called. This may invalidate caches based on this
+ * attribute.
+ */
+template<typename T> struct AttributeWriter {
+ /**
+ * Virtual array giving read and write access to the attribute. This may be empty.
+ * Consider using #SpanAttributeWriter when you want to access the virtual array as a span.
+ */
+ VMutableArray<T> varray;
+ /**
+ * Domain where the attribute is stored on the geometry. Also determines the size of the virtual
+ * array.
+ */
+ eAttrDomain domain;
+ /**
+ * A function that has to be called after the attribute has been edited. This may be empty.
+ */
+ std::function<void()> tag_modified_fn;
+
+ operator bool() const
+ {
+ return this->varray;
+ }
+
+ /**
+ * Has to be called after the attribute has been modified.
+ */
+ void finish()
+ {
+ if (this->tag_modified_fn) {
+ this->tag_modified_fn();
+ }
+ }
+};
+
+/**
+ * A version of #AttributeWriter for the common case when the user of the attribute wants to write
+ * to a span instead of a virtual array. Since most attributes are spans internally, this can
+ * result in better performance and also simplifies code.
+ */
+template<typename T> struct SpanAttributeWriter {
+ /**
+ * A span based on the virtual array that contains the attribute data. This may be empty.
+ */
+ MutableVArraySpan<T> span;
+ /**
+ * Domain of the attribute. Also determines the size of the span.
+ */
+ eAttrDomain domain;
+ /**
+ * Has to be called after writing to the span.
+ */
+ std::function<void()> tag_modified_fn;
+
+ SpanAttributeWriter() = default;
+
+ SpanAttributeWriter(AttributeWriter<T> &&other, const bool copy_values_to_span)
+ : span(std::move(other.varray), copy_values_to_span),
+ domain(other.domain),
+ tag_modified_fn(std::move(other.tag_modified_fn))
+ {
+ }
+
+ operator bool() const
+ {
+ return span.varray();
+ }
+
+ /**
+ * Has to be called when done writing to the attribute. This makes sure that the data is copied
+ * to the underlying attribute if it was not stored as an array. Furthermore, this may invalidate
+ * other data depending on the modified attribute.
+ */
+ void finish()
+ {
+ this->span.save();
+ if (this->tag_modified_fn) {
+ this->tag_modified_fn();
+ }
+ }
+};
+
+/**
+ * A generic version of #AttributeReader.
+ */
+struct GAttributeReader {
+ GVArray varray;
+ eAttrDomain domain;
+
+ operator bool() const
+ {
+ return this->varray;
+ }
+
+ template<typename T> AttributeReader<T> typed() const
+ {
+ return {varray.typed<T>(), domain};
+ }
+};
+
+/**
+ * A generic version of #AttributeWriter.
+ */
+struct GAttributeWriter {
+ GVMutableArray varray;
+ eAttrDomain domain;
+ std::function<void()> tag_modified_fn;
+
+ operator bool() const
+ {
+ return this->varray;
+ }
+
+ void finish()
+ {
+ if (this->tag_modified_fn) {
+ this->tag_modified_fn();
+ }
+ }
+
+ template<typename T> AttributeWriter<T> typed() const
+ {
+ return {varray.typed<T>(), domain, tag_modified_fn};
+ }
+};
+
+/**
+ * A generic version of #SpanAttributeWriter.
+ */
+struct GSpanAttributeWriter {
+ GMutableVArraySpan span;
+ eAttrDomain domain;
+ std::function<void()> tag_modified_fn;
+
+ GSpanAttributeWriter() = default;
+
+ GSpanAttributeWriter(GAttributeWriter &&other, const bool copy_values_to_span)
+ : span(std::move(other.varray), copy_values_to_span),
+ domain(other.domain),
+ tag_modified_fn(std::move(other.tag_modified_fn))
+ {
+ }
+
+ operator bool() const
+ {
+ return span.varray();
+ }
+
+ void finish()
+ {
+ this->span.save();
+ if (this->tag_modified_fn) {
+ this->tag_modified_fn();
+ }
+ }
+};
+
+/**
+ * Core functions which make up the attribute API. They should not be called directly, but through
+ * #AttributesAccessor or #MutableAttributesAccessor.
+ *
+ * This is similar to a virtual function table. A struct of function pointers is used instead,
+ * because this way the attribute accessors can be trivial and can be passed around by value. This
+ * makes it easy to return the attribute accessor for a geometry from a function.
+ */
+struct AttributeAccessorFunctions {
+ bool (*contains)(const void *owner, const AttributeIDRef &attribute_id);
+ std::optional<AttributeMetaData> (*lookup_meta_data)(const void *owner,
+ const AttributeIDRef &attribute_id);
+ bool (*domain_supported)(const void *owner, eAttrDomain domain);
+ int (*domain_size)(const void *owner, eAttrDomain domain);
+ bool (*is_builtin)(const void *owner, const AttributeIDRef &attribute_id);
+ GAttributeReader (*lookup)(const void *owner, const AttributeIDRef &attribute_id);
+ GVArray (*adapt_domain)(const void *owner,
+ const GVArray &varray,
+ eAttrDomain from_domain,
+ eAttrDomain to_domain);
+ bool (*for_all)(const void *owner,
+ FunctionRef<bool(const AttributeIDRef &, const AttributeMetaData &)> fn);
+
+ GAttributeWriter (*lookup_for_write)(void *owner, const AttributeIDRef &attribute_id);
+ bool (*remove)(void *owner, const AttributeIDRef &attribute_id);
+ bool (*add)(void *owner,
+ const AttributeIDRef &attribute_id,
+ eAttrDomain domain,
+ eCustomDataType data_type,
+ const AttributeInit &initializer);
+};
+
+/**
+ * Provides read-only access to the set of attributes on some geometry.
+ *
+ * Note, this does not own the attributes. When the owner is freed, it is invalid to access its
+ * attributes.
+ */
+class AttributeAccessor {
+ protected:
+ /**
+ * The data that actually owns the attributes, for example, a pointer to a #Mesh or #PointCloud
+ * Most commonly this is a pointer to a #Mesh or #PointCloud.
+ * Under some circumstances this can be null. In that case most methods can't be used. Allowed
+ * methods are #domain_size, #for_all and #is_builtin. We could potentially make these methods
+ * accessible without #AttributeAccessor and then #owner_ could always be non-null.
+ *
+ * \note This class cannot modify the owner's attributes, but the pointer is still non-const, so
+ * this class can be a base class for the mutable version.
+ */
+ void *owner_;
+ /**
+ * Functions that know how to access the attributes stored in the owner above.
+ */
+ const AttributeAccessorFunctions *fn_;
+
+ public:
+ AttributeAccessor(const void *owner, const AttributeAccessorFunctions &fn)
+ : owner_(const_cast<void *>(owner)), fn_(&fn)
+ {
+ }
+
+ /**
+ * \return True, when the attribute is available.
+ */
+ bool contains(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->contains(owner_, attribute_id);
+ }
+
+ /**
+ * \return Information about the attribute if it exists.
+ */
+ std::optional<AttributeMetaData> lookup_meta_data(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->lookup_meta_data(owner_, attribute_id);
+ }
+
+ /**
+ * \return True, when attributes can exist on that domain.
+ */
+ bool domain_supported(const eAttrDomain domain) const
+ {
+ return fn_->domain_supported(owner_, domain);
+ }
+
+ /**
+ * \return Number of elements in the given domain.
+ */
+ int domain_size(const eAttrDomain domain) const
+ {
+ return fn_->domain_size(owner_, domain);
+ }
+
+ /**
+ * \return True, when the attribute has a special meaning for Blender and can't be used for
+ * arbitrary things.
+ */
+ bool is_builtin(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->is_builtin(owner_, attribute_id);
+ }
+
+ /**
+ * Get read-only access to the attribute. If the attribute does not exist, the return value is
+ * empty.
+ */
+ GAttributeReader lookup(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->lookup(owner_, attribute_id);
+ }
+
+ /**
+ * Get read-only access to the attribute. If necessary, the attribute is interpolated to the
+ * given domain, and converted to the given type, in that order. The result may be empty.
+ */
+ GVArray lookup(const AttributeIDRef &attribute_id,
+ const std::optional<eAttrDomain> domain,
+ const std::optional<eCustomDataType> data_type) const;
+
+ /**
+ * Get read-only access to the attribute whereby the attribute is interpolated to the given
+ * domain. The result may be empty.
+ */
+ GVArray lookup(const AttributeIDRef &attribute_id, const eAttrDomain domain) const
+ {
+ return this->lookup(attribute_id, domain, std::nullopt);
+ }
+
+ /**
+ * Get read-only access to the attribute whereby the attribute is converted to the given type.
+ * The result may be empty.
+ */
+ GVArray lookup(const AttributeIDRef &attribute_id, const eCustomDataType data_type) const
+ {
+ return this->lookup(attribute_id, std::nullopt, data_type);
+ }
+
+ /**
+ * Get read-only access to the attribute. If necessary, the attribute is interpolated to the
+ * given domain and then converted to the given type, in that order. The result may be empty.
+ */
+ template<typename T>
+ VArray<T> lookup(const AttributeIDRef &attribute_id,
+ const std::optional<eAttrDomain> domain = std::nullopt) const
+ {
+ const CPPType &cpp_type = CPPType::get<T>();
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type);
+ return this->lookup(attribute_id, domain, data_type).typed<T>();
+ }
+
+ /**
+ * Get read-only access to the attribute. If necessary, the attribute is interpolated to the
+ * given domain and then converted to the given data type, in that order.
+ * If the attribute does not exist, a virtual array with the given default value is returned.
+ * If the passed in default value is null, the default value of the type is used (generally 0).
+ */
+ GVArray lookup_or_default(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const void *default_value = nullptr) const;
+
+ /**
+ * Same as the generic version above, but should be used when the type is known at compile time.
+ */
+ template<typename T>
+ VArray<T> lookup_or_default(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const T &default_value) const
+ {
+ if (VArray<T> varray = this->lookup<T>(attribute_id, domain)) {
+ return varray;
+ }
+ return VArray<T>::ForSingle(default_value, this->domain_size(domain));
+ }
+
+ /**
+ * Interpolate data from one domain to another.
+ */
+ GVArray adapt_domain(const GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
+ {
+ return fn_->adapt_domain(owner_, varray, from_domain, to_domain);
+ }
+
+ /**
+ * Interpolate data from one domain to another.
+ */
+ template<typename T>
+ VArray<T> adapt_domain(const VArray<T> &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) const
+ {
+ return this->adapt_domain(GVArray(varray), from_domain, to_domain).typed<T>();
+ }
+
+ /**
+ * Run the provided function for every attribute.
+ */
+ bool for_all(const AttributeForeachCallback fn) const
+ {
+ if (owner_ != nullptr) {
+ return fn_->for_all(owner_, fn);
+ }
+ return true;
+ }
+
+ /**
+ * Get a set of all attributes.
+ */
+ Set<AttributeIDRef> all_ids() const;
+};
+
+/**
+ * Extends #AttributeAccessor with methods that allow modifying individual attributes as well as
+ * the set of attributes.
+ */
+class MutableAttributeAccessor : public AttributeAccessor {
+ public:
+ MutableAttributeAccessor(void *owner, const AttributeAccessorFunctions &fn)
+ : AttributeAccessor(owner, fn)
+ {
+ }
+
+ /**
+ * Get a writable attribute or none if it does not exist.
+ * Make sure to call #finish after changes are done.
+ */
+ GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id)
+ {
+ return fn_->lookup_for_write(owner_, attribute_id);
+ }
+
+ /**
+ * Get a writable attribute or non if it does not exist.
+ * Make sure to call #finish after changes are done.
+ */
+ template<typename T> AttributeWriter<T> lookup_for_write(const AttributeIDRef &attribute_id)
+ {
+ GAttributeWriter attribute = this->lookup_for_write(attribute_id);
+ if (!attribute) {
+ return {};
+ }
+ if (!attribute.varray.type().is<T>()) {
+ return {};
+ }
+ return attribute.typed<T>();
+ }
+
+ /**
+ * Create a new attribute.
+ * \return True, when a new attribute has been created. False, when it's not possible to create
+ * this attribute or there is already an attribute with that id.
+ */
+ bool add(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer)
+ {
+ return fn_->add(owner_, attribute_id, domain, data_type, initializer);
+ }
+
+ /**
+ * Find an attribute with the given id, domain and data type. If it does not exist, create a new
+ * attribute. If the attribute does not exist and can't be created (e.g. because it already
+ * exists on a different domain or with a different type), none is returned.
+ */
+ GAttributeWriter lookup_or_add_for_write(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer = AttributeInitDefault());
+
+ /**
+ * Same as above, but returns a type that makes it easier to work with the attribute as a span.
+ * If the caller newly initializes the attribute, it's better to use
+ * #lookup_or_add_for_write_only_span.
+ */
+ GSpanAttributeWriter lookup_or_add_for_write_span(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer = AttributeInitDefault());
+
+ /**
+ * Same as above, but should be used when the type is known at compile time.
+ */
+ template<typename T>
+ AttributeWriter<T> lookup_or_add_for_write(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const AttributeInit &initializer = AttributeInitDefault())
+ {
+ const CPPType &cpp_type = CPPType::get<T>();
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type);
+ return this->lookup_or_add_for_write(attribute_id, domain, data_type, initializer).typed<T>();
+ }
+
+ /**
+ * Same as above, but should be used when the type is known at compile time.
+ */
+ template<typename T>
+ SpanAttributeWriter<T> lookup_or_add_for_write_span(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const AttributeInit &initializer = AttributeInitDefault())
+ {
+ AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>(
+ attribute_id, domain, initializer);
+ if (attribute) {
+ return SpanAttributeWriter<T>{std::move(attribute), true};
+ }
+ return {};
+ }
+
+ /**
+ * Find an attribute with the given id, domain and data type. If it does not exist, create a new
+ * attribute. If the attribute does not exist and can't be created, none is returned.
+ *
+ * The "only" in the name indicates that the caller should not read existing values from the
+ * span. If the attribute is not stored as span internally, the existing values won't be copied
+ * over to the span.
+ */
+ GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type);
+
+ /**
+ * Same as above, but should be used when the type is known at compile time.
+ */
+ template<typename T>
+ SpanAttributeWriter<T> lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain)
+ {
+ AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>(attribute_id, domain);
+ if (attribute) {
+ return SpanAttributeWriter<T>{std::move(attribute), false};
+ }
+ return {};
+ }
+
+ /**
+ * Remove an attribute.
+ * \return True, when the attribute has been deleted. False, when it's not possible to delete
+ * this attribute or if there is no attribute with that id.
+ */
+ bool remove(const AttributeIDRef &attribute_id)
+ {
+ return fn_->remove(owner_, attribute_id);
+ }
+
+ /**
+ * Remove all anonymous attributes.
+ */
+ void remove_anonymous();
+};
+
+struct AttributeTransferData {
+ /* Expect that if an attribute exists, it is stored as a contiguous array internally anyway. */
+ GVArraySpan src;
+ AttributeMetaData meta_data;
+ bke::GSpanAttributeWriter dst;
+};
+/**
+ * Retrieve attribute arrays and writers for attributes that should be transferred between
+ * data-blocks of the same type.
+ */
+Vector<AttributeTransferData> retrieve_attributes_for_transfer(
+ const bke::AttributeAccessor &src_attributes,
+ bke::MutableAttributeAccessor &dst_attributes,
+ eAttrDomainMask domain_mask,
+ const Set<std::string> &skip = {});
+
+bool allow_procedural_attribute_access(StringRef attribute_name);
+extern const char *no_procedural_access_message;
+
+eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> 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.
+ */
+eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains);
+
+/**
+ * A basic container around DNA CustomData so that its users
+ * don't have to implement special copy and move constructors.
+ */
+class CustomDataAttributes {
+ /**
+ * #CustomData needs a size to be freed, and unfortunately it isn't stored in the struct
+ * itself, so keep track of the size here so this class can implement its own destructor.
+ * If the implementation of the attribute storage changes, this could be removed.
+ */
+ int size_;
+
+ public:
+ CustomData data;
+
+ CustomDataAttributes();
+ ~CustomDataAttributes();
+ CustomDataAttributes(const CustomDataAttributes &other);
+ CustomDataAttributes(CustomDataAttributes &&other);
+ CustomDataAttributes &operator=(const CustomDataAttributes &other);
+
+ void reallocate(int size);
+
+ void clear();
+
+ std::optional<blender::GSpan> get_for_read(const AttributeIDRef &attribute_id) 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::GVArray get_for_read(const AttributeIDRef &attribute_id,
+ eCustomDataType data_type,
+ const void *default_value) const;
+
+ template<typename T>
+ blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const
+ {
+ const blender::CPPType &cpp_type = blender::CPPType::get<T>();
+ const eCustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ GVArray varray = this->get_for_read(attribute_id, type, &default_value);
+ return varray.typed<T>();
+ }
+
+ std::optional<blender::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id);
+ bool create(const AttributeIDRef &attribute_id, eCustomDataType data_type);
+ bool create_by_move(const AttributeIDRef &attribute_id, eCustomDataType data_type, void *buffer);
+ bool remove(const AttributeIDRef &attribute_id);
+
+ /**
+ * 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, eAttrDomain domain) const;
+};
+
+AttributeAccessor mesh_attributes(const Mesh &mesh);
+MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh);
+
+AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud);
+MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud);
+
+/* -------------------------------------------------------------------- */
+/** \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_);
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
deleted file mode 100644
index 8d449a124ec..00000000000
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ /dev/null
@@ -1,543 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-#include <mutex>
-
-#include "BKE_anonymous_attribute.hh"
-#include "BKE_attribute.h"
-
-#include "BLI_color.hh"
-#include "BLI_function_ref.hh"
-#include "BLI_generic_span.hh"
-#include "BLI_generic_virtual_array.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 {
-
-/**
- * Identifies an attribute that is either named or anonymous.
- * It does not own the identifier, so it is just a reference.
- */
-class AttributeIDRef {
- private:
- StringRef name_;
- const AnonymousAttributeID *anonymous_id_ = nullptr;
-
- public:
- 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);
-};
-
-} // namespace blender::bke
-
-/**
- * Contains information about an attribute in a geometry component.
- * More information can be added in the future. E.g. whether the attribute is builtin and how it is
- * stored (uv map, vertex group, ...).
- */
-struct AttributeMetaData {
- AttributeDomain domain;
- CustomDataType data_type;
-
- constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b)
- {
- return (a.domain == b.domain) && (a.data_type == b.data_type);
- }
-};
-
-struct AttributeKind {
- AttributeDomain domain;
- CustomDataType data_type;
-};
-
-/**
- * Base class for the attribute initializer types described below.
- */
-struct AttributeInit {
- enum class Type {
- Default,
- VArray,
- MoveArray,
- };
- Type type;
- AttributeInit(const Type type) : type(type)
- {
- }
-};
-
-/**
- * Create an attribute using the default value for the data type.
- * The default values may depend on the attribute provider implementation.
- */
-struct AttributeInitDefault : public AttributeInit {
- AttributeInitDefault() : AttributeInit(Type::Default)
- {
- }
-};
-
-/**
- * Create an attribute by copying data from an existing virtual array. The virtual array
- * must have the same type as the newly created attribute.
- *
- * Note that this can be used to fill the new attribute with the default
- */
-struct AttributeInitVArray : public AttributeInit {
- blender::GVArray varray;
-
- AttributeInitVArray(blender::GVArray varray)
- : AttributeInit(Type::VArray), varray(std::move(varray))
- {
- }
-};
-
-/**
- * Create an attribute with a by passing ownership of a pre-allocated contiguous array of data.
- * Sometimes data is created before a geometry component is available. In that case, it's
- * preferable to move data directly to the created attribute to avoid a new allocation and a copy.
- *
- * Note that this will only have a benefit for attributes that are stored directly as contiguous
- * arrays, so not for some built-in attributes.
- *
- * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it
- * can't be used directly, and that is generally how Blender expects custom data to be allocated.
- */
-struct AttributeInitMove : public AttributeInit {
- void *data = nullptr;
-
- AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data)
- {
- }
-};
-
-/* Returns false when the iteration should be stopped. */
-using AttributeForeachCallback = blender::FunctionRef<bool(
- const blender::bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data)>;
-
-namespace blender::bke {
-
-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);
-
-/**
- * Used when looking up a "plain attribute" based on a name for reading from it.
- */
-struct ReadAttributeLookup {
- /* The virtual array that is used to read from this attribute. */
- 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;
- }
-};
-
-/**
- * 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. */
- 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;
- }
-};
-
-/**
- * An output attribute allows writing to an attribute (and optionally reading as well). It adds
- * some convenience features on top of `GVMutableArray` that are very commonly used.
- *
- * Supported convenience features:
- * - Implicit type conversion when writing to builtin attributes.
- * - Supports simple access to a span containing the attribute values (that avoids the use of
- * 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 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:
- GVMutableArray varray_;
- AttributeDomain domain_ = ATTR_DOMAIN_AUTO;
- SaveFn save_;
- std::unique_ptr<GVMutableArray_GSpan> optional_span_varray_;
- bool ignore_old_values_ = false;
- bool save_has_been_called_ = false;
-
- public:
- OutputAttribute();
- OutputAttribute(OutputAttribute &&other);
- OutputAttribute(GVMutableArray varray,
- AttributeDomain domain,
- SaveFn save,
- bool ignore_old_values);
-
- ~OutputAttribute();
-
- operator bool() const;
-
- GVMutableArray &operator*();
- GVMutableArray *operator->();
- GVMutableArray &varray();
- AttributeDomain domain() const;
- const CPPType &cpp_type() const;
- CustomDataType custom_data_type() const;
-
- GMutableSpan as_span();
- template<typename T> MutableSpan<T> as_span();
-
- void save();
-};
-
-/**
- * Same as OutputAttribute, but should be used when the data type is known at compile time.
- */
-template<typename T> class OutputAttribute_Typed {
- private:
- OutputAttribute attribute_;
- VMutableArray<T> varray_;
-
- public:
- OutputAttribute_Typed();
- OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute))
- {
- if (attribute_) {
- 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_;
- }
-
- VMutableArray<T> &operator*()
- {
- return varray_;
- }
-
- VMutableArray<T> *operator->()
- {
- return &varray_;
- }
-
- VMutableArray<T> &varray()
- {
- return varray_;
- }
-
- AttributeDomain domain() const
- {
- return attribute_.domain();
- }
-
- const CPPType &cpp_type() const
- {
- return CPPType::get<T>();
- }
-
- CustomDataType custom_data_type() const
- {
- return cpp_type_to_custom_data_type(this->cpp_type());
- }
-
- MutableSpan<T> as_span()
- {
- return attribute_.as_span<T>();
- }
-
- void save()
- {
- attribute_.save();
- }
-};
-
-/* 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.
- */
-class CustomDataAttributes {
- /**
- * #CustomData needs a size to be freed, and unfortunately it isn't stored in the struct
- * itself, so keep track of the size here so this class can implement its own destructor.
- * If the implementation of the attribute storage changes, this could be removed.
- */
- int size_;
-
- public:
- CustomData data;
-
- CustomDataAttributes();
- ~CustomDataAttributes();
- CustomDataAttributes(const CustomDataAttributes &other);
- CustomDataAttributes(CustomDataAttributes &&other);
- CustomDataAttributes &operator=(const CustomDataAttributes &other);
-
- void reallocate(int size);
-
- void clear();
-
- std::optional<blender::GSpan> get_for_read(const AttributeIDRef &attribute_id) 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::GVArray get_for_read(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- const void *default_value) const;
-
- template<typename T>
- blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const
- {
- const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- GVArray varray = this->get_for_read(attribute_id, type, &default_value);
- return varray.typed<T>();
- }
-
- std::optional<blender::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id);
- bool create(const AttributeIDRef &attribute_id, const CustomDataType data_type);
- bool create_by_move(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- void *buffer);
- bool remove(const AttributeIDRef &attribute_id);
-
- /**
- * 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 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 3d194ba77dc..01c2ef988f2 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -39,7 +39,7 @@ inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
}
template<typename Func>
-inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
+inline void convert_to_static_type(const eCustomDataType data_type, const Func &func)
{
const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(data_type);
convert_to_static_type(cpp_type, func);
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index ab13a2e85d0..efe44ec657b 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -25,7 +25,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 0
+#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
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index a98f4802991..4d728002c87 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -119,10 +119,6 @@ float BKE_brush_sample_masktex(const struct Scene *scene,
int thread,
struct ImagePool *pool);
-/* Texture. */
-
-unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool use_secondary);
-
/**
* Radial control.
*/
diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h
index 8b2af96a063..8c65214c78e 100644
--- a/source/blender/blenkernel/BKE_callbacks.h
+++ b/source/blender/blenkernel/BKE_callbacks.h
@@ -97,6 +97,12 @@ typedef enum {
BKE_CB_EVT_XR_SESSION_START_PRE,
BKE_CB_EVT_ANNOTATION_PRE,
BKE_CB_EVT_ANNOTATION_POST,
+ BKE_CB_EVT_OBJECT_BAKE_PRE,
+ BKE_CB_EVT_OBJECT_BAKE_COMPLETE,
+ BKE_CB_EVT_OBJECT_BAKE_CANCEL,
+ BKE_CB_EVT_COMPOSITE_PRE,
+ BKE_CB_EVT_COMPOSITE_POST,
+ BKE_CB_EVT_COMPOSITE_CANCEL,
BKE_CB_EVT_TOT,
} eCbEvent;
diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h
index e55b8b1a2da..afe0eb35c4d 100644
--- a/source/blender/blenkernel/BKE_camera.h
+++ b/source/blender/blenkernel/BKE_camera.h
@@ -164,6 +164,15 @@ bool BKE_camera_multiview_spherical_stereo(const struct RenderData *rd,
/* Camera background image API */
struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam);
+
+/**
+ * Duplicate a background image, in a ID management compatible way.
+ *
+ * \param copy_flag: The usual ID copying flags, see `LIB_ID_CREATE_`/`LIB_ID_COPY_` enums in
+ * `BKE_lib_id.h`.
+ */
+struct CameraBGImage *BKE_camera_background_image_copy(struct CameraBGImage *bgpic_src,
+ const int copy_flag);
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_collection.h b/source/blender/blenkernel/BKE_collection.h
index a3bbcc8687a..feb3dc7de80 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -115,6 +115,18 @@ bool BKE_collection_is_empty(const struct Collection *collection);
bool BKE_collection_object_add(struct Main *bmain,
struct Collection *collection,
struct Object *ob);
+
+/**
+ * Add object to given collection, similar to #BKE_collection_object_add.
+ *
+ * However, it additionally ensures that the selected collection is also part of the given
+ * `view_layer`, if non-NULL. Otherwise, the object is not added to any collection.
+ */
+bool BKE_collection_viewlayer_object_add(struct Main *bmain,
+ const struct ViewLayer *view_layer,
+ struct Collection *collection,
+ struct Object *ob);
+
/**
* Same as #BKE_collection_object_add, but unconditionally adds the object to the given collection.
*
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
index ce1f4c2b98c..3186be3674d 100644
--- a/source/blender/blenkernel/BKE_constraint.h
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -265,6 +265,8 @@ void BKE_constraint_panel_expand(struct bConstraint *con);
/* Constraint Evaluation function prototypes */
/**
+ * 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.
*/
@@ -307,6 +309,25 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
void *ownerdata,
float mat[4][4],
float ctime);
+
+/**
+ * Retrieves the list of all constraint targets, including the custom space target.
+ * Must be followed by a call to BKE_constraint_targets_flush to free memory.
+ *
+ * \param r_targets: Pointer to the list to be initialized with target data.
+ * \returns the number of targets stored in the list.
+ */
+int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets);
+
+/**
+ * Copies changed data from the list produced by #BKE_constraint_targets_get back to the constraint
+ * data structures and frees memory.
+ *
+ * \param targets: List of targets filled by BKE_constraint_targets_get.
+ * \param no_copy: Only free memory without copying changes (read-only mode).
+ */
+void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy);
+
/**
* Get the list of targets required for solving a constraint.
*/
@@ -315,7 +336,15 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
struct bConstraintOb *ob,
struct ListBase *targets,
float ctime);
-void BKE_constraint_custom_object_space_get(float r_mat[4][4], struct bConstraint *con);
+
+/**
+ * Initialize the Custom Space matrix inside `cob` (if required by the constraint).
+ *
+ * \param cob: Constraint evaluation context (contains the matrix to be initialized).
+ * \param con: Constraint that is about to be evaluated.
+ */
+void BKE_constraint_custom_object_space_init(struct bConstraintOb *cob, 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.
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index d9d23473e34..19824cf3a5c 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -223,9 +223,10 @@ void CTX_wm_operator_poll_msg_clear(struct bContext *C);
/* Data Context
*
- * - listbases consist of CollectionPointerLink items and must be
- * freed with BLI_freelistN!
- * - the dir listbase consists of LinkData items */
+ * - #ListBase consists of #CollectionPointerLink items and must be
+ * freed with #BLI_freelistN!
+ * - The dir #ListBase consists of #LinkData items.
+ */
/* data type, needed so we can tell between a NULL pointer and an empty list */
enum {
diff --git a/source/blender/blenkernel/BKE_curve_legacy_convert.hh b/source/blender/blenkernel/BKE_curve_legacy_convert.hh
new file mode 100644
index 00000000000..88f93282f25
--- /dev/null
+++ b/source/blender/blenkernel/BKE_curve_legacy_convert.hh
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_curves.hh"
+
+struct Curve;
+struct Curves;
+
+namespace blender::bke {
+
+Curves *curve_legacy_to_curves(const Curve &curve_legacy);
+Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list);
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_curves.h b/source/blender/blenkernel/BKE_curves.h
index 88bb1c67fd1..c3302c6d2aa 100644
--- a/source/blender/blenkernel/BKE_curves.h
+++ b/source/blender/blenkernel/BKE_curves.h
@@ -25,7 +25,7 @@ void *BKE_curves_add(struct Main *bmain, const char *name);
struct BoundBox *BKE_curves_boundbox_get(struct Object *ob);
-bool BKE_curves_customdata_required(struct Curves *curves, struct CustomDataLayer *layer);
+bool BKE_curves_customdata_required(const struct Curves *curves, const char *name);
/* Depsgraph */
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 87fa26a4f73..68c90a45031 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -20,7 +20,7 @@
#include "BLI_vector.hh"
#include "BLI_virtual_array.hh"
-#include "BKE_attribute_access.hh"
+#include "BKE_attribute.hh"
namespace blender::bke {
@@ -182,6 +182,7 @@ class CurvesGeometry : public ::CurvesGeometry {
void update_curve_types();
bool has_curve_with_type(CurveType type) const;
+ bool has_curve_with_type(Span<CurveType> types) const;
/** Return true if all of the curves have the provided type. */
bool is_single_type(CurveType type) const;
/** Return the number of curves with each type. */
@@ -264,22 +265,15 @@ class CurvesGeometry : public ::CurvesGeometry {
MutableSpan<float> nurbs_weights_for_write();
/**
- * The index of a triangle (#MLoopTri) that a curve is attached to.
- * The index is -1, if the curve is not attached.
+ * UV coordinate for each curve that encodes where the curve is attached to the surface mesh.
*/
- VArray<int> surface_triangle_indices() const;
- MutableSpan<int> surface_triangle_indices_for_write();
+ Span<float2> surface_uv_coords() const;
+ MutableSpan<float2> surface_uv_coords_for_write();
- /**
- * Barycentric coordinates of the attachment point within a triangle.
- * Only the first two coordinates are stored. The third coordinate can be derived because the sum
- * of the three coordinates is 1.
- *
- * When the triangle index is -1, this coordinate should be ignored.
- * The span can be empty, when all triangle indices are -1.
- */
- Span<float2> surface_triangle_coords() const;
- MutableSpan<float2> surface_triangle_coords_for_write();
+ VArray<float> selection_point_float() const;
+ MutableSpan<float> selection_point_float_for_write();
+ VArray<float> selection_curve_float() const;
+ MutableSpan<float> selection_curve_float_for_write();
/**
* Calculate the largest and smallest position values, only including control points
@@ -391,8 +385,7 @@ class CurvesGeometry : public ::CurvesGeometry {
void calculate_bezier_auto_handles();
- void update_customdata_pointers();
-
+ void remove_points(IndexMask points_to_delete);
void remove_curves(IndexMask curves_to_delete);
/**
@@ -401,11 +394,24 @@ class CurvesGeometry : public ::CurvesGeometry {
*/
void reverse_curves(IndexMask curves_to_reverse);
+ /**
+ * Remove any attributes that are unused based on the types in the curves.
+ */
+ void remove_attributes_based_on_types();
+
+ AttributeAccessor attributes() const;
+ MutableAttributeAccessor attributes_for_write();
+
/* --------------------------------------------------------------------
* Attributes.
*/
- GVArray adapt_domain(const GVArray &varray, AttributeDomain from, AttributeDomain to) const;
+ GVArray adapt_domain(const GVArray &varray, eAttrDomain from, eAttrDomain to) const;
+ template<typename T>
+ VArray<T> adapt_domain(const VArray<T> &varray, eAttrDomain from, eAttrDomain to) const
+ {
+ return this->adapt_domain(GVArray(varray), from, to).typed<T>();
+ }
};
namespace curves {
@@ -418,7 +424,7 @@ namespace curves {
* The number of segments between control points, accounting for the last segment of cyclic
* curves. The logic is simple, but this function should be used to make intentions clearer.
*/
-inline int curve_segment_num(const int points_num, const bool cyclic)
+inline int segments_num(const int points_num, const bool cyclic)
{
BLI_assert(points_num > 0);
return (cyclic && points_num > 1) ? points_num : points_num - 1;
@@ -453,7 +459,7 @@ void calculate_tangents(Span<float3> positions, bool is_cyclic, MutableSpan<floa
/**
* Calculate directions perpendicular to the tangent at every point by rotating an arbitrary
- * starting vector by the same rotation of each tangent. If the curve is cylic, propagate a
+ * starting vector by the same rotation of each tangent. If the curve is cyclic, propagate a
* correction through the entire to make sure the first and last normal align.
*/
void calculate_normals_minimum(Span<float3> tangents, bool cyclic, MutableSpan<float3> normals);
@@ -478,15 +484,18 @@ namespace bezier {
* Return true if the handles that make up a segment both have a vector type. Vector segments for
* Bezier curves have special behavior because they aren't divided into many evaluated points.
*/
+bool segment_is_vector(const HandleType left, const HandleType right);
+bool segment_is_vector(const int8_t left, const int8_t right);
bool segment_is_vector(Span<int8_t> handle_types_left,
Span<int8_t> handle_types_right,
int segment_index);
/**
- * Return true if the curve's last cylic segment has a vector type.
+ * Return true if the curve's last cyclic segment has a vector type.
* This only makes a difference in the shape of cyclic curves.
*/
-bool last_cylic_segment_is_vector(Span<int8_t> handle_types_left, Span<int8_t> handle_types_right);
+bool last_cyclic_segment_is_vector(Span<int8_t> handle_types_left,
+ Span<int8_t> handle_types_right);
/**
* Return true if the handle types at the index are free (#BEZIER_HANDLE_FREE) or vector
@@ -509,6 +518,43 @@ void calculate_evaluated_offsets(Span<int8_t> handle_types_left,
int resolution,
MutableSpan<int> evaluated_offsets);
+/** See #insert. */
+struct Insertion {
+ float3 handle_prev;
+ float3 left_handle;
+ float3 position;
+ float3 right_handle;
+ float3 handle_next;
+};
+
+/**
+ * Compute the Bezier segment insertion for the given parameter on the segment, returning
+ * the position and handles of the new point and the updated existing handle positions.
+ * <pre>
+ * handle_prev handle_next
+ * x-----------------x
+ * / \
+ * / x---O---x \
+ * / result \
+ * / \
+ * O O
+ * point_prev point_next
+ * </pre>
+ */
+Insertion insert(const float3 &point_prev,
+ const float3 &handle_prev,
+ const float3 &handle_next,
+ const float3 &point_next,
+ float parameter);
+
+/**
+ * Calculate the automatically defined positions for a vector handle (#BEZIER_HANDLE_VECTOR). While
+ * this can be calculated automatically with #calculate_auto_handles, when more context is
+ * available, it can be preferable for performance reasons to calculate it for a single segment
+ * when necessary.
+ */
+float3 calculate_vector_handle(const float3 &point, const float3 &next_point);
+
/**
* Recalculate all auto (#BEZIER_HANDLE_AUTO) and vector (#BEZIER_HANDLE_VECTOR) handles with
* positions automatically derived from the neighboring control points, and update aligned
@@ -593,6 +639,15 @@ int calculate_evaluated_num(int points_num, bool cyclic, int resolution);
*/
void interpolate_to_evaluated(GSpan src, bool cyclic, int resolution, GMutableSpan dst);
+/**
+ * Evaluate the Catmull Rom curve. The size of each segment and its offset in the #dst span
+ * is encoded in #evaluated_offsets, with the same method as #CurvesGeometry::offsets().
+ */
+void interpolate_to_evaluated(const GSpan src,
+ const bool cyclic,
+ const Span<int> evaluated_offsets,
+ GMutableSpan dst);
+
} // namespace catmull_rom
/** \} */
@@ -678,6 +733,12 @@ Curves *curves_new_nomain(CurvesGeometry curves);
*/
Curves *curves_new_nomain_single(int points_num, CurveType type);
+/**
+ * Copy data from #src to #dst, except the geometry data in #CurvesGeometry. Typically used to
+ * copy high-level parameters when a geometry-altering operation creates a new curves data-block.
+ */
+void curves_copy_parameters(const Curves &src, Curves &dst);
+
std::array<int, CURVE_TYPES_NUM> calculate_type_counts(const VArray<int8_t> &types);
/* -------------------------------------------------------------------- */
@@ -711,6 +772,12 @@ inline bool CurvesGeometry::has_curve_with_type(const CurveType type) const
return this->curve_type_counts()[type] > 0;
}
+inline bool CurvesGeometry::has_curve_with_type(const Span<CurveType> types) const
+{
+ return std::any_of(
+ types.begin(), types.end(), [&](CurveType type) { return this->has_curve_with_type(type); });
+}
+
inline const std::array<int, CURVE_TYPES_NUM> &CurvesGeometry::curve_type_counts() const
{
BLI_assert(this->runtime->type_counts == calculate_type_counts(this->curve_types()));
@@ -770,7 +837,7 @@ inline IndexRange CurvesGeometry::lengths_range_for_curve(const int curve_index,
BLI_assert(cyclic == this->cyclic()[curve_index]);
const IndexRange points = this->evaluated_points_for_curve(curve_index);
const int start = points.start() + curve_index;
- return {start, curves::curve_segment_num(points.size(), cyclic)};
+ return {start, curves::segments_num(points.size(), cyclic)};
}
inline Span<float> CurvesGeometry::evaluated_lengths_for_curve(const int curve_index,
@@ -785,6 +852,9 @@ inline float CurvesGeometry::evaluated_length_total_for_curve(const int curve_in
const bool cyclic) const
{
const Span<float> lengths = this->evaluated_lengths_for_curve(curve_index, cyclic);
+ if (lengths.is_empty()) {
+ return 0.0f;
+ }
return lengths.last();
}
@@ -804,8 +874,36 @@ inline bool point_is_sharp(const Span<int8_t> handle_types_left,
ELEM(handle_types_right[index], BEZIER_HANDLE_VECTOR, BEZIER_HANDLE_FREE);
}
+inline bool segment_is_vector(const HandleType left, const HandleType right)
+{
+ return left == BEZIER_HANDLE_VECTOR && right == BEZIER_HANDLE_VECTOR;
+}
+
+inline bool segment_is_vector(const int8_t left, const int8_t right)
+{
+ return segment_is_vector(HandleType(left), HandleType(right));
+}
+
+inline float3 calculate_vector_handle(const float3 &point, const float3 &next_point)
+{
+ return math::interpolate(point, next_point, 1.0f / 3.0f);
+}
+
/** \} */
} // namespace curves::bezier
+struct CurvesSurfaceTransforms {
+ float4x4 curves_to_world;
+ float4x4 curves_to_surface;
+ float4x4 world_to_curves;
+ float4x4 world_to_surface;
+ float4x4 surface_to_world;
+ float4x4 surface_to_curves;
+ float4x4 surface_to_curves_normal;
+
+ CurvesSurfaceTransforms() = default;
+ CurvesSurfaceTransforms(const Object &curves_ob, const Object *surface_ob);
+};
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
index 62b060093e9..0fbd33002e1 100644
--- a/source/blender/blenkernel/BKE_curves_utils.hh
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -9,9 +9,60 @@
* \brief Low-level operations for curves.
*/
+#include "BLI_function_ref.hh"
+#include "BLI_generic_pointer.hh"
+
namespace blender::bke::curves {
/**
+ * Copy the provided point attribute values between all curves in the #curve_ranges index
+ * ranges, assuming that all curves have the same number of control points in #src_curves
+ * and #dst_curves.
+ */
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ Span<IndexRange> curve_ranges,
+ GSpan src,
+ GMutableSpan dst);
+
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ IndexMask src_curve_selection,
+ GSpan src,
+ GMutableSpan dst);
+
+template<typename T>
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const IndexMask src_curve_selection,
+ const Span<T> src,
+ MutableSpan<T> dst)
+{
+ copy_point_data(src_curves, dst_curves, src_curve_selection, GSpan(src), GMutableSpan(dst));
+}
+
+void fill_points(const CurvesGeometry &curves,
+ IndexMask curve_selection,
+ GPointer value,
+ GMutableSpan dst);
+
+template<typename T>
+void fill_points(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ const T &value,
+ MutableSpan<T> dst)
+{
+ fill_points(curves, curve_selection, &value, dst);
+}
+
+/**
+ * Copy only the information on the point domain, but not the offsets or any point attributes,
+ * meant for operations that change the number of points but not the number of curves.
+ * \warning The returned curves have invalid offsets!
+ */
+bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves);
+
+/**
* Copy the size of every curve in #curve_ranges to the corresponding index in #counts.
*/
void fill_curve_counts(const bke::CurvesGeometry &curves,
@@ -23,4 +74,18 @@ void fill_curve_counts(const bke::CurvesGeometry &curves,
*/
void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, int start_offset = 0);
+IndexMask indices_for_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ const CurveType type,
+ const IndexMask selection,
+ Vector<int64_t> &r_indices);
+
+void foreach_curve_by_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ IndexMask selection,
+ FunctionRef<void(IndexMask)> catmull_rom_fn,
+ FunctionRef<void(IndexMask)> poly_fn,
+ FunctionRef<void(IndexMask)> bezier_fn,
+ FunctionRef<void(IndexMask)> nurbs_fn);
+
} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index f05dfb164cf..010fbb27172 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -10,6 +10,10 @@
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
+#ifdef __cplusplus
+# include "BLI_span.hh"
+# include "BLI_vector.hh"
+#endif
#include "DNA_customdata_types.h"
@@ -24,7 +28,7 @@ struct BlendWriter;
struct CustomData;
struct CustomData_MeshMasks;
struct ID;
-typedef uint64_t CustomDataMask;
+typedef uint64_t eCustomDataMask;
/* A data type large enough to hold 1 element from any custom-data layer type. */
typedef struct {
@@ -59,7 +63,7 @@ typedef enum eCDAllocType {
CD_DUPLICATE = 4,
} eCDAllocType;
-#define CD_TYPE_AS_MASK(_type) (CustomDataMask)((CustomDataMask)1 << (CustomDataMask)(_type))
+#define CD_TYPE_AS_MASK(_type) (eCustomDataMask)((eCustomDataMask)1 << (eCustomDataMask)(_type))
void customData_mask_layers__print(const struct CustomData_MeshMasks *mask);
@@ -133,7 +137,7 @@ void CustomData_data_add(int type, void *data1, const void *data2);
*/
void CustomData_copy(const struct CustomData *source,
struct CustomData *dest,
- CustomDataMask mask,
+ eCustomDataMask mask,
eCDAllocType alloctype,
int totelem);
@@ -146,7 +150,7 @@ void CustomData_update_typemap(struct CustomData *data);
*/
bool CustomData_merge(const struct CustomData *source,
struct CustomData *dest,
- CustomDataMask mask,
+ eCustomDataMask mask,
eCDAllocType alloctype,
int totelem);
@@ -166,7 +170,7 @@ void CustomData_realloc(struct CustomData *data, int totelem);
*/
bool CustomData_bmesh_merge(const struct CustomData *source,
struct CustomData *dest,
- CustomDataMask mask,
+ eCustomDataMask mask,
eCDAllocType alloctype,
struct BMesh *bm,
char htype);
@@ -184,7 +188,7 @@ void CustomData_free(struct CustomData *data, int totelem);
/**
* Same as above, but only frees layers which matches the given mask.
*/
-void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask);
+void CustomData_free_typemask(struct CustomData *data, int totelem, eCustomDataMask mask);
/**
* Frees all layers with #CD_FLAG_TEMPORARY.
@@ -221,6 +225,7 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
* 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);
+bool CustomData_free_layer_named(struct CustomData *data, const char *name, const int totelem);
/**
* Frees the layer index with the give type.
@@ -244,7 +249,7 @@ bool CustomData_has_layer(const struct CustomData *data, int 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);
+int CustomData_number_of_layers_typemask(const struct CustomData *data, eCustomDataMask mask);
/**
* Duplicate data of a layer with flag NOFREE, and remove that flag.
@@ -272,7 +277,7 @@ 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
*/
-void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask);
+void CustomData_set_only_copy(const struct CustomData *data, eCustomDataMask mask);
/**
* Copies data from one CustomData object to another
@@ -305,7 +310,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const struct CustomData *source,
struct CustomData *dest,
void *src_block,
void **dest_block,
- CustomDataMask mask_exclude);
+ eCustomDataMask mask_exclude);
/**
* Copies data of a single layer of a given type.
@@ -484,7 +489,7 @@ void CustomData_bmesh_free_block_data(struct CustomData *data, void *block);
*/
void CustomData_bmesh_free_block_data_exclude_by_type(struct CustomData *data,
void *block,
- CustomDataMask mask_exclude);
+ eCustomDataMask mask_exclude);
/**
* Copy custom data to/from layers as in mesh/derived-mesh, to edit-mesh
@@ -545,33 +550,11 @@ void CustomData_validate_layer_name(const struct CustomData *data,
*/
bool CustomData_verify_versions(struct CustomData *data, int index);
-/* BMesh specific custom-data stuff.
- *
- * Needed to convert to/from different face representation (for versioning). */
+/* BMesh specific custom-data stuff. */
-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, 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
-
/**
* Validate and fix data of \a layer,
* if possible (needs relevant callback in layer's type to be defined).
@@ -589,14 +572,14 @@ void CustomData_external_remove(struct CustomData *data, struct ID *id, int type
bool CustomData_external_test(struct CustomData *data, int type);
void CustomData_external_write(
- struct CustomData *data, struct ID *id, CustomDataMask mask, int totelem, int free);
+ struct CustomData *data, struct ID *id, eCustomDataMask mask, int totelem, int free);
void CustomData_external_read(struct CustomData *data,
struct ID *id,
- CustomDataMask mask,
+ eCustomDataMask mask,
int totelem);
void CustomData_external_reload(struct CustomData *data,
struct ID *id,
- CustomDataMask mask,
+ eCustomDataMask mask,
int totelem);
/* Mesh-to-mesh transfer data. */
@@ -700,39 +683,33 @@ void CustomData_data_transfer(const struct MeshPairRemap *me_remap,
/* .blend file I/O */
+#ifdef __cplusplus
+
/**
* 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.
+ * \param data: The custom-data to tweak for .blend file writing (modified in place).
+ * \param layers_to_write: A reduced set of layers to be written to file.
*
- * \warning After this function 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.
+ * \warning This function invalidates the custom data struct by changing the layer counts and the
+ * #layers pointer, and by invalidating the type map. It expects to work on a shallow copy of
+ * the struct.
*/
-void CustomData_blend_write_prepare(struct CustomData *data,
- struct CustomDataLayer **r_write_layers,
- struct CustomDataLayer *write_layers_buff,
- size_t write_layers_size);
+void CustomData_blend_write_prepare(CustomData &data,
+ blender::Vector<CustomDataLayer, 16> &layers_to_write);
/**
- * \param layers: The layers argument assigned by #CustomData_blend_write_prepare.
+ * \param layers_to_write: Layers created by #CustomData_blend_write_prepare.
*/
-void CustomData_blend_write(struct BlendWriter *writer,
- struct CustomData *data,
- CustomDataLayer *layers,
+void CustomData_blend_write(BlendWriter *writer,
+ CustomData *data,
+ blender::Span<CustomDataLayer> layers_to_write,
int count,
- CustomDataMask cddata_mask,
- struct ID *id);
+ eCustomDataMask cddata_mask,
+ ID *id);
+
+#endif
+
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
#ifndef NDEBUG
@@ -751,7 +728,7 @@ void CustomData_debug_info_from_layers(const struct CustomData *data,
# include "BLI_cpp_type.hh"
namespace blender::bke {
-const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
-CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
+const CPPType *custom_data_type_to_cpp_type(eCustomDataType type);
+eCustomDataType cpp_type_to_custom_data_type(const CPPType &type);
} // namespace blender::bke
#endif
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 6784a1296e9..c5788c07336 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -259,6 +259,18 @@ struct FCurve *BKE_fcurve_iter_step(struct FCurve *fcu_iter, const char rna_path
/**
* High level function to get an f-curve from C without having the RNA.
+ *
+ * If there is an action assigned to the `id`'s #AnimData, it will be searched for a matching
+ * F-curve first. Drivers are searched only if no valid action F-curve could be found.
+ *
+ * \note Return pointer parameter (`r_driven`) is optional and may be NULL.
+ *
+ * \warning In case no animation (from an Action) F-curve is found, returned value is always NULL.
+ * This means that this function will set `r_driven` to True in case a valid driver F-curve is
+ * found, but will not return said F-curve. In other words:
+ * - Animated with FCurve: returns the `FCurve*` and `*r_driven = false`.
+ * - Animated with driver: returns `NULL` and `*r_driven = true`.
+ * - Not animated: returns `NULL` and `*r_driven = false`.
*/
struct FCurve *id_data_find_fcurve(
ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, bool *r_driven);
@@ -279,6 +291,25 @@ struct FCurve *id_data_find_fcurve(
int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, const char *dataName);
/**
+ * Find an F-Curve from its rna path and index.
+ *
+ * If there is an action assigned to the `animdata`, it will be searched for a matching F-curve
+ * first. Drivers are searched only if no valid action F-curve could be found.
+ *
+ * \note Typically, indices in RNA arrays are stored separately in F-curves, so the rna_path
+ * should not include them (e.g. `rna_path='location[0]'` will not match any F-Curve on an Object,
+ * but `rna_path='location', rna_index=0` will if it exists).
+ *
+ * \note Return pointer parameters (`r_action`, `r_driven` and `r_special`) are all optional and
+ * may be NULL.
+ */
+struct FCurve *BKE_animadata_fcurve_find_by_rna_path(struct AnimData *animdata,
+ const char *rna_path,
+ const int rna_index,
+ struct bAction **r_action,
+ bool *r_driven);
+
+/**
* Find an f-curve based on an rna property.
*/
struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
@@ -291,9 +322,12 @@ struct FCurve *BKE_fcurve_find_by_rna(struct PointerRNA *ptr,
/**
* Same as above, but takes a context data,
* temp hack needed for complex paths like texture ones.
+ *
+ * \param r_special: Optional, ignored when NULL. Set to `true` if the given RNA `ptr` is a NLA
+ * strip, and the returned F-curve comes from this NLA strip.
*/
struct FCurve *BKE_fcurve_find_by_rna_context_ui(struct bContext *C,
- struct PointerRNA *ptr,
+ const struct PointerRNA *ptr,
struct PropertyRNA *prop,
int rnaindex,
struct AnimData **r_animdata,
@@ -429,23 +463,39 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
struct BezTriple *next,
float *r_pdelta);
+/**
+ * Delete a keyframe from an F-curve at a specific index.
+ */
+void BKE_fcurve_delete_key(struct FCurve *fcu, int index);
+
+/**
+ * Delete selected keyframes from an F-curve.
+ */
+bool BKE_fcurve_delete_keys_selected(struct FCurve *fcu);
+
+/**
+ * Delete all keyframes from an F-curve.
+ */
+void BKE_fcurve_delete_keys_all(struct FCurve *fcu);
+
/* -------- 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().
+ * flag. To use a different flag, use #BKE_fcurve_handles_recalc_ex().
*
* If the BezTriples have been rearranged, sort them first before using this.
*/
-void calchandles_fcurve(struct FCurve *fcu);
+void BKE_fcurve_handles_recalc(struct FCurve *fcu);
/**
- * Variant of #calchandles_fcurve() that allows calculating based on a different select flag.
+ * Variant of #BKE_fcurve_handles_recalc() 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 BKE_fcurve_handles_recalc_ex(struct FCurve *fcu, eBezTriple_Flag handle_sel_flag);
/**
* Update handles, making sure the handle-types are valid (e.g. correctly deduced from an "Auto"
* type), and recalculating their position vectors.
diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh
index 9c86ab262ef..7c504826044 100644
--- a/source/blender/blenkernel/BKE_geometry_fields.hh
+++ b/source/blender/blenkernel/BKE_geometry_fields.hh
@@ -17,10 +17,10 @@ namespace blender::bke {
class GeometryComponentFieldContext : public fn::FieldContext {
private:
const GeometryComponent &component_;
- const AttributeDomain domain_;
+ const eAttrDomain domain_;
public:
- GeometryComponentFieldContext(const GeometryComponent &component, const AttributeDomain domain)
+ GeometryComponentFieldContext(const GeometryComponent &component, const eAttrDomain domain)
: component_(component), domain_(domain)
{
}
@@ -30,7 +30,7 @@ class GeometryComponentFieldContext : public fn::FieldContext {
return component_;
}
- AttributeDomain domain() const
+ eAttrDomain domain() const
{
return domain_;
}
@@ -45,7 +45,7 @@ class GeometryFieldInput : public fn::FieldInput {
ResourceScope &scope) const override;
virtual GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const = 0;
};
@@ -73,7 +73,7 @@ class AttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -90,7 +90,7 @@ class IDAttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -99,12 +99,12 @@ class IDAttributeFieldInput : public GeometryFieldInput {
bool is_equal_to(const fn::FieldNode &other) const override;
};
-VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain);
+VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain);
VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
const Mesh &mesh,
const IndexMask mask,
- const AttributeDomain domain);
+ eAttrDomain domain);
class NormalFieldInput : public GeometryFieldInput {
public:
@@ -114,7 +114,7 @@ class NormalFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -153,7 +153,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const override;
std::string socket_inspection_name() const override;
@@ -166,7 +166,7 @@ class CurveLengthFieldInput final : public GeometryFieldInput {
public:
CurveLengthFieldInput();
GVArray get_varray_for_context(const GeometryComponent &component,
- AttributeDomain domain,
+ eAttrDomain domain,
IndexMask mask) const final;
uint64_t hash() const override;
bool is_equal_to(const fn::FieldNode &other) const override;
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 849c430fd7b..4108e2f7e2e 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -8,6 +8,7 @@
#include <atomic>
#include <iostream>
+#include <mutex>
#include "BLI_float4x4.hh"
#include "BLI_function_ref.hh"
@@ -19,7 +20,7 @@
#include "BLI_vector_set.hh"
#include "BKE_anonymous_attribute.hh"
-#include "BKE_attribute_access.hh"
+#include "BKE_attribute.hh"
#include "BKE_geometry_set.h"
struct Curves;
@@ -63,6 +64,15 @@ class GeometryComponent {
virtual ~GeometryComponent() = default;
static GeometryComponent *create(GeometryComponentType component_type);
+ int attribute_domain_size(eAttrDomain domain) const;
+
+ /**
+ * Get access to the attributes in this geometry component. May return none if the geometry does
+ * not support the attribute system.
+ */
+ virtual std::optional<blender::bke::AttributeAccessor> attributes() const;
+ virtual std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write();
+
/* The returned component should be of the same type as the type this is called on. */
virtual GeometryComponent *copy() const = 0;
@@ -78,203 +88,7 @@ class GeometryComponent {
GeometryComponentType type() const;
- /**
- * 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.
- */
- std::optional<AttributeMetaData> attribute_get_meta_data(
- const blender::bke::AttributeIDRef &attribute_id) 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_num(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 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 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
- * interpolate from one domain to another.
- * \return null if the interpolation is not implemented.
- */
- blender::GVArray attribute_try_adapt_domain(const blender::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. */
- bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id);
-
- /**
- * Remove any anonymous attributes on the geometry (they generally shouldn't exist on original
- * geometry).
- */
- void attributes_remove_anonymous();
-
- /** Returns true when the attribute has been created. */
- bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id,
- 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.
- */
- 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 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::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type) 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::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain) const;
-
- /**
- * 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 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::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::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const T &default_value) const
- {
- const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_get_for_read(attribute_id, domain, type, &default_value)
- .template typed<T>();
- }
-
- /**
- * Returns an "output attribute", which is essentially a mutable virtual array with some commonly
- * used convince features. The returned output attribute might be empty if requested attribute
- * cannot exist on the geometry.
- *
- * The included convenience features are:
- * - Implicit type conversion when writing to builtin attributes.
- * - If the attribute name exists already, but has a different type/domain, a temporary attribute
- * is created that will overwrite the existing attribute in the end.
- */
- blender::bke::OutputAttribute attribute_try_get_for_output(
- const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value = nullptr);
- /* 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,
- const AttributeDomain domain,
- const T default_value)
- {
- const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value);
- }
-
- /**
- * 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)
- {
- const blender::CPPType &cpp_type = blender::CPPType::get<T>();
- const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_try_get_for_output_only(attribute_id, domain, data_type);
- }
-
- private:
- virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
-
- virtual blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const;
};
template<typename T>
@@ -381,7 +195,7 @@ struct GeometrySet {
using AttributeForeachCallback =
blender::FunctionRef<void(const blender::bke::AttributeIDRef &attribute_id,
- const AttributeMetaData &meta_data,
+ const blender::bke::AttributeMetaData &meta_data,
const GeometryComponent &component)>;
void attribute_foreach(blender::Span<GeometryComponentType> component_types,
@@ -392,7 +206,7 @@ struct GeometrySet {
blender::Span<GeometryComponentType> component_types,
GeometryComponentType dst_component_type,
bool include_instances,
- blender::Map<blender::bke::AttributeIDRef, AttributeKind> &r_attributes) const;
+ blender::Map<blender::bke::AttributeIDRef, blender::bke::AttributeKind> &r_attributes) const;
blender::Vector<GeometryComponentType> gather_component_types(bool include_instances,
bool ignore_empty) const;
@@ -412,6 +226,11 @@ struct GeometrySet {
static GeometrySet create_with_mesh(
Mesh *mesh, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
/**
+ * Create a new geometry set that only contains the given volume.
+ */
+ static GeometrySet create_with_volume(
+ Volume *volume, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
+ /**
* Create a new geometry set that only contains the given point cloud.
*/
static GeometrySet create_with_pointcloud(
@@ -521,11 +340,11 @@ struct GeometrySet {
};
/**
- * A geometry component that can store a mesh, storing the #Mesh data structure.
+ * A geometry component that can store a mesh, using the #Mesh data-block.
*
- * 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.
+ * Attributes are stored, 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:
@@ -560,8 +379,6 @@ class MeshComponent : public GeometryComponent {
*/
Mesh *get_for_write();
- int attribute_domain_num(AttributeDomain domain) const final;
-
bool is_empty() const final;
bool owns_direct_data() const override;
@@ -569,12 +386,8 @@ class MeshComponent : public GeometryComponent {
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_MESH;
- private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
-
- blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
};
/**
@@ -623,17 +436,17 @@ class PointCloudComponent : public GeometryComponent {
*/
PointCloud *get_for_write();
- int attribute_domain_num(AttributeDomain domain) const final;
-
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
+
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
/**
@@ -664,26 +477,21 @@ class CurveComponentLegacy : public GeometryComponent {
const CurveEval *get_for_read() const;
CurveEval *get_for_write();
- int attribute_domain_num(AttributeDomain domain) const final;
-
bool is_empty() const final;
bool owns_direct_data() const override;
void ensure_owns_direct_data() override;
- static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
- private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
-
- blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
};
/**
- * A geometry component that stores a group of curves, corresponding the #Curves and
- * #CurvesGeometry types.
+ * A geometry component that stores a group of curves, corresponding the #Curves data-block type
+ * and the #CurvesGeometry type. Attributes are are stored on the control point domain and the
+ * curve domain.
*/
class CurveComponent : public GeometryComponent {
private:
@@ -715,8 +523,6 @@ class CurveComponent : public GeometryComponent {
const Curves *get_for_read() const;
Curves *get_for_write();
- int attribute_domain_num(AttributeDomain domain) const final;
-
bool is_empty() const final;
bool owns_direct_data() const override;
@@ -728,14 +534,10 @@ class CurveComponent : public GeometryComponent {
*/
const Curve *get_curve_for_render() const;
- static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
- private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
-
- blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
};
/**
@@ -960,10 +762,11 @@ class InstancesComponent : public GeometryComponent {
blender::Span<int> almost_unique_ids() const;
- blender::bke::CustomDataAttributes &attributes();
- const blender::bke::CustomDataAttributes &attributes() const;
+ blender::bke::CustomDataAttributes &instance_attributes();
+ const blender::bke::CustomDataAttributes &instance_attributes() const;
- int attribute_domain_num(AttributeDomain domain) const final;
+ std::optional<blender::bke::AttributeAccessor> attributes() const final;
+ std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
void foreach_referenced_geometry(
blender::FunctionRef<void(const GeometrySet &geometry_set)> callback) const;
@@ -976,7 +779,6 @@ class InstancesComponent : public GeometryComponent {
static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_INSTANCES;
private:
- const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
};
/**
diff --git a/source/blender/blenkernel/BKE_geometry_set_instances.hh b/source/blender/blenkernel/BKE_geometry_set_instances.hh
index dd4cfd69cb1..6d4b9a2128c 100644
--- a/source/blender/blenkernel/BKE_geometry_set_instances.hh
+++ b/source/blender/blenkernel/BKE_geometry_set_instances.hh
@@ -43,15 +43,4 @@ struct GeometryInstanceGroup {
void geometry_set_gather_instances(const GeometrySet &geometry_set,
Vector<GeometryInstanceGroup> &r_instance_groups);
-/**
- * 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
- * attribute with the given name on all of the input components.
- */
-void geometry_set_gather_instances_attribute_info(
- Span<GeometryInstanceGroup> set_groups,
- Span<GeometryComponentType> component_types,
- const Set<std::string> &ignored_attributes,
- Map<AttributeIDRef, AttributeKind> &r_attributes);
-
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 60564d1282e..dc7a5ab003a 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -76,13 +76,13 @@ struct bGPdata;
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 */
+/** Free stroke, doesn't unlink from any #ListBase. */
void BKE_gpencil_free_stroke(struct bGPDstroke *gps);
-/* Free strokes belonging to a gp-frame */
+/** Free strokes belonging to a gp-frame. */
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf);
-/* Free all of a gp-layer's frames */
+/** 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) */
+/** 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);
@@ -108,9 +108,9 @@ void BKE_gpencil_batch_cache_free(struct bGPdata *gpd);
*/
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. */
+/** 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. */
+/** Reset unique stroke ID for selection. */
void BKE_gpencil_stroke_select_index_reset(struct bGPDstroke *gps);
/**
diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h
index 96c405e46ec..6472c804e05 100644
--- a/source/blender/blenkernel/BKE_gpencil_modifier.h
+++ b/source/blender/blenkernel/BKE_gpencil_modifier.h
@@ -383,6 +383,8 @@ typedef struct GpencilLineartLimitInfo {
char min_level;
char max_level;
short edge_types;
+ char shadow_selection;
+ char silhouette_selection;
} GpencilLineartLimitInfo;
GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index b6607a92c14..4e622a5708f 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -97,7 +97,7 @@ int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, const struct ImageForm
*/
int BKE_imbuf_write_as(struct ImBuf *ibuf,
const char *name,
- struct ImageFormatData *imf,
+ const struct ImageFormatData *imf,
bool save_copy);
/**
@@ -195,6 +195,14 @@ struct Image *BKE_image_add_generated(struct Main *bmain,
struct Image *BKE_image_add_from_imbuf(struct Main *bmain, struct ImBuf *ibuf, const char *name);
/**
+ * For a non-viewer single-buffer image (single frame file, or generated image) replace its image
+ * buffer with the given one.
+ * If an unsupported image type (multi-layer, image sequence, ...) the function will assert in the
+ * debug mode and will have an undefined behavior in the release mode.
+ */
+void BKE_image_replace_imbuf(struct Image *image, struct ImBuf *ibuf);
+
+/**
* For reload, refresh, pack.
*/
void BKE_imageuser_default(struct ImageUser *iuser);
@@ -371,6 +379,11 @@ typedef enum {
} eUDIM_TILE_FORMAT;
/**
+ * Checks if the filename portion of the path contains a UDIM token.
+ */
+bool BKE_image_is_filename_tokenized(char *filepath);
+
+/**
* Ensures that `filename` contains a UDIM token if we find a supported format pattern.
* \note This must only be the name component (without slashes).
*/
diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h
index b5db15bb174..e17136174eb 100644
--- a/source/blender/blenkernel/BKE_image_save.h
+++ b/source/blender/blenkernel/BKE_image_save.h
@@ -46,15 +46,16 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
struct Scene *scene,
struct Image *ima,
struct ImageUser *iuser,
- const bool guess_path);
-void BKE_image_save_options_update(struct ImageSaveOptions *opts, struct Image *ima);
+ const bool guess_path,
+ const bool save_as_render);
+void BKE_image_save_options_update(struct ImageSaveOptions *opts, const struct Image *ima);
void BKE_image_save_options_free(struct ImageSaveOptions *opts);
bool BKE_image_save(struct ReportList *reports,
struct Main *bmain,
struct Image *ima,
struct ImageUser *iuser,
- struct ImageSaveOptions *opts);
+ const struct ImageSaveOptions *opts);
/* Render saving. */
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 676ac6fe37b..37b30d63722 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -46,8 +46,11 @@ void key_curve_normal_weights(float t, float data[4], int type);
/**
* Returns key coordinates (+ tilt) when key applied, NULL otherwise.
+ *
+ * \param obdata if given, also update that geometry with the result of the shape keys evaluation.
*/
-float *BKE_key_evaluate_object_ex(struct Object *ob, int *r_totelem, float *arr, size_t arr_size);
+float *BKE_key_evaluate_object_ex(
+ struct Object *ob, int *r_totelem, float *arr, size_t arr_size, struct ID *obdata);
float *BKE_key_evaluate_object(struct Object *ob, int *r_totelem);
/**
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index 504ab47c1c5..59c842d614e 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -478,10 +478,12 @@ void BKE_lib_id_expand_local(struct Main *bmain, struct ID *id, int flags);
*
* \return true if a new name had to be created.
*/
-bool BKE_id_new_name_validate(struct ListBase *lb,
+bool BKE_id_new_name_validate(struct Main *bmain,
+ struct ListBase *lb,
struct ID *id,
const char *name,
- bool do_linked_data) ATTR_NONNULL(1, 2);
+ bool do_linked_data) ATTR_NONNULL(1, 2, 3);
+
/**
* Pull an ID out of a library (make it local). Only call this for IDs that
* don't have other library users.
@@ -526,7 +528,7 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain);
/**
* Only for repairing files via versioning, avoid for general use.
*/
-void BKE_main_id_repair_duplicate_names_listbase(struct ListBase *lb);
+void BKE_main_id_repair_duplicate_names_listbase(struct Main *bmain, 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. */
@@ -603,7 +605,7 @@ bool BKE_id_can_be_asset(const struct ID *id);
* we should either cache that status info also in virtual override IDs, or address the
* long-standing TODO of getting an efficient 'owner_id' access for all embedded ID types.
*/
-bool BKE_id_is_editable(struct Main *bmain, struct ID *id);
+bool BKE_id_is_editable(const struct Main *bmain, const struct ID *id);
/**
* Returns ordered list of data-blocks for display in the UI.
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h
index 38de4bebdbd..b2162e651fd 100644
--- a/source/blender/blenkernel/BKE_lib_override.h
+++ b/source/blender/blenkernel/BKE_lib_override.h
@@ -62,12 +62,25 @@ void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_
/**
* 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);
+bool BKE_lib_override_library_is_user_edited(const struct ID *id);
/**
* Check if given ID is a system override.
*/
-bool BKE_lib_override_library_is_system_defined(struct Main *bmain, struct ID *id);
+bool BKE_lib_override_library_is_system_defined(const struct Main *bmain, const struct ID *id);
+
+/**
+ * Check if given Override Property for given ID is animated (through a F-Curve in an Action, or
+ * from a driver).
+ *
+ * \param override_rna_prop: if not NULL, the RNA property matching the given path in the
+ * `override_prop`.
+ * \param rnaprop_index: Array in the RNA property, 0 if unknown or irrelevant.
+ */
+bool BKE_lib_override_library_property_is_animated(const ID *id,
+ const IDOverrideLibraryProperty *override_prop,
+ const struct PropertyRNA *override_rna_prop,
+ const int rnaprop_index);
/**
* Check if given ID is a leaf in its liboverride hierarchy (i.e. if it does not use any other
@@ -281,11 +294,14 @@ void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override
*
* \param idpoin: Pointer to the override ID.
* \param library_prop: The library override property to find the matching RNA property for.
+ * \param r_index: The RNA array flat index (i.e. flattened index in case of multi-dimensional
+ * array properties). See #RNA_path_resolve_full family of functions for details.
*/
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);
+ struct PropertyRNA **r_override_prop,
+ int *r_index);
/**
* Find override property operation from given sub-item(s), if it exists.
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index f62225179bd..37b626fb4da 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -95,11 +95,11 @@ typedef enum eIDRemapType {
*/
void BKE_libblock_remap_multiple_locked(struct Main *bmain,
struct IDRemapper *mappings,
- const short remap_flags);
+ short remap_flags);
void BKE_libblock_remap_multiple(struct Main *bmain,
struct IDRemapper *mappings,
- const short remap_flags);
+ short remap_flags);
/**
* Replace all references in given Main to \a old_id by \a new_id
@@ -142,9 +142,9 @@ void BKE_libblock_relink_ex(struct Main *bmain,
*/
void BKE_libblock_relink_multiple(struct Main *bmain,
struct LinkNode *ids,
- const eIDRemapType remap_type,
+ eIDRemapType remap_type,
struct IDRemapper *id_remapper,
- const short remap_flags);
+ short remap_flags);
/**
* Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 59b22f7759b..4d26ed11f1b 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -36,6 +36,7 @@ struct IDNameLib_Map;
struct ImBuf;
struct Library;
struct MainLock;
+struct UniqueName_Map;
/* Blender thumbnail, as written on file (width, height, and data as char RGBA). */
/* We pack pixel data after that struct. */
@@ -77,8 +78,16 @@ typedef struct MainIDRelationsEntry {
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 in the `to` direction (i.e. we processed the IDs
+ * used by this item). */
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO = 1 << 1,
+ /* Generic tag marking the entry as processed in the `from` direction (i.e. we processed the IDs
+ * using by this item). */
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM = 1 << 2,
/* Generic tag marking the entry as processed. */
- MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = 1 << 1,
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED = MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO |
+ MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM,
} eMainIDRelationsEntryTags;
typedef struct MainIDRelations {
@@ -185,6 +194,9 @@ typedef struct Main {
/* IDMap of IDs. Currently used when reading (expanding) libraries. */
struct IDNameLib_Map *id_map;
+ /* Used for efficient calculations of unique names. */
+ struct UniqueName_Map *name_map;
+
struct MainLock *lock;
} Main;
diff --git a/source/blender/blenkernel/BKE_main_namemap.h b/source/blender/blenkernel/BKE_main_namemap.h
new file mode 100644
index 00000000000..d201e45a2c9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_main_namemap.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
+/** \file
+ * \ingroup bke
+ *
+ * API to ensure name uniqueness.
+ *
+ * Main database contains the UniqueName_Map which is a cache that tracks names, base
+ * names and their suffixes currently in use. So that whenever a new name has to be
+ * assigned or validated, it can quickly ensure uniqueness and adjust the name in case
+ * of collisions.
+ *
+ * \section Function Names
+ *
+ * - `BKE_main_namemap_` Should be used for functions in this file.
+ */
+
+#include "BLI_compiler_attrs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ID;
+struct Main;
+struct UniqueName_Map;
+
+struct UniqueName_Map *BKE_main_namemap_create(void) ATTR_WARN_UNUSED_RESULT;
+void BKE_main_namemap_destroy(struct UniqueName_Map **r_name_map) ATTR_NONNULL();
+
+/**
+ * Ensures the given name is unique within the given ID type.
+ *
+ * In case of name collisions, the name will be adjusted to be unique.
+ *
+ * \return true if the name had to be adjusted for uniqueness.
+ */
+bool BKE_main_namemap_get_name(struct Main *bmain, struct ID *id, char *name) ATTR_NONNULL();
+
+/**
+ * Remove a given name from usage.
+ *
+ * Call this whenever deleting or renaming an object.
+ */
+void BKE_main_namemap_remove_name(struct Main *bmain, struct ID *id, const char *name)
+ ATTR_NONNULL();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 05e502f06c2..ab14fa92514 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -87,6 +87,17 @@ 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);
+
+/**
+ * Similar to #BKE_object_material_assign with #BKE_MAT_ASSIGN_OBDATA type,
+ * but does not scan whole Main for other usages of the same obdata. Only
+ * use in cases where you know that the object's obdata is only used by this one
+ * object.
+ */
+void BKE_object_material_assign_single_obdata(struct Main *bmain,
+ struct Object *ob,
+ struct Material *ma,
+ short act);
/**
* \warning this calls many more update calls per object then are needed, could be optimized.
*/
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index f40d0bb3004..a23d010b51f 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -24,14 +24,25 @@ struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name);
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);
+
+/**
+ * Return `true` if `ob1` and `ob2` are part of the same metaBall group.
+ *
+ * \note Currently checks whether their two base names (without numerical suffix) is the same.
+ */
+bool BKE_mball_is_same_group(const struct Object *ob1, const struct Object *ob2);
+/**
+ * Return `true` if `ob1` and `ob2` are part of the same metaBall group, and `ob1` is its
+ * basis.
+ */
+bool BKE_mball_is_basis_for(const struct Object *ob1, const 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);
+bool BKE_mball_is_basis(const struct Object *ob);
/**
* This function finds the basis meta-ball.
*
@@ -58,13 +69,15 @@ 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.
+ * Copy some properties from a meta-ball obdata to all other meta-ball obdata belonging to the same
+ * family (i.e. object sharing the same name basis).
*
* 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);
+ * meta-ball, because this meta-ball influences polygonization of meta-balls.
+ */
+void BKE_mball_properties_copy(struct Main *bmain, struct MetaBall *active_metaball);
bool BKE_mball_minmax_ex(
const struct MetaBall *mb, float min[3], float max[3], const float obmat[4][4], short flag);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 23ec69babc8..6c61068b1c2 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -52,6 +52,18 @@ extern "C" {
# define BKE_MESH_OMP_LIMIT 10000
#endif
+/* mesh_runtime.cc */
+
+/**
+ * Call after changing vertex positions to tag lazily calculated caches for recomputation.
+ */
+void BKE_mesh_tag_coords_changed(struct Mesh *mesh);
+
+/**
+ * Call after moving every mesh vertex by the same translation.
+ */
+void BKE_mesh_tag_coords_changed_uniformly(struct Mesh *mesh);
+
/* *** mesh.c *** */
struct BMesh *BKE_mesh_to_bmesh_ex(const struct Mesh *me,
@@ -73,10 +85,18 @@ struct Mesh *BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm,
* Add original index (#CD_ORIGINDEX) layers if they don't already exist. This is meant to be used
* when creating an evaluated mesh from an original edit mode mesh, to allow mapping from the
* evaluated vertices to the originals.
+ *
+ * The mesh is expected to of a `ME_WRAPPER_TYPE_MDATA` wrapper type. This is asserted.
*/
void BKE_mesh_ensure_default_orig_index_customdata(struct Mesh *mesh);
/**
+ * Same as #BKE_mesh_ensure_default_orig_index_customdata but does not perform any checks: they
+ * must be done by the caller.
+ */
+void BKE_mesh_ensure_default_orig_index_customdata_no_check(struct Mesh *mesh);
+
+/**
* Find the index of the loop in 'poly' which references vertex,
* returns -1 if not found
*/
@@ -171,14 +191,6 @@ void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totver
*/
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,
- int nr);
struct Mesh *BKE_mesh_from_object(struct Object *ob);
void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me);
void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me);
@@ -292,7 +304,6 @@ 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], bool do_keys);
-void BKE_mesh_tessface_ensure(struct Mesh *mesh);
void BKE_mesh_tessface_clear(struct Mesh *mesh);
void BKE_mesh_do_versions_cd_flag_init(struct Mesh *mesh);
@@ -322,26 +333,6 @@ void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[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,
- struct MVert *mvert,
- int totface,
- int totloop,
- int totpoly);
-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,
@@ -709,7 +700,8 @@ void BKE_mesh_calc_normals_split(struct Mesh *mesh);
* to split geometry along sharp edges.
*/
void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh,
- struct MLoopNorSpaceArray *r_lnors_spacearr);
+ struct MLoopNorSpaceArray *r_lnors_spacearr,
+ float (*r_corner_normals)[3]);
/**
* Higher level functions hiding most of the code needed around call to
@@ -788,37 +780,6 @@ void BKE_mesh_calc_volume(const struct MVert *mverts,
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,
- struct CustomData *ldata,
- struct CustomData *pdata,
- int totedge_i,
- int totface_i,
- int totloop_i,
- int totpoly_i,
- struct MEdge *medge,
- struct MFace *mface,
- int *r_totloop,
- int *r_totpoly,
- struct MLoop **r_mloop,
- struct MPoly **r_mpoly);
-
/**
* Flip a single MLoop's #MDisps structure,
* low level function to be called from face-flipping code which re-arranged the mdisps themselves.
@@ -885,9 +846,6 @@ enum {
* 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,
@@ -1036,7 +994,7 @@ void BKE_mesh_strip_loose_edges(struct Mesh *me);
/**
* If the mesh is from a very old blender version,
- * convert mface->edcode to edge drawflags
+ * convert #MFace.edcode to edge #ME_EDGEDRAW.
*/
void BKE_mesh_calc_edges_legacy(struct Mesh *me, bool use_old);
void BKE_mesh_calc_edges_loose(struct Mesh *mesh);
@@ -1052,8 +1010,8 @@ void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool selec
void BKE_mesh_calc_edges_tessface(struct Mesh *mesh);
/* In DerivedMesh.cc */
-void BKE_mesh_wrapper_deferred_finalize(struct Mesh *me_eval,
- const struct CustomData_MeshMasks *cd_mask_finalize);
+void BKE_mesh_wrapper_deferred_finalize_mdata(struct Mesh *me_eval,
+ const struct CustomData_MeshMasks *cd_mask_finalize);
/* **** Depsgraph evaluation **** */
@@ -1074,18 +1032,6 @@ char *BKE_mesh_debug_info(const struct Mesh *me)
void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1);
#endif
-/* Inlines */
-
-/* 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)
-{
- const int j = index_mf_to_mpoly[i];
- return (j != -1) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : -1;
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
index abaf2ab0178..441783d46a1 100644
--- a/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
+++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.hh
@@ -23,6 +23,8 @@ namespace blender::meshintersect {
* \param material_remaps: An array 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.
+ * \param r_intersecting_edges: Array to store indices of edges on the resulting mesh in. These
+ * 'new' edges are the result of the intersections.
*/
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<const float4x4 *> transforms,
@@ -30,6 +32,7 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<Array<short>> material_remaps,
bool use_self,
bool hole_tolerant,
- int boolean_mode);
+ int boolean_mode,
+ Vector<int> *r_intersecting_edges);
} // namespace blender::meshintersect
diff --git a/source/blender/blenkernel/BKE_mesh_legacy_convert.h b/source/blender/blenkernel/BKE_mesh_legacy_convert.h
new file mode 100644
index 00000000000..909fd0e0dea
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_legacy_convert.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_utildefines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct CustomData;
+struct Mesh;
+struct MFace;
+
+/**
+ * Recreate #MFace Tessellation.
+ *
+ * \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.
+ */
+
+void BKE_mesh_tessface_calc(struct Mesh *mesh);
+
+void BKE_mesh_tessface_ensure(struct Mesh *mesh);
+
+void BKE_mesh_add_mface_layers(struct CustomData *fdata, struct CustomData *ldata, int total);
+
+/**
+ * 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,
+ int nr);
+
+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);
+
+/* Inlines */
+
+/* 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)
+{
+ const int j = index_mf_to_mpoly[i];
+ return (j != -1) ? (index_mp_to_orig ? index_mp_to_orig[j] : j) : -1;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index 163acf062e0..c58bcbea242 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -69,8 +69,6 @@ typedef struct UvElementMap {
int *islandIndices;
} UvElementMap;
-#define INVALID_ISLAND ((unsigned int)-1)
-
/* Connectivity data */
typedef struct MeshElemMap {
int *indices;
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index e2b16a7681d..ee0179c7a77 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -42,7 +42,7 @@ void BKE_mesh_remap_free(MeshPairRemap *map);
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.
+ * Add other 'from/to' mapping sources, like e.g. using a UVMap, etc.
* https://blenderartists.org/t/619105
*
* We could also use similar topology mappings inside a same mesh
diff --git a/source/blender/blenkernel/BKE_mesh_runtime.h b/source/blender/blenkernel/BKE_mesh_runtime.h
index 0e78f9d7e15..dfefe125a51 100644
--- a/source/blender/blenkernel/BKE_mesh_runtime.h
+++ b/source/blender/blenkernel/BKE_mesh_runtime.h
@@ -8,7 +8,7 @@
* This file contains access functions for the Mesh.runtime struct.
*/
-//#include "BKE_customdata.h" /* for CustomDataMask */
+//#include "BKE_customdata.h" /* for eCustomDataMask */
#ifdef __cplusplus
extern "C" {
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
index a942f3bb7ed..356709d8942 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.hh
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -6,17 +6,21 @@
* \ingroup bke
*/
+#include "BLI_function_ref.hh"
#include "BLI_generic_virtual_array.hh"
#include "BLI_math_vec_types.hh"
+#include "DNA_meshdata_types.h"
+
#include "BKE_attribute.h"
+#include "BKE_attribute.hh"
struct Mesh;
+struct BVHTreeFromMesh;
-namespace blender::bke {
-struct ReadAttributeLookup;
-class OutputAttribute;
-} // namespace blender::bke
+namespace blender {
+class RandomNumberGenerator;
+}
namespace blender::bke::mesh_surface_sample {
@@ -69,12 +73,12 @@ class MeshAttributeInterpolator {
const Span<int> looptri_indices);
void sample_data(const GVArray &src,
- AttributeDomain domain,
+ eAttrDomain domain,
eAttributeMapMode mode,
const GMutableSpan dst);
- void sample_attribute(const ReadAttributeLookup &src_attribute,
- OutputAttribute &dst_attribute,
+ void sample_attribute(const GAttributeReader &src_attribute,
+ GSpanAttributeWriter &dst_attribute,
eAttributeMapMode mode);
protected:
@@ -82,4 +86,55 @@ class MeshAttributeInterpolator {
Span<float3> ensure_nearest_weights();
};
+/**
+ * Find randomly distributed points on the surface of a mesh within a 3D sphere. This does not
+ * sample an exact number of points because it comes with extra overhead to avoid bias that is only
+ * required in some cases. If an exact number of points is required, that has to be implemented at
+ * a higher level.
+ *
+ * \param approximate_density: Roughly the number of points per unit of area.
+ * \return The number of added points.
+ */
+int sample_surface_points_spherical(RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ Span<int> looptri_indices_to_sample,
+ const float3 &sample_pos,
+ float sample_radius,
+ float approximate_density,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions);
+
+/**
+ * Find randomly distributed points on the surface of a mesh within a circle that is projected on
+ * the mesh. This does not result in an exact number of points because that would come with extra
+ * overhead and is not always possible. If an exact number of points is required, that has to be
+ * implemented at a higher level.
+ *
+ * \param region_position_to_ray: Function that converts a 2D position into a 3D ray that is used
+ * to find positions on the mesh.
+ * \param mesh_bvhtree: BVH tree of the triangles in the mesh. Passed in so that it does not have
+ * to be retrieved again.
+ * \param tries_num: Number of 2d positions that are sampled. The maximum
+ * number of new samples.
+ * \return The number of added points.
+ */
+int sample_surface_points_projected(
+ RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ BVHTreeFromMesh &mesh_bvhtree,
+ const float2 &sample_pos_re,
+ float sample_radius_re,
+ FunctionRef<void(const float2 &pos_re, float3 &r_start, float3 &r_end)> region_position_to_ray,
+ bool front_face_only,
+ int tries_num,
+ int max_points,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions);
+
+float3 compute_bary_coord_in_triangle(const Mesh &mesh,
+ const MLoopTri &looptri,
+ const float3 &position);
+
} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/BKE_mesh_wrapper.h b/source/blender/blenkernel/BKE_mesh_wrapper.h
index f664c703def..b4742583b03 100644
--- a/source/blender/blenkernel/BKE_mesh_wrapper.h
+++ b/source/blender/blenkernel/BKE_mesh_wrapper.h
@@ -38,7 +38,7 @@ 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);
+struct Mesh *BKE_mesh_wrapper_ensure_subdivision(struct Mesh *me);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 866b0353d07..cda1fd01e44 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -446,10 +446,22 @@ bool BKE_modifier_is_enabled(const struct Scene *scene,
*/
bool BKE_modifier_is_nonlocal_in_liboverride(const struct Object *ob,
const struct ModifierData *md);
+
+/* Set modifier execution error.
+ * The message will be shown in the interface and will be logged as an error to the console. */
void BKE_modifier_set_error(const struct Object *ob,
struct ModifierData *md,
const char *format,
...) ATTR_PRINTF_FORMAT(3, 4);
+
+/* Set modifier execution warning, which does not prevent the modifier from being applied but which
+ * might need an attention. The message will only be shown in the interface, but will not appear in
+ * the logs. */
+void BKE_modifier_set_warning(const struct Object *ob,
+ struct ModifierData *md,
+ const char *format,
+ ...) ATTR_PRINTF_FORMAT(3, 4);
+
bool BKE_modifier_is_preview(struct ModifierData *md);
void BKE_modifiers_foreach_ID_link(struct Object *ob, IDWalkFunc walk, void *userData);
@@ -586,12 +598,8 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
* 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,
- bool get_cage_mesh);
+struct Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval);
void BKE_modifier_check_uuids_unique_and_report(const struct Object *object);
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index 215adc3e67b..2613f4286f0 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -7,6 +7,9 @@
* \ingroup bke
*/
+/* temp constant defined for these funcs only... */
+#define NLASTRIP_MIN_LEN_THRESH 0.1f
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -219,6 +222,33 @@ bool BKE_nlatrack_is_nonlocal_in_liboverride(const struct ID *id, const struct N
/* ............ */
/**
+ * Compute the left-hand-side 'frame limit' of that strip, in its NLA track.
+ *
+ * \details This is either :
+ * - the end frame of the previous strip, if the strip's track contains another strip on it left
+ * - the macro MINFRAMEF, if no strips are to the left of this strip in its track
+ *
+ * \param strip: The strip to compute the left-hand-side 'frame limit' of.
+ * \return The beginning frame of the previous strip, or MINFRAMEF if no strips are next in that
+ * track.
+ */
+float BKE_nlastrip_compute_frame_from_previous_strip(struct NlaStrip *strip);
+/**
+ * Compute the right-hand-side 'frame limit' of that strip, in its NLA track.
+ *
+ * \details This is either :
+ *
+ * - the begin frame of the next strip, if the strip's track contains another strip on it right
+ * - the macro MAXFRAMEF, if no strips are to the right of this strip in its track
+ *
+ * \param strip: The strip to compute the right-hand-side 'frame limit' of.
+ * \return The beginning frame of the next strip, or MAXFRAMEF if no strips are next in that track.
+ */
+float BKE_nlastrip_compute_frame_to_next_strip(struct NlaStrip *strip);
+
+/* ............ */
+
+/**
* Find the active NLA-strip within the given track.
*/
struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 1ff10d06b00..ea43fba1a85 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -314,6 +314,10 @@ typedef struct bNodeType {
/* Execute a geometry node. */
NodeGeometryExecFunction geometry_node_execute;
+ /**
+ * If true, the geometry nodes evaluator can call the execute function multiple times to improve
+ * performance by specifying required data in one call and using it for calculations in another.
+ */
bool geometry_node_execute_supports_laziness;
/* Declares which sockets the node has. */
@@ -1493,6 +1497,15 @@ struct TexResult;
#define GEO_NODE_STORE_NAMED_ATTRIBUTE 1156
#define GEO_NODE_INPUT_NAMED_ATTRIBUTE 1157
#define GEO_NODE_REMOVE_ATTRIBUTE 1158
+#define GEO_NODE_INPUT_INSTANCE_ROTATION 1159
+#define GEO_NODE_INPUT_INSTANCE_SCALE 1160
+#define GEO_NODE_VOLUME_CUBE 1161
+#define GEO_NODE_POINTS 1162
+#define GEO_NODE_FIELD_ON_DOMAIN 1163
+#define GEO_NODE_MESH_TO_VOLUME 1164
+#define GEO_NODE_UV_UNWRAP 1165
+#define GEO_NODE_UV_PACK_ISLANDS 1166
+#define GEO_NODE_DEFORM_CURVES_ON_SURFACE 1167
/** \} */
diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh
new file mode 100644
index 00000000000..f5fb53f962b
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node_runtime.hh
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <memory>
+
+#include "BLI_sys_types.h"
+#include "BLI_utility_mixins.hh"
+
+namespace blender::nodes {
+struct FieldInferencingInterface;
+class NodeDeclaration;
+} // namespace blender::nodes
+
+namespace blender::bke {
+
+class bNodeTreeRuntime : NonCopyable, NonMovable {
+ public:
+ /**
+ * 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 = 0;
+ /**
+ * 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 = 0;
+
+ /**
+ * Used to cache run-time information of the node tree.
+ * #eNodeTreeRuntimeFlag.
+ */
+ uint8_t runtime_flag = 0;
+
+ /** Information about how inputs and outputs of the node group interact with fields. */
+ std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface;
+};
+
+/**
+ * Run-time data for every socket. This should only contain data that is somewhat persistent (i.e.
+ * data that lives longer than a single depsgraph evaluation + redraw). Data that's only used in
+ * smaller scopes should generally be stored in separate arrays and/or maps.
+ */
+class bNodeSocketRuntime : NonCopyable, NonMovable {
+ public:
+ /**
+ * 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 = nullptr;
+
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag = 0;
+};
+
+/**
+ * Run-time data for every node. This should only contain data that is somewhat persistent (i.e.
+ * data that lives longer than a single depsgraph evaluation + redraw). Data that's only used in
+ * smaller scopes should generally be stored in separate arrays and/or maps.
+ */
+class bNodeRuntime : NonCopyable, NonMovable {
+ public:
+ /**
+ * Describes the desired interface of the node. This is run-time data only.
+ * The actual interface of the node may deviate from the declaration temporarily.
+ * It's possible to sync the actual state of the node to the desired state. Currently, this is
+ * only done when a node is created or loaded.
+ *
+ * In the future, we may want to keep more data only in the declaration, so that it does not have
+ * to be synced to other places that are stored in files. That especially applies to data that
+ * can't be edited by users directly (e.g. min/max values of sockets, tooltips, ...).
+ *
+ * The declaration of a node can be recreated at any time when it is used. Caching it here is
+ * just a bit more efficient when it is used a lot. To make sure that the cache is up-to-date,
+ * call #nodeDeclarationEnsure before using it.
+ *
+ * Currently, the declaration is the same for every node of the same type. Going forward, that is
+ * intended to change though. Especially when nodes become more dynamic with respect to how many
+ * sockets they have.
+ */
+ NodeDeclarationHandle *declaration = nullptr;
+
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag = 0;
+};
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index faf878dfc2a..f0eb16a819d 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -69,9 +69,6 @@ void BKE_object_free_caches(struct Object *object);
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
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 *fx);
/**
* \return True if the object's type supports regular modifiers (not grease pencil modifiers).
@@ -376,6 +373,13 @@ bool BKE_object_minmax_dupli(struct Depsgraph *depsgraph,
float r_min[3],
float r_max[3],
bool use_hidden);
+/**
+ * Calculate visual bounds from an empty objects draw-type.
+ *
+ * \note This is not part of the calculation used by #BKE_object_boundbox_get
+ * as these bounds represent the extents of visual guides (use for viewport culling for e.g.)
+ */
+bool BKE_object_minmax_empty_drawtype(const struct Object *ob, float r_min[3], float r_max[3]);
/**
* Sometimes min-max isn't enough, we need to loop over each point.
@@ -629,8 +633,6 @@ void BKE_object_groups_clear(struct Main *bmain, struct Scene *scene, struct Obj
*/
struct KDTree_3d *BKE_object_as_kdtree(struct Object *ob, int *r_tot);
-bool BKE_object_modifier_use_time(struct Scene *scene, struct Object *ob, struct ModifierData *md);
-
/**
* \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!
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index c39ab22ce3a..162459d2005 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -200,6 +200,11 @@ bool BKE_paint_select_vert_test(struct Object *ob);
* (when we don't care if its face or vert)
*/
bool BKE_paint_select_elem_test(struct Object *ob);
+/**
+ * Checks if face/vertex hiding is always applied in the current mode.
+ * Returns true in vertex/weight paint.
+ */
+bool BKE_paint_always_hide_test(struct Object *ob);
/* Partial visibility. */
@@ -501,8 +506,8 @@ typedef struct SculptSession {
struct MPropCol *vcol;
struct MLoopCol *mcol;
- AttributeDomain vcol_domain;
- CustomDataType vcol_type;
+ eAttrDomain vcol_domain;
+ eCustomDataType vcol_type;
float *vmask;
@@ -552,8 +557,7 @@ typedef struct SculptSession {
float (*deform_cos)[3]; /* Coords of deformed mesh but without stroke displacement. */
float (*deform_imats)[3][3]; /* Crazy-space deformation matrices. */
- /* Used to cache the render of the active texture */
- unsigned int texcache_side, *texcache, texcache_actual;
+ /* Pool for texture evaluations. */
struct ImagePool *tex_pool;
struct StrokeCache *cache;
@@ -613,6 +617,10 @@ 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;
@@ -676,8 +684,8 @@ void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph,
struct Object *ob_orig,
bool need_pmap,
bool need_mask,
- bool need_colors);
-void BKE_sculpt_update_object_before_eval(struct Object *ob_eval);
+ bool is_paint_tool);
+void BKE_sculpt_update_object_before_eval(const struct Scene *scene, struct Object *ob_eval);
void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Object *ob_eval);
/**
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 291b9b6b778..f517ff3a949 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -221,7 +221,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
- void *user_data);
+ void *user_data,
+ bool full_render);
void BKE_pbvh_draw_debug_cb(
PBVH *pbvh,
@@ -549,7 +550,7 @@ PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
bool BKE_pbvh_get_color_layer(const struct Mesh *me,
CustomDataLayer **r_layer,
- AttributeDomain *r_attr);
+ eAttrDomain *r_attr);
/* Swaps colors at each element in indices (of domain pbvh->vcol_domain)
* with values in colors. */
diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h
index c238a24f173..ee90fea6506 100644
--- a/source/blender/blenkernel/BKE_pointcloud.h
+++ b/source/blender/blenkernel/BKE_pointcloud.h
@@ -29,9 +29,7 @@ struct PointCloud *BKE_pointcloud_new_nomain(int totpoint);
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
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,
- struct CustomDataLayer *layer);
+bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, const char *name);
/* Dependency Graph */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index a6402a1e8a1..61fc883fe7f 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -251,6 +251,10 @@ bool BKE_scene_check_rigidbody_active(const struct Scene *scene);
int BKE_scene_num_threads(const struct Scene *scene);
int BKE_render_num_threads(const struct RenderData *r);
+void BKE_render_resolution(const struct RenderData *r,
+ const bool use_crop,
+ int *r_width,
+ int *r_height);
int BKE_render_preview_pixel_size(const struct RenderData *r);
/**********************************/
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 4dda21d99b8..3922bfb6c0d 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -440,6 +440,14 @@ 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 provided \a regionbase.
+ *
+ * \note this is useful for versioning where either the #Area or #SpaceLink regionbase are typical
+ * inputs
+ */
+struct ARegion *BKE_region_find_in_listbase_by_type(const struct ListBase *regionbase,
+ const int region_type);
+/**
* 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.
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index edb301f06bf..9965b6f1351 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -136,7 +136,7 @@ void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle);
void BKE_sound_mute_scene_sound(void *handle, char mute);
-void BKE_sound_move_scene_sound(struct Scene *scene,
+void BKE_sound_move_scene_sound(const struct Scene *scene,
void *handle,
int startframe,
int endframe,
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index 28f326a4ad4..767018ae0bb 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -15,7 +15,7 @@
#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
-#include "BKE_attribute_access.hh"
+#include "BKE_attribute.hh"
#include "BKE_attribute_math.hh"
struct Curve;
@@ -646,6 +646,8 @@ struct CurveEval {
void transform(const blender::float4x4 &matrix);
bool bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const;
+ blender::bke::MutableAttributeAccessor attributes_for_write();
+
/**
* 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
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index cb0f2ac7e32..e4a7f813a8b 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -20,7 +20,7 @@ struct Subdiv;
typedef enum eSubdivEvaluatorType {
SUBDIV_EVALUATOR_TYPE_CPU,
- SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE,
+ SUBDIV_EVALUATOR_TYPE_GPU,
} eSubdivEvaluatorType;
/* Returns true if evaluator is ready for use. */
diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h
index 4ad17610207..271026d4253 100644
--- a/source/blender/blenkernel/BKE_subdiv_modifier.h
+++ b/source/blender/blenkernel/BKE_subdiv_modifier.h
@@ -7,6 +7,8 @@
#pragma once
+#include "BKE_subdiv.h"
+
#include "BLI_sys_types.h"
#ifdef __cplusplus
@@ -24,9 +26,30 @@ struct Subdiv;
struct SubdivSettings;
struct SubsurfModifierData;
-void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
- const struct SubsurfModifierData *smd,
- bool use_render_params);
+/* Runtime subsurf modifier data, cached in modifier on evaluated meshes. */
+typedef struct SubsurfRuntimeData {
+ /* Subdivision settings, exists before descriptor or mesh wrapper is created. */
+ SubdivSettings settings;
+
+ /* Cached subdivision surface descriptor, with topology and settings. */
+ struct Subdiv *subdiv;
+ bool set_by_draw_code;
+
+ /* Cached mesh wrapper data, to be used for GPU subdiv or lazy evaluation on CPU. */
+ bool has_gpu_subdiv;
+ int resolution;
+ bool use_optimal_display;
+ bool calc_loop_normals;
+ bool use_loop_normals;
+
+ /* Cached from the draw code for stats display. */
+ int stats_totvert;
+ int stats_totedge;
+ int stats_totpoly;
+ int stats_totloop;
+} SubsurfRuntimeData;
+
+bool BKE_subsurf_modifier_runtime_init(struct SubsurfModifierData *smd, bool use_render_params);
bool BKE_subsurf_modifier_use_custom_loop_normals(const struct SubsurfModifierData *smd,
const struct Mesh *mesh);
@@ -57,12 +80,7 @@ extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
* 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);
+ struct SubsurfRuntimeData *runtime_data, const struct Mesh *mesh, bool for_draw_code);
/**
* Return the #ModifierMode required for the evaluation of the subsurf modifier,
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 3f6d32e2f70..89f30ce8ef8 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -7,6 +7,8 @@
* \ingroup bke
*/
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -560,6 +562,11 @@ struct ImBuf *BKE_tracking_get_search_imbuf(struct ImBuf *ibuf,
bool anchored,
bool disable_channels);
+/* Create a new image buffer which consists of pixels which the plane marker "sees".
+ * The function will choose best image resolution based on the plane marker size. */
+struct ImBuf *BKE_tracking_get_plane_imbuf(const struct ImBuf *frame_ibuf,
+ const struct MovieTrackingPlaneMarker *plane_marker);
+
/**
* 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
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index 823d32f83ba..f051335fc41 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -19,6 +19,10 @@ struct UnitSettings;
*/
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);
+/**
+ * Representation of a value in units. Negative precision is used to disable stripping of zeroes.
+ * This reduces text jumping when changing values.
+ */
size_t BKE_unit_value_as_string(char *str,
int len_max,
double value,
diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
index 3f92d6fa117..736f7548bb4 100644
--- a/source/blender/blenkernel/BKE_writeffmpeg.h
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -68,7 +68,7 @@ void BKE_ffmpeg_filepath_get(char *string,
const char *suffix);
void BKE_ffmpeg_preset_set(struct RenderData *rd, int preset);
-void BKE_ffmpeg_image_type_verify(struct RenderData *rd, struct ImageFormatData *imf);
+void BKE_ffmpeg_image_type_verify(struct RenderData *rd, const struct ImageFormatData *imf);
bool BKE_ffmpeg_alpha_channel_is_supported(const struct RenderData *rd);
void *BKE_ffmpeg_context_create(void);
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 0b4f81df452..45a9e85874d 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -76,7 +76,7 @@ set(SRC
intern/asset_catalog_path.cc
intern/asset_library.cc
intern/asset_library_service.cc
- intern/attribute.c
+ intern/attribute.cc
intern/attribute_access.cc
intern/attribute_math.cc
intern/autoexec.c
@@ -88,7 +88,7 @@ set(SRC
intern/blendfile_link_append.c
intern/boids.c
intern/bpath.c
- intern/brush.c
+ intern/brush.cc
intern/bvhutils.cc
intern/cachefile.c
intern/callbacks.c
@@ -111,6 +111,7 @@ set(SRC
intern/curve_decimate.c
intern/curve_deform.c
intern/curve_eval.cc
+ intern/curve_legacy_convert.cc
intern/curve_nurbs.cc
intern/curve_poly.cc
intern/curve_to_mesh_convert.cc
@@ -174,7 +175,7 @@ set(SRC
intern/lib_id_delete.c
intern/lib_id_eval.c
intern/lib_id_remapper.cc
- intern/lib_override.c
+ intern/lib_override.cc
intern/lib_override_proxy_conversion.c
intern/lib_query.c
intern/lib_remap.c
@@ -184,6 +185,7 @@ set(SRC
intern/linestyle.c
intern/main.c
intern/main_idmap.c
+ intern/main_namemap.cc
intern/mask.c
intern/mask_evaluate.c
intern/mask_rasterize.c
@@ -198,6 +200,7 @@ set(SRC
intern/mesh_evaluate.cc
intern/mesh_fair.cc
intern/mesh_iterators.c
+ intern/mesh_legacy_convert.cc
intern/mesh_mapping.c
intern/mesh_merge.c
intern/mesh_merge_customdata.cc
@@ -323,7 +326,7 @@ set(SRC
BKE_asset_library.h
BKE_asset_library.hh
BKE_attribute.h
- BKE_attribute_access.hh
+ BKE_attribute.hh
BKE_attribute_math.hh
BKE_autoexec.h
BKE_blender.h
@@ -353,6 +356,7 @@ set(SRC
BKE_cryptomatte.h
BKE_cryptomatte.hh
BKE_curve.h
+ BKE_curve_legacy_convert.hh
BKE_curve_to_mesh.hh
BKE_curveprofile.h
BKE_curves.h
@@ -409,6 +413,7 @@ set(SRC
BKE_linestyle.h
BKE_main.h
BKE_main_idmap.h
+ BKE_main_namemap.h
BKE_mask.h
BKE_material.h
BKE_mball.h
@@ -417,6 +422,7 @@ set(SRC
BKE_mesh_boolean_convert.hh
BKE_mesh_fair.h
BKE_mesh_iterators.h
+ BKE_mesh_legacy_convert.h
BKE_mesh_mapping.h
BKE_mesh_mirror.h
BKE_mesh_remap.h
@@ -431,6 +437,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
+ BKE_node_runtime.hh
BKE_node_tree_update.h
BKE_object.h
BKE_object_deform.h
@@ -610,7 +617,7 @@ if(WITH_IMAGE_HDR)
endif()
if(WITH_IMAGE_WEBP)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
if(WITH_CODEC_AVI)
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 5cf0ca6e062..a29d8726f21 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -52,6 +52,7 @@
#include "BKE_object.h"
#include "BKE_object_deform.h"
#include "BKE_paint.h"
+#include "BKE_subdiv_modifier.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -65,6 +66,9 @@
# include "DNA_userdef_types.h"
#endif
+using blender::float3;
+using blender::IndexRange;
+
/* very slow! enable for testing only! */
//#define USE_MODIFIER_VALIDATE
@@ -80,6 +84,8 @@ static ThreadRWMutex loops_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
static void mesh_init_origspace(Mesh *mesh);
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const CustomData_MeshMasks *final_datamask);
+static void editbmesh_calc_modifier_final_normals_or_defer(
+ Mesh *mesh_final, const CustomData_MeshMasks *final_datamask);
/* -------------------------------------------------------------------- */
@@ -598,10 +604,10 @@ static bool mesh_has_modifier_final_normals(const Mesh *mesh_input,
/* Test if mesh has the required loop normals, in case an additional modifier
* evaluation from another instance or from an operator requests it but the
* initial normals were not loop normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- return (!do_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
+ return (!calc_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
}
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
@@ -610,16 +616,19 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
Mesh *mesh_final)
{
/* Compute normals. */
- const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). In case
* of deferred CPU subdivision, this will be computed when the wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
@@ -628,14 +637,14 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
/* without this, drawing ngon tri's faces will show ugly tessellated face
* 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
+ * note that this isn't a problem for subsurf (only quads) or edit-mode
* which deals with drawing differently. */
BKE_mesh_ensure_normals_for_display(mesh_final);
}
/* Some modifiers, like data-transfer, may generate those data as temp layer,
* we do not want to keep them, as they are used by display code when available
- * (i.e. even if autosmooth is disabled). */
+ * (i.e. even if auto-smooth is disabled). */
if (CustomData_has_layer(&mesh_final->ldata, CD_NORMAL)) {
CustomData_free_layers(&mesh_final->ldata, CD_NORMAL, mesh_final->totloop);
}
@@ -656,8 +665,8 @@ static void mesh_calc_finalize(const Mesh *mesh_input, Mesh *mesh_eval)
mesh_eval->edit_mesh = mesh_input->edit_mesh;
}
-void BKE_mesh_wrapper_deferred_finalize(Mesh *me_eval,
- const CustomData_MeshMasks *cd_mask_finalize)
+void BKE_mesh_wrapper_deferred_finalize_mdata(Mesh *me_eval,
+ const CustomData_MeshMasks *cd_mask_finalize)
{
if (me_eval->runtime.wrapper_type_finalize & (1 << ME_WRAPPER_TYPE_BMESH)) {
editbmesh_calc_modifier_final_normals(me_eval, cd_mask_finalize);
@@ -810,6 +819,25 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Clear errors before evaluation. */
BKE_modifiers_clear_errors(ob);
+ if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
+ if (mesh_final == nullptr) {
+ mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+ ASSERT_IS_VALID_MESH(mesh_final);
+ }
+ float3 *rest_positions = static_cast<float3 *>(CustomData_add_layer_named(&mesh_final->vdata,
+ CD_PROP_FLOAT3,
+ CD_DEFAULT,
+ nullptr,
+ mesh_final->totvert,
+ "rest_position"));
+ blender::threading::parallel_for(
+ IndexRange(mesh_final->totvert), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ rest_positions[i] = mesh_final->mvert[i].co;
+ }
+ });
+ }
+
/* Apply all leading deform modifiers. */
if (use_deform) {
for (; md; md = md->next, md_datamask = md_datamask->next) {
@@ -1260,21 +1288,18 @@ bool editbmesh_modifier_is_enabled(const Scene *scene,
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const CustomData_MeshMasks *final_datamask)
{
- if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) {
- /* Generated at draw time. */
- mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type);
- return;
- }
-
- const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
- (final_datamask->lmask & CD_MASK_NORMAL) != 0);
+ const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
+ (final_datamask->lmask & CD_MASK_NORMAL) != 0);
- mesh_final->runtime.subsurf_do_loop_normals = do_loop_normals;
+ SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime.subsurf_runtime_data;
+ if (subsurf_runtime_data) {
+ subsurf_runtime_data->calc_loop_normals = calc_loop_normals;
+ }
- if (do_loop_normals) {
+ if (calc_loop_normals) {
/* Compute loop normals. In case of deferred CPU subdivision, this will be computed when the
* wrapper is generated. */
- if (mesh_final->runtime.subsurf_resolution == 0) {
+ if (!subsurf_runtime_data || subsurf_runtime_data->resolution == 0) {
BKE_mesh_calc_normals_split(mesh_final);
}
}
@@ -1290,6 +1315,18 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
}
}
+static void editbmesh_calc_modifier_final_normals_or_defer(
+ Mesh *mesh_final, const CustomData_MeshMasks *final_datamask)
+{
+ if (mesh_final->runtime.wrapper_type != ME_WRAPPER_TYPE_MDATA) {
+ /* Generated at draw time. */
+ mesh_final->runtime.wrapper_type_finalize = (1 << mesh_final->runtime.wrapper_type);
+ return;
+ }
+
+ editbmesh_calc_modifier_final_normals(mesh_final, final_datamask);
+}
+
static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
const Scene *scene,
Object *ob,
@@ -1569,9 +1606,9 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
}
/* Compute normals. */
- editbmesh_calc_modifier_final_normals(mesh_final, &final_datamask);
+ editbmesh_calc_modifier_final_normals_or_defer(mesh_final, &final_datamask);
if (mesh_cage && (mesh_cage != mesh_final)) {
- editbmesh_calc_modifier_final_normals(mesh_cage, &final_datamask);
+ editbmesh_calc_modifier_final_normals_or_defer(mesh_cage, &final_datamask);
}
/* Return final mesh. */
@@ -1764,7 +1801,7 @@ void makeDerivedMesh(struct Depsgraph *depsgraph,
BKE_object_free_derived_caches(ob);
if (DEG_is_active(depsgraph)) {
- BKE_sculpt_update_object_before_eval(ob);
+ BKE_sculpt_update_object_before_eval(scene, ob);
}
/* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 371bd8ded6d..fee7582acb3 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -980,13 +980,10 @@ void BKE_pose_channels_remove(Object *ob,
else {
/* Maybe something the bone references is being removed instead? */
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == ob) {
if (ct->subtarget[0]) {
@@ -998,9 +995,7 @@ void BKE_pose_channels_remove(Object *ob,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
@@ -1988,3 +1983,16 @@ void BKE_pose_blend_read_expand(BlendExpander *expander, bPose *pose)
BLO_expand(expander, chan->custom);
}
}
+
+void BKE_action_fcurves_clear(bAction *act)
+{
+ if (!act) {
+ return;
+ }
+ while (act->curves.first) {
+ FCurve *fcu = act->curves.first;
+ action_groups_remove_channel(act, fcu);
+ BKE_fcurve_free(fcu);
+ }
+ DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH);
+}
diff --git a/source/blender/blenkernel/intern/action_mirror.c b/source/blender/blenkernel/intern/action_mirror.c
index 7ef561c8216..0663538f3bb 100644
--- a/source/blender/blenkernel/intern/action_mirror.c
+++ b/source/blender/blenkernel/intern/action_mirror.c
@@ -363,7 +363,7 @@ static void action_flip_pchan(Object *ob_arm,
/* Recalculate handles. */
for (int i = 0; i < fcurve_array_len; i++) {
- calchandles_fcurve_ex(fcurve_array[i], 0);
+ BKE_fcurve_handles_recalc_ex(fcurve_array[i], 0);
}
MEM_freeN((void *)keyed_frames);
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 94b85e42f96..eb4784bebff 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -4074,7 +4074,7 @@ void BKE_animsys_evaluate_all_animation(Main *main, Depsgraph *depsgraph, float
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
- * this tagged by Depsgraph on framechange. This optimization means that objects
+ * this tagged by Depsgraph on frame-change. This optimization means that objects
* linked from other (not-visible) scenes will not need their data calculated.
*/
EVAL_ANIM_IDS(main->objects.first, 0);
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index dfe3d9cc310..f29074c827c 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -2661,13 +2661,31 @@ BoundBox *BKE_armature_boundbox_get(Object *ob)
return ob->runtime.bb;
}
-void BKE_pchan_minmax(const Object *ob, const bPoseChannel *pchan, float r_min[3], float r_max[3])
+void BKE_pchan_minmax(const Object *ob,
+ const bPoseChannel *pchan,
+ const bool use_empty_drawtype,
+ float r_min[3],
+ float r_max[3])
{
const bArmature *arm = ob->data;
- const bPoseChannel *pchan_tx = (pchan->custom && pchan->custom_tx) ? pchan->custom_tx : pchan;
- const BoundBox *bb_custom = ((pchan->custom) && !(arm->flag & ARM_NO_CUSTOM)) ?
- BKE_object_boundbox_get(pchan->custom) :
- NULL;
+ Object *ob_custom = (arm->flag & ARM_NO_CUSTOM) ? NULL : pchan->custom;
+ const bPoseChannel *pchan_tx = (ob_custom && pchan->custom_tx) ? pchan->custom_tx : pchan;
+ const BoundBox *bb_custom = NULL;
+ BoundBox bb_custom_buf;
+
+ if (ob_custom) {
+ float min[3], max[3];
+ if (use_empty_drawtype && (ob_custom->type == OB_EMPTY) &&
+ BKE_object_minmax_empty_drawtype(ob_custom, min, max)) {
+ memset(&bb_custom_buf, 0x0, sizeof(bb_custom_buf));
+ BKE_boundbox_init_from_minmax(&bb_custom_buf, min, max);
+ bb_custom = &bb_custom_buf;
+ }
+ else {
+ bb_custom = BKE_object_boundbox_get(ob_custom);
+ }
+ }
+
if (bb_custom) {
float mat[4][4], smat[4][4], rmat[4][4], tmp[4][4];
scale_m4_fl(smat, PCHAN_CUSTOM_BONE_LENGTH(pchan));
@@ -2704,7 +2722,7 @@ bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden
if (pchan->bone && (!((use_hidden == false) && (PBONE_VISIBLE(arm, pchan->bone) == false)) &&
!((use_select == true) && ((pchan->bone->flag & BONE_SELECTED) == 0)))) {
- BKE_pchan_minmax(ob, pchan, r_min, r_max);
+ BKE_pchan_minmax(ob, pchan, false, r_min, r_max);
changed = true;
}
}
diff --git a/source/blender/blenkernel/intern/attribute.c b/source/blender/blenkernel/intern/attribute.cc
index 7f93eb7b393..030e4941874 100644
--- a/source/blender/blenkernel/intern/attribute.c
+++ b/source/blender/blenkernel/intern/attribute.cc
@@ -7,7 +7,7 @@
* on top of CustomData, which manages individual domains.
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -18,10 +18,12 @@
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
+#include "BLI_index_range.hh"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BKE_attribute.h"
+#include "BKE_attribute.hh"
#include "BKE_curves.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
@@ -30,10 +32,12 @@
#include "RNA_access.h"
-typedef struct DomainInfo {
+using blender::IndexRange;
+
+struct DomainInfo {
CustomData *customdata;
int length;
-} DomainInfo;
+};
static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
{
@@ -49,7 +53,7 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
case ID_ME: {
Mesh *mesh = (Mesh *)id;
BMEditMesh *em = mesh->edit_mesh;
- if (em != NULL) {
+ if (em != nullptr) {
BMesh *bm = em->bm;
info[ATTR_DOMAIN_POINT].customdata = &bm->vdata;
info[ATTR_DOMAIN_POINT].length = bm->totvert;
@@ -85,27 +89,11 @@ static void get_domains(const ID *id, DomainInfo info[ATTR_DOMAIN_NUM])
}
}
-static CustomData *attribute_customdata_find(ID *id, CustomDataLayer *layer)
+bool BKE_id_attributes_supported(const ID *id)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
-
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
- CustomData *customdata = info[domain].customdata;
- if (customdata &&
- ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
- return customdata;
- }
- }
-
- return NULL;
-}
-
-bool BKE_id_attributes_supported(struct ID *id)
-{
- DomainInfo info[ATTR_DOMAIN_NUM];
- get_domains(id, info);
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
if (info[domain].customdata) {
return true;
}
@@ -113,30 +101,38 @@ bool BKE_id_attributes_supported(struct ID *id)
return false;
}
+bool BKE_attribute_allow_procedural_access(const char *attribute_name)
+{
+ return blender::bke::allow_procedural_attribute_access(attribute_name);
+}
+
bool BKE_id_attribute_rename(ID *id,
- CustomDataLayer *layer,
+ const char *old_name,
const char *new_name,
ReportList *reports)
{
- if (BKE_id_attribute_required(id, layer)) {
+ if (BKE_id_attribute_required(id, old_name)) {
BLI_assert_msg(0, "Required attribute name is not editable");
return false;
}
- CustomData *customdata = attribute_customdata_find(id, layer);
- if (customdata == NULL) {
+ CustomDataLayer *layer = BKE_id_attribute_search(
+ id, old_name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ if (layer == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
return false;
}
- BLI_strncpy_utf8(layer->name, new_name, sizeof(layer->name));
- CustomData_set_layer_unique_name(customdata, layer - customdata->layers);
+ char result_name[MAX_CUSTOMDATA_LAYER_NAME];
+ BKE_id_attribute_calc_unique_name(id, new_name, result_name);
+ BLI_strncpy_utf8(layer->name, result_name, sizeof(layer->name));
+
return true;
}
-typedef struct AttrUniqueData {
+struct AttrUniqueData {
ID *id;
-} AttrUniqueData;
+};
static bool unique_name_cb(void *arg, const char *name)
{
@@ -145,7 +141,7 @@ static bool unique_name_cb(void *arg, const char *name)
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(data->id, info);
- for (AttributeDomain domain = ATTR_DOMAIN_POINT; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
if (!info[domain].customdata) {
continue;
}
@@ -165,23 +161,24 @@ static bool unique_name_cb(void *arg, const char *name)
bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname)
{
- AttrUniqueData data = {.id = id};
+ AttrUniqueData data{id};
BLI_strncpy_utf8(outname, name, MAX_CUSTOMDATA_LAYER_NAME);
- return BLI_uniquename_cb(unique_name_cb, &data, NULL, '.', outname, MAX_CUSTOMDATA_LAYER_NAME);
+ return BLI_uniquename_cb(
+ unique_name_cb, &data, nullptr, '.', outname, MAX_CUSTOMDATA_LAYER_NAME);
}
CustomDataLayer *BKE_id_attribute_new(
- ID *id, const char *name, const int type, const AttributeDomain domain, ReportList *reports)
+ ID *id, const char *name, const int type, const eAttrDomain domain, ReportList *reports)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
CustomData *customdata = info[domain].customdata;
- if (customdata == NULL) {
+ if (customdata == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute domain not supported by this geometry type");
- return NULL;
+ return nullptr;
}
char uniquename[MAX_CUSTOMDATA_LAYER_NAME];
@@ -191,77 +188,106 @@ CustomDataLayer *BKE_id_attribute_new(
case ID_ME: {
Mesh *me = (Mesh *)id;
BMEditMesh *em = me->edit_mesh;
- if (em != NULL) {
+ if (em != nullptr) {
BM_data_layer_add_named(em->bm, customdata, type, uniquename);
}
else {
CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, NULL, info[domain].length, uniquename);
+ customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
}
break;
}
default: {
CustomData_add_layer_named(
- customdata, type, CD_DEFAULT, NULL, info[domain].length, uniquename);
+ customdata, type, CD_DEFAULT, nullptr, info[domain].length, uniquename);
break;
}
}
const int index = CustomData_get_named_layer_index(customdata, type, uniquename);
- return (index == -1) ? NULL : &(customdata->layers[index]);
+ return (index == -1) ? nullptr : &(customdata->layers[index]);
}
-bool BKE_id_attribute_remove(ID *id, CustomDataLayer *layer, ReportList *reports)
+CustomDataLayer *BKE_id_attribute_duplicate(ID *id, const char *name, ReportList *reports)
{
- CustomData *customdata = attribute_customdata_find(id, layer);
- const int index = (customdata) ?
- CustomData_get_named_layer_index(customdata, layer->type, layer->name) :
- -1;
-
- if (index == -1) {
+ const CustomDataLayer *src_layer = BKE_id_attribute_search(
+ id, name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ if (src_layer == nullptr) {
BKE_report(reports, RPT_ERROR, "Attribute is not part of this geometry");
- return false;
+ return nullptr;
}
- if (BKE_id_attribute_required(id, layer)) {
+ const eCustomDataType type = (eCustomDataType)src_layer->type;
+ const eAttrDomain domain = BKE_id_attribute_domain(id, src_layer);
+
+ /* Make a copy of name in case CustomData API reallocates the layers. */
+ const std::string name_copy = name;
+
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+ CustomData *customdata = info[domain].customdata;
+
+ CustomDataLayer *new_layer = BKE_id_attribute_new(id, name_copy.c_str(), type, domain, reports);
+ if (new_layer == nullptr) {
+ return nullptr;
+ }
+
+ const int from_index = CustomData_get_named_layer_index(customdata, type, name_copy.c_str());
+ const int to_index = CustomData_get_named_layer_index(customdata, type, new_layer->name);
+ CustomData_copy_data_layer(
+ customdata, customdata, from_index, to_index, 0, 0, info[domain].length);
+
+ return new_layer;
+}
+
+bool BKE_id_attribute_remove(ID *id, const char *name, ReportList *reports)
+{
+ if (BKE_id_attribute_required(id, name)) {
BKE_report(reports, RPT_ERROR, "Attribute is required and can't be removed");
return false;
}
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+
switch (GS(id->name)) {
case ID_ME: {
- Mesh *me = (Mesh *)id;
- BMEditMesh *em = me->edit_mesh;
- if (em != NULL) {
- BM_data_layer_free(em->bm, customdata, layer->type);
- }
- else {
- const int length = BKE_id_attribute_data_length(id, layer);
- CustomData_free_layer(customdata, layer->type, length, index);
+ Mesh *mesh = reinterpret_cast<Mesh *>(id);
+ if (BMEditMesh *em = mesh->edit_mesh) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
+ if (CustomData *data = info[domain].customdata) {
+ if (BM_data_layer_free_named(em->bm, data, name)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
- break;
- }
- default: {
- const int length = BKE_id_attribute_data_length(id, layer);
- CustomData_free_layer(customdata, layer->type, length, index);
- break;
+ ATTR_FALLTHROUGH;
}
+ default:
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
+ if (CustomData *data = info[domain].customdata) {
+ if (CustomData_free_layer_named(data, name, info[domain].length)) {
+ return true;
+ }
+ }
+ }
+ return false;
}
-
- return true;
}
CustomDataLayer *BKE_id_attribute_find(const ID *id,
const char *name,
const int type,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
CustomData *customdata = info[domain].customdata;
- if (customdata == NULL) {
- return NULL;
+ if (customdata == nullptr) {
+ return nullptr;
}
for (int i = 0; i < customdata->totlayer; i++) {
@@ -271,17 +297,47 @@ CustomDataLayer *BKE_id_attribute_find(const ID *id,
}
}
- return NULL;
+ return nullptr;
+}
+
+CustomDataLayer *BKE_id_attribute_search(ID *id,
+ const char *name,
+ const eCustomDataMask type_mask,
+ const eAttrDomainMask domain_mask)
+{
+ DomainInfo info[ATTR_DOMAIN_NUM];
+ get_domains(id, info);
+
+ for (eAttrDomain domain = ATTR_DOMAIN_POINT; domain < ATTR_DOMAIN_NUM;
+ domain = static_cast<eAttrDomain>((static_cast<int>(domain)) + 1)) {
+ if (!(domain_mask & ATTR_DOMAIN_AS_MASK(domain))) {
+ continue;
+ }
+
+ CustomData *customdata = info[domain].customdata;
+ if (customdata == nullptr) {
+ continue;
+ }
+
+ for (int i = 0; i < customdata->totlayer; i++) {
+ CustomDataLayer *layer = &customdata->layers[i];
+ if ((CD_TYPE_AS_MASK(layer->type) & type_mask) && STREQ(layer->name, name)) {
+ return layer;
+ }
+ }
+ }
+
+ return nullptr;
}
-int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, CustomDataMask mask)
+int BKE_id_attributes_length(const ID *id, eAttrDomainMask domain_mask, eCustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
int length = 0;
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata && ((1 << (int)domain) & domain_mask)) {
@@ -292,21 +348,21 @@ int BKE_id_attributes_length(const ID *id, AttributeDomainMask domain_mask, Cust
return length;
}
-AttributeDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *layer)
+eAttrDomain BKE_id_attribute_domain(const ID *id, const CustomDataLayer *layer)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata &&
ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
- return domain;
+ return static_cast<eAttrDomain>(domain);
}
}
BLI_assert_msg(0, "Custom data layer not found in geometry");
- return ATTR_DOMAIN_NUM;
+ return static_cast<eAttrDomain>(ATTR_DOMAIN_POINT);
}
int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
@@ -317,7 +373,7 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
switch (GS(id->name)) {
case ID_ME: {
Mesh *mesh = (Mesh *)id;
- if (mesh->edit_mesh != NULL) {
+ if (mesh->edit_mesh != nullptr) {
return 0;
}
}
@@ -328,7 +384,7 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata &&
ARRAY_HAS_ITEM((CustomDataLayer *)layer, customdata->layers, customdata->totlayer)) {
@@ -340,14 +396,14 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer)
return 0;
}
-bool BKE_id_attribute_required(ID *id, CustomDataLayer *layer)
+bool BKE_id_attribute_required(const ID *id, const char *name)
{
switch (GS(id->name)) {
case ID_PT: {
- return BKE_pointcloud_customdata_required((PointCloud *)id, layer);
+ return BKE_pointcloud_customdata_required((const PointCloud *)id, name);
}
case ID_CV: {
- return BKE_curves_customdata_required((Curves *)id, layer);
+ return BKE_curves_customdata_required((const Curves *)id, name);
}
default:
return false;
@@ -366,7 +422,7 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
int index = 0;
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata) {
for (int i = 0; i < customdata->totlayer; i++) {
@@ -381,7 +437,7 @@ CustomDataLayer *BKE_id_attributes_active_get(ID *id)
}
}
- return NULL;
+ return nullptr;
}
void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
@@ -391,7 +447,7 @@ void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer)
int index = 0;
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata) {
for (int i = 0; i < customdata->totlayer; i++) {
@@ -421,7 +477,7 @@ int *BKE_id_attributes_active_index_p(ID *id)
return &((Curves *)id)->attributes_active_index;
}
default:
- return NULL;
+ return nullptr;
}
}
@@ -430,9 +486,9 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
- bool use_next = (layers == NULL);
+ bool use_next = (layers == nullptr);
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (customdata && customdata->layers && customdata->totlayer) {
if (customdata->layers == layers) {
@@ -444,19 +500,19 @@ CustomData *BKE_id_attributes_iterator_next_domain(ID *id, CustomDataLayer *laye
}
}
- return NULL;
+ return nullptr;
}
CustomDataLayer *BKE_id_attribute_from_index(ID *id,
int lookup_index,
- AttributeDomainMask domain_mask,
- CustomDataMask layer_mask)
+ eAttrDomainMask domain_mask,
+ eCustomDataMask layer_mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
get_domains(id, info);
int index = 0;
- for (AttributeDomain domain = 0; domain < ATTR_DOMAIN_NUM; domain++) {
+ for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) {
CustomData *customdata = info[domain].customdata;
if (!customdata || !((1 << (int)domain) & domain_mask)) {
@@ -477,33 +533,33 @@ CustomDataLayer *BKE_id_attribute_from_index(ID *id,
}
}
- return NULL;
+ return nullptr;
}
/** Get list of domain types but with ATTR_DOMAIN_FACE and
* ATTR_DOMAIN_CORNER swapped.
*/
-static void get_domains_types(AttributeDomain domains[ATTR_DOMAIN_NUM])
+static void get_domains_types(eAttrDomain domains[ATTR_DOMAIN_NUM])
{
- for (AttributeDomain i = 0; i < ATTR_DOMAIN_NUM; i++) {
- domains[i] = i;
+ for (const int i : IndexRange(ATTR_DOMAIN_NUM)) {
+ domains[i] = static_cast<eAttrDomain>(i);
}
/* Swap corner and face. */
- SWAP(AttributeDomain, domains[ATTR_DOMAIN_FACE], domains[ATTR_DOMAIN_CORNER]);
+ SWAP(eAttrDomain, domains[ATTR_DOMAIN_FACE], domains[ATTR_DOMAIN_CORNER]);
}
-int BKE_id_attribute_to_index(const struct ID *id,
+int BKE_id_attribute_to_index(const ID *id,
const CustomDataLayer *layer,
- AttributeDomainMask domain_mask,
- CustomDataMask layer_mask)
+ eAttrDomainMask domain_mask,
+ eCustomDataMask layer_mask)
{
if (!layer) {
return -1;
}
DomainInfo info[ATTR_DOMAIN_NUM];
- AttributeDomain domains[ATTR_DOMAIN_NUM];
+ eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info);
@@ -513,9 +569,9 @@ int BKE_id_attribute_to_index(const struct ID *id,
continue;
}
- CustomData *cdata = info[domains[i]].customdata;
+ const CustomData *cdata = info[domains[i]].customdata;
for (int j = 0; j < cdata->totlayer; j++) {
- CustomDataLayer *layer_iter = cdata->layers + j;
+ const CustomDataLayer *layer_iter = cdata->layers + j;
if (!(CD_TYPE_AS_MASK(layer_iter->type) & layer_mask) ||
(layer_iter->flag & CD_FLAG_TEMPORARY)) {
@@ -535,16 +591,16 @@ int BKE_id_attribute_to_index(const struct ID *id,
CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id,
int active_flag,
- AttributeDomainMask domain_mask,
- CustomDataMask mask)
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
- AttributeDomain domains[ATTR_DOMAIN_NUM];
+ eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info);
- CustomDataLayer *candidate = NULL;
+ CustomDataLayer *candidate = nullptr;
for (int i = 0; i < ARRAY_SIZE(domains); i++) {
if (!((1 << domains[i]) & domain_mask) || !info[domains[i]].customdata) {
continue;
@@ -573,17 +629,17 @@ CustomDataLayer *BKE_id_attribute_subset_active_get(const ID *id,
void BKE_id_attribute_subset_active_set(ID *id,
CustomDataLayer *layer,
int active_flag,
- AttributeDomainMask domain_mask,
- CustomDataMask mask)
+ eAttrDomainMask domain_mask,
+ eCustomDataMask mask)
{
DomainInfo info[ATTR_DOMAIN_NUM];
- AttributeDomain domains[ATTR_DOMAIN_NUM];
+ eAttrDomain domains[ATTR_DOMAIN_NUM];
get_domains_types(domains);
get_domains(id, info);
for (int i = 0; i < ATTR_DOMAIN_NUM; i++) {
- AttributeDomainMask domain_mask2 = (AttributeDomainMask)(1 << domains[i]);
+ eAttrDomainMask domain_mask2 = (eAttrDomainMask)(1 << domains[i]);
if (!(domain_mask2 & domain_mask) || !info[domains[i]].customdata) {
continue;
@@ -632,15 +688,16 @@ void BKE_id_attributes_render_color_set(ID *id, CustomDataLayer *active_layer)
CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name)
{
CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT);
- if (layer == NULL) {
+ if (layer == nullptr) {
layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER);
}
- if (layer == NULL) {
+ if (layer == nullptr) {
layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_POINT);
}
- if (layer == NULL) {
+ if (layer == nullptr) {
layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER);
}
+
return layer;
}
@@ -661,7 +718,7 @@ void BKE_id_attribute_copy_domains_temp(short id_type,
Mesh *me = (Mesh *)r_id;
memset((void *)me, 0, sizeof(*me));
- me->edit_mesh = NULL;
+ me->edit_mesh = nullptr;
me->vdata = vdata ? *vdata : reset;
me->edata = edata ? *edata : reset;
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index e86bac21084..a834b77d65e 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -2,7 +2,6 @@
#include <utility>
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_customdata.h"
#include "BKE_deform.h"
@@ -26,8 +25,6 @@
#include "attribute_access_intern.hh"
-static CLG_LogRef LOG = {"bke.attribute_access"};
-
using blender::float3;
using blender::GMutableSpan;
using blender::GSpan;
@@ -36,7 +33,6 @@ using blender::Set;
using blender::StringRef;
using blender::StringRefNull;
using blender::bke::AttributeIDRef;
-using blender::bke::OutputAttribute;
namespace blender::bke {
@@ -55,7 +51,15 @@ std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_i
return stream;
}
-static int attribute_data_type_complexity(const CustomDataType data_type)
+const char *no_procedural_access_message =
+ "This attribute can not be accessed in a procedural context";
+
+bool allow_procedural_attribute_access(StringRef attribute_name)
+{
+ return !attribute_name.startswith(".selection");
+}
+
+static int attribute_data_type_complexity(const eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_BOOL:
@@ -85,12 +89,12 @@ static int attribute_data_type_complexity(const CustomDataType data_type)
}
}
-CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_types)
+eCustomDataType attribute_data_type_highest_complexity(Span<eCustomDataType> data_types)
{
int highest_complexity = INT_MIN;
- CustomDataType most_complex_type = CD_PROP_COLOR;
+ eCustomDataType most_complex_type = CD_PROP_COLOR;
- for (const CustomDataType data_type : data_types) {
+ for (const eCustomDataType data_type : data_types) {
const int complexity = attribute_data_type_complexity(data_type);
if (complexity > highest_complexity) {
highest_complexity = complexity;
@@ -105,7 +109,7 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_
* \note Generally the order should mirror the order of the domains
* established in each component's ComponentAttributeProviders.
*/
-static int attribute_domain_priority(const AttributeDomain domain)
+static int attribute_domain_priority(const eAttrDomain domain)
{
switch (domain) {
case ATTR_DOMAIN_INSTANCE:
@@ -127,12 +131,12 @@ static int attribute_domain_priority(const AttributeDomain domain)
}
}
-AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
+eAttrDomain attribute_domain_highest_priority(Span<eAttrDomain> domains)
{
int highest_priority = INT_MIN;
- AttributeDomain highest_priority_domain = ATTR_DOMAIN_CORNER;
+ eAttrDomain highest_priority_domain = ATTR_DOMAIN_CORNER;
- for (const AttributeDomain domain : domains) {
+ for (const eAttrDomain domain : domains) {
const int priority = attribute_domain_priority(domain);
if (priority > highest_priority) {
highest_priority = priority;
@@ -143,37 +147,6 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
return highest_priority_domain;
}
-GMutableSpan OutputAttribute::as_span()
-{
- if (!optional_span_varray_) {
- const bool materialize_old_values = !ignore_old_values_;
- optional_span_varray_ = std::make_unique<GVMutableArray_GSpan>(varray_,
- materialize_old_values);
- }
- GVMutableArray_GSpan &span_varray = *optional_span_varray_;
- return span_varray;
-}
-
-void OutputAttribute::save()
-{
- save_has_been_called_ = true;
- if (optional_span_varray_) {
- optional_span_varray_->save();
- }
- if (save_) {
- save_(*this);
- }
-}
-
-OutputAttribute::~OutputAttribute()
-{
- if (!save_has_been_called_) {
- if (varray_) {
- std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
- }
- }
-}
-
static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer &layer)
{
if (layer.anonymous_id != nullptr) {
@@ -183,7 +156,7 @@ static AttributeIDRef attribute_id_from_custom_data_layer(const CustomDataLayer
}
static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const int domain_num,
const AttributeInit &initializer)
{
@@ -218,7 +191,7 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data
}
static void *add_generic_custom_data_layer(CustomData &custom_data,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const eCDAllocType alloctype,
void *layer_data,
const int domain_num,
@@ -237,7 +210,7 @@ static void *add_generic_custom_data_layer(CustomData &custom_data,
static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id,
CustomData &custom_data,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const int domain_num,
const AttributeInit &initializer)
{
@@ -285,9 +258,9 @@ static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer,
return layer.name == attribute_id.name();
}
-GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent &component) const
+GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const void *owner) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
@@ -303,21 +276,20 @@ GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
- return as_read_attribute_(data, domain_num);
+ const int element_num = custom_data_access_.get_element_num(owner);
+ return as_read_attribute_(data, element_num);
}
-WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
- GeometryComponent &component) const
+GAttributeWriter BuiltinCustomDataLayerProvider::try_get_for_write(void *owner) const
{
if (writable_ != Writable) {
return {};
}
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
void *data;
if (stored_as_named_attribute_) {
@@ -333,75 +305,70 @@ WriteAttributeLookup BuiltinCustomDataLayerProvider::try_get_for_write(
void *new_data;
if (stored_as_named_attribute_) {
new_data = CustomData_duplicate_referenced_layer_named(
- custom_data, stored_type_, name_.c_str(), domain_num);
+ custom_data, stored_type_, name_.c_str(), element_num);
}
else {
- new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_num);
+ new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, element_num);
}
if (data != new_data) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
data = new_data;
}
std::function<void()> tag_modified_fn;
if (update_on_write_ != nullptr) {
- tag_modified_fn = [component = &component, update = update_on_write_]() {
- update(*component);
- };
+ tag_modified_fn = [owner, update = update_on_write_]() { update(owner); };
}
- return {as_write_attribute_(data, domain_num), domain_, std::move(tag_modified_fn)};
+ return {as_write_attribute_(data, element_num), domain_, std::move(tag_modified_fn)};
}
-bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const
+bool BuiltinCustomDataLayerProvider::try_delete(void *owner) const
{
if (deletable_ != Deletable) {
return false;
}
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
- int layer_index;
+ const int element_num = custom_data_access_.get_element_num(owner);
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;
+ if (CustomData_free_layer_named(custom_data, name_.c_str(), element_num)) {
+ if (custom_data_access_.update_custom_data_pointers) {
+ custom_data_access_.update_custom_data_pointers(owner);
}
+ return true;
}
- }
- else {
- layer_index = CustomData_get_layer_index(custom_data, stored_type_);
+ return false;
}
- const bool delete_success = CustomData_free_layer(
- custom_data, stored_type_, domain_num, layer_index);
- if (delete_success) {
+ const int layer_index = CustomData_get_layer_index(custom_data, stored_type_);
+ if (CustomData_free_layer(custom_data, stored_type_, element_num, layer_index)) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
+ return true;
}
- return delete_success;
+ return false;
}
-bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
+bool BuiltinCustomDataLayerProvider::try_create(void *owner,
const AttributeInit &initializer) const
{
if (createable_ != Creatable) {
return false;
}
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
bool success;
if (stored_as_named_attribute_) {
if (CustomData_get_layer_named(custom_data, data_type_, name_.c_str())) {
@@ -409,7 +376,7 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
return false;
}
success = add_custom_data_layer_from_attribute_init(
- name_, *custom_data, stored_type_, domain_num, initializer);
+ name_, *custom_data, stored_type_, element_num, initializer);
}
else {
if (CustomData_get_layer(custom_data, stored_type_) != nullptr) {
@@ -417,19 +384,19 @@ bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component,
return false;
}
success = add_builtin_type_custom_data_layer_from_init(
- *custom_data, stored_type_, domain_num, initializer);
+ *custom_data, stored_type_, element_num, initializer);
}
if (success) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
}
return success;
}
-bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) const
+bool BuiltinCustomDataLayerProvider::exists(const void *owner) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
@@ -439,80 +406,81 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component)
return CustomData_get_layer(custom_data, stored_type_) != nullptr;
}
-ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
- const GeometryComponent &component, const AttributeIDRef &attribute_id) const
+GAttributeReader CustomDataAttributeProvider::try_get_for_read(
+ const void *owner, const AttributeIDRef &attribute_id) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
continue;
}
- const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
+ const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
if (type == nullptr) {
continue;
}
- GSpan data{*type, layer.data, domain_num};
+ GSpan data{*type, layer.data, element_num};
return {GVArray::ForSpan(data), domain_};
}
return {};
}
-WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
- GeometryComponent &component, const AttributeIDRef &attribute_id) const
+GAttributeWriter CustomDataAttributeProvider::try_get_for_write(
+ void *owner, const AttributeIDRef &attribute_id) const
{
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
if (!custom_data_layer_matches_attribute_id(layer, attribute_id)) {
continue;
}
if (attribute_id.is_named()) {
- CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_num);
+ CustomData_duplicate_referenced_layer_named(
+ custom_data, layer.type, layer.name, element_num);
}
else {
CustomData_duplicate_referenced_layer_anonymous(
- custom_data, layer.type, &attribute_id.anonymous_id(), domain_num);
+ custom_data, layer.type, &attribute_id.anonymous_id(), element_num);
}
- const CPPType *type = custom_data_type_to_cpp_type((CustomDataType)layer.type);
+ const CPPType *type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
if (type == nullptr) {
continue;
}
- GMutableSpan data{*type, layer.data, domain_num};
+ GMutableSpan data{*type, layer.data, element_num};
return {GVMutableArray::ForSpan(data), domain_};
}
return {};
}
-bool CustomDataAttributeProvider::try_delete(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const
+bool CustomDataAttributeProvider::try_delete(void *owner, const AttributeIDRef &attribute_id) const
{
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
+ ;
for (const int i : IndexRange(custom_data->totlayer)) {
const CustomDataLayer &layer = custom_data->layers[i];
- if (this->type_is_supported((CustomDataType)layer.type) &&
+ if (this->type_is_supported((eCustomDataType)layer.type) &&
custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- CustomData_free_layer(custom_data, layer.type, domain_num, i);
+ CustomData_free_layer(custom_data, layer.type, element_num, i);
return true;
}
}
return false;
}
-bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
+bool CustomDataAttributeProvider::try_create(void *owner,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const AttributeInit &initializer) const
{
if (domain_ != domain) {
@@ -521,7 +489,7 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
if (!this->type_is_supported(data_type)) {
return false;
}
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
@@ -530,21 +498,21 @@ bool CustomDataAttributeProvider::try_create(GeometryComponent &component,
return false;
}
}
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
add_custom_data_layer_from_attribute_init(
- attribute_id, *custom_data, data_type, domain_num, initializer);
+ attribute_id, *custom_data, data_type, element_num, initializer);
return true;
}
-bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &component,
+bool CustomDataAttributeProvider::foreach_attribute(const void *owner,
const AttributeForeachCallback callback) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return true;
}
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
- const CustomDataType data_type = (CustomDataType)layer.type;
+ const eCustomDataType data_type = (eCustomDataType)layer.type;
if (this->type_is_supported(data_type)) {
AttributeMetaData meta_data{domain_, data_type};
const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
@@ -556,17 +524,17 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
return true;
}
-ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
- const GeometryComponent &component, const AttributeIDRef &attribute_id) const
+GAttributeReader NamedLegacyCustomDataProvider::try_get_for_read(
+ const void *owner, const AttributeIDRef &attribute_id) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) {
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_num = component.attribute_domain_num(domain_);
+ const int domain_num = custom_data_access_.get_element_num(owner);
return {as_read_attribute_(layer.data, domain_num), domain_};
}
}
@@ -574,36 +542,36 @@ ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
return {};
}
-WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
- GeometryComponent &component, const AttributeIDRef &attribute_id) const
+GAttributeWriter NamedLegacyCustomDataProvider::try_get_for_write(
+ void *owner, const AttributeIDRef &attribute_id) const
{
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return {};
}
for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) {
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_num = component.attribute_domain_num(domain_);
+ const int element_num = custom_data_access_.get_element_num(owner);
void *data_old = layer.data;
void *data_new = CustomData_duplicate_referenced_layer_named(
- custom_data, stored_type_, layer.name, domain_num);
+ custom_data, stored_type_, layer.name, element_num);
if (data_old != data_new) {
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
}
- return {as_write_attribute_(layer.data, domain_num), domain_};
+ return {as_write_attribute_(layer.data, element_num), domain_};
}
}
}
return {};
}
-bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
+bool NamedLegacyCustomDataProvider::try_delete(void *owner,
const AttributeIDRef &attribute_id) const
{
- CustomData *custom_data = custom_data_access_.get_custom_data(component);
+ CustomData *custom_data = custom_data_access_.get_custom_data(owner);
if (custom_data == nullptr) {
return false;
}
@@ -611,10 +579,10 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
const CustomDataLayer &layer = custom_data->layers[i];
if (layer.type == stored_type_) {
if (custom_data_layer_matches_attribute_id(layer, attribute_id)) {
- const int domain_num = component.attribute_domain_num(domain_);
- CustomData_free_layer(custom_data, stored_type_, domain_num, i);
+ const int element_num = custom_data_access_.get_element_num(owner);
+ CustomData_free_layer(custom_data, stored_type_, element_num, i);
if (custom_data_access_.update_custom_data_pointers) {
- custom_data_access_.update_custom_data_pointers(component);
+ custom_data_access_.update_custom_data_pointers(owner);
}
return true;
}
@@ -624,9 +592,9 @@ bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component,
}
bool NamedLegacyCustomDataProvider::foreach_attribute(
- const GeometryComponent &component, const AttributeForeachCallback callback) const
+ const void *owner, const AttributeForeachCallback callback) const
{
- const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
+ const CustomData *custom_data = custom_data_access_.get_const_custom_data(owner);
if (custom_data == nullptr) {
return true;
}
@@ -642,7 +610,7 @@ bool NamedLegacyCustomDataProvider::foreach_attribute(
}
void NamedLegacyCustomDataProvider::foreach_domain(
- const FunctionRef<void(AttributeDomain)> callback) const
+ const FunctionRef<void(eAttrDomain)> callback) const
{
callback(domain_);
}
@@ -685,7 +653,7 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at
{
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);
+ const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
BLI_assert(cpp_type != nullptr);
return GSpan(*cpp_type, layer.data, size_);
}
@@ -694,7 +662,7 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at
}
GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const void *default_value) const
{
const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
@@ -718,7 +686,7 @@ std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeI
{
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);
+ const CPPType *cpp_type = custom_data_type_to_cpp_type((eCustomDataType)layer.type);
BLI_assert(cpp_type != nullptr);
return GMutableSpan(*cpp_type, layer.data, size_);
}
@@ -727,7 +695,7 @@ std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeI
}
bool CustomDataAttributes::create(const AttributeIDRef &attribute_id,
- const CustomDataType data_type)
+ const eCustomDataType data_type)
{
void *result = add_generic_custom_data_layer(
data, data_type, CD_DEFAULT, nullptr, size_, attribute_id);
@@ -735,7 +703,7 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id,
}
bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
void *buffer)
{
void *result = add_generic_custom_data_layer(
@@ -768,10 +736,10 @@ void CustomDataAttributes::clear()
}
bool CustomDataAttributes::foreach_attribute(const AttributeForeachCallback callback,
- const AttributeDomain domain) const
+ const eAttrDomain domain) const
{
for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
- AttributeMetaData meta_data{domain, (CustomDataType)layer.type};
+ AttributeMetaData meta_data{domain, (eCustomDataType)layer.type};
const AttributeIDRef attribute_id = attribute_id_from_custom_data_layer(layer);
if (!callback(attribute_id, meta_data)) {
return false;
@@ -800,275 +768,10 @@ void CustomDataAttributes::reorder(Span<AttributeIDRef> new_order)
CustomData_update_typemap(&data);
}
-} // namespace blender::bke
-
/* -------------------------------------------------------------------- */
/** \name Geometry Component
* \{ */
-const blender::bke::ComponentAttributeProviders *GeometryComponent::get_attribute_providers() const
-{
- return nullptr;
-}
-
-bool GeometryComponent::attribute_domain_supported(const AttributeDomain domain) const
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return false;
- }
- return providers->supported_domains().contains(domain);
-}
-
-int GeometryComponent::attribute_domain_num(const AttributeDomain UNUSED(domain)) const
-{
- return 0;
-}
-
-bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_name) const
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return false;
- }
- return providers->builtin_attribute_providers().contains_as(attribute_name);
-}
-
-bool GeometryComponent::attribute_is_builtin(const AttributeIDRef &attribute_id) const
-{
- /* Anonymous attributes cannot be built-in. */
- return attribute_id.is_named() && this->attribute_is_builtin(attribute_id.name());
-}
-
-blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
- const AttributeIDRef &attribute_id) const
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return {};
- }
- if (attribute_id.is_named()) {
- 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_read(*this), builtin_provider->domain()};
- }
- }
- for (const DynamicAttributesProvider *dynamic_provider :
- providers->dynamic_attribute_providers()) {
- ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_id);
- if (attribute) {
- return attribute;
- }
- }
- return {};
-}
-
-blender::GVArray GeometryComponent::attribute_try_adapt_domain_impl(
- const blender::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
-{
- if (from_domain == to_domain) {
- return varray;
- }
- return {};
-}
-
-blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write(
- const AttributeIDRef &attribute_id)
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return {};
- }
- if (attribute_id.is_named()) {
- 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);
- }
- }
- for (const DynamicAttributesProvider *dynamic_provider :
- providers->dynamic_attribute_providers()) {
- WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_id);
- if (attribute) {
- return attribute;
- }
- }
- return {};
-}
-
-bool GeometryComponent::attribute_try_delete(const AttributeIDRef &attribute_id)
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return {};
- }
- if (attribute_id.is_named()) {
- const BuiltinAttributeProvider *builtin_provider =
- providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
- if (builtin_provider != nullptr) {
- return builtin_provider->try_delete(*this);
- }
- }
- bool success = false;
- for (const DynamicAttributesProvider *dynamic_provider :
- providers->dynamic_attribute_providers()) {
- success = dynamic_provider->try_delete(*this, attribute_id) || success;
- }
- return success;
-}
-
-void GeometryComponent::attributes_remove_anonymous()
-{
- using namespace blender;
- Vector<const AnonymousAttributeID *> anonymous_ids;
- for (const AttributeIDRef &id : this->attribute_ids()) {
- if (id.is_anonymous()) {
- anonymous_ids.append(&id.anonymous_id());
- }
- }
-
- while (!anonymous_ids.is_empty()) {
- this->attribute_try_delete(anonymous_ids.pop_last());
- }
-}
-
-bool GeometryComponent::attribute_try_create(const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const AttributeInit &initializer)
-{
- using namespace blender::bke;
- if (!attribute_id) {
- return false;
- }
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return false;
- }
- if (this->attribute_exists(attribute_id)) {
- return false;
- }
- if (attribute_id.is_named()) {
- const BuiltinAttributeProvider *builtin_provider =
- providers->builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
- if (builtin_provider != nullptr) {
- if (builtin_provider->domain() != domain) {
- return false;
- }
- if (builtin_provider->data_type() != data_type) {
- return false;
- }
- return builtin_provider->try_create(*this, initializer);
- }
- }
- for (const DynamicAttributesProvider *dynamic_provider :
- providers->dynamic_attribute_providers()) {
- if (dynamic_provider->try_create(*this, attribute_id, domain, data_type, initializer)) {
- return true;
- }
- }
- return false;
-}
-
-bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name,
- const AttributeInit &initializer)
-{
- using namespace blender::bke;
- if (attribute_name.is_empty()) {
- return false;
- }
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return false;
- }
- const BuiltinAttributeProvider *builtin_provider =
- providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
- if (builtin_provider == nullptr) {
- return false;
- }
- return builtin_provider->try_create(*this, initializer);
-}
-
-Set<AttributeIDRef> GeometryComponent::attribute_ids() const
-{
- Set<AttributeIDRef> attributes;
- this->attribute_foreach(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &UNUSED(meta_data)) {
- attributes.add(attribute_id);
- return true;
- });
- return attributes;
-}
-
-bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callback) const
-{
- using namespace blender::bke;
- const ComponentAttributeProviders *providers = this->get_attribute_providers();
- if (providers == nullptr) {
- return true;
- }
-
- /* Keep track handled attribute names to make sure that we do not return the same name twice. */
- Set<std::string> handled_attribute_names;
-
- for (const BuiltinAttributeProvider *provider :
- providers->builtin_attribute_providers().values()) {
- if (provider->exists(*this)) {
- AttributeMetaData meta_data{provider->domain(), provider->data_type()};
- if (!callback(provider->name(), meta_data)) {
- return false;
- }
- handled_attribute_names.add_new(provider->name());
- }
- }
- for (const DynamicAttributesProvider *provider : providers->dynamic_attribute_providers()) {
- const bool continue_loop = provider->foreach_attribute(
- *this, [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- if (attribute_id.is_anonymous() || handled_attribute_names.add(attribute_id.name())) {
- return callback(attribute_id, meta_data);
- }
- return true;
- });
- if (!continue_loop) {
- return false;
- }
- }
-
- return true;
-}
-
-bool GeometryComponent::attribute_exists(const AttributeIDRef &attribute_id) const
-{
- blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
- if (attribute) {
- return true;
- }
- return false;
-}
-
-std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
- const AttributeIDRef &attribute_id) const
-{
- std::optional<AttributeMetaData> result{std::nullopt};
- this->attribute_foreach(
- [&](const AttributeIDRef &current_attribute_id, const AttributeMetaData &meta_data) {
- if (attribute_id == current_attribute_id) {
- result = meta_data;
- return false;
- }
- return true;
- });
- return result;
-}
-
static blender::GVArray try_adapt_data_type(blender::GVArray varray,
const blender::CPPType &to_type)
{
@@ -1077,296 +780,6 @@ static blender::GVArray try_adapt_data_type(blender::GVArray varray,
return conversions.try_convert(std::move(varray), to_type);
}
-blender::GVArray GeometryComponent::attribute_try_get_for_read(
- const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type) const
-{
- blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
- if (!attribute) {
- return {};
- }
-
- blender::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 {};
- }
- }
-
- const blender::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
- if (varray.type() != *cpp_type) {
- varray = try_adapt_data_type(std::move(varray), *cpp_type);
- if (!varray) {
- return {};
- }
- }
-
- return varray;
-}
-
-blender::GVArray GeometryComponent::attribute_try_get_for_read(const AttributeIDRef &attribute_id,
- const AttributeDomain domain) const
-{
- if (!this->attribute_domain_supported(domain)) {
- return {};
- }
-
- blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
- if (!attribute) {
- return {};
- }
-
- if (attribute.domain != domain) {
- return this->attribute_try_adapt_domain(std::move(attribute.varray), attribute.domain, domain);
- }
-
- return std::move(attribute.varray);
-}
-
-blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
- const AttributeIDRef &attribute_id, const CustomDataType data_type) const
-{
- blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_id);
- if (!attribute) {
- return {};
- }
- const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(type != nullptr);
- if (attribute.varray.type() == *type) {
- return attribute;
- }
- const blender::bke::DataTypeConversions &conversions =
- blender::bke::get_implicit_type_conversions();
- return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
-}
-
-blender::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value) const
-{
- blender::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type);
- if (varray) {
- return varray;
- }
- const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
- if (default_value == nullptr) {
- default_value = type->default_value();
- }
- const int domain_num = this->attribute_domain_num(domain);
- return blender::GVArray::ForSingle(*type, domain_num, default_value);
-}
-
-class GVMutableAttribute_For_OutputAttribute : public blender::GVArrayImpl_For_GSpan {
- public:
- GeometryComponent *component;
- std::string attribute_name;
- blender::bke::WeakAnonymousAttributeID anonymous_attribute_id;
-
- GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
- GeometryComponent &component,
- const AttributeIDRef &attribute_id)
- : blender::GVArrayImpl_For_GSpan(data), component(&component)
- {
- if (attribute_id.is_named()) {
- this->attribute_name = attribute_id.name();
- }
- else {
- const AnonymousAttributeID *anonymous_id = &attribute_id.anonymous_id();
- BKE_anonymous_attribute_id_increment_weak(anonymous_id);
- this->anonymous_attribute_id = blender::bke::WeakAnonymousAttributeID{anonymous_id};
- }
- }
-
- ~GVMutableAttribute_For_OutputAttribute() override
- {
- type_->destruct_n(data_, size_);
- MEM_freeN(data_);
- }
-};
-
-static void save_output_attribute(OutputAttribute &output_attribute)
-{
- using namespace blender;
- using namespace blender::fn;
- using namespace blender::bke;
-
- GVMutableAttribute_For_OutputAttribute &varray =
- dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(
- *output_attribute.varray().get_implementation());
-
- GeometryComponent &component = *varray.component;
- AttributeIDRef attribute_id;
- if (!varray.attribute_name.empty()) {
- attribute_id = varray.attribute_name;
- }
- else {
- attribute_id = varray.anonymous_attribute_id.extract();
- }
- const AttributeDomain domain = output_attribute.domain();
- const CustomDataType data_type = output_attribute.custom_data_type();
- const CPPType &cpp_type = output_attribute.cpp_type();
-
- component.attribute_try_delete(attribute_id);
- if (!component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault())) {
- if (!varray.attribute_name.empty()) {
- CLOG_WARN(&LOG,
- "Could not create the '%s' attribute with type '%s'.",
- varray.attribute_name.c_str(),
- cpp_type.name().c_str());
- }
- return;
- }
- WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id);
- 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);
- }
- 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,
- const CustomDataType data_type,
- const bool ignore_old_values,
- const void *default_value)
-{
- using namespace blender;
- using namespace blender::fn;
- using namespace blender::bke;
-
- if (!attribute_id) {
- return {};
- }
-
- const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
- const DataTypeConversions &conversions = get_implicit_type_conversions();
-
- if (component.attribute_is_builtin(attribute_id)) {
- const StringRef attribute_name = attribute_id.name();
- WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
- if (!attribute) {
- if (default_value) {
- const int64_t domain_num = component.attribute_domain_num(domain);
- component.attribute_try_create_builtin(
- attribute_name,
- AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_num, default_value)));
- }
- else {
- component.attribute_try_create_builtin(attribute_name, AttributeInitDefault());
- }
- attribute = component.attribute_try_get_for_write(attribute_name);
- if (!attribute) {
- /* Builtin attribute does not exist and can't be created. */
- return {};
- }
- }
- if (attribute.domain != domain) {
- /* Builtin attribute is on different domain. */
- return {};
- }
- GVMutableArray varray = std::move(attribute.varray);
- if (varray.type() == *cpp_type) {
- /* Builtin attribute matches exactly. */
- 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,
- get_simple_output_attribute_save_method(attribute),
- ignore_old_values);
- }
-
- const int domain_num = component.attribute_domain_num(domain);
-
- WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id);
- if (!attribute) {
- if (default_value) {
- component.attribute_try_create(
- attribute_id,
- domain,
- data_type,
- AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_num, default_value)));
- }
- else {
- component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault());
- }
-
- attribute = component.attribute_try_get_for_write(attribute_id);
- if (!attribute) {
- /* Can't create the attribute. */
- return {};
- }
- }
- if (attribute.domain == domain && attribute.varray.type() == *cpp_type) {
- /* Existing generic attribute matches exactly. */
-
- 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
- * attribute after processing is done. */
- void *data = MEM_mallocN_aligned(cpp_type->size() * domain_num, cpp_type->alignment(), __func__);
- if (ignore_old_values) {
- /* This does nothing for trivially constructible types, but is necessary for correctness. */
- cpp_type->default_construct_n(data, domain);
- }
- else {
- /* Fill the temporary array with values from the existing attribute. */
- GVArray old_varray = component.attribute_get_for_read(
- attribute_id, domain, data_type, default_value);
- old_varray.materialize_to_uninitialized(IndexRange(domain_num), data);
- }
- GVMutableArray varray = GVMutableArray::For<GVMutableAttribute_For_OutputAttribute>(
- GMutableSpan{*cpp_type, data, domain_num}, component, attribute_id);
-
- return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
-}
-
-OutputAttribute GeometryComponent::attribute_try_get_for_output(const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value)
-{
- return create_output_attribute(*this, attribute_id, domain, data_type, false, default_value);
-}
-
-OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
- const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type)
-{
- return create_output_attribute(*this, attribute_id, domain, data_type, true, nullptr);
-}
-
-namespace blender::bke {
-
GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context,
IndexMask mask,
ResourceScope &UNUSED(scope)) const
@@ -1374,18 +787,21 @@ GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &conte
if (const GeometryComponentFieldContext *geometry_context =
dynamic_cast<const GeometryComponentFieldContext *>(&context)) {
const GeometryComponent &component = geometry_context->geometry_component();
- const AttributeDomain domain = geometry_context->domain();
+ const eAttrDomain domain = geometry_context->domain();
return this->get_varray_for_context(component, domain, mask);
}
return {};
}
GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain 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);
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ if (auto attributes = component.attributes()) {
+ return attributes->lookup(name_, domain, data_type);
+ }
+ return {};
}
std::string AttributeFieldInput::socket_inspection_name() const
@@ -1408,7 +824,7 @@ bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
-static StringRef get_random_id_attribute_name(const AttributeDomain domain)
+static StringRef get_random_id_attribute_name(const eAttrDomain domain)
{
switch (domain) {
case ATTR_DOMAIN_POINT:
@@ -1420,15 +836,15 @@ static StringRef get_random_id_attribute_name(const AttributeDomain domain)
}
GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain 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_num(domain));
- return attribute;
+ if (auto attributes = component.attributes()) {
+ if (GVArray attribute = attributes->lookup(name, domain, CD_PROP_INT32)) {
+ return attribute;
+ }
}
/* Use the index as the fallback if no random ID attribute exists. */
@@ -1453,11 +869,11 @@ bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
}
GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain 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);
+ const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_);
+ return component.attributes()->lookup(anonymous_id_.get(), domain, data_type);
}
std::string AnonymousAttributeFieldInput::socket_inspection_name() const
@@ -1481,6 +897,151 @@ bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const
return false;
}
+GVArray AttributeAccessor::lookup(const AttributeIDRef &attribute_id,
+ const std::optional<eAttrDomain> domain,
+ const std::optional<eCustomDataType> data_type) const
+{
+ GAttributeReader attribute = this->lookup(attribute_id);
+ if (!attribute) {
+ return {};
+ }
+ GVArray varray = std::move(attribute.varray);
+ if (domain.has_value()) {
+ if (attribute.domain != domain) {
+ varray = this->adapt_domain(varray, attribute.domain, *domain);
+ if (!varray) {
+ return {};
+ }
+ }
+ }
+ if (data_type.has_value()) {
+ const CPPType &type = *custom_data_type_to_cpp_type(*data_type);
+ if (varray.type() != type) {
+ varray = try_adapt_data_type(std::move(varray), type);
+ if (!varray) {
+ return {};
+ }
+ }
+ }
+ return varray;
+}
+
+GVArray AttributeAccessor::lookup_or_default(const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const void *default_value) const
+{
+ GVArray varray = this->lookup(attribute_id, domain, data_type);
+ if (varray) {
+ return varray;
+ }
+ const CPPType &type = *custom_data_type_to_cpp_type(data_type);
+ const int64_t domain_size = this->domain_size(domain);
+ if (default_value == nullptr) {
+ return GVArray::ForSingleRef(type, domain_size, type.default_value());
+ }
+ return GVArray::ForSingle(type, domain_size, default_value);
+}
+
+Set<AttributeIDRef> AttributeAccessor::all_ids() const
+{
+ Set<AttributeIDRef> ids;
+ this->for_all(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData & /* meta_data */) {
+ ids.add(attribute_id);
+ return true;
+ });
+ return ids;
+}
+
+void MutableAttributeAccessor::remove_anonymous()
+{
+ Vector<const AnonymousAttributeID *> anonymous_ids;
+ for (const AttributeIDRef &id : this->all_ids()) {
+ if (id.is_anonymous()) {
+ anonymous_ids.append(&id.anonymous_id());
+ }
+ }
+
+ while (!anonymous_ids.is_empty()) {
+ this->remove(anonymous_ids.pop_last());
+ }
+}
+
+GAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer)
+{
+ std::optional<AttributeMetaData> meta_data = this->lookup_meta_data(attribute_id);
+ if (meta_data.has_value()) {
+ if (meta_data->domain == domain && meta_data->data_type == data_type) {
+ return this->lookup_for_write(attribute_id);
+ }
+ return {};
+ }
+ if (this->add(attribute_id, domain, data_type, initializer)) {
+ return this->lookup_for_write(attribute_id);
+ }
+ return {};
+}
+
+GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_span(
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer)
+{
+ GAttributeWriter attribute = this->lookup_or_add_for_write(
+ attribute_id, domain, data_type, initializer);
+ if (attribute) {
+ return GSpanAttributeWriter{std::move(attribute), true};
+ }
+ return {};
+}
+
+GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span(
+ const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type)
+{
+ GAttributeWriter attribute = this->lookup_or_add_for_write(attribute_id, domain, data_type);
+ if (attribute) {
+ return GSpanAttributeWriter{std::move(attribute), false};
+ }
+ return {};
+}
+
+Vector<AttributeTransferData> retrieve_attributes_for_transfer(
+ const bke::AttributeAccessor &src_attributes,
+ bke::MutableAttributeAccessor &dst_attributes,
+ const eAttrDomainMask domain_mask,
+ const Set<std::string> &skip)
+{
+ Vector<AttributeTransferData> attributes;
+ src_attributes.for_all(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
+ if (!(ATTR_DOMAIN_AS_MASK(meta_data.domain) & domain_mask)) {
+ return true;
+ }
+ if (id.is_named() && skip.contains(id.name())) {
+ return true;
+ }
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ GVArray src = src_attributes.lookup(id, meta_data.domain);
+ BLI_assert(src);
+ bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
+ id, meta_data.domain, meta_data.data_type);
+ BLI_assert(dst);
+ attributes.append({std::move(src), meta_data, std::move(dst)});
+
+ return true;
+ });
+ return attributes;
+}
+
} // namespace blender::bke
/** \} */
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index f0f47cb7a11..17432fa2726 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -15,12 +15,14 @@ namespace blender::bke {
* components in a generic way.
*/
struct CustomDataAccessInfo {
- using CustomDataGetter = CustomData *(*)(GeometryComponent &component);
- using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component);
- using UpdateCustomDataPointers = void (*)(GeometryComponent &component);
+ using CustomDataGetter = CustomData *(*)(void *owner);
+ using ConstCustomDataGetter = const CustomData *(*)(const void *owner);
+ using GetElementNum = int (*)(const void *owner);
+ using UpdateCustomDataPointers = void (*)(void *owner);
CustomDataGetter get_custom_data;
ConstCustomDataGetter get_const_custom_data;
+ GetElementNum get_element_num;
UpdateCustomDataPointers update_custom_data_pointers;
};
@@ -47,16 +49,16 @@ class BuiltinAttributeProvider {
protected:
const std::string name_;
- const AttributeDomain domain_;
- const CustomDataType data_type_;
+ const eAttrDomain domain_;
+ const eCustomDataType data_type_;
const CreatableEnum createable_;
const WritableEnum writable_;
const DeletableEnum deletable_;
public:
BuiltinAttributeProvider(std::string name,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const CreatableEnum createable,
const WritableEnum writable,
const DeletableEnum deletable)
@@ -69,24 +71,23 @@ class BuiltinAttributeProvider {
{
}
- 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;
- virtual bool exists(const GeometryComponent &component) const = 0;
+ virtual GVArray try_get_for_read(const void *owner) const = 0;
+ virtual GAttributeWriter try_get_for_write(void *owner) const = 0;
+ virtual bool try_delete(void *owner) const = 0;
+ virtual bool try_create(void *onwer, const AttributeInit &initializer) const = 0;
+ virtual bool exists(const void *owner) const = 0;
StringRefNull name() const
{
return name_;
}
- AttributeDomain domain() const
+ eAttrDomain domain() const
{
return domain_;
}
- CustomDataType data_type() const
+ eCustomDataType data_type() const
{
return data_type_;
}
@@ -98,25 +99,25 @@ class BuiltinAttributeProvider {
*/
class DynamicAttributesProvider {
public:
- virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const = 0;
- virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const = 0;
- virtual bool try_delete(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const = 0;
- virtual bool try_create(GeometryComponent &UNUSED(component),
- const AttributeIDRef &UNUSED(attribute_id),
- const AttributeDomain UNUSED(domain),
- const CustomDataType UNUSED(data_type),
- const AttributeInit &UNUSED(initializer)) const
+ virtual GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const = 0;
+ virtual GAttributeWriter try_get_for_write(void *owner,
+ const AttributeIDRef &attribute_id) const = 0;
+ virtual bool try_delete(void *owner, const AttributeIDRef &attribute_id) const = 0;
+ virtual bool try_create(void *owner,
+ const AttributeIDRef &attribute_id,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
+ const AttributeInit &initializer) const
{
+ UNUSED_VARS(owner, attribute_id, domain, data_type, initializer);
/* Some providers should not create new attributes. */
return false;
};
- virtual bool foreach_attribute(const GeometryComponent &component,
+ virtual bool foreach_attribute(const void *owner,
const AttributeForeachCallback callback) const = 0;
- virtual void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const = 0;
+ virtual void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const = 0;
};
/**
@@ -128,40 +129,38 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL |
CD_MASK_PROP_INT8 | CD_MASK_PROP_BYTE_COLOR;
- const AttributeDomain domain_;
+ const eAttrDomain domain_;
const CustomDataAccessInfo custom_data_access_;
public:
- CustomDataAttributeProvider(const AttributeDomain domain,
+ CustomDataAttributeProvider(const eAttrDomain domain,
const CustomDataAccessInfo custom_data_access)
: domain_(domain), custom_data_access_(custom_data_access)
{
}
- ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final;
+ GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const final;
- WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final;
+ GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final;
- bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final;
+ bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final;
- bool try_create(GeometryComponent &component,
+ bool try_create(void *owner,
const AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type,
+ eAttrDomain domain,
+ const eCustomDataType data_type,
const AttributeInit &initializer) const final;
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final;
+ bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final;
- void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
+ void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
{
callback(domain_);
}
private:
- bool type_is_supported(CustomDataType data_type) const
+ bool type_is_supported(eCustomDataType data_type) const
{
return ((1ULL << data_type) & supported_types_mask) != 0;
}
@@ -174,17 +173,17 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
private:
using AsReadAttribute = GVArray (*)(const void *data, int domain_num);
using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num);
- const AttributeDomain domain_;
- const CustomDataType attribute_type_;
- const CustomDataType stored_type_;
+ const eAttrDomain domain_;
+ const eCustomDataType attribute_type_;
+ const eCustomDataType stored_type_;
const CustomDataAccessInfo custom_data_access_;
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
public:
- NamedLegacyCustomDataProvider(const AttributeDomain domain,
- const CustomDataType attribute_type,
- const CustomDataType stored_type,
+ NamedLegacyCustomDataProvider(const eAttrDomain domain,
+ const eCustomDataType attribute_type,
+ const eCustomDataType stored_type,
const CustomDataAccessInfo custom_data_access,
const AsReadAttribute as_read_attribute,
const AsWriteAttribute as_write_attribute)
@@ -197,14 +196,12 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
{
}
- ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final;
- WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final;
- bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final;
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final;
- void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final;
+ GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const final;
+ GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final;
+ bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final;
+ bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final;
+ void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final;
};
template<typename T> GVArray make_array_read_attribute(const void *data, const int domain_num)
@@ -226,11 +223,11 @@ template<typename T> GVMutableArray make_array_write_attribute(void *data, const
* if the stored type is the same as the attribute type.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = GVArray (*)(const void *data, int domain_num);
- using AsWriteAttribute = GVMutableArray (*)(void *data, int domain_num);
- using UpdateOnRead = void (*)(const GeometryComponent &component);
- using UpdateOnWrite = void (*)(GeometryComponent &component);
- const CustomDataType stored_type_;
+ using AsReadAttribute = GVArray (*)(const void *data, int element_num);
+ using AsWriteAttribute = GVMutableArray (*)(void *data, int element_num);
+ using UpdateOnRead = void (*)(const void *owner);
+ using UpdateOnWrite = void (*)(void *owner);
+ const eCustomDataType stored_type_;
const CustomDataAccessInfo custom_data_access_;
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
@@ -239,9 +236,9 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
public:
BuiltinCustomDataLayerProvider(std::string attribute_name,
- const AttributeDomain domain,
- const CustomDataType attribute_type,
- const CustomDataType stored_type,
+ const eAttrDomain domain,
+ const eCustomDataType attribute_type,
+ const eCustomDataType stored_type,
const CreatableEnum creatable,
const WritableEnum writable,
const DeletableEnum deletable,
@@ -260,11 +257,11 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
{
}
- 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;
+ GVArray try_get_for_read(const void *owner) const final;
+ GAttributeWriter try_get_for_write(void *owner) const final;
+ bool try_delete(void *owner) const final;
+ bool try_create(void *owner, const AttributeInit &initializer) const final;
+ bool exists(const void *owner) const final;
};
/**
@@ -288,7 +285,7 @@ class ComponentAttributeProviders {
/**
* All the domains that are supported by at least one of the providers above.
*/
- VectorSet<AttributeDomain> supported_domains_;
+ VectorSet<eAttrDomain> supported_domains_;
public:
ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers,
@@ -301,7 +298,7 @@ class ComponentAttributeProviders {
supported_domains_.add(provider->domain());
}
for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) {
- provider->foreach_domain([&](AttributeDomain domain) { supported_domains_.add(domain); });
+ provider->foreach_domain([&](eAttrDomain domain) { supported_domains_.add(domain); });
}
}
@@ -315,10 +312,189 @@ class ComponentAttributeProviders {
return dynamic_attribute_providers_;
}
- Span<AttributeDomain> supported_domains() const
+ Span<eAttrDomain> supported_domains() const
{
return supported_domains_;
}
};
+namespace attribute_accessor_functions {
+
+template<const ComponentAttributeProviders &providers>
+inline bool is_builtin(const void *UNUSED(owner), const AttributeIDRef &attribute_id)
+{
+ if (!attribute_id.is_named()) {
+ return false;
+ }
+ const StringRef name = attribute_id.name();
+ return providers.builtin_attribute_providers().contains_as(name);
+}
+
+template<const ComponentAttributeProviders &providers>
+inline GAttributeReader lookup(const void *owner, const AttributeIDRef &attribute_id)
+{
+ if (attribute_id.is_named()) {
+ const StringRef name = attribute_id.name();
+ if (const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) {
+ return {provider->try_get_for_read(owner), provider->domain()};
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ GAttributeReader attribute = provider->try_get_for_read(owner, attribute_id);
+ if (attribute) {
+ return attribute;
+ }
+ }
+ return {};
+}
+
+template<const ComponentAttributeProviders &providers>
+inline bool for_all(const void *owner,
+ FunctionRef<bool(const AttributeIDRef &, const AttributeMetaData &)> fn)
+{
+ Set<AttributeIDRef> handled_attribute_ids;
+ for (const BuiltinAttributeProvider *provider :
+ providers.builtin_attribute_providers().values()) {
+ if (provider->exists(owner)) {
+ AttributeMetaData meta_data{provider->domain(), provider->data_type()};
+ if (!fn(provider->name(), meta_data)) {
+ return false;
+ }
+ handled_attribute_ids.add_new(provider->name());
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ const bool continue_loop = provider->foreach_attribute(
+ owner, [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (handled_attribute_ids.add(attribute_id)) {
+ return fn(attribute_id, meta_data);
+ }
+ return true;
+ });
+ if (!continue_loop) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline bool contains(const void *owner, const blender::bke::AttributeIDRef &attribute_id)
+{
+ bool found = false;
+ for_all<providers>(
+ owner,
+ [&](const AttributeIDRef &other_attribute_id, const AttributeMetaData & /* meta_data */) {
+ if (attribute_id == other_attribute_id) {
+ found = true;
+ return false;
+ }
+ return true;
+ });
+ return found;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline std::optional<AttributeMetaData> lookup_meta_data(const void *owner,
+ const AttributeIDRef &attribute_id)
+{
+ std::optional<AttributeMetaData> meta_data;
+ for_all<providers>(
+ owner,
+ [&](const AttributeIDRef &other_attribute_id, const AttributeMetaData &other_meta_data) {
+ if (attribute_id == other_attribute_id) {
+ meta_data = other_meta_data;
+ return false;
+ }
+ return true;
+ });
+ return meta_data;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline GAttributeWriter lookup_for_write(void *owner, const AttributeIDRef &attribute_id)
+{
+ if (attribute_id.is_named()) {
+ const StringRef name = attribute_id.name();
+ if (const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) {
+ return provider->try_get_for_write(owner);
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ GAttributeWriter attribute = provider->try_get_for_write(owner, attribute_id);
+ if (attribute) {
+ return attribute;
+ }
+ }
+ return {};
+}
+
+template<const ComponentAttributeProviders &providers>
+inline bool remove(void *owner, const AttributeIDRef &attribute_id)
+{
+ if (attribute_id.is_named()) {
+ const StringRef name = attribute_id.name();
+ if (const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) {
+ return provider->try_delete(owner);
+ }
+ }
+ bool success = false;
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ success = provider->try_delete(owner, attribute_id) || success;
+ }
+ return success;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline bool add(void *owner,
+ const AttributeIDRef &attribute_id,
+ eAttrDomain domain,
+ eCustomDataType data_type,
+ const AttributeInit &initializer)
+{
+ if (contains<providers>(owner, attribute_id)) {
+ return false;
+ }
+ if (attribute_id.is_named()) {
+ const StringRef name = attribute_id.name();
+ if (const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(name, nullptr)) {
+ if (provider->domain() != domain) {
+ return false;
+ }
+ if (provider->data_type() != data_type) {
+ return false;
+ }
+ return provider->try_create(owner, initializer);
+ }
+ }
+ for (const DynamicAttributesProvider *provider : providers.dynamic_attribute_providers()) {
+ if (provider->try_create(owner, attribute_id, domain, data_type, initializer)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+template<const ComponentAttributeProviders &providers>
+inline AttributeAccessorFunctions accessor_functions_for_providers()
+{
+ return AttributeAccessorFunctions{contains<providers>,
+ lookup_meta_data<providers>,
+ nullptr,
+ nullptr,
+ is_builtin<providers>,
+ lookup<providers>,
+ nullptr,
+ for_all<providers>,
+ lookup_for_write<providers>,
+ remove<providers>,
+ add<providers>};
+}
+
+} // namespace attribute_accessor_functions
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.cc
index 083d5af063a..99733c8edb3 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.cc
@@ -68,12 +68,12 @@ static void brush_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
BKE_previewimg_id_copy(&brush_dst->id, &brush_src->id);
}
else {
- brush_dst->preview = NULL;
+ brush_dst->preview = nullptr;
}
brush_dst->curve = BKE_curvemapping_copy(brush_src->curve);
- if (brush_src->gpencil_settings != NULL) {
- brush_dst->gpencil_settings = MEM_dupallocN(brush_src->gpencil_settings);
+ if (brush_src->gpencil_settings != nullptr) {
+ brush_dst->gpencil_settings = MEM_cnew(__func__, *(brush_src->gpencil_settings));
brush_dst->gpencil_settings->curve_sensitivity = BKE_curvemapping_copy(
brush_src->gpencil_settings->curve_sensitivity);
brush_dst->gpencil_settings->curve_strength = BKE_curvemapping_copy(
@@ -94,8 +94,8 @@ static void brush_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
brush_dst->gpencil_settings->curve_rand_value = BKE_curvemapping_copy(
brush_src->gpencil_settings->curve_rand_value);
}
- if (brush_src->curves_sculpt_settings != NULL) {
- brush_dst->curves_sculpt_settings = MEM_dupallocN(brush_src->curves_sculpt_settings);
+ if (brush_src->curves_sculpt_settings != nullptr) {
+ brush_dst->curves_sculpt_settings = MEM_cnew(__func__, *(brush_src->curves_sculpt_settings));
}
/* enable fake user by default */
@@ -110,7 +110,7 @@ static void brush_free_data(ID *id)
}
BKE_curvemapping_free(brush->curve);
- if (brush->gpencil_settings != NULL) {
+ if (brush->gpencil_settings != nullptr) {
BKE_curvemapping_free(brush->gpencil_settings->curve_sensitivity);
BKE_curvemapping_free(brush->gpencil_settings->curve_strength);
BKE_curvemapping_free(brush->gpencil_settings->curve_jitter);
@@ -124,7 +124,7 @@ static void brush_free_data(ID *id)
MEM_SAFE_FREE(brush->gpencil_settings);
}
- if (brush->curves_sculpt_settings != NULL) {
+ if (brush->curves_sculpt_settings != nullptr) {
MEM_freeN(brush->curves_sculpt_settings);
}
@@ -153,7 +153,7 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
/* NOTE: assert below ensures that the comment above is valid, and that exception is
* acceptable for the time being. */
BKE_lib_id_make_local(bmain, &brush->clone.image->id, 0);
- BLI_assert(!ID_IS_LINKED(brush->clone.image) && brush->clone.image->id.newid == NULL);
+ BLI_assert(!ID_IS_LINKED(brush->clone.image) && brush->clone.image->id.newid == nullptr);
}
if (force_local) {
@@ -268,7 +268,7 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id)
/* grease pencil */
BLO_read_data_address(reader, &brush->gpencil_settings);
- if (brush->gpencil_settings != NULL) {
+ if (brush->gpencil_settings != nullptr) {
BLO_read_data_address(reader, &brush->gpencil_settings->curve_sensitivity);
BLO_read_data_address(reader, &brush->gpencil_settings->curve_strength);
BLO_read_data_address(reader, &brush->gpencil_settings->curve_jitter);
@@ -319,8 +319,8 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &brush->curves_sculpt_settings);
- brush->preview = NULL;
- brush->icon_imbuf = NULL;
+ brush->preview = nullptr;
+ brush->icon_imbuf = nullptr;
}
static void brush_blend_read_lib(BlendLibReader *reader, ID *id)
@@ -335,7 +335,7 @@ static void brush_blend_read_lib(BlendLibReader *reader, ID *id)
BLO_read_id_address(reader, brush->id.lib, &brush->paint_curve);
/* link default grease pencil palette */
- if (brush->gpencil_settings != NULL) {
+ if (brush->gpencil_settings != nullptr) {
if (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED) {
BLO_read_id_address(reader, brush->id.lib, &brush->gpencil_settings->material);
@@ -344,7 +344,7 @@ static void brush_blend_read_lib(BlendLibReader *reader, ID *id)
}
}
else {
- brush->gpencil_settings->material = NULL;
+ brush->gpencil_settings->material = nullptr;
}
}
}
@@ -356,20 +356,20 @@ static void brush_blend_read_expand(BlendExpander *expander, ID *id)
BLO_expand(expander, brush->mask_mtex.tex);
BLO_expand(expander, brush->clone.image);
BLO_expand(expander, brush->paint_curve);
- if (brush->gpencil_settings != NULL) {
+ if (brush->gpencil_settings != nullptr) {
BLO_expand(expander, brush->gpencil_settings->material);
}
}
static int brush_undo_preserve_cb(LibraryIDLinkCallbackData *cb_data)
{
- BlendLibReader *reader = cb_data->user_data;
+ BlendLibReader *reader = (BlendLibReader *)cb_data->user_data;
ID *id_old = *cb_data->id_pointer;
/* Old data has not been remapped to new values of the pointers, if we want to keep the old
* pointer here we need its new address. */
- ID *id_old_new = id_old != NULL ? BLO_read_get_new_id_address(reader, id_old->lib, id_old) :
- NULL;
- BLI_assert(id_old_new == NULL || ELEM(id_old, id_old_new, id_old_new->orig_id));
+ ID *id_old_new = id_old != nullptr ? BLO_read_get_new_id_address(reader, id_old->lib, id_old) :
+ nullptr;
+ BLI_assert(id_old_new == nullptr || ELEM(id_old, id_old_new, id_old_new->orig_id));
if (cb_data->cb_flag & IDWALK_CB_USER) {
id_us_plus_no_lib(id_old_new);
id_us_min(id_old);
@@ -381,11 +381,11 @@ static int brush_undo_preserve_cb(LibraryIDLinkCallbackData *cb_data)
static void brush_undo_preserve(BlendLibReader *reader, ID *id_new, ID *id_old)
{
/* Whole Brush is preserved across undo-steps. */
- BKE_lib_id_swap(NULL, id_new, id_old);
+ BKE_lib_id_swap(nullptr, id_new, id_old);
/* `id_new` now has content from `id_old`, we need to ensure those old ID pointers are valid.
* NOTE: Since we want to re-use all old pointers here, code is much simpler than for Scene. */
- BKE_library_foreach_ID_link(NULL, id_new, brush_undo_preserve_cb, reader, IDWALK_NOP);
+ BKE_library_foreach_ID_link(nullptr, id_new, brush_undo_preserve_cb, reader, IDWALK_NOP);
/* NOTE: We do not swap IDProperties, as dealing with potential ID pointers in those would be
* fairly delicate. */
@@ -393,33 +393,33 @@ static void brush_undo_preserve(BlendLibReader *reader, ID *id_new, ID *id_old)
}
IDTypeInfo IDType_ID_BR = {
- .id_code = ID_BR,
- .id_filter = FILTER_ID_BR,
- .main_listbase_index = INDEX_ID_BR,
- .struct_size = sizeof(Brush),
- .name = "Brush",
- .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,
- .free_data = brush_free_data,
- .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,
- .blend_read_data = brush_blend_read_data,
- .blend_read_lib = brush_blend_read_lib,
- .blend_read_expand = brush_blend_read_expand,
-
- .blend_read_undo_preserve = brush_undo_preserve,
-
- .lib_override_apply_post = NULL,
+ /* id_code */ ID_BR,
+ /* id_filter */ FILTER_ID_BR,
+ /* main_listbase_index */ INDEX_ID_BR,
+ /* struct_size */ sizeof(Brush),
+ /* name */ "Brush",
+ /* name_plural */ "brushes",
+ /* translation_context */ BLT_I18NCONTEXT_ID_BRUSH,
+ /* flags */ IDTYPE_FLAGS_NO_ANIMDATA,
+ /* asset_type_info */ nullptr,
+
+ /* init_data */ brush_init_data,
+ /* copy_data */ brush_copy_data,
+ /* free_data */ brush_free_data,
+ /* make_local */ brush_make_local,
+ /* foreach_id */ brush_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ brush_foreach_path,
+ /* owner_get */ nullptr,
+
+ /* blend_write */ brush_blend_write,
+ /* blend_read_data */ brush_blend_read_data,
+ /* blend_read_lib */ brush_blend_read_lib,
+ /* blend_read_expand */ brush_blend_read_expand,
+
+ /* blend_read_undo_preserve */ brush_undo_preserve,
+
+ /* lib_override_apply_post */ nullptr,
};
static RNG *brush_rng;
@@ -432,11 +432,11 @@ void BKE_brush_system_init(void)
void BKE_brush_system_exit(void)
{
- if (brush_rng == NULL) {
+ if (brush_rng == nullptr) {
return;
}
BLI_rng_free(brush_rng);
- brush_rng = NULL;
+ brush_rng = nullptr;
}
static void brush_defaults(Brush *brush)
@@ -444,7 +444,8 @@ static void brush_defaults(Brush *brush)
const Brush *brush_def = DNA_struct_default_get(Brush);
-#define FROM_DEFAULT(member) memcpy(&brush->member, &brush_def->member, sizeof(brush->member))
+#define FROM_DEFAULT(member) \
+ memcpy((void *)&brush->member, (void *)&brush_def->member, sizeof(brush->member))
#define FROM_DEFAULT_PTR(member) memcpy(brush->member, brush_def->member, sizeof(brush->member))
FROM_DEFAULT(blend);
@@ -494,9 +495,7 @@ static void brush_defaults(Brush *brush)
Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
{
- Brush *brush;
-
- brush = BKE_id_new(bmain, ID_BR, name);
+ Brush *brush = (Brush *)BKE_id_new(bmain, ID_BR, name);
brush->ob_mode = ob_mode;
@@ -509,8 +508,8 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
void BKE_brush_init_gpencil_settings(Brush *brush)
{
- if (brush->gpencil_settings == NULL) {
- brush->gpencil_settings = MEM_callocN(sizeof(BrushGpencilSettings), "BrushGpencilSettings");
+ if (brush->gpencil_settings == nullptr) {
+ brush->gpencil_settings = MEM_cnew<BrushGpencilSettings>("BrushGpencilSettings");
}
brush->gpencil_settings->draw_smoothlvl = 1;
@@ -536,7 +535,7 @@ void BKE_brush_init_gpencil_settings(Brush *brush)
Brush *BKE_brush_add_gpencil(Main *bmain, ToolSettings *ts, const char *name, eObjectMode mode)
{
- Paint *paint = NULL;
+ Paint *paint = nullptr;
Brush *brush;
switch (mode) {
case OB_MODE_PAINT_GPENCIL: {
@@ -588,15 +587,15 @@ bool BKE_brush_delete(Main *bmain, Brush *brush)
return true;
}
-/* grease pencil cumapping->preset */
-typedef enum eGPCurveMappingPreset {
+/** Local grease pencil curve mapping preset. */
+using eGPCurveMappingPreset = enum eGPCurveMappingPreset {
GPCURVE_PRESET_PENCIL = 0,
GPCURVE_PRESET_INK = 1,
GPCURVE_PRESET_INKNOISE = 2,
GPCURVE_PRESET_MARKER = 3,
GPCURVE_PRESET_CHISEL_SENSIVITY = 4,
GPCURVE_PRESET_CHISEL_STRENGTH = 5,
-} eGPCurveMappingPreset;
+};
static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
{
@@ -605,7 +604,7 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset)
}
cuma->totpoint = tot;
- cuma->curve = MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
+ cuma->curve = (CurveMapPoint *)MEM_callocN(cuma->totpoint * sizeof(CurveMapPoint), __func__);
switch (preset) {
case GPCURVE_PRESET_PENCIL:
@@ -673,7 +672,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
#define SMOOTH_STROKE_FACTOR 0.9f
#define ACTIVE_SMOOTH 0.35f
- CurveMapping *custom_curve = NULL;
+ CurveMapping *custom_curve = nullptr;
/* Optionally assign a material preset. */
enum {
@@ -695,7 +694,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
brush->curve_preset = BRUSH_CURVE_SMOOTH;
- if (brush->gpencil_settings == NULL) {
+ if (brush->gpencil_settings == nullptr) {
return;
}
@@ -1266,8 +1265,8 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
* This material is required because the brush uses the material
* to define how the stroke is drawn. */
const char *ma_id = "Dots Stroke";
- Material *ma = BLI_findstring(&bmain->materials, ma_id, offsetof(ID, name) + 2);
- if (ma == NULL) {
+ Material *ma = (Material *)BLI_findstring(&bmain->materials, ma_id, offsetof(ID, name) + 2);
+ if (ma == nullptr) {
ma = BKE_gpencil_material_add(bmain, ma_id);
ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
BLI_assert(ma->id.us == 1);
@@ -1287,19 +1286,19 @@ static Brush *gpencil_brush_ensure(
Main *bmain, ToolSettings *ts, const char *brush_name, eObjectMode mode, bool *r_new)
{
*r_new = false;
- Brush *brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
+ Brush *brush = (Brush *)BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2);
/* If the brush exist, but the type is not GPencil or the mode is wrong, create a new one. */
- if ((brush != NULL) && ((brush->gpencil_settings == NULL) || (brush->ob_mode != mode))) {
- brush = NULL;
+ if ((brush != nullptr) && ((brush->gpencil_settings == nullptr) || (brush->ob_mode != mode))) {
+ brush = nullptr;
}
- if (brush == NULL) {
+ if (brush == nullptr) {
brush = BKE_brush_add_gpencil(bmain, ts, brush_name, mode);
*r_new = true;
}
- if (brush->gpencil_settings == NULL) {
+ if (brush->gpencil_settings == nullptr) {
BKE_brush_init_gpencil_settings(brush);
}
@@ -1399,7 +1398,7 @@ void BKE_brush_gpencil_paint_presets(Main *bmain, ToolSettings *ts, const bool r
}
/* Set default Draw brush. */
- if ((reset == false) && (brush_prev != NULL)) {
+ if ((reset == false) && (brush_prev != nullptr)) {
BKE_paint_brush_set(paint, brush_prev);
}
else {
@@ -1443,11 +1442,11 @@ void BKE_brush_gpencil_vertex_presets(Main *bmain, ToolSettings *ts, const bool
}
/* Set default Vertex brush. */
- if (reset || brush_prev == NULL) {
+ if (reset || brush_prev == nullptr) {
BKE_paint_brush_set(vertexpaint, deft_vertex);
}
else {
- if (brush_prev != NULL) {
+ if (brush_prev != nullptr) {
BKE_paint_brush_set(vertexpaint, brush_prev);
}
}
@@ -1517,11 +1516,11 @@ void BKE_brush_gpencil_sculpt_presets(Main *bmain, ToolSettings *ts, const bool
}
/* Set default brush. */
- if (reset || brush_prev == NULL) {
+ if (reset || brush_prev == nullptr) {
BKE_paint_brush_set(sculptpaint, deft_sculpt);
}
else {
- if (brush_prev != NULL) {
+ if (brush_prev != nullptr) {
BKE_paint_brush_set(sculptpaint, brush_prev);
}
}
@@ -1542,11 +1541,11 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool
deft_weight = brush; /* save default brush. */
/* Set default brush. */
- if (reset || brush_prev == NULL) {
+ if (reset || brush_prev == nullptr) {
BKE_paint_brush_set(weightpaint, deft_weight);
}
else {
- if (brush_prev != NULL) {
+ if (brush_prev != nullptr) {
BKE_paint_brush_set(weightpaint, brush_prev);
}
}
@@ -1554,32 +1553,31 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool
void BKE_brush_init_curves_sculpt_settings(Brush *brush)
{
- if (brush->curves_sculpt_settings == NULL) {
- brush->curves_sculpt_settings = MEM_callocN(sizeof(BrushCurvesSculptSettings), __func__);
+ if (brush->curves_sculpt_settings == nullptr) {
+ brush->curves_sculpt_settings = MEM_cnew<BrushCurvesSculptSettings>(__func__);
}
BrushCurvesSculptSettings *settings = brush->curves_sculpt_settings;
settings->add_amount = 1;
settings->points_per_curve = 8;
settings->minimum_length = 0.01f;
settings->curve_length = 0.3f;
+ settings->density_add_attempts = 100;
}
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
{
- Brush *brush;
-
- for (brush = bmain->brushes.first; brush; brush = brush->id.next) {
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
if (brush->ob_mode & ob_mode) {
return brush;
}
}
- return NULL;
+ return nullptr;
}
void BKE_brush_debug_print_state(Brush *br)
{
/* create a fake brush and set it to the defaults */
- Brush def = {{NULL}};
+ Brush def = {{nullptr}};
brush_defaults(&def);
#define BR_TEST(field, t) \
@@ -1943,8 +1941,8 @@ void BKE_brush_sculpt_reset(Brush *br)
void BKE_brush_curve_preset(Brush *b, eCurveMappingPreset preset)
{
- CurveMapping *cumap = NULL;
- CurveMap *cuma = NULL;
+ CurveMapping *cumap = nullptr;
+ CurveMap *cuma = nullptr;
if (!b->curve) {
b->curve = BKE_curvemapping_add(1, 0, 0, 1, 1);
@@ -2469,71 +2467,55 @@ float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len
}
/* TODO: should probably be unified with BrushPainter stuff? */
-unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_secondary)
+static bool brush_gen_texture(const Brush *br,
+ const int side,
+ const bool use_secondary,
+ float *rect)
{
- unsigned int *texcache = NULL;
- MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex;
- float intensity;
- float rgba_dummy[4];
- int ix, iy;
- int side = half_side * 2;
+ const MTex *mtex = (use_secondary) ? &br->mask_mtex : &br->mtex;
+ if (mtex->tex == nullptr) {
+ return false;
+ }
- if (mtex->tex) {
- float x, y, step = 2.0 / side, co[3];
+ const float step = 2.0 / side;
+ int ix, iy;
+ float x, y;
- texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
+ /* Do normalized canonical view coords for texture. */
+ for (y = -1.0, iy = 0; iy < side; iy++, y += step) {
+ for (x = -1.0, ix = 0; ix < side; ix++, x += step) {
+ const float co[3] = {x, y, 0.0f};
- /* do normalized canonical view coords for texture */
- for (y = -1.0, iy = 0; iy < side; iy++, y += step) {
- for (x = -1.0, ix = 0; ix < side; ix++, x += step) {
- co[0] = x;
- co[1] = y;
- co[2] = 0.0f;
+ float intensity;
+ float rgba_dummy[4];
+ RE_texture_evaluate(mtex, co, 0, nullptr, false, false, &intensity, rgba_dummy);
- /* This is copied from displace modifier code */
- /* TODO(sergey): brush are always caching with CM enabled for now. */
- RE_texture_evaluate(mtex, co, 0, NULL, false, false, &intensity, rgba_dummy);
- copy_v4_uchar((uchar *)&texcache[iy * side + ix], (char)(intensity * 255.0f));
- }
+ rect[iy * side + ix] = intensity;
}
}
- return texcache;
+ return true;
}
struct ImBuf *BKE_brush_gen_radial_control_imbuf(Brush *br, bool secondary, bool display_gradient)
{
- ImBuf *im = MEM_callocN(sizeof(ImBuf), "radial control texture");
- unsigned int *texcache;
+ ImBuf *im = MEM_cnew<ImBuf>("radial control texture");
int side = 512;
int half = side / 2;
- int i, j;
BKE_curvemapping_init(br->curve);
- texcache = BKE_brush_gen_texture_cache(br, half, secondary);
- im->rect_float = MEM_callocN(sizeof(float) * side * side, "radial control rect");
+ im->rect_float = (float *)MEM_callocN(sizeof(float) * side * side, "radial control rect");
im->x = im->y = side;
- if (display_gradient || texcache) {
- for (i = 0; i < side; i++) {
- for (j = 0; j < side; j++) {
- float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
- im->rect_float[i * side + j] = BKE_brush_curve_strength_clamped(br, magn, half);
- }
- }
- }
+ const bool have_texture = brush_gen_texture(br, side, secondary, im->rect_float);
- if (texcache) {
- /* Modulate curve with texture */
- for (i = 0; i < side; i++) {
- for (j = 0; j < side; j++) {
- const int col = texcache[i * side + j];
- im->rect_float[i * side + j] *= (((char *)&col)[0] + ((char *)&col)[1] +
- ((char *)&col)[2]) /
- 3.0f / 255.0f;
+ if (display_gradient || have_texture) {
+ for (int i = 0; i < side; i++) {
+ for (int j = 0; j < side; j++) {
+ float magn = sqrtf(pow2f(i - half) + pow2f(j - half));
+ im->rect_float[i * side + j] *= BKE_brush_curve_strength_clamped(br, magn, half);
}
}
- MEM_freeN(texcache);
}
return im;
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 35c2039634a..03dd5c89b70 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -19,6 +19,7 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BKE_attribute.hh"
#include "BKE_bvhutils.h"
#include "BKE_editmesh.h"
#include "BKE_mesh.h"
@@ -1430,13 +1431,17 @@ BVHTree *BKE_bvhtree_from_pointcloud_get(BVHTreeFromPointCloud *data,
return nullptr;
}
- for (int i = 0; i < pointcloud->totpoint; i++) {
- BLI_bvhtree_insert(tree, i, pointcloud->co[i], 1);
+ blender::bke::AttributeAccessor attributes = blender::bke::pointcloud_attributes(*pointcloud);
+ blender::VArraySpan<blender::float3> positions = attributes.lookup_or_default<blender::float3>(
+ "position", ATTR_DOMAIN_POINT, blender::float3(0));
+
+ for (const int i : positions.index_range()) {
+ BLI_bvhtree_insert(tree, i, positions[i], 1);
}
BLI_assert(BLI_bvhtree_get_len(tree) == pointcloud->totpoint);
bvhtree_balance(tree, false);
- data->coords = pointcloud->co;
+ data->coords = (const float(*)[3])positions.data();
data->tree = tree;
data->nearest_callback = nullptr;
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index b59e44aae8a..9aea3b2768f 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -25,6 +25,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_action.h"
#include "BKE_anim_data.h"
#include "BKE_camera.h"
#include "BKE_idtype.h"
@@ -66,14 +67,19 @@ static void camera_init_data(ID *id)
*
* \param flag: Copying options (see BKE_lib_id.h's LIB_ID_COPY_... flags for more).
*/
-static void camera_copy_data(Main *UNUSED(bmain),
- ID *id_dst,
- const ID *id_src,
- const int UNUSED(flag))
+static void camera_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
{
Camera *cam_dst = (Camera *)id_dst;
const Camera *cam_src = (const Camera *)id_src;
- BLI_duplicatelist(&cam_dst->bg_images, &cam_src->bg_images);
+
+ /* We never handle usercount here for own data. */
+ const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+
+ BLI_listbase_clear(&cam_dst->bg_images);
+ LISTBASE_FOREACH (CameraBGImage *, bgpic_src, &cam_src->bg_images) {
+ CameraBGImage *bgpic_dst = BKE_camera_background_image_copy(bgpic_src, flag_subdata);
+ BLI_addtail(&cam_dst->bg_images, bgpic_dst);
+ }
}
/** Free (or release) any data used by this camera (does not free the camera itself). */
@@ -125,6 +131,11 @@ static void camera_blend_read_data(BlendDataReader *reader, ID *id)
LISTBASE_FOREACH (CameraBGImage *, bgpic, &ca->bg_images) {
bgpic->iuser.scene = NULL;
+
+ /* If linking from a library, clear 'local' library override flag. */
+ if (ID_IS_LINKED(ca)) {
+ bgpic->flag &= ~CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL;
+ }
}
}
@@ -211,7 +222,16 @@ float BKE_camera_object_dof_distance(const Object *ob)
if (cam->dof.focus_object) {
float view_dir[3], dof_dir[3];
normalize_v3_v3(view_dir, ob->obmat[2]);
- sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof.focus_object->obmat[3]);
+ bPoseChannel *pchan = BKE_pose_channel_find_name(cam->dof.focus_object->pose,
+ cam->dof.focus_subtarget);
+ if (pchan) {
+ float posemat[4][4];
+ mul_m4_m4m4(posemat, cam->dof.focus_object->obmat, pchan->pose_mat);
+ sub_v3_v3v3(dof_dir, ob->obmat[3], posemat[3]);
+ }
+ else {
+ sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof.focus_object->obmat[3]);
+ }
return fabsf(dot_v3v3(view_dir, dof_dir));
}
return cam->dof.focus_distance;
@@ -518,7 +538,7 @@ void BKE_camera_view_frame_ex(const Scene *scene,
if (do_clip) {
/* Ensure the frame isn't behind the near clipping plane, T62814. */
- float fac = (camera->clip_start + 0.1f) / -r_vec[0][2];
+ float fac = ((camera->clip_start + 0.1f) / -r_vec[0][2]) * scale[2];
for (uint i = 0; i < 4; i++) {
if (camera->type == CAM_ORTHO) {
r_vec[i][2] *= fac;
@@ -549,6 +569,11 @@ void BKE_camera_view_frame(const Scene *scene, const Camera *camera, float r_vec
#define CAMERA_VIEWFRAME_NUM_PLANES 4
+#define Y_MIN 0
+#define Y_MAX 1
+#define Z_MIN 2
+#define Z_MAX 3
+
typedef struct CameraViewFrameData {
float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4]; /* 4 planes normalized */
float dist_vals[CAMERA_VIEWFRAME_NUM_PLANES]; /* distance (signed) */
@@ -612,15 +637,13 @@ static void camera_frame_fit_data_init(const Scene *scene,
invert_m4(camera_rotmat_transposed_inversed);
/* Extract frustum planes from projection matrix. */
- planes_from_projmat(
- params->winmat,
- /* left right top bottom near far */
- data->plane_tx[2],
- data->plane_tx[0],
- data->plane_tx[3],
- data->plane_tx[1],
- NULL,
- NULL);
+ planes_from_projmat(params->winmat,
+ data->plane_tx[Y_MIN],
+ data->plane_tx[Y_MAX],
+ data->plane_tx[Z_MIN],
+ data->plane_tx[Z_MAX],
+ NULL,
+ NULL);
/* Rotate planes and get normals from them */
for (uint i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
@@ -660,21 +683,21 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
const float *cam_axis_y = data->camera_rotmat[1];
const float *cam_axis_z = data->camera_rotmat[2];
const float *dists = data->dist_vals;
- float scale_diff;
+ const float dist_span_y = dists[Y_MIN] + dists[Y_MAX];
+ const float dist_span_z = dists[Z_MIN] + dists[Z_MAX];
+ const float dist_mid_y = (dists[Y_MIN] - dists[Y_MAX]) * 0.5f;
+ const float dist_mid_z = (dists[Z_MIN] - dists[Z_MAX]) * 0.5f;
+ const float scale_diff = (dist_span_z < dist_span_y) ?
+ (dist_span_z * (BLI_rctf_size_x(&params->viewplane) /
+ BLI_rctf_size_y(&params->viewplane))) :
+ (dist_span_y * (BLI_rctf_size_y(&params->viewplane) /
+ BLI_rctf_size_x(&params->viewplane)));
- if ((dists[0] + dists[2]) > (dists[1] + dists[3])) {
- scale_diff = (dists[1] + dists[3]) *
- (BLI_rctf_size_x(&params->viewplane) / BLI_rctf_size_y(&params->viewplane));
- }
- else {
- scale_diff = (dists[0] + dists[2]) *
- (BLI_rctf_size_y(&params->viewplane) / BLI_rctf_size_x(&params->viewplane));
- }
*r_scale = params->ortho_scale - scale_diff;
zero_v3(r_co);
- madd_v3_v3fl(r_co, cam_axis_x, (dists[2] - dists[0]) * 0.5f + params->shiftx * scale_diff);
- madd_v3_v3fl(r_co, cam_axis_y, (dists[1] - dists[3]) * 0.5f + params->shifty * scale_diff);
+ madd_v3_v3fl(r_co, cam_axis_x, dist_mid_y + (params->shiftx * scale_diff));
+ madd_v3_v3fl(r_co, cam_axis_y, dist_mid_z + (params->shifty * scale_diff));
madd_v3_v3fl(r_co, cam_axis_z, -(data->z_range[0] - 1.0f - params->clip_start));
}
else {
@@ -690,36 +713,37 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
plane_from_point_normal_v3(plane_tx[i], co, data->plane_tx[i]);
}
- if ((!isect_plane_plane_v3(plane_tx[0], plane_tx[2], plane_isect_1, plane_isect_1_no)) ||
- (!isect_plane_plane_v3(plane_tx[1], plane_tx[3], plane_isect_2, plane_isect_2_no))) {
+ if ((!isect_plane_plane_v3(
+ plane_tx[Y_MIN], plane_tx[Y_MAX], plane_isect_1, plane_isect_1_no)) ||
+ (!isect_plane_plane_v3(
+ plane_tx[Z_MIN], plane_tx[Z_MAX], plane_isect_2, plane_isect_2_no))) {
return false;
}
add_v3_v3v3(plane_isect_1_other, plane_isect_1, plane_isect_1_no);
add_v3_v3v3(plane_isect_2_other, plane_isect_2, plane_isect_2_no);
- if (isect_line_line_v3(plane_isect_1,
- plane_isect_1_other,
- plane_isect_2,
- plane_isect_2_other,
- plane_isect_pt_1,
- plane_isect_pt_2) == 0) {
+ if (!isect_line_line_v3(plane_isect_1,
+ plane_isect_1_other,
+ plane_isect_2,
+ plane_isect_2_other,
+ plane_isect_pt_1,
+ plane_isect_pt_2)) {
return false;
}
float cam_plane_no[3];
float plane_isect_delta[3];
- float plane_isect_delta_len;
- float shift_fac = BKE_camera_sensor_size(
- params->sensor_fit, params->sensor_x, params->sensor_y) /
- params->lens;
+ const float shift_fac = BKE_camera_sensor_size(
+ params->sensor_fit, params->sensor_x, params->sensor_y) /
+ params->lens;
/* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */
negate_v3_v3(cam_plane_no, data->camera_rotmat[2]);
sub_v3_v3v3(plane_isect_delta, plane_isect_pt_2, plane_isect_pt_1);
- plane_isect_delta_len = len_v3(plane_isect_delta);
+ const float plane_isect_delta_len = len_v3(plane_isect_delta);
if (dot_v3v3(plane_isect_delta, cam_plane_no) > 0.0f) {
copy_v3_v3(r_co, plane_isect_pt_1);
@@ -745,6 +769,11 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
return true;
}
+#undef Y_MIN
+#undef Y_MAX
+#undef Z_MIN
+#undef Z_MAX
+
bool BKE_camera_view_frame_fit_to_scene(Depsgraph *depsgraph,
const Scene *scene,
Object *camera_ob,
@@ -1119,13 +1148,31 @@ CameraBGImage *BKE_camera_background_image_new(Camera *cam)
bgpic->scale = 1.0f;
bgpic->alpha = 0.5f;
bgpic->iuser.flag |= IMA_ANIM_ALWAYS;
- bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED;
+ bgpic->flag |= CAM_BGIMG_FLAG_EXPANDED | CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL;
BLI_addtail(&cam->bg_images, bgpic);
return bgpic;
}
+CameraBGImage *BKE_camera_background_image_copy(CameraBGImage *bgpic_src, const int flag)
+{
+ CameraBGImage *bgpic_dst = MEM_dupallocN(bgpic_src);
+
+ bgpic_dst->next = bgpic_dst->prev = NULL;
+
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ id_us_plus((ID *)bgpic_dst->ima);
+ id_us_plus((ID *)bgpic_dst->clip);
+ }
+
+ if ((flag & LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG) == 0) {
+ bgpic_dst->flag |= CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL;
+ }
+
+ return bgpic_dst;
+}
+
void BKE_camera_background_image_remove(Camera *cam, CameraBGImage *bgpic)
{
BLI_remlink(&cam->bg_images, bgpic);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index ab9a27a3996..8622174231c 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -1171,7 +1171,7 @@ static Mesh *cloth_make_rest_mesh(ClothModifierData *clmd, Mesh *mesh)
for (unsigned i = 0; i < mesh->totvert; i++, verts++) {
copy_v3_v3(mvert[i].co, verts->xrest);
}
- BKE_mesh_normals_tag_dirty(new_mesh);
+ BKE_mesh_tag_coords_changed(new_mesh);
return new_mesh;
}
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 76c6dc1d5e7..b71bcef229a 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -996,9 +996,11 @@ static void collection_tag_update_parent_recursive(Main *bmain,
}
}
-static Collection *collection_parent_editable_find_recursive(Collection *collection)
+static Collection *collection_parent_editable_find_recursive(const ViewLayer *view_layer,
+ Collection *collection)
{
- if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) {
+ if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
+ (view_layer == NULL || BKE_view_layer_has_collection(view_layer, collection))) {
return collection;
}
@@ -1009,10 +1011,16 @@ static Collection *collection_parent_editable_find_recursive(Collection *collect
LISTBASE_FOREACH (CollectionParent *, collection_parent, &collection->parents) {
if (!ID_IS_LINKED(collection_parent->collection) &&
!ID_IS_OVERRIDE_LIBRARY(collection_parent->collection)) {
+ if (view_layer != NULL &&
+ !BKE_view_layer_has_collection(view_layer, collection_parent->collection)) {
+ /* In case this parent collection is not in given view_layer, there is no point in
+ * searching in its ancestors either, we can skip that whole parenting branch. */
+ continue;
+ }
return collection_parent->collection;
}
Collection *editable_collection = collection_parent_editable_find_recursive(
- collection_parent->collection);
+ view_layer, collection_parent->collection);
if (editable_collection != NULL) {
return editable_collection;
}
@@ -1110,11 +1118,23 @@ bool BKE_collection_object_add_notest(Main *bmain, Collection *collection, Objec
bool BKE_collection_object_add(Main *bmain, Collection *collection, Object *ob)
{
+ return BKE_collection_viewlayer_object_add(bmain, NULL, collection, ob);
+}
+
+bool BKE_collection_viewlayer_object_add(Main *bmain,
+ const ViewLayer *view_layer,
+ Collection *collection,
+ Object *ob)
+{
if (collection == NULL) {
return false;
}
- collection = collection_parent_editable_find_recursive(collection);
+ collection = collection_parent_editable_find_recursive(view_layer, collection);
+
+ if (collection == NULL) {
+ return false;
+ }
return BKE_collection_object_add_notest(bmain, collection, ob);
}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 35f2f94bc91..0534899a86c 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -116,7 +116,6 @@ void BKE_constraint_unique_name(bConstraint *con, ListBase *list)
/* ----------------- Evaluation Loop Preparation --------------- */
-/* package an object/bone for use in constraint evaluation */
bConstraintOb *BKE_constraints_make_evalob(
Depsgraph *depsgraph, Scene *scene, Object *ob, void *subdata, short datatype)
{
@@ -949,30 +948,9 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
} \
(void)0
-static void custom_space_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
+static bool is_custom_space_needed(bConstraint *con)
{
- func(con, (ID **)&con->space_object, false, userdata);
-}
-
-static int get_space_tar(bConstraint *con, ListBase *list)
-{
- if (!con || !list ||
- (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) {
- return 0;
- }
- bConstraintTarget *ct;
- SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, list);
- return 1;
-}
-
-static void flush_space_tar(bConstraint *con, ListBase *list, bool no_copy)
-{
- if (!con || !list ||
- (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) {
- return;
- }
- bConstraintTarget *ct = (bConstraintTarget *)list->last;
- SINGLETARGET_FLUSH_TARS(con, con->space_object, con->space_subtarget, ct, list, no_copy);
+ return con->ownspace == CONSTRAINT_SPACE_CUSTOM || con->tarspace == CONSTRAINT_SPACE_CUSTOM;
}
/* --------- ChildOf Constraint ------------ */
@@ -1161,8 +1139,6 @@ static void trackto_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int trackto_get_tars(bConstraint *con, ListBase *list)
@@ -1174,7 +1150,7 @@ static int trackto_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -1188,7 +1164,6 @@ static void trackto_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -1661,11 +1636,11 @@ static bConstraintTypeInfo CTI_LOCLIMIT = {
"Limit Location", /* name */
"bLocLimitConstraint", /* struct name */
NULL, /* free data */
- custom_space_id_looper, /* id looper */
+ NULL, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- get_space_tar, /* get constraint targets */
- flush_space_tar, /* flush constraint targets */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
NULL, /* get target matrix */
loclimit_evaluate, /* evaluate */
};
@@ -1742,11 +1717,11 @@ static bConstraintTypeInfo CTI_ROTLIMIT = {
"Limit Rotation", /* name */
"bRotLimitConstraint", /* struct name */
NULL, /* free data */
- custom_space_id_looper, /* id looper */
+ NULL, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- get_space_tar, /* get constraint targets */
- flush_space_tar, /* flush constraint targets */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
NULL, /* get target matrix */
rotlimit_evaluate, /* evaluate */
};
@@ -1809,11 +1784,11 @@ static bConstraintTypeInfo CTI_SIZELIMIT = {
"Limit Scale", /* name */
"bSizeLimitConstraint", /* struct name */
NULL, /* free data */
- custom_space_id_looper, /* id looper */
+ NULL, /* id looper */
NULL, /* copy data */
NULL, /* new data */
- get_space_tar, /* get constraint targets */
- flush_space_tar, /* flush constraint targets */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
NULL, /* get target matrix */
sizelimit_evaluate, /* evaluate */
};
@@ -1833,8 +1808,6 @@ static void loclike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int loclike_get_tars(bConstraint *con, ListBase *list)
@@ -1846,7 +1819,7 @@ static int loclike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -1860,7 +1833,6 @@ static void loclike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -1933,8 +1905,6 @@ static void rotlike_id_looper(bConstraint *con, ConstraintIDFunc func, void *use
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int rotlike_get_tars(bConstraint *con, ListBase *list)
@@ -1946,7 +1916,7 @@ static int rotlike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -1960,7 +1930,6 @@ static void rotlike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -2114,8 +2083,6 @@ static void sizelike_id_looper(bConstraint *con, ConstraintIDFunc func, void *us
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int sizelike_get_tars(bConstraint *con, ListBase *list)
@@ -2127,7 +2094,7 @@ static int sizelike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -2141,7 +2108,6 @@ static void sizelike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -2239,8 +2205,6 @@ static void translike_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int translike_get_tars(bConstraint *con, ListBase *list)
@@ -2252,7 +2216,7 @@ static int translike_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -2266,7 +2230,6 @@ static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -2400,11 +2363,11 @@ static bConstraintTypeInfo CTI_SAMEVOL = {
"Maintain Volume", /* name */
"bSameVolumeConstraint", /* struct name */
NULL, /* free data */
- custom_space_id_looper, /* id looper */
+ NULL, /* id looper */
NULL, /* copy data */
samevolume_new_data, /* new data */
- get_space_tar, /* get constraint targets */
- flush_space_tar, /* flush constraint targets */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
NULL, /* get target matrix */
samevolume_evaluate, /* evaluate */
};
@@ -2810,8 +2773,6 @@ static void actcon_id_looper(bConstraint *con, ConstraintIDFunc func, void *user
/* action */
func(con, (ID **)&data->act, true, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int actcon_get_tars(bConstraint *con, ListBase *list)
@@ -2823,7 +2784,7 @@ static int actcon_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -2837,7 +2798,6 @@ static void actcon_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -3338,8 +3298,6 @@ static void distlimit_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int distlimit_get_tars(bConstraint *con, ListBase *list)
@@ -3351,7 +3309,7 @@ static int distlimit_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -3365,7 +3323,6 @@ static void distlimit_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -3694,8 +3651,6 @@ static void minmax_id_looper(bConstraint *con, ConstraintIDFunc func, void *user
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int minmax_get_tars(bConstraint *con, ListBase *list)
@@ -3707,7 +3662,7 @@ static int minmax_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -3721,7 +3676,6 @@ static void minmax_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -4019,8 +3973,6 @@ static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *u
/* target only */
func(con, (ID **)&data->tar, false, userdata);
-
- custom_space_id_looper(con, func, userdata);
}
static int transform_get_tars(bConstraint *con, ListBase *list)
@@ -4032,7 +3984,7 @@ static int transform_get_tars(bConstraint *con, ListBase *list)
/* standard target-getting macro for single-target constraints */
SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list);
- return 1 + get_space_tar(con, list);
+ return 1;
}
return 0;
@@ -4046,7 +3998,6 @@ static void transform_flush_tars(bConstraint *con, ListBase *list, bool no_copy)
/* the following macro is used for all standard single-target constraints */
SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, no_copy);
- flush_space_tar(con, list, no_copy);
}
}
@@ -5582,6 +5533,19 @@ static void con_unlink_refs_cb(bConstraint *UNUSED(con),
}
}
+/** Helper function to invoke the id_looper callback, including custom space. */
+static void con_invoke_id_looper(const bConstraintTypeInfo *cti,
+ bConstraint *con,
+ ConstraintIDFunc func,
+ void *userdata)
+{
+ if (cti->id_looper) {
+ cti->id_looper(con, func, userdata);
+ }
+
+ func(con, (ID **)&con->space_object, false, userdata);
+}
+
void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
{
if (con->data) {
@@ -5594,8 +5558,8 @@ void BKE_constraint_free_data_ex(bConstraint *con, bool do_id_user)
}
/* unlink the referenced resources it uses */
- if (do_id_user && cti->id_looper) {
- cti->id_looper(con, con_unlink_refs_cb, NULL);
+ if (do_id_user) {
+ con_invoke_id_looper(cti, con, con_unlink_refs_cb, NULL);
}
}
@@ -5880,9 +5844,12 @@ static bConstraint *add_new_constraint(Object *ob,
return con;
}
-bool BKE_constraint_target_uses_bbone(struct bConstraint *con,
- struct bConstraintTarget *UNUSED(ct))
+bool BKE_constraint_target_uses_bbone(struct bConstraint *con, struct bConstraintTarget *ct)
{
+ if (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE) {
+ return false;
+ }
+
return (con->flag & CONSTRAINT_BBONE_SHAPE) || (con->type == CONSTRAINT_TYPE_ARMATURE);
}
@@ -5913,9 +5880,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (cti) {
- if (cti->id_looper) {
- cti->id_looper(con, func, userdata);
- }
+ con_invoke_id_looper(cti, con, func, userdata);
}
}
}
@@ -5967,16 +5932,14 @@ static void constraint_copy_data_ex(bConstraint *dst,
}
/* Fix usercounts for all referenced data that need it. */
- if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
- cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
+ if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+ con_invoke_id_looper(cti, dst, con_fix_copied_refs_cb, NULL);
}
/* for proxies we don't want to make extern */
if (do_extern) {
/* go over used ID-links for this constraint to ensure that they are valid for proxies */
- if (cti->id_looper) {
- cti->id_looper(dst, con_extern_cb, NULL);
- }
+ con_invoke_id_looper(cti, dst, con_extern_cb, NULL);
}
}
}
@@ -6191,6 +6154,63 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai
/* -------- Target-Matrix Stuff ------- */
+int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets)
+{
+ BLI_listbase_clear(r_targets);
+
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (!cti) {
+ return 0;
+ }
+
+ int count = 0;
+
+ /* Constraint-specific targets. */
+ if (cti->get_constraint_targets) {
+ count = cti->get_constraint_targets(con, r_targets);
+ }
+
+ /* Add the custom target. */
+ if (is_custom_space_needed(con)) {
+ bConstraintTarget *ct;
+ SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, r_targets);
+ ct->space = CONSTRAINT_SPACE_WORLD;
+ ct->flag |= CONSTRAINT_TAR_CUSTOM_SPACE;
+ count++;
+ }
+
+ return count;
+}
+
+void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy)
+{
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ if (!cti) {
+ return;
+ }
+
+ /* Remove the custom target. */
+ bConstraintTarget *ct = (bConstraintTarget *)targets->last;
+
+ if (ct && (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE)) {
+ BLI_assert(is_custom_space_needed(con));
+
+ if (!no_copy) {
+ con->space_object = ct->tar;
+ BLI_strncpy(con->space_subtarget, ct->subtarget, sizeof(con->space_subtarget));
+ }
+
+ BLI_freelinkN(targets, ct);
+ }
+
+ /* Release the constraint-specific targets. */
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, targets, no_copy);
+ }
+}
+
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
Scene *scene,
bConstraint *con,
@@ -6242,6 +6262,9 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
}
}
+ /* Initialize the custom space for use in calculating the matrices. */
+ BKE_constraint_custom_object_space_init(cob, con);
+
/* get targets - we only need the first one though (and there should only be one) */
cti->get_constraint_targets(con, &targets);
@@ -6305,33 +6328,23 @@ void BKE_constraint_targets_for_solving_get(struct Depsgraph *depsgraph,
}
}
-void BKE_constraint_custom_object_space_get(float r_mat[4][4], bConstraint *con)
+void BKE_constraint_custom_object_space_init(bConstraintOb *cob, bConstraint *con)
{
- if (!con ||
- (con->ownspace != CONSTRAINT_SPACE_CUSTOM && con->tarspace != CONSTRAINT_SPACE_CUSTOM)) {
- return;
- }
- bConstraintTarget *ct;
- ListBase target = {NULL, NULL};
- SINGLETARGET_GET_TARS(con, con->space_object, con->space_subtarget, ct, &target);
-
- /* Basically default_get_tarmat but without the unused parameters. */
- if (VALID_CONS_TARGET(ct)) {
- constraint_target_to_mat4(ct->tar,
- ct->subtarget,
+ if (con && con->space_object && is_custom_space_needed(con)) {
+ /* Basically default_get_tarmat but without the unused parameters. */
+ constraint_target_to_mat4(con->space_object,
+ con->space_subtarget,
NULL,
- ct->matrix,
+ cob->space_obj_world_matrix,
CONSTRAINT_SPACE_WORLD,
CONSTRAINT_SPACE_WORLD,
0,
0);
- copy_m4_m4(r_mat, ct->matrix);
- }
- else {
- unit_m4(r_mat);
+
+ return;
}
- SINGLETARGET_FLUSH_TARS(con, con->space_object, con->space_subtarget, ct, &target, true);
+ unit_m4(cob->space_obj_world_matrix);
}
/* ---------- Evaluation ----------- */
@@ -6376,8 +6389,8 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
*/
enf = con->enforce;
- /* Get custom space matrix. */
- BKE_constraint_custom_object_space_get(cob->space_obj_world_matrix, con);
+ /* Initialize the custom space for use in calculating the matrices. */
+ BKE_constraint_custom_object_space_init(cob, con);
/* make copy of world-space matrix pre-constraint for use with blending later */
copy_m4_m4(oldmat, cob->matrix);
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index 4338883853d..5125e010b81 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -44,7 +44,6 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_object.h"
-#include "BKE_spline.hh"
#include "BKE_vfont.h"
#include "DEG_depsgraph.h"
diff --git a/source/blender/blenkernel/intern/curve_bezier.cc b/source/blender/blenkernel/intern/curve_bezier.cc
index 13695525616..59b09384698 100644
--- a/source/blender/blenkernel/intern/curve_bezier.cc
+++ b/source/blender/blenkernel/intern/curve_bezier.cc
@@ -16,15 +16,14 @@ bool segment_is_vector(const Span<int8_t> handle_types_left,
const int segment_index)
{
BLI_assert(handle_types_left.index_range().drop_back(1).contains(segment_index));
- return handle_types_right[segment_index] == BEZIER_HANDLE_VECTOR &&
- handle_types_left[segment_index + 1] == BEZIER_HANDLE_VECTOR;
+ return segment_is_vector(handle_types_right[segment_index],
+ handle_types_left[segment_index + 1]);
}
-bool last_cylic_segment_is_vector(const Span<int8_t> handle_types_left,
- const Span<int8_t> handle_types_right)
+bool last_cyclic_segment_is_vector(const Span<int8_t> handle_types_left,
+ const Span<int8_t> handle_types_right)
{
- return handle_types_right.last() == BEZIER_HANDLE_VECTOR &&
- handle_types_left.first() == BEZIER_HANDLE_VECTOR;
+ return segment_is_vector(handle_types_right.last(), handle_types_left.first());
}
void calculate_evaluated_offsets(const Span<int8_t> handle_types_left,
@@ -49,7 +48,8 @@ void calculate_evaluated_offsets(const Span<int8_t> handle_types_left,
}
if (cyclic) {
- offset += last_cylic_segment_is_vector(handle_types_left, handle_types_right) ? 1 : resolution;
+ offset += last_cyclic_segment_is_vector(handle_types_left, handle_types_right) ? 1 :
+ resolution;
}
else {
offset++;
@@ -58,6 +58,26 @@ void calculate_evaluated_offsets(const Span<int8_t> handle_types_left,
evaluated_offsets.last() = offset;
}
+Insertion insert(const float3 &point_prev,
+ const float3 &handle_prev,
+ const float3 &handle_next,
+ const float3 &point_next,
+ float parameter)
+{
+ /* De Casteljau Bezier subdivision. */
+ BLI_assert(parameter <= 1.0f && parameter >= 0.0f);
+
+ const float3 center_point = math::interpolate(handle_prev, handle_next, parameter);
+
+ Insertion result;
+ result.handle_prev = math::interpolate(point_prev, handle_prev, parameter);
+ result.handle_next = math::interpolate(handle_next, point_next, parameter);
+ result.left_handle = math::interpolate(result.handle_prev, center_point, parameter);
+ result.right_handle = math::interpolate(center_point, result.handle_next, parameter);
+ result.position = math::interpolate(result.left_handle, result.right_handle, parameter);
+ return result;
+}
+
static float3 calculate_aligned_handle(const float3 &position,
const float3 &other_handle,
const float3 &aligned_handle)
@@ -105,11 +125,11 @@ static void calculate_point_handles(const HandleType type_left,
}
if (type_left == BEZIER_HANDLE_VECTOR) {
- left = math::interpolate(position, prev_position, 1.0f / 3.0f);
+ left = calculate_vector_handle(position, prev_position);
}
if (type_right == BEZIER_HANDLE_VECTOR) {
- right = math::interpolate(position, next_position, 1.0f / 3.0f);
+ right = calculate_vector_handle(position, next_position);
}
/* When one of the handles is "aligned" handle, it must be aligned with the other, i.e. point in
diff --git a/source/blender/blenkernel/intern/curve_catmull_rom.cc b/source/blender/blenkernel/intern/curve_catmull_rom.cc
index 4b2174c912c..952d59edcf9 100644
--- a/source/blender/blenkernel/intern/curve_catmull_rom.cc
+++ b/source/blender/blenkernel/intern/curve_catmull_rom.cc
@@ -11,7 +11,7 @@ namespace blender::bke::curves::catmull_rom {
int calculate_evaluated_num(const int points_num, const bool cyclic, const int resolution)
{
- const int eval_num = resolution * curve_segment_num(points_num, cyclic);
+ const int eval_num = resolution * segments_num(points_num, cyclic);
/* If the curve isn't cyclic, one last point is added to the final point. */
return cyclic ? eval_num : eval_num + 1;
}
@@ -39,15 +39,18 @@ static void evaluate_segment(const T &a, const T &b, const T &c, const T &d, Mut
}
}
-template<typename T>
+/**
+ * \param range_fn: Returns an index range describing where in the #dst span each segment should be
+ * evaluated to, and how many points to add to it. This is used to avoid the need to allocate an
+ * actual offsets array in typical evaluation use cases where the resolution is per-curve.
+ */
+template<typename T, typename RangeForSegmentFn>
static void interpolate_to_evaluated(const Span<T> src,
const bool cyclic,
- const int resolution,
+ const RangeForSegmentFn &range_fn,
MutableSpan<T> dst)
{
- BLI_assert(dst.size() == calculate_evaluated_num(src.size(), cyclic, resolution));
-
/* - First deal with one and two point curves need special attention.
* - Then evaluate the first and last segment(s) whose control points need to wrap around
* to the other side of the source array.
@@ -57,11 +60,14 @@ static void interpolate_to_evaluated(const Span<T> src,
dst.first() = src.first();
return;
}
+
+ const IndexRange first = range_fn(0);
+
if (src.size() == 2) {
- evaluate_segment(src.first(), src.first(), src.last(), src.last(), dst.take_front(resolution));
+ evaluate_segment(src.first(), src.first(), src.last(), src.last(), dst.slice(first));
if (cyclic) {
- evaluate_segment(
- src.last(), src.last(), src.first(), src.first(), dst.take_back(resolution));
+ const IndexRange last = range_fn(1);
+ evaluate_segment(src.last(), src.last(), src.first(), src.first(), dst.slice(last));
}
else {
dst.last() = src.last();
@@ -69,39 +75,65 @@ static void interpolate_to_evaluated(const Span<T> src,
return;
}
+ const IndexRange second_to_last = range_fn(src.index_range().last(1));
+ const IndexRange last = range_fn(src.index_range().last());
if (cyclic) {
- /* The first segment. */
- evaluate_segment(src.last(), src[0], src[1], src[2], dst.take_front(resolution));
- /* The second-to-last segment. */
- evaluate_segment(src.last(2),
- src.last(1),
- src.last(),
- src.first(),
- dst.take_back(resolution * 2).drop_back(resolution));
- /* The last segment. */
- evaluate_segment(src.last(1), src.last(), src[0], src[1], dst.take_back(resolution));
+ evaluate_segment(src.last(), src[0], src[1], src[2], dst.slice(first));
+ evaluate_segment(src.last(2), src.last(1), src.last(), src.first(), dst.slice(second_to_last));
+ evaluate_segment(src.last(1), src.last(), src[0], src[1], dst.slice(last));
}
else {
- /* The first segment. */
- evaluate_segment(src[0], src[0], src[1], src[2], dst.take_front(resolution));
- /* The last segment. */
- evaluate_segment(
- src.last(2), src.last(1), src.last(), src.last(), dst.drop_back(1).take_back(resolution));
- /* The final point of the last segment. */
+ evaluate_segment(src[0], src[0], src[1], src[2], dst.slice(first));
+ evaluate_segment(src.last(2), src.last(1), src.last(), src.last(), dst.slice(second_to_last));
+ /* For non-cyclic curves, the last segment should always just have a single point. We could
+ * assert that the size of the provided range is 1 here, but that would require specializing
+ * the #range_fn implementation for the last point, which may have a performance cost. */
dst.last() = src.last();
}
/* Evaluate every segment that isn't the first or last. */
- const int grain_size = std::max(512 / resolution, 1);
const IndexRange inner_range = src.index_range().drop_back(2).drop_front(1);
- threading::parallel_for(inner_range, grain_size, [&](IndexRange range) {
+ threading::parallel_for(inner_range, 512, [&](IndexRange range) {
for (const int i : range) {
- const IndexRange segment_range(resolution * i, resolution);
- evaluate_segment(src[i - 1], src[i], src[i + 1], src[i + 2], dst.slice(segment_range));
+ const IndexRange segment = range_fn(i);
+ evaluate_segment(src[i - 1], src[i], src[i + 1], src[i + 2], dst.slice(segment));
}
});
}
+template<typename T>
+static void interpolate_to_evaluated(const Span<T> src,
+ const bool cyclic,
+ const int resolution,
+ MutableSpan<T> dst)
+
+{
+ BLI_assert(dst.size() == calculate_evaluated_num(src.size(), cyclic, resolution));
+ interpolate_to_evaluated(
+ src,
+ cyclic,
+ [resolution](const int segment_i) -> IndexRange {
+ return {segment_i * resolution, resolution};
+ },
+ dst);
+}
+
+template<typename T>
+static void interpolate_to_evaluated(const Span<T> src,
+ const bool cyclic,
+ const Span<int> evaluated_offsets,
+ MutableSpan<T> dst)
+
+{
+ interpolate_to_evaluated(
+ src,
+ cyclic,
+ [evaluated_offsets](const int segment_i) -> IndexRange {
+ return bke::offsets_to_range(evaluated_offsets, segment_i);
+ },
+ dst);
+}
+
void interpolate_to_evaluated(const GSpan src,
const bool cyclic,
const int resolution,
@@ -117,4 +149,19 @@ void interpolate_to_evaluated(const GSpan src,
});
}
+void interpolate_to_evaluated(const GSpan src,
+ const bool cyclic,
+ const Span<int> evaluated_offsets,
+ GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
+ * supporting more types. */
+ if constexpr (is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
+ interpolate_to_evaluated(src.typed<T>(), cyclic, evaluated_offsets, dst.typed<T>());
+ }
+ });
+}
+
} // namespace blender::bke::curves::catmull_rom
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index dd2bd982506..424fa311dc7 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -21,19 +21,17 @@ using blender::Array;
using blender::float3;
using blender::float4x4;
using blender::GVArray;
-using blender::GVArray_GSpan;
+using blender::GVArraySpan;
using blender::IndexRange;
using blender::Map;
using blender::MutableSpan;
using blender::Span;
using blender::StringRefNull;
using blender::VArray;
-using blender::VArray_Span;
+using blender::VArraySpan;
using blender::Vector;
using blender::bke::AttributeIDRef;
-using blender::bke::OutputAttribute;
-using blender::bke::OutputAttribute_Typed;
-using blender::bke::ReadAttributeLookup;
+using blender::bke::AttributeMetaData;
blender::Span<SplinePtr> CurveEval::splines() const
{
@@ -345,32 +343,31 @@ 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));
}
-static void copy_attributes_between_components(const GeometryComponent &src_component,
- GeometryComponent &dst_component,
- Span<std::string> skip)
+static void copy_attributes_between_components(
+ const blender::bke::AttributeAccessor &src_attributes,
+ blender::bke::MutableAttributeAccessor &dst_attributes,
+ Span<std::string> skip)
{
- src_component.attribute_foreach(
- [&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- if (id.is_named() && skip.contains(id.name())) {
- return true;
- }
+ src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (id.is_named() && skip.contains(id.name())) {
+ return true;
+ }
- GVArray src_attribute = src_component.attribute_try_get_for_read(
- id, meta_data.domain, meta_data.data_type);
- if (!src_attribute) {
- return true;
- }
- GVArray_GSpan src_attribute_data{src_attribute};
+ GVArray src_attribute = src_attributes.lookup(id, meta_data.domain, meta_data.data_type);
+ if (!src_attribute) {
+ return true;
+ }
+ GVArraySpan src_attribute_data{src_attribute};
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- id, meta_data.domain, meta_data.data_type);
- if (!dst_attribute) {
- return true;
- }
- dst_attribute.varray().set_all(src_attribute_data.data());
- dst_attribute.save();
- return true;
- });
+ blender::bke::GAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write(
+ id, meta_data.domain, meta_data.data_type);
+ if (!dst_attribute) {
+ return true;
+ }
+ dst_attribute.varray.set_all(src_attribute_data.data());
+ dst_attribute.finish();
+ return true;
+ });
}
std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves_id)
@@ -379,21 +376,22 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves_id)
src_component.replace(&const_cast<Curves &>(curves_id), GeometryOwnershipType::ReadOnly);
const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
curves_id.geometry);
+ const blender::bke::AttributeAccessor src_attributes = curves.attributes();
VArray<int> resolution = curves.resolution();
VArray<int8_t> normal_mode = curves.normal_mode();
- VArray_Span<float> nurbs_weights{
- src_component.attribute_get_for_read<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)};
- VArray_Span<int8_t> nurbs_orders{
- src_component.attribute_get_for_read<int8_t>("nurbs_order", ATTR_DOMAIN_CURVE, 4)};
- VArray_Span<int8_t> nurbs_knots_modes{
- src_component.attribute_get_for_read<int8_t>("knots_mode", ATTR_DOMAIN_CURVE, 0)};
+ VArraySpan<float> nurbs_weights{
+ src_attributes.lookup_or_default<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)};
+ VArraySpan<int8_t> nurbs_orders{
+ src_attributes.lookup_or_default<int8_t>("nurbs_order", ATTR_DOMAIN_CURVE, 4)};
+ VArraySpan<int8_t> nurbs_knots_modes{
+ src_attributes.lookup_or_default<int8_t>("knots_mode", ATTR_DOMAIN_CURVE, 0)};
- VArray_Span<int8_t> handle_types_right{
- src_component.attribute_get_for_read<int8_t>("handle_type_right", ATTR_DOMAIN_POINT, 0)};
- VArray_Span<int8_t> handle_types_left{
- src_component.attribute_get_for_read<int8_t>("handle_type_left", ATTR_DOMAIN_POINT, 0)};
+ VArraySpan<int8_t> handle_types_right{
+ src_attributes.lookup_or_default<int8_t>("handle_type_right", ATTR_DOMAIN_POINT, 0)};
+ VArraySpan<int8_t> handle_types_left{
+ src_attributes.lookup_or_default<int8_t>("handle_type_left", ATTR_DOMAIN_POINT, 0)};
/* Create splines with the correct size and type. */
VArray<int8_t> curve_types = curves.curve_types();
@@ -446,9 +444,10 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves_id)
CurveComponentLegacy dst_component;
dst_component.replace(curve_eval.get(), GeometryOwnershipType::Editable);
+ blender::bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
- copy_attributes_between_components(src_component,
- dst_component,
+ copy_attributes_between_components(src_attributes,
+ dst_attributes,
{"curve_type",
"resolution",
"normal_mode",
@@ -467,37 +466,38 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
curve_eval.splines().size());
CurveComponent dst_component;
dst_component.replace(curves_id, GeometryOwnershipType::Editable);
+ blender::bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(curves_id->geometry);
curves.offsets_for_write().copy_from(curve_eval.control_point_offsets());
MutableSpan<int8_t> curve_types = curves.curve_types_for_write();
- OutputAttribute_Typed<int8_t> normal_mode =
- dst_component.attribute_try_get_for_output_only<int8_t>("normal_mode", ATTR_DOMAIN_CURVE);
- OutputAttribute_Typed<float> nurbs_weight;
- OutputAttribute_Typed<int> nurbs_order;
- OutputAttribute_Typed<int8_t> nurbs_knots_mode;
+ blender::bke::SpanAttributeWriter<int8_t> normal_mode =
+ dst_attributes.lookup_or_add_for_write_only_span<int8_t>("normal_mode", ATTR_DOMAIN_CURVE);
+ blender::bke::SpanAttributeWriter<float> nurbs_weight;
+ blender::bke::SpanAttributeWriter<int> nurbs_order;
+ blender::bke::SpanAttributeWriter<int8_t> nurbs_knots_mode;
if (curve_eval.has_spline_with_type(CURVE_TYPE_NURBS)) {
- nurbs_weight = dst_component.attribute_try_get_for_output_only<float>("nurbs_weight",
- ATTR_DOMAIN_POINT);
- nurbs_order = dst_component.attribute_try_get_for_output_only<int>("nurbs_order",
- ATTR_DOMAIN_CURVE);
- nurbs_knots_mode = dst_component.attribute_try_get_for_output_only<int8_t>("knots_mode",
- ATTR_DOMAIN_CURVE);
+ nurbs_weight = dst_attributes.lookup_or_add_for_write_only_span<float>("nurbs_weight",
+ ATTR_DOMAIN_POINT);
+ nurbs_order = dst_attributes.lookup_or_add_for_write_only_span<int>("nurbs_order",
+ ATTR_DOMAIN_CURVE);
+ nurbs_knots_mode = dst_attributes.lookup_or_add_for_write_only_span<int8_t>("knots_mode",
+ ATTR_DOMAIN_CURVE);
}
- OutputAttribute_Typed<int8_t> handle_type_right;
- OutputAttribute_Typed<int8_t> handle_type_left;
+ blender::bke::SpanAttributeWriter<int8_t> handle_type_right;
+ blender::bke::SpanAttributeWriter<int8_t> handle_type_left;
if (curve_eval.has_spline_with_type(CURVE_TYPE_BEZIER)) {
- handle_type_right = dst_component.attribute_try_get_for_output_only<int8_t>(
+ handle_type_right = dst_attributes.lookup_or_add_for_write_only_span<int8_t>(
"handle_type_right", ATTR_DOMAIN_POINT);
- handle_type_left = dst_component.attribute_try_get_for_output_only<int8_t>("handle_type_left",
- ATTR_DOMAIN_POINT);
+ handle_type_left = dst_attributes.lookup_or_add_for_write_only_span<int8_t>("handle_type_left",
+ ATTR_DOMAIN_POINT);
}
for (const int curve_index : curve_eval.splines().index_range()) {
const Spline &spline = *curve_eval.splines()[curve_index];
curve_types[curve_index] = curve_eval.splines()[curve_index]->type();
- normal_mode.as_span()[curve_index] = curve_eval.splines()[curve_index]->normal_mode;
+ normal_mode.span[curve_index] = curve_eval.splines()[curve_index]->normal_mode;
const IndexRange points = curves.points_for_curve(curve_index);
switch (spline.type()) {
@@ -505,15 +505,15 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
break;
case CURVE_TYPE_BEZIER: {
const BezierSpline &src = static_cast<const BezierSpline &>(spline);
- handle_type_right.as_span().slice(points).copy_from(src.handle_types_right());
- handle_type_left.as_span().slice(points).copy_from(src.handle_types_left());
+ handle_type_right.span.slice(points).copy_from(src.handle_types_right());
+ handle_type_left.span.slice(points).copy_from(src.handle_types_left());
break;
}
case CURVE_TYPE_NURBS: {
const NURBSpline &src = static_cast<const NURBSpline &>(spline);
- nurbs_knots_mode.as_span()[curve_index] = static_cast<int8_t>(src.knots_mode);
- nurbs_order.as_span()[curve_index] = src.order();
- nurbs_weight.as_span().slice(points).copy_from(src.weights());
+ nurbs_knots_mode.span[curve_index] = static_cast<int8_t>(src.knots_mode);
+ nurbs_order.span[curve_index] = src.order();
+ nurbs_weight.span.slice(points).copy_from(src.weights());
break;
}
case CURVE_TYPE_CATMULL_ROM: {
@@ -525,17 +525,18 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
curves.update_curve_types();
- normal_mode.save();
- nurbs_weight.save();
- nurbs_order.save();
- nurbs_knots_mode.save();
- handle_type_right.save();
- handle_type_left.save();
+ normal_mode.finish();
+ nurbs_weight.finish();
+ nurbs_order.finish();
+ nurbs_knots_mode.finish();
+ handle_type_right.finish();
+ handle_type_left.finish();
CurveComponentLegacy src_component;
src_component.replace(&const_cast<CurveEval &>(curve_eval), GeometryOwnershipType::ReadOnly);
+ const blender::bke::AttributeAccessor src_attributes = *src_component.attributes();
- copy_attributes_between_components(src_component, dst_component, {});
+ copy_attributes_between_components(src_attributes, dst_attributes, {});
return curves_id;
}
diff --git a/source/blender/blenkernel/intern/curve_legacy_convert.cc b/source/blender/blenkernel/intern/curve_legacy_convert.cc
new file mode 100644
index 00000000000..ff5bbc32afe
--- /dev/null
+++ b/source/blender/blenkernel/intern/curve_legacy_convert.cc
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_task.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_curve_types.h"
+#include "DNA_curves_types.h"
+
+#include "BKE_curve.h"
+#include "BKE_curve_legacy_convert.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
+
+namespace blender::bke {
+
+static CurveType curve_type_from_legacy(const short type)
+{
+ switch (type) {
+ case CU_POLY:
+ return CURVE_TYPE_POLY;
+ case CU_BEZIER:
+ return CURVE_TYPE_BEZIER;
+ case CU_NURBS:
+ return CURVE_TYPE_NURBS;
+ }
+ BLI_assert_unreachable();
+ return CURVE_TYPE_POLY;
+}
+
+static HandleType handle_type_from_legacy(const uint8_t handle_type_legacy)
+{
+ switch (handle_type_legacy) {
+ case HD_FREE:
+ return BEZIER_HANDLE_FREE;
+ case HD_AUTO:
+ return BEZIER_HANDLE_AUTO;
+ case HD_VECT:
+ return BEZIER_HANDLE_VECTOR;
+ case HD_ALIGN:
+ return BEZIER_HANDLE_ALIGN;
+ case HD_AUTO_ANIM:
+ return BEZIER_HANDLE_AUTO;
+ case HD_ALIGN_DOUBLESIDE:
+ return BEZIER_HANDLE_ALIGN;
+ }
+ BLI_assert_unreachable();
+ return BEZIER_HANDLE_AUTO;
+}
+
+static NormalMode normal_mode_from_legacy(const short twist_mode)
+{
+ switch (twist_mode) {
+ case CU_TWIST_Z_UP:
+ case CU_TWIST_TANGENT:
+ return NORMAL_MODE_Z_UP;
+ case CU_TWIST_MINIMUM:
+ return NORMAL_MODE_MINIMUM_TWIST;
+ }
+ BLI_assert_unreachable();
+ return NORMAL_MODE_MINIMUM_TWIST;
+}
+
+static KnotsMode knots_mode_from_legacy(const short flag)
+{
+ switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
+ case CU_NURB_ENDPOINT:
+ return NURBS_KNOT_MODE_ENDPOINT;
+ case CU_NURB_BEZIER:
+ return NURBS_KNOT_MODE_BEZIER;
+ case CU_NURB_ENDPOINT | CU_NURB_BEZIER:
+ return NURBS_KNOT_MODE_ENDPOINT_BEZIER;
+ case 0:
+ return NURBS_KNOT_MODE_NORMAL;
+ }
+ BLI_assert_unreachable();
+ return NURBS_KNOT_MODE_NORMAL;
+}
+
+Curves *curve_legacy_to_curves(const Curve &curve_legacy, const ListBase &nurbs_list)
+{
+ const Vector<const Nurb *> src_curves(nurbs_list);
+
+ Curves *curves_id = curves_new_nomain(0, src_curves.size());
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ MutableAttributeAccessor curves_attributes = curves.attributes_for_write();
+
+ MutableSpan<int8_t> types = curves.curve_types_for_write();
+ MutableSpan<bool> cyclic = curves.cyclic_for_write();
+
+ int offset = 0;
+ MutableSpan<int> offsets = curves.offsets_for_write();
+ for (const int i : src_curves.index_range()) {
+ offsets[i] = offset;
+
+ const Nurb &src_curve = *src_curves[i];
+ types[i] = curve_type_from_legacy(src_curve.type);
+ cyclic[i] = src_curve.flagu & CU_NURB_CYCLIC;
+
+ offset += src_curve.pntsu;
+ }
+ offsets.last() = offset;
+ curves.resize(curves.offsets().last(), curves.curves_num());
+
+ curves.update_curve_types();
+
+ if (curves.curves_num() == 0) {
+ return curves_id;
+ }
+
+ MutableSpan<float3> positions = curves.positions_for_write();
+ SpanAttributeWriter<float> radius_attribute =
+ curves_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
+ MutableSpan<float> radii = radius_attribute.span;
+ MutableSpan<float> tilts = curves.tilt_for_write();
+
+ auto create_poly = [&](IndexMask selection) {
+ threading::parallel_for(selection.index_range(), 246, [&](IndexRange range) {
+ for (const int curve_i : selection.slice(range)) {
+ const Nurb &src_curve = *src_curves[curve_i];
+ const Span<BPoint> src_points(src_curve.bp, src_curve.pntsu);
+ const IndexRange points = curves.points_for_curve(curve_i);
+
+ for (const int i : src_points.index_range()) {
+ const BPoint &bp = src_points[i];
+ positions[points[i]] = bp.vec;
+ radii[points[i]] = bp.radius;
+ tilts[points[i]] = bp.tilt;
+ }
+ }
+ });
+ };
+
+ /* NOTE: For curve handles, legacy curves can end up in invalid situations where the handle
+ * positions don't agree with the types because of evaluation, or because one-sided aligned
+ * handles weren't considered. While recalculating automatic handles to fix those situations
+ * is an option, currently this opts not to for the sake of flexibility. */
+ auto create_bezier = [&](IndexMask selection) {
+ MutableSpan<int> resolutions = curves.resolution_for_write();
+ MutableSpan<float3> handle_positions_l = curves.handle_positions_left_for_write();
+ MutableSpan<float3> handle_positions_r = curves.handle_positions_right_for_write();
+ MutableSpan<int8_t> handle_types_l = curves.handle_types_left_for_write();
+ MutableSpan<int8_t> handle_types_r = curves.handle_types_right_for_write();
+
+ threading::parallel_for(selection.index_range(), 246, [&](IndexRange range) {
+ for (const int curve_i : selection.slice(range)) {
+ const Nurb &src_curve = *src_curves[curve_i];
+ const Span<BezTriple> src_points(src_curve.bezt, src_curve.pntsu);
+ const IndexRange points = curves.points_for_curve(curve_i);
+
+ resolutions[curve_i] = src_curve.resolu;
+
+ for (const int i : src_points.index_range()) {
+ const BezTriple &point = src_points[i];
+ positions[points[i]] = point.vec[1];
+ handle_positions_l[points[i]] = point.vec[0];
+ handle_types_l[points[i]] = handle_type_from_legacy(point.h1);
+ handle_positions_r[points[i]] = point.vec[2];
+ handle_types_r[points[i]] = handle_type_from_legacy(point.h2);
+ radii[points[i]] = point.radius;
+ tilts[points[i]] = point.tilt;
+ }
+ }
+ });
+ };
+
+ auto create_nurbs = [&](IndexMask selection) {
+ threading::parallel_for(selection.index_range(), 246, [&](IndexRange range) {
+ MutableSpan<int> resolutions = curves.resolution_for_write();
+ MutableSpan<float> nurbs_weights = curves.nurbs_weights_for_write();
+ MutableSpan<int8_t> nurbs_orders = curves.nurbs_orders_for_write();
+ MutableSpan<int8_t> nurbs_knots_modes = curves.nurbs_knots_modes_for_write();
+
+ for (const int curve_i : selection.slice(range)) {
+ const Nurb &src_curve = *src_curves[curve_i];
+ const Span src_points(src_curve.bp, src_curve.pntsu);
+ const IndexRange points = curves.points_for_curve(curve_i);
+
+ resolutions[curve_i] = src_curve.resolu;
+ nurbs_orders[curve_i] = src_curve.orderu;
+ nurbs_knots_modes[curve_i] = knots_mode_from_legacy(src_curve.flagu);
+
+ for (const int i : src_points.index_range()) {
+ const BPoint &bp = src_points[i];
+ positions[points[i]] = bp.vec;
+ radii[points[i]] = bp.radius;
+ tilts[points[i]] = bp.tilt;
+ nurbs_weights[points[i]] = bp.vec[3];
+ }
+ }
+ });
+ };
+
+ bke::curves::foreach_curve_by_type(
+ curves.curve_types(),
+ curves.curve_type_counts(),
+ curves.curves_range(),
+ [&](IndexMask /*selection*/) { BLI_assert_unreachable(); },
+ create_poly,
+ create_bezier,
+ create_nurbs);
+
+ curves.normal_mode_for_write().fill(normal_mode_from_legacy(curve_legacy.twist_mode));
+
+ radius_attribute.finish();
+
+ return curves_id;
+}
+
+Curves *curve_legacy_to_curves(const Curve &curve_legacy)
+{
+ return curve_legacy_to_curves(curve_legacy, *BKE_curve_nurbs_get_for_read(&curve_legacy));
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/curve_nurbs.cc b/source/blender/blenkernel/intern/curve_nurbs.cc
index cd6b64e9a03..3ab6fb01ea5 100644
--- a/source/blender/blenkernel/intern/curve_nurbs.cc
+++ b/source/blender/blenkernel/intern/curve_nurbs.cc
@@ -38,7 +38,7 @@ int calculate_evaluated_num(const int points_num,
if (!check_valid_num_and_order(points_num, order, cyclic, knots_mode)) {
return points_num;
}
- return resolution * curve_segment_num(points_num, cyclic);
+ return resolution * segments_num(points_num, cyclic);
}
int knots_num(const int points_num, const int8_t order, const bool cyclic)
@@ -168,7 +168,7 @@ void calculate_basis_cache(const int points_num,
MutableSpan<int> basis_start_indices(basis_cache.start_indices);
const int last_control_point_index = cyclic ? points_num + degree : points_num;
- const int evaluated_segment_num = curve_segment_num(evaluated_num, cyclic);
+ const int evaluated_segment_num = segments_num(evaluated_num, cyclic);
const float start = knots[degree];
const float end = knots[last_control_point_index];
diff --git a/source/blender/blenkernel/intern/curve_poly.cc b/source/blender/blenkernel/intern/curve_poly.cc
index 1b337379604..7ab92068d81 100644
--- a/source/blender/blenkernel/intern/curve_poly.cc
+++ b/source/blender/blenkernel/intern/curve_poly.cc
@@ -13,15 +13,28 @@
namespace blender::bke::curves::poly {
-static float3 direction_bisect(const float3 &prev, const float3 &middle, const float3 &next)
+static float3 direction_bisect(const float3 &prev,
+ const float3 &middle,
+ const float3 &next,
+ bool &r_used_fallback)
{
+ const float epsilon = 1e-6f;
+ const bool prev_equal = math::almost_equal_relative(prev, middle, epsilon);
+ const bool next_equal = math::almost_equal_relative(middle, next, epsilon);
+ if (prev_equal && next_equal) {
+ r_used_fallback = true;
+ return {0.0f, 0.0f, 0.0f};
+ }
+ if (prev_equal) {
+ return math::normalize(next - middle);
+ }
+ if (next_equal) {
+ return math::normalize(middle - prev);
+ }
+
const float3 dir_prev = math::normalize(middle - prev);
const float3 dir_next = math::normalize(next - middle);
-
const float3 result = math::normalize(dir_prev + dir_next);
- if (UNLIKELY(math::is_zero(result))) {
- return float3(0.0f, 0.0f, 1.0f);
- }
return result;
}
@@ -36,8 +49,11 @@ void calculate_tangents(const Span<float3> positions,
return;
}
+ bool used_fallback = false;
+
for (const int i : IndexRange(1, positions.size() - 2)) {
- tangents[i] = direction_bisect(positions[i - 1], positions[i], positions[i + 1]);
+ tangents[i] = direction_bisect(
+ positions[i - 1], positions[i], positions[i + 1], used_fallback);
}
if (is_cyclic) {
@@ -45,13 +61,46 @@ void calculate_tangents(const Span<float3> positions,
const float3 &last = positions.last();
const float3 &first = positions.first();
const float3 &second = positions[1];
- tangents.first() = direction_bisect(last, first, second);
- tangents.last() = direction_bisect(second_to_last, last, first);
+ tangents.first() = direction_bisect(last, first, second, used_fallback);
+ tangents.last() = direction_bisect(second_to_last, last, first, used_fallback);
}
else {
tangents.first() = math::normalize(positions[1] - positions.first());
tangents.last() = math::normalize(positions.last() - positions[positions.size() - 2]);
}
+
+ if (!used_fallback) {
+ return;
+ }
+
+ /* Find the first tangent that does not use the fallback. */
+ int first_valid_tangent_index = -1;
+ for (const int i : tangents.index_range()) {
+ if (!math::is_zero(tangents[i])) {
+ first_valid_tangent_index = i;
+ break;
+ }
+ }
+ if (first_valid_tangent_index == -1) {
+ /* If all tangents used the fallback, it means that all positions are (almost) the same. Just
+ * use the up-vector as default tangent. */
+ const float3 up_vector{0.0f, 0.0f, 1.0f};
+ tangents.fill(up_vector);
+ }
+ else {
+ const float3 &first_valid_tangent = tangents[first_valid_tangent_index];
+ /* If the first few tangents are invalid, use the tangent from the first point with a valid
+ * tangent. */
+ tangents.take_front(first_valid_tangent_index).fill(first_valid_tangent);
+ /* Use the previous valid tangent for points that had no valid tangent. */
+ for (const int i : tangents.index_range().drop_front(first_valid_tangent_index + 1)) {
+ float3 &tangent = tangents[i];
+ if (math::is_zero(tangent)) {
+ const float3 &prev_tangent = tangents[i - 1];
+ tangent = prev_tangent;
+ }
+ }
+ }
}
void calculate_normals_z_up(const Span<float3> tangents, MutableSpan<float3> normals)
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 0cd324cfe2c..7f051b683b4 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -8,7 +8,6 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
@@ -39,8 +38,8 @@ static void fill_mesh_topology(const int vert_offset,
MutableSpan<MLoop> loops,
MutableSpan<MPoly> polys)
{
- const int main_segment_num = curves::curve_segment_num(main_point_num, main_cyclic);
- const int profile_segment_num = curves::curve_segment_num(profile_point_num, profile_cyclic);
+ const int main_segment_num = curves::segments_num(main_point_num, main_cyclic);
+ const int profile_segment_num = curves::segments_num(profile_point_num, profile_cyclic);
if (profile_point_num == 1) {
for (const int i : IndexRange(main_point_num - 1)) {
@@ -228,8 +227,8 @@ struct CurvesInfo {
const CurvesGeometry &profile;
/* Make sure these are spans because they are potentially accessed many times. */
- VArray_Span<bool> main_cyclic;
- VArray_Span<bool> profile_cyclic;
+ VArraySpan<bool> main_cyclic;
+ VArraySpan<bool> profile_cyclic;
};
static CurvesInfo get_curves_info(const CurvesGeometry &main, const CurvesGeometry &profile)
{
@@ -273,7 +272,7 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
for (const int i_main : info.main.curves_range()) {
const bool main_cyclic = info.main_cyclic[i_main];
const int main_point_num = info.main.evaluated_points_for_curve(i_main).size();
- const int main_segment_num = curves::curve_segment_num(main_point_num, main_cyclic);
+ const int main_segment_num = curves::segments_num(main_point_num, main_cyclic);
for (const int i_profile : info.profile.curves_range()) {
result.vert[mesh_index] = vert_offset;
result.edge[mesh_index] = edge_offset;
@@ -285,7 +284,7 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
const bool profile_cyclic = info.profile_cyclic[i_profile];
const int profile_point_num = info.profile.evaluated_points_for_curve(i_profile).size();
- const int profile_segment_num = curves::curve_segment_num(profile_point_num, profile_cyclic);
+ const int profile_segment_num = curves::segments_num(profile_point_num, profile_cyclic);
const bool has_caps = fill_caps && !main_cyclic && profile_cyclic;
const int tube_face_num = main_segment_num * profile_segment_num;
@@ -315,15 +314,15 @@ static ResultOffsets calculate_result_offsets(const CurvesInfo &info, const bool
return result;
}
-static AttributeDomain get_attribute_domain_for_mesh(const MeshComponent &mesh,
- const AttributeIDRef &attribute_id)
+static eAttrDomain get_attribute_domain_for_mesh(const AttributeAccessor &mesh_attributes,
+ const AttributeIDRef &attribute_id)
{
/* Only use a different domain if it is builtin and must only exist on one domain. */
- if (!mesh.attribute_is_builtin(attribute_id)) {
+ if (!mesh_attributes.is_builtin(attribute_id)) {
return ATTR_DOMAIN_POINT;
}
- std::optional<AttributeMetaData> meta_data = mesh.attribute_get_meta_data(attribute_id);
+ std::optional<AttributeMetaData> meta_data = mesh_attributes.lookup_meta_data(attribute_id);
if (!meta_data) {
return ATTR_DOMAIN_POINT;
}
@@ -331,16 +330,17 @@ static AttributeDomain get_attribute_domain_for_mesh(const MeshComponent &mesh,
return meta_data->domain;
}
-static bool should_add_attribute_to_mesh(const CurveComponent &curve_component,
- const MeshComponent &mesh_component,
+static bool should_add_attribute_to_mesh(const AttributeAccessor &curve_attributes,
+ const AttributeAccessor &mesh_attributes,
const AttributeIDRef &id)
{
+
/* The position attribute has special non-generic evaluation. */
if (id.is_named() && id.name() == "position") {
return false;
}
/* Don't propagate built-in curves attributes that are not built-in on meshes. */
- if (curve_component.attribute_is_builtin(id) && !mesh_component.attribute_is_builtin(id)) {
+ if (curve_attributes.is_builtin(id) && !mesh_attributes.is_builtin(id)) {
return false;
}
if (!id.should_be_kept()) {
@@ -407,8 +407,8 @@ static void foreach_curve_combination(const CurvesInfo &info,
profile_points,
main_cyclic,
profile_cyclic,
- curves::curve_segment_num(main_points.size(), main_cyclic),
- curves::curve_segment_num(profile_points.size(), profile_cyclic),
+ curves::segments_num(main_points.size(), main_cyclic),
+ curves::segments_num(profile_points.size(), profile_cyclic),
offsets_to_range(offsets.vert.as_span(), i),
offsets_to_range(offsets.edge.as_span(), i),
offsets_to_range(offsets.poly.as_span(), i),
@@ -456,7 +456,7 @@ static void copy_main_point_data_to_mesh_faces(const Span<T> src,
static void copy_main_point_domain_attribute_to_mesh(const CurvesInfo &curves_info,
const ResultOffsets &offsets,
- const AttributeDomain dst_domain,
+ const eAttrDomain dst_domain,
const GSpan src_all,
GMutableSpan dst_all)
{
@@ -538,7 +538,7 @@ static void copy_profile_point_data_to_mesh_faces(const Span<T> src,
static void copy_profile_point_domain_attribute_to_mesh(const CurvesInfo &curves_info,
const ResultOffsets &offsets,
- const AttributeDomain dst_domain,
+ const eAttrDomain dst_domain,
const GSpan src_all,
GMutableSpan dst_all)
{
@@ -597,7 +597,7 @@ static void copy_indices_to_offset_ranges(const VArray<T> &src,
static void copy_curve_domain_attribute_to_mesh(const ResultOffsets &mesh_offsets,
const Span<int> curve_indices,
- const AttributeDomain dst_domain,
+ const eAttrDomain dst_domain,
const GVArray &src,
GMutableSpan dst)
{
@@ -667,20 +667,13 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
Vector<std::byte> eval_buffer;
- Curves main_id = {{nullptr}};
- main_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(main);
- CurveComponent main_component;
- main_component.replace(&main_id, GeometryOwnershipType::Editable);
-
- Curves profile_id = {{nullptr}};
- profile_id.geometry = reinterpret_cast<const ::CurvesGeometry &>(profile);
- CurveComponent profile_component;
- profile_component.replace(&profile_id, GeometryOwnershipType::Editable);
+ const AttributeAccessor main_attributes = main.attributes();
+ const AttributeAccessor profile_attributes = profile.attributes();
Span<float> radii = {};
- if (main_component.attribute_exists("radius")) {
+ if (main_attributes.contains("radius")) {
radii = evaluated_attribute_if_necessary(
- main_component.attribute_get_for_read<float>("radius", ATTR_DOMAIN_POINT, 1.0f),
+ main_attributes.lookup_or_default<float>("radius", ATTR_DOMAIN_POINT, 1.0f),
main,
main.curve_type_counts(),
eval_buffer)
@@ -700,8 +693,8 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
if (profile.curve_type_counts()[CURVE_TYPE_BEZIER] > 0) {
const VArray<int8_t> curve_types = profile.curve_types();
- const VArray_Span<int8_t> handle_types_left{profile.handle_types_left()};
- const VArray_Span<int8_t> handle_types_right{profile.handle_types_right()};
+ const VArraySpan<int8_t> handle_types_left{profile.handle_types_left()};
+ const VArraySpan<int8_t> handle_types_right{profile.handle_types_right()};
foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
if (curve_types[info.i_profile] == CURVE_TYPE_BEZIER) {
@@ -716,24 +709,23 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
});
}
- Set<AttributeIDRef> main_attributes;
+ Set<AttributeIDRef> main_attributes_set;
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ MutableAttributeAccessor mesh_attributes = bke::mesh_attributes_for_write(*mesh);
- main_component.attribute_foreach([&](const AttributeIDRef &id,
- const AttributeMetaData meta_data) {
- if (!should_add_attribute_to_mesh(main_component, mesh_component, id)) {
+ main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ if (!should_add_attribute_to_mesh(main_attributes, mesh_attributes, id)) {
return true;
}
- main_attributes.add_new(id);
+ main_attributes_set.add_new(id);
- const AttributeDomain src_domain = meta_data.domain;
- const CustomDataType type = meta_data.data_type;
- GVArray src = main_component.attribute_try_get_for_read(id, src_domain, type);
+ const eAttrDomain src_domain = meta_data.domain;
+ const eCustomDataType type = meta_data.data_type;
+ GVArray src = main_attributes.lookup(id, src_domain, type);
- const AttributeDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
- OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type);
+ const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_attributes, id);
+ GSpanAttributeWriter dst = mesh_attributes.lookup_or_add_for_write_only_span(
+ id, dst_domain, type);
if (!dst) {
return true;
}
@@ -744,31 +736,31 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
offsets,
dst_domain,
evaluated_attribute_if_necessary(src, main, main.curve_type_counts(), eval_buffer),
- dst.as_span());
+ dst.span);
}
else if (src_domain == ATTR_DOMAIN_CURVE) {
copy_curve_domain_attribute_to_mesh(
- offsets, offsets.main_indices, dst_domain, src, dst.as_span());
+ offsets, offsets.main_indices, dst_domain, src, dst.span);
}
- dst.save();
+ dst.finish();
return true;
});
- profile_component.attribute_foreach([&](const AttributeIDRef &id,
- const AttributeMetaData meta_data) {
+ profile_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (main_attributes.contains(id)) {
return true;
}
- if (!should_add_attribute_to_mesh(profile_component, mesh_component, id)) {
+ if (!should_add_attribute_to_mesh(profile_attributes, mesh_attributes, id)) {
return true;
}
- const AttributeDomain src_domain = meta_data.domain;
- const CustomDataType type = meta_data.data_type;
- GVArray src = profile_component.attribute_try_get_for_read(id, src_domain, type);
+ const eAttrDomain src_domain = meta_data.domain;
+ const eCustomDataType type = meta_data.data_type;
+ GVArray src = profile_attributes.lookup(id, src_domain, type);
- const AttributeDomain dst_domain = get_attribute_domain_for_mesh(mesh_component, id);
- OutputAttribute dst = mesh_component.attribute_try_get_for_output_only(id, dst_domain, type);
+ const eAttrDomain dst_domain = get_attribute_domain_for_mesh(mesh_attributes, id);
+ GSpanAttributeWriter dst = mesh_attributes.lookup_or_add_for_write_only_span(
+ id, dst_domain, type);
if (!dst) {
return true;
}
@@ -779,14 +771,14 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
offsets,
dst_domain,
evaluated_attribute_if_necessary(src, profile, profile.curve_type_counts(), eval_buffer),
- dst.as_span());
+ dst.span);
}
else if (src_domain == ATTR_DOMAIN_CURVE) {
copy_curve_domain_attribute_to_mesh(
- offsets, offsets.profile_indices, dst_domain, src, dst.as_span());
+ offsets, offsets.profile_indices, dst_domain, src, dst.span);
}
- dst.save();
+ dst.finish();
return true;
});
diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc
index d38bc790978..5684a2e5b07 100644
--- a/source/blender/blenkernel/intern/curves.cc
+++ b/source/blender/blenkernel/intern/curves.cc
@@ -23,6 +23,7 @@
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BKE_anim_data.h"
#include "BKE_curves.hh"
@@ -48,11 +49,10 @@ using blender::IndexRange;
using blender::MutableSpan;
using blender::RandomNumberGenerator;
using blender::Span;
+using blender::Vector;
static const char *ATTR_POSITION = "position";
-static void update_custom_data_pointers(Curves &curves);
-
static void curves_init_data(ID *id)
{
Curves *curves = (Curves *)id;
@@ -87,12 +87,14 @@ static void curves_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src,
dst.curve_offsets = static_cast<int *>(MEM_dupallocN(src.curve_offsets));
+ if (curves_src->surface_uv_map != nullptr) {
+ curves_dst->surface_uv_map = BLI_strdup(curves_src->surface_uv_map);
+ }
+
dst.runtime = MEM_new<bke::CurvesGeometryRuntime>(__func__);
dst.runtime->type_counts = src.runtime->type_counts;
- dst.update_customdata_pointers();
-
curves_dst->batch_cache = nullptr;
}
@@ -106,6 +108,7 @@ static void curves_free_data(ID *id)
BKE_curves_batch_cache_free(curves);
MEM_SAFE_FREE(curves->mat);
+ MEM_SAFE_FREE(curves->surface_uv_map);
}
static void curves_foreach_id(ID *id, LibraryForeachIDData *data)
@@ -121,12 +124,10 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre
{
Curves *curves = (Curves *)id;
- CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE];
- CustomData_blend_write_prepare(
- &curves->geometry.point_data, &players, players_buff, ARRAY_SIZE(players_buff));
- CustomData_blend_write_prepare(
- &curves->geometry.curve_data, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
+ Vector<CustomDataLayer, 16> point_layers;
+ Vector<CustomDataLayer, 16> curve_layers;
+ CustomData_blend_write_prepare(curves->geometry.point_data, point_layers);
+ CustomData_blend_write_prepare(curves->geometry.curve_data, curve_layers);
/* Write LibData */
BLO_write_id_struct(writer, Curves, id_address, &curves->id);
@@ -135,31 +136,25 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre
/* Direct data */
CustomData_blend_write(writer,
&curves->geometry.point_data,
- players,
+ point_layers,
curves->geometry.point_num,
CD_MASK_ALL,
&curves->id);
CustomData_blend_write(writer,
&curves->geometry.curve_data,
- clayers,
+ curve_layers,
curves->geometry.curve_num,
CD_MASK_ALL,
&curves->id);
BLO_write_int32_array(writer, curves->geometry.curve_num + 1, curves->geometry.curve_offsets);
+ BLO_write_string(writer, curves->surface_uv_map);
+
BLO_write_pointer_array(writer, curves->totcol, curves->mat);
if (curves->adt) {
BKE_animdata_blend_write(writer, curves->adt);
}
-
- /* Remove temporary data. */
- if (players && players != players_buff) {
- MEM_freeN(players);
- }
- if (clayers && clayers != clayers_buff) {
- MEM_freeN(clayers);
- }
}
static void curves_blend_read_data(BlendDataReader *reader, ID *id)
@@ -171,10 +166,11 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id)
/* Geometry */
CustomData_blend_read(reader, &curves->geometry.point_data, curves->geometry.point_num);
CustomData_blend_read(reader, &curves->geometry.curve_data, curves->geometry.curve_num);
- update_custom_data_pointers(*curves);
BLO_read_int32_array(reader, curves->geometry.curve_num + 1, &curves->geometry.curve_offsets);
+ BLO_read_data_address(reader, &curves->surface_uv_map);
+
curves->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
/* Recalculate curve type count cache that isn't saved in files. */
@@ -207,8 +203,8 @@ IDTypeInfo IDType_ID_CV = {
/*id_filter */ FILTER_ID_CV,
/*main_listbase_index */ INDEX_ID_CV,
/*struct_size */ sizeof(Curves),
- /*name */ "Hair Curves",
- /*name_plural */ "Hair Curves",
+ /*name */ "Curves",
+ /*name_plural */ "curves",
/*translation_context */ BLT_I18NCONTEXT_ID_CURVES,
/*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
/*asset_type_info */ nullptr,
@@ -232,11 +228,6 @@ IDTypeInfo IDType_ID_CV = {
/*lib_override_apply_post */ nullptr,
};
-static void update_custom_data_pointers(Curves &curves)
-{
- blender::bke::CurvesGeometry::wrap(curves.geometry).update_customdata_pointers();
-}
-
void *BKE_curves_add(Main *bmain, const char *name)
{
Curves *curves = static_cast<Curves *>(BKE_id_new(bmain, ID_CV, name));
@@ -272,9 +263,9 @@ BoundBox *BKE_curves_boundbox_get(Object *ob)
return ob->runtime.bb;
}
-bool BKE_curves_customdata_required(Curves *UNUSED(curves), CustomDataLayer *layer)
+bool BKE_curves_customdata_required(const Curves *UNUSED(curves), const char *name)
{
- return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, ATTR_POSITION);
+ return STREQ(name, ATTR_POSITION);
}
Curves *BKE_curves_copy_for_eval(Curves *curves_src, bool reference)
@@ -387,4 +378,35 @@ Curves *curves_new_nomain(CurvesGeometry curves)
return curves_id;
}
+void curves_copy_parameters(const Curves &src, Curves &dst)
+{
+ dst.flag = src.flag;
+ dst.attributes_active_index = src.attributes_active_index;
+ MEM_SAFE_FREE(dst.mat);
+ dst.mat = static_cast<Material **>(MEM_malloc_arrayN(src.totcol, sizeof(Material *), __func__));
+ dst.totcol = src.totcol;
+ MutableSpan(dst.mat, dst.totcol).copy_from(Span(src.mat, src.totcol));
+ dst.symmetry = src.symmetry;
+ dst.selection_domain = src.selection_domain;
+ dst.surface = src.surface;
+ MEM_SAFE_FREE(dst.surface_uv_map);
+ if (src.surface_uv_map != nullptr) {
+ dst.surface_uv_map = BLI_strdup(src.surface_uv_map);
+ }
+}
+
+CurvesSurfaceTransforms::CurvesSurfaceTransforms(const Object &curves_ob, const Object *surface_ob)
+{
+ this->curves_to_world = curves_ob.obmat;
+ this->world_to_curves = this->curves_to_world.inverted();
+
+ if (surface_ob != nullptr) {
+ this->surface_to_world = surface_ob->obmat;
+ this->world_to_surface = this->surface_to_world.inverted();
+ this->surface_to_curves = this->world_to_curves * this->surface_to_world;
+ this->curves_to_surface = this->world_to_surface * this->curves_to_world;
+ this->surface_to_curves_normal = this->surface_to_curves.inverted().transposed();
+ }
+}
+
} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index 0fd58a52f81..7fc660cfbfc 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -18,6 +18,7 @@
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
namespace blender::bke {
@@ -35,8 +36,9 @@ static const std::string ATTR_HANDLE_POSITION_RIGHT = "handle_right";
static const std::string ATTR_NURBS_ORDER = "nurbs_order";
static const std::string ATTR_NURBS_WEIGHT = "nurbs_weight";
static const std::string ATTR_NURBS_KNOTS_MODE = "knots_mode";
-static const std::string ATTR_SURFACE_TRIANGLE_INDEX = "surface_triangle_index";
-static const std::string ATTR_SURFACE_TRIANGLE_COORDINATE = "surface_triangle_coordinate";
+static const std::string ATTR_SELECTION_POINT_FLOAT = ".selection_point_float";
+static const std::string ATTR_SELECTION_CURVE_FLOAT = ".selection_curve_float";
+static const std::string ATTR_SURFACE_UV_COORDINATE = "surface_uv_coordinate";
/* -------------------------------------------------------------------- */
/** \name Constructors/Destructor
@@ -60,9 +62,11 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num)
this->point_num,
ATTR_POSITION.c_str());
- this->curve_offsets = (int *)MEM_calloc_arrayN(this->curve_num + 1, sizeof(int), __func__);
-
- this->update_customdata_pointers();
+ this->curve_offsets = (int *)MEM_malloc_arrayN(this->curve_num + 1, sizeof(int), __func__);
+#ifdef DEBUG
+ this->offsets_for_write().fill(-1);
+#endif
+ this->offsets_for_write().first() = 0;
this->runtime = MEM_new<CurvesGeometryRuntime>(__func__);
/* Fill the type counts with the default so they're in a valid state. */
@@ -82,15 +86,13 @@ static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src)
CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, CD_DUPLICATE, dst.curve_num);
MEM_SAFE_FREE(dst.curve_offsets);
- dst.curve_offsets = (int *)MEM_calloc_arrayN(dst.point_num + 1, sizeof(int), __func__);
+ dst.curve_offsets = (int *)MEM_malloc_arrayN(dst.point_num + 1, sizeof(int), __func__);
dst.offsets_for_write().copy_from(src.offsets());
dst.tag_topology_changed();
/* Though type counts are a cache, they must be copied because they are calculated eagerly. */
dst.runtime->type_counts = src.runtime->type_counts;
-
- dst.update_customdata_pointers();
}
CurvesGeometry::CurvesGeometry(const CurvesGeometry &other)
@@ -124,9 +126,6 @@ static void move_curves_geometry(CurvesGeometry &dst, CurvesGeometry &src)
MEM_SAFE_FREE(src.curve_offsets);
std::swap(dst.runtime, src.runtime);
-
- src.update_customdata_pointers();
- dst.update_customdata_pointers();
}
CurvesGeometry::CurvesGeometry(CurvesGeometry &&other)
@@ -158,30 +157,29 @@ CurvesGeometry::~CurvesGeometry()
/** \name Accessors
* \{ */
-static int domain_num(const CurvesGeometry &curves, const AttributeDomain domain)
+static int domain_num(const CurvesGeometry &curves, const eAttrDomain domain)
{
return domain == ATTR_DOMAIN_POINT ? curves.points_num() : curves.curves_num();
}
-static CustomData &domain_custom_data(CurvesGeometry &curves, const AttributeDomain domain)
+static CustomData &domain_custom_data(CurvesGeometry &curves, const eAttrDomain domain)
{
return domain == ATTR_DOMAIN_POINT ? curves.point_data : curves.curve_data;
}
-static const CustomData &domain_custom_data(const CurvesGeometry &curves,
- const AttributeDomain domain)
+static const CustomData &domain_custom_data(const CurvesGeometry &curves, const eAttrDomain domain)
{
return domain == ATTR_DOMAIN_POINT ? curves.point_data : curves.curve_data;
}
template<typename T>
static VArray<T> get_varray_attribute(const CurvesGeometry &curves,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const StringRefNull name,
const T default_value)
{
const int num = domain_num(curves, domain);
- const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
+ const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
const CustomData &custom_data = domain_custom_data(curves, domain);
const T *data = (const T *)CustomData_get_layer_named(&custom_data, type, name.c_str());
@@ -193,12 +191,12 @@ static VArray<T> get_varray_attribute(const CurvesGeometry &curves,
template<typename T>
static Span<T> get_span_attribute(const CurvesGeometry &curves,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const StringRefNull name)
{
const int num = domain_num(curves, domain);
const CustomData &custom_data = domain_custom_data(curves, domain);
- const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
+ const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
T *data = (T *)CustomData_get_layer_named(&custom_data, type, name.c_str());
if (data == nullptr) {
@@ -209,12 +207,12 @@ static Span<T> get_span_attribute(const CurvesGeometry &curves,
template<typename T>
static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const StringRefNull name,
const T default_value = T())
{
const int num = domain_num(curves, domain);
- const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
+ const eCustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
CustomData &custom_data = domain_custom_data(curves, domain);
T *data = (T *)CustomData_duplicate_referenced_layer_named(
@@ -301,13 +299,11 @@ void CurvesGeometry::update_curve_types()
Span<float3> CurvesGeometry::positions() const
{
- return {(const float3 *)this->position, this->point_num};
+ return get_span_attribute<float3>(*this, ATTR_DOMAIN_POINT, ATTR_POSITION);
}
MutableSpan<float3> CurvesGeometry::positions_for_write()
{
- this->position = (float(*)[3])CustomData_duplicate_referenced_layer_named(
- &this->point_data, CD_PROP_FLOAT3, ATTR_POSITION.c_str(), this->point_num);
- return {(float3 *)this->position, this->point_num};
+ return get_mutable_attribute<float3>(*this, ATTR_DOMAIN_POINT, ATTR_POSITION);
}
Span<int> CurvesGeometry::offsets() const
@@ -418,24 +414,34 @@ MutableSpan<int8_t> CurvesGeometry::nurbs_knots_modes_for_write()
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE, 0);
}
-VArray<int> CurvesGeometry::surface_triangle_indices() const
+Span<float2> CurvesGeometry::surface_uv_coords() const
+{
+ return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_UV_COORDINATE);
+}
+
+MutableSpan<float2> CurvesGeometry::surface_uv_coords_for_write()
+{
+ return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_UV_COORDINATE);
+}
+
+VArray<float> CurvesGeometry::selection_point_float() const
{
- return get_varray_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
+ return get_varray_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_SELECTION_POINT_FLOAT, 1.0f);
}
-MutableSpan<int> CurvesGeometry::surface_triangle_indices_for_write()
+MutableSpan<float> CurvesGeometry::selection_point_float_for_write()
{
- return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
+ return get_mutable_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_SELECTION_POINT_FLOAT, 1.0f);
}
-Span<float2> CurvesGeometry::surface_triangle_coords() const
+VArray<float> CurvesGeometry::selection_curve_float() const
{
- return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE);
+ return get_varray_attribute<float>(*this, ATTR_DOMAIN_CURVE, ATTR_SELECTION_CURVE_FLOAT, 1.0f);
}
-MutableSpan<float2> CurvesGeometry::surface_triangle_coords_for_write()
+MutableSpan<float> CurvesGeometry::selection_curve_float_for_write()
{
- return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE);
+ return get_mutable_attribute<float>(*this, ATTR_DOMAIN_CURVE, ATTR_SELECTION_CURVE_FLOAT, 1.0f);
}
/** \} */
@@ -462,8 +468,8 @@ static void calculate_evaluated_offsets(const CurvesGeometry &curves,
VArray<int> resolution = curves.resolution();
VArray<bool> cyclic = curves.cyclic();
- VArray_Span<int8_t> handle_types_left{curves.handle_types_left()};
- VArray_Span<int8_t> handle_types_right{curves.handle_types_right()};
+ VArraySpan<int8_t> handle_types_left{curves.handle_types_left()};
+ VArraySpan<int8_t> handle_types_right{curves.handle_types_right()};
VArray<int8_t> nurbs_orders = curves.nurbs_orders();
VArray<int8_t> nurbs_knots_modes = curves.nurbs_knots_modes();
@@ -540,16 +546,8 @@ IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
const IndexMask selection,
Vector<int64_t> &r_indices) const
{
- if (this->curve_type_counts()[type] == this->curves_num()) {
- return selection;
- }
- const VArray<int8_t> types = this->curve_types();
- if (types.is_single()) {
- return types.get_internal_single() == type ? IndexMask(this->curves_num()) : IndexMask(0);
- }
- Span<int8_t> types_span = types.get_internal_span();
- return index_mask_ops::find_indices_based_on_predicate(
- selection, 1024, r_indices, [&](const int index) { return types_span[index] == type; });
+ return curves::indices_for_type(
+ this->curve_types(), this->curve_type_counts(), type, selection, r_indices);
}
void CurvesGeometry::ensure_nurbs_basis_cache() const
@@ -954,7 +952,6 @@ void CurvesGeometry::resize(const int points_num, const int curves_num)
this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1));
}
this->tag_topology_changed();
- this->update_customdata_pointers();
}
void CurvesGeometry::tag_positions_changed()
@@ -1006,8 +1003,8 @@ void CurvesGeometry::calculate_bezier_auto_handles()
return;
}
const VArray<bool> cyclic = this->cyclic();
- const VArray_Span<int8_t> types_left{this->handle_types_left()};
- const VArray_Span<int8_t> types_right{this->handle_types_right()};
+ const VArraySpan<int8_t> types_left{this->handle_types_left()};
+ const VArraySpan<int8_t> types_right{this->handle_types_right()};
const Span<float3> positions = this->positions();
MutableSpan<float3> positions_left = this->handle_positions_left_for_write();
MutableSpan<float3> positions_right = this->handle_positions_right_for_write();
@@ -1053,10 +1050,11 @@ void CurvesGeometry::transform(const float4x4 &matrix)
static std::optional<bounds::MinMaxResult<float3>> curves_bounds(const CurvesGeometry &curves)
{
- Span<float3> positions = curves.positions();
- if (curves.radius) {
- Span<float> radii{curves.radius, curves.points_num()};
- return bounds::min_max_with_radii(positions, radii);
+ const Span<float3> positions = curves.positions();
+ const VArray<float> radii = curves.attributes().lookup_or_default<float>(
+ ATTR_RADIUS, ATTR_DOMAIN_POINT, 0.0f);
+ if (!(radii.is_single() && radii.get_internal_single() == 0.0f)) {
+ return bounds::min_max_with_radii(positions, radii.get_internal_span());
}
return bounds::min_max(positions);
}
@@ -1072,19 +1070,9 @@ bool CurvesGeometry::bounds_min_max(float3 &min, float3 &max) const
return true;
}
-void CurvesGeometry::update_customdata_pointers()
-{
- this->position = (float(*)[3])CustomData_get_layer_named(
- &this->point_data, CD_PROP_FLOAT3, ATTR_POSITION.c_str());
- this->radius = (float *)CustomData_get_layer_named(
- &this->point_data, CD_PROP_FLOAT, ATTR_RADIUS.c_str());
- this->curve_type = (int8_t *)CustomData_get_layer_named(
- &this->point_data, CD_PROP_INT8, ATTR_CURVE_TYPE.c_str());
-}
-
static void *ensure_customdata_layer(CustomData &custom_data,
const StringRefNull name,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const int tot_elements)
{
for (const int other_layer_i : IndexRange(custom_data.totlayer)) {
@@ -1097,6 +1085,165 @@ static void *ensure_customdata_layer(CustomData &custom_data,
&custom_data, data_type, CD_DEFAULT, nullptr, tot_elements, name.c_str());
}
+static void copy_between_buffers(const CPPType &type,
+ const void *src_buffer,
+ void *dst_buffer,
+ const IndexRange src_range,
+ const IndexRange dst_range)
+{
+ BLI_assert(src_range.size() == dst_range.size());
+ type.copy_construct_n(POINTER_OFFSET(src_buffer, type.size() * src_range.start()),
+ POINTER_OFFSET(dst_buffer, type.size() * dst_range.start()),
+ src_range.size());
+}
+
+template<typename T>
+static void copy_with_map(const Span<T> src, const Span<int> map, MutableSpan<T> dst)
+{
+ threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[map[i]];
+ }
+ });
+}
+
+static void copy_with_map(const GSpan src, const Span<int> map, GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_with_map(src.typed<T>(), map, dst.typed<T>());
+ });
+}
+
+/**
+ * Builds an array that for every point, contains the corresponding curve index.
+ */
+static Array<int> build_point_to_curve_map(const CurvesGeometry &curves)
+{
+ Array<int> point_to_curve_map(curves.points_num());
+ threading::parallel_for(curves.curves_range(), 1024, [&](const IndexRange curves_range) {
+ for (const int i_curve : curves_range) {
+ point_to_curve_map.as_mutable_span().slice(curves.points_for_curve(i_curve)).fill(i_curve);
+ }
+ });
+ return point_to_curve_map;
+}
+
+static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves,
+ const IndexMask points_to_delete)
+{
+ /* Use a map from points to curves to facilitate using an #IndexMask input. */
+ const Array<int> point_to_curve_map = build_point_to_curve_map(curves);
+
+ const Vector<IndexRange> copy_point_ranges = points_to_delete.extract_ranges_invert(
+ curves.points_range());
+
+ /* For every range of points to copy, find the offset in the result curves point layers. */
+ int new_point_count = 0;
+ Array<int> copy_point_range_dst_offsets(copy_point_ranges.size());
+ for (const int i : copy_point_ranges.index_range()) {
+ copy_point_range_dst_offsets[i] = new_point_count;
+ new_point_count += copy_point_ranges[i].size();
+ }
+ BLI_assert(new_point_count == (curves.points_num() - points_to_delete.size()));
+
+ /* Find out how many non-deleted points there are in every curve. */
+ Array<int> curve_point_counts(curves.curves_num(), 0);
+ for (const IndexRange range : copy_point_ranges) {
+ for (const int point_i : range) {
+ curve_point_counts[point_to_curve_map[point_i]]++;
+ }
+ }
+
+ /* Build the offsets for the new curve points, skipping curves that had all points deleted.
+ * Also store the original indices of the corresponding input curves, to facilitate parallel
+ * copying of curve domain data. */
+ int new_curve_count = 0;
+ int curve_point_offset = 0;
+ Vector<int> new_curve_offsets;
+ Vector<int> new_curve_orig_indices;
+ new_curve_offsets.append(0);
+ for (const int i : curve_point_counts.index_range()) {
+ if (curve_point_counts[i] > 0) {
+ curve_point_offset += curve_point_counts[i];
+ new_curve_offsets.append(curve_point_offset);
+
+ new_curve_count++;
+ new_curve_orig_indices.append(i);
+ }
+ }
+
+ CurvesGeometry new_curves{new_point_count, new_curve_count};
+
+ threading::parallel_invoke(
+ /* Initialize curve offsets. */
+ [&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); },
+ /* Copy over point attributes. */
+ [&]() {
+ const CustomData &old_point_data = curves.point_data;
+ CustomData &new_point_data = new_curves.point_data;
+ for (const int layer_i : IndexRange(old_point_data.totlayer)) {
+ const CustomDataLayer &old_layer = old_point_data.layers[layer_i];
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ void *dst_buffer = ensure_customdata_layer(
+ new_point_data, old_layer.name, data_type, new_point_count);
+
+ threading::parallel_for(
+ copy_point_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
+ for (const int range_i : ranges_range) {
+ const IndexRange src_range = copy_point_ranges[range_i];
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ src_range,
+ {copy_point_range_dst_offsets[range_i], src_range.size()});
+ }
+ });
+ }
+ },
+ /* Copy over curve attributes.
+ * In some cases points are just dissolved, so the the number of
+ * curves will be the same. That could be optimized in the future. */
+ [&]() {
+ const CustomData &old_curve_data = curves.curve_data;
+ CustomData &new_curve_data = new_curves.curve_data;
+ for (const int layer_i : IndexRange(old_curve_data.totlayer)) {
+ const CustomDataLayer &old_layer = old_curve_data.layers[layer_i];
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
+ const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
+
+ void *dst_buffer = ensure_customdata_layer(
+ new_curve_data, old_layer.name, data_type, new_curve_count);
+
+ if (new_curves.curves_num() == curves.curves_num()) {
+ type.copy_construct_n(old_layer.data, dst_buffer, new_curves.curves_num());
+ }
+ else {
+ copy_with_map({type, old_layer.data, curves.curves_num()},
+ new_curve_orig_indices,
+ {type, dst_buffer, new_curves.curves_num()});
+ }
+ }
+ });
+
+ new_curves.update_curve_types();
+
+ return new_curves;
+}
+
+void CurvesGeometry::remove_points(const IndexMask points_to_delete)
+{
+ if (points_to_delete.is_empty()) {
+ return;
+ }
+ if (points_to_delete.size() == this->points_num()) {
+ *this = {};
+ }
+ *this = copy_with_removed_points(*this, points_to_delete);
+}
+
static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
const IndexMask curves_to_delete)
{
@@ -1153,23 +1300,20 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
CustomData &new_point_data = new_curves.point_data;
for (const int layer_i : IndexRange(old_point_data.totlayer)) {
const CustomDataLayer &old_layer = old_point_data.layers[layer_i];
- const CustomDataType data_type = static_cast<CustomDataType>(old_layer.type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
- const void *src_buffer = old_layer.data;
void *dst_buffer = ensure_customdata_layer(
new_point_data, old_layer.name, data_type, new_tot_points);
threading::parallel_for(
old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
for (const int range_i : ranges_range) {
- const IndexRange old_point_range = old_point_ranges[range_i];
- const IndexRange new_point_range = new_point_ranges[range_i];
-
- type.copy_construct_n(
- POINTER_OFFSET(src_buffer, type.size() * old_point_range.start()),
- POINTER_OFFSET(dst_buffer, type.size() * new_point_range.start()),
- old_point_range.size());
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ old_point_ranges[range_i],
+ new_point_ranges[range_i]);
}
});
}
@@ -1180,23 +1324,20 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
CustomData &new_curve_data = new_curves.curve_data;
for (const int layer_i : IndexRange(old_curve_data.totlayer)) {
const CustomDataLayer &old_layer = old_curve_data.layers[layer_i];
- const CustomDataType data_type = static_cast<CustomDataType>(old_layer.type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(old_layer.type);
const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
- const void *src_buffer = old_layer.data;
void *dst_buffer = ensure_customdata_layer(
- new_curve_data, old_layer.name, data_type, new_tot_points);
+ new_curve_data, old_layer.name, data_type, new_tot_curves);
threading::parallel_for(
old_curve_ranges.index_range(), 128, [&](const IndexRange ranges_range) {
for (const int range_i : ranges_range) {
- const IndexRange old_curve_range = old_curve_ranges[range_i];
- const IndexRange new_curve_range = new_curve_ranges[range_i];
-
- type.copy_construct_n(
- POINTER_OFFSET(src_buffer, type.size() * old_curve_range.start()),
- POINTER_OFFSET(dst_buffer, type.size() * new_curve_range.start()),
- old_curve_range.size());
+ copy_between_buffers(type,
+ old_layer.data,
+ dst_buffer,
+ old_curve_ranges[range_i],
+ new_curve_ranges[range_i]);
}
});
}
@@ -1209,6 +1350,13 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
void CurvesGeometry::remove_curves(const IndexMask curves_to_delete)
{
+ if (curves_to_delete.is_empty()) {
+ return;
+ }
+ if (curves_to_delete.size() == this->curves_num()) {
+ *this = {};
+ return;
+ }
*this = copy_with_removed_curves(*this, curves_to_delete);
}
@@ -1246,7 +1394,7 @@ static void reverse_swap_curve_point_data(const CurvesGeometry &curves,
static bool layer_matches_name_and_type(const CustomDataLayer &layer,
const StringRef name,
- const CustomDataType type)
+ const eCustomDataType type)
{
if (layer.type != type) {
return false;
@@ -1289,7 +1437,7 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
continue;
}
- const CustomDataType data_type = static_cast<CustomDataType>(layer.type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(layer.type);
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
reverse_curve_point_data<T>(
@@ -1312,6 +1460,26 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
this->tag_topology_changed();
}
+void CurvesGeometry::remove_attributes_based_on_types()
+{
+ const int points_num = this->points_num();
+ const int curves_num = this->curves_num();
+ if (!this->has_curve_with_type(CURVE_TYPE_BEZIER)) {
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_LEFT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_RIGHT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_LEFT.c_str(), points_num);
+ CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_RIGHT.c_str(), points_num);
+ }
+ if (!this->has_curve_with_type(CURVE_TYPE_NURBS)) {
+ CustomData_free_layer_named(&this->point_data, ATTR_NURBS_WEIGHT.c_str(), points_num);
+ CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_ORDER.c_str(), curves_num);
+ CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_KNOTS_MODE.c_str(), curves_num);
+ }
+ if (!this->has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_NURBS})) {
+ CustomData_free_layer_named(&this->curve_data, ATTR_RESOLUTION.c_str(), curves_num);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1408,8 +1576,8 @@ static GVArray adapt_curve_domain_curve_to_point(const CurvesGeometry &curves,
}
GVArray CurvesGeometry::adapt_domain(const GVArray &varray,
- const AttributeDomain from,
- const AttributeDomain to) const
+ const eAttrDomain from,
+ const eAttrDomain to) const
{
if (!varray) {
return {};
diff --git a/source/blender/blenkernel/intern/curves_geometry_test.cc b/source/blender/blenkernel/intern/curves_geometry_test.cc
index 48493743cfc..2c87fc539fe 100644
--- a/source/blender/blenkernel/intern/curves_geometry_test.cc
+++ b/source/blender/blenkernel/intern/curves_geometry_test.cc
@@ -16,7 +16,7 @@ static CurvesGeometry create_basic_curves(const int points_size, const int curve
const int curve_length = points_size / curves_size;
for (const int i : curves.curves_range()) {
- curves.offsets_for_write()[i] = points_size * curve_length;
+ curves.offsets_for_write()[i] = curve_length * i;
}
curves.offsets_for_write().last() = points_size;
diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc
index 78c2382b62f..d98832e796c 100644
--- a/source/blender/blenkernel/intern/curves_utils.cc
+++ b/source/blender/blenkernel/intern/curves_utils.cc
@@ -4,6 +4,8 @@
* \ingroup bke
*/
+#include "BLI_index_mask_ops.hh"
+
#include "BKE_curves_utils.hh"
namespace blender::bke::curves {
@@ -35,4 +37,102 @@ void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int
counts_to_offsets.last() = offset;
}
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const Span<IndexRange> curve_ranges,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
+ for (const IndexRange range : curve_ranges.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curves(range);
+ const IndexRange dst_points = dst_curves.points_for_curves(range);
+ /* The arrays might be large, so a threaded copy might make sense here too. */
+ dst.slice(dst_points).copy_from(src.slice(src_points));
+ }
+ });
+}
+
+void copy_point_data(const CurvesGeometry &src_curves,
+ const CurvesGeometry &dst_curves,
+ const IndexMask src_curve_selection,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ threading::parallel_for(src_curve_selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : src_curve_selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ /* The arrays might be large, so a threaded copy might make sense here too. */
+ dst.slice(dst_points).copy_from(src.slice(src_points));
+ }
+ });
+}
+
+void fill_points(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ const GPointer value,
+ GMutableSpan dst)
+{
+ BLI_assert(*value.type() == dst.type());
+ const CPPType &type = dst.type();
+ threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : curve_selection.slice(range)) {
+ const IndexRange points = curves.points_for_curve(i);
+ type.fill_assign_n(value.get(), dst.slice(curves.points_for_curve(i)).data(), points.size());
+ }
+ });
+}
+
+bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
+{
+ bke::CurvesGeometry dst_curves(0, src_curves.curves_num());
+ CustomData_copy(&src_curves.curve_data,
+ &dst_curves.curve_data,
+ CD_MASK_ALL,
+ CD_DUPLICATE,
+ src_curves.curves_num());
+ dst_curves.runtime->type_counts = src_curves.runtime->type_counts;
+ return dst_curves;
+}
+
+IndexMask indices_for_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &type_counts,
+ const CurveType type,
+ const IndexMask selection,
+ Vector<int64_t> &r_indices)
+{
+ if (type_counts[type] == types.size()) {
+ return selection;
+ }
+ if (types.is_single()) {
+ return types.get_internal_single() == type ? IndexMask(types.size()) : IndexMask(0);
+ }
+ Span<int8_t> types_span = types.get_internal_span();
+ return index_mask_ops::find_indices_based_on_predicate(
+ selection, 4096, r_indices, [&](const int index) { return types_span[index] == type; });
+}
+
+void foreach_curve_by_type(const VArray<int8_t> &types,
+ const std::array<int, CURVE_TYPES_NUM> &counts,
+ const IndexMask selection,
+ FunctionRef<void(IndexMask)> catmull_rom_fn,
+ FunctionRef<void(IndexMask)> poly_fn,
+ FunctionRef<void(IndexMask)> bezier_fn,
+ FunctionRef<void(IndexMask)> nurbs_fn)
+{
+ Vector<int64_t> indices;
+ auto call_if_not_empty = [&](const CurveType type, FunctionRef<void(IndexMask)> fn) {
+ indices.clear();
+ const IndexMask mask = indices_for_type(types, counts, type, selection, indices);
+ if (!mask.is_empty()) {
+ fn(mask);
+ }
+ };
+ call_if_not_empty(CURVE_TYPE_CATMULL_ROM, catmull_rom_fn);
+ call_if_not_empty(CURVE_TYPE_POLY, poly_fn);
+ call_if_not_empty(CURVE_TYPE_BEZIER, bezier_fn);
+ call_if_not_empty(CURVE_TYPE_NURBS, nurbs_fn);
+}
+
} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 27e8bf96dc6..277218033e9 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -20,12 +20,15 @@
#include "BLI_bitmap.h"
#include "BLI_color.hh"
#include "BLI_endian_switch.h"
+#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_math_vector.hh"
#include "BLI_mempool.h"
#include "BLI_path_util.h"
+#include "BLI_span.hh"
#include "BLI_string.h"
+#include "BLI_string_ref.hh"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
@@ -54,6 +57,11 @@
/* only for customdata_data_transfer_interp_normal_normals */
#include "data_transfer_intern.h"
+using blender::IndexRange;
+using blender::Span;
+using blender::StringRef;
+using blender::Vector;
+
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
@@ -256,8 +264,8 @@ static void layerInterp_mdeformvert(const void **sources,
};
MDeformVert *dvert = static_cast<MDeformVert *>(dest);
- struct MDeformWeight_Link *dest_dwlink = nullptr;
- struct MDeformWeight_Link *node;
+ MDeformWeight_Link *dest_dwlink = nullptr;
+ MDeformWeight_Link *node;
/* build a list of unique def_nrs for dest */
int totweight = 0;
@@ -284,7 +292,7 @@ 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 = static_cast<MDeformWeight_Link *>(
+ 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;
@@ -517,6 +525,22 @@ static void layerCopy_propInt(const void *source, void *dest, int count)
memcpy(dest, source, sizeof(MIntProperty) * count);
}
+static void layerInterp_propInt(const void **sources,
+ const float *weights,
+ const float *UNUSED(sub_weights),
+ int count,
+ void *dest)
+{
+ float result = 0.0f;
+ for (const int i : IndexRange(count)) {
+ const float weight = weights[i];
+ const float src = *static_cast<const int *>(sources[i]);
+ result += src * weight;
+ }
+ const int rounded_result = static_cast<int>(round(result));
+ *static_cast<int *>(dest) = rounded_result;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1679,7 +1703,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
N_("Int"),
layerCopy_propInt,
nullptr,
- nullptr,
+ layerInterp_propInt,
nullptr},
/* 12: CD_PROP_STRING */
{sizeof(MStringProperty),
@@ -2216,9 +2240,9 @@ static bool customdata_typemap_is_valid(const CustomData *data)
}
#endif
-bool CustomData_merge(const struct CustomData *source,
- struct CustomData *dest,
- CustomDataMask mask,
+bool CustomData_merge(const CustomData *source,
+ CustomData *dest,
+ eCustomDataMask mask,
eCDAllocType alloctype,
int totelem)
{
@@ -2305,6 +2329,7 @@ bool CustomData_merge(const struct CustomData *source,
void CustomData_realloc(CustomData *data, int totelem)
{
+ BLI_assert(totelem >= 0);
for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
const LayerTypeInfo *typeInfo;
@@ -2318,9 +2343,9 @@ void CustomData_realloc(CustomData *data, int totelem)
}
}
-void CustomData_copy(const struct CustomData *source,
- struct CustomData *dest,
- CustomDataMask mask,
+void CustomData_copy(const CustomData *source,
+ CustomData *dest,
+ eCustomDataMask mask,
eCDAllocType alloctype,
int totelem)
{
@@ -2382,7 +2407,7 @@ void CustomData_free(CustomData *data, int totelem)
CustomData_reset(data);
}
-void CustomData_free_typemask(struct CustomData *data, int totelem, CustomDataMask mask)
+void CustomData_free_typemask(CustomData *data, int totelem, eCustomDataMask mask)
{
for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
@@ -2437,7 +2462,7 @@ int CustomData_get_layer_index(const CustomData *data, int type)
return data->typemap[type];
}
-int CustomData_get_layer_index_n(const struct CustomData *data, int type, int n)
+int CustomData_get_layer_index_n(const CustomData *data, int type, int n)
{
BLI_assert(n >= 0);
int i = CustomData_get_layer_index(data, type);
@@ -2494,7 +2519,7 @@ int CustomData_get_stencil_layer_index(const CustomData *data, int type)
/* -------------------------------------------------------------------- */
/* index values per layer type */
-int CustomData_get_named_layer(const struct CustomData *data, int type, const char *name)
+int CustomData_get_named_layer(const CustomData *data, int type, const char *name)
{
const int named_index = CustomData_get_named_layer_index(data, type, name);
const int layer_index = data->typemap[type];
@@ -2530,7 +2555,7 @@ int CustomData_get_stencil_layer(const CustomData *data, int type)
return (layer_index != -1) ? data->layers[layer_index].active_mask : -1;
}
-const char *CustomData_get_active_layer_name(const struct CustomData *data, const int type)
+const char *CustomData_get_active_layer_name(const CustomData *data, const int type)
{
/* Get the layer index of the active layer of this type. */
const int layer_index = CustomData_get_active_layer_index(data, type);
@@ -2621,7 +2646,7 @@ void CustomData_set_layer_stencil_index(CustomData *data, int type, int n)
}
}
-void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
+void CustomData_set_layer_flag(CustomData *data, int type, int flag)
{
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].type == type) {
@@ -2630,7 +2655,7 @@ 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_clear_layer_flag(CustomData *data, int type, int flag)
{
const int nflag = ~flag;
@@ -2805,7 +2830,7 @@ void *CustomData_add_layer_named(CustomData *data,
return nullptr;
}
-void *CustomData_add_layer_anonymous(struct CustomData *data,
+void *CustomData_add_layer_anonymous(CustomData *data,
int type,
eCDAllocType alloctype,
void *layerdata,
@@ -2878,6 +2903,18 @@ bool CustomData_free_layer(CustomData *data, int type, int totelem, int index)
return true;
}
+bool CustomData_free_layer_named(CustomData *data, const char *name, const int totelem)
+{
+ for (const int i : IndexRange(data->totlayer)) {
+ const CustomDataLayer &layer = data->layers[i];
+ if (StringRef(layer.name) == name) {
+ CustomData_free_layer(data, layer.type, totelem, i);
+ return true;
+ }
+ }
+ return false;
+}
+
bool CustomData_free_layer_active(CustomData *data, int type, int totelem)
{
const int index = CustomData_get_active_layer_index(data, type);
@@ -2913,7 +2950,7 @@ int CustomData_number_of_layers(const CustomData *data, int type)
return number;
}
-int CustomData_number_of_layers_typemask(const CustomData *data, CustomDataMask mask)
+int CustomData_number_of_layers_typemask(const CustomData *data, eCustomDataMask mask)
{
int number = 0;
@@ -3011,7 +3048,7 @@ void CustomData_duplicate_referenced_layers(CustomData *data, int totelem)
}
}
-bool CustomData_is_referenced_layer(struct CustomData *data, int type)
+bool CustomData_is_referenced_layer(CustomData *data, int type)
{
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
@@ -3056,7 +3093,7 @@ void CustomData_free_temporary(CustomData *data, int totelem)
}
}
-void CustomData_set_only_copy(const struct CustomData *data, CustomDataMask mask)
+void CustomData_set_only_copy(const CustomData *data, eCustomDataMask mask)
{
for (int i = 0; i < data->totlayer; i++) {
if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type))) {
@@ -3289,7 +3326,7 @@ void CustomData_interp(const CustomData *source,
}
}
-void CustomData_swap_corners(struct CustomData *data, int index, const int *corner_indices)
+void CustomData_swap_corners(CustomData *data, int index, const int *corner_indices)
{
for (int i = 0; i < data->totlayer; i++) {
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type);
@@ -3302,7 +3339,7 @@ void CustomData_swap_corners(struct CustomData *data, int index, const int *corn
}
}
-void CustomData_swap(struct CustomData *data, const int index_a, const int index_b)
+void CustomData_swap(CustomData *data, const int index_a, const int index_b)
{
char buff_static[256];
@@ -3381,7 +3418,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n)
return data->layers[layer_index].data;
}
-void *CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
+void *CustomData_get_layer_named(const CustomData *data, int type, const char *name)
{
int layer_index = CustomData_get_named_layer_index(data, type, name);
if (layer_index == -1) {
@@ -3448,7 +3485,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
return ptr;
}
-void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr)
+void *CustomData_set_layer_n(const CustomData *data, int type, int n, void *ptr)
{
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
@@ -3480,97 +3517,6 @@ void CustomData_set(const CustomData *data, int index, int type, const void *sou
/* BMesh functions */
-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, nullptr, totloop, fdata->layers[i].name);
- }
- else if (fdata->layers[i].type == CD_MCOL) {
- CustomData_add_layer_named(
- ldata, CD_PROP_BYTE_COLOR, 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, nullptr, totloop, fdata->layers[i].name);
- }
- else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) {
- CustomData_add_layer_named(
- ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
- }
- }
-}
-
-void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
-{
- /* avoid accumulating extra layers */
- BLI_assert(!CustomData_from_bmeshpoly_test(fdata, ldata, false));
-
- for (int i = 0; i < ldata->totlayer; i++) {
- if (ldata->layers[i].type == CD_MLOOPUV) {
- CustomData_add_layer_named(
- fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
- }
- if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) {
- 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, nullptr, total, ldata->layers[i].name);
- }
- else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
- CustomData_add_layer_named(
- 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, nullptr, total, ldata->layers[i].name);
- }
- else if (ldata->layers[i].type == CD_TANGENT) {
- CustomData_add_layer_named(
- fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name);
- }
- }
-
- CustomData_bmesh_update_active_layers(fdata, ldata);
-}
-
-#ifndef NDEBUG
-bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *ldata, bool fallback)
-{
- int a_num = 0, b_num = 0;
-# define LAYER_CMP(l_a, t_a, l_b, t_b) \
- ((a_num += CustomData_number_of_layers(l_a, t_a)) == \
- (b_num += CustomData_number_of_layers(l_b, t_b)))
-
- if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE)) {
- return false;
- }
- if (!LAYER_CMP(ldata, CD_PROP_BYTE_COLOR, fdata, CD_MCOL)) {
- return false;
- }
- if (!LAYER_CMP(ldata, CD_PREVIEW_MLOOPCOL, fdata, CD_PREVIEW_MCOL)) {
- return false;
- }
- if (!LAYER_CMP(ldata, CD_ORIGSPACE_MLOOP, fdata, CD_ORIGSPACE)) {
- return false;
- }
- if (!LAYER_CMP(ldata, CD_NORMAL, fdata, CD_TESSLOOPNORMAL)) {
- return false;
- }
- if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT)) {
- return false;
- }
-
-# undef LAYER_CMP
-
- /* if no layers are on either CustomData's,
- * then there was nothing to do... */
- return a_num ? true : fallback;
-}
-#endif
-
void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
{
int act;
@@ -3604,39 +3550,6 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata)
}
}
-void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
-{
- int act;
-
- if (CustomData_has_layer(fdata, CD_MTFACE)) {
- act = CustomData_get_active_layer(fdata, CD_MTFACE);
- CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_render_layer(fdata, CD_MTFACE);
- CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_clone_layer(fdata, CD_MTFACE);
- CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
-
- act = CustomData_get_stencil_layer(fdata, CD_MTFACE);
- CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
- }
-
- if (CustomData_has_layer(fdata, CD_MCOL)) {
- act = CustomData_get_active_layer(fdata, CD_MCOL);
- CustomData_set_layer_active(ldata, CD_PROP_BYTE_COLOR, act);
-
- act = CustomData_get_render_layer(fdata, CD_MCOL);
- CustomData_set_layer_render(ldata, CD_PROP_BYTE_COLOR, act);
-
- act = CustomData_get_clone_layer(fdata, CD_MCOL);
- CustomData_set_layer_clone(ldata, CD_PROP_BYTE_COLOR, act);
-
- act = CustomData_get_stencil_layer(fdata, CD_MCOL);
- CustomData_set_layer_stencil(ldata, CD_PROP_BYTE_COLOR, act);
- }
-}
-
void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
{
int chunksize;
@@ -3671,7 +3584,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
bool CustomData_bmesh_merge(const CustomData *source,
CustomData *dest,
- CustomDataMask mask,
+ eCustomDataMask mask,
eCDAllocType alloctype,
BMesh *bm,
const char htype)
@@ -3820,7 +3733,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
void *block,
- const CustomDataMask mask_exclude)
+ const eCustomDataMask mask_exclude)
{
if (block == nullptr) {
return;
@@ -3867,7 +3780,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
CustomData *dest,
void *src_block,
void **dest_block,
- const CustomDataMask mask_exclude)
+ const eCustomDataMask mask_exclude)
{
/* Note that having a version of this function without a 'mask_exclude'
* would cause too much duplicate code, so add a check instead. */
@@ -3965,7 +3878,7 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
return POINTER_OFFSET(block, data->layers[n].offset);
}
-bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
+bool CustomData_layer_has_math(const CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -3977,7 +3890,7 @@ bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
return false;
}
-bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
+bool CustomData_layer_has_interp(const CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -3988,7 +3901,7 @@ bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
return false;
}
-bool CustomData_has_math(const struct CustomData *data)
+bool CustomData_has_math(const CustomData *data)
{
/* interpolates a layer at a time */
for (int i = 0; i < data->totlayer; i++) {
@@ -4000,7 +3913,7 @@ bool CustomData_has_math(const struct CustomData *data)
return false;
}
-bool CustomData_bmesh_has_free(const struct CustomData *data)
+bool CustomData_bmesh_has_free(const CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
if (!(data->layers[i].flag & CD_FLAG_NOFREE)) {
@@ -4013,7 +3926,7 @@ bool CustomData_bmesh_has_free(const struct CustomData *data)
return false;
}
-bool CustomData_has_interp(const struct CustomData *data)
+bool CustomData_has_interp(const CustomData *data)
{
/* interpolates a layer at a time */
for (int i = 0; i < data->totlayer; i++) {
@@ -4025,7 +3938,7 @@ bool CustomData_has_interp(const struct CustomData *data)
return false;
}
-bool CustomData_has_referenced(const struct CustomData *data)
+bool CustomData_has_referenced(const CustomData *data)
{
for (int i = 0; i < data->totlayer; i++) {
if (data->layers[i].flag & CD_FLAG_NOFREE) {
@@ -4349,45 +4262,19 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str
*r_struct_num = typeInfo->structnum;
}
-void CustomData_blend_write_prepare(CustomData *data,
- CustomDataLayer **r_write_layers,
- CustomDataLayer *write_layers_buff,
- size_t write_layers_size)
+void CustomData_blend_write_prepare(CustomData &data, Vector<CustomDataLayer, 16> &layers_to_write)
{
- CustomDataLayer *write_layers = write_layers_buff;
- const size_t chunk_size = (write_layers_size > 0) ? write_layers_size : CD_TEMP_CHUNK_SIZE;
-
- const int totlayer = data->totlayer;
- int i, j;
-
- 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 != nullptr) {
- data->totlayer--;
- // CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name);
+ for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) {
+ if (layer.flag & CD_FLAG_NOCOPY) {
+ continue;
}
- else {
- if (UNLIKELY((size_t)j >= write_layers_size)) {
- if (write_layers == write_layers_buff) {
- 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 = (CustomDataLayer *)MEM_reallocN(
- write_layers, sizeof(*write_layers) * (write_layers_size + chunk_size));
- }
- write_layers_size += chunk_size;
- }
- write_layers[j++] = *layer;
+ if (layer.anonymous_id != nullptr) {
+ continue;
}
+ layers_to_write.append(layer);
}
- BLI_assert(j == data->totlayer);
- data->maxlayer = data->totlayer; /* We only write that much of data! */
- *r_write_layers = write_layers;
+ data.totlayer = layers_to_write.size();
+ data.maxlayer = data.totlayer;
}
int CustomData_sizeof(int type)
@@ -4510,7 +4397,7 @@ void CustomData_validate_layer_name(const CustomData *data,
}
}
-bool CustomData_verify_versions(struct CustomData *data, int index)
+bool CustomData_verify_versions(CustomData *data, int index)
{
const LayerTypeInfo *typeInfo;
CustomDataLayer *layer = &data->layers[index];
@@ -4605,7 +4492,10 @@ static void customdata_external_filename(char filepath[FILE_MAX],
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(id));
}
-void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask mask, int totelem)
+void CustomData_external_reload(CustomData *data,
+ ID *UNUSED(id),
+ eCustomDataMask mask,
+ int totelem)
{
for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
@@ -4623,7 +4513,7 @@ void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask
}
}
-void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int totelem)
+void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, int totelem)
{
CustomDataExternal *external = data->external;
CustomDataLayer *layer;
@@ -4697,7 +4587,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
}
void CustomData_external_write(
- CustomData *data, ID *id, CustomDataMask mask, int totelem, int free)
+ CustomData *data, ID *id, eCustomDataMask mask, int totelem, int free)
{
CustomDataExternal *external = data->external;
int update = 0;
@@ -5186,9 +5076,9 @@ static void write_grid_paint_mask(BlendWriter *writer,
void CustomData_blend_write(BlendWriter *writer,
CustomData *data,
- CustomDataLayer *layers,
+ Span<CustomDataLayer> layers_to_write,
int count,
- CustomDataMask cddata_mask,
+ eCustomDataMask cddata_mask,
ID *id)
{
/* write external customdata (not for undo) */
@@ -5196,55 +5086,50 @@ void CustomData_blend_write(BlendWriter *writer,
CustomData_external_write(data, id, cddata_mask, count, 0);
}
- BLO_write_struct_array_at_address(writer, CustomDataLayer, data->totlayer, data->layers, layers);
+ BLO_write_struct_array_at_address(
+ writer, CustomDataLayer, data->totlayer, data->layers, layers_to_write.data());
- for (int i = 0; i < data->totlayer; i++) {
- CustomDataLayer *layer = &layers[i];
-
- if (layer->type == CD_MDEFORMVERT) {
- /* layer types that allocate own memory need special handling */
- BKE_defvert_blend_write(writer, count, static_cast<const MDeformVert *>(layer->data));
- }
- else if (layer->type == CD_MDISPS) {
- write_mdisps(
- writer, count, static_cast<const MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
- }
- else if (layer->type == CD_PAINT_MASK) {
- 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 = 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, static_cast<const GridPaintMask *>(layer->data));
- }
- else if (layer->type == CD_FACEMAP) {
- 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 = 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 {
- const char *structname;
- int structnum;
- CustomData_file_write_info(layer->type, &structname, &structnum);
- if (structnum) {
- int datasize = structnum * count;
- BLO_write_struct_array_by_name(writer, structname, datasize, layer->data);
- }
- else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */
- printf("%s error: layer '%s':%d - can't be written to file\n",
- __func__,
- structname,
- layer->type);
+ for (const CustomDataLayer &layer : layers_to_write) {
+ switch (layer.type) {
+ case CD_MDEFORMVERT:
+ BKE_defvert_blend_write(writer, count, static_cast<const MDeformVert *>(layer.data));
+ break;
+ case CD_MDISPS:
+ write_mdisps(
+ writer, count, static_cast<const MDisps *>(layer.data), layer.flag & CD_FLAG_EXTERNAL);
+ break;
+ case CD_PAINT_MASK:
+ BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
+ break;
+ case CD_SCULPT_FACE_SETS:
+ BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
+ break;
+ case CD_GRID_PAINT_MASK:
+ write_grid_paint_mask(writer, count, static_cast<const GridPaintMask *>(layer.data));
+ break;
+ case CD_FACEMAP:
+ BLO_write_raw(writer, sizeof(int) * count, static_cast<const int *>(layer.data));
+ break;
+ case CD_PROP_BOOL:
+ BLO_write_raw(writer, sizeof(bool) * count, static_cast<const bool *>(layer.data));
+ break;
+ case CD_CREASE:
+ BLO_write_raw(writer, sizeof(float) * count, static_cast<const float *>(layer.data));
+ break;
+ default: {
+ const char *structname;
+ int structnum;
+ CustomData_file_write_info(layer.type, &structname, &structnum);
+ if (structnum) {
+ int datasize = structnum * count;
+ BLO_write_struct_array_by_name(writer, structname, datasize, layer.data);
+ }
+ else if (!BLO_write_is_undo(writer)) { /* Do not warn on undo. */
+ printf("%s error: layer '%s':%d - can't be written to file\n",
+ __func__,
+ structname,
+ layer.type);
+ }
}
}
}
@@ -5394,7 +5279,7 @@ namespace blender::bke {
/** \name Custom Data C++ API
* \{ */
-const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
+const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT:
@@ -5419,7 +5304,7 @@ const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
return nullptr;
}
-CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
+eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
{
if (type.is<float>()) {
return CD_PROP_FLOAT;
@@ -5445,7 +5330,7 @@ CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<ColorGeometry4b>()) {
return CD_PROP_BYTE_COLOR;
}
- return static_cast<CustomDataType>(-1);
+ return static_cast<eCustomDataType>(-1);
}
/** \} */
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 196a6a00ade..17a74b5564a 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -1410,7 +1410,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, &me_src_mask);
if (is_modifier) {
- me_src = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_src, false);
+ me_src = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_src);
if (me_src == NULL ||
!CustomData_MeshMasks_are_matching(&ob_src->runtime.last_data_mask, &me_src_mask)) {
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 63aa03483b2..823fce52b50 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -30,6 +30,7 @@
#include "BKE_anim_path.h"
#include "BKE_curve.h"
+#include "BKE_curve_legacy_convert.hh"
#include "BKE_displist.h"
#include "BKE_geometry_set.hh"
#include "BKE_key.h"
@@ -40,7 +41,6 @@
#include "BKE_mesh.h"
#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. */
@@ -863,9 +863,8 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
geometry_set.replace_mesh(mesh);
}
else {
- std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve(
- *cu, ob->runtime.curve_cache->deformed_nurbs);
- geometry_set.replace_curves(curve_eval_to_curves(*curve_eval));
+ geometry_set.replace_curves(
+ blender::bke::curve_legacy_to_curves(*cu, ob->runtime.curve_cache->deformed_nurbs));
}
for (; md; md = md->next) {
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 48f2d66c1cd..423e76fce8c 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2024,13 +2024,13 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
settings.use_threading = (sData->total_points > 1000);
BLI_task_parallel_range(
0, sData->total_points, &data, dynamic_paint_apply_surface_wave_cb, &settings);
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_tag_coords_changed(result);
}
/* displace */
if (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE) {
dynamicPaint_applySurfaceDisplace(surface, result);
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_tag_coords_changed(result);
}
}
}
@@ -2552,7 +2552,7 @@ static void dynamic_paint_find_island_border(const DynamicPaintCreateUVSurfaceDa
const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v;
/* Use a pre-computed vert-to-looptri mapping,
- * speeds up things a lot compared to looping over all loopti. */
+ * speeds up things a lot compared to looping over all looptri. */
const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0];
bool found_other = false;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index f2915a97746..7722c2fa004 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -868,8 +868,6 @@ static void do_texture_effector(EffectorCache *eff,
return;
}
- result[0].nor = result[1].nor = result[2].nor = result[3].nor = NULL;
-
strength = eff->pd->f_strength * efd->falloff;
copy_v3_v3(tex_co, point->loc);
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 34357c3e454..972ff377519 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -229,16 +229,13 @@ FCurve *id_data_find_fcurve(
return NULL;
}
- /* Animation takes priority over drivers. */
- if (adt->action && adt->action->curves.first) {
- fcu = BKE_fcurve_find(&adt->action->curves, path, index);
- }
-
- /* If not animated, check if driven. */
- if (fcu == NULL && adt->drivers.first) {
- fcu = BKE_fcurve_find(&adt->drivers, path, index);
- if (fcu && r_driven) {
- *r_driven = true;
+ /* FIXME: The way drivers are handled here (always NULL-ifying `fcu`) is very weird, this needs
+ * to be re-checked I think?. */
+ bool is_driven = false;
+ fcu = BKE_animadata_fcurve_find_by_rna_path(adt, path, index, NULL, &is_driven);
+ if (is_driven) {
+ if (r_driven != NULL) {
+ *r_driven = is_driven;
}
fcu = NULL;
}
@@ -259,12 +256,11 @@ FCurve *BKE_fcurve_find(ListBase *list, const char rna_path[], const int array_i
/* Check paths of curves, then array indices... */
for (fcu = list->first; fcu; fcu = fcu->next) {
+ /* Check indices first, much cheaper than a string comparison. */
/* Simple string-compare (this assumes that they have the same root...) */
- if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
- /* Now check indices. */
- if (fcu->array_index == array_index) {
- return fcu;
- }
+ if (UNLIKELY(fcu->array_index == array_index && fcu->rna_path &&
+ fcu->rna_path[0] == rna_path[0] && STREQ(fcu->rna_path, rna_path))) {
+ return fcu;
}
}
@@ -339,6 +335,47 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con
return matches;
}
+FCurve *BKE_animadata_fcurve_find_by_rna_path(
+ AnimData *animdata, const char *rna_path, int rna_index, bAction **r_action, bool *r_driven)
+{
+ if (r_driven != NULL) {
+ *r_driven = false;
+ }
+ if (r_action != NULL) {
+ *r_action = NULL;
+ }
+
+ const bool has_action_fcurves = animdata->action != NULL &&
+ !BLI_listbase_is_empty(&animdata->action->curves);
+ const bool has_drivers = !BLI_listbase_is_empty(&animdata->drivers);
+
+ /* Animation takes priority over drivers. */
+ if (has_action_fcurves) {
+ FCurve *fcu = BKE_fcurve_find(&animdata->action->curves, rna_path, rna_index);
+
+ if (fcu != NULL) {
+ if (r_action != NULL) {
+ *r_action = animdata->action;
+ }
+ return fcu;
+ }
+ }
+
+ /* If not animated, check if driven. */
+ if (has_drivers) {
+ FCurve *fcu = BKE_fcurve_find(&animdata->drivers, rna_path, rna_index);
+
+ if (fcu != NULL) {
+ if (r_driven != NULL) {
+ *r_driven = true;
+ }
+ return fcu;
+ }
+ }
+
+ return NULL;
+}
+
FCurve *BKE_fcurve_find_by_rna(PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
@@ -351,8 +388,8 @@ FCurve *BKE_fcurve_find_by_rna(PointerRNA *ptr,
NULL, ptr, prop, rnaindex, r_adt, r_action, r_driven, r_special);
}
-FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
- PointerRNA *ptr,
+FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *UNUSED(C),
+ const PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
AnimData **r_animdata,
@@ -360,18 +397,18 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
bool *r_driven,
bool *r_special)
{
- FCurve *fcu = NULL;
- PointerRNA tptr = *ptr;
-
- *r_driven = false;
- *r_special = false;
-
- if (r_animdata) {
+ if (r_animdata != NULL) {
*r_animdata = NULL;
}
- if (r_action) {
+ if (r_action != NULL) {
*r_action = NULL;
}
+ if (r_driven != NULL) {
+ *r_driven = false;
+ }
+ if (r_special) {
+ *r_special = false;
+ }
/* Special case for NLA Control Curves... */
if (BKE_nlastrip_has_curves_for_property(ptr, prop)) {
@@ -380,87 +417,46 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
/* Set the special flag, since it cannot be a normal action/driver
* if we've been told to start looking here...
*/
- *r_special = true;
+ if (r_special) {
+ *r_special = true;
+ }
+
+ *r_driven = false;
+ if (r_animdata) {
+ *r_animdata = NULL;
+ }
+ if (r_action) {
+ *r_action = NULL;
+ }
/* The F-Curve either exists or it doesn't here... */
- fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
- return fcu;
+ return BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), rnaindex);
}
/* There must be some RNA-pointer + property combo. */
- if (prop && tptr.owner_id && RNA_property_animateable(&tptr, prop)) {
- AnimData *adt = BKE_animdata_from_id(tptr.owner_id);
- int step = (
- /* Always 1 in case we have no context (can't check in 'ancestors' of given RNA ptr). */
- C ? 2 : 1);
- char *path = NULL;
-
- if (!adt && C) {
- path = RNA_path_from_ID_to_property(&tptr, prop);
- adt = BKE_animdata_from_id(tptr.owner_id);
- step--;
- }
-
- /* Standard F-Curve - Animation (Action) or Drivers. */
- while (adt && step--) {
- if ((adt->action == NULL || adt->action->curves.first == NULL) &&
- (adt->drivers.first == NULL)) {
- continue;
- }
-
- /* XXX This function call can become a performance bottleneck. */
- if (step) {
- path = RNA_path_from_ID_to_property(&tptr, prop);
- }
- if (path == NULL) {
- continue;
- }
-
- /* XXX: The logic here is duplicated with a function up above. */
- /* animation takes priority over drivers. */
- if (adt->action && adt->action->curves.first) {
- fcu = BKE_fcurve_find(&adt->action->curves, path, rnaindex);
-
- if (fcu && r_action) {
- *r_action = adt->action;
- }
- }
+ if (!prop || !ptr->owner_id || !RNA_property_animateable(ptr, prop)) {
+ return NULL;
+ }
- /* If not animated, check if driven. */
- if (!fcu && (adt->drivers.first)) {
- fcu = BKE_fcurve_find(&adt->drivers, path, rnaindex);
+ AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
+ if (adt == NULL) {
+ return NULL;
+ }
- if (fcu) {
- if (r_animdata) {
- *r_animdata = adt;
- }
- *r_driven = true;
- }
- }
+ /* XXX This function call can become a performance bottleneck. */
+ char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+ if (rna_path == NULL) {
+ return NULL;
+ }
- if (fcu && r_action) {
- if (r_animdata) {
- *r_animdata = adt;
- }
- *r_action = adt->action;
- break;
- }
+ /* Standard F-Curve from animdata - Animation (Action) or Drivers. */
+ FCurve *fcu = BKE_animadata_fcurve_find_by_rna_path(adt, rna_path, rnaindex, r_action, r_driven);
- if (step) {
- char *tpath = path ? path : RNA_path_from_ID_to_property(&tptr, prop);
- if (tpath && tpath != path) {
- MEM_freeN(path);
- path = tpath;
- adt = BKE_animdata_from_id(tptr.owner_id);
- }
- else {
- adt = NULL;
- }
- }
- }
- MEM_SAFE_FREE(path);
+ if (fcu != NULL && r_animdata != NULL) {
+ *r_animdata = adt;
}
+ MEM_freeN(rna_path);
return fcu;
}
@@ -1028,9 +1024,8 @@ static void UNUSED_FUNCTION(bezt_add_to_cfra_elem)(ListBase *lb, BezTriple *bezt
* \{ */
/* Some utilities for working with FPoints (i.e. 'sampled' animation curve data, such as
- * data imported from BVH/Mocap files), which are specialized for use with high density datasets,
- * which BezTriples/Keyframe data are ill equipped to do.
- */
+ * data imported from BVH/motion-capture files), which are specialized for use with high density
+ * datasets, which BezTriples/Keyframe data are ill equipped to do. */
float fcurve_samplingcb_evalcurve(FCurve *fcu, void *UNUSED(data), float evaltime)
{
@@ -1151,7 +1146,7 @@ void fcurve_samples_to_keyframes(FCurve *fcu, const int start, const int end)
MEM_SAFE_FREE(fcu->fpt);
/* Not strictly needed since we use linear interpolation, but better be consistent here. */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* ***************************** F-Curve Sanity ********************************* */
@@ -1221,7 +1216,7 @@ static BezTriple *cycle_offset_triple(
return out;
}
-void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
+void BKE_fcurve_handles_recalc_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
{
BezTriple *bezt, *prev, *next;
int a = fcu->totvert;
@@ -1304,9 +1299,9 @@ void calchandles_fcurve_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
}
}
-void calchandles_fcurve(FCurve *fcu)
+void BKE_fcurve_handles_recalc(FCurve *fcu)
{
- calchandles_fcurve_ex(fcu, SELECT);
+ BKE_fcurve_handles_recalc_ex(fcu, SELECT);
}
void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_handle)
@@ -1325,7 +1320,7 @@ void testhandles_fcurve(FCurve *fcu, eBezTriple_Flag sel_flag, const bool use_ha
}
/* Recalculate handles. */
- calchandles_fcurve_ex(fcu, sel_flag);
+ BKE_fcurve_handles_recalc_ex(fcu, sel_flag);
}
void sort_time_fcurve(FCurve *fcu)
@@ -1595,6 +1590,12 @@ static void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
}
}
+static void fcurve_bezt_free(FCurve *fcu)
+{
+ MEM_SAFE_FREE(fcu->bezt);
+ fcu->totvert = 0;
+}
+
bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
struct BezTriple *prev,
struct BezTriple *next,
@@ -1656,6 +1657,69 @@ bool BKE_fcurve_bezt_subdivide_handles(struct BezTriple *bezt,
return true;
}
+void BKE_fcurve_delete_key(FCurve *fcu, int index)
+{
+ /* sanity check */
+ if (fcu == NULL) {
+ return;
+ }
+
+ /* verify the index:
+ * 1) cannot be greater than the number of available keyframes
+ * 2) negative indices are for specifying a value from the end of the array
+ */
+ if (abs(index) >= fcu->totvert) {
+ return;
+ }
+ if (index < 0) {
+ index += fcu->totvert;
+ }
+
+ /* Delete this keyframe */
+ memmove(
+ &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
+ fcu->totvert--;
+
+ /* Free the array of BezTriples if there are not keyframes */
+ if (fcu->totvert == 0) {
+ fcurve_bezt_free(fcu);
+ }
+}
+
+bool BKE_fcurve_delete_keys_selected(FCurve *fcu)
+{
+ bool changed = false;
+
+ if (fcu->bezt == NULL) { /* ignore baked curves */
+ return false;
+ }
+
+ /* Delete selected BezTriples */
+ for (int i = 0; i < fcu->totvert; i++) {
+ if (fcu->bezt[i].f2 & SELECT) {
+ if (i == fcu->active_keyframe_index) {
+ BKE_fcurve_active_keyframe_set(fcu, NULL);
+ }
+ memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
+ fcu->totvert--;
+ i--;
+ changed = true;
+ }
+ }
+
+ /* Free the array of BezTriples if there are not keyframes */
+ if (fcu->totvert == 0) {
+ fcurve_bezt_free(fcu);
+ }
+
+ return changed;
+}
+
+void BKE_fcurve_delete_keys_all(FCurve *fcu)
+{
+ fcurve_bezt_free(fcu);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 06d32d5bfd4..8e95bf18c6b 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1942,7 +1942,6 @@ static void sample_mesh(FluidFlowSettings *ffs,
tex_co[1] = tex_co[1] * 2.0f - 1.0f;
tex_co[2] = ffs->texture_offset;
}
- texres.nor = NULL;
BKE_texture_get_value(NULL, ffs->noise_texture, tex_co, &texres, false);
emission_strength *= texres.tin;
}
@@ -3762,16 +3761,16 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
MEM_freeN(objs);
}
- /* TODO(sebbas): Cache reset for when flow / effector object need update flag is set. */
-# if 0
- /* If the just updated flags now carry the 'outdated' flag, reset the cache here!
- * Plus sanity check: Do not clear cache on file load. */
- if (fds->cache_flag & FLUID_DOMAIN_OUTDATED_DATA &&
- ((fds->flags & FLUID_DOMAIN_FILE_LOAD) == 0)) {
- BKE_fluid_cache_free_all(fds, ob);
- BKE_fluid_modifier_reset_ex(fmd, false);
+ /* If 'outdated', reset the cache here. */
+ if (is_startframe && mode == FLUID_DOMAIN_CACHE_REPLAY) {
+ PTCacheID pid;
+ BKE_ptcache_id_from_smoke(&pid, ob, fmd);
+ if (pid.cache->flag & PTCACHE_OUTDATED) {
+ BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
+ BKE_fluid_cache_free_all(fds, ob);
+ BKE_fluid_modifier_reset_ex(fmd, false);
+ }
}
-# endif
/* Fluid domain init must not fail in order to continue modifier evaluation. */
if (!fds->fluid && !BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me)) {
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
index 1bb7c49d616..e4c7572b9e4 100644
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ b/source/blender/blenkernel/intern/fmodifier.c
@@ -1127,7 +1127,7 @@ FModifier *add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
/* update the fcurve if the Cycles modifier is added */
if ((owner_fcu) && (type == FMODIFIER_TYPE_CYCLES)) {
- calchandles_fcurve(owner_fcu);
+ BKE_fcurve_handles_recalc(owner_fcu);
}
/* return modifier for further editing */
@@ -1215,7 +1215,7 @@ bool remove_fmodifier(ListBase *modifiers, FModifier *fcm)
/* update the fcurve if the Cycles modifier is removed */
if (update_fcu) {
- calchandles_fcurve(update_fcu);
+ BKE_fcurve_handles_recalc(update_fcu);
}
return true;
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index a28afc8ddca..22f105af0f1 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -5,7 +5,6 @@
#include "DNA_ID_enums.h"
#include "DNA_curve_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_curve.h"
#include "BKE_geometry_set.hh"
@@ -17,7 +16,7 @@
using blender::GMutableSpan;
using blender::GSpan;
using blender::GVArray;
-using blender::GVArray_GSpan;
+using blender::GVArraySpan;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -114,24 +113,6 @@ void CurveComponentLegacy::ensure_owns_direct_data()
/** \name Attribute Access Helper Functions
* \{ */
-int CurveComponentLegacy::attribute_domain_num(const AttributeDomain domain) const
-{
- if (curve_ == nullptr) {
- return 0;
- }
- if (domain == ATTR_DOMAIN_POINT) {
- int total = 0;
- for (const SplinePtr &spline : curve_->splines()) {
- total += spline->size();
- }
- return total;
- }
- if (domain == ATTR_DOMAIN_CURVE) {
- return curve_->splines().size();
- }
- return 0;
-}
-
namespace blender::bke {
namespace {
@@ -231,7 +212,7 @@ 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. */
- VArray_Span<T> original_data_;
+ VArraySpan<T> original_data_;
Array<int> offsets_;
public:
@@ -308,10 +289,10 @@ static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArra
} // namespace blender::bke
-GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(
- const GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+static GVArray adapt_curve_attribute_domain(const CurveEval &curve,
+ const GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain)
{
if (!varray) {
return {};
@@ -324,30 +305,15 @@ GVArray CurveComponentLegacy::attribute_try_adapt_domain_impl(
}
if (from_domain == ATTR_DOMAIN_POINT && to_domain == ATTR_DOMAIN_CURVE) {
- return blender::bke::adapt_curve_domain_point_to_spline(*curve_, std::move(varray));
+ return blender::bke::adapt_curve_domain_point_to_spline(curve, std::move(varray));
}
if (from_domain == ATTR_DOMAIN_CURVE && to_domain == ATTR_DOMAIN_POINT) {
- return blender::bke::adapt_curve_domain_spline_to_point(*curve_, std::move(varray));
+ return blender::bke::adapt_curve_domain_spline_to_point(curve, std::move(varray));
}
return {};
}
-static CurveEval *get_curve_from_component_for_write(GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- CurveComponentLegacy &curve_component = static_cast<CurveComponentLegacy &>(component);
- return curve_component.get_for_write();
-}
-
-static const CurveEval *get_curve_from_component_for_read(const GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- const CurveComponentLegacy &curve_component = static_cast<const CurveComponentLegacy &>(
- component);
- return curve_component.get_for_read();
-}
-
/** \} */
namespace blender::bke {
@@ -366,7 +332,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
public:
BuiltinSplineAttributeProvider(std::string attribute_name,
- const CustomDataType attribute_type,
+ const eCustomDataType attribute_type,
const WritableEnum writable,
const AsReadAttribute as_read_attribute,
const AsWriteAttribute as_write_attribute)
@@ -381,41 +347,41 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const void *owner) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
return as_read_attribute_(*curve);
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
+ GAttributeWriter try_get_for_write(void *owner) const final
{
if (writable_ != Writable) {
return {};
}
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
return {as_write_attribute_(*curve), domain_};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(void *UNUSED(owner)) const final
{
return false;
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
- bool exists(const GeometryComponent &component) const final
+ bool exists(const void *owner) const final
{
- return component.attribute_domain_num(ATTR_DOMAIN_CURVE) != 0;
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
+ return !curve->splines().is_empty();
}
};
@@ -577,7 +543,7 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data,
}
static GVArray varray_from_initializer(const AttributeInit &initializer,
- const CustomDataType data_type,
+ const eCustomDataType data_type,
const Span<SplinePtr> splines)
{
switch (initializer.type) {
@@ -601,12 +567,11 @@ static GVArray varray_from_initializer(const AttributeInit &initializer,
return {};
}
-static bool create_point_attribute(GeometryComponent &component,
+static bool create_point_attribute(CurveEval *curve,
const AttributeIDRef &attribute_id,
const AttributeInit &initializer,
- const CustomDataType data_type)
+ const eCustomDataType data_type)
{
- CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr || curve->splines().size() == 0) {
return false;
}
@@ -639,15 +604,16 @@ static bool create_point_attribute(GeometryComponent &component,
return true;
}
- WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(attribute_id);
+ GAttributeWriter write_attribute = curve->attributes_for_write().lookup_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());
+ GVArraySpan source_VArraySpan{source_varray};
+ write_attribute.varray.set_all(source_VArraySpan.data());
+ write_attribute.finish();
if (initializer.type == AttributeInit::Type::MoveArray) {
MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data);
@@ -656,10 +622,8 @@ static bool create_point_attribute(GeometryComponent &component,
return true;
}
-static bool remove_point_attribute(GeometryComponent &component,
- const AttributeIDRef &attribute_id)
+static bool remove_point_attribute(CurveEval *curve, const AttributeIDRef &attribute_id)
{
- CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
return false;
}
@@ -935,14 +899,14 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const override
+ GVArray try_get_for_read(const void *owner) const override
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
- if (!this->exists(component)) {
+ if (!this->exists(owner)) {
return {};
}
@@ -963,14 +927,14 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
return point_data_varray(spans, offsets);
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
+ GAttributeWriter try_get_for_write(void *owner) const override
{
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
- if (!this->exists(component)) {
+ if (!this->exists(owner)) {
return {};
}
@@ -999,25 +963,27 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu
return {point_data_varray_mutable(spans, offsets), domain_, tag_modified_fn};
}
- bool try_delete(GeometryComponent &component) const final
+ bool try_delete(void *owner) const final
{
if (deletable_ == DeletableEnum::NonDeletable) {
return false;
}
- return remove_point_attribute(component, name_);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
+ return remove_point_attribute(curve, name_);
}
- bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final
+ bool try_create(void *owner, const AttributeInit &initializer) const final
{
if (createable_ == CreatableEnum::NonCreatable) {
return false;
}
- return create_point_attribute(component, name_, initializer, CD_PROP_INT32);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
+ return create_point_attribute(curve, name_, initializer, CD_PROP_INT32);
}
- bool exists(const GeometryComponent &component) const final
+ bool exists(const void *owner) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return false;
}
@@ -1068,9 +1034,9 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
{
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
+ GAttributeWriter try_get_for_write(void *owner) const final
{
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
@@ -1078,7 +1044,7 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo
/* Use the regular position virtual array when there aren't any Bezier splines
* to avoid the overhead of checking the spline type for every point. */
if (!curve->has_spline_with_type(CURVE_TYPE_BEZIER)) {
- return BuiltinPointAttributeProvider<float3>::try_get_for_write(component);
+ return BuiltinPointAttributeProvider<float3>::try_get_for_write(owner);
}
auto tag_modified_fn = [curve]() {
@@ -1111,9 +1077,9 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const override
+ GVArray try_get_for_read(const void *owner) const override
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
@@ -1129,9 +1095,9 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
const_cast<CurveEval *>(curve)->splines(), std::move(offsets), is_right_);
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override
+ GAttributeWriter try_get_for_write(void *owner) const override
{
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr) {
return {};
}
@@ -1149,26 +1115,27 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
tag_modified_fn};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(void *UNUSED(owner)) const final
{
return false;
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
- bool exists(const GeometryComponent &component) const final
+ bool exists(const void *owner) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr) {
return false;
}
- return curve->has_spline_with_type(CURVE_TYPE_BEZIER) &&
- component.attribute_domain_num(ATTR_DOMAIN_POINT) != 0;
+ CurveComponentLegacy component;
+ component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly);
+
+ return curve->has_spline_with_type(CURVE_TYPE_BEZIER) && !curve->splines().is_empty();
}
};
@@ -1191,10 +1158,10 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
CD_MASK_PROP_INT8;
public:
- ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final
+ GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr || curve->splines().size() == 0) {
return {};
}
@@ -1229,7 +1196,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
}
- ReadAttributeLookup attribute = {};
+ GAttributeReader attribute = {};
Array<int> offsets = curve->control_point_offsets();
attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
using T = decltype(dummy);
@@ -1247,10 +1214,9 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
}
/* This function is almost the same as #try_get_for_read, but without const. */
- WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final
+ GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
{
- CurveEval *curve = get_curve_from_component_for_write(component);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
if (curve == nullptr || curve->splines().size() == 0) {
return {};
}
@@ -1285,7 +1251,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
}
- WriteAttributeLookup attribute = {};
+ GAttributeWriter attribute = {};
Array<int> offsets = curve->control_point_offsets();
attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
using T = decltype(dummy);
@@ -1299,28 +1265,29 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return attribute;
}
- bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final
+ bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
{
- return remove_point_attribute(component, attribute_id);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
+ return remove_point_attribute(curve, attribute_id);
}
- bool try_create(GeometryComponent &component,
+ bool try_create(void *owner,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
+ const eAttrDomain domain,
+ const eCustomDataType data_type,
const AttributeInit &initializer) const final
{
BLI_assert(this->type_is_supported(data_type));
if (domain != ATTR_DOMAIN_POINT) {
return false;
}
- return create_point_attribute(component, attribute_id, initializer, data_type);
+ CurveEval *curve = static_cast<CurveEval *>(owner);
+ return create_point_attribute(curve, attribute_id, initializer, data_type);
}
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
+ bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
{
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
if (curve == nullptr || curve->splines().size() == 0) {
return false;
}
@@ -1336,12 +1303,12 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
return true;
}
- void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
+ void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
{
callback(ATTR_DOMAIN_POINT);
}
- bool type_is_supported(CustomDataType data_type) const
+ bool type_is_supported(eCustomDataType data_type) const
{
return ((1ULL << data_type) & supported_types_mask) != 0;
}
@@ -1372,14 +1339,18 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
make_cyclic_write_attribute);
static CustomDataAccessInfo spline_custom_data_access = {
- [](GeometryComponent &component) -> CustomData * {
- CurveEval *curve = get_curve_from_component_for_write(component);
+ [](void *owner) -> CustomData * {
+ CurveEval *curve = static_cast<CurveEval *>(owner);
return curve ? &curve->attributes.data : nullptr;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const CurveEval *curve = get_curve_from_component_for_read(component);
+ [](const void *owner) -> const CustomData * {
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
return curve ? &curve->attributes.data : nullptr;
},
+ [](const void *owner) -> int {
+ const CurveEval *curve = static_cast<const CurveEval *>(owner);
+ return curve->splines().size();
+ },
nullptr};
static CustomDataAttributeProvider spline_custom_data(ATTR_DOMAIN_CURVE,
@@ -1431,12 +1402,63 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
/** \} */
+static AttributeAccessorFunctions get_curve_accessor_functions()
+{
+ static const ComponentAttributeProviders providers = create_attribute_providers_for_curve();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) -> int {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const CurveEval &curve_eval = *static_cast<const CurveEval *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return curve_eval.total_control_point_num();
+ case ATTR_DOMAIN_CURVE:
+ return curve_eval.splines().size();
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ };
+ fn.adapt_domain = [](const void *owner,
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) -> GVArray {
+ if (owner == nullptr) {
+ return {};
+ }
+ const CurveEval &curve_eval = *static_cast<const CurveEval *>(owner);
+ return adapt_curve_attribute_domain(curve_eval, varray, from_domain, to_domain);
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_curve_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_curve_accessor_functions();
+ return fn;
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *CurveComponentLegacy::get_attribute_providers()
- const
+std::optional<blender::bke::AttributeAccessor> CurveComponentLegacy::attributes() const
+{
+ return blender::bke::AttributeAccessor(curve_, blender::bke::get_curve_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> CurveComponentLegacy::attributes_for_write()
+{
+ CurveEval *curve = this->get_for_write();
+ return blender::bke::MutableAttributeAccessor(curve,
+ blender::bke::get_curve_accessor_functions_ref());
+}
+
+blender::bke::MutableAttributeAccessor CurveEval::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_curve();
- return &providers;
+ return blender::bke::MutableAttributeAccessor(this,
+ blender::bke::get_curve_accessor_functions_ref());
}
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index 9b023d12a7d..2714c78e381 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -5,14 +5,12 @@
#include "DNA_ID_enums.h"
#include "DNA_curve_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_curve.h"
#include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
-#include "BKE_spline.hh"
#include "attribute_access_intern.hh"
@@ -208,7 +206,7 @@ static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves
return results;
}
-VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain)
+VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -219,7 +217,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const Attri
const VArray<int8_t> types = curves.curve_types();
if (curves.is_single_type(CURVE_TYPE_POLY)) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain);
}
@@ -230,7 +228,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const Attri
}
if (domain == ATTR_DOMAIN_CURVE) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
}
@@ -244,7 +242,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const Attri
* \{ */
static VArray<float> construct_curve_length_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -265,7 +263,7 @@ static VArray<float> construct_curve_length_gvarray(const CurveComponent &compon
}
if (domain == ATTR_DOMAIN_POINT) {
- return component.attribute_try_adapt_domain<float>(
+ return component.attributes()->adapt_domain<float>(
std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
@@ -279,7 +277,7 @@ CurveLengthFieldInput::CurveLengthFieldInput()
}
GVArray CurveLengthFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
@@ -308,75 +306,29 @@ bool CurveLengthFieldInput::is_equal_to(const fn::FieldNode &other) const
/** \name Attribute Access Helper Functions
* \{ */
-int CurveComponent::attribute_domain_num(const AttributeDomain domain) const
+static void tag_component_topology_changed(void *owner)
{
- if (curves_ == nullptr) {
- return 0;
- }
- const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
- curves_->geometry);
- if (domain == ATTR_DOMAIN_POINT) {
- return curves.points_num();
- }
- if (domain == ATTR_DOMAIN_CURVE) {
- return curves.curves_num();
- }
- return 0;
-}
-
-GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
-{
- return blender::bke::CurvesGeometry::wrap(curves_->geometry)
- .adapt_domain(varray, from_domain, to_domain);
-}
-
-static Curves *get_curves_from_component_for_write(GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- CurveComponent &curve_component = static_cast<CurveComponent &>(component);
- return curve_component.get_for_write();
-}
-
-static const Curves *get_curves_from_component_for_read(const GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
- const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- return curve_component.get_for_read();
+ blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
+ curves.tag_topology_changed();
}
-static void tag_component_topology_changed(GeometryComponent &component)
+static void tag_component_curve_types_changed(void *owner)
{
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed();
- }
+ blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
+ curves.update_curve_types();
+ curves.tag_topology_changed();
}
-static void tag_component_curve_types_changed(GeometryComponent &component)
+static void tag_component_positions_changed(void *owner)
{
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).update_curve_types();
- blender::bke::CurvesGeometry::wrap(curves->geometry).tag_topology_changed();
- }
+ blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
+ curves.tag_positions_changed();
}
-static void tag_component_positions_changed(GeometryComponent &component)
+static void tag_component_normals_changed(void *owner)
{
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).tag_positions_changed();
- }
-}
-
-static void tag_component_normals_changed(GeometryComponent &component)
-{
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).tag_normals_changed();
- }
+ blender::bke::CurvesGeometry &curves = *static_cast<blender::bke::CurvesGeometry *>(owner);
+ curves.tag_normals_changed();
}
/** \} */
@@ -394,35 +346,33 @@ namespace blender::bke {
static ComponentAttributeProviders create_attribute_providers_for_curve()
{
static CustomDataAccessInfo curve_access = {
- [](GeometryComponent &component) -> CustomData * {
- Curves *curves = get_curves_from_component_for_write(component);
- return curves ? &curves->geometry.curve_data : nullptr;
+ [](void *owner) -> CustomData * {
+ CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
+ return &curves.curve_data;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const Curves *curves = get_curves_from_component_for_read(component);
- return curves ? &curves->geometry.curve_data : nullptr;
+ [](const void *owner) -> const CustomData * {
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return &curves.curve_data;
},
- [](GeometryComponent &component) {
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers();
- }
- }};
+ [](const void *owner) -> int {
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return curves.curves_num();
+ },
+ [](void * /*owner*/) {}};
static CustomDataAccessInfo point_access = {
- [](GeometryComponent &component) -> CustomData * {
- Curves *curves = get_curves_from_component_for_write(component);
- return curves ? &curves->geometry.point_data : nullptr;
+ [](void *owner) -> CustomData * {
+ CurvesGeometry &curves = *static_cast<CurvesGeometry *>(owner);
+ return &curves.point_data;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const Curves *curves = get_curves_from_component_for_read(component);
- return curves ? &curves->geometry.point_data : nullptr;
+ [](const void *owner) -> const CustomData * {
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return &curves.point_data;
},
- [](GeometryComponent &component) {
- Curves *curves = get_curves_from_component_for_write(component);
- if (curves) {
- blender::bke::CurvesGeometry::wrap(curves->geometry).update_customdata_pointers();
- }
- }};
+ [](const void *owner) -> int {
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return curves.points_num();
+ },
+ [](void * /*owner*/) {}};
static BuiltinCustomDataLayerProvider position("position",
ATTR_DOMAIN_POINT,
@@ -627,11 +577,68 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
/** \} */
+static AttributeAccessorFunctions get_curves_accessor_functions()
+{
+ static const ComponentAttributeProviders providers = create_attribute_providers_for_curve();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return curves.points_num();
+ case ATTR_DOMAIN_CURVE:
+ return curves.curves_num();
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ };
+ fn.adapt_domain = [](const void *owner,
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) -> GVArray {
+ if (owner == nullptr) {
+ return {};
+ }
+ const CurvesGeometry &curves = *static_cast<const CurvesGeometry *>(owner);
+ return curves.adapt_domain(varray, from_domain, to_domain);
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_curves_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_curves_accessor_functions();
+ return fn;
+}
+
+AttributeAccessor CurvesGeometry::attributes() const
+{
+ return AttributeAccessor(this, get_curves_accessor_functions_ref());
+}
+
+MutableAttributeAccessor CurvesGeometry::attributes_for_write()
+{
+ return MutableAttributeAccessor(this, get_curves_accessor_functions_ref());
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *CurveComponent::get_attribute_providers() const
+std::optional<blender::bke::AttributeAccessor> CurveComponent::attributes() const
+{
+ return blender::bke::AttributeAccessor(curves_ ? &curves_->geometry : nullptr,
+ blender::bke::get_curves_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> CurveComponent::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_curve();
- return &providers;
+ Curves *curves = this->get_for_write();
+ return blender::bke::MutableAttributeAccessor(curves ? &curves->geometry : nullptr,
+ blender::bke::get_curves_accessor_functions_ref());
}
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index e56a7ca4dd8..c16311945ba 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -13,7 +13,6 @@
#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"
@@ -157,7 +156,7 @@ void InstancesComponent::remove_instances(const IndexMask mask)
dst_attributes.reallocate(mask.size());
src_attributes.foreach_attribute(
- [&](const bke::AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
if (!id.should_be_kept()) {
return true;
}
@@ -366,20 +365,12 @@ blender::Span<int> InstancesComponent::almost_unique_ids() const
return almost_unique_ids_;
}
-int InstancesComponent::attribute_domain_num(const AttributeDomain domain) const
-{
- if (domain != ATTR_DOMAIN_INSTANCE) {
- return 0;
- }
- return this->instances_num();
-}
-
-blender::bke::CustomDataAttributes &InstancesComponent::attributes()
+blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes()
{
return this->attributes_;
}
-const blender::bke::CustomDataAttributes &InstancesComponent::attributes() const
+const blender::bke::CustomDataAttributes &InstancesComponent::instance_attributes() const
{
return this->attributes_;
}
@@ -404,17 +395,17 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const void *owner) const final
{
- const InstancesComponent &instances_component = static_cast<const InstancesComponent &>(
- component);
+ const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
+ owner);
Span<float4x4> transforms = instances_component.instance_transforms();
return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms);
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final
+ GAttributeWriter try_get_for_write(void *owner) const final
{
- InstancesComponent &instances_component = static_cast<InstancesComponent &>(component);
+ InstancesComponent &instances_component = *static_cast<InstancesComponent *>(owner);
MutableSpan<float4x4> transforms = instances_component.instance_transforms();
return {VMutableArray<float3>::ForDerivedSpan<float4x4,
get_transform_position,
@@ -422,18 +413,17 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
domain_};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(void *UNUSED(owner)) const final
{
return false;
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
- bool exists(const GeometryComponent &UNUSED(component)) const final
+ bool exists(const void *UNUSED(owner)) const final
{
return true;
}
@@ -443,13 +433,17 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
{
static InstancePositionAttributeProvider position;
static CustomDataAccessInfo instance_custom_data_access = {
- [](GeometryComponent &component) -> CustomData * {
- InstancesComponent &inst = static_cast<InstancesComponent &>(component);
- return &inst.attributes().data;
+ [](void *owner) -> CustomData * {
+ InstancesComponent &inst = *static_cast<InstancesComponent *>(owner);
+ return &inst.instance_attributes().data;
+ },
+ [](const void *owner) -> const CustomData * {
+ const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
+ return &inst.instance_attributes().data;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const InstancesComponent &inst = static_cast<const InstancesComponent &>(component);
- return &inst.attributes().data;
+ [](const void *owner) -> int {
+ const InstancesComponent &inst = *static_cast<const InstancesComponent *>(owner);
+ return inst.instances_num();
},
nullptr};
@@ -476,14 +470,57 @@ static ComponentAttributeProviders create_attribute_providers_for_instances()
return ComponentAttributeProviders({&position, &id}, {&instance_custom_data});
}
+
+static AttributeAccessorFunctions get_instances_accessor_functions()
+{
+ static const ComponentAttributeProviders providers = create_attribute_providers_for_instances();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const InstancesComponent &instances = *static_cast<const InstancesComponent *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_INSTANCE:
+ return instances.instances_num();
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return domain == ATTR_DOMAIN_INSTANCE;
+ };
+ fn.adapt_domain = [](const void *UNUSED(owner),
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) {
+ if (from_domain == to_domain && from_domain == ATTR_DOMAIN_INSTANCE) {
+ return varray;
+ }
+ return blender::GVArray{};
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_instances_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_instances_accessor_functions();
+ return fn;
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *InstancesComponent::get_attribute_providers()
- const
+std::optional<blender::bke::AttributeAccessor> InstancesComponent::attributes() const
+{
+ return blender::bke::AttributeAccessor(this,
+ blender::bke::get_instances_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> InstancesComponent::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_instances();
- return &providers;
+ return blender::bke::MutableAttributeAccessor(
+ this, blender::bke::get_instances_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 5ac9a03f43c..436868ba375 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -7,7 +7,6 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_deform.h"
#include "BKE_geometry_fields.hh"
@@ -119,7 +118,7 @@ namespace blender::bke {
VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
const Mesh &mesh,
const IndexMask mask,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
switch (domain) {
case ATTR_DOMAIN_FACE: {
@@ -151,7 +150,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
* 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(
+ return mesh_component.attributes()->adapt_domain(
VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}),
ATTR_DOMAIN_FACE,
ATTR_DOMAIN_CORNER);
@@ -169,26 +168,6 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
/** \name Attribute Access
* \{ */
-int MeshComponent::attribute_domain_num(const AttributeDomain domain) const
-{
- if (mesh_ == nullptr) {
- return 0;
- }
- switch (domain) {
- case ATTR_DOMAIN_CORNER:
- return mesh_->totloop;
- case ATTR_DOMAIN_POINT:
- return mesh_->totvert;
- case ATTR_DOMAIN_EDGE:
- return mesh_->totedge;
- case ATTR_DOMAIN_FACE:
- return mesh_->totpoly;
- default:
- break;
- }
- return 0;
-}
-
namespace blender::bke {
template<typename T>
@@ -319,12 +298,14 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
const MPoly &poly = mesh.mpoly[poly_index];
/* For every edge, mix values from the two adjacent corners (the current and next corner). */
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const int loop_index_next = (loop_index + 1) % poly.totloop;
- const MLoop &loop = mesh.mloop[loop_index];
+ for (const int i : IndexRange(poly.totloop)) {
+ const int next_i = (i + 1) % poly.totloop;
+ const int loop_i = poly.loopstart + i;
+ const int next_loop_i = poly.loopstart + next_i;
+ const MLoop &loop = mesh.mloop[loop_i];
const int edge_index = loop.e;
- mixer.mix_in(edge_index, old_values[loop_index]);
- mixer.mix_in(edge_index, old_values[loop_index_next]);
+ mixer.mix_in(edge_index, old_values[loop_i]);
+ mixer.mix_in(edge_index, old_values[next_loop_i]);
}
}
@@ -346,13 +327,16 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
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 int loop_index_next = (loop_index == poly.totloop) ? poly.loopstart : (loop_index + 1);
- const MLoop &loop = mesh.mloop[loop_index];
+ for (const int i : IndexRange(poly.totloop)) {
+ const int next_i = (i + 1) % poly.totloop;
+ const int loop_i = poly.loopstart + i;
+ const int next_loop_i = poly.loopstart + next_i;
+ const MLoop &loop = mesh.mloop[loop_i];
const int edge_index = loop.e;
+
loose_edges[edge_index] = false;
- if (!old_values[loop_index] || !old_values[loop_index_next]) {
+ if (!old_values[loop_i] || !old_values[next_loop_i]) {
r_values[edge_index] = false;
}
}
@@ -747,10 +731,10 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v
} // namespace blender::bke
-blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(
- const blender::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+static blender::GVArray adapt_mesh_attribute_domain(const Mesh &mesh,
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain)
{
if (!varray) {
return {};
@@ -766,11 +750,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(
case ATTR_DOMAIN_CORNER: {
switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, 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_, 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_, varray);
+ return blender::bke::adapt_mesh_domain_corner_to_edge(mesh, varray);
default:
break;
}
@@ -779,11 +763,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(
case ATTR_DOMAIN_POINT: {
switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, 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_, 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_, varray);
+ return blender::bke::adapt_mesh_domain_point_to_edge(mesh, varray);
default:
break;
}
@@ -792,11 +776,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(
case ATTR_DOMAIN_FACE: {
switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, 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_, 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_, varray);
+ return blender::bke::adapt_mesh_domain_face_to_edge(mesh, varray);
default:
break;
}
@@ -805,11 +789,11 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(
case ATTR_DOMAIN_EDGE: {
switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, 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_, 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_, varray);
+ return blender::bke::adapt_mesh_domain_edge_to_face(mesh, varray);
default:
break;
}
@@ -822,20 +806,6 @@ blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(
return {};
}
-static Mesh *get_mesh_from_component_for_write(GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- return mesh_component.get_for_write();
-}
-
-static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component)
-{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- return mesh_component.get_for_read();
-}
-
namespace blender::bke {
template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
@@ -865,11 +835,11 @@ static void set_vertex_position(MVert &vert, float3 position)
copy_v3_v3(vert.co, position);
}
-static void tag_normals_dirty_when_writing_position(GeometryComponent &component)
+static void tag_component_positions_changed(void *owner)
{
- Mesh *mesh = get_mesh_from_component_for_write(component);
+ Mesh *mesh = static_cast<Mesh *>(owner);
if (mesh != nullptr) {
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_tag_coords_changed(mesh);
}
}
@@ -1002,15 +972,13 @@ class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
*/
class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
public:
- ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final
+ GAttributeReader try_get_for_read(const void *owner,
+ const AttributeIDRef &attribute_id) const final
{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
if (!attribute_id.is_named()) {
return {};
}
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
+ const Mesh *mesh = static_cast<const Mesh *>(owner);
if (mesh == nullptr) {
return {};
}
@@ -1029,15 +997,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
ATTR_DOMAIN_POINT};
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &component,
- const AttributeIDRef &attribute_id) const final
+ GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
if (!attribute_id.is_named()) {
return {};
}
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- Mesh *mesh = mesh_component.get_for_write();
+ Mesh *mesh = static_cast<Mesh *>(owner);
if (mesh == nullptr) {
return {};
}
@@ -1061,14 +1026,12 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
ATTR_DOMAIN_POINT};
}
- bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final
+ bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
if (!attribute_id.is_named()) {
return false;
}
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- Mesh *mesh = mesh_component.get_for_write();
+ Mesh *mesh = static_cast<Mesh *>(owner);
if (mesh == nullptr) {
return true;
}
@@ -1093,16 +1056,18 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) {
MDeformWeight *weight = BKE_defvert_find_index(&dvert, index);
BKE_defvert_remove_group(&dvert, weight);
+ for (MDeformWeight &weight : MutableSpan(dvert.dw, dvert.totweight)) {
+ if (weight.def_nr > index) {
+ weight.def_nr--;
+ }
+ }
}
return true;
}
- bool foreach_attribute(const GeometryComponent &component,
- const AttributeForeachCallback callback) const final
+ bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
{
- BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
+ const Mesh *mesh = static_cast<const Mesh *>(owner);
if (mesh == nullptr) {
return true;
}
@@ -1115,7 +1080,7 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
return true;
}
- void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final
+ void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
{
callback(ATTR_DOMAIN_POINT);
}
@@ -1132,35 +1097,34 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
{
}
- GVArray try_get_for_read(const GeometryComponent &component) const final
+ GVArray try_get_for_read(const void *owner) const final
{
- const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
- const Mesh *mesh = mesh_component.get_for_read();
+ const Mesh *mesh = static_cast<const Mesh *>(owner);
if (mesh == nullptr || mesh->totpoly == 0) {
return {};
}
return VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly});
}
- WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final
+ GAttributeWriter try_get_for_write(void *UNUSED(owner)) const final
{
return {};
}
- bool try_delete(GeometryComponent &UNUSED(component)) const final
+ bool try_delete(void *UNUSED(owner)) const final
{
return false;
}
- bool try_create(GeometryComponent &UNUSED(component),
- const AttributeInit &UNUSED(initializer)) const final
+ bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
{
return false;
}
- bool exists(const GeometryComponent &component) const final
+ bool exists(const void *owner) const final
{
- return component.attribute_domain_num(ATTR_DOMAIN_FACE) != 0;
+ const Mesh *mesh = static_cast<const Mesh *>(owner);
+ return mesh->totpoly != 0;
}
};
@@ -1170,34 +1134,42 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
*/
static ComponentAttributeProviders create_attribute_providers_for_mesh()
{
- static auto update_custom_data_pointers = [](GeometryComponent &component) {
- if (Mesh *mesh = get_mesh_from_component_for_write(component)) {
- BKE_mesh_update_customdata_pointers(mesh, false);
- }
+ static auto update_custom_data_pointers = [](void *owner) {
+ Mesh *mesh = static_cast<Mesh *>(owner);
+ BKE_mesh_update_customdata_pointers(mesh, false);
};
#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
- [](GeometryComponent &component) -> CustomData * { \
- Mesh *mesh = get_mesh_from_component_for_write(component); \
- return mesh ? &mesh->NAME : nullptr; \
+ [](void *owner) -> CustomData * { \
+ Mesh *mesh = static_cast<Mesh *>(owner); \
+ return &mesh->NAME; \
}
#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
- [](const GeometryComponent &component) -> const CustomData * { \
- const Mesh *mesh = get_mesh_from_component_for_read(component); \
- return mesh ? &mesh->NAME : nullptr; \
+ [](const void *owner) -> const CustomData * { \
+ const Mesh *mesh = static_cast<const Mesh *>(owner); \
+ return &mesh->NAME; \
+ }
+#define MAKE_GET_ELEMENT_NUM_GETTER(NAME) \
+ [](const void *owner) -> int { \
+ const Mesh *mesh = static_cast<const Mesh *>(owner); \
+ return mesh->NAME; \
}
static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata),
MAKE_CONST_CUSTOM_DATA_GETTER(ldata),
+ MAKE_GET_ELEMENT_NUM_GETTER(totloop),
update_custom_data_pointers};
static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata),
MAKE_CONST_CUSTOM_DATA_GETTER(vdata),
+ MAKE_GET_ELEMENT_NUM_GETTER(totvert),
update_custom_data_pointers};
static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata),
MAKE_CONST_CUSTOM_DATA_GETTER(edata),
+ MAKE_GET_ELEMENT_NUM_GETTER(totedge),
update_custom_data_pointers};
static CustomDataAccessInfo face_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata),
MAKE_CONST_CUSTOM_DATA_GETTER(pdata),
+ MAKE_GET_ELEMENT_NUM_GETTER(totpoly),
update_custom_data_pointers};
#undef MAKE_CONST_CUSTOM_DATA_GETTER
@@ -1214,7 +1186,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
point_access,
make_derived_read_attribute<MVert, float3, get_vertex_position>,
make_derived_write_attribute<MVert, float3, get_vertex_position, set_vertex_position>,
- tag_normals_dirty_when_writing_position);
+ tag_component_positions_changed);
static NormalAttributeProvider normal;
@@ -1293,13 +1265,73 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
&face_custom_data});
}
+static AttributeAccessorFunctions get_mesh_accessor_functions()
+{
+ static const ComponentAttributeProviders providers = create_attribute_providers_for_mesh();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const Mesh &mesh = *static_cast<const Mesh *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return mesh.totvert;
+ case ATTR_DOMAIN_EDGE:
+ return mesh.totedge;
+ case ATTR_DOMAIN_FACE:
+ return mesh.totpoly;
+ case ATTR_DOMAIN_CORNER:
+ return mesh.totloop;
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
+ };
+ fn.adapt_domain = [](const void *owner,
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) -> blender::GVArray {
+ if (owner == nullptr) {
+ return {};
+ }
+ const Mesh &mesh = *static_cast<const Mesh *>(owner);
+ return adapt_mesh_attribute_domain(mesh, varray, from_domain, to_domain);
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_mesh_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_mesh_accessor_functions();
+ return fn;
+}
+
+AttributeAccessor mesh_attributes(const Mesh &mesh)
+{
+ return AttributeAccessor(&mesh, get_mesh_accessor_functions_ref());
+}
+
+MutableAttributeAccessor mesh_attributes_for_write(Mesh &mesh)
+{
+ return MutableAttributeAccessor(&mesh, get_mesh_accessor_functions_ref());
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const
+std::optional<blender::bke::AttributeAccessor> MeshComponent::attributes() const
+{
+ return blender::bke::AttributeAccessor(mesh_, blender::bke::get_mesh_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> MeshComponent::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_mesh();
- return &providers;
+ Mesh *mesh = this->get_for_write();
+ return blender::bke::MutableAttributeAccessor(mesh,
+ blender::bke::get_mesh_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
index 6de123c7cb9..4953da8a5ee 100644
--- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -2,7 +2,6 @@
#include "DNA_pointcloud_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_pointcloud.h"
@@ -104,17 +103,6 @@ void PointCloudComponent::ensure_owns_direct_data()
/** \name Attribute Access
* \{ */
-int PointCloudComponent::attribute_domain_num(const AttributeDomain domain) const
-{
- if (pointcloud_ == nullptr) {
- return 0;
- }
- if (domain != ATTR_DOMAIN_POINT) {
- return 0;
- }
- return pointcloud_->totpoint;
-}
-
namespace blender::bke {
/**
@@ -123,23 +111,19 @@ namespace blender::bke {
*/
static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
{
- static auto update_custom_data_pointers = [](GeometryComponent &component) {
- PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
- if (PointCloud *pointcloud = pointcloud_component.get_for_write()) {
- BKE_pointcloud_update_customdata_pointers(pointcloud);
- }
- };
+ static auto update_custom_data_pointers = [](void * /*owner*/) {};
static CustomDataAccessInfo point_access = {
- [](GeometryComponent &component) -> CustomData * {
- PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component);
- PointCloud *pointcloud = pointcloud_component.get_for_write();
- return pointcloud ? &pointcloud->pdata : nullptr;
+ [](void *owner) -> CustomData * {
+ PointCloud *pointcloud = static_cast<PointCloud *>(owner);
+ return &pointcloud->pdata;
+ },
+ [](const void *owner) -> const CustomData * {
+ const PointCloud *pointcloud = static_cast<const PointCloud *>(owner);
+ return &pointcloud->pdata;
},
- [](const GeometryComponent &component) -> const CustomData * {
- const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>(
- component);
- const PointCloud *pointcloud = pointcloud_component.get_for_read();
- return pointcloud ? &pointcloud->pdata : nullptr;
+ [](const void *owner) -> int {
+ const PointCloud *pointcloud = static_cast<const PointCloud *>(owner);
+ return pointcloud->totpoint;
},
update_custom_data_pointers};
@@ -180,14 +164,68 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
return ComponentAttributeProviders({&position, &radius, &id}, {&point_custom_data});
}
+static AttributeAccessorFunctions get_pointcloud_accessor_functions()
+{
+ static const ComponentAttributeProviders providers =
+ create_attribute_providers_for_point_cloud();
+ AttributeAccessorFunctions fn =
+ attribute_accessor_functions::accessor_functions_for_providers<providers>();
+ fn.domain_size = [](const void *owner, const eAttrDomain domain) {
+ if (owner == nullptr) {
+ return 0;
+ }
+ const PointCloud &pointcloud = *static_cast<const PointCloud *>(owner);
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return pointcloud.totpoint;
+ default:
+ return 0;
+ }
+ };
+ fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
+ return domain == ATTR_DOMAIN_POINT;
+ };
+ fn.adapt_domain = [](const void *UNUSED(owner),
+ const blender::GVArray &varray,
+ const eAttrDomain from_domain,
+ const eAttrDomain to_domain) {
+ if (from_domain == to_domain && from_domain == ATTR_DOMAIN_POINT) {
+ return varray;
+ }
+ return blender::GVArray{};
+ };
+ return fn;
+}
+
+static const AttributeAccessorFunctions &get_pointcloud_accessor_functions_ref()
+{
+ static const AttributeAccessorFunctions fn = get_pointcloud_accessor_functions();
+ return fn;
+}
+
+AttributeAccessor pointcloud_attributes(const PointCloud &pointcloud)
+{
+ return AttributeAccessor(&pointcloud, get_pointcloud_accessor_functions_ref());
+}
+
+MutableAttributeAccessor pointcloud_attributes_for_write(PointCloud &pointcloud)
+{
+ return MutableAttributeAccessor(&pointcloud, get_pointcloud_accessor_functions_ref());
+}
+
} // namespace blender::bke
-const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers()
- const
+std::optional<blender::bke::AttributeAccessor> PointCloudComponent::attributes() const
+{
+ return blender::bke::AttributeAccessor(pointcloud_,
+ blender::bke::get_pointcloud_accessor_functions_ref());
+}
+
+std::optional<blender::bke::MutableAttributeAccessor> PointCloudComponent::attributes_for_write()
{
- static blender::bke::ComponentAttributeProviders providers =
- blender::bke::create_attribute_providers_for_point_cloud();
- return &providers;
+ PointCloud *pointcloud = this->get_for_write();
+ return blender::bke::MutableAttributeAccessor(
+ pointcloud, blender::bke::get_pointcloud_accessor_functions_ref());
}
/** \} */
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index 40e36ced199..c6fe8eebc7f 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -1,12 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_bounds.hh"
#include "BLI_map.hh"
#include "BLI_task.hh"
#include "BLT_translation.h"
#include "BKE_attribute.h"
-#include "BKE_attribute_access.hh"
#include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
@@ -15,7 +15,6 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "BKE_volume.h"
#include "DNA_collection_types.h"
@@ -59,6 +58,27 @@ GeometryComponent *GeometryComponent::create(GeometryComponentType component_typ
return nullptr;
}
+int GeometryComponent::attribute_domain_size(const eAttrDomain domain) const
+{
+ if (this->is_empty()) {
+ return 0;
+ }
+ const std::optional<blender::bke::AttributeAccessor> attributes = this->attributes();
+ if (attributes.has_value()) {
+ return attributes->domain_size(domain);
+ }
+ return 0;
+}
+
+std::optional<blender::bke::AttributeAccessor> GeometryComponent::attributes() const
+{
+ return std::nullopt;
+};
+std::optional<blender::bke::MutableAttributeAccessor> GeometryComponent::attributes_for_write()
+{
+ return std::nullopt;
+}
+
void GeometryComponent::user_add() const
{
users_.fetch_add(1);
@@ -175,6 +195,7 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
{
+ using namespace blender;
bool have_minmax = false;
if (const PointCloud *pointcloud = this->get_pointcloud_for_read()) {
have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
@@ -185,10 +206,16 @@ bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_ma
if (const Volume *volume = this->get_volume_for_read()) {
have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max);
}
- if (const Curves *curves = this->get_curves_for_read()) {
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
+ if (const Curves *curves_id = this->get_curves_for_read()) {
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
/* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */
- have_minmax |= curve->bounds_min_max(*r_min, *r_max, true);
+ std::optional<bounds::MinMaxResult<float3>> min_max = bounds::min_max(
+ curves.evaluated_positions());
+ if (min_max) {
+ have_minmax = true;
+ *r_min = math::min(*r_min, min_max->min);
+ *r_max = math::max(*r_max, min_max->max);
+ }
}
return have_minmax;
}
@@ -315,6 +342,16 @@ GeometrySet GeometrySet::create_with_mesh(Mesh *mesh, GeometryOwnershipType owne
return geometry_set;
}
+GeometrySet GeometrySet::create_with_volume(Volume *volume, GeometryOwnershipType ownership)
+{
+ GeometrySet geometry_set;
+ if (volume != nullptr) {
+ VolumeComponent &component = geometry_set.get_component_for_write<VolumeComponent>();
+ component.replace(volume, ownership);
+ }
+ return geometry_set;
+}
+
GeometrySet GeometrySet::create_with_pointcloud(PointCloud *pointcloud,
GeometryOwnershipType ownership)
{
@@ -427,11 +464,14 @@ void GeometrySet::attribute_foreach(const Span<GeometryComponentType> component_
continue;
}
const GeometryComponent &component = *this->get_component_for_read(component_type);
- component.attribute_foreach(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- callback(attribute_id, meta_data, component);
- return true;
- });
+ const std::optional<AttributeAccessor> attributes = component.attributes();
+ if (attributes.has_value()) {
+ attributes->for_all(
+ [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ callback(attribute_id, meta_data, component);
+ return true;
+ });
+ }
}
if (include_instances && this->has_instances()) {
const InstancesComponent &instances = *this->get_component_for_read<InstancesComponent>();
@@ -445,7 +485,7 @@ void GeometrySet::gather_attributes_for_propagation(
const Span<GeometryComponentType> component_types,
const GeometryComponentType dst_component_type,
bool include_instances,
- blender::Map<blender::bke::AttributeIDRef, AttributeKind> &r_attributes) const
+ blender::Map<blender::bke::AttributeIDRef, blender::bke::AttributeKind> &r_attributes) const
{
using namespace blender;
using namespace blender::bke;
@@ -458,8 +498,8 @@ void GeometrySet::gather_attributes_for_propagation(
[&](const AttributeIDRef &attribute_id,
const AttributeMetaData &meta_data,
const GeometryComponent &component) {
- if (component.attribute_is_builtin(attribute_id)) {
- if (!dummy_component->attribute_is_builtin(attribute_id)) {
+ if (component.attributes()->is_builtin(attribute_id)) {
+ if (!dummy_component->attributes()->is_builtin(attribute_id)) {
/* Don't propagate built-in attributes that are not built-in on the destination
* component. */
return;
@@ -470,7 +510,7 @@ void GeometrySet::gather_attributes_for_propagation(
return;
}
- AttributeDomain domain = meta_data.domain;
+ eAttrDomain domain = meta_data.domain;
if (dst_component_type != GEO_COMPONENT_TYPE_INSTANCES && domain == ATTR_DOMAIN_INSTANCE) {
domain = ATTR_DOMAIN_POINT;
}
@@ -567,7 +607,7 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback)
namespace blender::bke {
GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index d3c3f41779a..df48a99f706 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -27,14 +27,12 @@ static void geometry_set_collect_recursive_collection(const Collection &collecti
static void add_final_mesh_as_geometry_component(const Object &object, GeometrySet &geometry_set)
{
- Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(&const_cast<Object &>(object),
- false);
+ Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(
+ &const_cast<Object &>(object));
if (mesh != nullptr) {
BKE_mesh_wrapper_ensure_mdata(mesh);
-
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
+ geometry_set.replace_mesh(mesh, GeometryOwnershipType::ReadOnly);
}
}
@@ -73,11 +71,6 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
return geometry_set;
}
- /* 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 {};
}
@@ -164,41 +157,6 @@ void geometry_set_gather_instances(const GeometrySet &geometry_set,
geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups);
}
-void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups,
- Span<GeometryComponentType> component_types,
- const Set<std::string> &ignored_attributes,
- Map<AttributeIDRef, AttributeKind> &r_attributes)
-{
- 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)) {
- continue;
- }
- const GeometryComponent &component = *set.get_component_for_read(component_type);
-
- component.attribute_foreach(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) {
- return true;
- }
- auto add_info = [&](AttributeKind *attribute_kind) {
- attribute_kind->domain = meta_data.domain;
- attribute_kind->data_type = meta_data.data_type;
- };
- auto modify_info = [&](AttributeKind *attribute_kind) {
- attribute_kind->domain = meta_data.domain; /* TODO: Use highest priority domain. */
- attribute_kind->data_type = bke::attribute_data_type_highest_complexity(
- {attribute_kind->data_type, meta_data.data_type});
- };
-
- r_attributes.add_or_modify(attribute_id, add_info, modify_info);
- return true;
- });
- }
- }
-}
-
} // namespace blender::bke
void InstancesComponent::foreach_referenced_geometry(
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 35b514ac1a0..3d546c5c36a 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -55,8 +55,6 @@
#include "BLO_read_write.h"
-#include "BKE_gpencil.h"
-
static CLG_LogRef LOG = {"bke.gpencil"};
static void greasepencil_copy_data(Main *UNUSED(bmain),
@@ -867,7 +865,7 @@ bGPDstroke *BKE_gpencil_stroke_duplicate(bGPDstroke *gps_src,
if (dup_points) {
gps_dst->points = MEM_dupallocN(gps_src->points);
- if ((gps_src->dvert != NULL) && (gps_src->dvert->totweight > 0)) {
+ if (gps_src->dvert != NULL) {
gps_dst->dvert = MEM_dupallocN(gps_src->dvert);
BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst);
}
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 20b8342f090..d68b322e4c5 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -501,7 +501,7 @@ void BKE_gpencil_convert_curve(Main *bmain,
}
/* Check if there is an active frame and add if needed. */
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_COPY);
/* Read all splines of the curve and create a stroke for each. */
LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index dd22d64aee1..d0075a7d161 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -25,8 +25,6 @@
#include "BLI_polyfill_2d.h"
#include "BLI_span.hh"
-#include "BLT_translation.h"
-
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_material_types.h"
@@ -2708,7 +2706,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
gpl_fill = BKE_gpencil_layer_addnew(gpd, element_name, true, false);
}
bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get(
- gpl_fill, CFRA + frame_offset, GP_GETFRAME_ADD_NEW);
+ gpl_fill, scene->r.cfra + frame_offset, GP_GETFRAME_ADD_NEW);
int i;
for (i = 0; i < mpoly_len; i++) {
const MPoly *mp = &mpoly[i];
@@ -2783,7 +2781,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain,
gpl_stroke = BKE_gpencil_layer_addnew(gpd, element_name, true, false);
}
bGPDframe *gpf_stroke = BKE_gpencil_layer_frame_get(
- gpl_stroke, CFRA + frame_offset, GP_GETFRAME_ADD_NEW);
+ gpl_stroke, scene->r.cfra + frame_offset, GP_GETFRAME_ADD_NEW);
gpencil_generate_edgeloops(ob_eval,
gpd,
@@ -4209,7 +4207,14 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d,
if (gps->totpoints == 0) {
return nullptr;
}
- bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, true, false);
+ /* Duplicate only points and fill data. Weight and Curve are not needed. */
+ bGPDstroke *gps_temp = (bGPDstroke *)MEM_dupallocN(gps);
+ gps_temp->prev = gps_temp->next = nullptr;
+ gps_temp->triangles = (bGPDtriangle *)MEM_dupallocN(gps->triangles);
+ gps_temp->points = (bGPDspoint *)MEM_dupallocN(gps->points);
+ gps_temp->dvert = nullptr;
+ gps_temp->editcurve = nullptr;
+
const bool cyclic = ((gps_temp->flag & GP_STROKE_CYCLIC) != 0);
/* If Cyclic, add a new point. */
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index faafd1e1040..82899b974bc 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -95,7 +95,7 @@ void BKE_gpencil_cache_data_init(Depsgraph *depsgraph, Object *ob)
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);
+ Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__);
if (BKE_shrinkwrap_init_tree(
mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) {
@@ -221,6 +221,9 @@ GpencilLineartLimitInfo BKE_gpencil_get_lineart_modifier_limits(const Object *ob
info.max_level = MAX2(info.max_level,
(lmd->use_multiple_levels ? lmd->level_end : lmd->level_start));
info.edge_types |= lmd->edge_types;
+ info.shadow_selection = MAX2(lmd->shadow_selection, info.shadow_selection);
+ info.silhouette_selection = MAX2(lmd->silhouette_selection, info.silhouette_selection);
+ is_first = false;
}
}
}
@@ -237,11 +240,15 @@ void BKE_gpencil_set_lineart_modifier_limits(GpencilModifierData *md,
lmd->level_start_override = info->min_level;
lmd->level_end_override = info->max_level;
lmd->edge_types_override = info->edge_types;
+ lmd->shadow_selection_override = info->shadow_selection;
+ lmd->shadow_use_silhouette_override = info->silhouette_selection;
}
else {
lmd->level_start_override = lmd->level_start;
lmd->level_end_override = lmd->level_end;
lmd->edge_types_override = lmd->edge_types;
+ lmd->shadow_selection_override = lmd->shadow_selection;
+ lmd->shadow_use_silhouette_override = lmd->silhouette_selection;
}
}
@@ -647,32 +654,38 @@ static bGPdata *gpencil_copy_structure_for_eval(bGPdata *gpd)
return gpd_eval;
}
-static void copy_frame_to_eval_cb(bGPDlayer *UNUSED(gpl),
+static void copy_frame_to_eval_ex(bGPDframe *gpf_orig, bGPDframe *gpf_eval)
+{
+ /* Free any existing eval stroke data. This happens in case we have a single user on the data
+ * block and the strokes have not been deleted. */
+ if (!BLI_listbase_is_empty(&gpf_eval->strokes)) {
+ BKE_gpencil_free_strokes(gpf_eval);
+ }
+ /* Copy strokes to eval frame and update internal orig pointers. */
+ BKE_gpencil_frame_copy_strokes(gpf_orig, gpf_eval);
+ BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf_eval);
+}
+
+static void copy_frame_to_eval_cb(bGPDlayer *gpl,
bGPDframe *gpf,
bGPDstroke *UNUSED(gps),
void *UNUSED(thunk))
{
- /* Early return when callback is not provided with a frame. */
- if (gpf == NULL) {
+ /* Early return when callback:
+ * - Is not provided with a frame.
+ * - When the frame is the layer's active frame (already handled in
+ * gpencil_copy_visible_frames_to_eval).
+ */
+ if (gpf == NULL || gpf == gpl->actframe) {
return;
}
- /* Free any existing eval stroke data. This happens in case we have a single user on the data
- * block and the strokes have not been deleted. */
- if (!BLI_listbase_is_empty(&gpf->strokes)) {
- BKE_gpencil_free_strokes(gpf);
- }
-
- /* Get original frame. */
- bGPDframe *gpf_orig = gpf->runtime.gpf_orig;
- /* Copy strokes to eval frame and update internal orig pointers. */
- BKE_gpencil_frame_copy_strokes(gpf_orig, gpf);
- BKE_gpencil_frame_original_pointers_update(gpf_orig, gpf);
+ copy_frame_to_eval_ex(gpf->runtime.gpf_orig, gpf);
}
static void gpencil_copy_visible_frames_to_eval(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- /* Remap layers' active frame with time modifiers applied. */
+ /* Remap layers active frame with time modifiers applied. */
bGPdata *gpd_eval = ob->data;
LISTBASE_FOREACH (bGPDlayer *, gpl_eval, &gpd_eval->layers) {
bGPDframe *gpf_eval = gpl_eval->actframe;
@@ -680,9 +693,14 @@ static void gpencil_copy_visible_frames_to_eval(Depsgraph *depsgraph, Scene *sce
if (gpf_eval == NULL || gpf_eval->framenum != remap_cfra) {
gpl_eval->actframe = BKE_gpencil_layer_frame_get(gpl_eval, remap_cfra, GP_GETFRAME_USE_PREV);
}
+ /* Always copy active frame to eval, because the modifiers always evaluate the active frame,
+ * even if it's not visible (e.g. the layer is hidden).*/
+ if (gpl_eval->actframe != NULL) {
+ copy_frame_to_eval_ex(gpl_eval->actframe->runtime.gpf_orig, gpl_eval->actframe);
+ }
}
- /* Copy only visible frames to evaluated version. */
+ /* Copy visible frames that are not the active one to evaluated version. */
BKE_gpencil_visible_stroke_advanced_iter(
NULL, ob, copy_frame_to_eval_cb, NULL, NULL, true, scene->r.cfra);
}
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index e99230ef523..35f02c29a00 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -168,7 +168,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen)
/* NOTE: This code comes from python, here's the corresponding comment. */
/* This over-allocates proportional to the list size, making room
- * for additional growth. The over-allocation is mild, but is
+ * for additional growth. The over-allocation is mild, but is
* enough to give linear-time amortized behavior over a long
* sequence of appends() in the presence of a poorly-performing
* system realloc().
diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c
index e55143d6852..923582dff4c 100644
--- a/source/blender/blenkernel/intern/idtype.c
+++ b/source/blender/blenkernel/intern/idtype.c
@@ -209,7 +209,11 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
case ID_##_id: \
return FILTER_ID_##_id
- switch (idcode) {
+#define CASE_IDFILTER_NONE(_id) \
+ case ID_##_id: \
+ return 0
+
+ switch ((ID_Type)idcode) {
CASE_IDFILTER(AC);
CASE_IDFILTER(AR);
CASE_IDFILTER(BR);
@@ -220,7 +224,11 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(GR);
CASE_IDFILTER(CV);
CASE_IDFILTER(IM);
+ CASE_IDFILTER_NONE(IP);
+ CASE_IDFILTER(KE);
CASE_IDFILTER(LA);
+ CASE_IDFILTER(LI);
+ CASE_IDFILTER(LP);
CASE_IDFILTER(LS);
CASE_IDFILTER(LT);
CASE_IDFILTER(MA);
@@ -234,22 +242,25 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode)
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
CASE_IDFILTER(PT);
- CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SCR);
CASE_IDFILTER(SIM);
- CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
+ CASE_IDFILTER(SPK);
CASE_IDFILTER(TE);
CASE_IDFILTER(TXT);
CASE_IDFILTER(VF);
CASE_IDFILTER(VO);
+ CASE_IDFILTER(WM);
CASE_IDFILTER(WO);
CASE_IDFILTER(WS);
- default:
- return 0;
}
+ BLI_assert_unreachable();
+ return 0;
+
#undef CASE_IDFILTER
+#undef CASE_IDFILTER_NONE
}
short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
@@ -258,6 +269,8 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
case FILTER_ID_##_id: \
return ID_##_id
+#define CASE_IDFILTER_NONE(_id) (void)0
+
switch (idfilter) {
CASE_IDFILTER(AC);
CASE_IDFILTER(AR);
@@ -269,7 +282,11 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
CASE_IDFILTER(GR);
CASE_IDFILTER(CV);
CASE_IDFILTER(IM);
+ CASE_IDFILTER_NONE(IP);
+ CASE_IDFILTER(KE);
CASE_IDFILTER(LA);
+ CASE_IDFILTER(LI);
+ CASE_IDFILTER(LP);
CASE_IDFILTER(LS);
CASE_IDFILTER(LT);
CASE_IDFILTER(MA);
@@ -283,21 +300,25 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter)
CASE_IDFILTER(PAL);
CASE_IDFILTER(PC);
CASE_IDFILTER(PT);
- CASE_IDFILTER(LP);
CASE_IDFILTER(SCE);
+ CASE_IDFILTER(SCR);
CASE_IDFILTER(SIM);
- CASE_IDFILTER(SPK);
CASE_IDFILTER(SO);
+ CASE_IDFILTER(SPK);
CASE_IDFILTER(TE);
CASE_IDFILTER(TXT);
CASE_IDFILTER(VF);
CASE_IDFILTER(VO);
+ CASE_IDFILTER(WM);
CASE_IDFILTER(WO);
- default:
- return 0;
+ CASE_IDFILTER(WS);
}
+ BLI_assert_unreachable();
+ return 0;
+
#undef CASE_IDFILTER
+#undef CASE_IDFILTER_NONE
}
int BKE_idtype_idcode_to_index(const short idcode)
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index bc21e706d1e..f8b2d841028 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -1172,24 +1172,83 @@ Image *BKE_image_add_generated(Main *bmain,
return ima;
}
-Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
+static void image_colorspace_from_imbuf(Image *image, const ImBuf *ibuf)
{
- Image *ima;
+ const char *colorspace_name = NULL;
+ if (ibuf->rect_float) {
+ if (ibuf->float_colorspace) {
+ colorspace_name = IMB_colormanagement_colorspace_get_name(ibuf->float_colorspace);
+ }
+ else {
+ colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_FLOAT);
+ }
+ }
+
+ if (ibuf->rect && !colorspace_name) {
+ if (ibuf->rect_colorspace) {
+ colorspace_name = IMB_colormanagement_colorspace_get_name(ibuf->rect_colorspace);
+ }
+ else {
+ colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE);
+ }
+ }
+
+ if (colorspace_name) {
+ STRNCPY(image->colorspace_settings.name, colorspace_name);
+ }
+}
+
+Image *BKE_image_add_from_imbuf(Main *bmain, ImBuf *ibuf, const char *name)
+{
if (name == nullptr) {
name = BLI_path_basename(ibuf->name);
}
- ima = image_alloc(bmain, name, IMA_SRC_FILE, IMA_TYPE_IMAGE);
+ /* When the image buffer has valid path create a new image with "file" source and copy the path
+ * from the image buffer.
+ * Otherwise create "generated" image, avoiding invalid configuration with an empty file path. */
+ const eImageSource source = ibuf->name[0] != '\0' ? IMA_SRC_FILE : IMA_SRC_GENERATED;
- if (ima) {
- STRNCPY(ima->filepath, ibuf->name);
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ Image *ima = image_alloc(bmain, name, source, IMA_TYPE_IMAGE);
+
+ if (!ima) {
+ return nullptr;
}
+ BKE_image_replace_imbuf(ima, ibuf);
+
return ima;
}
+void BKE_image_replace_imbuf(Image *image, ImBuf *ibuf)
+{
+ BLI_assert(image->type == IMA_TYPE_IMAGE &&
+ ELEM(image->source, IMA_SRC_FILE, IMA_SRC_GENERATED));
+
+ BKE_image_free_buffers(image);
+
+ image_assign_ibuf(image, ibuf, IMA_NO_INDEX, 0);
+ image_colorspace_from_imbuf(image, ibuf);
+
+ /* Keep generated image type flags consistent with the image buffer. */
+ if (image->source == IMA_SRC_GENERATED) {
+ if (ibuf->rect_float) {
+ image->gen_flag |= IMA_GEN_FLOAT;
+ }
+ else {
+ image->gen_flag &= ~IMA_GEN_FLOAT;
+ }
+
+ image->gen_x = ibuf->x;
+ image->gen_y = ibuf->y;
+ }
+
+ /* Consider image dirty since its content can not be re-created unless the image is explicitly
+ * saved. */
+ BKE_image_mark_dirty(image, ibuf);
+}
+
/** Pack image buffer to memory as PNG or EXR. */
static bool image_memorypack_imbuf(
Image *ima, ImBuf *ibuf, int view, int tile_number, const char *filepath)
@@ -1582,7 +1641,7 @@ static void stampdata(
}
if (use_dynamic && scene->r.stamp & R_STAMP_MARKER) {
- const char *name = BKE_scene_find_last_marker_name(scene, CFRA);
+ const char *name = BKE_scene_find_last_marker_name(scene, scene->r.cfra);
if (name) {
STRNCPY(text, name);
@@ -1730,7 +1789,7 @@ static void stampdata_from_template(StampData *stamp_data,
stamp_data->file[0] = '\0';
}
if (scene->r.stamp & R_STAMP_NOTE) {
- SNPRINTF(stamp_data->note, "%s", stamp_data_template->note);
+ STRNCPY(stamp_data->note, stamp_data_template->note);
}
else {
stamp_data->note[0] = '\0';
@@ -1950,7 +2009,7 @@ void BKE_image_stamp_buf(Scene *scene,
y -= BUFF_MARGIN_Y * 2;
}
- /* Top left corner, below File, Date, Rendertime */
+ /* Top left corner, below File, Date, Render-time */
if (TEXT_SIZE_CHECK(stamp_data.memory, w, h)) {
y -= h;
@@ -1973,7 +2032,7 @@ void BKE_image_stamp_buf(Scene *scene,
y -= BUFF_MARGIN_Y * 2;
}
- /* Top left corner, below File, Date, Rendertime, Memory */
+ /* Top left corner, below: File, Date, Render-time, Memory. */
if (TEXT_SIZE_CHECK(stamp_data.hostname, w, h)) {
y -= h;
@@ -1996,7 +2055,7 @@ void BKE_image_stamp_buf(Scene *scene,
y -= BUFF_MARGIN_Y * 2;
}
- /* Top left corner, below File, Date, Memory, Rendertime, Hostname */
+ /* Top left corner, below: File, Date, Memory, Render-time, Host-name. */
BLF_enable(mono, BLF_WORD_WRAP);
if (TEXT_SIZE_CHECK_WORD_WRAP(stamp_data.note, w, h)) {
y -= h;
@@ -2416,7 +2475,10 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, const ImageFormatData *imf)
return ok;
}
-int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, const bool save_copy)
+int BKE_imbuf_write_as(ImBuf *ibuf,
+ const char *name,
+ const ImageFormatData *imf,
+ const bool save_copy)
{
ImBuf ibuf_back = *ibuf;
int ok;
@@ -2929,6 +2991,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
MEM_freeN(tile);
}
base_tile->next = nullptr;
+ base_tile->tile_number = 1001;
ima->tiles.last = base_tile;
}
@@ -3111,7 +3174,9 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
char filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
- BKE_image_ensure_tile_token(filename);
+ if (!BKE_image_is_filename_tokenized(filename)) {
+ BKE_image_ensure_tile_token(filename);
+ }
eUDIM_TILE_FORMAT tile_format;
char *udim_pattern = BKE_image_get_tile_strformat(filename, &tile_format);
@@ -3145,10 +3210,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
BLI_filelist_free(dirs, dirs_num);
MEM_SAFE_FREE(udim_pattern);
- /* Ensure that all discovered UDIMs are valid and that there's at least 2 files in total.
- * Downstream code checks the range value to determine tiled-ness; it's important we match that
- * expectation here too (T97366). */
- if (all_valid_udim && min_udim <= IMA_UDIM_MAX && max_udim > min_udim) {
+ if (all_valid_udim && min_udim <= IMA_UDIM_MAX) {
BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
*r_tile_start = min_udim;
@@ -3315,13 +3377,18 @@ bool BKE_image_fill_tile(struct Image *ima,
return false;
}
+bool BKE_image_is_filename_tokenized(char *filepath)
+{
+ const char *filename = BLI_path_basename(filepath);
+ return strstr(filename, "<UDIM>") != nullptr || strstr(filename, "<UVTILE>") != nullptr;
+}
+
void BKE_image_ensure_tile_token(char *filename)
{
BLI_assert_msg(BLI_path_slash_find(filename) == nullptr,
"Only the file-name component should be used!");
- /* Is there a '<' character in the filename? Assume tokens already present. */
- if (strstr(filename, "<") != nullptr) {
+ if (BKE_image_is_filename_tokenized(filename)) {
return;
}
@@ -3890,7 +3957,7 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
}
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D) {
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]);
}
for (int i = 0; i < totviews; i++) {
@@ -4059,7 +4126,7 @@ static ImBuf *image_load_image_file(
/* multi-views/multi-layers OpenEXR files directly populate ima, and return null ibuf... */
if (BKE_image_is_stereo(ima) && ima->views_format == R_IMF_VIEWS_STEREO_3D && ibuf_arr[0] &&
tot_viewfiles == 1 && totviews >= 2) {
- IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], &ibuf_arr[0], &ibuf_arr[1]);
+ IMB_ImBufFromStereo3d(ima->stereo3d_format, ibuf_arr[0], ibuf_arr.data(), &ibuf_arr[1]);
}
/* return the original requested ImBuf */
@@ -4993,13 +5060,7 @@ void BKE_image_get_size(Image *image, ImageUser *iuser, int *r_width, int *r_hei
}
else if (image != nullptr && image->type == IMA_TYPE_R_RESULT && iuser != nullptr &&
iuser->scene != nullptr) {
- Scene *scene = iuser->scene;
- *r_width = (scene->r.xsch * scene->r.size) / 100;
- *r_height = (scene->r.ysch * scene->r.size) / 100;
- if ((scene->r.mode & R_BORDER) && (scene->r.mode & R_CROP)) {
- *r_width *= BLI_rctf_size_x(&scene->r.border);
- *r_height *= BLI_rctf_size_y(&scene->r.border);
- }
+ BKE_render_resolution(&iuser->scene->r, true, r_width, r_height);
}
else {
*r_width = IMG_SIZE_FALLBACK;
diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc
index bed79a318e8..6506b40b603 100644
--- a/source/blender/blenkernel/intern/image_gpu.cc
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -718,12 +718,31 @@ static void gpu_texture_update_from_ibuf(
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 == 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);
+ if (rect_float) {
+ /* Float image is already in scene linear colorspace or non-color data by
+ * convention, no colorspace conversion needed. But we do require 4 channels
+ * currently. */
+ if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+ rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
+ if (rect_float == nullptr) {
+ return;
+ }
+ tex_stride = w;
+ tex_offset = 0;
+
+ IMB_colormanagement_imbuf_to_float_texture(
+ rect_float, x, y, w, h, ibuf, store_premultiplied);
+ }
+ }
+ else {
+ /* Byte image is in original colorspace from the file, and may need conversion. */
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ /* Non-color data, just store buffer as is. */
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */
rect = (uchar *)MEM_mallocN(sizeof(uchar[4]) * w * h, __func__);
if (rect == nullptr) {
return;
@@ -734,13 +753,10 @@ static void gpu_texture_update_from_ibuf(
/* Convert to scene linear with sRGB compression, and premultiplied for
* correct texture interpolation. */
- IMB_colormanagement_imbuf_to_byte_texture(
- rect, x, y, w, h, ibuf, compress_as_srgb, store_premultiplied);
+ IMB_colormanagement_imbuf_to_byte_texture(rect, x, y, w, h, ibuf, store_premultiplied);
}
- }
- else {
- /* Float pixels. */
- if (ibuf->channels != 4 || scaled || !store_premultiplied) {
+ else {
+ /* Other colorspace, store as float texture to avoid precision loss. */
rect_float = (float *)MEM_mallocN(sizeof(float[4]) * w * h, __func__);
if (rect_float == nullptr) {
return;
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index b67d3490e03..cd86d3f7087 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -78,7 +78,8 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
Scene *scene,
Image *ima,
ImageUser *iuser,
- const bool guess_path)
+ const bool guess_path,
+ const bool save_as_render)
{
/* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
ImageUser save_iuser;
@@ -92,7 +93,7 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
opts->bmain = bmain;
opts->scene = scene;
- opts->save_as_render = ima->source == IMA_SRC_VIEWER;
+ opts->save_as_render = ima->source == IMA_SRC_VIEWER || save_as_render;
BKE_image_format_init(&opts->im_format, false);
@@ -104,9 +105,9 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
bool is_depth_set = false;
const char *ima_colorspace = ima->colorspace_settings.name;
- if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
- /* imtype */
- BKE_image_format_init_for_write(&opts->im_format, scene, NULL);
+ if (opts->save_as_render) {
+ /* Render/compositor output or user chose to save with render settings. */
+ BKE_image_format_init_for_write(&opts->im_format, scene, nullptr);
is_depth_set = true;
if (!BKE_image_is_multiview(ima)) {
/* In case multiview is disabled,
@@ -187,7 +188,7 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
}
/* append UDIM marker if not present */
- if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == NULL) {
+ if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == nullptr) {
int len = strlen(opts->filepath);
STR_CONCAT(opts->filepath, len, ".<UDIM>");
}
@@ -200,16 +201,16 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
BKE_image_release_ibuf(ima, ibuf, lock);
- return (ibuf != NULL);
+ return (ibuf != nullptr);
}
-void BKE_image_save_options_update(ImageSaveOptions *opts, Image *image)
+void BKE_image_save_options_update(ImageSaveOptions *opts, const Image *image)
{
/* Auto update color space when changing save as render and file type. */
if (opts->save_as_render) {
if (!opts->prev_save_as_render) {
if (ELEM(image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
- BKE_image_format_init_for_write(&opts->im_format, opts->scene, NULL);
+ BKE_image_format_init_for_write(&opts->im_format, opts->scene, nullptr);
}
else {
BKE_image_format_color_management_copy_from_scene(&opts->im_format, opts->scene);
@@ -252,11 +253,26 @@ void BKE_image_save_options_free(ImageSaveOptions *opts)
BKE_image_format_free(&opts->im_format);
}
+static void image_save_update_filepath(Image *ima,
+ const char *filepath,
+ const ImageSaveOptions *opts)
+{
+ if (opts->do_newpath) {
+ BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
+
+ /* only image path, never ibuf */
+ if (opts->relative) {
+ const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
+ BLI_path_rel(ima->filepath, relbase); /* only after saving */
+ }
+ }
+}
+
static void image_save_post(ReportList *reports,
Image *ima,
ImBuf *ibuf,
int ok,
- ImageSaveOptions *opts,
+ const ImageSaveOptions *opts,
int save_copy,
const char *filepath,
bool *r_colorspace_changed)
@@ -272,7 +288,11 @@ static void image_save_post(ReportList *reports,
if (opts->do_newpath) {
BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
- BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
+ }
+
+ /* The tiled image code-path must call this on its own. */
+ if (ima->source != IMA_SRC_TILED) {
+ image_save_update_filepath(ima, filepath, opts);
}
ibuf->userflags &= ~IB_BITMAPDIRTY;
@@ -302,12 +322,6 @@ static void image_save_post(ReportList *reports,
ima->type = IMA_TYPE_IMAGE;
}
- /* only image path, never ibuf */
- if (opts->relative) {
- const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
- BLI_path_rel(ima->filepath, relbase); /* only after saving */
- }
-
/* Update image file color space when saving to another color space. */
const bool linear_float_output = BKE_imtype_requires_linear_float(opts->im_format.imtype);
@@ -345,7 +359,7 @@ static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
static bool image_save_single(ReportList *reports,
Image *ima,
ImageUser *iuser,
- ImageSaveOptions *opts,
+ const ImageSaveOptions *opts,
bool *r_colorspace_changed)
{
void *lock;
@@ -361,7 +375,7 @@ static bool image_save_single(ReportList *reports,
ImBuf *colormanaged_ibuf = nullptr;
const bool save_copy = opts->save_copy;
const bool save_as_render = opts->save_as_render;
- ImageFormatData *imf = &opts->im_format;
+ const ImageFormatData *imf = &opts->im_format;
if (ima->type == IMA_TYPE_R_RESULT) {
/* enforce user setting for RGB or RGBA, but skip BW */
@@ -606,7 +620,7 @@ static bool image_save_single(ReportList *reports,
}
bool BKE_image_save(
- ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
+ ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, const ImageSaveOptions *opts)
{
/* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
ImageUser save_iuser;
@@ -639,22 +653,23 @@ bool BKE_image_save(
ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
}
else {
- char filepath[FILE_MAX];
- BLI_strncpy(filepath, opts->filepath, sizeof(filepath));
-
/* Save all the tiles. */
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ ImageSaveOptions tile_opts = *opts;
BKE_image_set_filepath_from_tile_number(
- opts->filepath, udim_pattern, tile_format, tile->tile_number);
+ tile_opts.filepath, udim_pattern, tile_format, tile->tile_number);
iuser->tile = tile->tile_number;
- ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
+ ok = image_save_single(reports, ima, iuser, &tile_opts, &colorspace_changed);
if (!ok) {
break;
}
}
- BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
- BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
+
+ /* Set the image path only if all tiles were ok. */
+ if (ok) {
+ image_save_update_filepath(ima, opts->filepath, opts);
+ }
MEM_freeN(udim_pattern);
}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 594cffe6406..7ef15912567 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -191,7 +191,7 @@ static void shapekey_blend_read_expand(BlendExpander *expander, ID *id)
IDTypeInfo IDType_ID_KE = {
.id_code = ID_KE,
- .id_filter = 0,
+ .id_filter = FILTER_ID_KE,
.main_listbase_index = INDEX_ID_KE,
.struct_size = sizeof(Key),
.name = "Key",
@@ -1501,7 +1501,14 @@ static void do_latt_key(Object *ob, Key *key, char *out, const int tot)
}
}
-float *BKE_key_evaluate_object_ex(Object *ob, int *r_totelem, float *arr, size_t arr_size)
+static void keyblock_data_convert_to_mesh(const float (*fp)[3], MVert *mvert, const int totvert);
+static void keyblock_data_convert_to_lattice(const float (*fp)[3],
+ BPoint *bpoint,
+ const int totpoint);
+static void keyblock_data_convert_to_curve(const float *fp, ListBase *nurb, const int totpoint);
+
+float *BKE_key_evaluate_object_ex(
+ Object *ob, int *r_totelem, float *arr, size_t arr_size, ID *obdata)
{
Key *key = BKE_key_from_object(ob);
KeyBlock *actkb = BKE_keyblock_from_object(ob);
@@ -1576,7 +1583,6 @@ float *BKE_key_evaluate_object_ex(Object *ob, int *r_totelem, float *arr, size_t
}
}
else {
-
if (ob->type == OB_MESH) {
do_mesh_key(ob, key, out, tot);
}
@@ -1591,6 +1597,31 @@ float *BKE_key_evaluate_object_ex(Object *ob, int *r_totelem, float *arr, size_t
}
}
+ if (obdata != NULL) {
+ switch (GS(obdata->name)) {
+ case ID_ME: {
+ Mesh *mesh = (Mesh *)obdata;
+ const int totvert = min_ii(tot, mesh->totvert);
+ keyblock_data_convert_to_mesh((const float(*)[3])out, mesh->mvert, totvert);
+ break;
+ }
+ case ID_LT: {
+ Lattice *lattice = (Lattice *)obdata;
+ const int totpoint = min_ii(tot, lattice->pntsu * lattice->pntsv * lattice->pntsw);
+ keyblock_data_convert_to_lattice((const float(*)[3])out, lattice->def, totpoint);
+ break;
+ }
+ case ID_CU_LEGACY: {
+ Curve *curve = (Curve *)obdata;
+ const int totpoint = min_ii(tot, BKE_keyblock_curve_element_count(&curve->nurb));
+ keyblock_data_convert_to_curve((const float *)out, &curve->nurb, totpoint);
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+ }
+
if (r_totelem) {
*r_totelem = tot;
}
@@ -1599,7 +1630,7 @@ float *BKE_key_evaluate_object_ex(Object *ob, int *r_totelem, float *arr, size_t
float *BKE_key_evaluate_object(Object *ob, int *r_totelem)
{
- return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0);
+ return BKE_key_evaluate_object_ex(ob, r_totelem, NULL, 0, NULL);
}
int BKE_keyblock_element_count_from_shape(const Key *key, const int shape_index)
@@ -1971,21 +2002,22 @@ void BKE_keyblock_convert_from_lattice(const Lattice *lt, KeyBlock *kb)
BKE_keyblock_update_from_lattice(lt, kb);
}
-void BKE_keyblock_convert_to_lattice(const KeyBlock *kb, Lattice *lt)
+static void keyblock_data_convert_to_lattice(const float (*fp)[3],
+ BPoint *bpoint,
+ const int totpoint)
{
- BPoint *bp;
- const float(*fp)[3];
- int a, tot;
-
- bp = lt->def;
- fp = kb->data;
+ for (int i = 0; i < totpoint; i++, fp++, bpoint++) {
+ copy_v3_v3(bpoint->vec, *fp);
+ }
+}
- tot = lt->pntsu * lt->pntsv * lt->pntsw;
- tot = min_ii(kb->totelem, tot);
+void BKE_keyblock_convert_to_lattice(const KeyBlock *kb, Lattice *lt)
+{
+ BPoint *bp = lt->def;
+ const float(*fp)[3] = kb->data;
+ const int tot = min_ii(kb->totelem, lt->pntsu * lt->pntsv * lt->pntsw);
- for (a = 0; a < tot; a++, fp++, bp++) {
- copy_v3_v3(bp->vec, *fp);
- }
+ keyblock_data_convert_to_lattice(fp, bp, tot);
}
/************************* Curve ************************/
@@ -2097,42 +2129,40 @@ void BKE_keyblock_convert_from_curve(const Curve *cu, KeyBlock *kb, const ListBa
BKE_keyblock_update_from_curve(cu, kb, nurb);
}
-void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nurb)
+static void keyblock_data_convert_to_curve(const float *fp, ListBase *nurb, int totpoint)
{
- Nurb *nu;
- BezTriple *bezt;
- BPoint *bp;
- const float *fp;
- int a, tot;
-
- tot = BKE_keyblock_curve_element_count(nurb);
- tot = min_ii(kb->totelem, tot);
-
- fp = kb->data;
- for (nu = nurb->first; nu && tot > 0; nu = nu->next) {
- if (nu->bezt) {
- for (a = nu->pntsu, bezt = nu->bezt; a && (tot -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0;
- a--, bezt++) {
- for (int i = 0; i < 3; i++) {
- copy_v3_v3(bezt->vec[i], &fp[i * 3]);
+ for (Nurb *nu = nurb->first; nu && totpoint > 0; nu = nu->next) {
+ if (nu->bezt != NULL) {
+ BezTriple *bezt = nu->bezt;
+ for (int i = nu->pntsu; i && (totpoint -= KEYELEM_ELEM_LEN_BEZTRIPLE) >= 0;
+ i--, bezt++, fp += KEYELEM_FLOAT_LEN_BEZTRIPLE) {
+ for (int j = 0; j < 3; j++) {
+ copy_v3_v3(bezt->vec[j], &fp[j * 3]);
}
bezt->tilt = fp[9];
bezt->radius = fp[10];
- fp += KEYELEM_FLOAT_LEN_BEZTRIPLE;
}
}
else {
- for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a && (tot -= KEYELEM_ELEM_LEN_BPOINT) >= 0;
- a--, bp++) {
+ BPoint *bp = nu->bp;
+ for (int i = nu->pntsu * nu->pntsv; i && (totpoint -= KEYELEM_ELEM_LEN_BPOINT) >= 0;
+ i--, bp++, fp += KEYELEM_FLOAT_LEN_BPOINT) {
copy_v3_v3(bp->vec, fp);
bp->tilt = fp[3];
bp->radius = fp[4];
- fp += KEYELEM_FLOAT_LEN_BPOINT;
}
}
}
}
+void BKE_keyblock_convert_to_curve(KeyBlock *kb, Curve *UNUSED(cu), ListBase *nurb)
+{
+ const float *fp = kb->data;
+ const int tot = min_ii(kb->totelem, BKE_keyblock_curve_element_count(nurb));
+
+ keyblock_data_convert_to_curve(fp, nurb, tot);
+}
+
/************************* Mesh ************************/
void BKE_keyblock_update_from_mesh(const Mesh *me, KeyBlock *kb)
@@ -2171,20 +2201,21 @@ void BKE_keyblock_convert_from_mesh(const Mesh *me, const Key *key, KeyBlock *kb
BKE_keyblock_update_from_mesh(me, kb);
}
-void BKE_keyblock_convert_to_mesh(const KeyBlock *kb, MVert *mvert, const int totvert)
+static void keyblock_data_convert_to_mesh(const float (*fp)[3], MVert *mvert, const int totvert)
{
- const float(*fp)[3];
- int a, tot;
-
- fp = kb->data;
-
- tot = min_ii(kb->totelem, totvert);
-
- for (a = 0; a < tot; a++, fp++, mvert++) {
+ for (int i = 0; i < totvert; i++, fp++, mvert++) {
copy_v3_v3(mvert->co, *fp);
}
}
+void BKE_keyblock_convert_to_mesh(const KeyBlock *kb, MVert *mvert, const int totvert)
+{
+ const float(*fp)[3] = kb->data;
+ const int tot = min_ii(kb->totelem, totvert);
+
+ keyblock_data_convert_to_mesh(fp, mvert, tot);
+}
+
void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
const Mesh *mesh,
float (*r_vertnors)[3],
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 2f8b3e00df9..affa1e72ad0 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -53,6 +53,7 @@
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
+#include "BKE_main_namemap.h"
#include "BKE_node.h"
#include "BKE_rigidbody.h"
@@ -186,7 +187,7 @@ void BKE_lib_id_clear_library_data(Main *bmain, ID *id, const int flags)
id->tag &= ~(LIB_TAG_INDIRECT | LIB_TAG_EXTERN);
id->flag &= ~LIB_INDIRECT_WEAK_LINK;
if (id_in_mainlist) {
- if (BKE_id_new_name_validate(which_libbase(bmain, GS(id->name)), id, NULL, false)) {
+ if (BKE_id_new_name_validate(bmain, which_libbase(bmain, GS(id->name)), id, NULL, false)) {
bmain->is_memfile_undo_written = false;
}
}
@@ -311,7 +312,7 @@ void id_us_min(ID *id)
const int limit = ID_FAKE_USERS(id);
if (id->us <= limit) {
- if (GS(id->name) != ID_IP) {
+ if (!ID_TYPE_IS_DEPRECATED(GS(id->name))) {
/* Do not assert on deprecated ID types, we cannot really ensure that their ID refcounting
* is valid... */
CLOG_ERROR(&LOG,
@@ -590,11 +591,9 @@ static int id_copy_libmanagement_cb(LibraryIDLinkCallbackData *cb_data)
bool BKE_id_copy_is_allowed(const ID *id)
{
-#define LIB_ID_TYPES_NOCOPY \
- ID_LI, ID_SCR, ID_WM, ID_WS, /* Not supported */ \
- ID_IP /* Deprecated */
+#define LIB_ID_TYPES_NOCOPY ID_LI, ID_SCR, ID_WM, ID_WS /* Not supported */
- return !ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY);
+ return !ID_TYPE_IS_DEPRECATED(GS(id->name)) && !ELEM(GS(id->name), LIB_ID_TYPES_NOCOPY);
#undef LIB_ID_TYPES_NOCOPY
}
@@ -844,7 +843,7 @@ void BKE_libblock_management_main_add(Main *bmain, void *idv)
BLI_addtail(lb, id);
/* We need to allow adding extra datablocks into libraries too, e.g. to support generating new
* overrides for recursive resync. */
- BKE_id_new_name_validate(lb, id, NULL, true);
+ BKE_id_new_name_validate(bmain, lb, id, NULL, true);
/* alphabetic insertion: is in new_id */
id->tag &= ~(LIB_TAG_NO_MAIN | LIB_TAG_NO_USER_REFCOUNT);
bmain->is_memfile_undo_written = false;
@@ -867,6 +866,7 @@ void BKE_libblock_management_main_remove(Main *bmain, void *idv)
ListBase *lb = which_libbase(bmain, GS(id->name));
BKE_main_lock(bmain);
BLI_remlink(lb, id);
+ BKE_main_namemap_remove_name(bmain, id, id->name + 2);
id->tag |= LIB_TAG_NO_MAIN;
bmain->is_memfile_undo_written = false;
BKE_main_unlock(bmain);
@@ -960,7 +960,7 @@ void BKE_main_id_flag_all(Main *bmain, const int flag, const bool value)
}
}
-void BKE_main_id_repair_duplicate_names_listbase(ListBase *lb)
+void BKE_main_id_repair_duplicate_names_listbase(Main *bmain, ListBase *lb)
{
int lb_len = 0;
LISTBASE_FOREACH (ID *, id, lb) {
@@ -984,7 +984,7 @@ void BKE_main_id_repair_duplicate_names_listbase(ListBase *lb)
}
for (i = 0; i < lb_len; i++) {
if (!BLI_gset_add(gset, id_array[i]->name + 2)) {
- BKE_id_new_name_validate(lb, id_array[i], NULL, false);
+ BKE_id_new_name_validate(bmain, lb, id_array[i], NULL, false);
}
}
BLI_gset_free(gset, NULL);
@@ -1075,7 +1075,7 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name, const int fl
BKE_main_lock(bmain);
BLI_addtail(lb, id);
- BKE_id_new_name_validate(lb, id, name, false);
+ BKE_id_new_name_validate(bmain, lb, id, name, false);
bmain->is_memfile_undo_written = false;
/* alphabetic insertion: is in new_id */
BKE_main_unlock(bmain);
@@ -1417,255 +1417,8 @@ void id_sort_by_name(ListBase *lb, ID *id, ID *id_sorting_hint)
#undef ID_SORT_STEP_SIZE
}
-/* NOTE: this code assumes and ensures that the suffix number can never go beyond 1 billion. */
-#define MAX_NUMBER 1000000000
-/* We do not want to get "name.000", so minimal number is 1. */
-#define MIN_NUMBER 1
-/* The maximum value up to which we search for the actual smallest unused number. Beyond that
- * value, we will only use the first biggest unused number, without trying to 'fill the gaps'
- * in-between already used numbers... */
-#define MAX_NUMBERS_IN_USE 1024
-
-/**
- * Helper building final ID name from given base_name and number.
- *
- * If everything goes well and we do generate a valid final ID name in given name, we return
- * true. In case the final name would overflow the allowed ID name length, or given number is
- * bigger than maximum allowed value, we truncate further the base_name (and given name, which is
- * assumed to have the same 'base_name' part), and return false.
- */
-static bool id_name_final_build(char *name, char *base_name, size_t base_name_len, int number)
-{
- char number_str[11]; /* Dot + nine digits + NULL terminator. */
- size_t number_str_len = BLI_snprintf_rlen(number_str, ARRAY_SIZE(number_str), ".%.3d", number);
-
- /* If the number would lead to an overflow of the maximum ID name length, we need to truncate
- * the base name part and do all the number checks again. */
- if (base_name_len + number_str_len >= MAX_ID_NAME - 2 || number >= MAX_NUMBER) {
- if (base_name_len + number_str_len >= MAX_ID_NAME - 2) {
- base_name_len = MAX_ID_NAME - 2 - number_str_len - 1;
- }
- else {
- base_name_len--;
- }
- base_name[base_name_len] = '\0';
-
- /* Code above may have generated invalid utf-8 string, due to raw truncation.
- * Ensure we get a valid one now. */
- base_name_len -= (size_t)BLI_str_utf8_invalid_strip(base_name, base_name_len);
-
- /* Also truncate orig name, and start the whole check again. */
- name[base_name_len] = '\0';
- return false;
- }
-
- /* We have our final number, we can put it in name and exit the function. */
- BLI_strncpy(name + base_name_len, number_str, number_str_len + 1);
- return true;
-}
-
-/**
- * Check to see if an ID name is already used, and find a new one if so.
- * Return true if a new name was created (returned in name).
- *
- * Normally the ID that's being checked is already in the ListBase, so ID *id points at the new
- * entry. The Python Library module needs to know what the name of a data-block will be before it
- * is appended, in this case ID *id is NULL.
- */
-static bool check_for_dupid(ListBase *lb, ID *id, char *name, ID **r_id_sorting_hint)
-{
- BLI_assert(strlen(name) < MAX_ID_NAME - 2);
-
- *r_id_sorting_hint = NULL;
-
- ID *id_test = lb->first;
- bool is_name_changed = false;
-
- if (id_test == NULL) {
- return is_name_changed;
- }
-
- const short id_type = (short)GS(id_test->name);
-
- /* Static storage of previous handled ID/name info, used to perform a quicker test and optimize
- * creation of huge number of IDs using the same given base name. */
- static char prev_orig_base_name[MAX_ID_NAME - 2] = {0};
- static char prev_final_base_name[MAX_ID_NAME - 2] = {0};
- static short prev_id_type = ID_LINK_PLACEHOLDER; /* Should never exist in actual ID list. */
- static int prev_number = MIN_NUMBER - 1;
-
- /* Initial test to check whether we can 'shortcut' the more complex loop of the main code
- * below. Note that we do not do that for low numbers, as that would prevent using actual
- * smallest available number in some cases, and benefits of this special case handling mostly
- * show up with high numbers anyway. */
- if (id_type == prev_id_type && prev_number >= MAX_NUMBERS_IN_USE &&
- prev_number < MAX_NUMBER - 1 && name[0] == prev_final_base_name[0]) {
-
- /* Get the name and number parts ("name.number"). */
- char base_name[MAX_ID_NAME - 2];
- int number = MIN_NUMBER;
- size_t base_name_len = BLI_split_name_num(base_name, &number, name, '.');
- size_t prev_final_base_name_len = strlen(prev_final_base_name);
- size_t prev_orig_base_name_len = strlen(prev_orig_base_name);
-
- if (base_name_len == prev_orig_base_name_len &&
- STREQLEN(base_name, prev_orig_base_name, prev_orig_base_name_len)) {
- /* Once we have ensured given base_name and original previous one are the same, we can
- * check that previously used number is actually used, and that next one is free. */
- /* Note that from now on, we only used previous final base name, as it might have been
- * truncated from original one due to number suffix length. */
- char final_name[MAX_ID_NAME - 2];
- char prev_final_name[MAX_ID_NAME - 2];
- BLI_strncpy(final_name, prev_final_base_name, prev_final_base_name_len + 1);
- BLI_strncpy(prev_final_name, prev_final_base_name, prev_final_base_name_len + 1);
-
- if (id_name_final_build(final_name, base_name, prev_final_base_name_len, prev_number + 1) &&
- id_name_final_build(prev_final_name, base_name, prev_final_base_name_len, prev_number)) {
- /* We successfully built valid final names of previous and current iterations,
- * now we have to ensure that previous final name is indeed used in current ID list,
- * and that current one is not. */
- bool is_valid = false;
- for (id_test = lb->first; id_test; id_test = id_test->next) {
- if (id != id_test && id_test->lib == id->lib) {
- if (id_test->name[2] == final_name[0] && STREQ(final_name, id_test->name + 2)) {
- /* We expect final_name to not be already used, so this is a failure. */
- is_valid = false;
- break;
- }
- /* Previous final name should only be found once in the list, so if it was found
- * already, no need to do a string comparison again. */
- if (!is_valid && id_test->name[2] == prev_final_name[0] &&
- STREQ(prev_final_name, id_test->name + 2)) {
- is_valid = true;
- *r_id_sorting_hint = id_test;
- }
- }
- }
-
- if (is_valid) {
- /* Only the number changed, prev_orig_base_name, prev_final_base_name and prev_id_type
- * remain the same. */
- prev_number++;
-
- strcpy(name, final_name);
- return true;
- }
- }
- }
- }
-
- /* To speed up finding smallest unused number within [0 .. MAX_NUMBERS_IN_USE - 1].
- * We do not bother beyond that point. */
- ID *ids_in_use[MAX_NUMBERS_IN_USE] = {NULL};
-
- bool is_first_run = true;
- while (true) {
- /* Get the name and number parts ("name.number"). */
- char base_name[MAX_ID_NAME - 2];
- int number = MIN_NUMBER;
- size_t base_name_len = BLI_split_name_num(base_name, &number, name, '.');
-
- /* Store previous original given base name now, as we might alter it later in code below. */
- if (is_first_run) {
- strcpy(prev_orig_base_name, base_name);
- is_first_run = false;
- }
-
- /* In case we get an insane initial number suffix in given name. */
- /* NOTE: BLI_split_name_num() cannot return negative numbers, so we do not have to check for
- * that here. */
- if (number >= MAX_NUMBER || number < MIN_NUMBER) {
- number = MIN_NUMBER;
- }
-
- bool is_orig_name_used = false;
- for (id_test = lb->first; id_test; id_test = id_test->next) {
- char base_name_test[MAX_ID_NAME - 2];
- int number_test;
- if ((id != id_test) && (id_test->lib == id->lib) && (name[0] == id_test->name[2]) &&
- (ELEM(id_test->name[base_name_len + 2], '.', '\0')) &&
- STREQLEN(name, id_test->name + 2, base_name_len) &&
- (BLI_split_name_num(base_name_test, &number_test, id_test->name + 2, '.') ==
- base_name_len)) {
- /* If we did not yet encounter exact same name as the given one, check the remaining
- * parts of the strings. */
- if (!is_orig_name_used) {
- is_orig_name_used = STREQ(name + base_name_len, id_test->name + 2 + base_name_len);
- }
- /* Mark number of current id_test name as used, if possible. */
- if (number_test < MAX_NUMBERS_IN_USE) {
- ids_in_use[number_test] = id_test;
- }
- /* Keep track of first largest unused number. */
- if (number <= number_test) {
- *r_id_sorting_hint = id_test;
- number = number_test + 1;
- }
- }
- }
-
- /* If there is no double, we are done.
- * Note however that name might have been changed (truncated) in a previous iteration
- * already.
- */
- if (!is_orig_name_used) {
- /* Don't bother updating `prev_*` static variables here, this case is not supposed to happen
- * that often, and is not straight-forward here, so just ignore and reset them to default. */
- prev_id_type = ID_LINK_PLACEHOLDER;
- prev_final_base_name[0] = '\0';
- prev_number = MIN_NUMBER - 1;
-
- /* Value set previously is meaningless in that case. */
- *r_id_sorting_hint = NULL;
-
- return is_name_changed;
- }
-
- /* Decide which value of number to use, either the smallest unused one if possible, or
- * default to the first largest unused one we got from previous loop. */
- for (int i = MIN_NUMBER; i < MAX_NUMBERS_IN_USE; i++) {
- if (ids_in_use[i] == NULL) {
- number = i;
- if (i > 0) {
- *r_id_sorting_hint = ids_in_use[i - 1];
- }
- break;
- }
- }
- /* At this point, number is either the lowest unused number within
- * [MIN_NUMBER .. MAX_NUMBERS_IN_USE - 1], or 1 greater than the largest used number if all
- * those low ones are taken.
- * We can't be bothered to look for the lowest unused number beyond
- * (MAX_NUMBERS_IN_USE - 1).
- */
- /* We know for wure that name will be changed. */
- is_name_changed = true;
-
- /* If id_name_final_build helper returns false, it had to truncate further given name, hence
- * we have to go over the whole check again. */
- if (!id_name_final_build(name, base_name, base_name_len, number)) {
- /* We have to clear our list of small used numbers before we do the whole check again. */
- memset(ids_in_use, 0, sizeof(ids_in_use));
-
- continue;
- }
-
- /* Update `prev_*` static variables, in case next call is for the same type of IDs and with the
- * same initial base name, we can skip a lot of above process. */
- prev_id_type = id_type;
- strcpy(prev_final_base_name, base_name);
- prev_number = number;
-
- return is_name_changed;
- }
-
-#undef MAX_NUMBERS_IN_USE
-}
-
-#undef MIN_NUMBER
-#undef MAX_NUMBER
-
-bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const bool do_linked_data)
+bool BKE_id_new_name_validate(
+ struct Main *bmain, ListBase *lb, ID *id, const char *tname, const bool do_linked_data)
{
bool result = false;
char name[MAX_ID_NAME - 2];
@@ -1695,22 +1448,10 @@ bool BKE_id_new_name_validate(ListBase *lb, ID *id, const char *tname, const boo
BLI_str_utf8_invalid_strip(name, strlen(name));
}
- ID *id_sorting_hint = NULL;
- result = check_for_dupid(lb, id, name, &id_sorting_hint);
- strcpy(id->name + 2, name);
-
- /* This was in 2.43 and previous releases
- * however all data in blender should be sorted, not just duplicate names
- * sorting should not hurt, but noting just in case it alters the way other
- * functions work, so sort every time. */
-#if 0
- if (result) {
- id_sort_by_name(lb, id, id_sorting_hint);
- }
-#endif
-
- id_sort_by_name(lb, id, id_sorting_hint);
+ result = BKE_main_namemap_get_name(bmain, id, name);
+ strcpy(id->name + 2, name);
+ id_sort_by_name(lb, id, NULL);
return result;
}
@@ -2076,7 +1817,7 @@ void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
idtest = BLI_findstring(lb, name + 2, offsetof(ID, name) + 2);
if (idtest != NULL && !ID_IS_LINKED(idtest)) {
/* BKE_id_new_name_validate also takes care of sorting. */
- BKE_id_new_name_validate(lb, idtest, NULL, false);
+ BKE_id_new_name_validate(bmain, lb, idtest, NULL, false);
bmain->is_memfile_undo_written = false;
}
}
@@ -2084,8 +1825,9 @@ void BLI_libblock_ensure_unique_name(Main *bmain, const char *name)
void BKE_libblock_rename(Main *bmain, ID *id, const char *name)
{
BLI_assert(!ID_IS_LINKED(id));
+ BKE_main_namemap_remove_name(bmain, id, id->name + 2);
ListBase *lb = which_libbase(bmain, GS(id->name));
- if (BKE_id_new_name_validate(lb, id, name, false)) {
+ if (BKE_id_new_name_validate(bmain, lb, id, name, false)) {
bmain->is_memfile_undo_written = false;
}
}
@@ -2163,7 +1905,7 @@ bool BKE_id_can_be_asset(const ID *id)
BKE_idtype_idcode_is_linkable(GS(id->name));
}
-bool BKE_id_is_editable(Main *bmain, ID *id)
+bool BKE_id_is_editable(const Main *bmain, const ID *id)
{
return !(ID_IS_LINKED(id) || BKE_lib_override_library_is_system_defined(bmain, id));
}
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index f14c11a949e..405b0be70f9 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -28,6 +28,7 @@
#include "BKE_lib_remap.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_main_namemap.h"
#include "lib_intern.h"
@@ -151,6 +152,7 @@ void BKE_id_free_ex(Main *bmain, void *idv, int flag, const bool use_flag_from_i
if ((flag & LIB_ID_FREE_NO_MAIN) == 0) {
ListBase *lb = which_libbase(bmain, type);
BLI_remlink(lb, id);
+ BKE_main_namemap_remove_name(bmain, id, id->name + 2);
}
BKE_libblock_free_data(id, (flag & LIB_ID_FREE_NO_USER_REFCOUNT) == 0);
@@ -237,6 +239,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
/* NOTE: in case we delete a library, we also delete all its datablocks! */
if ((id->tag & tag) || (ID_IS_LINKED(id) && (id->lib->id.tag & tag))) {
BLI_remlink(lb, id);
+ BKE_main_namemap_remove_name(bmain, id, id->name + 2);
BLI_addtail(&tagged_deleted_ids, id);
/* Do not tag as no_main now, we want to unlink it first (lower-level ID management
* code has some specific handling of 'no main' IDs that would be a problem in that
diff --git a/source/blender/blenkernel/intern/lib_id_remapper.cc b/source/blender/blenkernel/intern/lib_id_remapper.cc
index 7e75e0f5d93..98ac9110a48 100644
--- a/source/blender/blenkernel/intern/lib_id_remapper.cc
+++ b/source/blender/blenkernel/intern/lib_id_remapper.cc
@@ -36,6 +36,7 @@ struct IDRemapper {
BLI_assert(old_id != nullptr);
BLI_assert(new_id == nullptr || (GS(old_id->name) == GS(new_id->name)));
mappings.add(old_id, new_id);
+ BLI_assert(BKE_idtype_idcode_to_idfilter(GS(old_id->name)) != 0);
source_types |= BKE_idtype_idcode_to_idfilter(GS(old_id->name));
}
diff --git a/source/blender/blenkernel/intern/lib_id_test.cc b/source/blender/blenkernel/intern/lib_id_test.cc
index d6101d71be5..ea3f5395f1f 100644
--- a/source/blender/blenkernel/intern/lib_id_test.cc
+++ b/source/blender/blenkernel/intern/lib_id_test.cc
@@ -10,6 +10,7 @@
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_main_namemap.h"
#include "DNA_ID.h"
#include "DNA_mesh_types.h"
@@ -18,19 +19,18 @@
namespace blender::bke::tests {
struct LibIDMainSortTestContext {
- Main *bmain;
-};
-
-static void test_lib_id_main_sort_init(LibIDMainSortTestContext *ctx)
-{
- BKE_idtype_init();
- ctx->bmain = BKE_main_new();
-}
+ Main *bmain = nullptr;
-static void test_lib_id_main_sort_free(LibIDMainSortTestContext *ctx)
-{
- BKE_main_free(ctx->bmain);
-}
+ LibIDMainSortTestContext()
+ {
+ BKE_idtype_init();
+ bmain = BKE_main_new();
+ }
+ ~LibIDMainSortTestContext()
+ {
+ BKE_main_free(bmain);
+ }
+};
static void test_lib_id_main_sort_check_order(std::initializer_list<ID *> list)
{
@@ -47,8 +47,7 @@ static void test_lib_id_main_sort_check_order(std::initializer_list<ID *> list)
TEST(lib_id_main_sort, local_ids_1)
{
- LibIDMainSortTestContext ctx = {nullptr};
- test_lib_id_main_sort_init(&ctx);
+ LibIDMainSortTestContext ctx;
EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
@@ -57,14 +56,27 @@ TEST(lib_id_main_sort, local_ids_1)
EXPECT_TRUE(ctx.bmain->objects.first == id_a);
EXPECT_TRUE(ctx.bmain->objects.last == id_c);
test_lib_id_main_sort_check_order({id_a, id_b, id_c});
+}
+
+static void change_lib(Main *bmain, ID *id, Library *lib)
+{
+ if (id->lib == lib) {
+ return;
+ }
+ BKE_main_namemap_remove_name(bmain, id, id->name + 2);
+ id->lib = lib;
+}
- test_lib_id_main_sort_free(&ctx);
+static void change_name(Main *bmain, ID *id, const char *name)
+{
+ BKE_main_namemap_remove_name(bmain, id, id->name + 2);
+ BLI_strncpy(id->name + 2, name, MAX_NAME);
+ BKE_id_new_name_validate(bmain, &bmain->objects, id, nullptr, true);
}
TEST(lib_id_main_sort, linked_ids_1)
{
- LibIDMainSortTestContext ctx = {nullptr};
- test_lib_id_main_sort_init(&ctx);
+ LibIDMainSortTestContext ctx;
EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
Library *lib_a = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_A"));
@@ -92,14 +104,11 @@ TEST(lib_id_main_sort, linked_ids_1)
EXPECT_TRUE(ctx.bmain->objects.first == id_c);
EXPECT_TRUE(ctx.bmain->objects.last == id_b);
test_lib_id_main_sort_check_order({id_c, id_a, id_b});
-
- test_lib_id_main_sort_free(&ctx);
}
TEST(lib_id_main_unique_name, local_ids_1)
{
- LibIDMainSortTestContext ctx = {nullptr};
- test_lib_id_main_sort_init(&ctx);
+ LibIDMainSortTestContext ctx;
EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_C"));
@@ -107,21 +116,18 @@ TEST(lib_id_main_unique_name, local_ids_1)
ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
test_lib_id_main_sort_check_order({id_a, id_b, id_c});
- BLI_strncpy(id_c->name, id_a->name, sizeof(id_c->name));
- BKE_id_new_name_validate(&ctx.bmain->objects, id_c, nullptr, false);
- EXPECT_TRUE(strcmp(id_c->name + 2, "OB_A.001") == 0);
- EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
+ change_name(ctx.bmain, id_c, "OB_A");
+
+ EXPECT_STREQ(id_c->name + 2, "OB_A.001");
+ EXPECT_STREQ(id_a->name + 2, "OB_A");
EXPECT_TRUE(ctx.bmain->objects.first == id_a);
EXPECT_TRUE(ctx.bmain->objects.last == id_b);
test_lib_id_main_sort_check_order({id_a, id_c, id_b});
-
- test_lib_id_main_sort_free(&ctx);
}
TEST(lib_id_main_unique_name, linked_ids_1)
{
- LibIDMainSortTestContext ctx = {nullptr};
- test_lib_id_main_sort_init(&ctx);
+ LibIDMainSortTestContext ctx;
EXPECT_TRUE(BLI_listbase_is_empty(&ctx.bmain->libraries));
Library *lib_a = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LI_A"));
@@ -130,29 +136,276 @@ TEST(lib_id_main_unique_name, linked_ids_1)
ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_A"));
ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "OB_B"));
- id_a->lib = lib_a;
+ change_lib(ctx.bmain, id_a, lib_a);
id_sort_by_name(&ctx.bmain->objects, id_a, nullptr);
- id_b->lib = lib_a;
+ change_lib(ctx.bmain, id_b, lib_a);
id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
- BLI_strncpy(id_b->name, id_a->name, sizeof(id_b->name));
- BKE_id_new_name_validate(&ctx.bmain->objects, id_b, nullptr, true);
- EXPECT_TRUE(strcmp(id_b->name + 2, "OB_A.001") == 0);
- EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
+
+ change_name(ctx.bmain, id_b, "OB_A");
+ EXPECT_STREQ(id_b->name + 2, "OB_A.001");
+ EXPECT_STREQ(id_a->name + 2, "OB_A");
EXPECT_TRUE(ctx.bmain->objects.first == id_c);
EXPECT_TRUE(ctx.bmain->objects.last == id_b);
test_lib_id_main_sort_check_order({id_c, id_a, id_b});
- id_b->lib = lib_b;
+ change_lib(ctx.bmain, id_b, lib_b);
id_sort_by_name(&ctx.bmain->objects, id_b, nullptr);
- BLI_strncpy(id_b->name, id_a->name, sizeof(id_b->name));
- BKE_id_new_name_validate(&ctx.bmain->objects, id_b, nullptr, true);
- EXPECT_TRUE(strcmp(id_b->name + 2, "OB_A") == 0);
- EXPECT_TRUE(strcmp(id_a->name + 2, "OB_A") == 0);
+ change_name(ctx.bmain, id_b, "OB_A");
+ EXPECT_STREQ(id_b->name + 2, "OB_A");
+ EXPECT_STREQ(id_a->name + 2, "OB_A");
EXPECT_TRUE(ctx.bmain->objects.first == id_c);
EXPECT_TRUE(ctx.bmain->objects.last == id_b);
test_lib_id_main_sort_check_order({id_c, id_a, id_b});
+}
+
+TEST(lib_id_main_unique_name, ids_sorted_by_default)
+{
+ LibIDMainSortTestContext ctx;
+
+ ID *id_foo = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ ID *id_bar = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar"));
+ ID *id_baz = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Baz"));
+ ID *id_yes = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Yes"));
+ test_lib_id_main_sort_check_order({id_bar, id_baz, id_foo, id_yes});
+}
+
+static ID *add_id_in_library(Main *bmain, const char *name, Library *lib)
+{
+ ID *id = static_cast<ID *>(BKE_id_new(bmain, ID_OB, name));
+ id->lib = lib;
+ id_sort_by_name(&bmain->objects, id, nullptr);
+ return id;
+}
+
+TEST(lib_id_main_unique_name, ids_sorted_by_default_with_libraries)
+{
+ LibIDMainSortTestContext ctx;
+
+ Library *lib_one = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LibOne"));
+ Library *lib_two = static_cast<Library *>(BKE_id_new(ctx.bmain, ID_LI, "LibTwo"));
+
+ ID *id_foo = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ ID *id_bar = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar"));
+
+ ID *id_l1c = add_id_in_library(ctx.bmain, "C", lib_one);
+ ID *id_l2b = add_id_in_library(ctx.bmain, "B", lib_two);
+ ID *id_l1a = add_id_in_library(ctx.bmain, "A", lib_one);
+
+ ID *id_baz = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Baz"));
+ ID *id_yes = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Yes"));
+
+ test_lib_id_main_sort_check_order({id_bar, id_baz, id_foo, id_yes, id_l1a, id_l1c, id_l2b});
+}
+
+TEST(lib_id_main_unique_name, name_too_long_handling)
+{
+ LibIDMainSortTestContext ctx;
+ const char *name_a = "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_Truncated";
+ const char *name_b = "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123456";
+ const char *name_c = "Name_That_Has_Too_Long_Number_Suffix.1234567890";
+
+ ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_a));
+ ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_b));
+ ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, name_c));
+
+ EXPECT_STREQ(id_a->name + 2, "Long_Name_That_Does_Not_Fit_Into_Max_Name_Limit_And_Should_Get_");
+ EXPECT_STREQ(id_b->name + 2, "Another_Long_Name_That_Does_Not_Fit_And_Has_A_Number_Suffix.123");
+ EXPECT_STREQ(id_c->name + 2, "Name_That_Has_Too_Long_Number_Suffix.1234567890"); /* Unchanged */
+}
+
+TEST(lib_id_main_unique_name, create_equivalent_numeric_suffixes)
+{
+ LibIDMainSortTestContext ctx;
+
+ /* Create names where many of their numeric suffixes are
+ * the same number, yet the names are different and thus
+ * should be allowed as-is. */
+ ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123"));
+ ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.000"));
+ ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.003"));
+ ID *id_d = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.3"));
+ ID *id_e = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0"));
+ ID *id_f = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo."));
+ ID *id_g = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0123"));
+ ID *id_h = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ ID *id_i = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.."));
+ ID *id_j = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..001"));
+ ID *id_k = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..000"));
+
+ EXPECT_STREQ(id_a->name + 2, "Foo.123");
+ EXPECT_STREQ(id_b->name + 2, "Foo.000");
+ EXPECT_STREQ(id_c->name + 2, "Foo.003");
+ EXPECT_STREQ(id_d->name + 2, "Foo.3");
+ EXPECT_STREQ(id_e->name + 2, "Foo.0");
+ EXPECT_STREQ(id_f->name + 2, "Foo.");
+ EXPECT_STREQ(id_g->name + 2, "Foo.0123");
+ EXPECT_STREQ(id_h->name + 2, "Foo");
+ EXPECT_STREQ(id_i->name + 2, "Foo..");
+ EXPECT_STREQ(id_j->name + 2, "Foo..001");
+ EXPECT_STREQ(id_k->name + 2, "Foo..000");
+
+ /* Now create their exact duplicates again, and check what happens. */
+ id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123"));
+ id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.000"));
+ id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.003"));
+ id_d = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.3"));
+ id_e = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0"));
+ id_f = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo."));
+ id_g = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.0123"));
+ id_h = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ id_i = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.."));
+ id_j = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..001"));
+ id_k = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo..000"));
+
+ EXPECT_STREQ(id_a->name + 2, "Foo.001");
+ EXPECT_STREQ(id_b->name + 2, "Foo.002");
+ EXPECT_STREQ(id_c->name + 2, "Foo.004");
+ EXPECT_STREQ(id_d->name + 2, "Foo.005");
+ EXPECT_STREQ(id_e->name + 2, "Foo.006");
+ EXPECT_STREQ(id_f->name + 2, "Foo..002");
+ EXPECT_STREQ(id_g->name + 2, "Foo.007");
+ EXPECT_STREQ(id_h->name + 2, "Foo.008");
+ EXPECT_STREQ(id_i->name + 2, "Foo...001");
+ EXPECT_STREQ(id_j->name + 2, "Foo..003");
+ EXPECT_STREQ(id_k->name + 2, "Foo..004");
+}
+
+TEST(lib_id_main_unique_name, zero_suffix_is_never_assigned)
+{
+ LibIDMainSortTestContext ctx;
+
+ /* Creating these should assign 002 to the first one, but the next
+ * ones should start numbers starting from 1: 001 and 003. */
+ ID *id_002 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002"));
+ ID *id_001 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002"));
+ ID *id_003 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.002"));
+
+ EXPECT_STREQ(id_002->name + 2, "Foo.002");
+ EXPECT_STREQ(id_001->name + 2, "Foo.001");
+ EXPECT_STREQ(id_003->name + 2, "Foo.003");
+}
+
+TEST(lib_id_main_unique_name, remove_after_dup_get_original_name)
+{
+ LibIDMainSortTestContext ctx;
+
+ ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+
+ EXPECT_STREQ(id_a->name + 2, "Foo");
+ EXPECT_STREQ(id_b->name + 2, "Foo.001");
+ BKE_id_free(ctx.bmain, id_a);
+
+ id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ EXPECT_STREQ(id_a->name + 2, "Foo");
+}
+
+TEST(lib_id_main_unique_name, name_number_suffix_assignment)
+{
+ LibIDMainSortTestContext ctx;
+
+ /* Create <1k objects first. */
+ const int total_object_count = 1200;
+ ID *ids[total_object_count] = {};
+ for (int i = 0; i < total_object_count / 2; ++i) {
+ ids[i] = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ }
+
+ /* They should get assigned sequential numeric suffixes. */
+ EXPECT_STREQ(ids[0]->name + 2, "Foo");
+ EXPECT_STREQ(ids[1]->name + 2, "Foo.001");
+ EXPECT_STREQ(ids[total_object_count / 2 - 1]->name + 2, "Foo.599");
+
+ /* Free some of the objects. */
+ BKE_id_free(ctx.bmain, ids[10]);
+ BKE_id_free(ctx.bmain, ids[20]);
+ BKE_id_free(ctx.bmain, ids[30]);
+
+ /* Create objects again; they should get suffixes that were just free'd up. */
+ ID *id_010 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ EXPECT_STREQ(id_010->name + 2, "Foo.010");
+ ID *id_020 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.123"));
+ EXPECT_STREQ(id_020->name + 2, "Foo.020");
+ /* Suffixes >1k do not get the "use the most proper free one" treatment. */
+ ID *id_2000 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.2000"));
+ EXPECT_STREQ(id_2000->name + 2, "Foo.2000");
+ /* But smaller than 1k suffixes do get proper empty spots. */
+ ID *id_030 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ EXPECT_STREQ(id_030->name + 2, "Foo.030");
+ ID *id_600 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ EXPECT_STREQ(id_600->name + 2, "Foo.600");
+
+ /* Max possible numeric suffix. */
+ ID *id_max = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999"));
+ EXPECT_STREQ(id_max->name + 2, "Foo.999999999");
+ /* Try with max. possible suffix again: will assign free suffix under 1k. */
+ ID *id_max1 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999"));
+ EXPECT_STREQ(id_max1->name + 2, "Foo.601");
+
+ /* Now create the rest of objects, to use all the suffixes up to 1k.
+ * Once all the ones up to 1k are used, the logic will fall back to
+ * "use largest number seen + 1", but the largest one is already the max
+ * possible. So it will shorten the name part and restart the counter,
+ * i.e. "Fo.001". */
+ for (int i = total_object_count / 2; i < total_object_count; ++i) {
+ ids[i] = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ }
+ /* At this point creating "Foo" based objects will fall always
+ * result in shortened name to "Fo". */
+ ID *id_fo178 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ EXPECT_STREQ(id_fo178->name + 2, "Fo.178");
+ ID *id_fo179 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.2000"));
+ EXPECT_STREQ(id_fo179->name + 2, "Fo.179");
+ ID *id_fo180 = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo.999999999"));
+ EXPECT_STREQ(id_fo180->name + 2, "Fo.180");
+}
+
+TEST(lib_id_main_unique_name, renames_with_duplicates)
+{
+ LibIDMainSortTestContext ctx;
+
+ ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Bar"));
+
+ EXPECT_STREQ(id_a->name + 2, "Foo");
+ EXPECT_STREQ(id_b->name + 2, "Foo.001");
+ EXPECT_STREQ(id_c->name + 2, "Bar");
+
+ BKE_libblock_rename(ctx.bmain, id_a, "Foo.002");
+ EXPECT_STREQ(id_a->name + 2, "Foo.002");
+ BKE_libblock_rename(ctx.bmain, id_b, "Bar");
+ EXPECT_STREQ(id_b->name + 2, "Bar.001");
+ BKE_libblock_rename(ctx.bmain, id_c, "Foo");
+ EXPECT_STREQ(id_c->name + 2, "Foo");
+ BKE_libblock_rename(ctx.bmain, id_b, "Bar");
+ EXPECT_STREQ(id_b->name + 2, "Bar");
+}
+
+TEST(lib_id_main_unique_name, names_are_unique_per_id_type)
+{
+ LibIDMainSortTestContext ctx;
+
+ ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+ ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_CA, "Foo"));
+ ID *id_c = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "Foo"));
+
+ EXPECT_STREQ(id_a->name + 2, "Foo");
+ EXPECT_STREQ(id_b->name + 2, "Foo"); /* Different types (OB & CA) can have the same name. */
+ EXPECT_STREQ(id_c->name + 2, "Foo.001");
+}
+
+TEST(lib_id_main_unique_name, name_huge_number_suffix)
+{
+ LibIDMainSortTestContext ctx;
- test_lib_id_main_sort_free(&ctx);
+ /* Use numeric suffix that is really large: should come through
+ * fine, since no duplicates with other names. */
+ ID *id_a = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "SuperLong.1234567890"));
+ EXPECT_STREQ(id_a->name + 2, "SuperLong.1234567890");
+ /* Now create with the same name again: should get 001 suffix. */
+ ID *id_b = static_cast<ID *>(BKE_id_new(ctx.bmain, ID_OB, "SuperLong.1234567890"));
+ EXPECT_STREQ(id_b->name + 2, "SuperLong.001");
}
} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.cc
index 50c9514e810..0c5f59be768 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.cc
@@ -5,8 +5,8 @@
* \ingroup bke
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "CLG_log.h"
@@ -21,8 +21,10 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_collection.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -88,16 +90,20 @@ BLI_INLINE void lib_override_object_posemode_transfer(ID *id_dst, ID *id_src)
}
/** Get override data for a given ID. Needed because of our beloved shape keys snowflake. */
-BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner_id)
+BLI_INLINE const IDOverrideLibrary *lib_override_get(const Main *bmain,
+ const ID *id,
+ const ID **r_owner_id)
{
- if (r_owner_id != NULL) {
+ if (r_owner_id != nullptr) {
*r_owner_id = id;
}
if (id->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) {
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
- if (id_type->owner_get != NULL) {
- ID *owner_id = id_type->owner_get(bmain, id);
- if (r_owner_id != NULL) {
+ if (id_type->owner_get != nullptr) {
+ /* The #IDTypeInfo::owner_get callback should not modify the arguments, so casting away const
+ * is okay. */
+ const ID *owner_id = id_type->owner_get(const_cast<Main *>(bmain), const_cast<ID *>(id));
+ if (r_owner_id != nullptr) {
*r_owner_id = owner_id;
}
return owner_id->override_library;
@@ -107,21 +113,31 @@ BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner
return id->override_library;
}
+BLI_INLINE IDOverrideLibrary *lib_override_get(Main *bmain, ID *id, ID **r_owner_id)
+{
+ /* Reuse the implementation of the const access function, which does not change the arguments.
+ * Add const explicitly to make it clear to the compiler to avoid just calling this function. */
+ return const_cast<IDOverrideLibrary *>(lib_override_get(const_cast<const Main *>(bmain),
+ const_cast<const ID *>(id),
+ const_cast<const ID **>(r_owner_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.
+ /* If reference_id is nullptr, we are creating an override template for purely local data.
* Else, reference *must* be linked data. */
- BLI_assert(reference_id == NULL || ID_IS_LINKED(reference_id));
- BLI_assert(local_id->override_library == NULL);
+ BLI_assert(reference_id == nullptr || ID_IS_LINKED(reference_id));
+ BLI_assert(local_id->override_library == nullptr);
ID *ancestor_id;
- for (ancestor_id = reference_id; ancestor_id != NULL && ancestor_id->override_library != NULL &&
- ancestor_id->override_library->reference != NULL;
+ for (ancestor_id = reference_id;
+ ancestor_id != nullptr && ancestor_id->override_library != nullptr &&
+ ancestor_id->override_library->reference != nullptr;
ancestor_id = ancestor_id->override_library->reference) {
/* pass */
}
- if (ancestor_id != NULL && ancestor_id->override_library != NULL) {
+ if (ancestor_id != nullptr && ancestor_id->override_library != nullptr) {
/* Original ID has a template, use it! */
BKE_lib_override_library_copy(local_id, ancestor_id, true);
if (local_id->override_library->reference != reference_id) {
@@ -133,7 +149,7 @@ IDOverrideLibrary *BKE_lib_override_library_init(ID *local_id, ID *reference_id)
}
/* Else, generate new empty override. */
- local_id->override_library = MEM_callocN(sizeof(*local_id->override_library), __func__);
+ local_id->override_library = MEM_cnew<IDOverrideLibrary>(__func__);
local_id->override_library->reference = reference_id;
id_us_plus(local_id->override_library->reference);
local_id->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
@@ -148,20 +164,20 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY(src_id) || ID_IS_OVERRIDE_LIBRARY_TEMPLATE(src_id));
- if (dst_id->override_library != NULL) {
- if (src_id->override_library == NULL) {
+ if (dst_id->override_library != nullptr) {
+ if (src_id->override_library == nullptr) {
BKE_lib_override_library_free(&dst_id->override_library, true);
return;
}
BKE_lib_override_library_clear(dst_id->override_library, true);
}
- else if (src_id->override_library == NULL) {
+ else if (src_id->override_library == nullptr) {
/* Virtual overrides of embedded data does not require any extra work. */
return;
}
else {
- BKE_lib_override_library_init(dst_id, NULL);
+ BKE_lib_override_library_init(dst_id, nullptr);
}
/* If source is already overriding data, we copy it but reuse its reference for dest ID.
@@ -177,8 +193,10 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
if (do_full_copy) {
BLI_duplicatelist(&dst_id->override_library->properties,
&src_id->override_library->properties);
- for (IDOverrideLibraryProperty *op_dst = dst_id->override_library->properties.first,
- *op_src = src_id->override_library->properties.first;
+ for (IDOverrideLibraryProperty *op_dst = static_cast<IDOverrideLibraryProperty *>(
+ dst_id->override_library->properties.first),
+ *op_src = static_cast<IDOverrideLibraryProperty *>(
+ src_id->override_library->properties.first);
op_dst;
op_dst = op_dst->next, op_src = op_src->next) {
lib_override_library_property_copy(op_dst, op_src);
@@ -190,10 +208,10 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_id_user)
{
- BLI_assert(override != NULL);
+ BLI_assert(override != nullptr);
- if (!ELEM(NULL, override->runtime, override->runtime->rna_path_to_override_properties)) {
- BLI_ghash_clear(override->runtime->rna_path_to_override_properties, NULL, NULL);
+ if (!ELEM(nullptr, override->runtime, override->runtime->rna_path_to_override_properties)) {
+ BLI_ghash_clear(override->runtime->rna_path_to_override_properties, nullptr, nullptr);
}
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
@@ -207,20 +225,20 @@ void BKE_lib_override_library_clear(IDOverrideLibrary *override, const bool do_i
}
}
-void BKE_lib_override_library_free(struct IDOverrideLibrary **override, const bool do_id_user)
+void BKE_lib_override_library_free(IDOverrideLibrary **override, const bool do_id_user)
{
- BLI_assert(*override != NULL);
+ BLI_assert(*override != nullptr);
- if ((*override)->runtime != NULL) {
- if ((*override)->runtime->rna_path_to_override_properties != NULL) {
- BLI_ghash_free((*override)->runtime->rna_path_to_override_properties, NULL, NULL);
+ if ((*override)->runtime != nullptr) {
+ if ((*override)->runtime->rna_path_to_override_properties != nullptr) {
+ BLI_ghash_free((*override)->runtime->rna_path_to_override_properties, nullptr, nullptr);
}
MEM_SAFE_FREE((*override)->runtime);
}
BKE_lib_override_library_clear(*override, do_id_user);
MEM_freeN(*override);
- *override = NULL;
+ *override = nullptr;
}
static ID *lib_override_library_create_from(Main *bmain,
@@ -232,12 +250,12 @@ static ID *lib_override_library_create_from(Main *bmain,
* override template, or already an override of some other ref data). */
ID *local_id = BKE_id_copy_ex(bmain,
reference_id,
- NULL,
+ nullptr,
LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE |
lib_id_copy_flags);
- if (local_id == NULL) {
- return NULL;
+ if (local_id == nullptr) {
+ return nullptr;
}
id_us_min(local_id);
@@ -253,9 +271,9 @@ static ID *lib_override_library_create_from(Main *bmain,
* data-blocks, just like root node trees or master collections. Therefore, we never need to
* create overrides for them. We need a way to mark them as overrides though. */
Key *reference_key;
- if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
Key *local_key = BKE_key_from_id(local_id);
- BLI_assert(local_key != NULL);
+ BLI_assert(local_key != nullptr);
local_key->id.flag |= LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
@@ -264,7 +282,7 @@ static ID *lib_override_library_create_from(Main *bmain,
/* 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)
+bool BKE_lib_override_library_is_user_edited(const ID *id)
{
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
@@ -278,8 +296,8 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id)
return false;
}
- LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) {
- LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
+ LISTBASE_FOREACH (const IDOverrideLibraryProperty *, op, &id->override_library->properties) {
+ LISTBASE_FOREACH (const IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
if ((opop->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) != 0) {
continue;
}
@@ -294,11 +312,10 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id)
return false;
}
-bool BKE_lib_override_library_is_system_defined(Main *bmain, ID *id)
+bool BKE_lib_override_library_is_system_defined(const Main *bmain, const ID *id)
{
-
if (ID_IS_OVERRIDE_LIBRARY(id)) {
- ID *override_owner_id;
+ const ID *override_owner_id;
lib_override_get(bmain, id, &override_owner_id);
return (override_owner_id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) !=
0;
@@ -306,13 +323,41 @@ bool BKE_lib_override_library_is_system_defined(Main *bmain, ID *id)
return false;
}
+bool BKE_lib_override_library_property_is_animated(const ID *id,
+ const IDOverrideLibraryProperty *override_prop,
+ const PropertyRNA *override_rna_prop,
+ const int rnaprop_index)
+{
+ AnimData *anim_data = BKE_animdata_from_id(id);
+ if (anim_data != nullptr) {
+ struct FCurve *fcurve;
+ char *index_token_start = const_cast<char *>(
+ RNA_path_array_index_token_find(override_prop->rna_path, override_rna_prop));
+ if (index_token_start != nullptr) {
+ const char index_token_start_backup = *index_token_start;
+ *index_token_start = '\0';
+ fcurve = BKE_animadata_fcurve_find_by_rna_path(
+ anim_data, override_prop->rna_path, rnaprop_index, nullptr, nullptr);
+ *index_token_start = index_token_start_backup;
+ }
+ else {
+ fcurve = BKE_animadata_fcurve_find_by_rna_path(
+ anim_data, override_prop->rna_path, 0, nullptr, nullptr);
+ }
+ if (fcurve != nullptr) {
+ return true;
+ }
+ }
+ return false;
+}
+
static int foreachid_is_hierarchy_leaf_fn(LibraryIDLinkCallbackData *cb_data)
{
ID *id_owner = cb_data->id_owner;
ID *id = *cb_data->id_pointer;
- bool *is_leaf = cb_data->user_data;
+ bool *is_leaf = static_cast<bool *>(cb_data->user_data);
- if (id != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
+ if (id != nullptr && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
id->override_library->hierarchy_root == id_owner->override_library->hierarchy_root) {
*is_leaf = false;
return IDWALK_RET_STOP_ITER;
@@ -336,10 +381,10 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
ID *reference_id,
const bool do_tagged_remap)
{
- BLI_assert(reference_id != NULL);
+ BLI_assert(reference_id != nullptr);
BLI_assert(ID_IS_LINKED(reference_id));
- ID *local_id = lib_override_library_create_from(bmain, NULL, reference_id, 0);
+ ID *local_id = lib_override_library_create_from(bmain, nullptr, 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. */
@@ -348,10 +393,10 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
local_id->override_library->hierarchy_root = local_id;
if (do_tagged_remap) {
- Key *reference_key, *local_key = NULL;
- if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ Key *reference_key, *local_key = nullptr;
+ if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
local_key = BKE_key_from_id(local_id);
- BLI_assert(local_key != NULL);
+ BLI_assert(local_key != nullptr);
}
ID *other_id;
@@ -364,7 +409,7 @@ ID *BKE_lib_override_library_create_from_id(Main *bmain,
reference_id,
local_id,
ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY);
- if (reference_key != NULL) {
+ if (reference_key != nullptr) {
BKE_libblock_relink_ex(bmain,
other_id,
&reference_key->id,
@@ -383,14 +428,42 @@ static void lib_override_prefill_newid_from_existing_overrides(Main *bmain, ID *
{
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter) &&
- id_iter->override_library->hierarchy_root == id_hierarchy_root) {
- id_iter->override_library->reference->newid = id_iter;
+ ID *id = id_iter;
+ if (GS(id_iter->name) == ID_KE) {
+ id = reinterpret_cast<Key *>(id_iter)->from;
+ BLI_assert(id != nullptr);
+ }
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
+ id->override_library->hierarchy_root == id_hierarchy_root) {
+ id->override_library->reference->newid = id;
+ if (GS(id_iter->name) == ID_KE) {
+ Key *reference_key = BKE_key_from_id(id->override_library->reference);
+ if (reference_key != nullptr) {
+ reference_key->id.newid = id_iter;
+ }
+ }
}
}
FOREACH_MAIN_ID_END;
}
+static void lib_override_remapper_overrides_add(IDRemapper *id_remapper,
+ ID *reference_id,
+ ID *local_id)
+{
+ BKE_id_remapper_add(id_remapper, reference_id, local_id);
+
+ Key *reference_key, *local_key = nullptr;
+ if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
+ if (reference_id->newid != nullptr) {
+ local_key = BKE_key_from_id(reference_id->newid);
+ BLI_assert(local_key != nullptr);
+ }
+
+ BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id);
+ }
+}
+
/* TODO: Make this static local function instead? API is becoming complex, and it's not used
* outside of this file anyway. */
bool BKE_lib_override_library_create_from_tag(Main *bmain,
@@ -401,16 +474,16 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
const bool do_no_main,
const bool do_fully_editable)
{
- BLI_assert(id_root_reference != NULL && ID_IS_LINKED(id_root_reference));
+ BLI_assert(id_root_reference != nullptr && ID_IS_LINKED(id_root_reference));
/* If we do not have any hierarchy root given, then the root reference must be tagged for
* override. */
- BLI_assert(id_hierarchy_root != NULL || id_hierarchy_root_reference != NULL ||
+ BLI_assert(id_hierarchy_root != nullptr || id_hierarchy_root_reference != nullptr ||
(id_root_reference->tag & LIB_TAG_DOIT) != 0);
- /* At least one of the hierarchy root pointers must be NULL, passing both is useless and can
+ /* At least one of the hierarchy root pointers must be nullptr, passing both is useless and can
* create confusion. */
- BLI_assert(ELEM(NULL, id_hierarchy_root, id_hierarchy_root_reference));
+ BLI_assert(ELEM(nullptr, id_hierarchy_root, id_hierarchy_root_reference));
- if (id_hierarchy_root != NULL) {
+ if (id_hierarchy_root != nullptr) {
/* If the hierarchy root is given, it must be a valid existing override (used during partial
* resync process mainly). */
BLI_assert((ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root) &&
@@ -423,7 +496,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
lib_override_prefill_newid_from_existing_overrides(bmain, id_hierarchy_root);
}
}
- if (!ELEM(id_hierarchy_root_reference, NULL, id_root_reference)) {
+ if (!ELEM(id_hierarchy_root_reference, nullptr, id_root_reference)) {
/* If the reference hierarchy root is given, it must be from the same library as the reference
* root, and also tagged for override. */
BLI_assert((id_hierarchy_root_reference->lib == id_root_reference->lib &&
@@ -435,14 +508,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
ID *reference_id;
bool success = true;
- ListBase todo_ids = {NULL};
+ ListBase todo_ids = {nullptr};
LinkData *todo_id_iter;
/* Get all IDs we want to override. */
FOREACH_MAIN_ID_BEGIN (bmain, reference_id) {
if ((reference_id->tag & LIB_TAG_DOIT) != 0 && reference_id->lib == reference_library &&
BKE_idtype_idcode_is_linkable(GS(reference_id->name))) {
- todo_id_iter = MEM_callocN(sizeof(*todo_id_iter), __func__);
+ todo_id_iter = MEM_cnew<LinkData>(__func__);
todo_id_iter->data = reference_id;
BLI_addtail(&todo_ids, todo_id_iter);
}
@@ -450,18 +523,19 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
FOREACH_MAIN_ID_END;
/* Override the IDs. */
- for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- reference_id = todo_id_iter->data;
+ for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr;
+ todo_id_iter = todo_id_iter->next) {
+ reference_id = static_cast<ID *>(todo_id_iter->data);
/* If `newid` is already set, assume it has been handled by calling code.
* Only current use case: re-using proxy ID when converting to liboverride. */
- if (reference_id->newid == NULL) {
+ if (reference_id->newid == nullptr) {
/* NOTE: `no main` case is used during resync procedure, to support recursive resync.
* This requires extra care further down the resync process,
* see: #BKE_lib_override_library_resync. */
reference_id->newid = lib_override_library_create_from(
bmain, owner_library, reference_id, do_no_main ? LIB_ID_CREATE_NO_MAIN : 0);
- if (reference_id->newid == NULL) {
+ if (reference_id->newid == nullptr) {
success = false;
break;
}
@@ -473,11 +547,11 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
reference_id->newid->tag |= LIB_TAG_DOIT;
Key *reference_key;
- if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
+ if ((reference_key = BKE_key_from_id(reference_id)) != nullptr) {
reference_key->id.tag |= LIB_TAG_DOIT;
Key *local_key = BKE_key_from_id(reference_id->newid);
- BLI_assert(local_key != NULL);
+ BLI_assert(local_key != nullptr);
reference_key->id.newid = &local_key->id;
/* We also tag the new IDs so that in next step we can remap their pointers too. */
local_key->id.tag |= LIB_TAG_DOIT;
@@ -487,17 +561,18 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
/* Only remap new local ID's pointers, we don't want to force our new overrides onto our whole
* existing linked IDs usages. */
if (success) {
- if (id_hierarchy_root_reference != NULL) {
+ if (id_hierarchy_root_reference != nullptr) {
id_hierarchy_root = id_hierarchy_root_reference->newid;
}
- else if (id_root_reference->newid != NULL &&
- (id_hierarchy_root == NULL ||
+ else if (id_root_reference->newid != nullptr &&
+ (id_hierarchy_root == nullptr ||
id_hierarchy_root->override_library->reference == id_root_reference)) {
id_hierarchy_root = id_root_reference->newid;
}
- BLI_assert(id_hierarchy_root != NULL);
+ BLI_assert(id_hierarchy_root != nullptr);
- LinkNode *relinked_ids = NULL;
+ LinkNode *relinked_ids = nullptr;
+ IDRemapper *id_remapper = BKE_id_remapper_create();
/* Still checking the whole Main, that way we can tag other local IDs as needing to be
* remapped to use newly created overriding IDs, if needed. */
ID *id;
@@ -505,14 +580,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
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 == id_root_reference->lib && id->newid != NULL) {
+ if (do_no_main && id->lib == id_root_reference->lib && id->newid != nullptr) {
other_id = id->newid;
/* Otherwise we cannot properly distinguish between IDs that are actually from the
* linked library (and should not be remapped), and IDs that are overrides re-generated
* from the reference from the linked library, and must therefore be remapped.
*
* This is reset afterwards at the end of this loop. */
- other_id->lib = NULL;
+ other_id->lib = nullptr;
}
else {
other_id = id;
@@ -522,6 +597,14 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
* consider we should also relink it, as part of recursive resync. */
if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != id_root_reference->lib) {
BLI_linklist_prepend(&relinked_ids, other_id);
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(other_id) &&
+ other_id->override_library->hierarchy_root == id_hierarchy_root) {
+ reference_id = other_id->override_library->reference;
+ ID *local_id = reference_id->newid;
+ if (other_id == local_id) {
+ lib_override_remapper_overrides_add(id_remapper, reference_id, local_id);
+ }
+ }
}
if (other_id != id) {
other_id->lib = id_root_reference->lib;
@@ -529,26 +612,18 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
}
FOREACH_MAIN_ID_END;
- struct IDRemapper *id_remapper = BKE_id_remapper_create();
- for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- reference_id = todo_id_iter->data;
+ for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr;
+ todo_id_iter = todo_id_iter->next) {
+ reference_id = static_cast<ID *>(todo_id_iter->data);
ID *local_id = reference_id->newid;
- if (local_id == NULL) {
+ if (local_id == nullptr) {
continue;
}
local_id->override_library->hierarchy_root = id_hierarchy_root;
- BKE_id_remapper_add(id_remapper, reference_id, local_id);
-
- Key *reference_key, *local_key = NULL;
- if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
- local_key = BKE_key_from_id(reference_id->newid);
- BLI_assert(local_key != NULL);
-
- BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id);
- }
+ lib_override_remapper_overrides_add(id_remapper, reference_id, local_id);
}
BKE_libblock_relink_multiple(bmain,
@@ -558,14 +633,15 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT);
BKE_id_remapper_free(id_remapper);
- BLI_linklist_free(relinked_ids, NULL);
+ BLI_linklist_free(relinked_ids, nullptr);
}
else {
/* We need to cleanup potentially already created data. */
- for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
- reference_id = todo_id_iter->data;
+ for (todo_id_iter = static_cast<LinkData *>(todo_ids.first); todo_id_iter != nullptr;
+ todo_id_iter = todo_id_iter->next) {
+ reference_id = static_cast<ID *>(todo_id_iter->data);
BKE_id_delete(bmain, reference_id->newid);
- reference_id->newid = NULL;
+ reference_id->newid = nullptr;
}
}
@@ -574,7 +650,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
return success;
}
-typedef struct LibOverrideGroupTagData {
+struct LibOverrideGroupTagData {
Main *bmain;
Scene *scene;
ID *id_root;
@@ -590,7 +666,7 @@ typedef struct LibOverrideGroupTagData {
* 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)
@@ -605,8 +681,8 @@ static void lib_override_group_tag_data_object_to_collection_init_collection_pro
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));
+ *collections_linkedlist_p = static_cast<LinkNodePair *>(
+ BLI_memarena_calloc(data->mem_arena, sizeof(**collections_linkedlist_p)));
}
BLI_linklist_append_arena(*collections_linkedlist_p, collection, data->mem_arena);
}
@@ -623,7 +699,7 @@ static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGro
data->linked_object_to_instantiating_collections = BLI_ghash_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- if (data->scene != NULL) {
+ if (data->scene != nullptr) {
lib_override_group_tag_data_object_to_collection_init_collection_process(
data, data->scene->master_collection);
}
@@ -634,11 +710,56 @@ static void lib_override_group_tag_data_object_to_collection_init(LibOverrideGro
static void lib_override_group_tag_data_clear(LibOverrideGroupTagData *data)
{
- BLI_ghash_free(data->linked_object_to_instantiating_collections, NULL, NULL);
+ BLI_ghash_free(data->linked_object_to_instantiating_collections, nullptr, nullptr);
BLI_memarena_free(data->mem_arena);
memset(data, 0, sizeof(*data));
}
+static void lib_override_hierarchy_dependencies_recursive_tag_from(LibOverrideGroupTagData *data)
+{
+ Main *bmain = data->bmain;
+ ID *id = data->id_root;
+ const bool is_override = data->is_override;
+
+ if ((*(uint *)&id->tag & data->tag) == 0) {
+ /* This ID is not tagged, no reason to proceed further to its parents. */
+ return;
+ }
+
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
+
+ if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM) {
+ /* This ID has already been processed. */
+ return;
+ }
+ /* This way we won't process again that ID, should we encounter it again through another
+ * relationship hierarchy. */
+ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_FROM;
+
+ for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr;
+ from_id_entry = from_id_entry->next) {
+ if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
+ /* Never consider non-overridable relationships ('from', 'parents', 'owner' etc. pointers)
+ * as actual dependencies. */
+ continue;
+ }
+ /* We only consider IDs from the same library. */
+ ID *from_id = from_id_entry->id_pointer.from;
+ if (from_id == nullptr || from_id->lib != id->lib ||
+ (is_override && !ID_IS_OVERRIDE_LIBRARY(from_id))) {
+ /* IDs from different libraries, or non-override IDs in case we are processing overrides,
+ * are both barriers of dependency. */
+ continue;
+ }
+ from_id->tag |= data->tag;
+ LibOverrideGroupTagData sub_data = *data;
+ sub_data.id_root = from_id;
+ lib_override_hierarchy_dependencies_recursive_tag_from(&sub_data);
+ }
+}
+
/* Tag all IDs in dependency relationships within an override hierarchy/group.
*
* Requires existing `Main.relations`.
@@ -650,19 +771,21 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
Main *bmain = data->bmain;
ID *id = data->id_root;
const bool is_override = data->is_override;
+ const bool is_resync = data->is_resync;
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
- if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
+ if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO) {
/* This ID has already been processed. */
return (*(uint *)&id->tag & data->tag) != 0;
}
/* This way we won't process again that ID, should we encounter it again through another
* relationship hierarchy. */
- entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
+ entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED_TO;
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships ('from', 'parents', 'owner' etc. pointers) as
@@ -671,7 +794,7 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
}
/* We only consider IDs from the same library. */
ID *to_id = *to_id_entry->id_pointer.to;
- if (to_id == NULL || to_id->lib != id->lib ||
+ if (to_id == nullptr || to_id->lib != id->lib ||
(is_override && !ID_IS_OVERRIDE_LIBRARY(to_id))) {
/* IDs from different libraries, or non-override IDs in case we are processing overrides, are
* both barriers of dependency. */
@@ -684,6 +807,15 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(LibOverrideGroupTa
}
}
+ /* If the current ID is/has been tagged for override above, then check its reversed dependencies
+ * (i.e. IDs that depend on the current one).
+ *
+ * This will cover e.g. the case where user override an armature, and would expect the mesh
+ * object deformed by that armature to also be overridden. */
+ if ((*(uint *)&id->tag & data->tag) != 0 && !is_resync) {
+ lib_override_hierarchy_dependencies_recursive_tag_from(data);
+ }
+
return (*(uint *)&id->tag & data->tag) != 0;
}
@@ -696,9 +828,9 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
const uint tag = data->tag;
const uint missing_tag = data->missing_tag;
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
- id_owner);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_owner));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
@@ -708,7 +840,7 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
* relationship hierarchy. */
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -716,7 +848,7 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
}
ID *to_id = *to_id_entry->id_pointer.to;
- if (ELEM(to_id, NULL, id_owner)) {
+ if (ELEM(to_id, nullptr, id_owner)) {
continue;
}
/* We only consider IDs from the same library. */
@@ -751,10 +883,12 @@ static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursiv
* is not usable here, as it may have become invalid from some previous operation and it should
* not be updated here. So instead only use collections' reliable 'raw' data to check if some
* object in the hierarchy of the given collection is still tagged for override. */
- for (CollectionObject *collection_object = collection->gobject.first; collection_object != NULL;
+ for (CollectionObject *collection_object =
+ static_cast<CollectionObject *>(collection->gobject.first);
+ collection_object != nullptr;
collection_object = collection_object->next) {
Object *object = collection_object->ob;
- if (object == NULL) {
+ if (object == nullptr) {
continue;
}
if ((object->id.tag & data->tag) != 0) {
@@ -762,7 +896,9 @@ static bool lib_override_linked_group_tag_collections_keep_tagged_check_recursiv
}
}
- for (CollectionChild *collection_child = collection->children.first; collection_child != NULL;
+ for (CollectionChild *collection_child =
+ static_cast<CollectionChild *>(collection->children.first);
+ collection_child != nullptr;
collection_child = collection_child->next) {
if (lib_override_linked_group_tag_collections_keep_tagged_check_recursive(
data, collection_child->collection)) {
@@ -781,9 +917,11 @@ static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGr
/* 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 != id_root) {
+ if (ob->type == OB_ARMATURE && ob->pose != nullptr && (ob->id.tag & data->tag)) {
+ for (bPoseChannel *pchan = static_cast<bPoseChannel *>(ob->pose->chanbase.first);
+ pchan != nullptr;
+ pchan = pchan->next) {
+ if (pchan->custom != nullptr && &pchan->custom->id != id_root) {
pchan->custom->id.tag &= ~data->tag;
}
}
@@ -827,11 +965,6 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
id_root->tag |= data->tag;
}
- /* Only objects and groups are currently considered as 'keys' in override hierarchies. */
- if (!ELEM(GS(id_root->name), ID_OB, ID_GR)) {
- return;
- }
-
/* Tag all collections and objects recursively. */
lib_override_linked_group_tag_recursive(data);
@@ -860,17 +993,18 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
}
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;
+ Collection *instantiating_collection = nullptr;
+ Collection *instantiating_collection_override_candidate = nullptr;
/* 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) {
+ LinkNodePair *instantiating_collection_linklist = static_cast<LinkNodePair *>(
+ BLI_ghash_lookup(data->linked_object_to_instantiating_collections, ob));
+ if (instantiating_collection_linklist != nullptr) {
for (LinkNode *instantiating_collection_linknode = instantiating_collection_linklist->list;
- instantiating_collection_linknode != NULL;
+ instantiating_collection_linknode != nullptr;
instantiating_collection_linknode = instantiating_collection_linknode->next) {
- instantiating_collection = instantiating_collection_linknode->link;
+ instantiating_collection = static_cast<Collection *>(
+ instantiating_collection_linknode->link);
if (!ID_IS_LINKED(instantiating_collection)) {
/* There is a local collection instantiating the linked object to override, nothing
* else to be done here. */
@@ -882,12 +1016,12 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
break;
}
instantiating_collection_override_candidate = instantiating_collection;
- instantiating_collection = NULL;
+ instantiating_collection = nullptr;
}
}
- if (instantiating_collection == NULL &&
- instantiating_collection_override_candidate != NULL) {
+ if (instantiating_collection == nullptr &&
+ instantiating_collection_override_candidate != nullptr) {
if (instantiating_collection_override_candidate->id.tag & LIB_TAG_MISSING) {
instantiating_collection_override_candidate->id.tag |= data->missing_tag;
}
@@ -916,9 +1050,9 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
const uint tag = data->tag;
const uint missing_tag = data->missing_tag;
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
- id_owner);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id_owner));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
@@ -928,7 +1062,7 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
* relationship hierarchy. */
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -936,7 +1070,7 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
}
ID *to_id = *to_id_entry->id_pointer.to;
- if (ELEM(to_id, NULL, id_owner)) {
+ if (ELEM(to_id, nullptr, id_owner)) {
continue;
}
/* Different libraries or different hierarchy roots are break points in override hierarchies.
@@ -949,8 +1083,8 @@ static void lib_override_overrides_group_tag_recursive(LibOverrideGroupTagData *
continue;
}
- Library *reference_lib = lib_override_get(bmain, id_owner, NULL)->reference->lib;
- ID *to_id_reference = lib_override_get(bmain, to_id, NULL)->reference;
+ const Library *reference_lib = lib_override_get(bmain, id_owner, nullptr)->reference->lib;
+ const ID *to_id_reference = lib_override_get(bmain, to_id, nullptr)->reference;
if (to_id_reference->lib != reference_lib) {
/* We do not override data-blocks from other libraries, nor do we process them. */
continue;
@@ -978,7 +1112,7 @@ static void lib_override_overrides_group_tag(LibOverrideGroupTagData *data)
BLI_assert(data->is_override);
ID *id_hierarchy_root = data->hierarchy_root_id;
- BLI_assert(id_hierarchy_root != NULL);
+ BLI_assert(id_hierarchy_root != nullptr);
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root));
UNUSED_VARS_NDEBUG(id_hierarchy_root);
@@ -1001,32 +1135,45 @@ static bool lib_override_library_create_do(Main *bmain,
const bool do_fully_editable)
{
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = scene,
- .id_root = id_root_reference,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = false,
- .is_resync = false};
+ LibOverrideGroupTagData data{};
+ data.bmain = bmain;
+ data.scene = scene;
+ data.id_root = id_root_reference;
+ data.tag = LIB_TAG_DOIT;
+ data.missing_tag = LIB_TAG_MISSING;
+ data.is_override = false;
+ data.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);
+ /* In case the operation is on an already partially overridden hierarchy, all existing overrides
+ * in that hierarchy need to be tagged for remapping from linked reference ID usages to newly
+ * created overrides ones. */
+ if (id_hierarchy_root_reference->lib != id_root_reference->lib) {
+ BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
+ BLI_assert(id_hierarchy_root_reference->override_library->reference->lib ==
+ id_root_reference->lib);
+
+ BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
+ data.hierarchy_root_id = id_hierarchy_root_reference;
+ data.id_root = id_hierarchy_root_reference;
+ data.is_override = true;
+ lib_override_overrides_group_tag(&data);
+ }
+
BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data);
bool success = false;
if (id_hierarchy_root_reference->lib != id_root_reference->lib) {
- BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_hierarchy_root_reference));
- BLI_assert(id_hierarchy_root_reference->override_library->reference->lib ==
- id_root_reference->lib);
success = BKE_lib_override_library_create_from_tag(bmain,
owner_library,
id_root_reference,
id_hierarchy_root_reference,
- NULL,
+ nullptr,
false,
do_fully_editable);
}
@@ -1034,7 +1181,7 @@ static bool lib_override_library_create_do(Main *bmain,
success = BKE_lib_override_library_create_from_tag(bmain,
owner_library,
id_root_reference,
- NULL,
+ nullptr,
id_hierarchy_root_reference,
false,
do_fully_editable);
@@ -1064,25 +1211,25 @@ static void lib_override_library_create_post_process(Main *bmain,
/* We create a set of all objects referenced into the scene by its hierarchy of collections.
* NOTE: This is different that the list of bases, since objects in excluded collections etc.
* won't have a base, but are still considered as instanced from our point of view. */
- GSet *all_objects_in_scene = BKE_scene_objects_as_gset(scene, NULL);
+ GSet *all_objects_in_scene = BKE_scene_objects_as_gset(scene, nullptr);
/* Instantiating the root collection or object should never be needed in resync case, since the
* old override would be remapped to the new one. */
- if (!is_resync && id_root != NULL && id_root->newid != NULL &&
+ if (!is_resync && id_root != nullptr && id_root->newid != nullptr &&
(!ID_IS_LINKED(id_root->newid) || id_root->newid->lib == owner_library)) {
switch (GS(id_root->name)) {
case ID_GR: {
- Object *ob_reference = id_instance_hint != NULL && GS(id_instance_hint->name) == ID_OB ?
+ Object *ob_reference = id_instance_hint != nullptr && GS(id_instance_hint->name) == ID_OB ?
(Object *)id_instance_hint :
- NULL;
+ nullptr;
Collection *collection_new = ((Collection *)id_root->newid);
if (is_resync && BKE_collection_is_in_scene(collection_new)) {
break;
}
- if (ob_reference != NULL) {
+ if (ob_reference != nullptr) {
BKE_collection_add_from_object(bmain, scene, ob_reference, collection_new);
}
- else if (id_instance_hint != NULL) {
+ else if (id_instance_hint != nullptr) {
BLI_assert(GS(id_instance_hint->name) == ID_GR);
BKE_collection_add_from_collection(
bmain, scene, ((Collection *)id_instance_hint), collection_new);
@@ -1099,7 +1246,7 @@ static void lib_override_library_create_post_process(Main *bmain,
}
case ID_OB: {
Object *ob_new = (Object *)id_root->newid;
- if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) {
+ if (BLI_gset_lookup(all_objects_in_scene, ob_new) == nullptr) {
BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new);
all_objects_in_scene = BKE_scene_objects_as_gset(scene, all_objects_in_scene);
}
@@ -1114,16 +1261,16 @@ static void lib_override_library_create_post_process(Main *bmain,
Collection *default_instantiating_collection = residual_storage;
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
Object *ob_new = (Object *)ob->id.newid;
- if (ob_new == NULL || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) {
+ if (ob_new == nullptr || (ID_IS_LINKED(ob_new) && ob_new->id.lib != owner_library)) {
continue;
}
- BLI_assert(ob_new->id.override_library != NULL &&
+ BLI_assert(ob_new->id.override_library != nullptr &&
ob_new->id.override_library->reference == &ob->id);
- if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) {
- if (id_root != NULL && default_instantiating_collection == NULL) {
- ID *id_ref = id_root->newid != NULL ? id_root->newid : id_root;
+ if (BLI_gset_lookup(all_objects_in_scene, ob_new) == nullptr) {
+ if (id_root != nullptr && default_instantiating_collection == nullptr) {
+ ID *id_ref = id_root->newid != nullptr ? id_root->newid : id_root;
switch (GS(id_ref->name)) {
case ID_GR: {
/* Adding the object to a specific collection outside of the root overridden one is a
@@ -1136,7 +1283,8 @@ static void lib_override_library_create_post_process(Main *bmain,
if (ID_REAL_USERS(ob_new) != 0) {
continue;
}
- default_instantiating_collection = BKE_id_new(bmain, ID_GR, "OVERRIDE_HIDDEN");
+ default_instantiating_collection = static_cast<Collection *>(
+ BKE_id_new(bmain, ID_GR, "OVERRIDE_HIDDEN"));
id_us_min(&default_instantiating_collection->id);
/* Hide the collection from viewport and render. */
default_instantiating_collection->flag |= COLLECTION_HIDE_VIEWPORT |
@@ -1149,7 +1297,7 @@ static void lib_override_library_create_post_process(Main *bmain,
Object *ob_ref = (Object *)id_ref;
LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
if (BKE_collection_has_object(collection, ob_ref) &&
- (view_layer != NULL ?
+ (view_layer != nullptr ?
BKE_view_layer_has_collection(view_layer, collection) :
BKE_collection_has_collection(scene->master_collection, collection)) &&
!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) {
@@ -1162,7 +1310,7 @@ static void lib_override_library_create_post_process(Main *bmain,
break;
}
}
- if (default_instantiating_collection == NULL) {
+ if (default_instantiating_collection == nullptr) {
default_instantiating_collection = scene->master_collection;
}
@@ -1171,8 +1319,9 @@ static void lib_override_library_create_post_process(Main *bmain,
}
}
- if (id_root != NULL && !ELEM(default_instantiating_collection, NULL, scene->master_collection)) {
- ID *id_ref = id_root->newid != NULL ? id_root->newid : id_root;
+ if (id_root != nullptr &&
+ !ELEM(default_instantiating_collection, nullptr, scene->master_collection)) {
+ ID *id_ref = id_root->newid != nullptr ? id_root->newid : id_root;
switch (GS(id_ref->name)) {
case ID_GR:
BKE_collection_add_from_collection(
@@ -1180,12 +1329,13 @@ static void lib_override_library_create_post_process(Main *bmain,
break;
default:
/* Add to master collection. */
- BKE_collection_add_from_collection(bmain, scene, NULL, default_instantiating_collection);
+ BKE_collection_add_from_collection(
+ bmain, scene, nullptr, default_instantiating_collection);
break;
}
}
- BLI_gset_free(all_objects_in_scene, NULL);
+ BLI_gset_free(all_objects_in_scene, nullptr);
}
bool BKE_lib_override_library_create(Main *bmain,
@@ -1198,11 +1348,11 @@ bool BKE_lib_override_library_create(Main *bmain,
ID **r_id_root_override,
const bool do_fully_editable)
{
- if (r_id_root_override != NULL) {
- *r_id_root_override = NULL;
+ if (r_id_root_override != nullptr) {
+ *r_id_root_override = nullptr;
}
- if (id_hierarchy_root_reference == NULL) {
+ if (id_hierarchy_root_reference == nullptr) {
id_hierarchy_root_reference = id_root_reference;
}
@@ -1217,12 +1367,18 @@ bool BKE_lib_override_library_create(Main *bmain,
return success;
}
- if (r_id_root_override != NULL) {
+ if (r_id_root_override != nullptr) {
*r_id_root_override = id_root_reference->newid;
}
- lib_override_library_create_post_process(
- bmain, scene, view_layer, owner_library, id_root_reference, id_instance_hint, NULL, false);
+ lib_override_library_create_post_process(bmain,
+ scene,
+ view_layer,
+ owner_library,
+ id_root_reference,
+ id_instance_hint,
+ nullptr,
+ false);
/* Cleanup. */
BKE_main_id_newptr_and_tag_clear(bmain);
@@ -1234,7 +1390,7 @@ bool BKE_lib_override_library_create(Main *bmain,
return success;
}
-bool BKE_lib_override_library_template_create(struct ID *id)
+bool BKE_lib_override_library_template_create(ID *id)
{
if (ID_IS_LINKED(id)) {
return false;
@@ -1243,7 +1399,7 @@ bool BKE_lib_override_library_template_create(struct ID *id)
return false;
}
- BKE_lib_override_library_init(id, NULL);
+ BKE_lib_override_library_init(id, nullptr);
return true;
}
@@ -1254,16 +1410,17 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
"Levels of dependency relationships between library overrides IDs is way too high, "
"skipping further processing loops (involves at least '%s')",
id->name);
- return NULL;
+ return nullptr;
}
if (!ID_IS_OVERRIDE_LIBRARY(id)) {
BLI_assert_unreachable();
- return NULL;
+ return nullptr;
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
@@ -1285,7 +1442,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
int best_level_candidate = curr_level;
ID *best_root_id_candidate = id;
- for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL;
+ for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr;
from_id_entry = from_id_entry->next) {
if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -1293,7 +1450,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
}
ID *from_id = from_id_entry->id_pointer.from;
- if (ELEM(from_id, NULL, id)) {
+ if (ELEM(from_id, nullptr, id)) {
continue;
}
if (!ID_IS_OVERRIDE_LIBRARY(from_id) || (from_id->lib != id->lib)) {
@@ -1304,7 +1461,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
/* Recursively process the parent. */
ID *root_id_candidate = lib_override_root_find(
bmain, from_id, curr_level + 1, &level_candidate);
- if (level_candidate > best_level_candidate && root_id_candidate != NULL) {
+ if (level_candidate > best_level_candidate && root_id_candidate != nullptr) {
best_root_id_candidate = root_id_candidate;
best_level_candidate = level_candidate;
}
@@ -1319,7 +1476,7 @@ static ID *lib_override_root_find(Main *bmain, ID *id, const int curr_level, int
bmain, id_owner, curr_level + 1, &best_level_placeholder);
}
- BLI_assert(best_root_id_candidate != NULL);
+ BLI_assert(best_root_id_candidate != nullptr);
BLI_assert((best_root_id_candidate->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) == 0);
*r_best_level = best_level_candidate;
@@ -1337,14 +1494,14 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
/* Hierarchy root already set, and not matching currently proposed one, try to find which is
* best. */
- if (id->override_library->hierarchy_root != NULL) {
+ if (id->override_library->hierarchy_root != nullptr) {
/* Check if given `id_from` matches with the hierarchy of the linked reference ID, in which
* case we assume that the given hierarchy root is the 'real' one.
*
* NOTE: This can fail if user mixed dependencies between several overrides of a same
* reference linked hierarchy. Not much to be done in that case, it's virtually impossible to
* fix this automatically in a reliable way. */
- if (id_from == NULL || !ID_IS_OVERRIDE_LIBRARY_REAL(id_from)) {
+ if (id_from == nullptr || !ID_IS_OVERRIDE_LIBRARY_REAL(id_from)) {
/* Too complicated to deal with for now. */
CLOG_WARN(&LOG,
"Inconsistency in library override hierarchy of ID '%s'.\n"
@@ -1357,12 +1514,12 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
}
ID *id_from_ref = id_from->override_library->reference;
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers,
- id->override_library->reference);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(BLI_ghash_lookup(
+ bmain->relations->relations_from_pointers, id->override_library->reference));
+ BLI_assert(entry != nullptr);
bool do_replace_root = false;
- for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != NULL;
+ for (MainIDRelationsEntryItem *from_id_entry = entry->from_ids; from_id_entry != nullptr;
from_id_entry = from_id_entry->next) {
if ((from_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -1399,10 +1556,11 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
id->override_library->hierarchy_root = id_root;
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships as actual dependencies. */
@@ -1410,7 +1568,7 @@ static void lib_override_root_hierarchy_set(Main *bmain, ID *id_root, ID *id, ID
}
ID *to_id = *to_id_entry->id_pointer.to;
- if (ELEM(to_id, NULL, id)) {
+ if (ELEM(to_id, nullptr, id)) {
continue;
}
if (!ID_IS_OVERRIDE_LIBRARY(to_id) || (to_id->lib != id->lib)) {
@@ -1432,18 +1590,18 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
continue;
}
- if (id->override_library->hierarchy_root != NULL) {
+ if (id->override_library->hierarchy_root != nullptr) {
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id->override_library->hierarchy_root) ||
id->override_library->hierarchy_root->lib != id->lib) {
CLOG_ERROR(
&LOG,
"Existing override hierarchy root ('%s') for ID '%s' is invalid, will try to find a "
"new valid one",
- id->override_library->hierarchy_root != NULL ?
+ id->override_library->hierarchy_root != nullptr ?
id->override_library->hierarchy_root->name :
"<NONE>",
id->name);
- id->override_library->hierarchy_root = NULL;
+ id->override_library->hierarchy_root = nullptr;
}
else {
continue;
@@ -1455,7 +1613,7 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
int best_level = 0;
ID *id_root = lib_override_root_find(bmain, id, best_level, &best_level);
- if (!ELEM(id_root->override_library->hierarchy_root, id_root, NULL)) {
+ if (!ELEM(id_root->override_library->hierarchy_root, id_root, nullptr)) {
CLOG_WARN(&LOG,
"Potential inconsistency in library override hierarchy of ID '%s', detected as "
"part of the hierarchy of '%s', which has a different root '%s'",
@@ -1465,9 +1623,9 @@ void BKE_lib_override_library_main_hierarchy_root_ensure(Main *bmain)
continue;
}
- lib_override_root_hierarchy_set(bmain, id_root, id, NULL);
+ lib_override_root_hierarchy_set(bmain, id_root, id, nullptr);
- BLI_assert(id->override_library->hierarchy_root != NULL);
+ BLI_assert(id->override_library->hierarchy_root != nullptr);
}
FOREACH_MAIN_ID_END;
@@ -1479,14 +1637,14 @@ static void lib_override_library_remap(Main *bmain,
GHash *linkedref_to_old_override)
{
ID *id;
- struct IDRemapper *remapper = BKE_id_remapper_create();
- LinkNode *nomain_ids = NULL;
+ IDRemapper *remapper = BKE_id_remapper_create();
+ LinkNode *nomain_ids = nullptr;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && 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) {
+ ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id));
+ if (id_override_old == nullptr) {
continue;
}
@@ -1498,7 +1656,8 @@ static void lib_override_library_remap(Main *bmain,
/* 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);
+ ID *id_override_old_iter = static_cast<ID *>(
+ BLI_ghashIterator_getValue(&linkedref_to_old_override_iter));
if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) {
continue;
}
@@ -1514,7 +1673,7 @@ static void lib_override_library_remap(Main *bmain,
remapper,
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
BKE_id_remapper_free(remapper);
- BLI_linklist_free(nomain_ids, NULL);
+ BLI_linklist_free(nomain_ids, nullptr);
}
static bool lib_override_library_resync(Main *bmain,
@@ -1534,7 +1693,7 @@ static bool lib_override_library_resync(Main *bmain,
ID *id;
if (id_root_reference->tag & LIB_TAG_MISSING) {
- BKE_reportf(reports != NULL ? reports->reports : NULL,
+ BKE_reportf(reports != nullptr ? reports->reports : nullptr,
RPT_ERROR,
"Impossible to resync data-block %s and its dependencies, as its linked reference "
"is missing",
@@ -1543,14 +1702,15 @@ static bool lib_override_library_resync(Main *bmain,
}
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = scene,
- .id_root = id_root,
- .hierarchy_root_id = id_root->override_library->hierarchy_root,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = true,
- .is_resync = true};
+ LibOverrideGroupTagData data{};
+ data.bmain = bmain;
+ data.scene = scene;
+ data.id_root = id_root;
+ data.hierarchy_root_id = id_root->override_library->hierarchy_root;
+ data.tag = LIB_TAG_DOIT;
+ data.missing_tag = LIB_TAG_MISSING;
+ data.is_override = true;
+ data.is_resync = true;
lib_override_group_tag_data_object_to_collection_init(&data);
/* Mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, populated from
@@ -1560,9 +1720,9 @@ static bool lib_override_library_resync(Main *bmain,
/* Only tag linked IDs from related linked reference hierarchy that are actually part of
* the sub-trees of each detected sub-roots needing resync. */
- for (LinkNode *resync_root_link = id_resync_roots; resync_root_link != NULL;
+ for (LinkNode *resync_root_link = id_resync_roots; resync_root_link != nullptr;
resync_root_link = resync_root_link->next) {
- ID *id_resync_root = resync_root_link->link;
+ ID *id_resync_root = static_cast<ID *>(resync_root_link->link);
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_resync_root));
if ((id_resync_root->tag & LIB_TAG_NO_MAIN) != 0) {
@@ -1584,12 +1744,12 @@ static bool lib_override_library_resync(Main *bmain,
if (id_resync_root_reference->tag & LIB_TAG_MISSING) {
BKE_reportf(
- reports != NULL ? reports->reports : NULL,
+ reports != nullptr ? reports->reports : nullptr,
RPT_ERROR,
"Impossible to resync data-block %s and its dependencies, as its linked reference "
"is missing",
id_root->name + 2);
- BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
+ BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr);
BKE_main_relations_free(bmain);
lib_override_group_tag_data_clear(&data);
return false;
@@ -1624,11 +1784,16 @@ static bool lib_override_library_resync(Main *bmain,
id->tag |= LIB_TAG_MISSING;
}
- if (id->tag & LIB_TAG_DOIT && (id->lib == id_root->lib) && ID_IS_OVERRIDE_LIBRARY(id)) {
+ if ((id->lib == id_root->lib) && ID_IS_OVERRIDE_LIBRARY(id)) {
/* While this should not happen in typical cases (and won't be properly supported here),
* user is free to do all kind of very bad things, including having different local
* overrides of a same linked ID in a same hierarchy. */
- IDOverrideLibrary *id_override_library = lib_override_get(bmain, id, NULL);
+ IDOverrideLibrary *id_override_library = lib_override_get(bmain, id, nullptr);
+
+ if (id_override_library->hierarchy_root != id_root->override_library->hierarchy_root) {
+ continue;
+ }
+
ID *reference_id = id_override_library->reference;
if (GS(reference_id->name) != GS(id->name)) {
switch (GS(id->name)) {
@@ -1646,11 +1811,16 @@ static bool lib_override_library_resync(Main *bmain,
break;
}
}
+ if (reference_id == nullptr) {
+ /* Can happen e.g. when there is a local override of a shapekey, but the matching linked
+ * obdata (mesh etc.) does not have any shapekey anymore. */
+ continue;
+ }
BLI_assert(GS(reference_id->name) == GS(id->name));
if (!BLI_ghash_haskey(linkedref_to_old_override, reference_id)) {
BLI_ghash_insert(linkedref_to_old_override, reference_id, id);
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || (id->tag & LIB_TAG_DOIT) == 0) {
continue;
}
if ((id->override_library->reference->tag & LIB_TAG_DOIT) == 0) {
@@ -1701,24 +1871,24 @@ static bool lib_override_library_resync(Main *bmain,
* above). */
const bool success = BKE_lib_override_library_create_from_tag(
bmain,
- NULL,
+ nullptr,
id_root_reference,
id_root->override_library->hierarchy_root,
- NULL,
+ nullptr,
true,
false);
if (!success) {
- BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
+ BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr);
return success;
}
ListBase *lb;
FOREACH_MAIN_LISTBASE_BEGIN (bmain, lb) {
FOREACH_MAIN_LISTBASE_ID_BEGIN (lb, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && id->lib == id_root_reference->lib) {
ID *id_override_new = id->newid;
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id));
BLI_assert((id_override_new->tag & LIB_TAG_LIB_OVERRIDE_NEED_RESYNC) == 0);
@@ -1726,14 +1896,14 @@ static bool lib_override_library_resync(Main *bmain,
* duplicated from the reference ID with 'no main' option, it should currently be the same
* as the reference ID one). */
BLI_assert(/*!ID_IS_LINKED(id_override_new) || */ id_override_new->lib == id->lib);
- BLI_assert(id_override_old == NULL || id_override_old->lib == id_root->lib);
+ BLI_assert(id_override_old == nullptr || id_override_old->lib == id_root->lib);
id_override_new->lib = id_root->lib;
/* Remap step below will tag directly linked ones properly as needed. */
if (ID_IS_LINKED(id_override_new)) {
id_override_new->tag |= LIB_TAG_INDIRECT;
}
- if (id_override_old != NULL) {
+ if (id_override_old != nullptr) {
/* Swap the names between old override ID and new one. */
char id_name_buf[MAX_ID_NAME];
memcpy(id_name_buf, id_override_old->name, sizeof(id_name_buf));
@@ -1754,10 +1924,10 @@ static bool lib_override_library_resync(Main *bmain,
/* Copy over overrides rules from old override ID to new one. */
BLI_duplicatelist(&id_override_new->override_library->properties,
&id_override_old->override_library->properties);
- IDOverrideLibraryProperty *op_new =
- id_override_new->override_library->properties.first;
- IDOverrideLibraryProperty *op_old =
- id_override_old->override_library->properties.first;
+ IDOverrideLibraryProperty *op_new = static_cast<IDOverrideLibraryProperty *>(
+ id_override_new->override_library->properties.first);
+ IDOverrideLibraryProperty *op_old = static_cast<IDOverrideLibraryProperty *>(
+ id_override_old->override_library->properties.first);
for (; op_new; op_new = op_new->next, op_old = op_old->next) {
lib_override_library_property_copy(op_new, op_old);
}
@@ -1782,20 +1952,20 @@ static bool lib_override_library_resync(Main *bmain,
BKE_main_collection_sync(bmain);
- LinkNode *id_override_old_list = NULL;
+ LinkNode *id_override_old_list = nullptr;
/* We need to apply override rules in a separate loop, after all ID pointers have been properly
* remapped, and all new local override IDs have gotten their proper original names, otherwise
* override operations based on those ID names would fail. */
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
+ if (id->tag & LIB_TAG_DOIT && id->newid != nullptr && id->lib == id_root_reference->lib) {
ID *id_override_new = id->newid;
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_override_new)) {
continue;
}
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id));
- if (id_override_old == NULL) {
+ if (id_override_old == nullptr) {
continue;
}
if (ID_IS_OVERRIDE_LIBRARY_REAL(id_override_old)) {
@@ -1826,7 +1996,7 @@ static bool lib_override_library_resync(Main *bmain,
RNA_struct_override_apply(bmain,
&rnaptr_dst,
&rnaptr_src,
- NULL,
+ nullptr,
id_override_new->override_library,
do_hierarchy_enforce ?
RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS :
@@ -1841,18 +2011,18 @@ static bool lib_override_library_resync(Main *bmain,
/* Once overrides have been properly 'transferred' from old to new ID, we can clear ID usages
* of the old one.
* This is necessary in case said old ID is not in Main anymore. */
- struct IDRemapper *id_remapper = BKE_id_remapper_create();
+ IDRemapper *id_remapper = BKE_id_remapper_create();
BKE_libblock_relink_multiple(bmain,
id_override_old_list,
ID_REMAP_TYPE_CLEANUP,
id_remapper,
ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- for (LinkNode *ln_iter = id_override_old_list; ln_iter != NULL; ln_iter = ln_iter->next) {
- ID *id_override_old = ln_iter->link;
+ for (LinkNode *ln_iter = id_override_old_list; ln_iter != nullptr; ln_iter = ln_iter->next) {
+ ID *id_override_old = static_cast<ID *>(ln_iter->link);
id_override_old->tag |= LIB_TAG_NO_USER_REFCOUNT;
}
BKE_id_remapper_free(id_remapper);
- BLI_linklist_free(id_override_old_list, NULL);
+ BLI_linklist_free(id_override_old_list, nullptr);
/* Delete old override IDs.
* Note that we have to use tagged group deletion here, since ID deletion also uses
@@ -1863,10 +2033,10 @@ static bool lib_override_library_resync(Main *bmain,
/* Note that this works because linked IDs are always after local ones (including
* overrides), so we will only ever tag an old override ID after we have already checked it
* in this loop, hence we cannot untag it later. */
- if (id->newid != NULL && id->lib == id_root_reference->lib) {
- ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
+ if (id->newid != nullptr && id->lib == id_root_reference->lib) {
+ ID *id_override_old = static_cast<ID *>(BLI_ghash_lookup(linkedref_to_old_override, id));
- if (id_override_old != NULL) {
+ if (id_override_old != nullptr) {
id->newid->tag &= ~LIB_TAG_DOIT;
id_override_old->tag |= LIB_TAG_DOIT;
if (id_override_old->tag & LIB_TAG_NO_MAIN) {
@@ -1910,19 +2080,19 @@ static bool lib_override_library_resync(Main *bmain,
FOREACH_MAIN_ID_END;
/* Cleanup, many pointers in this GHash are already invalid now. */
- BLI_ghash_free(linkedref_to_old_override, NULL, NULL);
+ BLI_ghash_free(linkedref_to_old_override, nullptr, nullptr);
BKE_id_multi_tagged_delete(bmain);
/* At this point, `id_root` may have been resynced, therefore deleted. In that case we need to
* update it to its new version.
*/
- if (id_root_reference->newid != NULL) {
+ if (id_root_reference->newid != nullptr) {
id_root = id_root_reference->newid;
}
if (user_edited_overrides_deletion_count > 0) {
- BKE_reportf(reports != NULL ? reports->reports : NULL,
+ BKE_reportf(reports != nullptr ? reports->reports : nullptr,
RPT_WARNING,
"During resync of data-block %s, %d obsolete overrides were deleted, that had "
"local changes defined by user",
@@ -1939,7 +2109,7 @@ static bool lib_override_library_resync(Main *bmain,
lib_override_library_create_post_process(bmain,
scene,
view_layer,
- NULL,
+ nullptr,
id_root_reference,
id_root,
override_resync_residual_storage,
@@ -1961,8 +2131,10 @@ bool BKE_lib_override_library_resync(Main *bmain,
const bool do_hierarchy_enforce,
BlendFileReadReport *reports)
{
- ListBase no_main_ids_list = {NULL};
- LinkNode id_resync_roots = {.link = id_root, .next = NULL};
+ ListBase no_main_ids_list = {nullptr};
+ LinkNode id_resync_roots{};
+ id_resync_roots.link = id_root;
+ id_resync_roots.next = nullptr;
const bool success = lib_override_library_resync(bmain,
scene,
@@ -1996,14 +2168,14 @@ static ID *lib_override_library_main_resync_root_get(Main *bmain, ID *id)
{
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id);
- if (id_type->owner_get != NULL) {
+ if (id_type->owner_get != nullptr) {
id = id_type->owner_get(bmain, id);
}
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id));
}
ID *hierarchy_root_id = id->override_library->hierarchy_root;
- BLI_assert(hierarchy_root_id != NULL);
+ BLI_assert(hierarchy_root_id != nullptr);
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(hierarchy_root_id));
return hierarchy_root_id;
}
@@ -2038,8 +2210,9 @@ static bool lib_override_resync_tagging_finalize_recurse(
return false;
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
@@ -2073,7 +2246,7 @@ static bool lib_override_resync_tagging_finalize_recurse(
id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
bool is_ancestor_tagged_for_resync = false;
- for (MainIDRelationsEntryItem *entry_item = entry->from_ids; entry_item != NULL;
+ for (MainIDRelationsEntryItem *entry_item = entry->from_ids; entry_item != nullptr;
entry_item = entry_item->next) {
if (entry_item->usage_flag &
(IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE | IDWALK_CB_LOOPBACK)) {
@@ -2130,11 +2303,11 @@ static bool lib_override_resync_tagging_finalize_recurse(
CLOG_INFO(&LOG, 4, "Found root ID '%s' for resync root ID '%s'", id_root->name, id->name);
- BLI_assert(id_root->override_library != NULL);
+ BLI_assert(id_root->override_library != nullptr);
LinkNodePair **id_resync_roots_p;
if (!BLI_ghash_ensure_p(id_roots, id_root, (void ***)&id_resync_roots_p)) {
- *id_resync_roots_p = MEM_callocN(sizeof(**id_resync_roots_p), __func__);
+ *id_resync_roots_p = MEM_cnew<LinkNodePair>(__func__);
}
BLI_linklist_append(*id_resync_roots_p, id);
@@ -2169,13 +2342,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};
+ LibOverrideGroupTagData data = {};
+ data.bmain = bmain;
+ data.scene = scene;
+ data.id_root = nullptr;
+ data.tag = LIB_TAG_DOIT;
+ data.missing_tag = LIB_TAG_MISSING;
+ data.is_override = false;
+ data.is_resync = true;
lib_override_group_tag_data_object_to_collection_init(&data);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -2228,10 +2402,11 @@ static void lib_override_library_main_resync_on_library_indirect_level(
continue;
}
- MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->relations_from_pointers, id);
- BLI_assert(entry != NULL);
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(bmain->relations->relations_from_pointers, id));
+ BLI_assert(entry != nullptr);
- for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != NULL;
+ for (MainIDRelationsEntryItem *entry_item = entry->to_ids; entry_item != nullptr;
entry_item = entry_item->next) {
if (entry_item->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) {
continue;
@@ -2264,13 +2439,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
BKE_main_relations_tag_set(bmain, MAINIDRELATIONS_ENTRY_TAGS_PROCESSED, false);
GHashIterator *id_roots_iter = BLI_ghashIterator_new(id_roots);
while (!BLI_ghashIterator_done(id_roots_iter)) {
- ID *id_root = BLI_ghashIterator_getKey(id_roots_iter);
- LinkNodePair *id_resync_roots = BLI_ghashIterator_getValue(id_roots_iter);
+ ID *id_root = static_cast<ID *>(BLI_ghashIterator_getKey(id_roots_iter));
+ LinkNodePair *id_resync_roots = static_cast<LinkNodePair *>(
+ BLI_ghashIterator_getValue(id_roots_iter));
CLOG_INFO(
&LOG, 2, "Checking validity of computed TODO data for root '%s'... \n", id_root->name);
- for (LinkNode *id_resync_root_iter = id_resync_roots->list; id_resync_root_iter != NULL;
+ for (LinkNode *id_resync_root_iter = id_resync_roots->list; id_resync_root_iter != nullptr;
id_resync_root_iter = id_resync_root_iter->next) {
- ID *id_resync_root = id_resync_root_iter->link;
+ ID *id_resync_root = static_cast<ID *>(id_resync_root_iter->link);
BLI_assert(id_resync_root == id_root || !BLI_ghash_haskey(id_roots, id_resync_root));
if (id_resync_root == id_root) {
BLI_assert(id_resync_root_iter == id_resync_roots->list &&
@@ -2288,13 +2464,14 @@ static void lib_override_library_main_resync_on_library_indirect_level(
BKE_main_relations_free(bmain);
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
- ListBase no_main_ids_list = {NULL};
+ ListBase no_main_ids_list = {nullptr};
GHashIterator *id_roots_iter = BLI_ghashIterator_new(id_roots);
while (!BLI_ghashIterator_done(id_roots_iter)) {
- ID *id_root = BLI_ghashIterator_getKey(id_roots_iter);
+ ID *id_root = static_cast<ID *>(BLI_ghashIterator_getKey(id_roots_iter));
Library *library = id_root->lib;
- LinkNodePair *id_resync_roots = BLI_ghashIterator_getValue(id_roots_iter);
+ LinkNodePair *id_resync_roots = static_cast<LinkNodePair *>(
+ BLI_ghashIterator_getValue(id_roots_iter));
if (ID_IS_LINKED(id_root)) {
id_root->lib->tag |= LIBRARY_TAG_RESYNC_REQUIRED;
@@ -2326,7 +2503,7 @@ static void lib_override_library_main_resync_on_library_indirect_level(
}
}
- BLI_linklist_free(id_resync_roots->list, NULL);
+ BLI_linklist_free(id_resync_roots->list, nullptr);
BLI_ghashIterator_step(id_roots_iter);
}
BLI_ghashIterator_free(id_roots_iter);
@@ -2354,10 +2531,10 @@ static void lib_override_library_main_resync_on_library_indirect_level(
}
FOREACH_MAIN_ID_END;
- BLI_ghash_free(id_roots, NULL, MEM_freeN);
+ BLI_ghash_free(id_roots, nullptr, MEM_freeN);
/* In some fairly rare (and degenerate) cases, some root ID from other liboverrides may have been
- * freed, and therefore set to NULL. Attempt to fix this as best as possible. */
+ * freed, and therefore set to nullptr. Attempt to fix this as best as possible. */
BKE_lib_override_library_main_hierarchy_root_ensure(bmain);
if (do_reports_recursive_resync_timing) {
@@ -2372,10 +2549,10 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data)
}
ID *id_owner = cb_data->id_owner;
ID *id = *cb_data->id_pointer;
- if (id != NULL && ID_IS_LINKED(id) && id->lib != id_owner->lib) {
+ if (id != nullptr && ID_IS_LINKED(id) && id->lib != id_owner->lib) {
const int owner_library_indirect_level = ID_IS_LINKED(id_owner) ? id_owner->lib->temp_index :
0;
- if (owner_library_indirect_level > 200) {
+ if (owner_library_indirect_level > 100) {
CLOG_ERROR(&LOG,
"Levels of indirect usages of libraries is way too high, there are most likely "
"dependency loops, skipping further building loops (involves at least '%s' from "
@@ -2386,6 +2563,16 @@ static int lib_override_sort_libraries_func(LibraryIDLinkCallbackData *cb_data)
id->lib->filepath);
return IDWALK_RET_NOP;
}
+ if (owner_library_indirect_level > 90) {
+ CLOG_WARN(
+ &LOG,
+ "Levels of indirect usages of libraries is suspiciously too high, there are most likely "
+ "dependency loops (involves at least '%s' from '%s' and '%s' from '%s')",
+ id_owner->name,
+ id_owner->lib->filepath,
+ id->name,
+ id->lib->filepath);
+ }
if (owner_library_indirect_level >= id->lib->temp_index) {
id->lib->temp_index = owner_library_indirect_level + 1;
@@ -2433,12 +2620,13 @@ void BKE_lib_override_library_main_resync(Main *bmain,
/* We use a specific collection to gather/store all 'orphaned' override collections and objects
* generated by re-sync-process. This avoids putting them in scene's master collection. */
#define OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME "OVERRIDE_RESYNC_LEFTOVERS"
- Collection *override_resync_residual_storage = BLI_findstring(
- &bmain->collections, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME, offsetof(ID, name) + 2);
- if (override_resync_residual_storage != NULL && ID_IS_LINKED(override_resync_residual_storage)) {
- override_resync_residual_storage = NULL;
+ Collection *override_resync_residual_storage = static_cast<Collection *>(BLI_findstring(
+ &bmain->collections, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME, offsetof(ID, name) + 2));
+ if (override_resync_residual_storage != nullptr &&
+ ID_IS_LINKED(override_resync_residual_storage)) {
+ override_resync_residual_storage = nullptr;
}
- if (override_resync_residual_storage == NULL) {
+ if (override_resync_residual_storage == nullptr) {
override_resync_residual_storage = BKE_collection_add(
bmain, scene->master_collection, OVERRIDE_RESYNC_RESIDUAL_STORAGE_NAME);
/* Hide the collection from viewport and render. */
@@ -2466,7 +2654,7 @@ void BKE_lib_override_library_main_resync(Main *bmain,
/* Essentially ensures that potentially new overrides of new objects will be instantiated. */
lib_override_library_create_post_process(
- bmain, scene, view_layer, NULL, NULL, NULL, override_resync_residual_storage, true);
+ bmain, scene, view_layer, nullptr, nullptr, nullptr, override_resync_residual_storage, true);
if (BKE_collection_is_empty(override_resync_residual_storage)) {
BKE_collection_delete(bmain, override_resync_residual_storage, true);
@@ -2489,14 +2677,15 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root)
/* Tag all library overrides in the chains of dependencies from the given root one. */
BKE_main_relations_create(bmain, 0);
- LibOverrideGroupTagData data = {.bmain = bmain,
- .scene = NULL,
- .id_root = id_root,
- .hierarchy_root_id = id_root->override_library->hierarchy_root,
- .tag = LIB_TAG_DOIT,
- .missing_tag = LIB_TAG_MISSING,
- .is_override = true,
- .is_resync = false};
+ LibOverrideGroupTagData data{};
+ data.bmain = bmain;
+ data.scene = nullptr;
+ data.id_root = id_root;
+ data.hierarchy_root_id = id_root->override_library->hierarchy_root;
+ data.tag = LIB_TAG_DOIT;
+ data.missing_tag = LIB_TAG_MISSING;
+ data.is_override = true;
+ data.is_resync = false;
lib_override_group_tag_data_object_to_collection_init(&data);
lib_override_overrides_group_tag(&data);
@@ -2538,19 +2727,19 @@ void BKE_lib_override_library_make_local(ID *id)
BKE_lib_override_library_free(&id->override_library, true);
Key *shape_key = BKE_key_from_id(id);
- if (shape_key != NULL) {
+ if (shape_key != nullptr) {
shape_key->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
if (GS(id->name) == ID_SCE) {
Collection *master_collection = ((Scene *)id)->master_collection;
- if (master_collection != NULL) {
+ if (master_collection != nullptr) {
master_collection->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
}
bNodeTree *node_tree = ntreeFromID(id);
- if (node_tree != NULL) {
+ if (node_tree != nullptr) {
node_tree->id.flag &= ~LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
}
@@ -2558,8 +2747,8 @@ void BKE_lib_override_library_make_local(ID *id)
BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_runtime_ensure(
IDOverrideLibrary *override)
{
- if (override->runtime == NULL) {
- override->runtime = MEM_callocN(sizeof(*override->runtime), __func__);
+ if (override->runtime == nullptr) {
+ override->runtime = MEM_cnew<IDOverrideLibraryRuntime>(__func__);
}
return override->runtime;
}
@@ -2568,10 +2757,13 @@ BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_runtime_ensure(
BLI_INLINE GHash *override_library_rna_path_mapping_ensure(IDOverrideLibrary *override)
{
IDOverrideLibraryRuntime *override_runtime = override_library_rna_path_runtime_ensure(override);
- if (override_runtime->rna_path_to_override_properties == NULL) {
+ if (override_runtime->rna_path_to_override_properties == nullptr) {
override_runtime->rna_path_to_override_properties = BLI_ghash_new(
BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__);
- for (IDOverrideLibraryProperty *op = override->properties.first; op != NULL; op = op->next) {
+ for (IDOverrideLibraryProperty *op =
+ static_cast<IDOverrideLibraryProperty *>(override->properties.first);
+ op != nullptr;
+ op = op->next) {
BLI_ghash_insert(override_runtime->rna_path_to_override_properties, op->rna_path, op);
}
}
@@ -2583,7 +2775,7 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_find(IDOverrideLibr
const char *rna_path)
{
GHash *override_runtime = override_library_rna_path_mapping_ensure(override);
- return BLI_ghash_lookup(override_runtime, rna_path);
+ return static_cast<IDOverrideLibraryProperty *>(BLI_ghash_lookup(override_runtime, rna_path));
}
IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibrary *override,
@@ -2592,8 +2784,8 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
{
IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path);
- if (op == NULL) {
- op = MEM_callocN(sizeof(IDOverrideLibraryProperty), __func__);
+ if (op == nullptr) {
+ op = MEM_cnew<IDOverrideLibraryProperty>(__func__);
op->rna_path = BLI_strdup(rna_path);
BLI_addtail(&override->properties, op);
@@ -2614,11 +2806,12 @@ IDOverrideLibraryProperty *BKE_lib_override_library_property_get(IDOverrideLibra
bool BKE_lib_override_rna_property_find(PointerRNA *idpoin,
const IDOverrideLibraryProperty *library_prop,
PointerRNA *r_override_poin,
- PropertyRNA **r_override_prop)
+ PropertyRNA **r_override_prop,
+ int *r_index)
{
BLI_assert(RNA_struct_is_ID(idpoin->type) && ID_IS_OVERRIDE_LIBRARY(idpoin->data));
- return RNA_path_resolve_property(
- idpoin, library_prop->rna_path, r_override_poin, r_override_prop);
+ return RNA_path_resolve_property_full(
+ idpoin, library_prop->rna_path, r_override_poin, r_override_prop, r_index);
}
void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
@@ -2627,8 +2820,9 @@ void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
op_dst->rna_path = BLI_strdup(op_src->rna_path);
BLI_duplicatelist(&op_dst->operations, &op_src->operations);
- for (IDOverrideLibraryPropertyOperation *opop_dst = op_dst->operations.first,
- *opop_src = op_src->operations.first;
+ for (IDOverrideLibraryPropertyOperation *
+ opop_dst = static_cast<IDOverrideLibraryPropertyOperation *>(op_dst->operations.first),
+ *opop_src = static_cast<IDOverrideLibraryPropertyOperation *>(op_src->operations.first);
opop_dst;
opop_dst = opop_dst->next, opop_src = opop_src->next) {
lib_override_library_property_operation_copy(opop_dst, opop_src);
@@ -2637,7 +2831,7 @@ void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst,
void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
{
- BLI_assert(op->rna_path != NULL);
+ BLI_assert(op->rna_path != nullptr);
MEM_freeN(op->rna_path);
@@ -2650,11 +2844,11 @@ void lib_override_library_property_clear(IDOverrideLibraryProperty *op)
void BKE_lib_override_library_property_delete(IDOverrideLibrary *override,
IDOverrideLibraryProperty *override_property)
{
- if (!ELEM(NULL, override->runtime, override->runtime->rna_path_to_override_properties)) {
+ if (!ELEM(nullptr, override->runtime, override->runtime->rna_path_to_override_properties)) {
BLI_ghash_remove(override->runtime->rna_path_to_override_properties,
override_property->rna_path,
- NULL,
- NULL);
+ nullptr,
+ nullptr);
}
lib_override_library_property_clear(override_property);
BLI_freelinkN(&override->properties, override_property);
@@ -2676,74 +2870,75 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
*r_strict = true;
}
- if (subitem_locname != NULL) {
- opop = BLI_findstring_ptr(&override_property->operations,
- subitem_locname,
- offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name));
+ if (subitem_locname != nullptr) {
+ opop = static_cast<IDOverrideLibraryPropertyOperation *>(
+ BLI_findstring_ptr(&override_property->operations,
+ subitem_locname,
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_local_name)));
- if (opop == NULL) {
- return NULL;
+ if (opop == nullptr) {
+ return nullptr;
}
- if (subitem_refname == NULL || opop->subitem_reference_name == NULL) {
- return subitem_refname == opop->subitem_reference_name ? opop : NULL;
+ if (subitem_refname == nullptr || opop->subitem_reference_name == nullptr) {
+ return subitem_refname == opop->subitem_reference_name ? opop : nullptr;
}
- return (subitem_refname != NULL && opop->subitem_reference_name != NULL &&
+ return (subitem_refname != nullptr && opop->subitem_reference_name != nullptr &&
STREQ(subitem_refname, opop->subitem_reference_name)) ?
opop :
- NULL;
+ nullptr;
}
- if (subitem_refname != NULL) {
- opop = BLI_findstring_ptr(
- &override_property->operations,
- subitem_refname,
- offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name));
+ if (subitem_refname != nullptr) {
+ opop = static_cast<IDOverrideLibraryPropertyOperation *>(
+ BLI_findstring_ptr(&override_property->operations,
+ subitem_refname,
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_name)));
- if (opop == NULL) {
- return NULL;
+ if (opop == nullptr) {
+ return nullptr;
}
- if (subitem_locname == NULL || opop->subitem_local_name == NULL) {
- return subitem_locname == opop->subitem_local_name ? opop : NULL;
+ if (subitem_locname == nullptr || opop->subitem_local_name == nullptr) {
+ return subitem_locname == opop->subitem_local_name ? opop : nullptr;
}
- return (subitem_locname != NULL && opop->subitem_local_name != NULL &&
+ return (subitem_locname != nullptr && opop->subitem_local_name != nullptr &&
STREQ(subitem_locname, opop->subitem_local_name)) ?
opop :
- NULL;
+ nullptr;
}
- if ((opop = BLI_listbase_bytes_find(
+ if ((opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find(
&override_property->operations,
&subitem_locindex,
sizeof(subitem_locindex),
- offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index)))) {
- return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : NULL;
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index))))) {
+ return ELEM(subitem_refindex, -1, opop->subitem_reference_index) ? opop : nullptr;
}
- if ((opop = BLI_listbase_bytes_find(
+ if ((opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find(
&override_property->operations,
&subitem_refindex,
sizeof(subitem_refindex),
- offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_index)))) {
- return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : NULL;
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_reference_index))))) {
+ return ELEM(subitem_locindex, -1, opop->subitem_local_index) ? opop : nullptr;
}
/* `index == -1` means all indices, that is a valid fallback in case we requested specific index.
*/
if (!strict && (subitem_locindex != subitem_defindex) &&
- (opop = BLI_listbase_bytes_find(
+ (opop = static_cast<IDOverrideLibraryPropertyOperation *>(BLI_listbase_bytes_find(
&override_property->operations,
&subitem_defindex,
sizeof(subitem_defindex),
- offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index)))) {
+ offsetof(IDOverrideLibraryPropertyOperation, subitem_local_index))))) {
if (r_strict) {
*r_strict = false;
}
return opop;
}
- return NULL;
+ return nullptr;
}
IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get(
@@ -2766,8 +2961,8 @@ IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_
strict,
r_strict);
- if (opop == NULL) {
- opop = MEM_callocN(sizeof(IDOverrideLibraryPropertyOperation), __func__);
+ if (opop == nullptr) {
+ opop = MEM_cnew<IDOverrideLibraryPropertyOperation>(__func__);
opop->operation = operation;
if (subitem_locname) {
opop->subitem_local_name = BLI_strdup(subitem_locname);
@@ -2821,13 +3016,13 @@ void BKE_lib_override_library_property_operation_delete(
}
bool BKE_lib_override_library_property_operation_operands_validate(
- struct IDOverrideLibraryPropertyOperation *override_property_operation,
- struct PointerRNA *ptr_dst,
- struct PointerRNA *ptr_src,
- struct PointerRNA *ptr_storage,
- struct PropertyRNA *prop_dst,
- struct PropertyRNA *prop_src,
- struct PropertyRNA *prop_storage)
+ IDOverrideLibraryPropertyOperation *override_property_operation,
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *ptr_storage,
+ PropertyRNA *prop_dst,
+ PropertyRNA *prop_src,
+ PropertyRNA *prop_storage)
{
switch (override_property_operation->operation) {
case IDOVERRIDE_LIBRARY_OP_NOOP:
@@ -2837,7 +3032,7 @@ bool BKE_lib_override_library_property_operation_operands_validate(
case IDOVERRIDE_LIBRARY_OP_SUBTRACT:
ATTR_FALLTHROUGH;
case IDOVERRIDE_LIBRARY_OP_MULTIPLY:
- if (ptr_storage == NULL || ptr_storage->data == NULL || prop_storage == NULL) {
+ if (ptr_storage == nullptr || ptr_storage->data == nullptr || prop_storage == nullptr) {
BLI_assert_msg(0, "Missing data to apply differential override operation.");
return false;
}
@@ -2847,8 +3042,8 @@ bool BKE_lib_override_library_property_operation_operands_validate(
case IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE:
ATTR_FALLTHROUGH;
case IDOVERRIDE_LIBRARY_OP_REPLACE:
- if ((ptr_dst == NULL || ptr_dst->data == NULL || prop_dst == NULL) ||
- (ptr_src == NULL || ptr_src->data == NULL || prop_src == NULL)) {
+ if ((ptr_dst == nullptr || ptr_dst->data == nullptr || prop_dst == nullptr) ||
+ (ptr_src == nullptr || ptr_src->data == nullptr || prop_src == nullptr)) {
BLI_assert_msg(0, "Missing data to apply override operation.");
return false;
}
@@ -2859,10 +3054,10 @@ bool BKE_lib_override_library_property_operation_operands_validate(
void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *reports)
{
- if (id->override_library == NULL) {
+ if (id->override_library == nullptr) {
return;
}
- if (id->override_library->reference == NULL) {
+ if (id->override_library->reference == nullptr) {
/* This is a template ID, could be linked or local, not an override. */
return;
}
@@ -2873,7 +3068,7 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *
RPT_ERROR,
"Data corruption: data-block '%s' is using itself as library override reference",
id->name);
- id->override_library->reference = NULL;
+ id->override_library->reference = nullptr;
return;
}
if (!ID_IS_LINKED(id->override_library->reference)) {
@@ -2885,7 +3080,7 @@ void BKE_lib_override_library_validate(Main *UNUSED(bmain), ID *id, ReportList *
"library override reference",
id->name,
id->override_library->reference->name);
- id->override_library->reference = NULL;
+ id->override_library->reference = nullptr;
return;
}
}
@@ -2895,7 +3090,7 @@ void BKE_lib_override_library_main_validate(Main *bmain, ReportList *reports)
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->override_library != NULL) {
+ if (id->override_library != nullptr) {
BKE_lib_override_library_validate(bmain, id, reports);
}
}
@@ -2908,7 +3103,7 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
ID *reference = local->override_library->reference;
- if (reference == NULL) {
+ if (reference == nullptr) {
/* This is an override template, local status is always OK! */
return true;
}
@@ -2922,10 +3117,10 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
Object *ob_local = (Object *)local;
if (ob_local->type == OB_ARMATURE) {
Object *ob_reference = (Object *)local->override_library->reference;
- BLI_assert(ob_local->data != NULL);
- BLI_assert(ob_reference->data != NULL);
- BKE_pose_ensure(bmain, ob_local, ob_local->data, true);
- BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true);
+ BLI_assert(ob_local->data != nullptr);
+ BLI_assert(ob_reference->data != nullptr);
+ BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
+ BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
}
}
@@ -2935,15 +3130,16 @@ bool BKE_lib_override_library_status_check_local(Main *bmain, ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(reference, &rnaptr_reference);
- if (!RNA_struct_override_matches(bmain,
- &rnaptr_local,
- &rnaptr_reference,
- NULL,
- 0,
- local->override_library,
- RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE |
- RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN,
- NULL)) {
+ if (!RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local,
+ &rnaptr_reference,
+ nullptr,
+ 0,
+ local->override_library,
+ (eRNAOverrideMatch)(RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE |
+ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN),
+ nullptr)) {
local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
return false;
}
@@ -2957,7 +3153,7 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
ID *reference = local->override_library->reference;
- if (reference == NULL) {
+ if (reference == nullptr) {
/* This is an override template, reference is virtual, so its status is always OK! */
return true;
}
@@ -2981,10 +3177,10 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
Object *ob_local = (Object *)local;
if (ob_local->type == OB_ARMATURE) {
Object *ob_reference = (Object *)local->override_library->reference;
- BLI_assert(ob_local->data != NULL);
- BLI_assert(ob_reference->data != NULL);
- BKE_pose_ensure(bmain, ob_local, ob_local->data, true);
- BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true);
+ BLI_assert(ob_local->data != nullptr);
+ BLI_assert(ob_reference->data != nullptr);
+ BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
+ BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
}
}
@@ -2995,11 +3191,11 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
if (!RNA_struct_override_matches(bmain,
&rnaptr_local,
&rnaptr_reference,
- NULL,
+ nullptr,
0,
local->override_library,
RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN,
- NULL)) {
+ nullptr)) {
local->tag &= ~LIB_TAG_OVERRIDE_LIBRARY_REFOK;
return false;
}
@@ -3010,8 +3206,8 @@ bool BKE_lib_override_library_status_check_reference(Main *bmain, ID *local)
bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
{
BLI_assert(!ID_IS_LINKED(local));
- BLI_assert(local->override_library != NULL);
- const bool is_template = (local->override_library->reference == NULL);
+ BLI_assert(local->override_library != nullptr);
+ const bool is_template = (local->override_library->reference == nullptr);
bool created = false;
if (!is_template) {
@@ -3029,10 +3225,10 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
Object *ob_local = (Object *)local;
if (ob_local->type == OB_ARMATURE) {
Object *ob_reference = (Object *)local->override_library->reference;
- BLI_assert(ob_local->data != NULL);
- BLI_assert(ob_reference->data != NULL);
- BKE_pose_ensure(bmain, ob_local, ob_local->data, true);
- BKE_pose_ensure(bmain, ob_reference, ob_reference->data, true);
+ BLI_assert(ob_local->data != nullptr);
+ BLI_assert(ob_reference->data != nullptr);
+ BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
+ BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
}
}
@@ -3040,15 +3236,16 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local)
RNA_id_pointer_create(local, &rnaptr_local);
RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference);
- eRNAOverrideMatchResult report_flags = 0;
- RNA_struct_override_matches(bmain,
- &rnaptr_local,
- &rnaptr_reference,
- NULL,
- 0,
- local->override_library,
- RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE,
- &report_flags);
+ eRNAOverrideMatchResult report_flags = (eRNAOverrideMatchResult)0;
+ RNA_struct_override_matches(
+ bmain,
+ &rnaptr_local,
+ &rnaptr_reference,
+ nullptr,
+ 0,
+ local->override_library,
+ (eRNAOverrideMatch)(RNA_OVERRIDE_COMPARE_CREATE | RNA_OVERRIDE_COMPARE_RESTORE),
+ &report_flags);
if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) {
created = true;
@@ -3074,8 +3271,9 @@ struct LibOverrideOpCreateData {
static void lib_override_library_operations_create_cb(TaskPool *__restrict pool, void *taskdata)
{
- struct LibOverrideOpCreateData *create_data = BLI_task_pool_user_data(pool);
- ID *id = taskdata;
+ LibOverrideOpCreateData *create_data = static_cast<LibOverrideOpCreateData *>(
+ BLI_task_pool_user_data(pool));
+ ID *id = static_cast<ID *>(taskdata);
if (BKE_lib_override_library_operations_create(create_data->bmain, id)) {
/* Technically no need for atomic, all jobs write the same value and we only care if one did
@@ -3104,12 +3302,14 @@ bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
* #BKE_lib_override_library_operations_create is not a problem then. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob->type == OB_ARMATURE) {
- BLI_assert(ob->data != NULL);
- BKE_pose_ensure(bmain, ob, ob->data, true);
+ BLI_assert(ob->data != nullptr);
+ BKE_pose_ensure(bmain, ob, static_cast<bArmature *>(ob->data), true);
}
}
- struct LibOverrideOpCreateData create_pool_data = {.bmain = bmain, .changed = false};
+ LibOverrideOpCreateData create_pool_data{};
+ create_pool_data.bmain = bmain;
+ create_pool_data.changed = false;
TaskPool *task_pool = BLI_task_pool_create(&create_pool_data, TASK_PRIORITY_HIGH);
FOREACH_MAIN_ID_BEGIN (bmain, id) {
@@ -3120,14 +3320,15 @@ bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool for
if (GS(id->name) == ID_OB) {
Object *ob = (Object *)id;
if (ob->type == OB_ARMATURE) {
- BLI_assert(ob->data != NULL);
- BKE_pose_ensure(bmain, ob, ob->data, true);
+ BLI_assert(ob->data != nullptr);
+ BKE_pose_ensure(bmain, ob, static_cast<bArmature *>(ob->data), true);
}
}
/* Only check overrides if we do have the real reference data available, and not some empty
* 'placeholder' for missing data (broken links). */
if ((id->override_library->reference->tag & LIB_TAG_MISSING) == 0) {
- BLI_task_pool_push(task_pool, lib_override_library_operations_create_cb, id, false, NULL);
+ BLI_task_pool_push(
+ task_pool, lib_override_library_operations_create_cb, id, false, nullptr);
}
else {
BKE_lib_override_library_properties_tag(
@@ -3198,10 +3399,10 @@ static bool lib_override_library_id_reset_do(Main *bmain,
ptr = RNA_property_pointer_get(&ptr, prop);
ptr_lib = RNA_property_pointer_get(&ptr_lib, prop_lib);
}
- if (ptr.owner_id != NULL && ptr_lib.owner_id != NULL) {
+ if (ptr.owner_id != nullptr && ptr_lib.owner_id != nullptr) {
BLI_assert(ptr.type == ptr_lib.type);
do_op_delete = !(RNA_struct_is_ID(ptr.type) &&
- ptr.owner_id->override_library != NULL &&
+ ptr.owner_id->override_library != nullptr &&
ptr.owner_id->override_library->reference == ptr_lib.owner_id);
}
}
@@ -3233,7 +3434,7 @@ void BKE_lib_override_library_id_reset(Main *bmain,
}
if (lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override)) {
- if (id_root->override_library->runtime != NULL &&
+ if (id_root->override_library->runtime != nullptr &&
(id_root->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) !=
0) {
BKE_lib_override_library_update(bmain, id_root);
@@ -3251,13 +3452,13 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain,
}
void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root);
- if (entry_vp == NULL) {
+ if (entry_vp == nullptr) {
/* This ID is not used by nor using any other ID. */
lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override);
return;
}
- MainIDRelationsEntry *entry = *entry_vp;
+ MainIDRelationsEntry *entry = static_cast<MainIDRelationsEntry *>(*entry_vp);
if (entry->tags & MAINIDRELATIONS_ENTRY_TAGS_PROCESSED) {
/* This ID has already been processed. */
return;
@@ -3269,7 +3470,7 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain,
* relationship hierarchy. */
entry->tags |= MAINIDRELATIONS_ENTRY_TAGS_PROCESSED;
- for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != NULL;
+ for (MainIDRelationsEntryItem *to_id_entry = entry->to_ids; to_id_entry != nullptr;
to_id_entry = to_id_entry->next) {
if ((to_id_entry->usage_flag & IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE) != 0) {
/* Never consider non-overridable relationships ('from', 'parents', 'owner' etc. pointers) as
@@ -3277,9 +3478,9 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain,
continue;
}
/* We only consider IDs from the same library. */
- if (*to_id_entry->id_pointer.to != NULL) {
+ if (*to_id_entry->id_pointer.to != nullptr) {
ID *to_id = *to_id_entry->id_pointer.to;
- if (to_id->override_library != NULL) {
+ if (to_id->override_library != nullptr) {
lib_override_library_id_hierarchy_recursive_reset(bmain, to_id, do_reset_system_override);
}
}
@@ -3298,7 +3499,7 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain,
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || id->override_library->runtime == NULL ||
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) || id->override_library->runtime == nullptr ||
(id->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) == 0) {
continue;
}
@@ -3308,11 +3509,11 @@ void BKE_lib_override_library_id_hierarchy_reset(Main *bmain,
FOREACH_MAIN_ID_END;
}
-void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property,
+void BKE_lib_override_library_operations_tag(IDOverrideLibraryProperty *override_property,
const short tag,
const bool do_set)
{
- if (override_property != NULL) {
+ if (override_property != nullptr) {
if (do_set) {
override_property->tag |= tag;
}
@@ -3331,18 +3532,18 @@ void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *o
}
}
-void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override,
+void BKE_lib_override_library_properties_tag(IDOverrideLibrary *override,
const short tag,
const bool do_set)
{
- if (override != NULL) {
+ if (override != nullptr) {
LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &override->properties) {
BKE_lib_override_library_operations_tag(op, tag, do_set);
}
}
}
-void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, const bool do_set)
+void BKE_lib_override_library_main_tag(Main *bmain, const short tag, const bool do_set)
{
ID *id;
@@ -3354,7 +3555,7 @@ void BKE_lib_override_library_main_tag(struct Main *bmain, const short tag, cons
FOREACH_MAIN_ID_END;
}
-void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
+void BKE_lib_override_library_id_unused_cleanup(ID *local)
{
if (ID_IS_OVERRIDE_LIBRARY_REAL(local)) {
LISTBASE_FOREACH_MUTABLE (
@@ -3373,7 +3574,7 @@ void BKE_lib_override_library_id_unused_cleanup(struct ID *local)
}
}
-void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain)
+void BKE_lib_override_library_main_unused_cleanup(Main *bmain)
{
ID *id;
@@ -3429,10 +3630,10 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
ID *tmp_id = BKE_id_copy_ex(bmain,
local->override_library->reference,
- NULL,
+ nullptr,
LIB_ID_COPY_DEFAULT | LIB_ID_COPY_NO_LIB_OVERRIDE_LOCAL_DATA_FLAG);
- if (tmp_id == NULL) {
+ if (tmp_id == nullptr) {
return;
}
@@ -3448,12 +3649,12 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
* collections' parents are fully runtime and reconstructed later. */
Key *local_key = BKE_key_from_id(local);
Key *tmp_key = BKE_key_from_id(tmp_id);
- if (local_key != NULL && tmp_key != NULL) {
+ if (local_key != nullptr && tmp_key != nullptr) {
tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
tmp_key->id.lib = local_key->id.lib;
}
- PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = NULL;
+ PointerRNA rnaptr_src, rnaptr_dst, rnaptr_storage_stack, *rnaptr_storage = nullptr;
RNA_id_pointer_create(local, &rnaptr_src);
RNA_id_pointer_create(tmp_id, &rnaptr_dst);
if (local->override_library->storage) {
@@ -3474,7 +3675,7 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
* So when we'll free tmp_id, we'll actually free old, outdated data from local. */
lib_override_id_swap(bmain, local, tmp_id);
- if (local_key != NULL && tmp_key != NULL) {
+ if (local_key != nullptr && tmp_key != nullptr) {
/* This is some kind of hard-coded 'always enforced override'. */
lib_override_id_swap(bmain, &local_key->id, &tmp_key->id);
tmp_key->id.flag |= (local_key->id.flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE);
@@ -3494,7 +3695,7 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
/* Fun times again, thanks to bone pointers in pose data of objects. We keep same ID addresses,
* but internal data has changed for sure, so we need to invalidate pose-bones caches. */
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->pose != NULL && ob->data == local) {
+ if (ob->pose != nullptr && ob->data == local) {
BLI_assert(ob->type == OB_ARMATURE);
ob->pose->flag |= POSE_RECALC;
/* We need to clear pose bone pointers immediately, some code may access those before pose
@@ -3509,7 +3710,7 @@ void BKE_lib_override_library_update(Main *bmain, ID *local)
/* XXX For until we get fully shadow copies, we still need to ensure storage releases
* its usage of any ID pointers it may have. */
BKE_id_free_ex(bmain, local->override_library->storage, LIB_ID_FREE_NO_UI_USER, true);
- local->override_library->storage = NULL;
+ local->override_library->storage = nullptr;
}
local->tag |= LIB_TAG_OVERRIDE_LIBRARY_REFOK;
@@ -3533,7 +3734,7 @@ void BKE_lib_override_library_main_update(Main *bmain)
G_MAIN = bmain;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
- if (id->override_library != NULL) {
+ if (id->override_library != nullptr) {
BKE_lib_override_library_update(bmain, id);
}
}
@@ -3542,7 +3743,7 @@ void BKE_lib_override_library_main_update(Main *bmain)
G_MAIN = orig_gmain;
}
-bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id)
+bool BKE_lib_override_library_id_is_user_deletable(Main *bmain, ID *id)
{
/* The only strong known case currently are objects used by override collections. */
/* TODO: There are most likely other cases... This may need to be addressed in a better way at
@@ -3591,11 +3792,11 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
/* This is actually purely local data with an override template, or one of those embedded IDs
* (root node trees, master collections or shape-keys) that cannot have their own override.
* Nothing to do here! */
- return NULL;
+ return nullptr;
}
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(local));
- BLI_assert(override_storage != NULL);
+ BLI_assert(override_storage != nullptr);
UNUSED_VARS_NDEBUG(override_storage);
/* Forcefully ensure we know about all needed override operations. */
@@ -3623,7 +3824,7 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
* actually a (performances) issue here, before doing it. */
storage_id = BKE_id_copy((Main *)override_storage, local);
- if (storage_id != NULL) {
+ if (storage_id != nullptr) {
PointerRNA rnaptr_reference, rnaptr_final, rnaptr_storage;
RNA_id_pointer_create(local->override_library->reference, &rnaptr_reference);
RNA_id_pointer_create(local, &rnaptr_final);
@@ -3632,11 +3833,11 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
if (!RNA_struct_override_store(
bmain, &rnaptr_final, &rnaptr_reference, &rnaptr_storage, local->override_library)) {
BKE_id_free_ex(override_storage, storage_id, LIB_ID_FREE_NO_UI_USER, true);
- storage_id = NULL;
+ storage_id = nullptr;
}
}
#else
- storage_id = NULL;
+ storage_id = nullptr;
#endif
local->override_library->storage = storage_id;
@@ -3654,7 +3855,7 @@ void BKE_lib_override_library_operations_store_end(
/* Nothing else to do here really, we need to keep all temp override storage data-blocks in
* memory until whole file is written anyway (otherwise we'd get mem pointers overlap). */
- local->override_library->storage = NULL;
+ local->override_library->storage = nullptr;
}
void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage)
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 5de8704e13b..a869bf4c4b0 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -391,8 +391,7 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner)
switch ((ID_Type)id_type_owner) {
case ID_LI:
- /* ID_LI doesn't exist as filter_id. */
- return 0;
+ return FILTER_ID_LI;
case ID_SCE:
return FILTER_ID_OB | FILTER_ID_WO | FILTER_ID_SCE | FILTER_ID_MC | FILTER_ID_MA |
FILTER_ID_GR | FILTER_ID_TXT | FILTER_ID_LS | FILTER_ID_MSK | FILTER_ID_SO |
@@ -472,6 +471,8 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner)
/* Deprecated... */
return 0;
}
+
+ BLI_assert_unreachable();
return 0;
}
@@ -693,6 +694,13 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain,
* First recursively check all its valid users, if all of them can be tagged as
* unused, then we can tag this ID as such too. */
bool has_valid_from_users = false;
+ /* Preemptively consider this ID as unused. That way if there is a loop of dependency leading
+ * back to it, it won't create a fake 'valid user' detection.
+ * NOTE: This can only only be done for a subset of IDs, some types are never 'indirectly
+ * unused', same for IDs with a fake user. */
+ if ((id->flag & LIB_FAKEUSER) == 0 && !ELEM(GS(id->name), ID_SCE, ID_WM, ID_SCR, ID_WS, ID_LI)) {
+ id->tag |= tag;
+ }
for (MainIDRelationsEntryItem *id_from_item = id_relations->from_ids; id_from_item != NULL;
id_from_item = id_from_item->next) {
if ((id_from_item->usage_flag & ignored_usages) != 0 ||
@@ -715,7 +723,11 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain,
break;
}
}
- if (!has_valid_from_users) {
+ if (has_valid_from_users) {
+ /* This ID has 'valid' users, clear the 'tag as unused' preemptively set above. */
+ id->tag &= ~tag;
+ }
+ else {
/* This ID has no 'valid' users, tag it as unused. */
id->tag |= tag;
if (r_num_tagged != NULL) {
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 2600a40153c..28b0337d9a2 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -428,10 +428,13 @@ static void libblock_remap_data_update_tags(ID *old_id, ID *new_id, void *user_d
}
static void libblock_remap_reset_remapping_status_callback(ID *old_id,
- ID *UNUSED(new_id),
+ ID *new_id,
void *UNUSED(user_data))
{
BKE_libblock_runtime_reset_remapping_status(old_id);
+ if (new_id != NULL) {
+ BKE_libblock_runtime_reset_remapping_status(new_id);
+ }
}
/**
@@ -454,7 +457,7 @@ static void libblock_remap_reset_remapping_status_callback(ID *old_id,
* \param old_id: the data-block to dereference (may be NULL if \a id is non-NULL).
* \param new_id: the new data-block to replace \a old_id references with (may be NULL).
* \param r_id_remap_data: if non-NULL, the IDRemap struct to use
- * (uselful to retrieve info about remapping process).
+ * (useful to retrieve info about remapping process).
*/
ATTR_NONNULL(1)
static void libblock_remap_data(Main *bmain,
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 03a17b2ecc5..fee4cae2701 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -26,14 +26,26 @@
#include "BKE_lib_query.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_main_namemap.h"
#include "BKE_packedFile.h"
/* Unused currently. */
// static CLG_LogRef LOG = {.identifier = "bke.library"};
+struct BlendWriter;
+struct BlendDataReader;
+
+static void library_runtime_reset(Library *lib)
+{
+ if (lib->runtime.name_map) {
+ BKE_main_namemap_destroy(&lib->runtime.name_map);
+ }
+}
+
static void library_free_data(ID *id)
{
Library *library = (Library *)id;
+ library_runtime_reset(library);
if (library->packedfile) {
BKE_packedfile_free(library->packedfile);
}
@@ -61,9 +73,23 @@ static void library_foreach_path(ID *id, BPathForeachPathData *bpath_data)
}
}
+static void library_blend_write(struct BlendWriter *UNUSED(writer),
+ ID *id,
+ const void *UNUSED(id_address))
+{
+ Library *lib = (Library *)id;
+ library_runtime_reset(lib);
+}
+
+static void library_blend_read_data(struct BlendDataReader *UNUSED(reader), ID *id)
+{
+ Library *lib = (Library *)id;
+ library_runtime_reset(lib);
+}
+
IDTypeInfo IDType_ID_LI = {
.id_code = ID_LI,
- .id_filter = 0,
+ .id_filter = FILTER_ID_LI,
.main_listbase_index = INDEX_ID_LI,
.struct_size = sizeof(Library),
.name = "Library",
@@ -81,8 +107,8 @@ IDTypeInfo IDType_ID_LI = {
.foreach_path = library_foreach_path,
.owner_get = NULL,
- .blend_write = NULL,
- .blend_read_data = NULL,
+ .blend_write = library_blend_write,
+ .blend_read_data = library_blend_read_data,
.blend_read_lib = NULL,
.blend_read_expand = NULL,
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index c0eb1955fdf..12a661d139b 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -55,7 +55,7 @@ static void linestyle_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const
FreestyleLineStyle *linestyle_dst = (FreestyleLineStyle *)id_dst;
const FreestyleLineStyle *linestyle_src = (const FreestyleLineStyle *)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;
/* We always need allocation of our private ID data. */
const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c
index b9ed783fa8c..239aacf28d6 100644
--- a/source/blender/blenkernel/intern/main.c
+++ b/source/blender/blenkernel/intern/main.c
@@ -24,6 +24,7 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_main_idmap.h"
+#include "BKE_main_namemap.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -184,6 +185,10 @@ void BKE_main_free(Main *mainvar)
BKE_main_idmap_destroy(mainvar->id_map);
}
+ if (mainvar->name_map) {
+ BKE_main_namemap_destroy(&mainvar->name_map);
+ }
+
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
MEM_freeN(mainvar);
diff --git a/source/blender/blenkernel/intern/main_namemap.cc b/source/blender/blenkernel/intern/main_namemap.cc
new file mode 100644
index 00000000000..3cbd33057a8
--- /dev/null
+++ b/source/blender/blenkernel/intern/main_namemap.cc
@@ -0,0 +1,361 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_idtype.h"
+#include "BKE_main.h"
+#include "BKE_main_namemap.h"
+
+#include "BLI_assert.h"
+#include "BLI_bitmap.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_map.hh"
+#include "BLI_math_base.hh"
+#include "BLI_set.hh"
+#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
+
+#include "DNA_ID.h"
+
+#include "MEM_guardedalloc.h"
+
+//#define DEBUG_PRINT_MEMORY_USAGE
+
+using namespace blender;
+
+/* Assumes and ensure that the suffix number can never go beyond 1 billion. */
+#define MAX_NUMBER 1000000000
+/* We do not want to get "name.000", so minimal number is 1. */
+#define MIN_NUMBER 1
+
+/**
+ * Helper building final ID name from given base_name and number.
+ *
+ * If everything goes well and we do generate a valid final ID name in given name, we return
+ * true. In case the final name would overflow the allowed ID name length, or given number is
+ * bigger than maximum allowed value, we truncate further the base_name (and given name, which is
+ * assumed to have the same 'base_name' part), and return false.
+ */
+static bool id_name_final_build(char *name, char *base_name, size_t base_name_len, int number)
+{
+ char number_str[11]; /* Dot + nine digits + NULL terminator. */
+ size_t number_str_len = BLI_snprintf_rlen(number_str, ARRAY_SIZE(number_str), ".%.3d", number);
+
+ /* If the number would lead to an overflow of the maximum ID name length, we need to truncate
+ * the base name part and do all the number checks again. */
+ if (base_name_len + number_str_len >= MAX_NAME || number >= MAX_NUMBER) {
+ if (base_name_len + number_str_len >= MAX_NAME) {
+ base_name_len = MAX_NAME - number_str_len - 1;
+ }
+ else {
+ base_name_len--;
+ }
+ base_name[base_name_len] = '\0';
+
+ /* Code above may have generated invalid utf-8 string, due to raw truncation.
+ * Ensure we get a valid one now. */
+ base_name_len -= (size_t)BLI_str_utf8_invalid_strip(base_name, base_name_len);
+
+ /* Also truncate orig name, and start the whole check again. */
+ name[base_name_len] = '\0';
+ return false;
+ }
+
+ /* We have our final number, we can put it in name and exit the function. */
+ BLI_strncpy(name + base_name_len, number_str, number_str_len + 1);
+ return true;
+}
+
+/* Key used in set/map lookups: just a string name. */
+struct UniqueName_Key {
+ char name[MAX_NAME];
+ uint64_t hash() const
+ {
+ return BLI_ghashutil_strhash_n(name, MAX_NAME);
+ }
+ bool operator==(const UniqueName_Key &o) const
+ {
+ return !BLI_ghashutil_strcmp(name, o.name);
+ }
+};
+
+/* Tracking of used numeric suffixes. For each base name:
+ *
+ * - Exactly track which of the lowest 1024 suffixes are in use,
+ * whenever there is a name collision we pick the lowest "unused"
+ * one. This is done with a bit map.
+ * - Above 1024, do not track them exactly, just track the maximum
+ * suffix value seen so far. Upon collision, assign number that is
+ * one larger.
+ */
+struct UniqueName_Value {
+ static constexpr unsigned max_exact_tracking = 1024;
+ BLI_BITMAP_DECLARE(mask, max_exact_tracking);
+ int max_value = 0;
+
+ void mark_used(int number)
+ {
+ if (number >= 0 && number < max_exact_tracking) {
+ BLI_BITMAP_ENABLE(mask, number);
+ }
+ if (number < MAX_NUMBER) {
+ math::max_inplace(max_value, number);
+ }
+ }
+
+ void mark_unused(int number)
+ {
+ if (number >= 0 && number < max_exact_tracking) {
+ BLI_BITMAP_DISABLE(mask, number);
+ }
+ if (number > 0 && number == max_value) {
+ --max_value;
+ }
+ }
+
+ bool use_if_unused(int number)
+ {
+ if (number >= 0 && number < max_exact_tracking) {
+ if (!BLI_BITMAP_TEST_BOOL(mask, number)) {
+ BLI_BITMAP_ENABLE(mask, number);
+ math::max_inplace(max_value, number);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int use_smallest_unused()
+ {
+ /* Find the smallest available one <1k.
+ * However we never want to pick zero ("none") suffix, even if it is
+ * available, e.g. if Foo.001 was used and we want to create another
+ * Foo.001, we should return Foo.002 and not Foo.
+ * So while searching, mark #0 as "used" to make sure we don't find it,
+ * and restore the value afterwards. */
+
+ BLI_bitmap prev_first = mask[0];
+ mask[0] |= 1;
+ int result = BLI_bitmap_find_first_unset(mask, max_exact_tracking);
+ if (result >= 0) {
+ BLI_BITMAP_ENABLE(mask, result);
+ math::max_inplace(max_value, result);
+ }
+ mask[0] |= prev_first & 1; /* Restore previous value of #0 bit. */
+ return result;
+ }
+};
+
+/* Tracking of names for a single ID type. */
+struct UniqueName_TypeMap {
+ /* Set of full names that are in use. */
+ Set<UniqueName_Key> full_names;
+ /* For each base name (i.e. without numeric suffix), track the
+ * numeric suffixes that are in use. */
+ Map<UniqueName_Key, UniqueName_Value> base_name_to_num_suffix;
+};
+
+struct UniqueName_Map {
+ UniqueName_TypeMap type_maps[INDEX_ID_MAX];
+
+ UniqueName_TypeMap *find_by_type(short id_type)
+ {
+ int index = BKE_idtype_idcode_to_index(id_type);
+ return index >= 0 ? &type_maps[index] : nullptr;
+ }
+};
+
+struct UniqueName_Map *BKE_main_namemap_create()
+{
+ struct UniqueName_Map *map = MEM_new<UniqueName_Map>(__func__);
+ return map;
+}
+
+void BKE_main_namemap_destroy(struct UniqueName_Map **r_name_map)
+{
+#ifdef DEBUG_PRINT_MEMORY_USAGE
+ int64_t size_sets = 0;
+ int64_t size_maps = 0;
+ for (const UniqueName_TypeMap &type_map : (*r_name_map)->type_maps) {
+ size_sets += type_map.full_names.size_in_bytes();
+ size_maps += type_map.base_name_to_num_suffix.size_in_bytes();
+ }
+ printf(
+ "NameMap memory usage: sets %.1fKB, maps %.1fKB\n", size_sets / 1024.0, size_maps / 1024.0);
+#endif
+ MEM_delete<UniqueName_Map>(*r_name_map);
+ *r_name_map = nullptr;
+}
+
+static void main_namemap_populate(UniqueName_Map *name_map, struct Main *bmain, ID *ignore_id)
+{
+ BLI_assert_msg(name_map != nullptr, "name_map should not be null");
+ for (UniqueName_TypeMap &type_map : name_map->type_maps) {
+ type_map.base_name_to_num_suffix.clear();
+ }
+ Library *library = ignore_id->lib;
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ if ((id == ignore_id) || (id->lib != library)) {
+ continue;
+ }
+ UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id->name));
+ BLI_assert(type_map != nullptr);
+
+ /* Insert the full name into the set. */
+ UniqueName_Key key;
+ BLI_strncpy(key.name, id->name + 2, MAX_NAME);
+ type_map->full_names.add(key);
+
+ /* Get the name and number parts ("name.number"). */
+ int number = MIN_NUMBER;
+ BLI_split_name_num(key.name, &number, id->name + 2, '.');
+
+ /* Get and update the entry for this base name. */
+ UniqueName_Value &val = type_map->base_name_to_num_suffix.lookup_or_add_default(key);
+ val.mark_used(number);
+ }
+ FOREACH_MAIN_ID_END;
+}
+
+/* Get the name map object used for the given Main/ID.
+ * Lazily creates and populates the contents of the name map, if ensure_created is true.
+ * Note: if the contents are populated, the name of the given ID itself is not added. */
+static UniqueName_Map *get_namemap_for(Main *bmain, ID *id, bool ensure_created)
+{
+ if (id->lib != nullptr) {
+ if (ensure_created && id->lib->runtime.name_map == nullptr) {
+ id->lib->runtime.name_map = BKE_main_namemap_create();
+ main_namemap_populate(id->lib->runtime.name_map, bmain, id);
+ }
+ return id->lib->runtime.name_map;
+ }
+ if (ensure_created && bmain->name_map == nullptr) {
+ bmain->name_map = BKE_main_namemap_create();
+ main_namemap_populate(bmain->name_map, bmain, id);
+ }
+ return bmain->name_map;
+}
+
+bool BKE_main_namemap_get_name(struct Main *bmain, struct ID *id, char *name)
+{
+ BLI_assert(bmain != nullptr);
+ BLI_assert(id != nullptr);
+ UniqueName_Map *name_map = get_namemap_for(bmain, id, true);
+ BLI_assert(name_map != nullptr);
+ BLI_assert(strlen(name) < MAX_NAME);
+ UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id->name));
+ BLI_assert(type_map != nullptr);
+
+ bool is_name_changed = false;
+
+ UniqueName_Key key;
+ while (true) {
+ /* Check if the full original name has a duplicate. */
+ BLI_strncpy(key.name, name, MAX_NAME);
+ const bool has_dup = type_map->full_names.contains(key);
+
+ /* Get the name and number parts ("name.number"). */
+ int number = MIN_NUMBER;
+ size_t base_name_len = BLI_split_name_num(key.name, &number, name, '.');
+
+ bool added_new = false;
+ UniqueName_Value &val = type_map->base_name_to_num_suffix.lookup_or_add_cb(key, [&]() {
+ added_new = true;
+ return UniqueName_Value();
+ });
+ if (added_new || !has_dup) {
+ /* This base name is not used at all yet, or the full original
+ * name has no duplicates. The latter could happen if splitting
+ * by number would produce the same values, for different name
+ * strings (e.g. Foo.001 and Foo.1). */
+ val.mark_used(number);
+
+ if (!has_dup) {
+ BLI_strncpy(key.name, name, MAX_NAME);
+ type_map->full_names.add(key);
+ }
+ return is_name_changed;
+ }
+
+ /* The base name is already used. But our number suffix might not be used yet. */
+ int number_to_use = -1;
+ if (val.use_if_unused(number)) {
+ /* Our particular number suffix is not used yet: use it. */
+ number_to_use = number;
+ }
+ else {
+ /* Find lowest free under 1k and use it. */
+ number_to_use = val.use_smallest_unused();
+
+ /* Did not find one under 1k. */
+ if (number_to_use == -1) {
+ if (number >= MIN_NUMBER && number > val.max_value) {
+ val.max_value = number;
+ number_to_use = number;
+ }
+ else {
+ val.max_value++;
+ number_to_use = val.max_value;
+ }
+ }
+ }
+
+ /* Try to build final name from the current base name and the number.
+ * Note that this can fail due to too long base name, or a too large number,
+ * in which case it will shorten the base name, and we'll start again. */
+ BLI_assert(number_to_use >= MIN_NUMBER);
+ if (id_name_final_build(name, key.name, base_name_len, number_to_use)) {
+ /* All good, add final name to the set. */
+ BLI_strncpy(key.name, name, MAX_NAME);
+ type_map->full_names.add(key);
+ break;
+ }
+
+ /* Name had to be truncated, or number too large: mark
+ * the output name as definitely changed, and proceed with the
+ * truncated name again. */
+ is_name_changed = true;
+ }
+ return is_name_changed;
+}
+
+void BKE_main_namemap_remove_name(struct Main *bmain, struct ID *id, const char *name)
+{
+ BLI_assert(bmain != nullptr);
+ BLI_assert(id != nullptr);
+ BLI_assert(name != nullptr);
+ /* Name is empty or not initialized yet, nothing to remove. */
+ if (name[0] == '\0') {
+ return;
+ }
+
+ struct UniqueName_Map *name_map = get_namemap_for(bmain, id, false);
+ if (name_map == nullptr) {
+ return;
+ }
+ BLI_assert(strlen(name) < MAX_NAME);
+ UniqueName_TypeMap *type_map = name_map->find_by_type(GS(id->name));
+ BLI_assert(type_map != nullptr);
+
+ UniqueName_Key key;
+ /* Remove full name from the set. */
+ BLI_strncpy(key.name, name, MAX_NAME);
+ type_map->full_names.remove(key);
+
+ int number = MIN_NUMBER;
+ BLI_split_name_num(key.name, &number, name, '.');
+ UniqueName_Value *val = type_map->base_name_to_num_suffix.lookup_ptr(key);
+ if (val == nullptr) {
+ return;
+ }
+ if (number == 0 && val->max_value == 0) {
+ /* This was the only base name usage, remove whole key. */
+ type_map->base_name_to_num_suffix.remove(key);
+ return;
+ }
+ val->mark_unused(number);
+}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index e5b875cadf9..f899901b54e 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -954,7 +954,8 @@ void BKE_id_material_assign(Main *bmain, ID *id, Material *ma, short act)
BKE_objects_materials_test_all(bmain, id);
}
-void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
+static void object_material_assign(
+ Main *bmain, Object *ob, Material *ma, short act, int assign_type, bool do_test_all)
{
Material *mao, **matar, ***matarar;
short *totcolp;
@@ -1037,7 +1038,10 @@ void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act
id_us_min(&mao->id);
}
(*matarar)[act - 1] = ma;
- BKE_objects_materials_test_all(bmain, ob->data); /* Data may be used by several objects... */
+ /* Data may be used by several objects. */
+ if (do_test_all) {
+ BKE_objects_materials_test_all(bmain, ob->data);
+ }
}
if (ma) {
@@ -1045,6 +1049,19 @@ void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act
}
}
+void BKE_object_material_assign(Main *bmain, Object *ob, Material *ma, short act, int assign_type)
+{
+ object_material_assign(bmain, ob, ma, act, assign_type, true);
+}
+
+void BKE_object_material_assign_single_obdata(struct Main *bmain,
+ struct Object *ob,
+ struct Material *ma,
+ short act)
+{
+ object_material_assign(bmain, ob, ma, act, BKE_MAT_ASSIGN_OBDATA, false);
+}
+
void BKE_object_material_remap(Object *ob, const unsigned int *remap)
{
Material ***matar = BKE_object_material_array_p(ob);
@@ -1448,7 +1465,7 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
slot->attribute_name = storage->name;
if (storage->type == SHD_ATTRIBUTE_GEOMETRY) {
const Mesh *mesh = (const Mesh *)fill_data->ob->data;
- CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
+ const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name);
slot->valid = layer != NULL;
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 1340e53f06e..2a1c940493c 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -347,7 +347,7 @@ float *BKE_mball_make_orco(Object *ob, ListBase *dispbase)
return orcodata;
}
-bool BKE_mball_is_basis(Object *ob)
+bool BKE_mball_is_basis(const Object *ob)
{
/* Meta-Ball Basis Notes from Blender-2.5x
* =======================================
@@ -370,7 +370,7 @@ bool BKE_mball_is_basis(Object *ob)
return (!isdigit(ob->id.name[len - 1]));
}
-bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
+bool BKE_mball_is_same_group(const Object *ob1, const Object *ob2)
{
int basis1nr, basis2nr;
char basis1name[MAX_ID_NAME], basis2name[MAX_ID_NAME];
@@ -383,11 +383,12 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.');
BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.');
- if (STREQ(basis1name, basis2name)) {
- return BKE_mball_is_basis(ob1);
- }
+ return STREQ(basis1name, basis2name);
+}
- return false;
+bool BKE_mball_is_basis_for(const Object *ob1, const Object *ob2)
+{
+ return BKE_mball_is_same_group(ob1, ob2) && BKE_mball_is_basis(ob1);
}
bool BKE_mball_is_any_selected(const MetaBall *mb)
@@ -422,41 +423,85 @@ bool BKE_mball_is_any_unselected(const MetaBall *mb)
return false;
}
-void BKE_mball_properties_copy(Scene *scene, Object *active_object)
+static void mball_data_properties_copy(MetaBall *mb_dst, MetaBall *mb_src)
{
- Scene *sce_iter = scene;
- Base *base;
- Object *ob;
- MetaBall *active_mball = (MetaBall *)active_object->data;
- int basisnr, obnr;
- char basisname[MAX_ID_NAME], obname[MAX_ID_NAME];
- SceneBaseIter iter;
-
- BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
-
- /* Pass depsgraph as NULL, which means we will not expand into
- * duplis unlike when we generate the meta-ball. Expanding duplis
- * would not be compatible when editing multiple view layers. */
- BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 0, NULL, NULL);
- while (BKE_scene_base_iter_next(NULL, &iter, &sce_iter, 1, &base, &ob)) {
- if (ob->type == OB_MBALL) {
- if (ob != active_object) {
- BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
-
- /* Object ob has to be in same "group" ... it means, that it has to have
- * same base of its name */
- if (STREQ(obname, basisname)) {
- MetaBall *mb = ob->data;
-
- /* Copy properties from selected/edited metaball */
- mb->wiresize = active_mball->wiresize;
- mb->rendersize = active_mball->rendersize;
- mb->thresh = active_mball->thresh;
- mb->flag = active_mball->flag;
- DEG_id_tag_update(&mb->id, 0);
- }
+ mb_dst->wiresize = mb_src->wiresize;
+ mb_dst->rendersize = mb_src->rendersize;
+ mb_dst->thresh = mb_src->thresh;
+ mb_dst->flag = mb_src->flag;
+ DEG_id_tag_update(&mb_dst->id, 0);
+}
+
+void BKE_mball_properties_copy(Main *bmain, MetaBall *metaball_src)
+{
+ /**
+ * WARNING: This code does not cover all potential corner-cases. E.g. if:
+ * <pre>
+ * | Object | ObData |
+ * | ---------- | ---------- |
+ * | Meta_A | Meta_A |
+ * | Meta_A.001 | Meta_A.001 |
+ * | Meta_B | Meta_A |
+ * | Meta_B.001 | Meta_B.001 |
+ * </pre>
+ *
+ * Calling this function with `metaball_src` being `Meta_A.001` will update `Meta_A`, but NOT
+ * `Meta_B.001`. So in the 'Meta_B' family, the two metaballs will have unmatching settings now.
+ *
+ * Solving this case would drastically increase the complexity of this code though, so don't
+ * think it would be worth it.
+ */
+ for (Object *ob_src = bmain->objects.first; ob_src != NULL && !ID_IS_LINKED(ob_src);) {
+ if (ob_src->data != metaball_src) {
+ ob_src = ob_src->id.next;
+ continue;
+ }
+
+ /* In this code we take advantage of two facts:
+ * - MetaBalls of the same family have the same basis name,
+ * - IDs are sorted by name in their Main listbase.
+ * So, all MetaBall objects of the same family are contiguous in bmain list (potentially mixed
+ * with non-meta-ball objects with same basis names).
+ *
+ * Using this, it is possible to process the whole set of meta-balls with a single loop on the
+ * whole list of Objects, though additionally going backward on part of the list in some cases.
+ */
+ Object *ob_iter = NULL;
+ int obactive_nr, ob_nr;
+ char obactive_name[MAX_ID_NAME], ob_name[MAX_ID_NAME];
+ BLI_split_name_num(obactive_name, &obactive_nr, ob_src->id.name + 2, '.');
+
+ for (ob_iter = ob_src->id.prev; ob_iter != NULL; ob_iter = ob_iter->id.prev) {
+ if (ob_iter->id.name[2] != obactive_name[0]) {
+ break;
+ }
+ if (ob_iter->type != OB_MBALL || ob_iter->data == metaball_src) {
+ continue;
+ }
+ BLI_split_name_num(ob_name, &ob_nr, ob_iter->id.name + 2, '.');
+ if (!STREQ(obactive_name, ob_name)) {
+ break;
+ }
+
+ mball_data_properties_copy(ob_iter->data, metaball_src);
+ }
+
+ for (ob_iter = ob_src->id.next; ob_iter != NULL; ob_iter = ob_iter->id.next) {
+ if (ob_iter->id.name[2] != obactive_name[0] || ID_IS_LINKED(ob_iter)) {
+ break;
+ }
+ if (ob_iter->type != OB_MBALL || ob_iter->data == metaball_src) {
+ continue;
}
+ BLI_split_name_num(ob_name, &ob_nr, ob_iter->id.name + 2, '.');
+ if (!STREQ(obactive_name, ob_name)) {
+ break;
+ }
+
+ mball_data_properties_copy(ob_iter->data, metaball_src);
}
+
+ ob_src = ob_iter;
}
}
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 05baf156099..cf05dc0404e 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -31,6 +31,7 @@
#include "BLI_string.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -46,6 +47,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
@@ -60,6 +62,7 @@
#include "BLO_read_write.h"
using blender::float3;
+using blender::Vector;
static void mesh_clear_geometry(Mesh *mesh);
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata);
@@ -114,7 +117,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
CustomData_MeshMasks mask = CD_MASK_MESH;
if (mesh_src->id.tag & LIB_TAG_NO_MAIN) {
- /* For copies in depsgraph, keep data like origindex and orco. */
+ /* For copies in depsgraph, keep data like #CD_ORIGINDEX and #CD_ORCO. */
CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH);
}
@@ -208,46 +211,40 @@ 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 = 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];
+ Vector<CustomDataLayer, 16> vert_layers;
+ Vector<CustomDataLayer, 16> edge_layers;
+ Vector<CustomDataLayer, 16> loop_layers;
+ Vector<CustomDataLayer, 16> poly_layers;
/* cache only - don't write */
mesh->mface = nullptr;
mesh->totface = 0;
memset(&mesh->fdata, 0, sizeof(mesh->fdata));
mesh->runtime = blender::dna::shallow_zero_initialize();
- flayers = flayers_buff;
/* Do not store actual geometry data in case this is a library override ID. */
if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
mesh->mvert = nullptr;
mesh->totvert = 0;
memset(&mesh->vdata, 0, sizeof(mesh->vdata));
- vlayers = vlayers_buff;
mesh->medge = nullptr;
mesh->totedge = 0;
memset(&mesh->edata, 0, sizeof(mesh->edata));
- elayers = elayers_buff;
mesh->mloop = nullptr;
mesh->totloop = 0;
memset(&mesh->ldata, 0, sizeof(mesh->ldata));
- llayers = llayers_buff;
mesh->mpoly = nullptr;
mesh->totpoly = 0;
memset(&mesh->pdata, 0, sizeof(mesh->pdata));
- players = players_buff;
}
else {
- CustomData_blend_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff));
- CustomData_blend_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff));
- CustomData_blend_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff));
- CustomData_blend_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+ CustomData_blend_write_prepare(mesh->vdata, vert_layers);
+ CustomData_blend_write_prepare(mesh->edata, edge_layers);
+ CustomData_blend_write_prepare(mesh->ldata, loop_layers);
+ CustomData_blend_write_prepare(mesh->pdata, poly_layers);
}
BLO_write_id_struct(writer, Mesh, id_address, &mesh->id);
@@ -264,33 +261,15 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
BLO_write_raw(writer, sizeof(MSelect) * mesh->totselect, mesh->mselect);
CustomData_blend_write(
- writer, &mesh->vdata, vlayers, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id);
+ writer, &mesh->vdata, vert_layers, mesh->totvert, CD_MASK_MESH.vmask, &mesh->id);
CustomData_blend_write(
- writer, &mesh->edata, elayers, mesh->totedge, CD_MASK_MESH.emask, &mesh->id);
+ writer, &mesh->edata, edge_layers, mesh->totedge, CD_MASK_MESH.emask, &mesh->id);
/* fdata is really a dummy - written so slots align */
+ CustomData_blend_write(writer, &mesh->fdata, {}, mesh->totface, CD_MASK_MESH.fmask, &mesh->id);
CustomData_blend_write(
- writer, &mesh->fdata, flayers, mesh->totface, CD_MASK_MESH.fmask, &mesh->id);
+ writer, &mesh->ldata, loop_layers, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id);
CustomData_blend_write(
- writer, &mesh->ldata, llayers, mesh->totloop, CD_MASK_MESH.lmask, &mesh->id);
- CustomData_blend_write(
- writer, &mesh->pdata, players, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id);
-
- /* Free temporary data */
-
- /* Free custom-data layers, when not assigned a buffer value. */
-#define CD_LAYERS_FREE(id) \
- if (id && id != id##_buff) { \
- MEM_freeN(id); \
- } \
- ((void)0)
-
- CD_LAYERS_FREE(vlayers);
- CD_LAYERS_FREE(elayers);
- // CD_LAYER_FREE(flayers); /* Never allocated. */
- CD_LAYERS_FREE(llayers);
- CD_LAYERS_FREE(players);
-
-#undef CD_LAYERS_FREE
+ writer, &mesh->pdata, poly_layers, mesh->totpoly, CD_MASK_MESH.pmask, &mesh->id);
}
static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
@@ -777,7 +756,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me)
if (tottex_tessface != tottex_original || totcol_tessface != totcol_original) {
BKE_mesh_tessface_clear(me);
- CustomData_from_bmeshpoly(&me->fdata, &me->ldata, me->totface);
+ BKE_mesh_add_mface_layers(&me->fdata, &me->ldata, me->totface);
/* TODO: add some `--debug-mesh` option. */
if (G.debug & G_DEBUG) {
@@ -1211,6 +1190,11 @@ static void ensure_orig_index_layer(CustomData &data, const int size)
void BKE_mesh_ensure_default_orig_index_customdata(Mesh *mesh)
{
BLI_assert(mesh->runtime.wrapper_type == ME_WRAPPER_TYPE_MDATA);
+ BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh);
+}
+
+void BKE_mesh_ensure_default_orig_index_customdata_no_check(Mesh *mesh)
+{
ensure_orig_index_layer(mesh->vdata, mesh->totvert);
ensure_orig_index_layer(mesh->edata, mesh->totedge);
ensure_orig_index_layer(mesh->pdata, mesh->totpoly);
@@ -1374,74 +1358,6 @@ void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh)
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 */
- if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) {
- mface->v4 = 0;
- nr--;
- }
- if ((mface->v2 || mface->v4) && mface->v2 == mface->v3) {
- mface->v3 = mface->v4;
- mface->v4 = 0;
- nr--;
- }
- if (mface->v1 == mface->v2) {
- mface->v2 = mface->v3;
- mface->v3 = mface->v4;
- mface->v4 = 0;
- nr--;
- }
-
- /* Check corrupt cases, bow-tie geometry,
- * can't handle these because edge data won't exist so just return 0. */
- if (nr == 3) {
- if (
- /* real edges */
- mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v1) {
- return 0;
- }
- }
- else if (nr == 4) {
- if (
- /* real edges */
- mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v4 ||
- mface->v4 == mface->v1 ||
- /* across the face */
- mface->v1 == mface->v3 || mface->v2 == mface->v4) {
- return 0;
- }
- }
-
- /* prevent a zero at wrong index location */
- if (nr == 3) {
- if (mface->v3 == 0) {
- static int corner_indices[4] = {1, 2, 0, 3};
-
- SWAP(uint, mface->v1, mface->v2);
- SWAP(uint, mface->v2, mface->v3);
-
- if (fdata) {
- CustomData_swap_corners(fdata, mfindex, corner_indices);
- }
- }
- }
- else if (nr == 4) {
- if (mface->v3 == 0 || mface->v4 == 0) {
- static int corner_indices[4] = {2, 3, 0, 1};
-
- SWAP(uint, mface->v1, mface->v3);
- SWAP(uint, mface->v2, mface->v4);
-
- if (fdata) {
- CustomData_swap_corners(fdata, mfindex, corner_indices);
- }
- }
- }
-
- return nr;
-}
-
Mesh *BKE_mesh_from_object(Object *ob)
{
if (ob == nullptr) {
@@ -1706,7 +1622,7 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
mul_m3_v3(m3, *lnors);
}
}
- BKE_mesh_normals_tag_dirty(me);
+ BKE_mesh_tag_coords_changed(me);
}
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
@@ -1728,13 +1644,7 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
}
}
}
-}
-
-void BKE_mesh_tessface_ensure(Mesh *mesh)
-{
- if (mesh->totpoly && mesh->totface == 0) {
- BKE_mesh_tessface_calc(mesh);
- }
+ BKE_mesh_tag_coords_changed_uniformly(me);
}
void BKE_mesh_tessface_clear(Mesh *mesh)
@@ -1926,7 +1836,7 @@ void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3])
for (int i = 0; i < mesh->totvert; i++, mv++) {
copy_v3_v3(mv->co, vert_coords[i]);
}
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_tag_coords_changed(mesh);
}
void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
@@ -1940,12 +1850,28 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
for (int i = 0; i < mesh->totvert; i++, mv++) {
mul_v3_m4v3(mv->co, mat, vert_coords[i]);
}
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_tag_coords_changed(mesh);
}
-void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
+static float (*ensure_corner_normal_layer(Mesh &mesh))[3]
{
float(*r_loopnors)[3];
+ if (CustomData_has_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 = (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);
+ }
+ return r_loopnors;
+}
+
+void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
+ MLoopNorSpaceArray *r_lnors_spacearr,
+ float (*r_corner_normals)[3])
+{
short(*clnors)[2] = nullptr;
/* Note that we enforce computing clnors when the clnor space array is requested by caller here.
@@ -1955,16 +1881,6 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
((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 = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL);
- memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
- }
- else {
- 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 nullptr */
clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
@@ -1974,7 +1890,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
mesh->medge,
mesh->totedge,
mesh->mloop,
- r_loopnors,
+ r_corner_normals,
mesh->totloop,
mesh->mpoly,
BKE_mesh_poly_normals_ensure(mesh),
@@ -1990,7 +1906,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
void BKE_mesh_calc_normals_split(Mesh *mesh)
{
- BKE_mesh_calc_normals_split_ex(mesh, nullptr);
+ BKE_mesh_calc_normals_split_ex(mesh, nullptr, ensure_corner_normal_layer(*mesh));
}
/* Split faces helper functions. */
@@ -2209,7 +2125,7 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
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);
+ BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr, ensure_corner_normal_layer(*mesh));
/* Stealing memarena from loop normals space array. */
MemArena *memarena = lnors_spacearr.mem;
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 14bd6aa5b2f..a1ef2d2e6b5 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -791,7 +791,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
Span<Array<short>> material_remaps,
const bool use_self,
const bool hole_tolerant,
- const int boolean_mode)
+ const int boolean_mode,
+ Vector<int> *r_intersecting_edges)
{
#ifdef WITH_GMP
BLI_assert(meshes.size() == transforms.size());
@@ -828,7 +829,23 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
write_obj_mesh(m_out, "m_out");
}
- return imesh_to_mesh(&m_out, mim);
+ Mesh *result = imesh_to_mesh(&m_out, mim);
+
+ /* Store intersecting edge indices. */
+ if (r_intersecting_edges != nullptr) {
+ for (int fi : m_out.face_index_range()) {
+ const Face &face = *m_out.face(fi);
+ const MPoly &poly = result->mpoly[fi];
+ for (int corner_i : face.index_range()) {
+ if (face.is_intersect[corner_i]) {
+ int e_index = result->mloop[poly.loopstart + corner_i].e;
+ r_intersecting_edges->append(e_index);
+ }
+ }
+ }
+ }
+
+ return result;
#else // WITH_GMP
UNUSED_VARS(meshes,
transforms,
@@ -836,7 +853,8 @@ Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
target_transform,
use_self,
hole_tolerant,
- boolean_mode);
+ boolean_mode,
+ r_intersecting_edges);
return nullptr;
#endif // WITH_GMP
}
diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc
index 5895eb7fd71..31e20750cf2 100644
--- a/source/blender/blenkernel/intern/mesh_calc_edges.cc
+++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc
@@ -81,7 +81,7 @@ static void add_existing_edges_to_hash_maps(Mesh *mesh,
{
/* Assume existing edges are valid. */
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
for (const MEdge &edge : Span(mesh->medge, mesh->totedge)) {
OrderedEdge ordered_edge{edge.v1, edge.v2};
/* Only add the edge when it belongs into this map. */
@@ -98,7 +98,7 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh,
{
const Span<MLoop> loops{mesh->mloop, mesh->totloop};
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
for (const MPoly &poly : Span(mesh->mpoly, mesh->totpoly)) {
Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
const MLoop *prev_loop = &poly_loops.last();
@@ -131,7 +131,7 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
}
threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) {
- const int task_index = &edge_map - &edge_maps[0];
+ const int task_index = &edge_map - edge_maps.data();
int new_edge_index = edge_index_offsets[task_index];
for (EdgeMap::MutableItem item : edge_map.items()) {
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index cc4a995b1b1..923d2703960 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -41,7 +41,6 @@
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
-#include "BKE_spline.hh"
/* these 2 are only used by conversion functions */
#include "BKE_curve.h"
/* -- */
@@ -752,6 +751,8 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene),
void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud)
{
+ using namespace blender;
+
BLI_assert(me != nullptr);
pointcloud->totpoint = me->totvert;
@@ -759,14 +760,17 @@ void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud)
/* Copy over all attributes. */
CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert);
- BKE_pointcloud_update_customdata_pointers(pointcloud);
- CustomData_update_typemap(&pointcloud->pdata);
- MVert *mvert;
- mvert = me->mvert;
- for (int i = 0; i < me->totvert; i++, mvert++) {
- copy_v3_v3(pointcloud->co[i], mvert->co);
- }
+ bke::AttributeAccessor mesh_attributes = bke::mesh_attributes(*me);
+ bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(
+ *pointcloud);
+
+ const VArray<float3> mesh_positions = mesh_attributes.lookup_or_default<float3>(
+ "position", ATTR_DOMAIN_POINT, float3(0));
+ bke::SpanAttributeWriter<float3> point_positions =
+ point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
+ mesh_positions.materialize(point_positions.span);
+ point_positions.finish();
}
void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob)
@@ -1029,7 +1033,7 @@ static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh)
BKE_mesh_wrapper_ensure_mdata(mesh);
}
else {
- mesh = BKE_mesh_wrapper_ensure_subdivision(object, mesh);
+ mesh = BKE_mesh_wrapper_ensure_subdivision(mesh);
}
Mesh *mesh_result = (Mesh *)BKE_id_copy_ex(
@@ -1066,7 +1070,7 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph,
mask.pmask |= CD_MASK_ORIGINDEX;
}
Mesh *result = mesh_create_eval_final(depsgraph, scene, &object_for_eval, &mask);
- return BKE_mesh_wrapper_ensure_subdivision(object, result);
+ return BKE_mesh_wrapper_ensure_subdivision(result);
}
static Mesh *mesh_new_from_mesh_object(Depsgraph *depsgraph,
@@ -1210,9 +1214,7 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr, &CD_MASK_MESH, true);
/* Anonymous attributes shouldn't exist on original data. */
- MeshComponent component;
- component.replace(mesh_in_bmain, GeometryOwnershipType::Editable);
- component.attributes_remove_anonymous();
+ blender::bke::mesh_attributes_for_write(*mesh_in_bmain).remove_anonymous();
/* User-count is required because so far mesh was in a limbo, where library management does
* not perform any user management (i.e. copy of a mesh will not increase users of materials). */
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index de0489d668f..7d26262a504 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -632,278 +632,6 @@ void BKE_mesh_calc_volume(const MVert *mverts,
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name NGon Tessellation (NGon to MFace Conversion)
- * \{ */
-
-static void bm_corners_to_loops_ex(ID *id,
- CustomData *fdata,
- CustomData *ldata,
- MFace *mface,
- int totloop,
- int findex,
- int loopstart,
- int numTex,
- int numCol)
-{
- MFace *mf = mface + findex;
-
- for (int i = 0; i < numTex; i++) {
- const MTFace *texface = (const MTFace *)CustomData_get_n(fdata, CD_MTFACE, findex, i);
-
- MLoopUV *mloopuv = (MLoopUV *)CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
- copy_v2_v2(mloopuv->uv, texface->uv[0]);
- mloopuv++;
- copy_v2_v2(mloopuv->uv, texface->uv[1]);
- mloopuv++;
- copy_v2_v2(mloopuv->uv, texface->uv[2]);
- mloopuv++;
-
- if (mf->v4) {
- copy_v2_v2(mloopuv->uv, texface->uv[3]);
- mloopuv++;
- }
- }
-
- for (int i = 0; i < numCol; i++) {
- MLoopCol *mloopcol = (MLoopCol *)CustomData_get_n(ldata, CD_PROP_BYTE_COLOR, loopstart, i);
- const MCol *mcol = (const MCol *)CustomData_get_n(fdata, CD_MCOL, findex, i);
-
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]);
- mloopcol++;
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]);
- mloopcol++;
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]);
- mloopcol++;
- if (mf->v4) {
- MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]);
- mloopcol++;
- }
- }
-
- if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) {
- float(*lnors)[3] = (float(*)[3])CustomData_get(ldata, loopstart, CD_NORMAL);
- const short(*tlnors)[3] = (short(*)[3])CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
- const int max = mf->v4 ? 4 : 3;
-
- for (int i = 0; i < max; i++, lnors++, tlnors++) {
- normal_short_to_float_v3(*lnors, *tlnors);
- }
- }
-
- if (CustomData_has_layer(fdata, CD_MDISPS)) {
- MDisps *ld = (MDisps *)CustomData_get(ldata, loopstart, CD_MDISPS);
- const MDisps *fd = (const MDisps *)CustomData_get(fdata, findex, CD_MDISPS);
- const float(*disps)[3] = fd->disps;
- int tot = mf->v4 ? 4 : 3;
- int corners;
-
- if (CustomData_external_test(fdata, CD_MDISPS)) {
- if (id && fdata->external) {
- CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filepath);
- }
- }
-
- corners = multires_mdisp_corners(fd);
-
- if (corners == 0) {
- /* Empty #MDisp layers appear in at least one of the `sintel.blend` files.
- * Not sure why this happens, but it seems fine to just ignore them here.
- * If `corners == 0` for a non-empty layer though, something went wrong. */
- BLI_assert(fd->totdisp == 0);
- }
- else {
- const int side = (int)sqrtf((float)(fd->totdisp / corners));
- const int side_sq = side * side;
-
- for (int i = 0; i < tot; i++, disps += side_sq, ld++) {
- ld->totdisp = side_sq;
- ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1;
-
- if (ld->disps) {
- MEM_freeN(ld->disps);
- }
-
- ld->disps = (float(*)[3])MEM_malloc_arrayN(
- (size_t)side_sq, sizeof(float[3]), "converted loop mdisps");
- if (fd->disps) {
- memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3]));
- }
- else {
- memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3]));
- }
- }
- }
- }
-}
-
-void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
-{
- BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
- &mesh->fdata,
- &mesh->ldata,
- &mesh->pdata,
- mesh->totedge,
- mesh->totface,
- mesh->totloop,
- mesh->totpoly,
- mesh->medge,
- mesh->mface,
- &mesh->totloop,
- &mesh->totpoly,
- &mesh->mloop,
- &mesh->mpoly);
-
- BKE_mesh_update_customdata_pointers(mesh, true);
-}
-
-void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
-{
- BKE_mesh_convert_mfaces_to_mpolys_ex(&mesh->id,
- &mesh->fdata,
- &mesh->ldata,
- &mesh->pdata,
- mesh->totedge,
- mesh->totface,
- mesh->totloop,
- mesh->totpoly,
- mesh->medge,
- mesh->mface,
- &mesh->totloop,
- &mesh->totpoly,
- &mesh->mloop,
- &mesh->mpoly);
-
- CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
-
- BKE_mesh_update_customdata_pointers(mesh, true);
-}
-
-void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id,
- CustomData *fdata,
- CustomData *ldata,
- CustomData *pdata,
- int totedge_i,
- int totface_i,
- int totloop_i,
- int totpoly_i,
- MEdge *medge,
- MFace *mface,
- int *r_totloop,
- int *r_totpoly,
- MLoop **r_mloop,
- MPoly **r_mpoly)
-{
- MFace *mf;
- MLoop *ml, *mloop;
- MPoly *mp, *mpoly;
- MEdge *me;
- EdgeHash *eh;
- int numTex, numCol;
- int i, j, totloop, totpoly, *polyindex;
-
- /* old flag, clear to allow for reuse */
-#define ME_FGON (1 << 3)
-
- /* just in case some of these layers are filled in (can happen with python created meshes) */
- CustomData_free(ldata, totloop_i);
- CustomData_free(pdata, totpoly_i);
-
- totpoly = totface_i;
- mpoly = (MPoly *)MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted");
- CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly);
-
- numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
- numCol = CustomData_number_of_layers(fdata, CD_MCOL);
-
- totloop = 0;
- mf = mface;
- for (i = 0; i < totface_i; i++, mf++) {
- totloop += mf->v4 ? 4 : 3;
- }
-
- mloop = (MLoop *)MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted");
-
- CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
-
- CustomData_to_bmeshpoly(fdata, ldata, totloop);
-
- if (id) {
- /* ensure external data is transferred */
- /* TODO(sergey): Use multiresModifier_ensure_external_read(). */
- CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i);
- }
-
- eh = BLI_edgehash_new_ex(__func__, (uint)totedge_i);
-
- /* build edge hash */
- me = medge;
- for (i = 0; i < totedge_i; i++, me++) {
- BLI_edgehash_insert(eh, me->v1, me->v2, POINTER_FROM_UINT(i));
-
- /* unrelated but avoid having the FGON flag enabled,
- * so we can reuse it later for something else */
- me->flag &= ~ME_FGON;
- }
-
- polyindex = (int *)CustomData_get_layer(fdata, CD_ORIGINDEX);
-
- j = 0; /* current loop index */
- ml = mloop;
- mf = mface;
- mp = mpoly;
- for (i = 0; i < totface_i; i++, mf++, mp++) {
- mp->loopstart = j;
-
- mp->totloop = mf->v4 ? 4 : 3;
-
- mp->mat_nr = mf->mat_nr;
- mp->flag = mf->flag;
-
-#define ML(v1, v2) \
- { \
- ml->v = mf->v1; \
- ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \
- ml++; \
- j++; \
- } \
- (void)0
-
- ML(v1, v2);
- ML(v2, v3);
- if (mf->v4) {
- ML(v3, v4);
- ML(v4, v1);
- }
- else {
- ML(v3, v1);
- }
-
-#undef ML
-
- bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
-
- if (polyindex) {
- *polyindex = i;
- polyindex++;
- }
- }
-
- /* NOTE: we don't convert NGons at all, these are not even real ngons,
- * they have their own UV's, colors etc - its more an editing feature. */
-
- BLI_edgehash_free(eh, nullptr);
-
- *r_totpoly = totpoly;
- *r_totloop = totloop;
- *r_mpoly = mpoly;
- *r_mloop = mloop;
-
-#undef ME_FGON
-}
-
-/** \} */
-
void BKE_mesh_mdisp_flip(MDisps *md, const bool use_loop_mdisp_flip)
{
if (UNLIKELY(!md->totdisp || !md->disps)) {
diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc
new file mode 100644
index 00000000000..479dd6a012a
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc
@@ -0,0 +1,876 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+/** \file
+ * \ingroup bke
+ *
+ * Functions to convert mesh data to and from legacy formats like #MFace.
+ */
+
+// #include <climits>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BLI_edgehash.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_polyfill_2d.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
+#include "BKE_multires.h"
+
+/* -------------------------------------------------------------------- */
+/** \name NGon Tessellation (NGon to MFace Conversion)
+ * \{ */
+
+static void bm_corners_to_loops_ex(ID *id,
+ CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ int totloop,
+ int findex,
+ int loopstart,
+ int numTex,
+ int numCol)
+{
+ MFace *mf = mface + findex;
+
+ for (int i = 0; i < numTex; i++) {
+ const MTFace *texface = (const MTFace *)CustomData_get_n(fdata, CD_MTFACE, findex, i);
+
+ MLoopUV *mloopuv = (MLoopUV *)CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
+ copy_v2_v2(mloopuv->uv, texface->uv[0]);
+ mloopuv++;
+ copy_v2_v2(mloopuv->uv, texface->uv[1]);
+ mloopuv++;
+ copy_v2_v2(mloopuv->uv, texface->uv[2]);
+ mloopuv++;
+
+ if (mf->v4) {
+ copy_v2_v2(mloopuv->uv, texface->uv[3]);
+ mloopuv++;
+ }
+ }
+
+ for (int i = 0; i < numCol; i++) {
+ MLoopCol *mloopcol = (MLoopCol *)CustomData_get_n(ldata, CD_PROP_BYTE_COLOR, loopstart, i);
+ const MCol *mcol = (const MCol *)CustomData_get_n(fdata, CD_MCOL, findex, i);
+
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[0]);
+ mloopcol++;
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[1]);
+ mloopcol++;
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[2]);
+ mloopcol++;
+ if (mf->v4) {
+ MESH_MLOOPCOL_FROM_MCOL(mloopcol, &mcol[3]);
+ mloopcol++;
+ }
+ }
+
+ if (CustomData_has_layer(fdata, CD_TESSLOOPNORMAL)) {
+ float(*lnors)[3] = (float(*)[3])CustomData_get(ldata, loopstart, CD_NORMAL);
+ const short(*tlnors)[3] = (short(*)[3])CustomData_get(fdata, findex, CD_TESSLOOPNORMAL);
+ const int max = mf->v4 ? 4 : 3;
+
+ for (int i = 0; i < max; i++, lnors++, tlnors++) {
+ normal_short_to_float_v3(*lnors, *tlnors);
+ }
+ }
+
+ if (CustomData_has_layer(fdata, CD_MDISPS)) {
+ MDisps *ld = (MDisps *)CustomData_get(ldata, loopstart, CD_MDISPS);
+ const MDisps *fd = (const MDisps *)CustomData_get(fdata, findex, CD_MDISPS);
+ const float(*disps)[3] = fd->disps;
+ int tot = mf->v4 ? 4 : 3;
+ int corners;
+
+ if (CustomData_external_test(fdata, CD_MDISPS)) {
+ if (id && fdata->external) {
+ CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filepath);
+ }
+ }
+
+ corners = multires_mdisp_corners(fd);
+
+ if (corners == 0) {
+ /* Empty #MDisp layers appear in at least one of the `sintel.blend` files.
+ * Not sure why this happens, but it seems fine to just ignore them here.
+ * If `corners == 0` for a non-empty layer though, something went wrong. */
+ BLI_assert(fd->totdisp == 0);
+ }
+ else {
+ const int side = (int)sqrtf((float)(fd->totdisp / corners));
+ const int side_sq = side * side;
+
+ for (int i = 0; i < tot; i++, disps += side_sq, ld++) {
+ ld->totdisp = side_sq;
+ ld->level = (int)(logf((float)side - 1.0f) / (float)M_LN2) + 1;
+
+ if (ld->disps) {
+ MEM_freeN(ld->disps);
+ }
+
+ ld->disps = (float(*)[3])MEM_malloc_arrayN(
+ (size_t)side_sq, sizeof(float[3]), "converted loop mdisps");
+ if (fd->disps) {
+ memcpy(ld->disps, disps, (size_t)side_sq * sizeof(float[3]));
+ }
+ else {
+ memset(ld->disps, 0, (size_t)side_sq * sizeof(float[3]));
+ }
+ }
+ }
+ }
+}
+
+static 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, nullptr, totloop, fdata->layers[i].name);
+ }
+ else if (fdata->layers[i].type == CD_MCOL) {
+ CustomData_add_layer_named(
+ ldata, CD_PROP_BYTE_COLOR, 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, nullptr, totloop, fdata->layers[i].name);
+ }
+ else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) {
+ CustomData_add_layer_named(
+ ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
+ }
+ }
+}
+
+static void convert_mfaces_to_mpolys(ID *id,
+ CustomData *fdata,
+ CustomData *ldata,
+ CustomData *pdata,
+ int totedge_i,
+ int totface_i,
+ int totloop_i,
+ int totpoly_i,
+ MEdge *medge,
+ MFace *mface,
+ int *r_totloop,
+ int *r_totpoly,
+ MLoop **r_mloop,
+ MPoly **r_mpoly)
+{
+ MFace *mf;
+ MLoop *ml, *mloop;
+ MPoly *mp, *mpoly;
+ MEdge *me;
+ EdgeHash *eh;
+ int numTex, numCol;
+ int i, j, totloop, totpoly, *polyindex;
+
+ /* old flag, clear to allow for reuse */
+#define ME_FGON (1 << 3)
+
+ /* just in case some of these layers are filled in (can happen with python created meshes) */
+ CustomData_free(ldata, totloop_i);
+ CustomData_free(pdata, totpoly_i);
+
+ totpoly = totface_i;
+ mpoly = (MPoly *)MEM_calloc_arrayN((size_t)totpoly, sizeof(MPoly), "mpoly converted");
+ CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, totpoly);
+
+ numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
+ numCol = CustomData_number_of_layers(fdata, CD_MCOL);
+
+ totloop = 0;
+ mf = mface;
+ for (i = 0; i < totface_i; i++, mf++) {
+ totloop += mf->v4 ? 4 : 3;
+ }
+
+ mloop = (MLoop *)MEM_calloc_arrayN((size_t)totloop, sizeof(MLoop), "mloop converted");
+
+ CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
+
+ CustomData_to_bmeshpoly(fdata, ldata, totloop);
+
+ if (id) {
+ /* ensure external data is transferred */
+ /* TODO(sergey): Use multiresModifier_ensure_external_read(). */
+ CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i);
+ }
+
+ eh = BLI_edgehash_new_ex(__func__, (uint)totedge_i);
+
+ /* build edge hash */
+ me = medge;
+ for (i = 0; i < totedge_i; i++, me++) {
+ BLI_edgehash_insert(eh, me->v1, me->v2, POINTER_FROM_UINT(i));
+
+ /* unrelated but avoid having the FGON flag enabled,
+ * so we can reuse it later for something else */
+ me->flag &= ~ME_FGON;
+ }
+
+ polyindex = (int *)CustomData_get_layer(fdata, CD_ORIGINDEX);
+
+ j = 0; /* current loop index */
+ ml = mloop;
+ mf = mface;
+ mp = mpoly;
+ for (i = 0; i < totface_i; i++, mf++, mp++) {
+ mp->loopstart = j;
+
+ mp->totloop = mf->v4 ? 4 : 3;
+
+ mp->mat_nr = mf->mat_nr;
+ mp->flag = mf->flag;
+
+#define ML(v1, v2) \
+ { \
+ ml->v = mf->v1; \
+ ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \
+ ml++; \
+ j++; \
+ } \
+ (void)0
+
+ ML(v1, v2);
+ ML(v2, v3);
+ if (mf->v4) {
+ ML(v3, v4);
+ ML(v4, v1);
+ }
+ else {
+ ML(v3, v1);
+ }
+
+#undef ML
+
+ bm_corners_to_loops_ex(id, fdata, ldata, mface, totloop, i, mp->loopstart, numTex, numCol);
+
+ if (polyindex) {
+ *polyindex = i;
+ polyindex++;
+ }
+ }
+
+ /* NOTE: we don't convert NGons at all, these are not even real ngons,
+ * they have their own UV's, colors etc - its more an editing feature. */
+
+ BLI_edgehash_free(eh, nullptr);
+
+ *r_totpoly = totpoly;
+ *r_totloop = totloop;
+ *r_mpoly = mpoly;
+ *r_mloop = mloop;
+
+#undef ME_FGON
+}
+
+void BKE_mesh_convert_mfaces_to_mpolys(Mesh *mesh)
+{
+ convert_mfaces_to_mpolys(&mesh->id,
+ &mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->totedge,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->medge,
+ mesh->mface,
+ &mesh->totloop,
+ &mesh->totpoly,
+ &mesh->mloop,
+ &mesh->mpoly);
+
+ BKE_mesh_update_customdata_pointers(mesh, true);
+}
+
+/**
+ * Update active indices for active/render/clone/stencil custom data layers
+ * based on indices from fdata layers
+ * used when creating pdata and ldata for pre-bmesh
+ * meshes and needed to preserve active/render/clone/stencil flags set in pre-bmesh files.
+ */
+static void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, CustomData *ldata)
+{
+ int act;
+
+ if (CustomData_has_layer(fdata, CD_MTFACE)) {
+ act = CustomData_get_active_layer(fdata, CD_MTFACE);
+ CustomData_set_layer_active(ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_render_layer(fdata, CD_MTFACE);
+ CustomData_set_layer_render(ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_clone_layer(fdata, CD_MTFACE);
+ CustomData_set_layer_clone(ldata, CD_MLOOPUV, act);
+
+ act = CustomData_get_stencil_layer(fdata, CD_MTFACE);
+ CustomData_set_layer_stencil(ldata, CD_MLOOPUV, act);
+ }
+
+ if (CustomData_has_layer(fdata, CD_MCOL)) {
+ act = CustomData_get_active_layer(fdata, CD_MCOL);
+ CustomData_set_layer_active(ldata, CD_PROP_BYTE_COLOR, act);
+
+ act = CustomData_get_render_layer(fdata, CD_MCOL);
+ CustomData_set_layer_render(ldata, CD_PROP_BYTE_COLOR, act);
+
+ act = CustomData_get_clone_layer(fdata, CD_MCOL);
+ CustomData_set_layer_clone(ldata, CD_PROP_BYTE_COLOR, act);
+
+ act = CustomData_get_stencil_layer(fdata, CD_MCOL);
+ CustomData_set_layer_stencil(ldata, CD_PROP_BYTE_COLOR, act);
+ }
+}
+
+void BKE_mesh_do_versions_convert_mfaces_to_mpolys(Mesh *mesh)
+{
+ convert_mfaces_to_mpolys(&mesh->id,
+ &mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->totedge,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->medge,
+ mesh->mface,
+ &mesh->totloop,
+ &mesh->totpoly,
+ &mesh->mloop,
+ &mesh->mpoly);
+
+ CustomData_bmesh_do_versions_update_active_layers(&mesh->fdata, &mesh->ldata);
+
+ BKE_mesh_update_customdata_pointers(mesh, true);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name MFace Tessellation
+ *
+ * #MFace is a legacy data-structure that should be avoided, use #MLoopTri instead.
+ * \{ */
+
+/**
+ * Convert all CD layers from loop/poly to tessface data.
+ *
+ * \param loopindices: is an array of an int[4] per tessface,
+ * mapping tessface's verts to loops indices.
+ *
+ * \note when mface is not null, mface[face_index].v4
+ * is used to test quads, else, loopindices[face_index][3] is used.
+ */
+static void mesh_loops_to_tessdata(CustomData *fdata,
+ CustomData *ldata,
+ MFace *mface,
+ const int *polyindices,
+ uint (*loopindices)[4],
+ const int num_faces)
+{
+ /* NOTE(mont29): performances are sub-optimal when we get a null #MFace,
+ * we could be ~25% quicker with dedicated code.
+ * The issue is, unless having two different functions with nearly the same code,
+ * there's not much ways to solve this. Better IMHO to live with it for now (sigh). */
+ const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
+ const int numCol = CustomData_number_of_layers(ldata, CD_PROP_BYTE_COLOR);
+ const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
+ const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
+ const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
+ const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
+ int findex, i, j;
+ const int *pidx;
+ uint(*lidx)[4];
+
+ for (i = 0; i < numUV; i++) {
+ MTFace *texface = (MTFace *)CustomData_get_layer_n(fdata, CD_MTFACE, i);
+ const MLoopUV *mloopuv = (const MLoopUV *)CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
+
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++, texface++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
+ }
+ }
+ }
+
+ for (i = 0; i < numCol; i++) {
+ MCol(*mcol)[4] = (MCol(*)[4])CustomData_get_layer_n(fdata, CD_MCOL, i);
+ const MLoopCol *mloopcol = (const MLoopCol *)CustomData_get_layer_n(
+ ldata, CD_PROP_BYTE_COLOR, i);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
+ }
+ }
+ }
+
+ if (hasPCol) {
+ MCol(*mcol)[4] = (MCol(*)[4])CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
+ const MLoopCol *mloopcol = (const MLoopCol *)CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
+ }
+ }
+ }
+
+ if (hasOrigSpace) {
+ OrigSpaceFace *of = (OrigSpaceFace *)CustomData_get_layer(fdata, CD_ORIGSPACE);
+ const OrigSpaceLoop *lof = (const OrigSpaceLoop *)CustomData_get_layer(ldata,
+ CD_ORIGSPACE_MLOOP);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
+ }
+ }
+ }
+
+ if (hasLoopNormal) {
+ short(*fnors)[4][3] = (short(*)[4][3])CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
+ const float(*lnors)[3] = (const float(*)[3])CustomData_get_layer(ldata, CD_NORMAL);
+
+ for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
+ for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
+ normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]);
+ }
+ }
+ }
+
+ if (hasLoopTangent) {
+ /* Need to do for all UV maps at some point. */
+ float(*ftangents)[4] = (float(*)[4])CustomData_get_layer(fdata, CD_TANGENT);
+ const float(*ltangents)[4] = (const float(*)[4])CustomData_get_layer(ldata, CD_TANGENT);
+
+ for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
+ pidx++, lidx++, findex++) {
+ int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
+ for (j = nverts; j--;) {
+ copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
+ }
+ }
+ }
+}
+
+int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, int nr)
+{
+ /* first test if the face is legal */
+ if ((mface->v3 || nr == 4) && mface->v3 == mface->v4) {
+ mface->v4 = 0;
+ nr--;
+ }
+ if ((mface->v2 || mface->v4) && mface->v2 == mface->v3) {
+ mface->v3 = mface->v4;
+ mface->v4 = 0;
+ nr--;
+ }
+ if (mface->v1 == mface->v2) {
+ mface->v2 = mface->v3;
+ mface->v3 = mface->v4;
+ mface->v4 = 0;
+ nr--;
+ }
+
+ /* Check corrupt cases, bow-tie geometry,
+ * can't handle these because edge data won't exist so just return 0. */
+ if (nr == 3) {
+ if (
+ /* real edges */
+ mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v1) {
+ return 0;
+ }
+ }
+ else if (nr == 4) {
+ if (
+ /* real edges */
+ mface->v1 == mface->v2 || mface->v2 == mface->v3 || mface->v3 == mface->v4 ||
+ mface->v4 == mface->v1 ||
+ /* across the face */
+ mface->v1 == mface->v3 || mface->v2 == mface->v4) {
+ return 0;
+ }
+ }
+
+ /* prevent a zero at wrong index location */
+ if (nr == 3) {
+ if (mface->v3 == 0) {
+ static int corner_indices[4] = {1, 2, 0, 3};
+
+ SWAP(uint, mface->v1, mface->v2);
+ SWAP(uint, mface->v2, mface->v3);
+
+ if (fdata) {
+ CustomData_swap_corners(fdata, mfindex, corner_indices);
+ }
+ }
+ }
+ else if (nr == 4) {
+ if (mface->v3 == 0 || mface->v4 == 0) {
+ static int corner_indices[4] = {2, 3, 0, 1};
+
+ SWAP(uint, mface->v1, mface->v3);
+ SWAP(uint, mface->v2, mface->v4);
+
+ if (fdata) {
+ CustomData_swap_corners(fdata, mfindex, corner_indices);
+ }
+ }
+ }
+
+ return nr;
+}
+
+static int mesh_tessface_calc(CustomData *fdata,
+ CustomData *ldata,
+ CustomData *pdata,
+ MVert *mvert,
+ int totface,
+ int totloop,
+ int totpoly)
+{
+#define USE_TESSFACE_SPEEDUP
+#define USE_TESSFACE_QUADS
+
+/* We abuse #MFace.edcode to tag quad faces. See below for details. */
+#define TESSFACE_IS_QUAD 1
+
+ const int looptri_num = poly_to_tri_count(totpoly, totloop);
+
+ const MPoly *mp, *mpoly;
+ const MLoop *ml, *mloop;
+ MFace *mface, *mf;
+ MemArena *arena = nullptr;
+ int *mface_to_poly_map;
+ uint(*lindices)[4];
+ int poly_index, mface_index;
+ uint j;
+
+ mpoly = (const MPoly *)CustomData_get_layer(pdata, CD_MPOLY);
+ mloop = (const MLoop *)CustomData_get_layer(ldata, CD_MLOOP);
+
+ /* Allocate the length of `totfaces`, avoid many small reallocation's,
+ * if all faces are triangles it will be correct, `quads == 2x` allocations. */
+ /* Take care since memory is _not_ zeroed so be sure to initialize each field. */
+ mface_to_poly_map = (int *)MEM_malloc_arrayN(
+ (size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
+ mface = (MFace *)MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
+ lindices = (uint(*)[4])MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
+
+ mface_index = 0;
+ mp = mpoly;
+ for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
+ const uint mp_loopstart = (uint)mp->loopstart;
+ const uint mp_totloop = (uint)mp->totloop;
+ uint l1, l2, l3, l4;
+ uint *lidx;
+ if (mp_totloop < 3) {
+ /* Do nothing. */
+ }
+
+#ifdef USE_TESSFACE_SPEEDUP
+
+# define ML_TO_MF(i1, i2, i3) \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf = &mface[mface_index]; \
+ lidx = lindices[mface_index]; \
+ /* Set loop indices, transformed to vert indices later. */ \
+ l1 = mp_loopstart + i1; \
+ l2 = mp_loopstart + i2; \
+ l3 = mp_loopstart + i3; \
+ mf->v1 = mloop[l1].v; \
+ mf->v2 = mloop[l2].v; \
+ mf->v3 = mloop[l3].v; \
+ mf->v4 = 0; \
+ lidx[0] = l1; \
+ lidx[1] = l2; \
+ lidx[2] = l3; \
+ lidx[3] = 0; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ mf->edcode = 0; \
+ (void)0
+
+/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */
+# define ML_TO_MF_QUAD() \
+ mface_to_poly_map[mface_index] = poly_index; \
+ mf = &mface[mface_index]; \
+ lidx = lindices[mface_index]; \
+ /* Set loop indices, transformed to vert indices later. */ \
+ l1 = mp_loopstart + 0; /* EXCEPTION */ \
+ l2 = mp_loopstart + 1; /* EXCEPTION */ \
+ l3 = mp_loopstart + 2; /* EXCEPTION */ \
+ l4 = mp_loopstart + 3; /* EXCEPTION */ \
+ mf->v1 = mloop[l1].v; \
+ mf->v2 = mloop[l2].v; \
+ mf->v3 = mloop[l3].v; \
+ mf->v4 = mloop[l4].v; \
+ lidx[0] = l1; \
+ lidx[1] = l2; \
+ lidx[2] = l3; \
+ lidx[3] = l4; \
+ mf->mat_nr = mp->mat_nr; \
+ mf->flag = mp->flag; \
+ mf->edcode = TESSFACE_IS_QUAD; \
+ (void)0
+
+ else if (mp_totloop == 3) {
+ ML_TO_MF(0, 1, 2);
+ mface_index++;
+ }
+ else if (mp_totloop == 4) {
+# ifdef USE_TESSFACE_QUADS
+ ML_TO_MF_QUAD();
+ mface_index++;
+# else
+ ML_TO_MF(0, 1, 2);
+ mface_index++;
+ ML_TO_MF(0, 2, 3);
+ mface_index++;
+# endif
+ }
+#endif /* USE_TESSFACE_SPEEDUP */
+ else {
+ const float *co_curr, *co_prev;
+
+ float normal[3];
+
+ float axis_mat[3][3];
+ float(*projverts)[2];
+ uint(*tris)[3];
+
+ const uint totfilltri = mp_totloop - 2;
+
+ if (UNLIKELY(arena == nullptr)) {
+ arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+
+ tris = (uint(*)[3])BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
+ projverts = (float(*)[2])BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
+
+ zero_v3(normal);
+
+ /* Calculate the normal, flipped: to get a positive 2D cross product. */
+ ml = mloop + mp_loopstart;
+ co_prev = mvert[ml[mp_totloop - 1].v].co;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ co_curr = mvert[ml->v].co;
+ add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
+ co_prev = co_curr;
+ }
+ if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
+ normal[2] = 1.0f;
+ }
+
+ /* Project verts to 2D. */
+ axis_dominant_v3_to_m3_negate(axis_mat, normal);
+
+ ml = mloop + mp_loopstart;
+ for (j = 0; j < mp_totloop; j++, ml++) {
+ mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
+ }
+
+ BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
+
+ /* Apply fill. */
+ for (j = 0; j < totfilltri; j++) {
+ uint *tri = tris[j];
+ lidx = lindices[mface_index];
+
+ mface_to_poly_map[mface_index] = poly_index;
+ mf = &mface[mface_index];
+
+ /* Set loop indices, transformed to vert indices later. */
+ l1 = mp_loopstart + tri[0];
+ l2 = mp_loopstart + tri[1];
+ l3 = mp_loopstart + tri[2];
+
+ mf->v1 = mloop[l1].v;
+ mf->v2 = mloop[l2].v;
+ mf->v3 = mloop[l3].v;
+ mf->v4 = 0;
+
+ lidx[0] = l1;
+ lidx[1] = l2;
+ lidx[2] = l3;
+ lidx[3] = 0;
+
+ mf->mat_nr = mp->mat_nr;
+ mf->flag = mp->flag;
+ mf->edcode = 0;
+
+ mface_index++;
+ }
+
+ BLI_memarena_clear(arena);
+ }
+ }
+
+ if (arena) {
+ BLI_memarena_free(arena);
+ arena = nullptr;
+ }
+
+ CustomData_free(fdata, totface);
+ totface = mface_index;
+
+ BLI_assert(totface <= looptri_num);
+
+ /* Not essential but without this we store over-allocated memory in the #CustomData layers. */
+ if (LIKELY(looptri_num != totface)) {
+ mface = (MFace *)MEM_reallocN(mface, sizeof(*mface) * (size_t)totface);
+ mface_to_poly_map = (int *)MEM_reallocN(mface_to_poly_map,
+ sizeof(*mface_to_poly_map) * (size_t)totface);
+ }
+
+ CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
+
+ /* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons
+ * they are directly tessellated from. */
+ CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
+ BKE_mesh_add_mface_layers(fdata, ldata, totface);
+
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * Polygons take care of their loops ordering, hence not of their vertices ordering.
+ * Currently, our tfaces' fourth vertex index might be 0 even for a quad.
+ * However, we know our fourth loop index is never 0 for quads
+ * (because they are sorted for polygons, and our quads are still mere copies of their polygons).
+ * So we pass nullptr as MFace pointer, and #mesh_loops_to_tessdata
+ * will use the fourth loop index as quad test. */
+ mesh_loops_to_tessdata(fdata, ldata, nullptr, mface_to_poly_map, lindices, totface);
+
+ /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
+ * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
+ * BKE_mesh_mface_index_validate() will check this and rotate the tessellated face if needed.
+ */
+#ifdef USE_TESSFACE_QUADS
+ mf = mface;
+ for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
+ if (mf->edcode == TESSFACE_IS_QUAD) {
+ BKE_mesh_mface_index_validate(mf, fdata, mface_index, 4);
+ mf->edcode = 0;
+ }
+ }
+#endif
+
+ MEM_freeN(lindices);
+
+ return totface;
+
+#undef USE_TESSFACE_SPEEDUP
+#undef USE_TESSFACE_QUADS
+
+#undef ML_TO_MF
+#undef ML_TO_MF_QUAD
+}
+
+void BKE_mesh_tessface_calc(Mesh *mesh)
+{
+ mesh->totface = mesh_tessface_calc(&mesh->fdata,
+ &mesh->ldata,
+ &mesh->pdata,
+ mesh->mvert,
+ mesh->totface,
+ mesh->totloop,
+ mesh->totpoly);
+
+ BKE_mesh_update_customdata_pointers(mesh, true);
+}
+
+void BKE_mesh_tessface_ensure(struct Mesh *mesh)
+{
+ if (mesh->totpoly && mesh->totface == 0) {
+ BKE_mesh_tessface_calc(mesh);
+ }
+}
+
+#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.
+ */
+static bool check_matching_legacy_layer_counts(CustomData *fdata, CustomData *ldata, bool fallback)
+{
+ int a_num = 0, b_num = 0;
+# define LAYER_CMP(l_a, t_a, l_b, t_b) \
+ ((a_num += CustomData_number_of_layers(l_a, t_a)) == \
+ (b_num += CustomData_number_of_layers(l_b, t_b)))
+
+ if (!LAYER_CMP(ldata, CD_MLOOPUV, fdata, CD_MTFACE)) {
+ return false;
+ }
+ if (!LAYER_CMP(ldata, CD_PROP_BYTE_COLOR, fdata, CD_MCOL)) {
+ return false;
+ }
+ if (!LAYER_CMP(ldata, CD_PREVIEW_MLOOPCOL, fdata, CD_PREVIEW_MCOL)) {
+ return false;
+ }
+ if (!LAYER_CMP(ldata, CD_ORIGSPACE_MLOOP, fdata, CD_ORIGSPACE)) {
+ return false;
+ }
+ if (!LAYER_CMP(ldata, CD_NORMAL, fdata, CD_TESSLOOPNORMAL)) {
+ return false;
+ }
+ if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT)) {
+ return false;
+ }
+
+# undef LAYER_CMP
+
+ /* if no layers are on either CustomData's,
+ * then there was nothing to do... */
+ return a_num ? true : fallback;
+}
+#endif
+
+void BKE_mesh_add_mface_layers(CustomData *fdata, CustomData *ldata, int total)
+{
+ /* avoid accumulating extra layers */
+ BLI_assert(!check_matching_legacy_layer_counts(fdata, ldata, false));
+
+ for (int i = 0; i < ldata->totlayer; i++) {
+ if (ldata->layers[i].type == CD_MLOOPUV) {
+ CustomData_add_layer_named(
+ fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
+ }
+ if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) {
+ 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, nullptr, total, ldata->layers[i].name);
+ }
+ else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
+ CustomData_add_layer_named(
+ 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, nullptr, total, ldata->layers[i].name);
+ }
+ else if (ldata->layers[i].type == CD_TANGENT) {
+ CustomData_add_layer_named(
+ fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name);
+ }
+ }
+
+ CustomData_bmesh_update_active_layers(fdata, ldata);
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_merge_customdata.cc b/source/blender/blenkernel/intern/mesh_merge_customdata.cc
index adaf378ed27..7bc429954b0 100644
--- a/source/blender/blenkernel/intern/mesh_merge_customdata.cc
+++ b/source/blender/blenkernel/intern/mesh_merge_customdata.cc
@@ -33,11 +33,11 @@ static int compare_v2_classify(const float uv_a[2], const float uv_b[2])
if (uv_a[0] == uv_b[0] && uv_a[1] == uv_b[1]) {
return CMP_EQUAL;
}
- /* Note that the ULP value is the primary value used to compare relative values
- * as the absolute value doesn't account for float precision at difference scales.
+ /* NOTE(@campbellbarton): that the ULP value is the primary value used to compare relative
+ * values as the absolute value doesn't account for float precision at difference scales.
* - For subdivision-surface ULP of 3 is sufficient,
* although this value is extremely small.
- * - For bevel the URL of 12 is sufficient to merge UV's that appear to be connected
+ * - For bevel the ULP of 12 is sufficient to merge UV's that appear to be connected
* with bevel on Suzanne beveled 15% with 6 segments.
*
* These values could be tweaked but should be kept on the small side to prevent
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index ba1004e8371..2366b7526a1 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -345,7 +345,7 @@ void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert,
const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
- if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0);
return mesh->runtime.vert_normals;
}
@@ -356,7 +356,7 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
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))) {
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
BLI_assert(mesh->runtime.vert_normals != nullptr);
BLI_mutex_unlock(normals_mutex);
return mesh->runtime.vert_normals;
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index c960a7f35f1..85aed01ce52 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -375,7 +375,7 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source)
while ((layer = BKE_id_attribute_from_index(
const_cast<ID *>(&source->id), i++, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL))) {
- AttributeDomain domain = BKE_id_attribute_domain(&source->id, layer);
+ eAttrDomain domain = BKE_id_attribute_domain(&source->id, layer);
CustomData *target_cdata = domain == ATTR_DOMAIN_POINT ? &target->vdata : &target->ldata;
const CustomData *source_cdata = domain == ATTR_DOMAIN_POINT ? &source->vdata : &source->ldata;
diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc
index 90e9a2a2ff6..4521c519f45 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.cc
+++ b/source/blender/blenkernel/intern/mesh_runtime.cc
@@ -244,11 +244,8 @@ bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
{
- if (mesh->runtime.bvh_cache) {
- bvhcache_free(mesh->runtime.bvh_cache);
- mesh->runtime.bvh_cache = nullptr;
- }
- MEM_SAFE_FREE(mesh->runtime.looptris.array);
+ BKE_mesh_tag_coords_changed(mesh);
+
/* TODO(sergey): Does this really belong here? */
if (mesh->runtime.subdiv_ccg != nullptr) {
BKE_subdiv_ccg_destroy(mesh->runtime.subdiv_ccg);
@@ -259,6 +256,31 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
MEM_SAFE_FREE(mesh->runtime.subsurf_face_dot_tags);
}
+void BKE_mesh_tag_coords_changed(Mesh *mesh)
+{
+ BKE_mesh_normals_tag_dirty(mesh);
+ MEM_SAFE_FREE(mesh->runtime.looptris.array);
+ if (mesh->runtime.bvh_cache) {
+ bvhcache_free(mesh->runtime.bvh_cache);
+ mesh->runtime.bvh_cache = nullptr;
+ }
+}
+
+void BKE_mesh_tag_coords_changed_uniformly(Mesh *mesh)
+{
+ const bool vert_normals_were_dirty = BKE_mesh_vertex_normals_are_dirty(mesh);
+ const bool poly_normals_were_dirty = BKE_mesh_poly_normals_are_dirty(mesh);
+
+ BKE_mesh_tag_coords_changed(mesh);
+ /* The normals didn't change, since all vertices moved by the same amount. */
+ if (!vert_normals_were_dirty) {
+ BKE_mesh_poly_normals_clear_dirty(mesh);
+ }
+ if (!poly_normals_were_dirty) {
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
index 33b051c792c..dd09a3d6917 100644
--- a/source/blender/blenkernel/intern/mesh_sample.cc
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -1,13 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
+#include "BKE_bvhutils.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_sample.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BLI_rand.hh"
+
namespace blender::bke::mesh_surface_sample {
template<typename T>
@@ -204,7 +206,7 @@ Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
}
void MeshAttributeInterpolator::sample_data(const GVArray &src,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const eAttributeMapMode mode,
const GMutableSpan dst)
{
@@ -250,13 +252,182 @@ void MeshAttributeInterpolator::sample_data(const GVArray &src,
}
}
-void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_attribute,
- OutputAttribute &dst_attribute,
+void MeshAttributeInterpolator::sample_attribute(const GAttributeReader &src_attribute,
+ GSpanAttributeWriter &dst_attribute,
eAttributeMapMode mode)
{
if (src_attribute && dst_attribute) {
- this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span());
+ this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.span);
}
}
+int sample_surface_points_spherical(RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ const Span<int> looptri_indices_to_sample,
+ const float3 &sample_pos,
+ const float sample_radius,
+ const float approximate_density,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions)
+{
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ const float sample_radius_sq = pow2f(sample_radius);
+ const float sample_plane_area = M_PI * sample_radius_sq;
+ /* Used for switching between two triangle sampling strategies. */
+ const float area_threshold = sample_plane_area;
+
+ const int old_num = r_bary_coords.size();
+
+ for (const int looptri_index : looptri_indices_to_sample) {
+ const MLoopTri &looptri = looptris[looptri_index];
+
+ const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
+
+ const float looptri_area = area_tri_v3(v0, v1, v2);
+
+ if (looptri_area < area_threshold) {
+ /* The triangle is small compared to the sample radius. Sample by generating random
+ * barycentric coordinates. */
+ const int amount = rng.round_probabilistic(approximate_density * looptri_area);
+ for ([[maybe_unused]] const int i : IndexRange(amount)) {
+ const float3 bary_coord = rng.get_barycentric_coordinates();
+ const float3 point_pos = attribute_math::mix3(bary_coord, v0, v1, v2);
+ const float dist_to_sample_sq = math::distance_squared(point_pos, sample_pos);
+ if (dist_to_sample_sq > sample_radius_sq) {
+ continue;
+ }
+
+ r_bary_coords.append(bary_coord);
+ r_looptri_indices.append(looptri_index);
+ r_positions.append(point_pos);
+ }
+ }
+ else {
+ /* The triangle is large compared to the sample radius. Sample by generating random points
+ * on the triangle plane within the sample radius. */
+ float3 normal;
+ normal_tri_v3(normal, v0, v1, v2);
+
+ float3 sample_pos_proj = sample_pos;
+ project_v3_plane(sample_pos_proj, normal, v0);
+
+ const float proj_distance_sq = math::distance_squared(sample_pos_proj, sample_pos);
+ const float sample_radius_factor_sq = 1.0f -
+ std::min(1.0f, proj_distance_sq / sample_radius_sq);
+ const float radius_proj_sq = sample_radius_sq * sample_radius_factor_sq;
+ const float radius_proj = std::sqrt(radius_proj_sq);
+ const float circle_area = M_PI * radius_proj_sq;
+
+ const int amount = rng.round_probabilistic(approximate_density * circle_area);
+
+ const float3 axis_1 = math::normalize(v1 - v0) * radius_proj;
+ const float3 axis_2 = math::normalize(math::cross(axis_1, math::cross(axis_1, v2 - v0))) *
+ radius_proj;
+
+ for ([[maybe_unused]] const int i : IndexRange(amount)) {
+ const float r = std::sqrt(rng.get_float());
+ const float angle = rng.get_float() * 2.0f * M_PI;
+ const float x = r * std::cos(angle);
+ const float y = r * std::sin(angle);
+ const float3 point_pos = sample_pos_proj + axis_1 * x + axis_2 * y;
+ if (!isect_point_tri_prism_v3(point_pos, v0, v1, v2)) {
+ /* Sampled point is not in the triangle. */
+ continue;
+ }
+
+ float3 bary_coord;
+ interp_weights_tri_v3(bary_coord, v0, v1, v2, point_pos);
+
+ r_bary_coords.append(bary_coord);
+ r_looptri_indices.append(looptri_index);
+ r_positions.append(point_pos);
+ }
+ }
+ }
+ return r_bary_coords.size() - old_num;
+}
+
+int sample_surface_points_projected(
+ RandomNumberGenerator &rng,
+ const Mesh &mesh,
+ BVHTreeFromMesh &mesh_bvhtree,
+ const float2 &sample_pos_re,
+ const float sample_radius_re,
+ const FunctionRef<void(const float2 &pos_re, float3 &r_start, float3 &r_end)>
+ region_position_to_ray,
+ const bool front_face_only,
+ const int tries_num,
+ const int max_points,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions)
+{
+ const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
+ BKE_mesh_runtime_looptri_len(&mesh)};
+
+ int point_count = 0;
+ for ([[maybe_unused]] const int _ : IndexRange(tries_num)) {
+ if (point_count == max_points) {
+ break;
+ }
+
+ const float r = sample_radius_re * std::sqrt(rng.get_float());
+ const float angle = rng.get_float() * 2.0f * M_PI;
+ float3 ray_start, ray_end;
+ const float2 pos_re = sample_pos_re + r * float2(std::cos(angle), std::sin(angle));
+ region_position_to_ray(pos_re, ray_start, ray_end);
+ const float3 ray_direction = math::normalize(ray_end - ray_start);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(mesh_bvhtree.tree,
+ ray_start,
+ ray_direction,
+ 0.0f,
+ &ray_hit,
+ mesh_bvhtree.raycast_callback,
+ &mesh_bvhtree);
+
+ if (ray_hit.index == -1) {
+ continue;
+ }
+
+ if (front_face_only) {
+ const float3 normal = ray_hit.no;
+ if (math::dot(ray_direction, normal) >= 0.0f) {
+ continue;
+ }
+ }
+
+ const int looptri_index = ray_hit.index;
+ const float3 pos = ray_hit.co;
+
+ const float3 bary_coords = compute_bary_coord_in_triangle(mesh, looptris[looptri_index], pos);
+
+ r_positions.append(pos);
+ r_bary_coords.append(bary_coords);
+ r_looptri_indices.append(looptri_index);
+ point_count++;
+ }
+ return point_count;
+}
+
+float3 compute_bary_coord_in_triangle(const Mesh &mesh,
+ const MLoopTri &looptri,
+ const float3 &position)
+{
+ const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
+ return bary_coords;
+}
+
} // 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 c0b2b33c47c..a677a0d6ebb 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -167,7 +167,7 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
if (!loopuvs) {
BKE_reportf(reports,
RPT_ERROR,
- "Tangent space computation needs an UVMap, \"%s\" not found, aborting",
+ "Tangent space computation needs a UV Map, \"%s\" not found, aborting",
uvmap);
return;
}
diff --git a/source/blender/blenkernel/intern/mesh_tessellate.c b/source/blender/blenkernel/intern/mesh_tessellate.c
index 7cb656d2357..173fb98912b 100644
--- a/source/blender/blenkernel/intern/mesh_tessellate.c
+++ b/source/blender/blenkernel/intern/mesh_tessellate.c
@@ -32,370 +32,6 @@
#define MESH_FACE_TESSELLATE_THREADED_LIMIT 4096
/* -------------------------------------------------------------------- */
-/** \name MFace Tessellation
- *
- * #MFace is a legacy data-structure that should be avoided, use #MLoopTri instead.
- * \{ */
-
-/**
- * Convert all CD layers from loop/poly to tessface data.
- *
- * \param loopindices: is an array of an int[4] per tessface,
- * mapping tessface's verts to loops indices.
- *
- * \note when mface is not NULL, mface[face_index].v4
- * is used to test quads, else, loopindices[face_index][3] is used.
- */
-static void mesh_loops_to_tessdata(CustomData *fdata,
- CustomData *ldata,
- MFace *mface,
- const int *polyindices,
- uint (*loopindices)[4],
- const int num_faces)
-{
- /* NOTE(mont29): performances are sub-optimal when we get a NULL #MFace,
- * we could be ~25% quicker with dedicated code.
- * The issue is, unless having two different functions with nearly the same code,
- * there's not much ways to solve this. Better IMHO to live with it for now (sigh). */
- const int numUV = CustomData_number_of_layers(ldata, CD_MLOOPUV);
- const int numCol = CustomData_number_of_layers(ldata, CD_PROP_BYTE_COLOR);
- const bool hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
- const bool hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
- const bool hasLoopNormal = CustomData_has_layer(ldata, CD_NORMAL);
- const bool hasLoopTangent = CustomData_has_layer(ldata, CD_TANGENT);
- int findex, i, j;
- const int *pidx;
- uint(*lidx)[4];
-
- for (i = 0; i < numUV; i++) {
- MTFace *texface = CustomData_get_layer_n(fdata, CD_MTFACE, i);
- const MLoopUV *mloopuv = CustomData_get_layer_n(ldata, CD_MLOOPUV, i);
-
- for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
- pidx++, lidx++, findex++, texface++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- copy_v2_v2(texface->uv[j], mloopuv[(*lidx)[j]].uv);
- }
- }
- }
-
- for (i = 0; i < numCol; i++) {
- MCol(*mcol)[4] = CustomData_get_layer_n(fdata, CD_MCOL, i);
- const MLoopCol *mloopcol = CustomData_get_layer_n(ldata, CD_PROP_BYTE_COLOR, i);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
- }
- }
- }
-
- if (hasPCol) {
- MCol(*mcol)[4] = CustomData_get_layer(fdata, CD_PREVIEW_MCOL);
- const MLoopCol *mloopcol = CustomData_get_layer(ldata, CD_PREVIEW_MLOOPCOL);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, mcol++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- MESH_MLOOPCOL_TO_MCOL(&mloopcol[(*lidx)[j]], &(*mcol)[j]);
- }
- }
- }
-
- if (hasOrigSpace) {
- OrigSpaceFace *of = CustomData_get_layer(fdata, CD_ORIGSPACE);
- const OrigSpaceLoop *lof = CustomData_get_layer(ldata, CD_ORIGSPACE_MLOOP);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, of++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- copy_v2_v2(of->uv[j], lof[(*lidx)[j]].uv);
- }
- }
- }
-
- if (hasLoopNormal) {
- short(*fnors)[4][3] = CustomData_get_layer(fdata, CD_TESSLOOPNORMAL);
- const float(*lnors)[3] = CustomData_get_layer(ldata, CD_NORMAL);
-
- for (findex = 0, lidx = loopindices; findex < num_faces; lidx++, findex++, fnors++) {
- for (j = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3; j--;) {
- normal_float_to_short_v3((*fnors)[j], lnors[(*lidx)[j]]);
- }
- }
- }
-
- if (hasLoopTangent) {
- /* Need to do for all UV maps at some point. */
- float(*ftangents)[4] = CustomData_get_layer(fdata, CD_TANGENT);
- const float(*ltangents)[4] = CustomData_get_layer(ldata, CD_TANGENT);
-
- for (findex = 0, pidx = polyindices, lidx = loopindices; findex < num_faces;
- pidx++, lidx++, findex++) {
- int nverts = (mface ? mface[findex].v4 : (*lidx)[3]) ? 4 : 3;
- for (j = nverts; j--;) {
- copy_v4_v4(ftangents[findex * 4 + j], ltangents[(*lidx)[j]]);
- }
- }
- }
-}
-
-int BKE_mesh_tessface_calc_ex(CustomData *fdata,
- CustomData *ldata,
- CustomData *pdata,
- MVert *mvert,
- int totface,
- int totloop,
- int totpoly)
-{
-#define USE_TESSFACE_SPEEDUP
-#define USE_TESSFACE_QUADS
-
-/* We abuse #MFace.edcode to tag quad faces. See below for details. */
-#define TESSFACE_IS_QUAD 1
-
- const int looptri_num = poly_to_tri_count(totpoly, totloop);
-
- const MPoly *mp, *mpoly;
- const MLoop *ml, *mloop;
- MFace *mface, *mf;
- MemArena *arena = NULL;
- int *mface_to_poly_map;
- uint(*lindices)[4];
- int poly_index, mface_index;
- uint j;
-
- mpoly = CustomData_get_layer(pdata, CD_MPOLY);
- mloop = CustomData_get_layer(ldata, CD_MLOOP);
-
- /* Allocate the length of `totfaces`, avoid many small reallocation's,
- * if all faces are triangles it will be correct, `quads == 2x` allocations. */
- /* Take care since memory is _not_ zeroed so be sure to initialize each field. */
- mface_to_poly_map = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface_to_poly_map), __func__);
- mface = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*mface), __func__);
- lindices = MEM_malloc_arrayN((size_t)looptri_num, sizeof(*lindices), __func__);
-
- mface_index = 0;
- mp = mpoly;
- for (poly_index = 0; poly_index < totpoly; poly_index++, mp++) {
- const uint mp_loopstart = (uint)mp->loopstart;
- const uint mp_totloop = (uint)mp->totloop;
- uint l1, l2, l3, l4;
- uint *lidx;
- if (mp_totloop < 3) {
- /* Do nothing. */
- }
-
-#ifdef USE_TESSFACE_SPEEDUP
-
-# define ML_TO_MF(i1, i2, i3) \
- mface_to_poly_map[mface_index] = poly_index; \
- mf = &mface[mface_index]; \
- lidx = lindices[mface_index]; \
- /* Set loop indices, transformed to vert indices later. */ \
- l1 = mp_loopstart + i1; \
- l2 = mp_loopstart + i2; \
- l3 = mp_loopstart + i3; \
- mf->v1 = mloop[l1].v; \
- mf->v2 = mloop[l2].v; \
- mf->v3 = mloop[l3].v; \
- mf->v4 = 0; \
- lidx[0] = l1; \
- lidx[1] = l2; \
- lidx[2] = l3; \
- lidx[3] = 0; \
- mf->mat_nr = mp->mat_nr; \
- mf->flag = mp->flag; \
- mf->edcode = 0; \
- (void)0
-
-/* ALMOST IDENTICAL TO DEFINE ABOVE (see EXCEPTION) */
-# define ML_TO_MF_QUAD() \
- mface_to_poly_map[mface_index] = poly_index; \
- mf = &mface[mface_index]; \
- lidx = lindices[mface_index]; \
- /* Set loop indices, transformed to vert indices later. */ \
- l1 = mp_loopstart + 0; /* EXCEPTION */ \
- l2 = mp_loopstart + 1; /* EXCEPTION */ \
- l3 = mp_loopstart + 2; /* EXCEPTION */ \
- l4 = mp_loopstart + 3; /* EXCEPTION */ \
- mf->v1 = mloop[l1].v; \
- mf->v2 = mloop[l2].v; \
- mf->v3 = mloop[l3].v; \
- mf->v4 = mloop[l4].v; \
- lidx[0] = l1; \
- lidx[1] = l2; \
- lidx[2] = l3; \
- lidx[3] = l4; \
- mf->mat_nr = mp->mat_nr; \
- mf->flag = mp->flag; \
- mf->edcode = TESSFACE_IS_QUAD; \
- (void)0
-
- else if (mp_totloop == 3) {
- ML_TO_MF(0, 1, 2);
- mface_index++;
- }
- else if (mp_totloop == 4) {
-# ifdef USE_TESSFACE_QUADS
- ML_TO_MF_QUAD();
- mface_index++;
-# else
- ML_TO_MF(0, 1, 2);
- mface_index++;
- ML_TO_MF(0, 2, 3);
- mface_index++;
-# endif
- }
-#endif /* USE_TESSFACE_SPEEDUP */
- else {
- const float *co_curr, *co_prev;
-
- float normal[3];
-
- float axis_mat[3][3];
- float(*projverts)[2];
- uint(*tris)[3];
-
- const uint totfilltri = mp_totloop - 2;
-
- if (UNLIKELY(arena == NULL)) {
- arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- }
-
- tris = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)totfilltri);
- projverts = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)mp_totloop);
-
- zero_v3(normal);
-
- /* Calculate the normal, flipped: to get a positive 2D cross product. */
- ml = mloop + mp_loopstart;
- co_prev = mvert[ml[mp_totloop - 1].v].co;
- for (j = 0; j < mp_totloop; j++, ml++) {
- co_curr = mvert[ml->v].co;
- add_newell_cross_v3_v3v3(normal, co_prev, co_curr);
- co_prev = co_curr;
- }
- if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
- normal[2] = 1.0f;
- }
-
- /* Project verts to 2D. */
- axis_dominant_v3_to_m3_negate(axis_mat, normal);
-
- ml = mloop + mp_loopstart;
- for (j = 0; j < mp_totloop; j++, ml++) {
- mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
- }
-
- BLI_polyfill_calc_arena(projverts, mp_totloop, 1, tris, arena);
-
- /* Apply fill. */
- for (j = 0; j < totfilltri; j++) {
- uint *tri = tris[j];
- lidx = lindices[mface_index];
-
- mface_to_poly_map[mface_index] = poly_index;
- mf = &mface[mface_index];
-
- /* Set loop indices, transformed to vert indices later. */
- l1 = mp_loopstart + tri[0];
- l2 = mp_loopstart + tri[1];
- l3 = mp_loopstart + tri[2];
-
- mf->v1 = mloop[l1].v;
- mf->v2 = mloop[l2].v;
- mf->v3 = mloop[l3].v;
- mf->v4 = 0;
-
- lidx[0] = l1;
- lidx[1] = l2;
- lidx[2] = l3;
- lidx[3] = 0;
-
- mf->mat_nr = mp->mat_nr;
- mf->flag = mp->flag;
- mf->edcode = 0;
-
- mface_index++;
- }
-
- BLI_memarena_clear(arena);
- }
- }
-
- if (arena) {
- BLI_memarena_free(arena);
- arena = NULL;
- }
-
- CustomData_free(fdata, totface);
- totface = mface_index;
-
- BLI_assert(totface <= looptri_num);
-
- /* Not essential but without this we store over-allocated memory in the #CustomData layers. */
- if (LIKELY(looptri_num != totface)) {
- mface = MEM_reallocN(mface, sizeof(*mface) * (size_t)totface);
- mface_to_poly_map = MEM_reallocN(mface_to_poly_map,
- sizeof(*mface_to_poly_map) * (size_t)totface);
- }
-
- CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
-
- /* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons
- * they are directly tessellated from. */
- CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface);
- CustomData_from_bmeshpoly(fdata, ldata, totface);
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * Polygons take care of their loops ordering, hence not of their vertices ordering.
- * Currently, our tfaces' fourth vertex index might be 0 even for a quad.
- * However, we know our fourth loop index is never 0 for quads
- * (because they are sorted for polygons, and our quads are still mere copies of their polygons).
- * So we pass NULL as MFace pointer, and #mesh_loops_to_tessdata
- * will use the fourth loop index as quad test. */
- mesh_loops_to_tessdata(fdata, ldata, NULL, mface_to_poly_map, lindices, totface);
-
- /* NOTE: quad detection issue - fourth vertidx vs fourth loopidx:
- * ...However, most TFace code uses 'MFace->v4 == 0' test to check whether it is a tri or quad.
- * BKE_mesh_mface_index_validate() will check this and rotate the tessellated face if needed.
- */
-#ifdef USE_TESSFACE_QUADS
- mf = mface;
- for (mface_index = 0; mface_index < totface; mface_index++, mf++) {
- if (mf->edcode == TESSFACE_IS_QUAD) {
- BKE_mesh_mface_index_validate(mf, fdata, mface_index, 4);
- mf->edcode = 0;
- }
- }
-#endif
-
- MEM_freeN(lindices);
-
- return totface;
-
-#undef USE_TESSFACE_SPEEDUP
-#undef USE_TESSFACE_QUADS
-
-#undef ML_TO_MF
-#undef ML_TO_MF_QUAD
-}
-
-void BKE_mesh_tessface_calc(Mesh *mesh)
-{
- mesh->totface = BKE_mesh_tessface_calc_ex(&mesh->fdata,
- &mesh->ldata,
- &mesh->pdata,
- mesh->mvert,
- mesh->totface,
- mesh->totloop,
- mesh->totpoly);
-
- BKE_mesh_update_customdata_pointers(mesh, true);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Loop Tessellation
*
* Fill in #MLoopTri data-structure.
diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index d16f7eaf588..9b2697ecc84 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -926,7 +926,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
static bool mesh_validate_customdata(CustomData *data,
- CustomDataMask mask,
+ eCustomDataMask mask,
const uint totitems,
const bool do_verbose,
const bool do_fixes,
@@ -953,7 +953,7 @@ static bool mesh_validate_customdata(CustomData *data,
}
if (mask != 0) {
- CustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type);
+ eCustomDataMask layer_typemask = CD_TYPE_AS_MASK(layer->type);
if ((layer_typemask & mask) == 0) {
PRINT_ERR("\tCustomDataLayer type %d which isn't in the mask\n", layer->type);
ok = false;
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc
index c505a74724b..0b61b876abe 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.cc
+++ b/source/blender/blenkernel/intern/mesh_wrapper.cc
@@ -103,11 +103,7 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
/* Must isolate multithreaded tasks while holding a mutex lock. */
blender::threading::isolate_task([&]() {
- const eMeshWrapperType geom_type_orig = static_cast<eMeshWrapperType>(
- me->runtime.wrapper_type);
- me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
-
- switch (geom_type_orig) {
+ switch (static_cast<eMeshWrapperType>(me->runtime.wrapper_type)) {
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: {
break; /* Quiet warning. */
@@ -132,7 +128,7 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
* There is also a performance aspect, where this also assumes that original indices are
* always needed when converting an edit mesh to a mesh. That might be wrong, but it's not
* harmful. */
- BKE_mesh_ensure_default_orig_index_customdata(me);
+ BKE_mesh_ensure_default_orig_index_customdata_no_check(me);
EditMeshData *edit_data = me->runtime.edit_data;
if (edit_data->vertexCos) {
@@ -144,8 +140,12 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
}
if (me->runtime.wrapper_type_finalize) {
- BKE_mesh_wrapper_deferred_finalize(me, &me->runtime.cd_mask_extra);
+ BKE_mesh_wrapper_deferred_finalize_mdata(me, &me->runtime.cd_mask_extra);
}
+
+ /* Keep type assignment last, so that read-only access only uses the mdata code paths after all
+ * the underlying data has been initialized. */
+ me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
});
BLI_mutex_unlock(mesh_eval_mutex);
@@ -307,10 +307,10 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
/** \name CPU Subdivision Evaluation
* \{ */
-static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
+static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me)
{
- SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob);
- if (!smd) {
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)me->runtime.subsurf_runtime_data;
+ if (runtime_data == nullptr || runtime_data->settings.level == 0) {
return me;
}
@@ -318,29 +318,19 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
* 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;
+ mesh_settings.resolution = runtime_data->resolution;
+ mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
if (mesh_settings.resolution < 3) {
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) {
- return me;
- }
-
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, me, false);
if (subdiv == nullptr) {
/* Happens on bad topology, but also on empty input mesh. */
return me;
}
- const bool use_clnors = BKE_subsurf_modifier_use_custom_loop_normals(smd, me);
+ const bool use_clnors = runtime_data->use_loop_normals;
if (use_clnors) {
/* If custom normals are present and the option is turned on calculate the split
* normals and clear flag so the normals get interpolated to the result mesh. */
@@ -358,7 +348,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
CustomData_set_layer_flag(&me->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
CustomData_set_layer_flag(&subdiv_mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
- else if (me->runtime.subsurf_do_loop_normals) {
+ else if (runtime_data->calc_loop_normals) {
BKE_mesh_calc_normals_split(subdiv_mesh);
}
@@ -377,7 +367,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
return me->runtime.mesh_eval;
}
-Mesh *BKE_mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
+Mesh *BKE_mesh_wrapper_ensure_subdivision(Mesh *me)
{
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
BLI_mutex_lock(mesh_eval_mutex);
@@ -390,7 +380,7 @@ Mesh *BKE_mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
Mesh *result;
/* Must isolate multithreaded tasks while holding a mutex lock. */
- blender::threading::isolate_task([&]() { result = mesh_wrapper_ensure_subdivision(ob, me); });
+ blender::threading::isolate_task([&]() { result = mesh_wrapper_ensure_subdivision(me); });
BLI_mutex_unlock(mesh_eval_mutex);
return result;
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 6348d83362e..01eb4970f7e 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -456,6 +456,40 @@ 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);
}
+void BKE_modifier_set_warning(const struct Object *ob,
+ struct ModifierData *md,
+ const char *_format,
+ ...)
+{
+ char buffer[512];
+ va_list ap;
+ const char *format = TIP_(_format);
+
+ va_start(ap, _format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ /* Store the warning in the same field as the error.
+ * It is not expected to have both error and warning and having a single place to store the
+ * message simplifies interface code. */
+
+ if (md->error) {
+ MEM_freeN(md->error);
+ }
+
+ md->error = BLI_strdup(buffer);
+
+#ifndef NDEBUG
+ if ((md->mode & eModifierMode_Virtual) == 0) {
+ /* Ensure correct object is passed in. */
+ BLI_assert(BKE_modifier_get_original(ob, md) != NULL);
+ }
+#endif
+
+ UNUSED_VARS_NDEBUG(ob);
+}
+
int BKE_modifiers_get_cage_index(const Scene *scene,
Object *ob,
int *r_lastPossibleCageIndex,
@@ -1001,8 +1035,7 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
/* end modifier callback wrappers */
-Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval,
- const bool get_cage_mesh)
+Mesh *BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
{
Mesh *me = NULL;
@@ -1011,17 +1044,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) {
- 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;
+ me = BKE_object_get_editmesh_eval_final(ob_eval);
}
}
if (me == NULL) {
- me = (get_cage_mesh && ob_eval->runtime.mesh_deform_eval != NULL) ?
- ob_eval->runtime.mesh_deform_eval :
- BKE_object_get_evaluated_mesh(ob_eval);
+ me = BKE_object_get_evaluated_mesh(ob_eval);
}
return me;
diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.c b/source/blender/blenkernel/intern/multires_reshape_apply_base.c
index 837b64affa8..f7d29806353 100644
--- a/source/blender/blenkernel/intern/multires_reshape_apply_base.c
+++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.c
@@ -156,7 +156,7 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
/* Vertices were moved around, need to update normals after all the vertices are updated
* Probably this is possible to do in the loop above, but this is rather tricky because
* we don't know all needed vertices' coordinates there yet. */
- BKE_mesh_normals_tag_dirty(base_mesh);
+ BKE_mesh_tag_coords_changed(base_mesh);
}
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context)
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index a5f6c453ed4..9457c20eb7d 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -244,27 +244,50 @@ void BKE_nla_tracks_copy(Main *bmain, ListBase *dst, const ListBase *src, const
}
}
-static void update_active_strip_from_listbase(AnimData *adt_dest,
- NlaTrack *track_dest,
- const NlaStrip *active_strip,
- const ListBase /* NlaStrip */ *strips_source)
+/**
+ * Find `active_strip` in `strips_source`, then return the strip with the same
+ * index from `strips_dest`.
+ */
+static NlaStrip *find_active_strip_from_listbase(const NlaStrip *active_strip,
+ const ListBase /* NlaStrip */ *strips_source,
+ const ListBase /* NlaStrip */ *strips_dest)
{
- NlaStrip *strip_dest = track_dest->strips.first;
+ BLI_assert_msg(BLI_listbase_count(strips_source) == BLI_listbase_count(strips_dest),
+ "Expecting the same number of source and destination strips");
+
+ NlaStrip *strip_dest = strips_dest->first;
LISTBASE_FOREACH (const NlaStrip *, strip_source, strips_source) {
- if (strip_source == active_strip) {
- adt_dest->actstrip = strip_dest;
- return;
+ if (strip_dest == NULL) {
+ /* The tracks are assumed to have an equal number of strips, but this is
+ * not the case. Not sure when this might happen, but it's better to not
+ * crash. */
+ break;
}
-
- if (strip_source->type == NLASTRIP_TYPE_META) {
- update_active_strip_from_listbase(adt_dest, track_dest, active_strip, &strip_source->strips);
+ if (strip_source == active_strip) {
+ return strip_dest;
+ }
+
+ const bool src_is_meta = strip_source->type == NLASTRIP_TYPE_META;
+ const bool dst_is_meta = strip_dest->type == NLASTRIP_TYPE_META;
+ BLI_assert_msg(src_is_meta == dst_is_meta,
+ "Expecting topology of source and destination strips to be equal");
+ if (src_is_meta && dst_is_meta) {
+ NlaStrip *found_in_meta = find_active_strip_from_listbase(
+ active_strip, &strip_source->strips, &strip_dest->strips);
+ if (found_in_meta != NULL) {
+ return found_in_meta;
+ }
}
strip_dest = strip_dest->next;
}
+
+ return NULL;
}
-/* Set adt_dest->actstrip to the strip with the same index as adt_source->actstrip. */
+/* Set adt_dest->actstrip to the strip with the same index as
+ * adt_source->actstrip. Note that this always sets `adt_dest->actstrip`; sets
+ * to NULL when `adt_source->actstrip` cannot be found. */
static void update_active_strip(AnimData *adt_dest,
NlaTrack *track_dest,
const AnimData *adt_source,
@@ -272,13 +295,20 @@ static void update_active_strip(AnimData *adt_dest,
{
BLI_assert(BLI_listbase_count(&track_source->strips) == BLI_listbase_count(&track_dest->strips));
- update_active_strip_from_listbase(
- adt_dest, track_dest, adt_source->actstrip, &track_source->strips);
+ NlaStrip *active_strip = find_active_strip_from_listbase(
+ adt_source->actstrip, &track_source->strips, &track_dest->strips);
+ adt_dest->actstrip = active_strip;
}
/* Set adt_dest->act_track to the track with the same index as adt_source->act_track. */
static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
{
+ adt_dest->act_track = NULL;
+ adt_dest->actstrip = NULL;
+ if (adt_source->act_track == NULL && adt_source->actstrip == NULL) {
+ return;
+ }
+
BLI_assert(BLI_listbase_count(&adt_source->nla_tracks) ==
BLI_listbase_count(&adt_dest->nla_tracks));
@@ -287,7 +317,11 @@ static void update_active_track(AnimData *adt_dest, const AnimData *adt_source)
if (track_source == adt_source->act_track) {
adt_dest->act_track = track_dest;
}
- update_active_strip(adt_dest, track_dest, adt_source, track_source);
+
+ /* Only search for the active strip if it hasn't been found yet. */
+ if (adt_dest->actstrip == NULL && adt_source->actstrip != NULL) {
+ update_active_strip(adt_dest, track_dest, adt_source, track_source);
+ }
track_dest = track_dest->next;
}
@@ -1205,6 +1239,40 @@ static NlaStrip *nlastrip_find_active(ListBase /* NlaStrip */ *strips)
return NULL;
}
+float BKE_nlastrip_compute_frame_from_previous_strip(NlaStrip *strip)
+{
+ float limit_prev = MINFRAMEF;
+
+ /* Find the previous end frame, with a special case if the previous strip was a transition : */
+ if (strip->prev) {
+ if (strip->prev->type == NLASTRIP_TYPE_TRANSITION) {
+ limit_prev = strip->prev->start + NLASTRIP_MIN_LEN_THRESH;
+ }
+ else {
+ limit_prev = strip->prev->end;
+ }
+ }
+
+ return limit_prev;
+}
+
+float BKE_nlastrip_compute_frame_to_next_strip(NlaStrip *strip)
+{
+ float limit_next = MAXFRAMEF;
+
+ /* Find the next begin frame, with a special case if the next strip's a transition : */
+ if (strip->next) {
+ if (strip->next->type == NLASTRIP_TYPE_TRANSITION) {
+ limit_next = strip->next->end - NLASTRIP_MIN_LEN_THRESH;
+ }
+ else {
+ limit_next = strip->next->start;
+ }
+ }
+
+ return limit_next;
+}
+
NlaStrip *BKE_nlastrip_find_active(NlaTrack *nlt)
{
if (nlt == NULL) {
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index cf3b4f7bdf2..c6f140b9260 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -60,6 +60,7 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "RNA_access.h"
@@ -94,6 +95,9 @@ using blender::Stack;
using blender::StringRef;
using blender::Vector;
using blender::VectorSet;
+using blender::bke::bNodeRuntime;
+using blender::bke::bNodeSocketRuntime;
+using blender::bke::bNodeTreeRuntime;
using blender::nodes::FieldInferencingInterface;
using blender::nodes::InputSocketFieldType;
using blender::nodes::NodeDeclaration;
@@ -123,6 +127,7 @@ static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree,
static void ntree_init_data(ID *id)
{
bNodeTree *ntree = (bNodeTree *)id;
+ ntree->runtime = MEM_new<bNodeTreeRuntime>(__func__);
ntree_set_typeinfo(ntree, nullptr);
}
@@ -134,6 +139,8 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
/* We never handle usercount here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
+ ntree_dst->runtime = MEM_new<bNodeTreeRuntime>(__func__);
+
/* in case a running nodetree is copied */
ntree_dst->execdata = nullptr;
@@ -203,9 +210,9 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
/* node tree will generate its own interface type */
ntree_dst->interface_type = nullptr;
- if (ntree_src->field_inferencing_interface) {
- ntree_dst->field_inferencing_interface = new FieldInferencingInterface(
- *ntree_src->field_inferencing_interface);
+ if (ntree_src->runtime->field_inferencing_interface) {
+ ntree_dst->runtime->field_inferencing_interface = std::make_unique<FieldInferencingInterface>(
+ *ntree_src->runtime->field_inferencing_interface);
}
if (flag & LIB_ID_COPY_NO_PREVIEW) {
@@ -258,8 +265,6 @@ static void ntree_free_data(ID *id)
MEM_freeN(sock);
}
- delete ntree->field_inferencing_interface;
-
/* free preview hash */
if (ntree->previews) {
BKE_node_instance_hash_free(ntree->previews, (bNodeInstanceValueFP)BKE_node_preview_free);
@@ -270,6 +275,7 @@ static void ntree_free_data(ID *id)
}
BKE_previewimg_free(&ntree->preview);
+ MEM_delete(ntree->runtime);
}
static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock)
@@ -658,7 +664,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock)
BLO_read_data_address(reader, &sock->default_attribute_name);
sock->total_inputs = 0; /* Clear runtime data set before drawing. */
sock->cache = nullptr;
- sock->declaration = nullptr;
+ sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
}
void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
@@ -670,9 +676,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->progress = nullptr;
ntree->execdata = nullptr;
- ntree->runtime_flag = 0;
-
- ntree->field_inferencing_interface = nullptr;
+ ntree->runtime = MEM_new<bNodeTreeRuntime>(__func__);
BKE_ntree_update_tag_missing_runtime_data(ntree);
BLO_read_data_address(reader, &ntree->adt);
@@ -680,8 +684,8 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
BLO_read_list(reader, &ntree->nodes);
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ node->runtime = MEM_new<bNodeRuntime>(__func__);
node->typeinfo = nullptr;
- node->declaration = nullptr;
BLO_read_list(reader, &node->inputs);
BLO_read_list(reader, &node->outputs);
@@ -1512,6 +1516,7 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier));
bNodeSocket *sock = MEM_cnew<bNodeSocket>("sock");
+ sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
sock->in_out = in_out;
BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR);
@@ -1917,6 +1922,7 @@ static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
}
MEM_freeN(sock->default_value);
}
+ MEM_delete(sock->runtime);
}
void nodeRemoveSocket(bNodeTree *ntree, bNode *node, bNodeSocket *sock)
@@ -2122,6 +2128,7 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node)
bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname)
{
bNode *node = MEM_cnew<bNode>("new node");
+ node->runtime = MEM_new<bNodeRuntime>(__func__);
BLI_addtail(&ntree->nodes, node);
BLI_strncpy(node->idname, idname, sizeof(node->idname));
@@ -2159,6 +2166,7 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, const int flag)
{
+ sock_dst->runtime = MEM_new<bNodeSocketRuntime>(__func__);
if (sock_src->prop) {
sock_dst->prop = IDP_CopyProperty_ex(sock_src->prop, flag);
}
@@ -2191,6 +2199,8 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree,
bNode *node_dst = (bNode *)MEM_mallocN(sizeof(bNode), __func__);
*node_dst = node_src;
+ node_dst->runtime = MEM_new<bNodeRuntime>(__func__);
+
/* Can be called for nodes outside a node tree (e.g. clipboard). */
if (dst_tree) {
if (unique_name) {
@@ -2251,7 +2261,6 @@ bNode *node_copy_with_mapping(bNodeTree *dst_tree,
}
/* Reset the declaration of the new node. */
- node_dst->declaration = nullptr;
nodeDeclarationEnsure(dst_tree, node_dst);
return node_dst;
@@ -2668,6 +2677,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
flag |= LIB_ID_CREATE_NO_MAIN;
}
bNodeTree *ntree = (bNodeTree *)BKE_libblock_alloc(bmain, ID_NT, name, flag);
+ BKE_libblock_init_empty(&ntree->id);
if (is_embedded) {
ntree->id.flag |= LIB_EMBEDDED_DATA;
}
@@ -2969,9 +2979,10 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
}
if (node->typeinfo->declaration_is_dynamic) {
- delete node->declaration;
+ delete node->runtime->declaration;
}
+ MEM_delete(node->runtime);
MEM_freeN(node);
if (ntree) {
@@ -3063,6 +3074,7 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree),
}
MEM_freeN(sock->default_value);
}
+ MEM_delete(sock->runtime);
}
static void free_localized_node_groups(bNodeTree *ntree)
@@ -3289,6 +3301,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
}
bNodeSocket *sock = MEM_cnew<bNodeSocket>("socket template");
+ sock->runtime = MEM_new<bNodeSocketRuntime>(__func__);
BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
sock->in_out = in_out;
sock->type = SOCK_CUSTOM; /* int type undefined by default */
@@ -3676,34 +3689,34 @@ static void update_socket_declarations(ListBase *sockets,
int index;
LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) {
const SocketDeclaration &socket_decl = *declarations[index];
- socket->declaration = &socket_decl;
+ socket->runtime->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());
+ BLI_assert(node->runtime->declaration != nullptr);
+ update_socket_declarations(&node->inputs, node->runtime->declaration->inputs());
+ update_socket_declarations(&node->outputs, node->runtime->declaration->outputs());
}
bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node)
{
- if (node->declaration != nullptr) {
+ if (node->runtime->declaration != nullptr) {
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->runtime->declaration = new blender::nodes::NodeDeclaration();
+ blender::nodes::NodeDeclarationBuilder builder{*node->runtime->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;
+ node->runtime->declaration = node->typeinfo->fixed_declaration;
}
return true;
}
@@ -4736,6 +4749,7 @@ static void registerGeometryNodes()
register_node_type_geo_curve_to_mesh();
register_node_type_geo_curve_to_points();
register_node_type_geo_curve_trim();
+ register_node_type_geo_deform_curves_on_surface();
register_node_type_geo_delete_geometry();
register_node_type_geo_duplicate_elements();
register_node_type_geo_distribute_points_on_faces();
@@ -4743,6 +4757,7 @@ static void registerGeometryNodes()
register_node_type_geo_edge_split();
register_node_type_geo_extrude_mesh();
register_node_type_geo_field_at_index();
+ register_node_type_geo_field_on_domain();
register_node_type_geo_flip_faces();
register_node_type_geo_geometry_to_instance();
register_node_type_geo_image_texture();
@@ -4751,6 +4766,8 @@ static void registerGeometryNodes()
register_node_type_geo_input_curve_tilt();
register_node_type_geo_input_id();
register_node_type_geo_input_index();
+ register_node_type_geo_input_instance_rotation();
+ register_node_type_geo_input_instance_scale();
register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
register_node_type_geo_input_mesh_edge_angle();
@@ -4788,7 +4805,9 @@ static void registerGeometryNodes()
register_node_type_geo_mesh_subdivide();
register_node_type_geo_mesh_to_curve();
register_node_type_geo_mesh_to_points();
+ register_node_type_geo_mesh_to_volume();
register_node_type_geo_object_info();
+ register_node_type_geo_points();
register_node_type_geo_points_to_vertices();
register_node_type_geo_points_to_volume();
register_node_type_geo_proximity();
@@ -4821,7 +4840,10 @@ static void registerGeometryNodes()
register_node_type_geo_translate_instances();
register_node_type_geo_triangulate();
register_node_type_geo_viewer();
+ register_node_type_geo_volume_cube();
register_node_type_geo_volume_to_mesh();
+ register_node_type_geo_uv_pack_islands();
+ register_node_type_geo_uv_unwrap();
}
static void registerFunctionNodes()
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
index 68e4cccba00..019ab114b83 100644
--- a/source/blender/blenkernel/intern/node_tree_update.cc
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -15,6 +15,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "MOD_nodes.h"
@@ -48,19 +49,19 @@ enum eNodeTreeChangedFlag {
static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag)
{
- ntree->changed_flag |= flag;
+ ntree->runtime->changed_flag |= flag;
}
static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag)
{
add_tree_tag(ntree, flag);
- node->changed_flag |= flag;
+ node->runtime->changed_flag |= flag;
}
static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag)
{
add_tree_tag(ntree, flag);
- socket->changed_flag |= flag;
+ socket->runtime->changed_flag |= flag;
}
namespace blender::bke {
@@ -172,11 +173,11 @@ static FieldInferencingInterface get_node_field_inferencing_interface(const Node
/* 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) {
+ if (!group->runtime->field_inferencing_interface) {
/* This shouldn't happen because referenced node groups should always be updated first. */
BLI_assert_unreachable();
}
- return *group->field_inferencing_interface;
+ return *group->runtime->field_inferencing_interface;
}
FieldInferencingInterface inferencing_interface;
@@ -551,7 +552,8 @@ 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();
+ std::unique_ptr<FieldInferencingInterface> new_inferencing_interface =
+ std::make_unique<FieldInferencingInterface>();
new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
InputSocketFieldType::IsSupported);
new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
@@ -567,11 +569,10 @@ static bool update_field_inferencing(const NodeTreeRef &tree)
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 !=
+ const bool group_interface_changed = !btree.runtime->field_inferencing_interface ||
+ *btree.runtime->field_inferencing_interface !=
*new_inferencing_interface;
- delete btree.field_inferencing_interface;
- btree.field_inferencing_interface = new_inferencing_interface;
+ btree.runtime->field_inferencing_interface = std::move(new_inferencing_interface);
return group_interface_changed;
}
@@ -799,7 +800,7 @@ class NodeTreeMainUpdater {
{
Vector<bNodeTree *> changed_ntrees;
FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
- if (ntree->changed_flag != NTREE_CHANGED_NOTHING) {
+ if (ntree->runtime->changed_flag != NTREE_CHANGED_NOTHING) {
changed_ntrees.append(ntree);
}
}
@@ -817,7 +818,7 @@ class NodeTreeMainUpdater {
if (root_ntrees.size() == 1) {
bNodeTree *ntree = root_ntrees[0];
- if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ if (ntree->runtime->changed_flag == NTREE_CHANGED_NOTHING) {
return;
}
const TreeUpdateResult result = this->update_tree(*ntree);
@@ -830,7 +831,7 @@ class NodeTreeMainUpdater {
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) {
+ if (ntree->runtime->changed_flag == NTREE_CHANGED_NOTHING) {
continue;
}
if (!update_result_by_tree_.contains(ntree)) {
@@ -1002,7 +1003,8 @@ class NodeTreeMainUpdater {
ntreeTexCheckCyclics(&ntree);
}
- if (ntree.changed_flag & NTREE_CHANGED_INTERFACE || ntree.changed_flag & NTREE_CHANGED_ANY) {
+ if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE ||
+ ntree.runtime->changed_flag & NTREE_CHANGED_ANY) {
result.interface_changed = true;
}
@@ -1057,18 +1059,18 @@ class NodeTreeMainUpdater {
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;
+ const uint32_t old_changed_flag = ntree.runtime->changed_flag;
+ ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING;
- /* This may set #ntree.changed_flag which is detected below. */
+ /* This may set #ntree.runtime->changed_flag which is detected below. */
this->update_individual_node(node);
- if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ if (ntree.runtime->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;
+ ntree.runtime->changed_flag |= old_changed_flag;
}
}
}
@@ -1077,13 +1079,13 @@ class NodeTreeMainUpdater {
{
bNodeTree &ntree = *node.btree();
bNode &bnode = *node.bnode();
- if (ntree.changed_flag & NTREE_CHANGED_ANY) {
+ if (ntree.runtime->changed_flag & NTREE_CHANGED_ANY) {
return true;
}
- if (bnode.changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
+ if (bnode.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
return true;
}
- if (ntree.changed_flag & NTREE_CHANGED_LINK) {
+ if (ntree.runtime->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()) {
@@ -1101,7 +1103,7 @@ class NodeTreeMainUpdater {
return true;
}
}
- if (ntree.changed_flag & NTREE_CHANGED_INTERFACE) {
+ if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) {
if (node.is_group_input_node() || node.is_group_output_node()) {
return true;
}
@@ -1232,16 +1234,16 @@ class NodeTreeMainUpdater {
}
/* 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;
+ const uint32_t old_changed_flag = ntree.runtime->changed_flag;
+ ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING;
ntree.typeinfo->update(&ntree);
- if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) {
/* The tree ref is outdated and needs to be rebuilt. */
tree_ref.reset();
}
- ntree.changed_flag |= old_changed_flag;
+ ntree.runtime->changed_flag |= old_changed_flag;
}
void remove_unused_previews_when_necessary(bNodeTree &ntree)
@@ -1250,7 +1252,7 @@ class NodeTreeMainUpdater {
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) {
+ if ((ntree.runtime->changed_flag & allowed_flags) == ntree.runtime->changed_flag) {
return;
}
BKE_node_preview_remove_unused(&ntree);
@@ -1259,7 +1261,7 @@ class NodeTreeMainUpdater {
void propagate_runtime_flags(const NodeTreeRef &tree_ref)
{
bNodeTree &ntree = *tree_ref.btree();
- ntree.runtime_flag = 0;
+ ntree.runtime->runtime_flag = 0;
if (ntree.type != NTREE_SHADER) {
return;
}
@@ -1268,7 +1270,7 @@ class NodeTreeMainUpdater {
for (const NodeRef *group_node : tree_ref.nodes_by_type("NodeGroup")) {
const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->bnode()->id);
if (group != nullptr) {
- ntree.runtime_flag |= group->runtime_flag;
+ ntree.runtime->runtime_flag |= group->runtime->runtime_flag;
}
}
/* Check if the tree itself has an animated image. */
@@ -1276,7 +1278,7 @@ class NodeTreeMainUpdater {
for (const NodeRef *node : tree_ref.nodes_by_type(idname)) {
Image *image = reinterpret_cast<Image *>(node->bnode()->id);
if (image != nullptr && BKE_image_is_animated(image)) {
- ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
+ ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION;
break;
}
}
@@ -1288,7 +1290,7 @@ class NodeTreeMainUpdater {
"ShaderNodeOutputAOV"}) {
const Span<const NodeRef *> nodes = tree_ref.nodes_by_type(idname);
if (!nodes.is_empty()) {
- ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT;
+ ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT;
break;
}
}
@@ -1323,12 +1325,12 @@ class NodeTreeMainUpdater {
/* 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. */
+ * #btree.runtime.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 old_topology_hash = btree.runtime->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;
+ btree.runtime->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
@@ -1352,7 +1354,7 @@ class NodeTreeMainUpdater {
}
}
- if (btree.changed_flag & NTREE_CHANGED_ANY) {
+ if (btree.runtime->changed_flag & NTREE_CHANGED_ANY) {
return true;
}
@@ -1361,8 +1363,8 @@ class NodeTreeMainUpdater {
}
/* 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 (btree.runtime->changed_flag ==
+ (btree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) {
if (old_topology_hash == new_topology_hash) {
return false;
}
@@ -1404,7 +1406,7 @@ class NodeTreeMainUpdater {
if (bnode.type == NODE_GROUP) {
const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(bnode.id);
if (node_group != nullptr &&
- node_group->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) {
+ node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) {
return true;
}
}
@@ -1540,12 +1542,12 @@ class NodeTreeMainUpdater {
const NodeRef &node = in_out_socket.node();
const bNode &bnode = *node.bnode();
const bNodeSocket &bsocket = *in_out_socket.bsocket();
- if (bsocket.changed_flag != NTREE_CHANGED_NOTHING) {
+ if (bsocket.runtime->changed_flag != NTREE_CHANGED_NOTHING) {
return true;
}
- if (bnode.changed_flag != NTREE_CHANGED_NOTHING) {
+ if (bnode.runtime->changed_flag != NTREE_CHANGED_NOTHING) {
const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 &&
- bnode.changed_flag ==
+ bnode.runtime->changed_flag ==
NTREE_CHANGED_INTERNAL_LINK;
if (!only_unused_internal_link_changed) {
return true;
@@ -1591,15 +1593,15 @@ class NodeTreeMainUpdater {
void reset_changed_flags(bNodeTree &ntree)
{
- ntree.changed_flag = NTREE_CHANGED_NOTHING;
+ ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING;
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
- node->changed_flag = NTREE_CHANGED_NOTHING;
+ node->runtime->changed_flag = NTREE_CHANGED_NOTHING;
node->update = 0;
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- socket->changed_flag = NTREE_CHANGED_NOTHING;
+ socket->runtime->changed_flag = NTREE_CHANGED_NOTHING;
}
LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
- socket->changed_flag = NTREE_CHANGED_NOTHING;
+ socket->runtime->changed_flag = NTREE_CHANGED_NOTHING;
}
}
}
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 55b9951c52d..62ebb45b0ed 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -1402,6 +1402,7 @@ bool BKE_object_supports_modifiers(const Object *ob)
{
return (ELEM(ob->type,
OB_MESH,
+ OB_CURVES,
OB_CURVES_LEGACY,
OB_SURF,
OB_FONT,
@@ -2271,10 +2272,14 @@ Object *BKE_object_add(Main *bmain, ViewLayer *view_layer, int type, const char
Object *ob = object_add_common(bmain, view_layer, type, name);
LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer);
- BKE_collection_object_add(bmain, layer_collection->collection, ob);
+ BKE_collection_viewlayer_object_add(bmain, view_layer, layer_collection->collection, ob);
+ /* NOTE: There is no way to be sure that #BKE_collection_viewlayer_object_add will actually
+ * manage to find a valid collection in given `view_layer` to add the new object to. */
Base *base = BKE_view_layer_base_find(view_layer, ob);
- BKE_view_layer_base_select_and_set_active(view_layer, base);
+ if (base != nullptr) {
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+ }
return ob;
}
@@ -2479,21 +2484,16 @@ static void copy_object_pose(Object *obn, const Object *ob, const int flag)
* BKE_library_remap stuff, but...
* 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 = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == ob) {
ct->tar = obn;
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, false);
- }
+ BKE_constraint_targets_flush(con, &targets, false);
}
}
}
@@ -3986,6 +3986,70 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re
return true;
}
+bool BKE_object_minmax_empty_drawtype(const struct Object *ob, float r_min[3], float r_max[3])
+{
+ BLI_assert(ob->type == OB_EMPTY);
+ float3 min(0), max(0);
+
+ bool ok = false;
+ const float radius = ob->empty_drawsize;
+
+ switch (ob->empty_drawtype) {
+ case OB_ARROWS: {
+ max = float3(radius);
+ ok = true;
+ break;
+ }
+ case OB_PLAINAXES:
+ case OB_CUBE:
+ case OB_EMPTY_SPHERE: {
+ min = float3(-radius);
+ max = float3(radius);
+ ok = true;
+ break;
+ }
+ case OB_CIRCLE: {
+ max[0] = max[2] = radius;
+ min[0] = min[2] = -radius;
+ ok = true;
+ break;
+ }
+ case OB_SINGLE_ARROW: {
+ max[2] = radius;
+ ok = true;
+ break;
+ }
+ case OB_EMPTY_CONE: {
+ min = float3(-radius, 0.0f, -radius);
+ max = float3(radius, radius * 2.0f, radius);
+ ok = true;
+ break;
+ }
+ case OB_EMPTY_IMAGE: {
+ const float *ofs = ob->ima_ofs;
+ /* NOTE: this is the best approximation that can be calculated without loading the image. */
+ min[0] = ofs[0] * radius;
+ min[1] = ofs[1] * radius;
+ max[0] = radius + (ofs[0] * radius);
+ max[1] = radius + (ofs[1] * radius);
+ /* Since the image aspect can shrink the bounds towards the object origin,
+ * adjust the min/max to account for that. */
+ for (int i = 0; i < 2; i++) {
+ CLAMP_MAX(min[i], 0.0f);
+ CLAMP_MIN(max[i], 0.0f);
+ }
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok) {
+ copy_v3_v3(r_min, min);
+ copy_v3_v3(r_max, max);
+ }
+ return ok;
+}
+
bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -4319,7 +4383,7 @@ Mesh *BKE_object_get_evaluated_mesh(const Object *object)
}
if (object->data && GS(((const ID *)object->data)->name) == ID_ME) {
- mesh = BKE_mesh_wrapper_ensure_subdivision(object, mesh);
+ mesh = BKE_mesh_wrapper_ensure_subdivision(mesh);
}
return mesh;
@@ -5294,126 +5358,6 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot)
/** \name Object Modifier Utilities
* \{ */
-bool BKE_object_modifier_use_time(Scene *scene, Object *ob, ModifierData *md)
-{
- if (BKE_modifier_depends_ontime(scene, md)) {
- return true;
- }
-
- /* Check whether modifier is animated. */
- /* TODO: this should be handled as part of build_animdata() -- Aligorith */
- 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));
-
- char pattern[sizeof(md_name_esc) + 16];
- BLI_snprintf(pattern, sizeof(pattern), "modifiers[\"%s\"]", md_name_esc);
-
- /* action - check for F-Curves with paths containing 'modifiers[' */
- if (adt->action) {
- for (fcu = (FCurve *)adt->action->curves.first; fcu != nullptr; fcu = (FCurve *)fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
- return true;
- }
- }
- }
-
- /* This here allows modifier properties to get driven and still update properly
- *
- * Workaround to get T26764 (e.g. subsurf levels not updating when animated/driven)
- * 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 != nullptr; fcu = (FCurve *)fcu->next) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
- return true;
- }
- }
-
- /* XXX: also, should check NLA strips, though for now assume that nobody uses
- * that and we can omit that for performance reasons... */
- }
-
- return false;
-}
-
-bool BKE_object_modifier_gpencil_use_time(Object *ob, GpencilModifierData *md)
-{
- if (BKE_gpencil_modifier_depends_ontime(md)) {
- return true;
- }
-
- /* Check whether modifier is animated. */
- /* TODO(Aligorith): this should be handled as part of build_animdata() */
- if (ob->adt) {
- AnimData *adt = ob->adt;
-
- char md_name_esc[sizeof(md->name) * 2];
- BLI_str_escape(md_name_esc, md->name, sizeof(md_name_esc));
-
- char pattern[sizeof(md_name_esc) + 32];
- BLI_snprintf(pattern, sizeof(pattern), "grease_pencil_modifiers[\"%s\"]", md_name_esc);
-
- /* action - check for F-Curves with paths containing 'grease_pencil_modifiers[' */
- if (adt->action) {
- LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
- return true;
- }
- }
- }
-
- /* This here allows modifier properties to get driven and still update properly */
- LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool BKE_object_shaderfx_use_time(Object *ob, ShaderFxData *fx)
-{
- if (BKE_shaderfx_depends_ontime(fx)) {
- return true;
- }
-
- /* Check whether effect is animated. */
- /* TODO(Aligorith): this should be handled as part of build_animdata() */
- if (ob->adt) {
- AnimData *adt = ob->adt;
-
- char fx_name_esc[sizeof(fx->name) * 2];
- BLI_str_escape(fx_name_esc, fx->name, sizeof(fx_name_esc));
-
- char pattern[sizeof(fx_name_esc) + 32];
- BLI_snprintf(pattern, sizeof(pattern), "shader_effects[\"%s\"]", fx_name_esc);
-
- /* action - check for F-Curves with paths containing string[' */
- if (adt->action) {
- LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
- return true;
- }
- }
- }
-
- /* This here allows properties to get driven and still update properly */
- LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
- if (fcu->rna_path && strstr(fcu->rna_path, pattern)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
/**
* Set "ignore cache" flag for all caches on this object.
*/
@@ -5484,11 +5428,9 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* also update constraint targets */
LISTBASE_FOREACH (bConstraint *, con, &ob->constraints) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
+ if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar) {
BKE_object_modifier_update_subframe(
@@ -5496,9 +5438,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
}
}
/* free temp targets */
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, false);
- }
+ BKE_constraint_targets_flush(con, &targets, false);
}
}
}
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index f41d59c77ba..8ff02c7e698 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -130,11 +130,6 @@ void BKE_object_eval_transform_final(Depsgraph *depsgraph, Object *ob)
else {
ob->transflag &= ~OB_NEG_SCALE;
}
-
- /* Assign evaluated version. */
- if ((ob->type == OB_GPENCIL) && (ob->runtime.gpd_eval != NULL)) {
- ob->data = ob->runtime.gpd_eval;
- }
}
void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 4dc0130366e..dec9a594938 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -48,7 +48,7 @@ static float nextfr(RNG *rng, float min, float max)
static float gaussRand(RNG *rng)
{
/* NOTE: to avoid numerical problems with very small numbers, we make these variables
- * singe-precision floats, but later we call the double-precision log() and sqrt() functions
+ * single-precision floats, but later we call the double-precision log() and sqrt() functions
* instead of logf() and sqrtf(). */
float x;
float y;
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index cff7eb20b05..9b0d15ac702 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -996,6 +996,12 @@ bool BKE_paint_select_elem_test(Object *ob)
return (BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob));
}
+bool BKE_paint_always_hide_test(Object *ob)
+{
+ return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) &&
+ (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT));
+}
+
void BKE_paint_cavity_curve_preset(Paint *p, int preset)
{
CurveMapping *cumap = NULL;
@@ -1485,8 +1491,6 @@ void BKE_sculptsession_free(Object *ob)
BM_log_free(ss->bm_log);
}
- MEM_SAFE_FREE(ss->texcache);
-
if (ss->tex_pool) {
BKE_image_pool_free(ss->tex_pool);
}
@@ -1615,7 +1619,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
Mesh *me_eval,
bool need_pmap,
bool need_mask,
- bool UNUSED(need_colors))
+ bool is_paint_tool)
{
Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt;
@@ -1674,7 +1678,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK);
CustomDataLayer *layer;
- AttributeDomain domain;
+ eAttrDomain domain;
if (BKE_pbvh_get_color_layer(me, &layer, &domain)) {
if (layer->type == CD_PROP_COLOR) {
@@ -1775,47 +1779,67 @@ static void sculpt_update_object(Depsgraph *depsgraph,
}
}
- /*
- * We should rebuild the PBVH_pixels when painting canvas changes.
- *
- * The relevant changes are stored/encoded in the paint canvas key.
- * These include the active uv map, and resolutions.
- */
- if (U.experimental.use_sculpt_texture_paint && ss->pbvh) {
- char *paint_canvas_key = BKE_paint_canvas_key_get(&scene->toolsettings->paint_mode, ob);
- if (ss->last_paint_canvas_key == NULL || !STREQ(paint_canvas_key, ss->last_paint_canvas_key)) {
- MEM_SAFE_FREE(ss->last_paint_canvas_key);
- ss->last_paint_canvas_key = paint_canvas_key;
- BKE_pbvh_mark_rebuild_pixels(ss->pbvh);
+ if (is_paint_tool) {
+ /*
+ * We should rebuild the PBVH_pixels when painting canvas changes.
+ *
+ * The relevant changes are stored/encoded in the paint canvas key.
+ * These include the active uv map, and resolutions.
+ */
+ if (U.experimental.use_sculpt_texture_paint && ss->pbvh) {
+ char *paint_canvas_key = BKE_paint_canvas_key_get(&scene->toolsettings->paint_mode, ob);
+ if (ss->last_paint_canvas_key == NULL ||
+ !STREQ(paint_canvas_key, ss->last_paint_canvas_key)) {
+ MEM_SAFE_FREE(ss->last_paint_canvas_key);
+ ss->last_paint_canvas_key = paint_canvas_key;
+ BKE_pbvh_mark_rebuild_pixels(ss->pbvh);
+ }
+ else {
+ MEM_freeN(paint_canvas_key);
+ }
}
- else {
- MEM_freeN(paint_canvas_key);
+
+ /* We could be more precise when we have access to the active tool. */
+ const bool use_paint_slots = (ob->mode & OB_MODE_SCULPT) != 0;
+ if (use_paint_slots) {
+ BKE_texpaint_slots_refresh_object(scene, ob);
}
}
+}
- /* We could be more precise when we have access to the active tool. */
- const bool use_paint_slots = (ob->mode & OB_MODE_SCULPT) != 0;
- if (use_paint_slots) {
- BKE_texpaint_slots_refresh_object(scene, ob);
+static void sculpt_face_sets_ensure(Mesh *mesh)
+{
+ if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) {
+ return;
+ }
+
+ int *new_face_sets = CustomData_add_layer(
+ &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, mesh->totpoly);
+
+ /* Initialize the new Face Set data-layer with a default valid visible ID and set the default
+ * color to render it white. */
+ for (int i = 0; i < mesh->totpoly; i++) {
+ new_face_sets[i] = 1;
}
+ mesh->face_sets_color_default = 1;
}
-void BKE_sculpt_update_object_before_eval(Object *ob)
+void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval)
{
/* Update before mesh evaluation in the dependency graph. */
- SculptSession *ss = ob->sculpt;
+ SculptSession *ss = ob_eval->sculpt;
if (ss && ss->building_vp_handle == false) {
if (!ss->cache && !ss->filter_cache && !ss->expand_cache) {
/* We free pbvh on changes, except in the middle of drawing a stroke
* since it can't deal with changing PVBH node organization, we hope
* topology does not change in the meantime .. weak. */
- sculptsession_free_pbvh(ob);
+ sculptsession_free_pbvh(ob_eval);
- BKE_sculptsession_free_deformMats(ob->sculpt);
+ BKE_sculptsession_free_deformMats(ob_eval->sculpt);
/* In vertex/weight paint, force maps to be rebuilt. */
- BKE_sculptsession_free_vwpaint_data(ob->sculpt);
+ BKE_sculptsession_free_vwpaint_data(ob_eval->sculpt);
}
else {
PBVHNode **nodes;
@@ -1830,6 +1854,16 @@ void BKE_sculpt_update_object_before_eval(Object *ob)
MEM_freeN(nodes);
}
}
+
+ if (ss) {
+ Object *ob_orig = DEG_get_original_object(ob_eval);
+ Mesh *mesh = BKE_object_get_original_mesh(ob_orig);
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob_orig);
+
+ /* Ensure attribute layout is still correct. */
+ sculpt_face_sets_ensure(mesh);
+ BKE_sculpt_mask_layers_ensure(ob_orig, mmd);
+ }
}
void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
@@ -1878,7 +1912,7 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object)
}
void BKE_sculpt_update_object_for_edit(
- Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool need_colors)
+ Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool is_paint_tool)
{
BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
@@ -1886,7 +1920,7 @@ void BKE_sculpt_update_object_for_edit(
Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
BLI_assert(me_eval != NULL);
- sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, need_colors);
+ sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, is_paint_tool);
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
@@ -2117,7 +2151,7 @@ void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
/* Copy the current mesh visibility to the Face Sets. */
BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh);
if (object->sculpt != NULL) {
- /* If a sculpt session is active, ensure we have its faceset data porperly up-to-date. */
+ /* If a sculpt session is active, ensure we have its face-set data properly up-to-date. */
object->sculpt->face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
/* NOTE: In theory we could add that on the fly when required by sculpt code.
@@ -2227,12 +2261,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
return NULL;
}
- bool respect_hide = true;
- if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
- if (!(BKE_paint_select_vert_test(ob) || BKE_paint_select_face_test(ob))) {
- respect_hide = false;
- }
- }
+ const bool respect_hide = true;
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh != NULL) {
@@ -2284,7 +2313,7 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg)
subdiv_ccg->grid_hidden);
}
-bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
+bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d))
{
SculptSession *ss = ob->sculpt;
if (ss == NULL || ss->pbvh == NULL || ss->mode_type != OB_MODE_SCULPT) {
@@ -2293,8 +2322,8 @@ bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *v3d)
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
/* Regular mesh only draws from PBVH without modifiers and shape keys. */
- const bool full_shading = (v3d && (v3d->shading.type > OB_SOLID));
- return !(ss->shapekey_active || ss->deform_modifiers_active || full_shading);
+
+ return !(ss->shapekey_active || ss->deform_modifiers_active);
}
/* Multires and dyntopo always draw directly from the PBVH. */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index a5f7f73af70..2471d3baa59 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -58,6 +58,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -2276,7 +2277,7 @@ void psys_emitter_customdata_mask(ParticleSystem *psys, CustomData_MeshMasks *r_
r_cddata_masks->fmask |= CD_MASK_MTFACE;
}
- /* ask for vertexgroups if we need them */
+ /* Ask for vertex-groups if we need them. */
for (i = 0; i < PSYS_TOT_VG; i++) {
if (psys->vgroup[i]) {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 4be48efb2b5..da769515f08 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -28,6 +28,7 @@
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -1216,8 +1217,8 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx,
MEM_freeN(element_sum);
MEM_freeN(element_map);
- /* For hair, sort by origindex (allows optimization's in rendering), */
- /* however with virtual parents the children need to be in random order. */
+ /* For hair, sort by #CD_ORIGINDEX (allows optimization's in rendering),
+ * however with virtual parents the children need to be in random order. */
if (part->type == PART_HAIR && !(part->childtype == PART_CHILD_FACES && part->parents != 0.0f)) {
const int *orig_index = NULL;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index a7ab1536b1f..4a8f029beee 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -47,6 +47,7 @@
#include "BKE_effect.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_particle.h"
#include "BKE_bvhutils.h"
@@ -3121,7 +3122,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
col.cfra = cfra;
col.old_cfra = sim->psys->cfra;
- /* get acceleration (from gravity, forcefields etc. to be re-applied in collision response) */
+ /* Get acceleration (from gravity, force-fields etc. to be re-applied in collision response). */
sub_v3_v3v3(col.acc, pa->state.vel, pa->prev_state.vel);
mul_v3_fl(col.acc, 1.0f / col.total_time);
@@ -4962,7 +4963,7 @@ void particle_system_update(struct Depsgraph *depsgraph,
}
/* Save matrix for duplicators,
- * at rendertime the actual dupliobject's matrix is used so don't update! */
+ * at render-time the actual dupli-object's matrix is used so don't update! */
invert_m4_m4(psys->imat, ob->obmat);
BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 1d4fbb92fa0..00a4eee47e3 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -714,6 +714,10 @@ void BKE_pbvh_free(PBVH *pbvh)
MEM_SAFE_FREE(pbvh->vert_bitmap);
+ if (pbvh->vbo_id) {
+ GPU_pbvh_free_format(pbvh->vbo_id);
+ }
+
MEM_freeN(pbvh);
}
@@ -1264,7 +1268,7 @@ static int pbvh_get_buffers_update_flags(PBVH *UNUSED(pbvh))
return update_flags;
}
-bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, AttributeDomain *r_attr)
+bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDomain *r_attr)
{
CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)me);
@@ -1274,7 +1278,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, Attribu
return false;
}
- AttributeDomain domain = BKE_id_attribute_domain((ID *)me, layer);
+ eAttrDomain domain = BKE_id_attribute_domain((ID *)me, layer);
if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
*r_layer = NULL;
@@ -1299,11 +1303,27 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
+ CustomData *vdata, *ldata;
+
+ if (!pbvh->bm) {
+ vdata = pbvh->vdata;
+ ldata = pbvh->ldata;
+ }
+ else {
+ vdata = &pbvh->bm->vdata;
+ ldata = &pbvh->bm->ldata;
+ }
+
if (node->flag & PBVH_RebuildDrawBuffers) {
switch (pbvh->type) {
- case PBVH_GRIDS:
- node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, pbvh->grid_hidden);
+ case PBVH_GRIDS: {
+ bool smooth = node->totprim > 0 ?
+ pbvh->grid_flag_mats[node->prim_indices[0]].flag & ME_SMOOTH :
+ false;
+
+ node->draw_buffers = GPU_pbvh_grid_buffers_build(node->totprim, pbvh->grid_hidden, smooth);
break;
+ }
case PBVH_FACES:
node->draw_buffers = GPU_pbvh_mesh_buffers_build(
pbvh->mpoly,
@@ -1326,7 +1346,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
const int update_flags = pbvh_get_buffers_update_flags(pbvh);
switch (pbvh->type) {
case PBVH_GRIDS:
- GPU_pbvh_grid_buffers_update(node->draw_buffers,
+ GPU_pbvh_grid_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->subdiv_ccg,
pbvh->grids,
pbvh->grid_flag_mats,
@@ -1339,26 +1360,22 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
update_flags);
break;
case PBVH_FACES: {
- CustomDataLayer *layer = NULL;
- AttributeDomain domain;
-
- BKE_pbvh_get_color_layer(pbvh->mesh, &layer, &domain);
-
- GPU_pbvh_mesh_buffers_update(node->draw_buffers,
+ GPU_pbvh_mesh_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->verts,
- pbvh->vert_normals,
+ vdata,
+ ldata,
CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
- layer ? layer->data : NULL,
- layer ? layer->type : -1,
- layer ? domain : ATTR_DOMAIN_AUTO,
CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
pbvh->face_sets_color_seed,
pbvh->face_sets_color_default,
- update_flags);
+ update_flags,
+ pbvh->vert_normals);
break;
}
case PBVH_BMESH:
- GPU_pbvh_bmesh_buffers_update(node->draw_buffers,
+ GPU_pbvh_bmesh_buffers_update(pbvh->vbo_id,
+ node->draw_buffers,
pbvh->bm,
node->bm_faces,
node->bm_unique_verts,
@@ -1379,8 +1396,79 @@ void pbvh_free_draw_buffers(PBVH *pbvh, PBVHNode *node)
}
}
+static void pbvh_check_draw_layout(PBVH *pbvh)
+{
+ const CustomData *vdata;
+ const CustomData *ldata;
+
+ if (!pbvh->vbo_id) {
+ pbvh->vbo_id = GPU_pbvh_make_format();
+ }
+
+ switch (pbvh->type) {
+ case PBVH_BMESH:
+ if (!pbvh->bm) {
+ /* BMesh hasn't been created yet */
+ return;
+ }
+
+ vdata = &pbvh->bm->vdata;
+ ldata = &pbvh->bm->ldata;
+ break;
+ case PBVH_FACES:
+ vdata = pbvh->vdata;
+ ldata = pbvh->ldata;
+ break;
+ case PBVH_GRIDS:
+ ldata = vdata = NULL;
+ break;
+ }
+
+ /* Rebuild all draw buffers if attribute layout changed.
+ *
+ * NOTE: The optimization where we only send active attributes
+ * to the GPU in workbench mode is disabled due to bugs
+ * (there's no guarantee there isn't another EEVEE viewport which would
+ * free the draw buffers and corrupt the draw cache).
+ */
+ if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, false)) {
+ /* attribute layout changed; force rebuild */
+ for (int i = 0; i < pbvh->totnode; i++) {
+ PBVHNode *node = pbvh->nodes + i;
+
+ if (node->flag & PBVH_Leaf) {
+ node->flag |= PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
+ }
+ }
+ }
+}
+
static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, int update_flag)
{
+ const CustomData *vdata;
+
+ if (!pbvh->vbo_id) {
+ pbvh->vbo_id = GPU_pbvh_make_format();
+ }
+
+ switch (pbvh->type) {
+ case PBVH_BMESH:
+ if (!pbvh->bm) {
+ /* BMesh hasn't been created yet */
+ return;
+ }
+
+ vdata = &pbvh->bm->vdata;
+ break;
+ case PBVH_FACES:
+ vdata = pbvh->vdata;
+ break;
+ case PBVH_GRIDS:
+ vdata = NULL;
+ break;
+ }
+ UNUSED_VARS(vdata);
+
if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) {
/* Free buffers uses OpenGL, so not in parallel. */
for (int n = 0; n < totnode; n++) {
@@ -2311,16 +2399,16 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh,
const float *co[4];
if (origco) {
- co[0] = origco[y * gridsize + x];
- co[1] = origco[y * gridsize + x + 1];
- co[2] = origco[(y + 1) * gridsize + x + 1];
- co[3] = origco[(y + 1) * gridsize + x];
+ co[0] = origco[(y + 1) * gridsize + x];
+ co[1] = origco[(y + 1) * gridsize + x + 1];
+ co[2] = origco[y * gridsize + x + 1];
+ co[3] = origco[y * gridsize + x];
}
else {
- co[0] = CCG_grid_elem_co(gridkey, grid, x, y);
- co[1] = CCG_grid_elem_co(gridkey, grid, x + 1, y);
- co[2] = CCG_grid_elem_co(gridkey, grid, x + 1, y + 1);
- co[3] = CCG_grid_elem_co(gridkey, grid, x, y + 1);
+ co[0] = CCG_grid_elem_co(gridkey, grid, x, y + 1);
+ co[1] = CCG_grid_elem_co(gridkey, grid, x + 1, y + 1);
+ co[2] = CCG_grid_elem_co(gridkey, grid, x + 1, y);
+ co[3] = CCG_grid_elem_co(gridkey, grid, x, y);
}
if (ray_face_intersection_quad(
@@ -2540,7 +2628,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
}
if (origco) {
- /* intersect with backuped original coordinates */
+ /* Intersect with backed-up original coordinates. */
hit |= ray_face_nearest_tri(ray_start,
ray_normal,
origco[face_verts[0]],
@@ -2783,7 +2871,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
PBVHFrustumPlanes *update_frustum,
PBVHFrustumPlanes *draw_frustum,
void (*draw_fn)(void *user_data, GPU_PBVH_Buffers *buffers),
- void *user_data)
+ void *user_data,
+ bool UNUSED(full_render))
{
PBVHNode **nodes;
int totnode;
@@ -2806,6 +2895,8 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
update_flag = PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers;
}
+ pbvh_check_draw_layout(pbvh);
+
/* Update draw buffers. */
if (totnode != 0 && (update_flag & (PBVH_RebuildDrawBuffers | PBVH_UpdateDrawBuffers))) {
pbvh_update_draw_buffers(pbvh, nodes, totnode, update_flag);
@@ -3156,6 +3247,11 @@ bool BKE_pbvh_is_drawing(const PBVH *pbvh)
return pbvh->is_drawing;
}
+bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh)
+{
+ return pbvh->draw_cache_invalid;
+}
+
void BKE_pbvh_is_drawing_set(PBVH *pbvh, bool val)
{
pbvh->is_drawing = val;
@@ -3229,8 +3325,3 @@ void BKE_pbvh_ensure_node_loops(PBVH *pbvh)
MEM_SAFE_FREE(visit);
}
-
-bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh)
-{
- return pbvh->draw_cache_invalid;
-}
diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc
index be6e95426c2..dec93826b9b 100644
--- a/source/blender/blenkernel/intern/pbvh.cc
+++ b/source/blender/blenkernel/intern/pbvh.cc
@@ -44,7 +44,7 @@ using blender::IndexRange;
namespace blender::bke {
template<typename Func>
-inline void to_static_color_type(const CustomDataType type, const Func &func)
+inline void to_static_color_type(const eCustomDataType type, const Func &func)
{
switch (type) {
case CD_PROP_COLOR:
@@ -146,7 +146,7 @@ static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4])
extern "C" {
void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4])
{
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
blender::bke::pbvh_vertex_color_get<T>(*pbvh, vertex, r_color);
});
@@ -154,7 +154,7 @@ void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4])
void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4])
{
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
blender::bke::pbvh_vertex_color_set<T>(*pbvh, vertex, color);
});
@@ -165,7 +165,7 @@ void BKE_pbvh_swap_colors(PBVH *pbvh,
const int indices_num,
float (*r_colors)[4])
{
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data);
for (const int i : IndexRange(indices_num)) {
@@ -181,7 +181,7 @@ void BKE_pbvh_store_colors(PBVH *pbvh,
const int indices_num,
float (*r_colors)[4])
{
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
T *pbvh_colors = static_cast<T *>(pbvh->color_layer->data);
for (const int i : IndexRange(indices_num)) {
@@ -199,7 +199,7 @@ void BKE_pbvh_store_colors_vertex(PBVH *pbvh,
BKE_pbvh_store_colors(pbvh, indices, indices_num, r_colors);
}
else {
- blender::bke::to_static_color_type(CustomDataType(pbvh->color_layer->type), [&](auto dummy) {
+ blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) {
using T = decltype(dummy);
for (const int i : IndexRange(indices_num)) {
blender::bke::pbvh_vertex_color_get<T>(*pbvh, indices[i], r_colors[i]);
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index d4c6dcfbc96..112fd01c699 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -376,6 +376,9 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
return false;
}
+ /* Trigger draw manager cache invalidation. */
+ pbvh->draw_cache_invalid = true;
+
/* For each BMFace, store the AABB and AABB centroid */
BBC *bbc_array = MEM_mallocN(sizeof(BBC) * bm_faces_size, "BBC");
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index a86663a9c74..a4ac2744a73 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -2,6 +2,8 @@
#pragma once
+struct PBVHGPUFormat;
+
/** \file
* \ingroup bke
*/
@@ -123,9 +125,7 @@ struct PBVHNode {
PBVHPixelsNode pixels;
};
-typedef enum {
- PBVH_DYNTOPO_SMOOTH_SHADING = 1,
-} PBVHFlags;
+typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags;
typedef struct PBVHBMeshLog PBVHBMeshLog;
@@ -198,12 +198,14 @@ struct PBVH {
const struct MeshElemMap *pmap;
CustomDataLayer *color_layer;
- AttributeDomain color_domain;
+ eAttrDomain color_domain;
bool is_drawing;
/* Used by DynTopo to invalidate the draw cache. */
bool draw_cache_invalid;
+
+ struct PBVHGPUFormat *vbo_id;
};
/* pbvh.c */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 2467ca16670..5d8025dce8a 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -2920,7 +2920,7 @@ int BKE_ptcache_id_reset(Scene *scene, PTCacheID *pid, int mode)
BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, 0);
}
else if (after) {
- BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, CFRA);
+ BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_AFTER, scene->r.cfra);
}
return (reset || clear || after);
@@ -2980,6 +2980,15 @@ int BKE_ptcache_object_reset(Scene *scene, Object *ob, int mode)
}
}
}
+ if (md->type == eModifierType_Fluid) {
+ FluidModifierData *fmd = (FluidModifierData *)md;
+ FluidDomainSettings *fds = fmd->domain;
+ if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fds &&
+ fds->cache_type == FLUID_DOMAIN_CACHE_REPLAY) {
+ BKE_ptcache_id_from_smoke(&pid, ob, fmd);
+ reset |= BKE_ptcache_id_reset(scene, &pid, mode);
+ }
+ }
}
if (scene->rigidbody_world && (ob->rigidbody_object || ob->rigidbody_constraint)) {
@@ -3153,8 +3162,8 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
PTCacheID *pid = &baker->pid;
PointCache *cache = NULL;
float frameleno = scene->r.framelen;
- int cfrao = CFRA;
- int startframe = MAXFRAME, endframe = baker->anim_init ? scene->r.sfra : CFRA;
+ int cfrao = scene->r.cfra;
+ int startframe = MAXFRAME, endframe = baker->anim_init ? scene->r.sfra : scene->r.cfra;
int bake = baker->bake;
int render = baker->render;
@@ -3232,7 +3241,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
scene, pid->calldata, &cache->startframe, &cache->endframe);
}
- /* XXX workaround for regression inroduced in ee3fadd, needs looking into */
+ /* XXX: workaround for regression introduced in ee3fadd, needs looking into. */
if (pid->type == PTCACHE_TYPE_RIGIDBODY) {
if ((cache->flag & PTCACHE_REDO_NEEDED ||
(cache->flag & PTCACHE_SIMULATION_VALID) == 0) &&
@@ -3261,7 +3270,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
}
- CFRA = startframe;
+ scene->r.cfra = startframe;
scene->r.framelen = 1.0;
/* bake */
@@ -3273,21 +3282,21 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
stime = ptime = PIL_check_seconds_timer();
- for (int fr = CFRA; fr <= endframe; fr += baker->quick_step, CFRA = fr) {
+ for (int fr = scene->r.cfra; fr <= endframe; fr += baker->quick_step, scene->r.cfra = fr) {
BKE_scene_graph_update_for_newframe(depsgraph);
if (baker->update_progress) {
- float progress = ((float)(CFRA - startframe) / (float)(endframe - startframe));
+ float progress = ((float)(scene->r.cfra - startframe) / (float)(endframe - startframe));
baker->update_progress(baker->bake_job, progress, &cancel);
}
if (G.background) {
- printf("bake: frame %d :: %d\n", CFRA, endframe);
+ printf("bake: frame %d :: %d\n", scene->r.cfra, endframe);
}
else {
ctime = PIL_check_seconds_timer();
- fetd = (ctime - ptime) * (endframe - CFRA) / baker->quick_step;
+ fetd = (ctime - ptime) * (endframe - scene->r.cfra) / baker->quick_step;
if (use_timer || fetd > 60.0) {
use_timer = true;
@@ -3298,7 +3307,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
printf("Baked for %s, current frame: %i/%i (%.3fs), ETC: %s\r",
run,
- CFRA - startframe + 1,
+ scene->r.cfra - startframe + 1,
endframe - startframe + 1,
ctime - ptime,
etd);
@@ -3312,7 +3321,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
break;
}
- CFRA += 1;
+ scene->r.cfra += 1;
}
if (use_timer) {
@@ -3321,7 +3330,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
printf("\nBake %s %s (%i frames simulated).\n",
(cancel ? "canceled after" : "finished in"),
run,
- CFRA - startframe);
+ scene->r.cfra - startframe);
}
/* clear baking flag */
@@ -3370,7 +3379,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker)
}
scene->r.framelen = frameleno;
- CFRA = cfrao;
+ scene->r.cfra = cfrao;
if (bake) { /* already on cfra unless baking */
BKE_scene_graph_update_for_newframe(depsgraph);
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 3ee46fc4f15..261b053e4f9 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -20,6 +20,7 @@
#include "BLI_string.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BKE_anim_data.h"
#include "BKE_customdata.h"
@@ -44,6 +45,7 @@
using blender::float3;
using blender::IndexRange;
using blender::Span;
+using blender::Vector;
/* PointCloud datablock */
@@ -66,7 +68,6 @@ static void pointcloud_init_data(ID *id)
nullptr,
pointcloud->totpoint,
POINTCLOUD_ATTR_POSITION);
- BKE_pointcloud_update_customdata_pointers(pointcloud);
}
static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
@@ -81,7 +82,6 @@ static void pointcloud_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_s
CD_MASK_ALL,
alloc_type,
pointcloud_dst->totpoint);
- BKE_pointcloud_update_customdata_pointers(pointcloud_dst);
pointcloud_dst->batch_cache = nullptr;
}
@@ -107,27 +107,25 @@ static void pointcloud_blend_write(BlendWriter *writer, ID *id, const void *id_a
{
PointCloud *pointcloud = (PointCloud *)id;
- CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomData_blend_write_prepare(
- &pointcloud->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
+ Vector<CustomDataLayer, 16> point_layers;
+ CustomData_blend_write_prepare(pointcloud->pdata, point_layers);
/* Write LibData */
BLO_write_id_struct(writer, PointCloud, id_address, &pointcloud->id);
BKE_id_blend_write(writer, &pointcloud->id);
/* Direct data */
- CustomData_blend_write(
- writer, &pointcloud->pdata, players, pointcloud->totpoint, CD_MASK_ALL, &pointcloud->id);
+ CustomData_blend_write(writer,
+ &pointcloud->pdata,
+ point_layers,
+ pointcloud->totpoint,
+ CD_MASK_ALL,
+ &pointcloud->id);
BLO_write_pointer_array(writer, pointcloud->totcol, pointcloud->mat);
if (pointcloud->adt) {
BKE_animdata_blend_write(writer, pointcloud->adt);
}
-
- /* Remove temporary data. */
- if (players && players != players_buff) {
- MEM_freeN(players);
- }
}
static void pointcloud_blend_read_data(BlendDataReader *reader, ID *id)
@@ -138,7 +136,6 @@ static void pointcloud_blend_read_data(BlendDataReader *reader, ID *id)
/* Geometry */
CustomData_blend_read(reader, &pointcloud->pdata, pointcloud->totpoint);
- BKE_pointcloud_update_customdata_pointers(pointcloud);
/* Materials */
BLO_read_pointer_array(reader, (void **)&pointcloud->mat);
@@ -194,17 +191,28 @@ static void pointcloud_random(PointCloud *pointcloud)
{
pointcloud->totpoint = 400;
CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
- BKE_pointcloud_update_customdata_pointers(pointcloud);
RNG *rng = BLI_rng_new(0);
- for (int i = 0; i < pointcloud->totpoint; i++) {
- pointcloud->co[i][0] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->co[i][1] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->co[i][2] = 2.0f * BLI_rng_get_float(rng) - 1.0f;
- pointcloud->radius[i] = 0.05f * BLI_rng_get_float(rng);
+ blender::bke::MutableAttributeAccessor attributes =
+ blender::bke::pointcloud_attributes_for_write(*pointcloud);
+ blender::bke::SpanAttributeWriter positions =
+ attributes.lookup_or_add_for_write_only_span<float3>(POINTCLOUD_ATTR_POSITION,
+ ATTR_DOMAIN_POINT);
+ blender::bke::SpanAttributeWriter<float> radii =
+ attributes.lookup_or_add_for_write_only_span<float>(POINTCLOUD_ATTR_RADIUS,
+ ATTR_DOMAIN_POINT);
+
+ for (const int i : positions.span.index_range()) {
+ positions.span[i] =
+ float3(BLI_rng_get_float(rng), BLI_rng_get_float(rng), BLI_rng_get_float(rng)) * 2.0f -
+ 1.0f;
+ radii.span[i] = 0.05f * BLI_rng_get_float(rng);
}
+ positions.finish();
+ radii.finish();
+
BLI_rng_free(rng);
}
@@ -250,7 +258,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
pointcloud->totpoint = totpoint;
CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
- BKE_pointcloud_update_customdata_pointers(pointcloud);
return pointcloud;
}
@@ -258,10 +265,14 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
static std::optional<blender::bounds::MinMaxResult<float3>> point_cloud_bounds(
const PointCloud &pointcloud)
{
- Span<float3> positions{reinterpret_cast<float3 *>(pointcloud.co), pointcloud.totpoint};
- if (pointcloud.radius) {
- Span<float> radii{pointcloud.radius, pointcloud.totpoint};
- return blender::bounds::min_max_with_radii(positions, radii);
+ blender::bke::AttributeAccessor attributes = blender::bke::pointcloud_attributes(pointcloud);
+ blender::VArraySpan<float3> positions = attributes.lookup_or_default<float3>(
+ POINTCLOUD_ATTR_POSITION, ATTR_DOMAIN_POINT, float3(0));
+ blender::VArray<float> radii = attributes.lookup_or_default<float>(
+ POINTCLOUD_ATTR_RADIUS, ATTR_DOMAIN_POINT, 0.0f);
+
+ if (!(radii.is_single() && radii.get_internal_single() == 0.0f)) {
+ return blender::bounds::min_max_with_radii(positions, radii.get_internal_span());
}
return blender::bounds::min_max(positions);
}
@@ -307,17 +318,9 @@ BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
return ob->runtime.bb;
}
-void BKE_pointcloud_update_customdata_pointers(PointCloud *pointcloud)
-{
- pointcloud->co = static_cast<float(*)[3]>(
- CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT3, POINTCLOUD_ATTR_POSITION));
- pointcloud->radius = static_cast<float *>(
- CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, POINTCLOUD_ATTR_RADIUS));
-}
-
-bool BKE_pointcloud_customdata_required(PointCloud *UNUSED(pointcloud), CustomDataLayer *layer)
+bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), const char *name)
{
- return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, POINTCLOUD_ATTR_POSITION);
+ return STREQ(name, POINTCLOUD_ATTR_POSITION);
}
/* Dependency Graph */
@@ -334,7 +337,6 @@ PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int to
pointcloud_dst->totpoint = totpoint;
CustomData_copy(
&pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint);
- BKE_pointcloud_update_customdata_pointers(pointcloud_dst);
return pointcloud_dst;
}
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 60cc4ce83af..821976f8e0e 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1660,8 +1660,7 @@ static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
rigidbody_update_ob_array(rbw);
}
-static void rigidbody_update_sim_ob(
- Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo)
+static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Object *ob, RigidBodyOb *rbo)
{
/* only update if rigid body exists */
if (rbo->shared->physics_object == NULL) {
@@ -1712,54 +1711,6 @@ static void rigidbody_update_sim_ob(
RB_body_set_mass(rbo->shared->physics_object, 0.0f);
}
- /* update influence of effectors - but don't do it on an effector */
- /* only dynamic bodies need effector update */
- else if (rbo->type == RBO_TYPE_ACTIVE &&
- ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
- EffectorWeights *effector_weights = rbw->effector_weights;
- EffectedPoint epoint;
- ListBase *effectors;
-
- /* get effectors present in the group specified by effector_weights */
- effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false);
- if (effectors) {
- float eff_force[3] = {0.0f, 0.0f, 0.0f};
- float eff_loc[3], eff_vel[3];
-
- /* create dummy 'point' which represents last known position of object as result of sim */
- /* XXX: this can create some inaccuracies with sim position,
- * but is probably better than using un-simulated values? */
- RB_body_get_position(rbo->shared->physics_object, eff_loc);
- RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
-
- pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
-
- /* Calculate net force of effectors, and apply to sim object:
- * - we use 'central force' since apply force requires a "relative position"
- * which we don't have... */
- BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL);
- if (G.f & G_DEBUG) {
- printf("\tapplying force (%f,%f,%f) to '%s'\n",
- eff_force[0],
- eff_force[1],
- eff_force[2],
- ob->id.name + 2);
- }
- /* activate object in case it is deactivated */
- if (!is_zero_v3(eff_force)) {
- RB_body_activate(rbo->shared->physics_object);
- }
- RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
- }
- else if (G.f & G_DEBUG) {
- printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
- }
-
- /* cleanup */
- BKE_effectors_free(effectors);
- }
- /* NOTE: passive objects don't need to be updated since they don't move */
-
/* NOTE: no other settings need to be explicitly updated here,
* since RNA setters take care of the rest :)
*/
@@ -1854,7 +1805,7 @@ static void rigidbody_update_simulation(Depsgraph *depsgraph,
rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
/* update simulation object... */
- rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo);
+ rigidbody_update_sim_ob(depsgraph, ob, rbo);
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
@@ -1986,6 +1937,69 @@ static void rigidbody_update_kinematic_obj_substep(ListBase *substep_targets, fl
}
}
+static void rigidbody_update_external_forces(Depsgraph *depsgraph,
+ Scene *scene,
+ RigidBodyWorld *rbw)
+{
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) {
+ /* only update if rigid body exists */
+ RigidBodyOb *rbo = ob->rigidbody_object;
+ if (ob->type != OB_MESH || rbo->shared->physics_object == NULL) {
+ continue;
+ }
+
+ /* update influence of effectors - but don't do it on an effector */
+ /* only dynamic bodies need effector update */
+ if (rbo->type == RBO_TYPE_ACTIVE &&
+ ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
+ EffectorWeights *effector_weights = rbw->effector_weights;
+ EffectedPoint epoint;
+ ListBase *effectors;
+
+ /* get effectors present in the group specified by effector_weights */
+ effectors = BKE_effectors_create(depsgraph, ob, NULL, effector_weights, false);
+ if (effectors) {
+ float eff_force[3] = {0.0f, 0.0f, 0.0f};
+ float eff_loc[3], eff_vel[3];
+
+ /* create dummy 'point' which represents last known position of object as result of sim
+ */
+ /* XXX: this can create some inaccuracies with sim position,
+ * but is probably better than using un-simulated values? */
+ RB_body_get_position(rbo->shared->physics_object, eff_loc);
+ RB_body_get_linear_velocity(rbo->shared->physics_object, eff_vel);
+
+ pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint);
+
+ /* Calculate net force of effectors, and apply to sim object:
+ * - we use 'central force' since apply force requires a "relative position"
+ * which we don't have... */
+ BKE_effectors_apply(effectors, NULL, effector_weights, &epoint, eff_force, NULL, NULL);
+ if (G.f & G_DEBUG) {
+ printf("\tapplying force (%f,%f,%f) to '%s'\n",
+ eff_force[0],
+ eff_force[1],
+ eff_force[2],
+ ob->id.name + 2);
+ }
+ /* activate object in case it is deactivated */
+ if (!is_zero_v3(eff_force)) {
+ RB_body_activate(rbo->shared->physics_object);
+ }
+ RB_body_apply_central_force(rbo->shared->physics_object, eff_force);
+ }
+ else if (G.f & G_DEBUG) {
+ printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
+ }
+
+ /* cleanup */
+ BKE_effectors_free(effectors);
+ }
+ /* NOTE: passive objects don't need to be updated since they don't move */
+ }
+ FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
+}
+
static void rigidbody_free_substep_data(ListBase *substep_targets)
{
LISTBASE_FOREACH (LinkData *, link, substep_targets) {
@@ -2220,26 +2234,27 @@ void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime
BKE_ptcache_write(&pid, startframe);
}
- /* update and validate simulation */
- rigidbody_update_simulation(depsgraph, scene, rbw, false);
-
const float frame_diff = ctime - rbw->ltime;
/* calculate how much time elapsed since last step in seconds */
const float timestep = 1.0f / (float)FPS * frame_diff * rbw->time_scale;
const float substep = timestep / rbw->substeps_per_frame;
- ListBase substep_targets = rigidbody_create_substep_data(rbw);
+ ListBase kinematic_substep_targets = rigidbody_create_substep_data(rbw);
const float interp_step = 1.0f / rbw->substeps_per_frame;
float cur_interp_val = interp_step;
+ /* update and validate simulation */
+ rigidbody_update_simulation(depsgraph, scene, rbw, false);
+
for (int i = 0; i < rbw->substeps_per_frame; i++) {
- rigidbody_update_kinematic_obj_substep(&substep_targets, cur_interp_val);
+ rigidbody_update_external_forces(depsgraph, scene, rbw);
+ rigidbody_update_kinematic_obj_substep(&kinematic_substep_targets, cur_interp_val);
RB_dworld_step_simulation(rbw->shared->physics_world, substep, 0, substep);
cur_interp_val += interp_step;
}
- rigidbody_free_substep_data(&substep_targets);
+ rigidbody_free_substep_data(&kinematic_substep_targets);
rigidbody_update_simulation_post_step(depsgraph, rbw);
diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc
index e203d32a658..e2da27fc840 100644
--- a/source/blender/blenkernel/intern/scene.cc
+++ b/source/blender/blenkernel/intern/scene.cc
@@ -1173,6 +1173,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
BKE_curveprofile_blend_read(reader, sce->toolsettings->custom_bevel_profile_preset);
}
+ BLO_read_data_address(reader, &sce->toolsettings->paint_mode.canvas_image);
BLO_read_data_address(reader, &sce->toolsettings->sequencer_tool_settings);
}
@@ -2951,6 +2952,20 @@ int BKE_scene_num_threads(const Scene *scene)
return BKE_render_num_threads(&scene->r);
}
+void BKE_render_resolution(const struct RenderData *r,
+ const bool use_crop,
+ int *r_width,
+ int *r_height)
+{
+ *r_width = (r->xsch * r->size) / 100;
+ *r_height = (r->ysch * r->size) / 100;
+
+ if (use_crop && (r->mode & R_BORDER) && (r->mode & R_CROP)) {
+ *r_width *= BLI_rctf_size_x(&r->border);
+ *r_height *= BLI_rctf_size_y(&r->border);
+ }
+}
+
int BKE_render_preview_pixel_size(const RenderData *r)
{
if (r->preview_pixel_size == 0) {
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index cff9eb4197d..a45ad31147c 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -277,7 +277,7 @@ static void screen_blend_read_lib(BlendLibReader *reader, ID *id)
IDTypeInfo IDType_ID_SCR = {
.id_code = ID_SCR,
- .id_filter = 0,
+ .id_filter = FILTER_ID_SCR,
.main_listbase_index = INDEX_ID_SCR,
.struct_size = sizeof(bScreen),
.name = "Screen",
@@ -856,6 +856,17 @@ void BKE_screen_remove_unused_scrverts(bScreen *screen)
/* ***************** Utilities ********************** */
+ARegion *BKE_region_find_in_listbase_by_type(const ListBase *regionbase, const int region_type)
+{
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == region_type) {
+ return region;
+ }
+ }
+
+ return NULL;
+}
+
ARegion *BKE_area_find_region_type(const ScrArea *area, int region_type)
{
if (area) {
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 7c7aa80402d..82cc250c6d1 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -666,7 +666,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
}
if (calc->aux_target) {
- auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->aux_target, false);
+ auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->aux_target);
if (!auxMesh) {
return;
}
@@ -1397,7 +1397,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
if (smd->target != NULL) {
Object *ob_target = DEG_get_evaluated_object(ctx->depsgraph, smd->target);
- calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
/* TODO: there might be several "bugs" with non-uniform scales matrices
* because it will no longer be nearest surface, not sphere projection
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index de5589cf5dc..f459b5a82ac 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -54,6 +54,7 @@
#include "SEQ_sequencer.h"
#include "SEQ_sound.h"
+#include "SEQ_time.h"
static void sound_free_audio(bSound *sound);
@@ -719,8 +720,8 @@ void *BKE_sound_scene_add_scene_sound_defaults(Scene *scene, Sequence *sequence)
{
return BKE_sound_scene_add_scene_sound(scene,
sequence,
- sequence->startdisp,
- sequence->enddisp,
+ SEQ_time_left_handle_frame_get(scene, sequence),
+ SEQ_time_right_handle_frame_get(scene, sequence),
sequence->startofs + sequence->anim_startofs);
}
@@ -745,8 +746,8 @@ void *BKE_sound_add_scene_sound_defaults(Scene *scene, Sequence *sequence)
{
return BKE_sound_add_scene_sound(scene,
sequence,
- sequence->startdisp,
- sequence->enddisp,
+ SEQ_time_left_handle_frame_get(scene, sequence),
+ SEQ_time_right_handle_frame_get(scene, sequence),
sequence->startofs + sequence->anim_startofs);
}
@@ -760,8 +761,12 @@ void BKE_sound_mute_scene_sound(void *handle, char mute)
AUD_SequenceEntry_setMuted(handle, mute);
}
-void BKE_sound_move_scene_sound(
- Scene *scene, void *handle, int startframe, int endframe, int frameskip, double audio_offset)
+void BKE_sound_move_scene_sound(const Scene *scene,
+ void *handle,
+ int startframe,
+ int endframe,
+ int frameskip,
+ double audio_offset)
{
sound_verify_evaluated_id(&scene->id);
const double fps = FPS;
@@ -774,8 +779,8 @@ void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence)
if (sequence->scene_sound) {
BKE_sound_move_scene_sound(scene,
sequence->scene_sound,
- sequence->startdisp,
- sequence->enddisp,
+ SEQ_time_left_handle_frame_get(scene, sequence),
+ SEQ_time_right_handle_frame_get(scene, sequence),
sequence->startofs + sequence->anim_startofs,
0.0);
}
@@ -799,7 +804,7 @@ void BKE_sound_set_scene_volume(Scene *scene, float volume)
}
AUD_Sequence_setAnimationData(scene->sound_scene,
AUD_AP_VOLUME,
- CFRA,
+ scene->r.cfra,
&volume,
(scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0);
}
@@ -850,7 +855,7 @@ static double get_cur_time(Scene *scene)
/* We divide by the current framelen to take into account time remapping.
* Otherwise we will get the wrong starting time which will break A/V sync.
* See T74111 for further details. */
- return FRA2TIME((CFRA + SUBFRA) / (double)scene->r.framelen);
+ return FRA2TIME((scene->r.cfra + scene->r.subframe) / (double)scene->r.framelen);
}
void BKE_sound_play_scene(Scene *scene)
@@ -906,7 +911,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
int animation_playing;
const double one_frame = 1.0 / FPS;
- const double cur_time = FRA2TIME(CFRA);
+ const double cur_time = FRA2TIME(scene->r.cfra);
AUD_Device_lock(sound_device);
@@ -1126,13 +1131,13 @@ static void sound_update_base(Scene *scene, Object *object, void *new_set)
mat4_to_quat(quat, object->obmat);
AUD_SequenceEntry_setAnimationData(
- strip->speaker_handle, AUD_AP_LOCATION, CFRA, object->obmat[3], 1);
+ strip->speaker_handle, AUD_AP_LOCATION, scene->r.cfra, object->obmat[3], 1);
AUD_SequenceEntry_setAnimationData(
- strip->speaker_handle, AUD_AP_ORIENTATION, CFRA, quat, 1);
+ strip->speaker_handle, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1);
AUD_SequenceEntry_setAnimationData(
- strip->speaker_handle, AUD_AP_VOLUME, CFRA, &speaker->volume, 1);
+ strip->speaker_handle, AUD_AP_VOLUME, scene->r.cfra, &speaker->volume, 1);
AUD_SequenceEntry_setAnimationData(
- strip->speaker_handle, AUD_AP_PITCH, CFRA, &speaker->pitch, 1);
+ strip->speaker_handle, AUD_AP_PITCH, scene->r.cfra, &speaker->pitch, 1);
AUD_SequenceEntry_setSound(strip->speaker_handle, speaker->sound->playback_handle);
AUD_SequenceEntry_setMuted(strip->speaker_handle, mute);
}
@@ -1167,8 +1172,8 @@ void BKE_sound_update_scene(Depsgraph *depsgraph, Scene *scene)
if (scene->camera) {
mat4_to_quat(quat, scene->camera->obmat);
AUD_Sequence_setAnimationData(
- scene->sound_scene, AUD_AP_LOCATION, CFRA, scene->camera->obmat[3], 1);
- AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_ORIENTATION, CFRA, quat, 1);
+ scene->sound_scene, AUD_AP_LOCATION, scene->r.cfra, scene->camera->obmat[3], 1);
+ AUD_Sequence_setAnimationData(scene->sound_scene, AUD_AP_ORIENTATION, scene->r.cfra, quat, 1);
}
AUD_destroySet(scene->speaker_handles);
@@ -1344,7 +1349,7 @@ void BKE_sound_remove_scene_sound(Scene *UNUSED(scene), void *UNUSED(handle))
void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute))
{
}
-void BKE_sound_move_scene_sound(Scene *UNUSED(scene),
+void BKE_sound_move_scene_sound(const Scene *UNUSED(scene),
void *UNUSED(handle),
int UNUSED(startframe),
int UNUSED(endframe),
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index e8c7aff75d1..a674bf7800a 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -6,7 +6,6 @@
#include "BLI_task.hh"
#include "BLI_timeit.hh"
-#include "BKE_attribute_access.hh"
#include "BKE_attribute_math.hh"
#include "BKE_spline.hh"
@@ -21,6 +20,7 @@ using blender::Span;
using blender::VArray;
using blender::attribute_math::convert_to_static_type;
using blender::bke::AttributeIDRef;
+using blender::bke::AttributeMetaData;
CurveType Spline::type() const
{
diff --git a/source/blender/blenkernel/intern/subdiv_ccg_mask.c b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
index 04a274d0215..1290f1e0834 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg_mask.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg_mask.c
@@ -155,7 +155,7 @@ static void mask_init_functions(SubdivCCGMaskEvaluator *mask_evaluator)
bool BKE_subdiv_ccg_mask_init_from_paint(SubdivCCGMaskEvaluator *mask_evaluator,
const struct Mesh *mesh)
{
- if (CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK)) {
+ if (!CustomData_get_layer(&mesh->ldata, CD_GRID_PAINT_MASK)) {
return false;
}
/* Allocate all required memory. */
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 562bf2e7d61..841b47818f1 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -34,8 +34,8 @@ static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type(
case SUBDIV_EVALUATOR_TYPE_CPU: {
return OPENSUBDIV_EVALUATOR_CPU;
}
- case SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE: {
- return OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
+ case SUBDIV_EVALUATOR_TYPE_GPU: {
+ return OPENSUBDIV_EVALUATOR_GPU;
}
}
BLI_assert_msg(0, "Unknown evaluator type");
@@ -62,7 +62,7 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv,
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, opensubdiv_evaluator_type, evaluator_cache, settings);
+ subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->evaluator == NULL) {
return false;
@@ -71,6 +71,7 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv,
else {
/* TODO(sergey): Check for topology change. */
}
+ subdiv->evaluator->setSettings(subdiv->evaluator, settings);
BKE_subdiv_eval_init_displacement(subdiv);
return true;
}
@@ -246,7 +247,7 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
}
/* Set coordinates of base mesh vertices. */
set_coarse_positions(subdiv, mesh, coarse_vertex_cos);
- /* Set face-varyign data to UV maps. */
+ /* Set face-varying data to UV maps. */
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);
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index e846dc2d807..433bad34479 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -5,9 +5,6 @@
* \ingroup bke
*/
-#include "BKE_mesh.h"
-#include "BKE_subdiv_mesh.h"
-
#include "atomic_ops.h"
#include "DNA_key_types.h"
@@ -24,6 +21,7 @@
#include "BKE_subdiv.h"
#include "BKE_subdiv_eval.h"
#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
#include "MEM_guardedalloc.h"
@@ -44,7 +42,7 @@ typedef struct SubdivMeshContext {
/* UV layers interpolation. */
int num_uv_layers;
MLoopUV *uv_layers[MAX_MTFACE];
- /* Orco interpolation. */
+ /* Original coordinates (ORCO) interpolation. */
float (*orco)[3];
float (*cloth_orco)[3];
/* Per-subdivided vertex counter of averaged values. */
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
index e43da956ce5..2271fd90bda 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.c
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -3,8 +3,6 @@
#include "BKE_subdiv_modifier.h"
-#include "BLI_session_uuid.h"
-
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
@@ -21,22 +19,39 @@
#include "opensubdiv_capi.h"
-void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings,
- const SubsurfModifierData *smd,
- const bool use_render_params)
+bool BKE_subsurf_modifier_runtime_init(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(
+ SubdivSettings settings;
+ 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(
+ settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
smd->uv_smooth);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (settings.level == 0) {
+ /* Modifier is effectively disabled, but still update settings if runtime data
+ * was already allocated. */
+ if (runtime_data) {
+ runtime_data->settings = settings;
+ }
+
+ return false;
+ }
+
+ /* Allocate runtime data if it did not exist yet. */
+ if (runtime_data == NULL) {
+ runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
+ smd->modifier.runtime = runtime_data;
+ }
+ runtime_data->settings = settings;
+ return true;
}
static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
@@ -83,11 +98,6 @@ static bool is_subdivision_evaluation_possible_on_gpu(void)
return false;
}
- const int available_evaluators = openSubdiv_getAvailableEvaluators();
- if ((available_evaluators & OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) == 0) {
- return false;
- }
-
return true;
}
@@ -133,37 +143,27 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
{
- return BLI_session_uuid_is_generated(&mesh->runtime.subsurf_session_uuid);
+ SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ return runtime_data && runtime_data->has_gpu_subdiv;
}
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,
+Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,
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);
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(
+ runtime_data->subdiv, &runtime_data->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) {
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index ba2df362b92..efabb4f039a 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -926,11 +926,9 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
int x;
for (x = 1; x < edgeSize - 1; x++) {
- /* This gives errors with -debug-fpe
- * the normals don't seem to be unit length.
- * this is most likely caused by edges with no
- * faces which are now zerod out, see comment in:
- * ccgSubSurf__calcVertNormals(), - campbell */
+ /* NOTE(@campbellbarton): This gives errors with `--debug-fpe` the normals don't seem to be
+ * unit length. This is most likely caused by edges with no faces which are now zeroed out,
+ * see comment in: `ccgSubSurf__calcVertNormals()`. */
vd = ccgSubSurf_getEdgeData(ss, e, x);
ccgDM_to_MVert(&mvert[i++], &key, vd);
}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index f9d3a44e5cb..cd1af5a8de4 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -336,7 +336,11 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
tracking->stabilization.filter = TRACKING_FILTER_BILINEAR;
tracking->stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
- BKE_tracking_object_add(tracking, "Camera");
+ /* Descending order of average error: tracks with the highest error are on top. */
+ tracking->dopesheet.sort_method = TRACKING_DOPE_SORT_AVERAGE_ERROR;
+ tracking->dopesheet.flag |= TRACKING_DOPE_SORT_INVERSE;
+
+ BKE_tracking_object_add(tracking, DATA_("Camera"));
}
ListBase *BKE_tracking_get_active_tracks(MovieTracking *tracking)
@@ -2794,6 +2798,96 @@ ImBuf *BKE_tracking_get_search_imbuf(ImBuf *ibuf,
return searchibuf;
}
+BLI_INLINE int plane_marker_size_len_in_pixels(const float a[2],
+ const float b[2],
+ const int frame_width,
+ const int frame_height)
+{
+ const float a_px[2] = {a[0] * frame_width, a[1] * frame_height};
+ const float b_px[2] = {b[0] * frame_width, b[1] * frame_height};
+
+ return ceilf(len_v2v2(a_px, b_px));
+}
+
+ImBuf *BKE_tracking_get_plane_imbuf(const ImBuf *frame_ibuf,
+ const MovieTrackingPlaneMarker *plane_marker)
+{
+ /* Alias for corners, allowing shorter access to coordinates. */
+ const float(*corners)[2] = plane_marker->corners;
+
+ /* Dimensions of the frame image in pixels. */
+ const int frame_width = frame_ibuf->x;
+ const int frame_height = frame_ibuf->y;
+
+ /* Lengths of left and right edges of the plane marker, in pixels. */
+ const int left_side_len_px = plane_marker_size_len_in_pixels(
+ corners[0], corners[3], frame_width, frame_height);
+ const int right_side_len_px = plane_marker_size_len_in_pixels(
+ corners[1], corners[2], frame_width, frame_height);
+
+ /* Lengths of top and bottom edges of the plane marker, in pixels. */
+ const int top_side_len_px = plane_marker_size_len_in_pixels(
+ corners[3], corners[2], frame_width, frame_height);
+ const int bottom_side_len_px = plane_marker_size_len_in_pixels(
+ corners[0], corners[1], frame_width, frame_height);
+
+ /* Choose the number of samples as a maximum of the corresponding sides in pixels. */
+ const int num_samples_x = max_ii(top_side_len_px, bottom_side_len_px);
+ const int num_samples_y = max_ii(left_side_len_px, right_side_len_px);
+
+ /* Create new result image with the same type of content as the original. */
+ ImBuf *plane_ibuf = IMB_allocImBuf(
+ num_samples_x, num_samples_y, 32, frame_ibuf->rect_float ? IB_rectfloat : IB_rect);
+
+ /* Calculate corner coordinates in pixel space, as separate X/Y arrays. */
+ const double src_pixel_x[4] = {corners[0][0] * frame_width,
+ corners[1][0] * frame_width,
+ corners[2][0] * frame_width,
+ corners[3][0] * frame_width};
+ const double src_pixel_y[4] = {corners[0][1] * frame_height,
+ corners[1][1] * frame_height,
+ corners[2][1] * frame_height,
+ corners[3][1] * frame_height};
+
+ /* Warped Position is unused but is expected to be provided by the API. */
+ double warped_position_x, warped_position_y;
+
+ /* Actual sampling. */
+ if (frame_ibuf->rect_float != NULL) {
+ libmv_samplePlanarPatchFloat(frame_ibuf->rect_float,
+ frame_ibuf->x,
+ frame_ibuf->y,
+ 4,
+ src_pixel_x,
+ src_pixel_y,
+ num_samples_x,
+ num_samples_y,
+ NULL,
+ plane_ibuf->rect_float,
+ &warped_position_x,
+ &warped_position_y);
+ }
+ else {
+ libmv_samplePlanarPatchByte((unsigned char *)frame_ibuf->rect,
+ frame_ibuf->x,
+ frame_ibuf->y,
+ 4,
+ src_pixel_x,
+ src_pixel_y,
+ num_samples_x,
+ num_samples_y,
+ NULL,
+ (unsigned char *)plane_ibuf->rect,
+ &warped_position_x,
+ &warped_position_y);
+ }
+
+ plane_ibuf->rect_colorspace = frame_ibuf->rect_colorspace;
+ plane_ibuf->float_colorspace = frame_ibuf->float_colorspace;
+
+ return plane_ibuf;
+}
+
void BKE_tracking_disable_channels(
ImBuf *ibuf, bool disable_red, bool disable_green, bool disable_blue, bool grayscale)
{
@@ -2904,6 +2998,10 @@ static int channels_average_error_sort(const void *a, const void *b)
return 1;
}
+ if (channel_a->track->error == channel_b->track->error) {
+ return channels_alpha_sort(a, b);
+ }
+
return 0;
}
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index d86a0c10f01..e2e0b4227e3 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -362,7 +362,7 @@ static MovieTrackingMarker *get_tracking_data_point(StabContext *ctx,
*
* As a simple default, we use the weighted average of the location markers
* of the current frame as pivot point. TODO: It is planned to add further
- * options, like e.g. anchoring the pivot point at the canvas. Moreover,
+ * options, like e.g. anchoring the pivot point at the canvas. Moreover,
* it is planned to allow for a user controllable offset.
*/
static void setup_pivot(const float ref_pos[2], float r_pivot[2])
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index 30e02e5411b..b31632f0234 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -460,11 +460,20 @@ static size_t unit_as_string(char *str,
}
double value_conv = (value / unit->scalar) - unit->bias;
+ bool strip_skip = false;
+
+ /* Negative precision is used to disable stripping of zeroes.
+ * This reduces text jumping when changing values. */
+ if (prec < 0) {
+ strip_skip = true;
+ prec *= -1;
+ }
/* Adjust precision to expected number of significant digits.
* Note that here, we shall not have to worry about very big/small numbers, units are expected
* to replace 'scientific notation' in those cases. */
prec -= integer_digits_d(value_conv);
+
CLAMP(prec, 0, 6);
/* Convert to a string. */
@@ -478,12 +487,14 @@ static size_t unit_as_string(char *str,
size_t i = len - 1;
if (prec > 0) {
- while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
- str[i--] = pad;
- }
+ if (!strip_skip) {
+ while (i > 0 && str[i] == '0') { /* 4.300 -> 4.3 */
+ str[i--] = pad;
+ }
- if (i > 0 && str[i] == '.') { /* 10. -> 10 */
- str[i--] = pad;
+ if (i > 0 && str[i] == '.') { /* 10. -> 10 */
+ str[i--] = pad;
+ }
}
}
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 307466d7dc9..82405830437 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -97,12 +97,7 @@ static struct VolumeFileCache {
/* Cache Entry */
struct Entry {
Entry(const std::string &filepath, const openvdb::GridBase::Ptr &grid)
- : filepath(filepath),
- grid_name(grid->getName()),
- grid(grid),
- is_loaded(false),
- num_metadata_users(0),
- num_tree_users(0)
+ : filepath(filepath), grid_name(grid->getName()), grid(grid)
{
}
@@ -110,9 +105,7 @@ static struct VolumeFileCache {
: filepath(other.filepath),
grid_name(other.grid_name),
grid(other.grid),
- is_loaded(other.is_loaded),
- num_metadata_users(0),
- num_tree_users(0)
+ is_loaded(other.is_loaded)
{
}
@@ -151,12 +144,12 @@ static struct VolumeFileCache {
blender::Map<int, openvdb::GridBase::Ptr> simplified_grids;
/* Has the grid tree been loaded? */
- mutable bool is_loaded;
+ mutable bool is_loaded = false;
/* Error message if an error occurred while loading. */
std::string error_msg;
/* User counting. */
- int num_metadata_users;
- int num_tree_users;
+ int num_metadata_users = 0;
+ int num_tree_users = 0;
/* Mutex for on-demand reading of tree. */
mutable std::mutex mutex;
};
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c
index ef0a3069815..0265dd037b1 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.c
@@ -67,6 +67,8 @@ static void workspace_foreach_id(ID *id, LibraryForeachIDData *data)
{
WorkSpace *workspace = (WorkSpace *)id;
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, workspace->pin_scene, IDWALK_CB_NOP);
+
LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, layout->screen, IDWALK_CB_USER);
}
@@ -120,6 +122,15 @@ static void workspace_blend_read_lib(BlendLibReader *reader, ID *id)
WorkSpace *workspace = (WorkSpace *)id;
Main *bmain = BLO_read_lib_get_main(reader);
+ /* Do not keep the scene reference when appending a workspace. Setting a scene for a workspace is
+ * a convenience feature, but the workspace should never truly depend on scene data. */
+ if (ID_IS_LINKED(id)) {
+ workspace->pin_scene = NULL;
+ }
+ else {
+ BLO_read_id_address(reader, NULL, &workspace->pin_scene);
+ }
+
/* Restore proper 'parent' pointers to relevant data, and clean up unused/invalid entries. */
LISTBASE_FOREACH_MUTABLE (WorkSpaceDataRelation *, relation, &workspace->hook_layout_relations) {
relation->parent = NULL;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 5e11cd0703a..883591e3e87 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -1485,7 +1485,7 @@ void BKE_ffmpeg_preset_set(RenderData *rd, int preset)
}
}
-void BKE_ffmpeg_image_type_verify(RenderData *rd, ImageFormatData *imf)
+void BKE_ffmpeg_image_type_verify(RenderData *rd, const ImageFormatData *imf)
{
int audio = 0;
diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh
index e80dad82d01..a20239f214f 100644
--- a/source/blender/blenlib/BLI_any.hh
+++ b/source/blender/blenlib/BLI_any.hh
@@ -13,6 +13,7 @@
*/
#include <algorithm>
+#include <cstring>
#include <utility>
#include "BLI_memory_utils.hh"
@@ -26,6 +27,7 @@ namespace detail {
* Additional type specific #ExtraInfo can be embedded here as well.
*/
template<typename ExtraInfo> struct AnyTypeInfo {
+ /* The pointers are allowed to be null, which means that the implementation is trivial. */
void (*copy_construct)(void *dst, const void *src);
void (*move_construct)(void *dst, void *src);
void (*destruct)(void *src);
@@ -38,10 +40,15 @@ template<typename ExtraInfo> struct AnyTypeInfo {
*/
template<typename ExtraInfo, typename T>
static constexpr AnyTypeInfo<ExtraInfo> info_for_inline = {
- [](void *dst, const void *src) { new (dst) T(*(const T *)src); },
- [](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); },
- [](void *src) { std::destroy_at(((T *)src)); },
- [](const void *src) { return src; },
+ is_trivially_copy_constructible_extended_v<T> ?
+ nullptr :
+ +[](void *dst, const void *src) { new (dst) T(*(const T *)src); },
+ is_trivially_move_constructible_extended_v<T> ?
+ nullptr :
+ +[](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); },
+ is_trivially_destructible_extended_v<T> ? nullptr :
+ +[](void *src) { std::destroy_at(((T *)src)); },
+ nullptr,
ExtraInfo::template get<T>()};
/**
@@ -92,12 +99,14 @@ class Any {
using RealExtraInfo =
std::conditional_t<std::is_void_v<ExtraInfo>, detail::NoExtraInfo, ExtraInfo>;
using Info = detail::AnyTypeInfo<RealExtraInfo>;
+ static constexpr size_t RealInlineBufferCapacity = std::max(InlineBufferCapacity,
+ sizeof(std::unique_ptr<int>));
/**
* 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_{};
+ AlignedBuffer<RealInlineBufferCapacity, Alignment> buffer_{};
/**
* Information about the type that is currently stored.
@@ -144,7 +153,12 @@ class Any {
Any(const Any &other) : info_(other.info_)
{
if (info_ != nullptr) {
- info_->copy_construct(&buffer_, &other.buffer_);
+ if (info_->copy_construct != nullptr) {
+ info_->copy_construct(&buffer_, &other.buffer_);
+ }
+ else {
+ memcpy(&buffer_, &other.buffer_, RealInlineBufferCapacity);
+ }
}
}
@@ -155,7 +169,12 @@ class Any {
Any(Any &&other) noexcept : info_(other.info_)
{
if (info_ != nullptr) {
- info_->move_construct(&buffer_, &other.buffer_);
+ if (info_->move_construct != nullptr) {
+ info_->move_construct(&buffer_, &other.buffer_);
+ }
+ else {
+ memcpy(&buffer_, &other.buffer_, RealInlineBufferCapacity);
+ }
}
}
@@ -179,7 +198,9 @@ class Any {
~Any()
{
if (info_ != nullptr) {
- info_->destruct(&buffer_);
+ if (info_->destruct != nullptr) {
+ info_->destruct(&buffer_);
+ }
}
}
@@ -213,7 +234,9 @@ class Any {
void reset()
{
if (info_ != nullptr) {
- info_->destruct(&buffer_);
+ if (info_->destruct != nullptr) {
+ info_->destruct(&buffer_);
+ }
}
info_ = nullptr;
}
@@ -265,14 +288,20 @@ class Any {
void *get()
{
BLI_assert(info_ != nullptr);
- return const_cast<void *>(info_->get(&buffer_));
+ if (info_->get != nullptr) {
+ return const_cast<void *>(info_->get(&buffer_));
+ }
+ return &buffer_;
}
/** Get a pointer to the stored value. */
const void *get() const
{
BLI_assert(info_ != nullptr);
- return info_->get(&buffer_);
+ if (info_->get != nullptr) {
+ return info_->get(&buffer_);
+ }
+ return &buffer_;
}
/**
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index 9bb7f3bfa8b..4a7fae6e98c 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -73,7 +73,7 @@ void _BLI_assert_unreachable_print(const char *file, int line, const char *funct
# define BLI_STATIC_ASSERT(a, msg) _STATIC_ASSERT(a);
# endif
#elif defined(__COVERITY__)
-/* Workaround error with coverity */
+/* Workaround error with COVERITY. */
# define BLI_STATIC_ASSERT(a, msg)
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
/* C11 */
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index 19d8525311c..973cc5c3d1e 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -27,7 +27,7 @@ typedef unsigned int BLI_bitmap;
/**
* Number of blocks needed to hold '_num' bits.
*/
-#define _BITMAP_NUM_BLOCKS(_num) (((_num) >> _BITMAP_POWER) + 1)
+#define _BITMAP_NUM_BLOCKS(_num) (((_num) + _BITMAP_MASK) >> _BITMAP_POWER)
/**
* Size (in bytes) used to hold '_num' bits.
@@ -54,6 +54,11 @@ typedef unsigned int BLI_bitmap;
((BLI_bitmap *)BLI_memarena_calloc(_mem, BLI_BITMAP_SIZE(_num))))
/**
+ * Declares a bitmap as a variable.
+ */
+#define BLI_BITMAP_DECLARE(_name, _num) BLI_bitmap _name[_BITMAP_NUM_BLOCKS(_num)] = {}
+
+/**
* Get the value of a single bit at '_index'.
*/
#define BLI_BITMAP_TEST(_bitmap, _index) \
@@ -137,6 +142,12 @@ void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
*/
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
+/**
+ * Find index of the lowest unset bit.
+ * Returns -1 if all the bits are set.
+ */
+int BLI_bitmap_find_first_unset(const BLI_bitmap *bitmap, size_t bits);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_bounds.hh b/source/blender/blenlib/BLI_bounds.hh
index d20382ed500..f5a18a0ea48 100644
--- a/source/blender/blenlib/BLI_bounds.hh
+++ b/source/blender/blenlib/BLI_bounds.hh
@@ -28,10 +28,11 @@ template<typename T> static std::optional<MinMaxResult<T>> min_max(Span<T> value
if (values.is_empty()) {
return std::nullopt;
}
+ const MinMaxResult<T> init{values.first(), values.first()};
return threading::parallel_reduce(
values.index_range(),
1024,
- MinMaxResult<T>(),
+ init,
[&](IndexRange range, const MinMaxResult<T> &init) {
MinMaxResult<T> result = init;
for (const int i : range) {
@@ -55,10 +56,11 @@ static std::optional<MinMaxResult<T>> min_max_with_radii(Span<T> values, Span<Ra
if (values.is_empty()) {
return std::nullopt;
}
+ const MinMaxResult<T> init{values.first(), values.first()};
return threading::parallel_reduce(
values.index_range(),
1024,
- MinMaxResult<T>(),
+ init,
[&](IndexRange range, const MinMaxResult<T> &init) {
MinMaxResult<T> result = init;
for (const int i : range) {
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index 98fd7d0f15d..b1b9aeb17f1 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -79,7 +79,7 @@ enum class eSpace {
};
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;
@@ -167,7 +167,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al
}
/**
- * Convert to its byte encoded counter space.
+ * Convert to its byte encoded counterpart.
*/
ColorSceneLinearByteEncoded4b<Alpha> encode() const
{
@@ -179,7 +179,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al
/**
* Convert color and alpha association to premultiplied alpha.
*
- * Does nothing when color has already a premultiplied alpha.
+ * Does nothing when color already has a premultiplied alpha.
*/
ColorSceneLinear4f<eAlpha::Premultiplied> premultiply_alpha() const
{
@@ -196,7 +196,7 @@ class ColorSceneLinear4f final : public ColorRGBA<float, eSpace::SceneLinear, Al
/**
* Convert color and alpha association to straight alpha.
*
- * Does nothing when color has straighten alpha.
+ * Does nothing when color has straight alpha.
*/
ColorSceneLinear4f<eAlpha::Straight> unpremultiply_alpha() const
{
@@ -228,7 +228,7 @@ class ColorSceneLinearByteEncoded4b final
}
/**
- * Convert to back to float color.
+ * Convert to a float color.
*/
ColorSceneLinear4f<Alpha> decode() const
{
diff --git a/source/blender/blenlib/BLI_cpp_type.hh b/source/blender/blenlib/BLI_cpp_type.hh
index ed680214602..cc48b456da7 100644
--- a/source/blender/blenlib/BLI_cpp_type.hh
+++ b/source/blender/blenlib/BLI_cpp_type.hh
@@ -626,6 +626,11 @@ class CPPType : NonCopyable, NonMovable {
fill_construct_indices_(value, dst, mask);
}
+ bool can_exist_in_buffer(const int64_t buffer_size, const int64_t buffer_alignment) const
+ {
+ return size_ <= buffer_size && alignment_ <= buffer_alignment;
+ }
+
void print(const void *value, std::stringstream &ss) const
{
BLI_assert(this->pointer_can_point_to_instance(value));
diff --git a/source/blender/blenlib/BLI_float3x3.hh b/source/blender/blenlib/BLI_float3x3.hh
index 62478556d9b..6a9e7dd04f0 100644
--- a/source/blender/blenlib/BLI_float3x3.hh
+++ b/source/blender/blenlib/BLI_float3x3.hh
@@ -152,6 +152,13 @@ struct float3x3 {
return result;
}
+ friend float3 operator*(const float3x3 &a, const float3 &b)
+ {
+ float3 result;
+ mul_v3_m3v3(result, a.values, b);
+ return result;
+ }
+
void operator*=(const float3x3 &other)
{
mul_m3_m3_post(values, other.values);
diff --git a/source/blender/blenlib/BLI_generic_span.hh b/source/blender/blenlib/BLI_generic_span.hh
index 4c0bfc83ba8..143ab235d2e 100644
--- a/source/blender/blenlib/BLI_generic_span.hh
+++ b/source/blender/blenlib/BLI_generic_span.hh
@@ -16,20 +16,31 @@ namespace blender {
*/
class GSpan {
protected:
- const CPPType *type_;
- const void *data_;
- int64_t size_;
+ const CPPType *type_ = nullptr;
+ const void *data_ = nullptr;
+ int64_t size_ = 0;
public:
- GSpan(const CPPType &type, const void *buffer, int64_t size)
- : type_(&type), data_(buffer), size_(size)
+ GSpan() = default;
+
+ GSpan(const CPPType *type, const void *buffer, int64_t size)
+ : type_(type), data_(buffer), size_(size)
{
BLI_assert(size >= 0);
BLI_assert(buffer != nullptr || size == 0);
- BLI_assert(type.pointer_has_valid_alignment(buffer));
+ BLI_assert(size == 0 || type != nullptr);
+ BLI_assert(type == nullptr || type->pointer_has_valid_alignment(buffer));
+ }
+
+ GSpan(const CPPType &type, const void *buffer, int64_t size) : GSpan(&type, buffer, size)
+ {
+ }
+
+ GSpan(const CPPType &type) : type_(&type)
+ {
}
- GSpan(const CPPType &type) : GSpan(type, nullptr, 0)
+ GSpan(const CPPType *type) : type_(type)
{
}
@@ -41,9 +52,15 @@ class GSpan {
const CPPType &type() const
{
+ BLI_assert(type_ != nullptr);
return *type_;
}
+ const CPPType *type_ptr() const
+ {
+ return type_;
+ }
+
bool is_empty() const
{
return size_ == 0;
@@ -76,7 +93,7 @@ class GSpan {
BLI_assert(start >= 0);
BLI_assert(size >= 0);
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);
+ return GSpan(type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
}
GSpan slice(const IndexRange range) const
@@ -91,20 +108,31 @@ class GSpan {
*/
class GMutableSpan {
protected:
- const CPPType *type_;
- void *data_;
- int64_t size_;
+ const CPPType *type_ = nullptr;
+ void *data_ = nullptr;
+ int64_t size_ = 0;
public:
- GMutableSpan(const CPPType &type, void *buffer, int64_t size)
- : type_(&type), data_(buffer), size_(size)
+ GMutableSpan() = default;
+
+ GMutableSpan(const CPPType *type, void *buffer, int64_t size)
+ : type_(type), data_(buffer), size_(size)
{
BLI_assert(size >= 0);
BLI_assert(buffer != nullptr || size == 0);
- BLI_assert(type.pointer_has_valid_alignment(buffer));
+ BLI_assert(size == 0 || type != nullptr);
+ BLI_assert(type == nullptr || type->pointer_has_valid_alignment(buffer));
+ }
+
+ GMutableSpan(const CPPType &type, void *buffer, int64_t size) : GMutableSpan(&type, buffer, size)
+ {
+ }
+
+ GMutableSpan(const CPPType &type) : type_(&type)
+ {
}
- GMutableSpan(const CPPType &type) : GMutableSpan(type, nullptr, 0)
+ GMutableSpan(const CPPType *type) : type_(type)
{
}
@@ -116,14 +144,20 @@ class GMutableSpan {
operator GSpan() const
{
- return GSpan(*type_, data_, size_);
+ return GSpan(type_, data_, size_);
}
const CPPType &type() const
{
+ BLI_assert(type_ != nullptr);
return *type_;
}
+ const CPPType *type_ptr() const
+ {
+ return type_;
+ }
+
bool is_empty() const
{
return size_ == 0;
diff --git a/source/blender/blenlib/BLI_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh
index d02760d9178..43ca16a894f 100644
--- a/source/blender/blenlib/BLI_generic_virtual_array.hh
+++ b/source/blender/blenlib/BLI_generic_virtual_array.hh
@@ -42,11 +42,7 @@ class GVArrayImpl {
virtual void get(int64_t index, void *r_value) const;
virtual void get_to_uninitialized(int64_t index, void *r_value) const = 0;
- virtual bool is_span() const;
- virtual GSpan get_internal_span() const;
-
- virtual bool is_single() const;
- virtual void get_internal_single(void *UNUSED(r_value)) const;
+ virtual CommonVArrayInfo common_info() const;
virtual void materialize(const IndexMask mask, void *dst) const;
virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
@@ -55,13 +51,14 @@ class GVArrayImpl {
virtual void materialize_compressed_to_uninitialized(IndexMask mask, void *dst) const;
virtual bool try_assign_VArray(void *varray) const;
- virtual bool may_have_ownership() const;
};
/* A generic version of #VMutableArrayImpl. */
class GVMutableArrayImpl : public GVArrayImpl {
public:
- GVMutableArrayImpl(const CPPType &type, int64_t size);
+ GVMutableArrayImpl(const CPPType &type, int64_t size) : GVArrayImpl(type, size)
+ {
+ }
virtual void set_by_copy(int64_t index, const void *value);
virtual void set_by_relocate(int64_t index, void *value);
@@ -105,7 +102,7 @@ class GVArrayCommon {
Storage storage_;
protected:
- GVArrayCommon();
+ GVArrayCommon() = default;
GVArrayCommon(const GVArrayCommon &other);
GVArrayCommon(GVArrayCommon &&other) noexcept;
GVArrayCommon(const GVArrayImpl *impl);
@@ -139,6 +136,8 @@ class GVArrayCommon {
void materialize_compressed(IndexMask mask, void *dst) const;
void materialize_compressed_to_uninitialized(IndexMask mask, void *dst) const;
+ CommonVArrayInfo common_info() const;
+
/**
* Returns true when the virtual array is stored as a span internally.
*/
@@ -186,6 +185,10 @@ class GVArray : public GVArrayCommon {
GVArray(const GVArrayImpl *impl);
GVArray(std::shared_ptr<const GVArrayImpl> impl);
+ GVArray(varray_tag::span /* tag */, GSpan span);
+ GVArray(varray_tag::single_ref /* tag */, const CPPType &type, int64_t size, const void *value);
+ GVArray(varray_tag::single /* tag */, const CPPType &type, int64_t size, const void *value);
+
template<typename T> GVArray(const VArray<T> &varray);
template<typename T> VArray<T> typed() const;
@@ -254,22 +257,25 @@ class GVMutableArray : public GVArrayCommon {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArray_GSpan and #GVMutableArray_GSpan.
+/** \name #GVArraySpan and #GMutableVArraySpan.
* \{ */
-/* A generic version of VArray_Span. */
-class GVArray_GSpan : public GSpan {
+/* A generic version of VArraySpan. */
+class GVArraySpan : public GSpan {
private:
GVArray varray_;
void *owned_data_ = nullptr;
public:
- GVArray_GSpan(GVArray varray);
- ~GVArray_GSpan();
+ GVArraySpan();
+ GVArraySpan(GVArray varray);
+ GVArraySpan(GVArraySpan &&other);
+ ~GVArraySpan();
+ GVArraySpan &operator=(GVArraySpan &&other);
};
-/* A generic version of VMutableArray_Span. */
-class GVMutableArray_GSpan : public GMutableSpan {
+/* A generic version of MutableVArraySpan. */
+class GMutableVArraySpan : public GMutableSpan, NonCopyable, NonMovable {
private:
GVMutableArray varray_;
void *owned_data_ = nullptr;
@@ -277,8 +283,13 @@ class GVMutableArray_GSpan : public GMutableSpan {
bool show_not_saved_warning_ = true;
public:
- GVMutableArray_GSpan(GVMutableArray varray, bool copy_values_to_span = true);
- ~GVMutableArray_GSpan();
+ GMutableVArraySpan();
+ GMutableVArraySpan(GVMutableArray varray, bool copy_values_to_span = true);
+ GMutableVArraySpan(GMutableVArraySpan &&other);
+ ~GMutableVArraySpan();
+ GMutableVArraySpan &operator=(GMutableVArraySpan &&other);
+
+ const GVMutableArray &varray() const;
void save();
void disable_not_applied_warning();
@@ -312,26 +323,6 @@ template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl {
new (r_value) T(varray_[index]);
}
- bool is_span() const override
- {
- return varray_.is_span();
- }
-
- GSpan get_internal_span() const override
- {
- return GSpan(varray_.get_internal_span());
- }
-
- bool is_single() const override
- {
- return varray_.is_single();
- }
-
- void get_internal_single(void *r_value) const override
- {
- *(T *)r_value = varray_.get_internal_single();
- }
-
void materialize(const IndexMask mask, void *dst) const override
{
varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
@@ -358,9 +349,9 @@ template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl {
return true;
}
- bool may_have_ownership() const override
+ CommonVArrayInfo common_info() const override
{
- return varray_.may_have_ownership();
+ return varray_.common_info();
}
};
@@ -384,26 +375,9 @@ template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> {
return value;
}
- bool is_span() const override
- {
- return varray_.is_span();
- }
-
- Span<T> get_internal_span() const override
- {
- return varray_.get_internal_span().template typed<T>();
- }
-
- bool is_single() const override
+ CommonVArrayInfo common_info() const override
{
- return varray_.is_single();
- }
-
- T get_internal_single() const override
- {
- T value;
- varray_.get_internal_single(&value);
- return value;
+ return varray_.common_info();
}
bool try_assign_GVArray(GVArray &varray) const override
@@ -412,11 +386,6 @@ template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> {
return true;
}
- bool may_have_ownership() const override
- {
- return varray_.may_have_ownership();
- }
-
void materialize(IndexMask mask, MutableSpan<T> r_span) const override
{
varray_.materialize(mask, r_span.data());
@@ -461,25 +430,9 @@ template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutab
new (r_value) T(varray_[index]);
}
- bool is_span() const override
- {
- return varray_.is_span();
- }
-
- GSpan get_internal_span() const override
+ CommonVArrayInfo common_info() const override
{
- Span<T> span = varray_.get_internal_span();
- return span;
- }
-
- bool is_single() const override
- {
- return varray_.is_single();
- }
-
- void get_internal_single(void *r_value) const override
- {
- *(T *)r_value = varray_.get_internal_single();
+ return varray_.common_info();
}
void set_by_copy(const int64_t index, const void *value) override
@@ -537,11 +490,6 @@ template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutab
*(VMutableArray<T> *)varray = varray_;
return true;
}
-
- bool may_have_ownership() const override
- {
- return varray_.may_have_ownership();
- }
};
/* Used to convert an generic mutable virtual array into a typed one. */
@@ -570,26 +518,9 @@ template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutabl
varray_.set_by_relocate(index, &value);
}
- bool is_span() const override
- {
- return varray_.is_span();
- }
-
- Span<T> get_internal_span() const override
- {
- return varray_.get_internal_span().template typed<T>();
- }
-
- bool is_single() const override
+ CommonVArrayInfo common_info() const override
{
- return varray_.is_single();
- }
-
- T get_internal_single() const override
- {
- T value;
- varray_.get_internal_single(&value);
- return value;
+ return varray_.common_info();
}
bool try_assign_GVArray(GVArray &varray) const override
@@ -604,11 +535,6 @@ template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutabl
return true;
}
- bool may_have_ownership() const override
- {
- return varray_.may_have_ownership();
- }
-
void materialize(IndexMask mask, MutableSpan<T> r_span) const override
{
varray_.materialize(mask, r_span.data());
@@ -643,10 +569,18 @@ class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
const int64_t element_size_;
public:
- GVArrayImpl_For_GSpan(const GMutableSpan span);
+ GVArrayImpl_For_GSpan(const GMutableSpan span)
+ : GVMutableArrayImpl(span.type(), span.size()),
+ data_(span.data()),
+ element_size_(span.type().size())
+ {
+ }
protected:
- GVArrayImpl_For_GSpan(const CPPType &type, int64_t size);
+ GVArrayImpl_For_GSpan(const CPPType &type, int64_t size)
+ : GVMutableArrayImpl(type, size), element_size_(type.size())
+ {
+ }
public:
void get(int64_t index, void *r_value) const override;
@@ -656,8 +590,7 @@ class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
void set_by_move(int64_t index, void *value) override;
void set_by_relocate(int64_t index, void *value) override;
- bool is_span() const override;
- GSpan get_internal_span() const override;
+ CommonVArrayInfo common_info() const override;
virtual void materialize(const IndexMask mask, void *dst) const override;
virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const override;
@@ -667,6 +600,57 @@ class GVArrayImpl_For_GSpan : public GVMutableArrayImpl {
void *dst) const override;
};
+class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
+ public:
+ using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
+
+ private:
+ CommonVArrayInfo common_info() const override;
+};
+
+template<> inline constexpr bool is_trivial_extended_v<GVArrayImpl_For_GSpan_final> = true;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #GVArrayImpl_For_SingleValueRef.
+ * \{ */
+
+class GVArrayImpl_For_SingleValueRef : public GVArrayImpl {
+ protected:
+ const void *value_ = nullptr;
+
+ public:
+ GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
+ : GVArrayImpl(type, size), value_(value)
+ {
+ }
+
+ protected:
+ GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size)
+ {
+ }
+
+ void get(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized(const int64_t index, void *r_value) const override;
+ CommonVArrayInfo common_info() const override;
+ void materialize(const IndexMask mask, void *dst) const override;
+ void materialize_to_uninitialized(const IndexMask mask, void *dst) const override;
+ void materialize_compressed(const IndexMask mask, void *dst) const override;
+ void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override;
+};
+
+class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef {
+ public:
+ using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef;
+
+ private:
+ CommonVArrayInfo common_info() const override;
+};
+
+template<>
+inline constexpr bool is_trivial_extended_v<GVArrayImpl_For_SingleValueRef_final> = true;
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -790,6 +774,11 @@ inline GVArrayCommon::operator bool() const
return impl_ != nullptr;
}
+inline CommonVArrayInfo GVArrayCommon::common_info() const
+{
+ return impl_->common_info();
+}
+
inline int64_t GVArrayCommon::size() const
{
if (impl_ == nullptr) {
@@ -809,6 +798,22 @@ inline bool GVArrayCommon::is_empty() const
/** \name Inline methods for #GVArray.
* \{ */
+inline GVArray::GVArray(varray_tag::span /* tag */, const 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()};
+ this->emplace<GVArrayImpl_For_GSpan_final>(mutable_span);
+}
+
+inline GVArray::GVArray(varray_tag::single_ref /* tag */,
+ const CPPType &type,
+ const int64_t size,
+ const void *value)
+{
+ this->emplace<GVArrayImpl_For_SingleValueRef_final>(type, size, value);
+}
+
namespace detail {
template<typename StorageT> constexpr GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
{
@@ -846,25 +851,20 @@ template<typename T> inline GVArray::GVArray(const VArray<T> &varray)
if (!varray) {
return;
}
- if (varray.try_assign_GVArray(*this)) {
+ const CommonVArrayInfo info = varray.common_info();
+ if (info.type == CommonVArrayInfo::Type::Single) {
+ *this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), info.data);
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_single()) {
- T value = varray.get_internal_single();
- *this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value);
- }
- else if (varray.is_span()) {
- Span<T> data = varray.get_internal_span();
- *this = GVArray::ForSpan(data);
+ /* Need to check for ownership, because otherwise the referenced data can be destructed when
+ * #this is destructed. */
+ if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
+ *this = GVArray::ForSpan(GSpan(CPPType::get<T>(), info.data, varray.size()));
}
- else {
- *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
+ if (varray.try_assign_GVArray(*this)) {
+ return;
}
+ *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray);
}
template<typename T> inline VArray<T> GVArray::typed() const
@@ -873,22 +873,19 @@ template<typename T> inline VArray<T> GVArray::typed() const
return {};
}
BLI_assert(impl_->type().is<T>());
+ const CommonVArrayInfo info = this->common_info();
+ if (info.type == CommonVArrayInfo::Type::Single) {
+ return VArray<T>::ForSingle(*static_cast<const T *>(info.data), this->size());
+ }
+ /* Need to check for ownership, because otherwise the referenced data can be destructed when
+ * #this is destructed. */
+ if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
+ return VArray<T>::ForSpan(Span<T>(static_cast<const T *>(info.data), this->size()));
+ }
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);
- }
- if (this->is_single()) {
- T value;
- this->get_internal_single(&value);
- return VArray<T>::ForSingle(value, this->size());
- }
- if (this->is_span()) {
- const Span<T> span = this->get_internal_span().typed<T>();
- return VArray<T>::ForSpan(span);
- }
return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this);
}
@@ -912,19 +909,16 @@ template<typename T> inline GVMutableArray::GVMutableArray(const VMutableArray<T
if (!varray) {
return;
}
- if (varray.try_assign_GVMutableArray(*this)) {
+ const CommonVArrayInfo info = varray.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
+ *this = GVMutableArray::ForSpan(
+ GMutableSpan(CPPType::get<T>(), const_cast<void *>(info.data), varray.size()));
return;
}
- if (varray.may_have_ownership()) {
- *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
- }
- else if (varray.is_span()) {
- MutableSpan<T> data = varray.get_internal_span();
- *this = GVMutableArray::ForSpan(data);
- }
- else {
- *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
+ if (varray.try_assign_GVMutableArray(*this)) {
+ return;
}
+ *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray);
}
template<typename T> inline VMutableArray<T> GVMutableArray::typed() const
@@ -933,17 +927,15 @@ template<typename T> inline VMutableArray<T> GVMutableArray::typed() const
return {};
}
BLI_assert(this->type().is<T>());
+ const CommonVArrayInfo info = this->common_info();
+ if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
+ return VMutableArray<T>::ForSpan(
+ MutableSpan<T>(const_cast<T *>(static_cast<const T *>(info.data)), this->size()));
+ }
VMutableArray<T> varray;
if (this->try_assign_VMutableArray(varray)) {
return varray;
}
- if (this->may_have_ownership()) {
- return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this);
- }
- 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);
}
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 7f90ec20b66..8743b135dff 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -562,7 +562,7 @@ 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
+ * 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.
diff --git a/source/blender/blenlib/BLI_hash_tables.hh b/source/blender/blenlib/BLI_hash_tables.hh
index 334634613a2..156fe481828 100644
--- a/source/blender/blenlib/BLI_hash_tables.hh
+++ b/source/blender/blenlib/BLI_hash_tables.hh
@@ -209,11 +209,11 @@ template<typename Key, Key EmptyValue, Key RemovedValue> struct TemplatedKeyInfo
};
/**
- * 0xffff...ffff indicates an empty slot.
- * 0xffff...fffe indicates a removed slot.
+ * `0xffff...ffff` indicates an empty slot.
+ * `0xffff...fffe` indicates a removed slot.
*
* Those specific values are used, because with them a single comparison is enough to check whether
- * a slot is occupied. The keys 0x0000...0000 and 0x0000...0001 also satisfy this constraint.
+ * a slot is occupied. The keys `0x0000...0000` and `0x0000...0001` also satisfy this constraint.
* However, nullptr is much more likely to be used as valid key.
*/
template<typename Pointer> struct PointerKeyInfo {
diff --git a/source/blender/blenlib/BLI_index_mask.hh b/source/blender/blenlib/BLI_index_mask.hh
index b87ab0afc98..22bdf090181 100644
--- a/source/blender/blenlib/BLI_index_mask.hh
+++ b/source/blender/blenlib/BLI_index_mask.hh
@@ -278,7 +278,7 @@ class IndexMask {
* before each range in the return value starts.
*/
Vector<IndexRange> extract_ranges_invert(const IndexRange full_range,
- Vector<int64_t> *r_skip_amounts) const;
+ Vector<int64_t> *r_skip_amounts = nullptr) const;
};
} // namespace blender
diff --git a/source/blender/blenlib/BLI_index_mask_ops.hh b/source/blender/blenlib/BLI_index_mask_ops.hh
index 48a1f27a2fa..e4eece11e83 100644
--- a/source/blender/blenlib/BLI_index_mask_ops.hh
+++ b/source/blender/blenlib/BLI_index_mask_ops.hh
@@ -13,6 +13,7 @@
#include "BLI_index_mask.hh"
#include "BLI_task.hh"
#include "BLI_vector.hh"
+#include "BLI_virtual_array.hh"
namespace blender::index_mask_ops {
@@ -57,4 +58,17 @@ inline IndexMask find_indices_based_on_predicate(const IndexMask indices_to_chec
return detail::find_indices_based_on_predicate__merge(indices_to_check, sub_masks, r_indices);
}
+/**
+ * Find the true indices in a virtual array. This is a version of
+ * #find_indices_based_on_predicate optimized for a virtual array input.
+ *
+ * \param parallel_grain_size: The grain size for when the virtual array isn't a span or a single
+ * value internally. This should be adjusted based on the expected cost of evaluating the virtual
+ * array-- more expensive virtual arrays should have smaller grain sizes.
+ */
+IndexMask find_indices_from_virtual_array(IndexMask indices_to_check,
+ const VArray<bool> &virtual_array,
+ int64_t parallel_grain_size,
+ Vector<int64_t> &r_indices);
+
} // namespace blender::index_mask_ops
diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh
index 7d5c2400bba..6fcc560d856 100644
--- a/source/blender/blenlib/BLI_index_range.hh
+++ b/source/blender/blenlib/BLI_index_range.hh
@@ -186,13 +186,25 @@ class IndexRange {
}
/**
- * Get the last element in the range.
- * Asserts when the range is empty.
+ * Get the nth last element in the range.
+ * Asserts when the range is empty or when n is negative.
*/
- constexpr int64_t last() const
+ constexpr int64_t last(const int64_t n = 0) const
{
+ BLI_assert(n >= 0);
+ BLI_assert(n < size_);
BLI_assert(this->size() > 0);
- return start_ + size_ - 1;
+ return start_ + size_ - 1 - n;
+ }
+
+ /**
+ * Get the element one before the beginning. The returned value is undefined when the range is
+ * empty, and the range must start after zero already.
+ */
+ constexpr int64_t one_before_start() const
+ {
+ BLI_assert(start_ > 0);
+ return start_ - 1;
}
/**
@@ -280,6 +292,15 @@ class IndexRange {
}
/**
+ * Move the range forward or backward within the larger array. The amount may be negative,
+ * but its absolute value cannot be greater than the existing start of the range.
+ */
+ constexpr IndexRange shift(int64_t n) const
+ {
+ return IndexRange(start_ + n, size_);
+ }
+
+ /**
* Get read-only access to a memory buffer that contains the range as actual numbers.
*/
Span<int64_t> as_span() const;
diff --git a/source/blender/blenlib/BLI_kdtree.h b/source/blender/blenlib/BLI_kdtree.h
index 696b2206b5f..954282b099a 100644
--- a/source/blender/blenlib/BLI_kdtree.h
+++ b/source/blender/blenlib/BLI_kdtree.h
@@ -2,10 +2,6 @@
#pragma once
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/** \file
* \ingroup bli
* \brief A KD-tree for nearest neighbor search.
@@ -54,7 +50,3 @@ extern "C" {
#undef KDTree
#undef KDTreeNearest
#undef KDTREE_PREFIX_ID
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h
index 08fa40fd972..4187724fbda 100644
--- a/source/blender/blenlib/BLI_kdtree_impl.h
+++ b/source/blender/blenlib/BLI_kdtree_impl.h
@@ -12,6 +12,10 @@
#define _BLI_CONCAT(MACRO_ARG1, MACRO_ARG2) _BLI_CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
#define BLI_kdtree_nd_(id) _BLI_CONCAT(KDTREE_PREFIX_ID, _##id)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct KDTree;
typedef struct KDTree KDTree;
@@ -80,6 +84,29 @@ int BLI_kdtree_nd_(range_search_with_len_squared_cb)(
const void *user_data),
const void *user_data) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+template<typename Fn>
+inline void BLI_kdtree_nd_(range_search_cb_cpp)(const KDTree *tree,
+ const float co[KD_DIMS],
+ float distance,
+ const Fn &fn)
+{
+ BLI_kdtree_nd_(range_search_cb)(
+ tree,
+ co,
+ distance,
+ [](void *user_data, const int index, const float *co, const float dist_sq) {
+ const Fn &fn = *static_cast<const Fn *>(user_data);
+ return fn(index, co, dist_sq);
+ },
+ const_cast<Fn *>(&fn));
+}
+#endif
+
#undef _BLI_CONCAT_AUX
#undef _BLI_CONCAT
#undef BLI_kdtree_nd_
diff --git a/source/blender/blenlib/BLI_length_parameterize.hh b/source/blender/blenlib/BLI_length_parameterize.hh
index f13641c3a65..c44bb94f65d 100644
--- a/source/blender/blenlib/BLI_length_parameterize.hh
+++ b/source/blender/blenlib/BLI_length_parameterize.hh
@@ -17,9 +17,9 @@ namespace blender::length_parameterize {
* Return the size of the necessary lengths array for a group of points, taking into account the
* possible last cyclic segment.
*
- * \note This is the same as #bke::curves::curve_segment_num.
+ * \note This is the same as #bke::curves::segments_num.
*/
-inline int lengths_num(const int points_num, const bool cyclic)
+inline int segments_num(const int points_num, const bool cyclic)
{
return cyclic ? points_num : points_num - 1;
}
@@ -30,7 +30,7 @@ inline int lengths_num(const int points_num, const bool cyclic)
template<typename T>
void accumulate_lengths(const Span<T> values, const bool cyclic, MutableSpan<float> lengths)
{
- BLI_assert(lengths.size() == lengths_num(values.size(), cyclic));
+ BLI_assert(lengths.size() == segments_num(values.size(), cyclic));
float length = 0.0f;
for (const int i : IndexRange(values.size() - 1)) {
length += math::distance(values[i], values[i + 1]);
@@ -42,57 +42,122 @@ void accumulate_lengths(const Span<T> values, const bool cyclic, MutableSpan<flo
}
template<typename T>
-void linear_interpolation(const Span<T> src,
- const Span<int> indices,
- const Span<float> factors,
- MutableSpan<T> dst)
+inline void linear_interpolation(const Span<T> src,
+ const Span<int> indices,
+ const Span<float> factors,
+ MutableSpan<T> dst)
{
BLI_assert(indices.size() == factors.size());
BLI_assert(indices.size() == dst.size());
- const int last_src_index = src.index_range().last();
+ const int last_src_index = src.size() - 1;
- int cyclic_sample_count = 0;
- for (int i = indices.index_range().last(); i > 0; i--) {
- if (indices[i] != last_src_index) {
- break;
+ for (const int i : dst.index_range()) {
+ const int prev_index = indices[i];
+ const float factor = factors[i];
+ const bool is_cyclic_case = prev_index == last_src_index;
+ if (is_cyclic_case) {
+ dst[i] = math::interpolate(src.last(), src.first(), factor);
+ }
+ else {
+ dst[i] = math::interpolate(src[prev_index], src[prev_index + 1], factor);
+ }
+ }
+}
+
+/**
+ * Passing this to consecutive calls of #sample_at_length can increase performance.
+ */
+struct SampleSegmentHint {
+ int segment_index = -1;
+ float segment_start;
+ float segment_length_inv;
+};
+
+/**
+ * \param accumulated_segment_lengths: Lengths of individual segments added up.
+ * \param sample_length: The position to sample at.
+ * \param r_segment_index: Returns the index of the segment that #sample_length is in.
+ * \param r_factor: Returns the position within the segment.
+ *
+ * \note #sample_length must not be outside of any segment.
+ */
+inline void sample_at_length(const Span<float> accumulated_segment_lengths,
+ float sample_length,
+ int &r_segment_index,
+ float &r_factor,
+ SampleSegmentHint *hint = nullptr)
+{
+ /* Use a shorter variable name. */
+ const Span<float> lengths = accumulated_segment_lengths;
+
+ BLI_assert(lengths.size() > 0);
+ BLI_assert(sample_length >= 0.0f);
+ BLI_assert(sample_length <= lengths.last());
+
+ if (hint != nullptr && hint->segment_index >= 0) {
+ const float length_in_segment = sample_length - hint->segment_start;
+ const float factor = length_in_segment * hint->segment_length_inv;
+ if (factor >= 0.0f && factor < 1.0f) {
+ r_segment_index = hint->segment_index;
+ r_factor = factor;
+ return;
}
- dst[i] = math::interpolate(src.last(), src.first(), factors[i]);
- cyclic_sample_count++;
}
- for (const int i : dst.index_range().drop_back(cyclic_sample_count)) {
- dst[i] = math::interpolate(src[indices[i]], src[indices[i] + 1], factors[i]);
+ const float total_length = lengths.last();
+ if (sample_length >= total_length) {
+ /* Return the last position on the last segment. */
+ r_segment_index = lengths.size() - 1;
+ r_factor = 1.0f;
+ return;
+ }
+
+ const int prev_point_index = std::upper_bound(lengths.begin(), lengths.end(), sample_length) -
+ lengths.begin();
+ const float segment_start = prev_point_index == 0 ? 0.0f : lengths[prev_point_index - 1];
+ const float segment_end = lengths[prev_point_index];
+ const float segment_length = segment_end - segment_start;
+ const float segment_length_inv = safe_divide(1.0f, segment_length);
+ const float length_in_segment = sample_length - segment_start;
+ const float factor = length_in_segment * segment_length_inv;
+
+ r_segment_index = prev_point_index;
+ r_factor = factor;
+
+ if (hint != nullptr) {
+ hint->segment_index = r_segment_index;
+ hint->segment_start = segment_start;
+ hint->segment_length_inv = segment_length_inv;
}
}
/**
- * Find the given number of points, evenly spaced along the provided length. For non-cyclic
- * sequences, the first point will always be included, and last point will always be included if
- * the #count is greater than zero. For cyclic sequences, the first point will always be included.
+ * Find evenly spaced samples along the lengths.
*
- * \warning The #count argument must be greater than zero.
+ * \param accumulated_segment_lengths: The accumulated lengths of the original elements being
+ * sampled. Could be calculated by #accumulate_lengths.
+ * \param include_last_point: Generally false for cyclic sequences and true otherwise.
+ * \param r_segment_indices: The index of the previous point at each sample.
+ * \param r_factors: The portion of the length in each segment at each sample.
*/
-void create_uniform_samples(Span<float> lengths,
- bool cyclic,
- MutableSpan<int> indices,
- MutableSpan<float> factors);
+void sample_uniform(Span<float> accumulated_segment_lengths,
+ bool include_last_point,
+ MutableSpan<int> r_segment_indices,
+ MutableSpan<float> r_factors);
/**
* For each provided sample length, find the segment index and interpolation factor.
*
- * \param lengths: The accumulated lengths of the original elements being sampled.
- * Could be calculated by #accumulate_lengths.
+ * \param accumulated_segment_lengths: The accumulated lengths of the original elements being
+ * sampled. Could be calculated by #accumulate_lengths.
* \param sample_lengths: Sampled locations in the #lengths array. Must be sorted and is expected
* to be within the range of the #lengths values.
- * \param cyclic: Whether the points described by the #lenghts input is cyclic. This is likely
- * redundant information theoretically.
- * \param indices: The index of the previous point at each sample.
- * \param factors: The portion of the length in each segment at each sample.
+ * \param r_segment_indices: The index of the previous point at each sample.
+ * \param r_factors: The portion of the length in each segment at each sample.
*/
-void create_samples_from_sorted_lengths(Span<float> lengths,
- Span<float> sample_lengths,
- bool cyclic,
- MutableSpan<int> indices,
- MutableSpan<float> factors);
+void sample_at_lengths(Span<float> accumulated_segment_lengths,
+ Span<float> sample_lengths,
+ MutableSpan<int> r_segment_indices,
+ MutableSpan<float> r_factors);
} // namespace blender::length_parameterize
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index f072a17f384..c0c4594ddc0 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -221,6 +221,19 @@ MINLINE unsigned int power_of_2_min_u(unsigned int x);
* with integers, to avoid gradual darkening when rounding down.
*/
MINLINE int divide_round_i(int a, int b);
+
+/**
+ * Integer division that returns the ceiling, instead of flooring like normal C division.
+ */
+MINLINE uint divide_ceil_u(uint a, uint b);
+MINLINE uint64_t divide_ceil_ul(uint64_t a, uint64_t b);
+
+/**
+ * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
+ */
+MINLINE uint ceil_to_multiple_u(uint a, uint b);
+MINLINE uint64_t ceil_to_multiple_ul(uint64_t a, uint64_t b);
+
/**
* modulo that handles negative numbers, works the same as Python's.
*/
diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh
index 034c6968c94..b15179f75b6 100644
--- a/source/blender/blenlib/BLI_math_base.hh
+++ b/source/blender/blenlib/BLI_math_base.hh
@@ -14,19 +14,9 @@
#include "BLI_math_base_safe.h"
#include "BLI_utildefines.h"
-#ifdef WITH_GMP
-# include "BLI_math_mpq.hh"
-#endif
-
namespace blender::math {
-template<typename T>
-inline constexpr bool is_math_float_type = (std::is_floating_point_v<T>
-#ifdef WITH_GMP
- || std::is_same_v<T, mpq_class>
-#endif
-);
-
+template<typename T> inline constexpr bool is_math_float_type = std::is_floating_point_v<T>;
template<typename T> inline constexpr bool is_math_integral_type = std::is_integral_v<T>;
template<typename T> inline bool is_zero(const T &a)
@@ -54,6 +44,16 @@ template<typename T> inline T max(const T &a, const T &b)
return std::max(a, b);
}
+template<typename T> inline void max_inplace(T &a, const T &b)
+{
+ a = math::max(a, b);
+}
+
+template<typename T> inline void min_inplace(T &a, const T &b)
+{
+ a = math::min(a, b);
+}
+
template<typename T> inline T clamp(const T &a, const T &min, const T &max)
{
return std::clamp(a, min, max);
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 64b820a22b0..6386a7f76f8 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -123,7 +123,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c
* 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
+ * 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);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 5c1b6c8d774..93b413ab755 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -136,7 +136,7 @@ bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[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).
+ * (normals pointing away from each other).
* - (1 << 0): (v1-v3) is flipped.
* - (1 << 1): (v2-v4) is flipped.
*/
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index edfe53bc938..c2dafbe3a1a 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -238,6 +238,7 @@ 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_m2_m2(float R[2][2], const float A[2][2]);
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]);
@@ -374,7 +375,7 @@ 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.
+ * This works well for transformation matrices, when a single axis is zeroed.
*/
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]);
diff --git a/source/blender/blenlib/BLI_math_mpq.hh b/source/blender/blenlib/BLI_math_mpq.hh
index 7b43c90da84..02c92705323 100644
--- a/source/blender/blenlib/BLI_math_mpq.hh
+++ b/source/blender/blenlib/BLI_math_mpq.hh
@@ -19,4 +19,10 @@
*/
# include "gmpxx.h"
+# include "BLI_math_base.hh"
+
+namespace blender::math {
+template<> inline constexpr bool is_math_float_type<mpq_class> = true;
+}
+
#endif /* WITH_GMP */
diff --git a/source/blender/blenlib/BLI_math_rotation.hh b/source/blender/blenlib/BLI_math_rotation.hh
index e8b746b34df..50a062162ad 100644
--- a/source/blender/blenlib/BLI_math_rotation.hh
+++ b/source/blender/blenlib/BLI_math_rotation.hh
@@ -15,4 +15,13 @@ namespace blender::math {
*/
float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, float angle);
+/**
+ * Rotate any arbitrary \a vector around the \a center position, with a unit-length \a axis
+ * and the specified \a angle.
+ */
+float3 rotate_around_axis(const float3 &vector,
+ const float3 &center,
+ const float3 &axis,
+ float angle);
+
} // namespace blender::math
diff --git a/source/blender/blenlib/BLI_math_vec_types.hh b/source/blender/blenlib/BLI_math_vec_types.hh
index e36bbedee32..7f20881dfa3 100644
--- a/source/blender/blenlib/BLI_math_vec_types.hh
+++ b/source/blender/blenlib/BLI_math_vec_types.hh
@@ -14,10 +14,6 @@
#include "BLI_utildefines.h"
-#ifdef WITH_GMP
-# include "BLI_math_mpq.hh"
-#endif
-
namespace blender {
/* clang-format off */
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index f3283371a3c..0b178064a4c 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -40,6 +40,10 @@ MINLINE void swap_v2_v2(float a[2], float b[2]);
MINLINE void swap_v3_v3(float a[3], float b[3]);
MINLINE void swap_v4_v4(float a[4], float b[4]);
+MINLINE void swap_v2_v2_db(double a[2], double b[2]);
+MINLINE void swap_v3_v3_db(double a[3], double b[3]);
+MINLINE void swap_v4_v4_db(double a[4], double b[4]);
+
/* unsigned char */
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh
index b9f0939674e..384c4b49070 100644
--- a/source/blender/blenlib/BLI_math_vector.hh
+++ b/source/blender/blenlib/BLI_math_vector.hh
@@ -49,6 +49,20 @@ template<typename T, int Size> inline bool is_any_zero(const vec_base<T, Size> &
return false;
}
+template<typename T, int Size>
+inline bool almost_equal_relative(const vec_base<T, Size> &a,
+ const vec_base<T, Size> &b,
+ const T &epsilon_factor)
+{
+ for (int i = 0; i < Size; i++) {
+ const float epsilon = epsilon_factor * math::abs(a[i]);
+ if (math::distance(a[i], b[i]) > epsilon) {
+ return false;
+ }
+ }
+ return true;
+}
+
template<typename T, int Size> inline vec_base<T, Size> abs(const vec_base<T, Size> &a)
{
vec_base<T, Size> result;
@@ -145,6 +159,39 @@ inline T safe_mod(const vec_base<T, Size> &a, const T &b)
return result;
}
+/**
+ * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
+ * In other words, it is equivalent to `divide_ceil(a, b) * b`.
+ * It is undefined if \a a is negative or \b b is not strictly positive.
+ */
+template<typename T, int Size, BLI_ENABLE_IF((is_math_integral_type<T>))>
+inline vec_base<T, Size> ceil_to_multiple(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
+{
+ vec_base<T, Size> result;
+ for (int i = 0; i < Size; i++) {
+ BLI_assert(a[i] >= 0);
+ BLI_assert(b[i] > 0);
+ result[i] = ((a[i] + b[i] - 1) / b[i]) * b[i];
+ }
+ return result;
+}
+
+/**
+ * Integer division that returns the ceiling, instead of flooring like normal C division.
+ * It is undefined if \a a is negative or \b b is not strictly positive.
+ */
+template<typename T, int Size, BLI_ENABLE_IF((is_math_integral_type<T>))>
+inline vec_base<T, Size> divide_ceil(const vec_base<T, Size> &a, const vec_base<T, Size> &b)
+{
+ vec_base<T, Size> result;
+ for (int i = 0; i < Size; i++) {
+ BLI_assert(a[i] >= 0);
+ BLI_assert(b[i] > 0);
+ result[i] = (a[i] + b[i] - 1) / b[i];
+ }
+ return result;
+}
+
template<typename T, int Size>
inline void min_max(const vec_base<T, Size> &vector,
vec_base<T, Size> &min,
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index 940542c9f1d..c2ad3ea761a 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -19,6 +19,21 @@
namespace blender {
/**
+ * Under some circumstances #std::is_trivial_v<T> is false even though we know that the type is
+ * actually trivial. Using that extra knowledge allows for some optimizations.
+ */
+template<typename T> inline constexpr bool is_trivial_extended_v = std::is_trivial_v<T>;
+template<typename T>
+inline constexpr bool is_trivially_destructible_extended_v = is_trivial_extended_v<T> ||
+ std::is_trivially_destructible_v<T>;
+template<typename T>
+inline constexpr bool is_trivially_copy_constructible_extended_v =
+ is_trivial_extended_v<T> || std::is_trivially_copy_constructible_v<T>;
+template<typename T>
+inline constexpr bool is_trivially_move_constructible_extended_v =
+ is_trivial_extended_v<T> || std::is_trivially_move_constructible_v<T>;
+
+/**
* Call the destructor on n consecutive values. For trivially destructible types, this does
* nothing.
*
@@ -38,7 +53,7 @@ template<typename T> void destruct_n(T *ptr, int64_t n)
/* This is not strictly necessary, because the loop below will be optimized away anyway. It is
* nice to make behavior this explicitly, though. */
- if (std::is_trivially_destructible_v<T>) {
+ if (is_trivially_destructible_extended_v<T>) {
return;
}
diff --git a/source/blender/blenlib/BLI_utildefines_iter.h b/source/blender/blenlib/BLI_utildefines_iter.h
index 870e90bd971..03dc775a66b 100644
--- a/source/blender/blenlib/BLI_utildefines_iter.h
+++ b/source/blender/blenlib/BLI_utildefines_iter.h
@@ -21,7 +21,7 @@
* (100, 3) -> [16, 49, 83]
* (100, 100) -> [0..99]
* </pre>
- * \note this is mainly useful for numbers that might not divide evenly into eachother.
+ * \note this is mainly useful for numbers that might not divide evenly into each other.
*/
#define BLI_FOREACH_SPARSE_RANGE(src, dst, i) \
for (int _src = (src), _src2 = _src * 2, _dst2 = (dst)*2, _error = _dst2 - _src, i = 0, _delta; \
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index c23d846d277..1f5f97d754d 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -451,8 +451,16 @@ class Vector {
*/
int64_t append_and_get_index(const T &value)
{
+ return this->append_and_get_index_as(value);
+ }
+ int64_t append_and_get_index(T &&value)
+ {
+ return this->append_and_get_index_as(std::move(value));
+ }
+ template<typename... ForwardValue> int64_t append_and_get_index_as(ForwardValue &&...value)
+ {
const int64_t index = this->size();
- this->append(value);
+ this->append_as(std::forward<ForwardValue>(value)...);
return index;
}
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 6efd1d6d769..438fcc4b8f7 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -35,6 +35,36 @@ class GVArray;
class GVMutableArray;
/**
+ * Is used to quickly check if a varray is a span or single value. This struct also allows
+ * retrieving multiple pieces of data with a single virtual method call.
+ */
+struct CommonVArrayInfo {
+ enum class Type : uint8_t {
+ /* Is not one of the common special types below. */
+ Any,
+ Span,
+ Single,
+ };
+
+ Type type = Type::Any;
+
+ /** True when the #data becomes a dangling pointer when the virtual array is destructed. */
+ bool may_have_ownership = true;
+
+ /**
+ * Points either to nothing, a single value or array of values, depending on #type.
+ * If this is a span of a mutable virtual array, it is safe to cast away const.
+ */
+ const void *data;
+
+ CommonVArrayInfo() = default;
+ CommonVArrayInfo(const Type _type, const bool _may_have_ownership, const void *_data)
+ : type(_type), may_have_ownership(_may_have_ownership), data(_data)
+ {
+ }
+};
+
+/**
* 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.
*/
@@ -65,47 +95,12 @@ template<typename T> class VArrayImpl {
*/
virtual T get(int64_t index) const = 0;
- /**
- * Return true when the virtual array is a plain array internally.
- */
- virtual bool is_span() const
+ virtual CommonVArrayInfo common_info() const
{
- return false;
- }
-
- /**
- * 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 {};
}
/**
- * Return true when the virtual array has the same value at every index.
- */
- virtual bool is_single() const
- {
- return false;
- }
-
- /**
- * 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 returns false by default. */
- BLI_assert_unreachable();
- return T();
- }
-
- /**
* Copy values from the virtual array into the provided span. The index of the value in the
* virtual array is the same as the index in the span.
*/
@@ -113,16 +108,22 @@ template<typename T> class VArrayImpl {
{
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]; });
- }
- else if (this->is_single()) {
- const T single = this->get_internal_single();
- mask.foreach_index([&](const int64_t i) { dst[i] = single; });
- }
- else {
- mask.foreach_index([&](const int64_t i) { dst[i] = this->get(i); });
+ const CommonVArrayInfo info = this->common_info();
+ switch (info.type) {
+ case CommonVArrayInfo::Type::Any: {
+ mask.foreach_index([&](const int64_t i) { dst[i] = this->get(i); });
+ break;
+ }
+ case CommonVArrayInfo::Type::Span: {
+ const T *src = static_cast<const T *>(info.data);
+ mask.foreach_index([&](const int64_t i) { dst[i] = src[i]; });
+ break;
+ }
+ case CommonVArrayInfo::Type::Single: {
+ const T single = *static_cast<const T *>(info.data);
+ mask.foreach_index([&](const int64_t i) { dst[i] = single; });
+ break;
+ }
}
}
@@ -133,16 +134,22 @@ template<typename T> class VArrayImpl {
{
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]); });
- }
- else if (this->is_single()) {
- const T single = this->get_internal_single();
- mask.foreach_index([&](const int64_t i) { new (dst + i) T(single); });
- }
- else {
- mask.foreach_index([&](const int64_t i) { new (dst + i) T(this->get(i)); });
+ const CommonVArrayInfo info = this->common_info();
+ switch (info.type) {
+ case CommonVArrayInfo::Type::Any: {
+ mask.foreach_index([&](const int64_t i) { new (dst + i) T(this->get(i)); });
+ break;
+ }
+ case CommonVArrayInfo::Type::Span: {
+ const T *src = static_cast<const T *>(info.data);
+ mask.foreach_index([&](const int64_t i) { new (dst + i) T(src[i]); });
+ break;
+ }
+ case CommonVArrayInfo::Type::Single: {
+ const T single = *static_cast<const T *>(info.data);
+ mask.foreach_index([&](const int64_t i) { new (dst + i) T(single); });
+ break;
+ }
}
}
@@ -187,17 +194,6 @@ template<typename T> class VArrayImpl {
}
/**
- * 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
- {
- /* 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;
- }
-
- /**
* Return true when the other virtual array should be considered to be the same, e.g. because it
* shares the same underlying memory.
*/
@@ -222,10 +218,10 @@ template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
*/
virtual void set_all(Span<T> src)
{
- if (this->is_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());
+ const CommonVArrayInfo info = this->common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ initialized_copy_n(
+ src.data(), this->size_, const_cast<T *>(static_cast<const T *>(info.data)));
}
else {
const int64_t size = this->size_;
@@ -273,14 +269,9 @@ template<typename T> class VArrayImpl_For_Span : public VMutableArrayImpl<T> {
data_[index] = value;
}
- bool is_span() const override
+ CommonVArrayInfo common_info() const override
{
- return true;
- }
-
- Span<T> get_internal_span() const override
- {
- return Span<T>(data_, this->size_);
+ return CommonVArrayInfo(CommonVArrayInfo::Type::Span, true, data_);
}
bool is_same(const VArrayImpl<T> &other) const final
@@ -288,11 +279,11 @@ template<typename T> class VArrayImpl_For_Span : public VMutableArrayImpl<T> {
if (other.size() != this->size_) {
return false;
}
- if (!other.is_span()) {
+ const CommonVArrayInfo other_info = other.common_info();
+ if (other_info.type != CommonVArrayInfo::Type::Span) {
return false;
}
- const Span<T> other_span = other.get_internal_span();
- return data_ == other_span.data();
+ return data_ == static_cast<const T *>(other_info.data);
}
void materialize_compressed(IndexMask mask, MutableSpan<T> r_span) const override
@@ -325,12 +316,15 @@ template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_F
using VArrayImpl_For_Span<T>::VArrayImpl_For_Span;
private:
- bool may_have_ownership() const override
+ CommonVArrayInfo common_info() const final
{
- return false;
+ return CommonVArrayInfo(CommonVArrayInfo::Type::Span, false, this->data_);
}
};
+template<typename T>
+inline constexpr bool is_trivial_extended_v<VArrayImpl_For_Span_final<T>> = true;
+
/**
* A variant of `VArrayImpl_For_Span` that owns the underlying data.
* The `Container` type has to implement a `size()` and `data()` method.
@@ -371,24 +365,9 @@ template<typename T> class VArrayImpl_For_Single final : public VArrayImpl<T> {
return value_;
}
- bool is_span() const override
+ CommonVArrayInfo common_info() const override
{
- return this->size_ == 1;
- }
-
- Span<T> get_internal_span() const override
- {
- return Span<T>(&value_, 1);
- }
-
- bool is_single() const override
- {
- return true;
- }
-
- T get_internal_single() const override
- {
- return value_;
+ return CommonVArrayInfo(CommonVArrayInfo::Type::Single, true, &value_);
}
void materialize_compressed(IndexMask mask, MutableSpan<T> r_span) const override
@@ -406,6 +385,9 @@ template<typename T> class VArrayImpl_For_Single final : public VArrayImpl<T> {
}
};
+template<typename T>
+inline constexpr bool is_trivial_extended_v<VArrayImpl_For_Single<T>> = is_trivial_extended_v<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.
@@ -531,11 +513,6 @@ class VArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> {
});
}
- bool may_have_ownership() const override
- {
- return false;
- }
-
bool is_same(const VArrayImpl<ElemT> &other) const override
{
if (other.size() != this->size_) {
@@ -554,6 +531,13 @@ class VArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> {
}
};
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, ElemT)>
+inline constexpr bool
+ is_trivial_extended_v<VArrayImpl_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> = true;
+
namespace detail {
/**
@@ -768,11 +752,18 @@ template<typename T> class VArrayCommon {
return IndexRange(this->size());
}
+ CommonVArrayInfo common_info() const
+ {
+ BLI_assert(*this);
+ return impl_->common_info();
+ }
+
/** Return true when the virtual array is stored as a span internally. */
bool is_span() const
{
BLI_assert(*this);
- return impl_->is_span();
+ const CommonVArrayInfo info = impl_->common_info();
+ return info.type == CommonVArrayInfo::Type::Span;
}
/**
@@ -782,14 +773,16 @@ template<typename T> class VArrayCommon {
Span<T> get_internal_span() const
{
BLI_assert(this->is_span());
- return impl_->get_internal_span();
+ const CommonVArrayInfo info = impl_->common_info();
+ return Span<T>(static_cast<const T *>(info.data), this->size());
}
/** Return true when the virtual array returns the same value for every index. */
bool is_single() const
{
BLI_assert(*this);
- return impl_->is_single();
+ const CommonVArrayInfo info = impl_->common_info();
+ return info.type == CommonVArrayInfo::Type::Single;
}
/**
@@ -799,7 +792,8 @@ template<typename T> class VArrayCommon {
T get_internal_single() const
{
BLI_assert(this->is_single());
- return impl_->get_internal_single();
+ const CommonVArrayInfo info = impl_->common_info();
+ return *static_cast<const T *>(info.data);
}
/**
@@ -861,17 +855,27 @@ template<typename T> class VArrayCommon {
{
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;
/**
+ * Various tags to disambiguate constructors of virtual arrays.
+ * Generally it is easier to use `VArray::For*` functions to construct virtual arrays, but
+ * sometimes being able to use the constructor can result in better performance For example, when
+ * constructing the virtual array directly in a vector. Without the constructor one would have to
+ * construct the virtual array first and then move it into the vector.
+ */
+namespace varray_tag {
+struct span {
+};
+struct single_ref {
+};
+struct single {
+};
+} // namespace varray_tag
+
+/**
* 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).
@@ -892,6 +896,19 @@ template<typename T> class VArray : public VArrayCommon<T> {
{
}
+ VArray(varray_tag::span /* tag */, Span<T> span)
+ {
+ /* Cast const away, because the virtual array implementation for const and non const spans is
+ * shared. */
+ MutableSpan<T> mutable_span{const_cast<T *>(span.data()), span.size()};
+ this->template emplace<VArrayImpl_For_Span_final<T>>(mutable_span);
+ }
+
+ VArray(varray_tag::single /* tag */, T value, const int64_t size)
+ {
+ this->template emplace<VArrayImpl_For_Single<T>>(std::move(value), size);
+ }
+
/**
* Construct a new virtual array for a custom #VArrayImpl.
*/
@@ -908,7 +925,7 @@ template<typename T> class VArray : public VArrayCommon<T> {
*/
static VArray ForSingle(T value, const int64_t size)
{
- return VArray::For<VArrayImpl_For_Single<T>>(std::move(value), size);
+ return VArray(varray_tag::single{}, std::move(value), size);
}
/**
@@ -917,10 +934,7 @@ template<typename T> class VArray : public VArrayCommon<T> {
*/
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);
+ return VArray(varray_tag::span{}, values);
}
/**
@@ -1050,8 +1064,8 @@ template<typename T> class VMutableArray : public VArrayCommon<T> {
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());
+ const CommonVArrayInfo info = this->get_impl()->common_info();
+ return MutableSpan<T>(const_cast<T *>(static_cast<const T *>(info.data)), this->size());
}
/**
@@ -1106,17 +1120,23 @@ template<typename T> static constexpr bool is_VMutableArray_v<VMutableArray<T>>
* from faster access.
* - An API is called, that does not accept virtual arrays, but only spans.
*/
-template<typename T> class VArray_Span final : public Span<T> {
+template<typename T> class VArraySpan final : public Span<T> {
private:
VArray<T> varray_;
Array<T> owned_data_;
public:
- VArray_Span(VArray<T> varray) : Span<T>(), varray_(std::move(varray))
+ VArraySpan() = default;
+
+ VArraySpan(VArray<T> varray) : Span<T>(), varray_(std::move(varray))
{
+ if (!varray_) {
+ return;
+ }
this->size_ = varray_.size();
- if (varray_.is_span()) {
- this->data_ = varray_.get_internal_span().data();
+ const CommonVArrayInfo info = varray_.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ this->data_ = static_cast<const T *>(info.data);
}
else {
owned_data_.~Array();
@@ -1125,16 +1145,44 @@ template<typename T> class VArray_Span final : public Span<T> {
this->data_ = owned_data_.data();
}
}
+
+ VArraySpan(VArraySpan &&other)
+ : varray_(std::move(other.varray_)), owned_data_(std::move(other.owned_data_))
+ {
+ if (!varray_) {
+ return;
+ }
+ this->size_ = varray_.size();
+ const CommonVArrayInfo info = varray_.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ this->data_ = static_cast<const T *>(info.data);
+ }
+ else {
+ this->data_ = owned_data_.data();
+ }
+ other.data_ = nullptr;
+ other.size_ = 0;
+ }
+
+ VArraySpan &operator=(VArraySpan &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ std::destroy_at(this);
+ new (this) VArraySpan(std::move(other));
+ return *this;
+ }
};
/**
- * Same as #VArray_Span, but for a mutable span.
+ * Same as #VArraySpan, 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,
* if necessary.
*/
-template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
+template<typename T> class MutableVArraySpan final : public MutableSpan<T> {
private:
VMutableArray<T> varray_;
Array<T> owned_data_;
@@ -1142,14 +1190,21 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
bool show_not_saved_warning_ = true;
public:
+ MutableVArraySpan() = default;
+
/* 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)
+ MutableVArraySpan(VMutableArray<T> varray, const bool copy_values_to_span = true)
: MutableSpan<T>(), varray_(std::move(varray))
{
+ if (!varray_) {
+ return;
+ }
+
this->size_ = varray_.size();
- if (varray_.is_span()) {
- this->data_ = varray_.get_internal_span().data();
+ const CommonVArrayInfo info = varray_.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ this->data_ = const_cast<T *>(static_cast<const T *>(info.data));
}
else {
if (copy_values_to_span) {
@@ -1164,15 +1219,53 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
}
}
- ~VMutableArray_Span()
+ MutableVArraySpan(MutableVArraySpan &&other)
+ : varray_(std::move(other.varray_)),
+ owned_data_(std::move(other.owned_data_)),
+ show_not_saved_warning_(other.show_not_saved_warning_)
+ {
+ if (!varray_) {
+ return;
+ }
+
+ this->size_ = varray_.size();
+ const CommonVArrayInfo info = varray_.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ this->data_ = static_cast<T *>(const_cast<void *>(info.data));
+ }
+ else {
+ this->data_ = owned_data_.data();
+ }
+ other.data_ = nullptr;
+ other.size_ = 0;
+ }
+
+ ~MutableVArraySpan()
{
- if (show_not_saved_warning_) {
- if (!save_has_been_called_) {
- std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
+ if (varray_) {
+ if (show_not_saved_warning_) {
+ if (!save_has_been_called_) {
+ std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
+ }
}
}
}
+ MutableVArraySpan &operator=(MutableVArraySpan &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+ std::destroy_at(this);
+ new (this) MutableVArraySpan(std::move(other));
+ return *this;
+ }
+
+ const VMutableArray<T> &varray() const
+ {
+ return varray_;
+ }
+
/* Write back all values from a temporary allocated array to the underlying virtual array. */
void save()
{
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 109230ebfa7..d39a586206f 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -424,6 +424,7 @@ if(WITH_GTESTS)
tests/BLI_array_store_test.cc
tests/BLI_array_test.cc
tests/BLI_array_utils_test.cc
+ tests/BLI_bitmap_test.cc
tests/BLI_bounds_test.cc
tests/BLI_color_test.cc
tests/BLI_cpp_type_test.cc
@@ -445,6 +446,7 @@ if(WITH_GTESTS)
tests/BLI_index_range_test.cc
tests/BLI_inplace_priority_queue_test.cc
tests/BLI_kdopbvh_test.cc
+ tests/BLI_kdtree_test.cc
tests/BLI_length_parameterize_test.cc
tests/BLI_linear_allocator_test.cc
tests/BLI_linklist_lockfree_test.cc
diff --git a/source/blender/blenlib/intern/bitmap.c b/source/blender/blenlib/intern/bitmap.c
index 7fcbc31c066..2cc2fbc3e2f 100644
--- a/source/blender/blenlib/intern/bitmap.c
+++ b/source/blender/blenlib/intern/bitmap.c
@@ -11,6 +11,7 @@
#include <string.h>
#include "BLI_bitmap.h"
+#include "BLI_math_bits.h"
#include "BLI_utildefines.h"
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
@@ -46,3 +47,22 @@ void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
dst[i] |= src[i];
}
}
+
+int BLI_bitmap_find_first_unset(const BLI_bitmap *bitmap, const size_t bits)
+{
+ const size_t blocks_num = _BITMAP_NUM_BLOCKS(bits);
+ int result = -1;
+ /* Skip over completely set blocks. */
+ int index = 0;
+ while (index < blocks_num && bitmap[index] == ~0u) {
+ index++;
+ }
+ if (index < blocks_num) {
+ /* Found a partially used block: find the lowest unused bit. */
+ const uint m = ~bitmap[index];
+ BLI_assert(m != 0);
+ const uint bit_index = bitscan_forward_uint(m);
+ result = bit_index + (index << _BITMAP_POWER);
+ }
+ return result;
+}
diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc
index ece22bcf82e..db6cb0824dc 100644
--- a/source/blender/blenlib/intern/delaunay_2d.cc
+++ b/source/blender/blenlib/intern/delaunay_2d.cc
@@ -2637,6 +2637,7 @@ void prepare_cdt_for_output(CDT_state<T> *cdt_state, const CDT_output_type outpu
remove_faces_in_holes(cdt_state);
}
else if (output_type == CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES) {
+ remove_outer_edges_until_constraints(cdt_state);
remove_non_constraint_edges_leave_valid_bmesh(cdt_state);
remove_faces_in_holes(cdt_state);
}
diff --git a/source/blender/blenlib/intern/filereader_zstd.c b/source/blender/blenlib/intern/filereader_zstd.c
index 5f114f24fb0..aeb000e9754 100644
--- a/source/blender/blenlib/intern/filereader_zstd.c
+++ b/source/blender/blenlib/intern/filereader_zstd.c
@@ -281,7 +281,10 @@ static void zstd_close(FileReader *reader)
if (zstd->reader.seek) {
MEM_freeN(zstd->seek.uncompressed_ofs);
MEM_freeN(zstd->seek.compressed_ofs);
- MEM_freeN(zstd->seek.cached_content);
+ /* When an error has occurred this may be NULL, see: T99744. */
+ if (zstd->seek.cached_content) {
+ MEM_freeN(zstd->seek.cached_content);
+ }
}
else {
MEM_freeN((void *)zstd->in_buf.src);
diff --git a/source/blender/blenlib/intern/generic_virtual_array.cc b/source/blender/blenlib/intern/generic_virtual_array.cc
index a3a17952a97..1e548d006b2 100644
--- a/source/blender/blenlib/intern/generic_virtual_array.cc
+++ b/source/blender/blenlib/intern/generic_virtual_array.cc
@@ -46,25 +46,9 @@ void GVArrayImpl::get(const int64_t index, void *r_value) const
this->get_to_uninitialized(index, r_value);
}
-bool GVArrayImpl::is_span() const
+CommonVArrayInfo GVArrayImpl::common_info() const
{
- return false;
-}
-
-GSpan GVArrayImpl::get_internal_span() const
-{
- BLI_assert(false);
- return GSpan(*type_);
-}
-
-bool GVArrayImpl::is_single() const
-{
- return false;
-}
-
-void GVArrayImpl::get_internal_single(void *UNUSED(r_value)) const
-{
- BLI_assert(false);
+ return {};
}
bool GVArrayImpl::try_assign_VArray(void *UNUSED(varray)) const
@@ -72,24 +56,12 @@ bool GVArrayImpl::try_assign_VArray(void *UNUSED(varray)) const
return false;
}
-bool GVArrayImpl::may_have_ownership() const
-{
- /* 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;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name #GVMutableArrayImpl
* \{ */
-GVMutableArrayImpl::GVMutableArrayImpl(const CPPType &type, const int64_t size)
- : GVArrayImpl(type, size)
-{
-}
-
void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value)
{
BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
@@ -106,9 +78,9 @@ void GVMutableArrayImpl::set_by_relocate(const int64_t index, void *value)
void GVMutableArrayImpl::set_all(const void *src)
{
- if (this->is_span()) {
- const GSpan span = this->get_internal_span();
- type_->copy_assign_n(src, const_cast<void *>(span.data()), size_);
+ const CommonVArrayInfo info = this->common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ type_->copy_assign_n(src, const_cast<void *>(info.data), size_);
}
else {
for (int64_t i : IndexRange(size_)) {
@@ -119,9 +91,9 @@ void GVMutableArrayImpl::set_all(const void *src)
void GVMutableArray::fill(const void *value)
{
- if (this->is_span()) {
- const GSpan span = this->get_internal_span();
- this->type().fill_assign_n(value, const_cast<void *>(span.data()), this->size());
+ const CommonVArrayInfo info = this->common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ this->type().fill_assign_n(value, const_cast<void *>(info.data), this->size());
}
else {
for (int64_t i : IndexRange(this->size())) {
@@ -141,18 +113,6 @@ bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) 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())
-{
-}
-
-GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size)
- : GVMutableArrayImpl(type, size), element_size_(type.size())
-{
-}
-
void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const
{
type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value);
@@ -178,14 +138,9 @@ void GVArrayImpl_For_GSpan::set_by_relocate(const int64_t index, void *value)
type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index));
}
-bool GVArrayImpl_For_GSpan::is_span() const
-{
- return true;
-}
-
-GSpan GVArrayImpl_For_GSpan::get_internal_span() const
+CommonVArrayInfo GVArrayImpl_For_GSpan::common_info() const
{
- return GSpan(*type_, data_, size_);
+ return CommonVArrayInfo{CommonVArrayInfo::Type::Span, true, data_};
}
void GVArrayImpl_For_GSpan::materialize(const IndexMask mask, void *dst) const
@@ -209,17 +164,6 @@ void GVArrayImpl_For_GSpan::materialize_compressed_to_uninitialized(const IndexM
type_->copy_construct_compressed(data_, dst, mask);
}
-class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
- public:
- using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan;
-
- private:
- bool may_have_ownership() const override
- {
- return false;
- }
-};
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -227,79 +171,43 @@ class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan {
* \{ */
/* 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;
-
- public:
- GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
- : GVArrayImpl(type, size), value_(value)
- {
- }
- protected:
- GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size)
- {
- }
-
- 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);
- }
-
- bool is_span() const override
- {
- return size_ == 1;
- }
- GSpan get_internal_span() const override
- {
- return GSpan{*type_, value_, 1};
- }
-
- bool is_single() const override
- {
- return true;
- }
- void get_internal_single(void *r_value) const override
- {
- type_->copy_assign(value_, r_value);
- }
-
- void materialize(const IndexMask mask, void *dst) const override
- {
- type_->fill_assign_indices(value_, dst, mask);
- }
+void GVArrayImpl_For_SingleValueRef::get(const int64_t UNUSED(index), void *r_value) const
+{
+ type_->copy_assign(value_, r_value);
+}
+void GVArrayImpl_For_SingleValueRef::get_to_uninitialized(const int64_t UNUSED(index),
+ void *r_value) const
+{
+ type_->copy_construct(value_, r_value);
+}
- void materialize_to_uninitialized(const IndexMask mask, void *dst) const override
- {
- type_->fill_construct_indices(value_, dst, mask);
- }
+CommonVArrayInfo GVArrayImpl_For_SingleValueRef::common_info() const
+{
+ return CommonVArrayInfo{CommonVArrayInfo::Type::Single, true, value_};
+}
- void materialize_compressed(const IndexMask mask, void *dst) const override
- {
- type_->fill_assign_n(value_, dst, mask.size());
- }
+void GVArrayImpl_For_SingleValueRef::materialize(const IndexMask mask, void *dst) const
+{
+ type_->fill_assign_indices(value_, dst, mask);
+}
- void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override
- {
- type_->fill_construct_n(value_, dst, mask.size());
- }
-};
+void GVArrayImpl_For_SingleValueRef::materialize_to_uninitialized(const IndexMask mask,
+ void *dst) const
+{
+ type_->fill_construct_indices(value_, dst, mask);
+}
-class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef {
- public:
- using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef;
+void GVArrayImpl_For_SingleValueRef::materialize_compressed(const IndexMask mask, void *dst) const
+{
+ type_->fill_assign_n(value_, dst, mask.size());
+}
- private:
- bool may_have_ownership() const override
- {
- return false;
- }
-};
+void GVArrayImpl_For_SingleValueRef::materialize_compressed_to_uninitialized(const IndexMask mask,
+ void *dst) const
+{
+ type_->fill_construct_n(value_, dst, mask.size());
+}
/** \} */
@@ -362,32 +270,36 @@ template<int BufferSize> class GVArrayImpl_For_SmallTrivialSingleValue : public
this->copy_value_to(r_value);
}
- bool is_single() const override
- {
- return true;
- }
- void get_internal_single(void *r_value) const override
+ void copy_value_to(void *dst) const
{
- this->copy_value_to(r_value);
+ memcpy(dst, &buffer_, type_->size());
}
- void copy_value_to(void *dst) const
+ CommonVArrayInfo common_info() const override
{
- memcpy(dst, &buffer_, type_->size());
+ return CommonVArrayInfo{CommonVArrayInfo::Type::Single, true, &buffer_};
}
};
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVArray_GSpan
+/** \name #GVArraySpan
* \{ */
-GVArray_GSpan::GVArray_GSpan(GVArray varray) : GSpan(varray.type()), varray_(std::move(varray))
+GVArraySpan::GVArraySpan() = default;
+
+GVArraySpan::GVArraySpan(GVArray varray)
+ : GSpan(varray ? &varray.type() : nullptr), varray_(std::move(varray))
{
+ if (!varray_) {
+ return;
+ }
+
size_ = varray_.size();
- if (varray_.is_span()) {
- data_ = varray_.get_internal_span().data();
+ const CommonVArrayInfo info = varray_.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ data_ = info.data;
}
else {
owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__);
@@ -396,7 +308,27 @@ GVArray_GSpan::GVArray_GSpan(GVArray varray) : GSpan(varray.type()), varray_(std
}
}
-GVArray_GSpan::~GVArray_GSpan()
+GVArraySpan::GVArraySpan(GVArraySpan &&other)
+ : GSpan(other.type_ptr()), varray_(std::move(other.varray_)), owned_data_(other.owned_data_)
+{
+ if (!varray_) {
+ return;
+ }
+
+ size_ = varray_.size();
+ const CommonVArrayInfo info = varray_.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ data_ = info.data;
+ }
+ else {
+ data_ = owned_data_;
+ }
+ other.owned_data_ = nullptr;
+ other.data_ = nullptr;
+ other.size_ = 0;
+}
+
+GVArraySpan::~GVArraySpan()
{
if (owned_data_ != nullptr) {
type_->destruct_n(owned_data_, size_);
@@ -404,18 +336,34 @@ GVArray_GSpan::~GVArray_GSpan()
}
}
+GVArraySpan &GVArraySpan::operator=(GVArraySpan &&other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ std::destroy_at(this);
+ new (this) GVArraySpan(std::move(other));
+ return *this;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
-/** \name #GVMutableArray_GSpan
+/** \name #GMutableVArraySpan
* \{ */
-GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray varray, const bool copy_values_to_span)
- : GMutableSpan(varray.type()), varray_(std::move(varray))
+GMutableVArraySpan::GMutableVArraySpan() = default;
+
+GMutableVArraySpan::GMutableVArraySpan(GVMutableArray varray, const bool copy_values_to_span)
+ : GMutableSpan(varray ? &varray.type() : nullptr), varray_(std::move(varray))
{
+ if (!varray_) {
+ return;
+ }
size_ = varray_.size();
- if (varray_.is_span()) {
- data_ = varray_.get_internal_span().data();
+ const CommonVArrayInfo info = varray_.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ data_ = const_cast<void *>(info.data);
}
else {
owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__);
@@ -429,11 +377,35 @@ GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray varray, const bool cop
}
}
-GVMutableArray_GSpan::~GVMutableArray_GSpan()
+GMutableVArraySpan::GMutableVArraySpan(GMutableVArraySpan &&other)
+ : GMutableSpan(other.type_ptr()),
+ varray_(std::move(other.varray_)),
+ owned_data_(other.owned_data_),
+ show_not_saved_warning_(other.show_not_saved_warning_)
+{
+ if (!varray_) {
+ return;
+ }
+ size_ = varray_.size();
+ const CommonVArrayInfo info = varray_.common_info();
+ if (info.type == CommonVArrayInfo::Type::Span) {
+ data_ = const_cast<void *>(info.data);
+ }
+ else {
+ data_ = owned_data_;
+ }
+ other.owned_data_ = nullptr;
+ other.data_ = nullptr;
+ other.size_ = 0;
+}
+
+GMutableVArraySpan::~GMutableVArraySpan()
{
- if (show_not_saved_warning_) {
- if (!save_has_been_called_) {
- std::cout << "Warning: Call `apply()` to make sure that changes persist in all cases.\n";
+ if (varray_) {
+ if (show_not_saved_warning_) {
+ if (!save_has_been_called_) {
+ std::cout << "Warning: Call `apply()` to make sure that changes persist in all cases.\n";
+ }
}
}
if (owned_data_ != nullptr) {
@@ -442,7 +414,17 @@ GVMutableArray_GSpan::~GVMutableArray_GSpan()
}
}
-void GVMutableArray_GSpan::save()
+GMutableVArraySpan &GMutableVArraySpan::operator=(GMutableVArraySpan &&other)
+{
+ if (this == &other) {
+ return *this;
+ }
+ std::destroy_at(this);
+ new (this) GMutableVArraySpan(std::move(other));
+ return *this;
+}
+
+void GMutableVArraySpan::save()
{
save_has_been_called_ = true;
if (data_ != owned_data_) {
@@ -451,11 +433,16 @@ void GVMutableArray_GSpan::save()
varray_.set_all(owned_data_);
}
-void GVMutableArray_GSpan::disable_not_applied_warning()
+void GMutableVArraySpan::disable_not_applied_warning()
{
show_not_saved_warning_ = false;
}
+const GVMutableArray &GMutableVArraySpan::varray() const
+{
+ return varray_;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -488,22 +475,24 @@ class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
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
+ CommonVArrayInfo common_info() const override
{
- varray_.get_internal_single(r_value);
+ const CommonVArrayInfo internal_info = varray_.common_info();
+ switch (internal_info.type) {
+ case CommonVArrayInfo::Type::Any: {
+ return {};
+ }
+ case CommonVArrayInfo::Type::Span: {
+ return CommonVArrayInfo(CommonVArrayInfo::Type::Span,
+ internal_info.may_have_ownership,
+ POINTER_OFFSET(internal_info.data, type_->size() * offset_));
+ }
+ case CommonVArrayInfo::Type::Single: {
+ return internal_info;
+ }
+ }
+ BLI_assert_unreachable();
+ return {};
}
void materialize_compressed_to_uninitialized(const IndexMask mask, void *dst) const override
@@ -529,8 +518,6 @@ class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl {
/** \name #GVArrayCommon
* \{ */
-GVArrayCommon::GVArrayCommon() = default;
-
GVArrayCommon::GVArrayCommon(const GVArrayCommon &other) : storage_(other.storage_)
{
impl_ = this->impl_from_storage();
@@ -588,11 +575,6 @@ void GVArrayCommon::materialize_compressed_to_uninitialized(IndexMask mask, void
impl_->materialize_compressed_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) {
@@ -615,24 +597,28 @@ void GVArrayCommon::move_from(GVArrayCommon &&other) noexcept
bool GVArrayCommon::is_span() const
{
- return impl_->is_span();
+ const CommonVArrayInfo info = impl_->common_info();
+ return info.type == CommonVArrayInfo::Type::Span;
}
GSpan GVArrayCommon::get_internal_span() const
{
BLI_assert(this->is_span());
- return impl_->get_internal_span();
+ const CommonVArrayInfo info = impl_->common_info();
+ return GSpan(this->type(), info.data, this->size());
}
bool GVArrayCommon::is_single() const
{
- return impl_->is_single();
+ const CommonVArrayInfo info = impl_->common_info();
+ return info.type == CommonVArrayInfo::Type::Single;
}
void GVArrayCommon::get_internal_single(void *r_value) const
{
BLI_assert(this->is_single());
- impl_->get_internal_single(r_value);
+ const CommonVArrayInfo info = impl_->common_info();
+ this->type().copy_assign(info.data, r_value);
}
void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const
@@ -672,17 +658,27 @@ GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::m
{
}
-GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
+GVArray::GVArray(varray_tag::single /* tag */,
+ const CPPType &type,
+ 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);
+ this->emplace<GVArrayImpl_For_SmallTrivialSingleValue<16>>(type, size, value);
+ }
+ else {
+ this->emplace<GVArrayImpl_For_SingleValue>(type, size, value);
}
- return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value);
+}
+
+GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value)
+{
+ return GVArray(varray_tag::single{}, 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);
+ return GVArray(varray_tag::single_ref{}, type, size, value);
}
GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size)
@@ -692,10 +688,7 @@ GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size)
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);
+ return GVArray(varray_tag::span{}, span);
}
class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan {
@@ -721,6 +714,15 @@ GVArray GVArray::ForEmpty(const CPPType &type)
GVArray GVArray::slice(IndexRange slice) const
{
+ const CommonVArrayInfo info = this->common_info();
+ if (info.type == CommonVArrayInfo::Type::Single) {
+ return GVArray::ForSingle(this->type(), slice.size(), info.data);
+ }
+ /* Need to check for ownership, because otherwise the referenced data can be destructed when
+ * #this is destructed. */
+ if (info.type == CommonVArrayInfo::Type::Span && !info.may_have_ownership) {
+ return GVArray::ForSpan(GSpan(this->type(), info.data, this->size()).slice(slice));
+ }
return GVArray::For<GVArrayImpl_For_SlicedGVArray>(*this, slice);
}
@@ -798,10 +800,20 @@ void GVMutableArray::set_all(const void *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());
+ const CommonVArrayInfo info = impl_->common_info();
+ return GMutableSpan(this->type(), const_cast<void *>(info.data), this->size());
}
/** \} */
+CommonVArrayInfo GVArrayImpl_For_GSpan_final::common_info() const
+{
+ return CommonVArrayInfo(CommonVArrayInfo::Type::Span, false, data_);
+}
+
+CommonVArrayInfo GVArrayImpl_For_SingleValueRef_final::common_info() const
+{
+ return CommonVArrayInfo(CommonVArrayInfo::Type::Single, false, value_);
+}
+
} // namespace blender
diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c
index 9da8c0a0941..d57f859eb1b 100644
--- a/source/blender/blenlib/intern/hash_md5.c
+++ b/source/blender/blenlib/intern/hash_md5.c
@@ -143,7 +143,7 @@ static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ct
(void)0
/* Before we start, one word to the strange constants. They are defined in RFC 1321 as:
- * T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ * `T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64`
*/
/* Round 1. */
@@ -315,7 +315,7 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
break;
}
- /* Process buffer with BLOCKSIZE bytes. Note that BLOCKSIZE % 64 == 0. */
+ /* Process buffer with BLOCKSIZE bytes. Note that `BLOCKSIZE % 64 == 0`. */
md5_process_block(buffer, BLOCKSIZE, &ctx);
}
@@ -323,7 +323,7 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
* 'fillbuf' contains the needed bits. */
memcpy(&buffer[sum], fillbuf, 64);
- /* Compute amount of padding bytes needed. Alignment is done to (N + PAD) % 64 == 56.
+ /* Compute amount of padding bytes needed. Alignment is done to `(N + PAD) % 64 == 56`.
* There is always at least one byte padded, i.e. if the alignment is correctly aligned,
* 64 padding bytes are added.
*/
diff --git a/source/blender/blenlib/intern/index_mask.cc b/source/blender/blenlib/intern/index_mask.cc
index 1e301bc5fb9..e9af183d60d 100644
--- a/source/blender/blenlib/intern/index_mask.cc
+++ b/source/blender/blenlib/intern/index_mask.cc
@@ -128,7 +128,9 @@ Vector<IndexRange> IndexMask::extract_ranges_invert(const IndexRange full_range,
} // namespace blender
-namespace blender::index_mask_ops::detail {
+namespace blender::index_mask_ops {
+
+namespace detail {
IndexMask find_indices_based_on_predicate__merge(
IndexMask indices_to_check,
@@ -140,6 +142,7 @@ IndexMask find_indices_based_on_predicate__merge(
int64_t result_mask_size = 0;
for (Vector<Vector<int64_t>> &local_sub_masks : sub_masks) {
for (Vector<int64_t> &sub_mask : local_sub_masks) {
+ BLI_assert(!sub_mask.is_empty());
all_vectors.append(&sub_mask);
result_mask_size += sub_mask.size();
}
@@ -193,4 +196,49 @@ IndexMask find_indices_based_on_predicate__merge(
return r_indices.as_span();
}
-} // namespace blender::index_mask_ops::detail
+} // namespace detail
+
+IndexMask find_indices_from_virtual_array(const IndexMask indices_to_check,
+ const VArray<bool> &virtual_array,
+ const int64_t parallel_grain_size,
+ Vector<int64_t> &r_indices)
+{
+ if (virtual_array.is_single()) {
+ return virtual_array.get_internal_single() ? indices_to_check : IndexMask(0);
+ }
+ if (virtual_array.is_span()) {
+ const Span<bool> span = virtual_array.get_internal_span();
+ return find_indices_based_on_predicate(
+ indices_to_check, 4096, r_indices, [&](const int64_t i) { return span[i]; });
+ }
+
+ threading::EnumerableThreadSpecific<Vector<bool>> materialize_buffers;
+ threading::EnumerableThreadSpecific<Vector<Vector<int64_t>>> sub_masks;
+
+ threading::parallel_for(
+ indices_to_check.index_range(), parallel_grain_size, [&](const IndexRange range) {
+ const IndexMask sliced_mask = indices_to_check.slice(range);
+
+ /* To avoid virtual function call overhead from accessing the virtual array,
+ * materialize the necessary indices for this chunk into a reused buffer. */
+ Vector<bool> &buffer = materialize_buffers.local();
+ buffer.reinitialize(sliced_mask.size());
+ virtual_array.materialize_compressed(sliced_mask, buffer);
+
+ Vector<int64_t> masked_indices;
+ sliced_mask.to_best_mask_type([&](auto best_mask) {
+ for (const int64_t i : IndexRange(best_mask.size())) {
+ if (buffer[i]) {
+ masked_indices.append(best_mask[i]);
+ }
+ }
+ });
+ if (!masked_indices.is_empty()) {
+ sub_masks.local().append(std::move(masked_indices));
+ }
+ });
+
+ return detail::find_indices_based_on_predicate__merge(indices_to_check, sub_masks, r_indices);
+}
+
+} // namespace blender::index_mask_ops
diff --git a/source/blender/blenlib/intern/kdtree_impl.h b/source/blender/blenlib/intern/kdtree_impl.h
index d9ae826093c..6614f1bf964 100644
--- a/source/blender/blenlib/intern/kdtree_impl.h
+++ b/source/blender/blenlib/intern/kdtree_impl.h
@@ -927,6 +927,14 @@ int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree,
/** \name BLI_kdtree_3d_deduplicate
* \{ */
+static int kdtree_cmp_bool(const bool a, const bool b)
+{
+ if (a == b) {
+ return 0;
+ }
+ return b ? -1 : 1;
+}
+
static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p)
{
const KDTreeNode *n0 = n0_p;
@@ -939,17 +947,16 @@ static int kdtree_node_cmp_deduplicate(const void *n0_p, const void *n1_p)
return 1;
}
}
- /* Sort by pointer so the first added will be used.
- * assignment below ignores const correctness,
- * however the values aren't used for sorting and are to be discarded. */
- if (n0 < n1) {
- ((KDTreeNode *)n1)->d = KD_DIMS; /* tag invalid */
- return -1;
- }
- else {
- ((KDTreeNode *)n0)->d = KD_DIMS; /* tag invalid */
- return 1;
+
+ if (n0->d != KD_DIMS && n1->d != KD_DIMS) {
+ /* Two nodes share identical `co`
+ * Both are still valid.
+ * Cast away `const` and tag one of them as invalid. */
+ ((KDTreeNode *)n1)->d = KD_DIMS;
}
+
+ /* Keep sorting until each unique value has one and only one valid node. */
+ return kdtree_cmp_bool(n0->d == KD_DIMS, n1->d == KD_DIMS);
}
/**
diff --git a/source/blender/blenlib/intern/length_parameterize.cc b/source/blender/blenlib/intern/length_parameterize.cc
index 7c0fc860b53..06cca281510 100644
--- a/source/blender/blenlib/intern/length_parameterize.cc
+++ b/source/blender/blenlib/intern/length_parameterize.cc
@@ -1,144 +1,58 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_length_parameterize.hh"
+#include "BLI_task.hh"
namespace blender::length_parameterize {
-void create_uniform_samples(const Span<float> lengths,
- const bool cyclic,
- MutableSpan<int> indices,
- MutableSpan<float> factors)
+void sample_uniform(const Span<float> lengths,
+ const bool include_last_point,
+ MutableSpan<int> r_segment_indices,
+ MutableSpan<float> r_factors)
{
- const int count = indices.size();
+ const int count = r_segment_indices.size();
BLI_assert(count > 0);
BLI_assert(lengths.size() >= 1);
BLI_assert(std::is_sorted(lengths.begin(), lengths.end()));
- const int segments_num = lengths.size();
- const int points_num = cyclic ? segments_num : segments_num + 1;
- indices.first() = 0;
- factors.first() = 0.0f;
if (count == 1) {
+ r_segment_indices[0] = 0;
+ r_factors[0] = 0.0f;
return;
}
-
const float total_length = lengths.last();
- if (total_length == 0.0f) {
- indices.fill(0);
- factors.fill(0.0f);
- return;
- }
-
- const float step_length = total_length / (count - (cyclic ? 0 : 1));
- const float step_length_inv = 1.0f / step_length;
-
- int i_dst = 1;
- /* Store the length at the previous point in a variable so it can start out at zero
- * (the lengths array doesn't contain 0 for the first point). */
- float prev_length = 0.0f;
- for (const int i_src : IndexRange(points_num - 1)) {
- const float next_length = lengths[i_src];
- const float segment_length = next_length - prev_length;
- if (segment_length == 0.0f) {
- continue;
- }
- /* Add every sample that fits in this segment. */
- const float segment_length_inv = 1.0f / segment_length;
- const int segment_samples_num = std::ceil(next_length * step_length_inv - i_dst);
- indices.slice(i_dst, segment_samples_num).fill(i_src);
-
- for (const int i : factors.index_range().slice(i_dst, segment_samples_num)) {
- const float length_in_segment = step_length * i - prev_length;
- factors[i] = length_in_segment * segment_length_inv;
- }
-
- i_dst += segment_samples_num;
-
- prev_length = next_length;
- }
-
- /* Add the samples on the last cyclic segment if necessary, and also the samples
- * that weren't created in the previous loop due to floating point inaccuracy. */
- if (cyclic && lengths.size() > 1) {
- indices.drop_front(i_dst).fill(points_num - 1);
- const float segment_length = lengths.last() - lengths.last(1);
- if (segment_length == 0.0f) {
- return;
- }
- const float segment_length_inv = 1.0f / segment_length;
- for (const int i : indices.index_range().drop_front(i_dst)) {
- const float length_in_segment = step_length * i - prev_length;
- factors[i] = length_in_segment * segment_length_inv;
+ const float step_length = total_length / (count - include_last_point);
+ threading::parallel_for(IndexRange(count), 512, [&](const IndexRange range) {
+ SampleSegmentHint hint;
+ for (const int i : range) {
+ /* Use minimum to avoid issues with floating point accuracy. */
+ const float sample_length = std::min(total_length, i * step_length);
+ sample_at_length(lengths, sample_length, r_segment_indices[i], r_factors[i], &hint);
}
- }
- else {
- indices.drop_front(i_dst).fill(points_num - 2);
- factors.drop_front(i_dst).fill(1.0f);
- }
+ });
}
-void create_samples_from_sorted_lengths(const Span<float> lengths,
- const Span<float> sample_lengths,
- const bool cyclic,
- MutableSpan<int> indices,
- MutableSpan<float> factors)
+void sample_at_lengths(const Span<float> accumulated_segment_lengths,
+ const Span<float> sample_lengths,
+ MutableSpan<int> r_segment_indices,
+ MutableSpan<float> r_factors)
{
- BLI_assert(std::is_sorted(lengths.begin(), lengths.end()));
+ BLI_assert(
+ std::is_sorted(accumulated_segment_lengths.begin(), accumulated_segment_lengths.end()));
BLI_assert(std::is_sorted(sample_lengths.begin(), sample_lengths.end()));
- BLI_assert(indices.size() == sample_lengths.size());
- BLI_assert(indices.size() == factors.size());
- const int segments_num = lengths.size();
- const int points_num = cyclic ? segments_num : segments_num + 1;
- const float total_length = lengths.last();
- if (total_length == 0.0f) {
- indices.fill(0);
- factors.fill(0.0f);
- return;
- }
+ const int count = sample_lengths.size();
+ BLI_assert(count == r_segment_indices.size());
+ BLI_assert(count == r_factors.size());
- int i_dst = 0;
- /* Store the length at the previous point in a variable so it can start out at zero
- * (the lengths array doesn't contain 0 for the first point). */
- float prev_length = 0.0f;
- for (const int i_src : IndexRange(points_num - 1)) {
- const float next_length = lengths[i_src];
- const float segment_length = next_length - prev_length;
- if (segment_length == 0.0f) {
- continue;
- }
- /* Add every sample that fits in this segment. It's also necessary to check if the last sample
- * has been reached, since there is no upper bound on the number of samples in each segment. */
- const float segment_length_inv = 1.0f / segment_length;
- while (i_dst < sample_lengths.size() && sample_lengths[i_dst] < next_length) {
- const float length_in_segment = sample_lengths[i_dst] - prev_length;
- const float factor = length_in_segment * segment_length_inv;
- indices[i_dst] = i_src;
- factors[i_dst] = factor;
- i_dst++;
+ threading::parallel_for(IndexRange(count), 512, [&](const IndexRange range) {
+ SampleSegmentHint hint;
+ for (const int i : range) {
+ const float sample_length = sample_lengths[i];
+ sample_at_length(
+ accumulated_segment_lengths, sample_length, r_segment_indices[i], r_factors[i], &hint);
}
-
- prev_length = next_length;
- }
-
- /* Add the samples on the last cyclic segment if necessary, and also the samples
- * that weren't created in the previous loop due to floating point inaccuracy. */
- if (cyclic && lengths.size() > 1) {
- const float segment_length = lengths.last() - lengths.last(1);
- while (sample_lengths[i_dst] < total_length) {
- const float length_in_segment = sample_lengths[i_dst] - prev_length;
- const float factor = length_in_segment / segment_length;
- indices[i_dst] = points_num - 1;
- factors[i_dst] = factor;
- i_dst++;
- }
- indices.drop_front(i_dst).fill(points_num - 1);
- factors.drop_front(i_dst).fill(1.0f);
- }
- else {
- indices.drop_front(i_dst).fill(points_num - 2);
- factors.drop_front(i_dst).fill(1.0f);
- }
+ });
}
} // namespace blender::length_parameterize
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index a983821f15e..fb71e84c23e 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -370,6 +370,24 @@ MINLINE uint divide_ceil_u(uint a, uint b)
return (a + b - 1) / b;
}
+MINLINE uint64_t divide_ceil_ul(uint64_t a, uint64_t b)
+{
+ return (a + b - 1) / b;
+}
+
+/**
+ * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a .
+ */
+MINLINE uint ceil_to_multiple_u(uint a, uint b)
+{
+ return divide_ceil_u(a, b) * b;
+}
+
+MINLINE uint64_t ceil_to_multiple_ul(uint64_t a, uint64_t b)
+{
+ return divide_ceil_ul(a, b) * b;
+}
+
MINLINE int mod_i(int i, int n)
{
return (i % n + n) % n;
@@ -767,6 +785,20 @@ MALWAYS_INLINE __m128 _bli_math_fastpow24(const __m128 arg)
return _mm_mul_ps(x, _mm_mul_ps(x, x));
}
+MALWAYS_INLINE __m128 _bli_math_rsqrt(__m128 in)
+{
+ __m128 r = _mm_rsqrt_ps(in);
+ /* Only do additional Newton-Raphson iterations when using actual SSE
+ * code path. When we are emulating SSE on NEON via sse2neon, the
+ * additional NR iterations are already done inside _mm_rsqrt_ps
+ * emulation. */
+# if defined(__SSE2__)
+ r = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(1.5f), r),
+ _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(in, _mm_set1_ps(-0.5f)), r), _mm_mul_ps(r, r)));
+# endif
+ return r;
+}
+
/* Calculate powf(x, 1.0f / 2.4) */
MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg)
{
@@ -776,14 +808,14 @@ MALWAYS_INLINE __m128 _bli_math_fastpow512(const __m128 arg)
*/
__m128 xf = _bli_math_fastpow(0x3f2aaaab, 0x5eb504f3, arg);
__m128 xover = _mm_mul_ps(arg, xf);
- __m128 xfm1 = _mm_rsqrt_ps(xf);
+ __m128 xfm1 = _bli_math_rsqrt(xf);
__m128 x2 = _mm_mul_ps(arg, arg);
__m128 xunder = _mm_mul_ps(x2, xfm1);
/* sqrt2 * over + 2 * sqrt2 * under */
__m128 xavg = _mm_mul_ps(_mm_set1_ps(1.0f / (3.0f * 0.629960524947437f) * 0.999852f),
_mm_add_ps(xover, xunder));
- xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
- xavg = _mm_mul_ps(xavg, _mm_rsqrt_ps(xavg));
+ xavg = _mm_mul_ps(xavg, _bli_math_rsqrt(xavg));
+ xavg = _mm_mul_ps(xavg, _bli_math_rsqrt(xavg));
return xavg;
}
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index ce9abc36cad..fcd017b3082 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -1116,6 +1116,22 @@ double determinant_m3_array_db(const double m[3][3])
m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
}
+bool invert_m2_m2(float m1[2][2], const float m2[2][2])
+{
+ adjoint_m2_m2(m1, m2);
+ float det = determinant_m2(m2[0][0], m2[1][0], m2[0][1], m2[1][1]);
+
+ bool success = (det != 0.0f);
+ if (success) {
+ m1[0][0] /= det;
+ m1[1][0] /= det;
+ m1[0][1] /= det;
+ m1[1][1] /= det;
+ }
+
+ return success;
+}
+
bool invert_m3_ex(float m[3][3], const float epsilon)
{
float tmp[3][3];
diff --git a/source/blender/blenlib/intern/math_rotation.cc b/source/blender/blenlib/intern/math_rotation.cc
index 74300d55954..091e8af85d9 100644
--- a/source/blender/blenlib/intern/math_rotation.cc
+++ b/source/blender/blenlib/intern/math_rotation.cc
@@ -23,4 +23,17 @@ float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis,
return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
}
+float3 rotate_around_axis(const float3 &vector,
+ const float3 &center,
+ const float3 &axis,
+ const float angle)
+
+{
+ float3 result = vector - center;
+ float mat[3][3];
+ axis_angle_normalized_to_mat3(mat, axis, angle);
+ mul_m3_v3(mat, result);
+ return result + center;
+}
+
} // namespace blender::math
diff --git a/source/blender/blenlib/intern/math_solvers.c b/source/blender/blenlib/intern/math_solvers.c
index 2352d687061..b5650410a70 100644
--- a/source/blender/blenlib/intern/math_solvers.c
+++ b/source/blender/blenlib/intern/math_solvers.c
@@ -99,8 +99,8 @@ bool BLI_tridiagonal_solve_cyclic(
/* Degenerate case that works but can be simplified. */
if (count == 2) {
- float a2[2] = {0, a[1] + c[1]};
- float c2[2] = {a[0] + c[0], 0};
+ const float a2[2] = {0, a[1] + c[1]};
+ const float c2[2] = {a[0] + c[0], 0};
return BLI_tridiagonal_solve(a2, b, c2, d, r_x, count);
}
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 339bfb8f95e..27c17a90f5f 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -316,6 +316,27 @@ MINLINE void swap_v4_v4(float a[4], float b[4])
SWAP(float, a[3], b[3]);
}
+MINLINE void swap_v2_v2_db(double a[2], double b[2])
+{
+ SWAP(double, a[0], b[0]);
+ SWAP(double, a[1], b[1]);
+}
+
+MINLINE void swap_v3_v3_db(double a[3], double b[3])
+{
+ SWAP(double, a[0], b[0]);
+ SWAP(double, a[1], b[1]);
+ SWAP(double, a[2], b[2]);
+}
+
+MINLINE void swap_v4_v4_db(double a[4], double b[4])
+{
+ SWAP(double, a[0], b[0]);
+ SWAP(double, a[1], b[1]);
+ SWAP(double, a[2], b[2]);
+ SWAP(double, a[3], b[3]);
+}
+
/* float args -> vec */
MINLINE void copy_v2_fl2(float v[2], float x, float y)
@@ -613,10 +634,10 @@ 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])
{
- BLI_assert(r != vec);
-
- r[0] = mat[0] * vec[0] + (-mat[1]) * vec[1];
- r[1] = mat[1] * vec[0] + (+mat[0]) * vec[1];
+ float r0 = mat[0] * vec[0] + (-mat[1]) * vec[1];
+ float r1 = mat[1] * vec[0] + (+mat[0]) * vec[1];
+ r[0] = r0;
+ r[1] = r1;
}
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], const float co[3])
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
index 0bb606c288e..7248db5b718 100644
--- a/source/blender/blenlib/intern/rct.c
+++ b/source/blender/blenlib/intern/rct.c
@@ -265,7 +265,7 @@ bool BLI_rcti_isect_segment(const rcti *rect, const int s1[2], const int s2[2])
/* diagonal: [/] */
tvec1[0] = rect->xmin;
tvec1[1] = rect->ymin;
- tvec2[0] = rect->xmin;
+ tvec2[0] = rect->xmax;
tvec2[1] = rect->ymax;
if (isect_segments_i(s1, s2, tvec1, tvec2)) {
return true;
@@ -311,7 +311,7 @@ bool BLI_rctf_isect_segment(const rctf *rect, const float s1[2], const float s2[
/* diagonal: [/] */
tvec1[0] = rect->xmin;
tvec1[1] = rect->ymin;
- tvec2[0] = rect->xmin;
+ tvec2[0] = rect->xmax;
tvec2[1] = rect->ymax;
if (isect_segments_fl(s1, s2, tvec1, tvec2)) {
return true;
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 94efb0dd9e7..0cbf62cce03 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -363,6 +363,10 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst_w,
int BLI_wcwidth(char32_t ucs)
{
+ /* Treat private use areas (icon fonts), symbols, and emoticons as double-width. */
+ if (ucs >= 0xf0000 || (ucs >= 0xe000 && ucs < 0xf8ff) || (ucs >= 0x1f300 && ucs < 0x1fbff)) {
+ return 2;
+ }
return mk_wcwidth(ucs);
}
diff --git a/source/blender/blenlib/intern/timeit.cc b/source/blender/blenlib/intern/timeit.cc
index f11f9c4ad94..7a8cf8da038 100644
--- a/source/blender/blenlib/intern/timeit.cc
+++ b/source/blender/blenlib/intern/timeit.cc
@@ -3,19 +3,29 @@
#include "BLI_timeit.hh"
#include <algorithm>
+#include <iomanip>
namespace blender::timeit {
void print_duration(Nanoseconds duration)
{
- if (duration < std::chrono::microseconds(100)) {
+ using namespace std::chrono;
+ if (duration < microseconds(100)) {
std::cout << duration.count() << " ns";
}
- else if (duration < std::chrono::seconds(5)) {
- std::cout << duration.count() / 1.0e6 << " ms";
+ else if (duration < seconds(5)) {
+ std::cout << std::fixed << std::setprecision(1) << duration.count() / 1.0e6 << " ms";
+ }
+ else if (duration > seconds(90)) {
+ /* Long durations: print seconds, and also H:m:s */
+ const auto dur_hours = duration_cast<hours>(duration);
+ const auto dur_mins = duration_cast<minutes>(duration - dur_hours);
+ const auto dur_sec = duration_cast<seconds>(duration - dur_hours - dur_mins);
+ std::cout << std::fixed << std::setprecision(1) << duration.count() / 1.0e9 << " s ("
+ << dur_hours.count() << "H:" << dur_mins.count() << "m:" << dur_sec.count() << "s)";
}
else {
- std::cout << duration.count() / 1.0e9 << " s";
+ std::cout << std::fixed << std::setprecision(1) << duration.count() / 1.0e9 << " s";
}
}
diff --git a/source/blender/blenlib/tests/BLI_bitmap_test.cc b/source/blender/blenlib/tests/BLI_bitmap_test.cc
new file mode 100644
index 00000000000..fb9e03e3136
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_bitmap_test.cc
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include "BLI_bitmap.h"
+#include "testing/testing.h"
+
+namespace blender::tests {
+
+TEST(bitmap, empty_is_all_unset)
+{
+ BLI_BITMAP_DECLARE(bitmap, 10);
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_FALSE(BLI_BITMAP_TEST_BOOL(bitmap, i));
+ }
+}
+
+TEST(bitmap, find_first_unset_empty)
+{
+ BLI_BITMAP_DECLARE(bitmap, 10);
+ EXPECT_EQ(0, BLI_bitmap_find_first_unset(bitmap, 10));
+}
+
+TEST(bitmap, find_first_unset_full)
+{
+ BLI_BITMAP_DECLARE(bitmap, 10);
+ BLI_bitmap_flip_all(bitmap, 10);
+ EXPECT_EQ(-1, BLI_bitmap_find_first_unset(bitmap, 10));
+}
+
+TEST(bitmap, find_first_unset_middle)
+{
+ BLI_BITMAP_DECLARE(bitmap, 100);
+ BLI_bitmap_flip_all(bitmap, 100);
+ /* Turn some bits off */
+ BLI_BITMAP_DISABLE(bitmap, 53);
+ BLI_BITMAP_DISABLE(bitmap, 81);
+ BLI_BITMAP_DISABLE(bitmap, 85);
+ BLI_BITMAP_DISABLE(bitmap, 86);
+
+ /* Find lowest unset bit, and set it. */
+ EXPECT_EQ(53, BLI_bitmap_find_first_unset(bitmap, 100));
+ BLI_BITMAP_ENABLE(bitmap, 53);
+ /* Now should find the next lowest bit. */
+ EXPECT_EQ(81, BLI_bitmap_find_first_unset(bitmap, 100));
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_bounds_test.cc b/source/blender/blenlib/tests/BLI_bounds_test.cc
index 9c123d4705c..5aa4e710e90 100644
--- a/source/blender/blenlib/tests/BLI_bounds_test.cc
+++ b/source/blender/blenlib/tests/BLI_bounds_test.cc
@@ -33,6 +33,13 @@ TEST(bounds, MinMaxFloat)
EXPECT_EQ(result->max, 3.0f);
}
+TEST(bounds, MinGreaterThanZero)
+{
+ Array<float> data = {1.5f, 3.0f, 1.1f, 100.0f};
+ auto result = bounds::min_max(data.as_span());
+ EXPECT_GT(result->min, 1.0f);
+}
+
TEST(bounds, MinMaxRadii)
{
Array<int2> data = {int2(0, 1), int2(3, -1), int2(0, -2), int2(-1, 1)};
diff --git a/source/blender/blenlib/tests/BLI_index_range_test.cc b/source/blender/blenlib/tests/BLI_index_range_test.cc
index 10f6784cd44..f5b994d409a 100644
--- a/source/blender/blenlib/tests/BLI_index_range_test.cc
+++ b/source/blender/blenlib/tests/BLI_index_range_test.cc
@@ -105,6 +105,12 @@ TEST(index_range, OneAfterEnd)
EXPECT_EQ(range.one_after_last(), 8);
}
+TEST(index_range, OneBeforeStart)
+{
+ IndexRange range = IndexRange(5, 3);
+ EXPECT_EQ(range.one_before_start(), 4);
+}
+
TEST(index_range, Start)
{
IndexRange range = IndexRange(6, 2);
diff --git a/source/blender/blenlib/tests/BLI_kdtree_test.cc b/source/blender/blenlib/tests/BLI_kdtree_test.cc
new file mode 100644
index 00000000000..d040ea15172
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_kdtree_test.cc
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include "testing/testing.h"
+
+#include "BLI_kdtree.h"
+
+#include <cmath>
+
+/* -------------------------------------------------------------------- */
+/* Tests */
+
+static void standard_test()
+{
+ for (int tree_size = 30; tree_size < 500; tree_size++) {
+ int tree_index = 0;
+ KDTree_1d *tree = BLI_kdtree_1d_new(tree_size);
+ int mask = tree_size & 31;
+ bool occupied[32] = {false};
+
+ for (int i = 0; i < tree_size; i++) {
+ int index = i & mask;
+ occupied[index] = true;
+ float value = fmodf(index * 7.121f, 0.6037f); /* Co-prime. */
+ float key[1] = {value};
+ BLI_kdtree_1d_insert(tree, tree_index++, key);
+ }
+ int expected = 0;
+ for (int j = 0; j < 32; j++) {
+ if (occupied[j]) {
+ expected++;
+ }
+ }
+
+ int dedup_count = BLI_kdtree_1d_deduplicate(tree);
+ EXPECT_EQ(dedup_count, expected);
+ BLI_kdtree_1d_free(tree);
+ }
+}
+
+static void deduplicate_test()
+{
+ for (int tree_size = 1; tree_size < 40; tree_size++) {
+ int tree_index = 0;
+ KDTree_1d *tree = BLI_kdtree_1d_new(tree_size);
+ for (int i = 0; i < tree_size; i++) {
+ float key[1] = {1.0f};
+ BLI_kdtree_1d_insert(tree, tree_index++, key);
+ }
+ int dedup_count = BLI_kdtree_1d_deduplicate(tree);
+ EXPECT_EQ(dedup_count, 1);
+ BLI_kdtree_1d_free(tree);
+ }
+}
+
+TEST(kdtree, Standard)
+{
+ standard_test();
+}
+
+TEST(kdtree, Deduplicate)
+{
+ deduplicate_test();
+}
diff --git a/source/blender/blenlib/tests/BLI_length_parameterize_test.cc b/source/blender/blenlib/tests/BLI_length_parameterize_test.cc
index b63e3a0ec86..11f4997f563 100644
--- a/source/blender/blenlib/tests/BLI_length_parameterize_test.cc
+++ b/source/blender/blenlib/tests/BLI_length_parameterize_test.cc
@@ -10,7 +10,7 @@ namespace blender::length_parameterize::tests {
template<typename T> Array<float> calculate_lengths(const Span<T> values, const bool cyclic)
{
- Array<float> lengths(lengths_num(values.size(), cyclic));
+ Array<float> lengths(segments_num(values.size(), cyclic));
accumulate_lengths<T>(values, cyclic, lengths);
return lengths;
}
@@ -30,7 +30,7 @@ TEST(length_parameterize, FloatSimple)
Array<int> indices(4);
Array<float> factors(4);
- create_uniform_samples(lengths, false, indices, factors);
+ sample_uniform(lengths, true, indices, factors);
Array<float> results(4);
linear_interpolation<float>(values, indices, factors, results);
Array<float> expected({
@@ -52,7 +52,7 @@ TEST(length_parameterize, Float)
Array<int> indices(20);
Array<float> factors(20);
- create_uniform_samples(lengths, false, indices, factors);
+ sample_uniform(lengths, true, indices, factors);
Array<float> results(20);
linear_interpolation<float>(values, indices, factors, results);
Array<float> expected({
@@ -73,7 +73,7 @@ TEST(length_parameterize, Float2)
Array<int> indices(12);
Array<float> factors(12);
- create_uniform_samples(lengths, false, indices, factors);
+ sample_uniform(lengths, true, indices, factors);
Array<float2> results(12);
linear_interpolation<float2>(values, indices, factors, results);
Array<float2> expected({
@@ -103,7 +103,7 @@ TEST(length_parameterize, Float2Cyclic)
Array<int> indices(12);
Array<float> factors(12);
- create_uniform_samples(lengths, true, indices, factors);
+ sample_uniform(lengths, false, indices, factors);
Array<float2> results(12);
linear_interpolation<float2>(values, indices, factors, results);
Array<float2> expected({
@@ -133,7 +133,7 @@ TEST(length_parameterize, LineMany)
Array<int> indices(5007);
Array<float> factors(5007);
- create_uniform_samples(lengths, false, indices, factors);
+ sample_uniform(lengths, true, indices, factors);
Array<float> results(5007);
linear_interpolation<float>(values, indices, factors, results);
Array<float> expected({
@@ -152,7 +152,7 @@ TEST(length_parameterize, CyclicMany)
Array<int> indices(5007);
Array<float> factors(5007);
- create_uniform_samples(lengths, true, indices, factors);
+ sample_uniform(lengths, false, indices, factors);
Array<float2> results(5007);
linear_interpolation<float2>(values, indices, factors, results);
Array<float2> expected({
@@ -176,7 +176,7 @@ TEST(length_parameterize, InterpolateColor)
Array<int> indices(10);
Array<float> factors(10);
- create_uniform_samples(lengths, true, indices, factors);
+ sample_uniform(lengths, false, indices, factors);
Array<ColorGeometry4f> results(10);
linear_interpolation<ColorGeometry4f>(colors, indices, factors, results);
Array<ColorGeometry4f> expected({
@@ -207,7 +207,7 @@ TEST(length_parameterize, ArbitraryFloatSimple)
Array<float> sample_lengths{{0.5f, 1.5f, 2.0f, 4.0f}};
Array<int> indices(4);
Array<float> factors(4);
- create_samples_from_sorted_lengths(lengths, sample_lengths, false, indices, factors);
+ sample_at_lengths(lengths, sample_lengths, indices, factors);
Array<float> results(4);
linear_interpolation<float>(values, indices, factors, results);
results.as_span().print_as_lines("results");
@@ -231,7 +231,7 @@ TEST(length_parameterize, ArbitraryFloat2)
{0.5f, 1.5f, 2.0f, 2.0f, 2.1f, 2.5f, 3.5f, 3.6f, 3.8f, 3.85f, 3.90f, 4.0f}};
Array<int> indices(12);
Array<float> factors(12);
- create_samples_from_sorted_lengths(lengths, sample_lengths, true, indices, factors);
+ sample_at_lengths(lengths, sample_lengths, indices, factors);
Array<float2> results(12);
linear_interpolation<float2>(values, indices, factors, results);
results.as_span().print_as_lines("results");
diff --git a/source/blender/blenlib/tests/BLI_math_color_test.cc b/source/blender/blenlib/tests/BLI_math_color_test.cc
index 7f2c0a3f1ca..4d928477870 100644
--- a/source/blender/blenlib/tests/BLI_math_color_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_color_test.cc
@@ -74,3 +74,71 @@ TEST(math_color, LinearRGBTosRGBRoundtrip)
EXPECT_NEAR(orig_linear_color, linear_color, 1e-5);
}
}
+
+TEST(math_color, linearrgb_to_srgb_v3_v3)
+{
+ float srgb_color[3];
+ {
+ const float kTolerance = 1.0e-8f;
+ const float linear_color[3] = {0.0023f, 0.0024f, 0.0025f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(0.029716f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(0.031008f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(0.032300f, srgb_color[2], kTolerance);
+ }
+
+ {
+ /* SIMD implementation of linear->srgb for larger inputs
+ * is less accurate; use larger tolerance. */
+ const float kTolerance = 3.6e-5f;
+ const float linear_color[3] = {0.71f, 0.75f, 0.78f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(0.859696f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(0.880825f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(0.896244f, srgb_color[2], kTolerance);
+ }
+
+ {
+ /* Not a common, but possible case: values beyond 1.0 range. */
+ const float kTolerance = 2.3e-4f;
+ const float linear_color[3] = {1.5f, 2.8f, 5.6f};
+ linearrgb_to_srgb_v3_v3(srgb_color, linear_color);
+ EXPECT_NEAR(1.19418f, srgb_color[0], kTolerance);
+ EXPECT_NEAR(1.56520f, srgb_color[1], kTolerance);
+ EXPECT_NEAR(2.10771f, srgb_color[2], kTolerance);
+ }
+}
+
+TEST(math_color, srgb_to_linearrgb_v3_v3)
+{
+ float linear_color[3];
+ {
+ const float kTolerance = 1.0e-8f;
+ const float srgb_color[3] = {0.0023f, 0.0024f, 0.0025f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(0.000178019f, linear_color[0], kTolerance);
+ EXPECT_NEAR(0.000185759f, linear_color[1], kTolerance);
+ EXPECT_NEAR(0.000193498f, linear_color[2], kTolerance);
+ }
+
+ {
+ /* SIMD implementation of linear->srgb for larger inputs
+ * is less accurate; use larger tolerance. */
+ const float kTolerance = 1.5e-7f;
+ const float srgb_color[3] = {0.71f, 0.72f, 0.73f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(0.4623615f, linear_color[0], kTolerance);
+ EXPECT_NEAR(0.4770000f, linear_color[1], kTolerance);
+ EXPECT_NEAR(0.4919052f, linear_color[2], kTolerance);
+ }
+
+ {
+ /* Not a common, but possible case: values beyond 1.0 range. */
+ const float kTolerance = 7.7e-6f;
+ const float srgb_color[3] = {1.1f, 2.5f, 5.6f};
+ srgb_to_linearrgb_v3_v3(linear_color, srgb_color);
+ EXPECT_NEAR(1.24277f, linear_color[0], kTolerance);
+ EXPECT_NEAR(8.35473f, linear_color[1], kTolerance);
+ EXPECT_NEAR(56.23833f, linear_color[2], kTolerance);
+ }
+}
diff --git a/source/blender/blenlib/tests/BLI_math_vector_test.cc b/source/blender/blenlib/tests/BLI_math_vector_test.cc
index 282be5f1963..5686be975b5 100644
--- a/source/blender/blenlib/tests/BLI_math_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_vector_test.cc
@@ -105,4 +105,24 @@ TEST(math_vector, InterpolateFloat)
EXPECT_FLOAT_EQ(result.z, 75.0f);
}
+TEST(math_vector, CeilToMultiple)
+{
+ const int3 a(21, 16, 0);
+ const int3 b(8, 16, 15);
+ const int3 result = math::ceil_to_multiple(a, b);
+ EXPECT_FLOAT_EQ(result.x, 24);
+ EXPECT_FLOAT_EQ(result.y, 16);
+ EXPECT_FLOAT_EQ(result.z, 0);
+}
+
+TEST(math_vector, DivideCeil)
+{
+ const int3 a(21, 16, 0);
+ const int3 b(8, 16, 15);
+ const int3 result = math::divide_ceil(a, b);
+ EXPECT_FLOAT_EQ(result.x, 3);
+ EXPECT_FLOAT_EQ(result.y, 1);
+ EXPECT_FLOAT_EQ(result.z, 0);
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc
index 29b6d2b41fe..3a12fe14de3 100644
--- a/source/blender/blenlib/tests/BLI_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_test.cc
@@ -264,7 +264,8 @@ TEST(vector, AppendAndGetIndex)
EXPECT_EQ(vec.append_and_get_index(10), 1);
EXPECT_EQ(vec.append_and_get_index(10), 2);
vec.append(10);
- EXPECT_EQ(vec.append_and_get_index(10), 4);
+ int value = 10;
+ EXPECT_EQ(vec.append_and_get_index(value), 4);
}
TEST(vector, AppendNonDuplicates)
@@ -479,6 +480,7 @@ TEST(vector, UniquePtrValue)
vec.remove_and_reorder(0);
vec.remove(0);
EXPECT_EQ(vec.size(), 1);
+ EXPECT_EQ(vec.append_and_get_index(std::make_unique<int>(4)), 1);
UNUSED_VARS(a, b);
}
diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
index 90c7f1078a5..14f5480f751 100644
--- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: Apache-2.0 */
#include "BLI_array.hh"
+#include "BLI_generic_virtual_array.hh"
#include "BLI_strict_flags.h"
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
@@ -109,7 +110,7 @@ TEST(virtual_array, AsSpan)
{
auto func = [](int64_t index) { return (int)(10 * index); };
VArray<int> func_varray = VArray<int>::ForFunc(10, func);
- VArray_Span span_varray{func_varray};
+ VArraySpan span_varray{func_varray};
EXPECT_EQ(span_varray.size(), 10);
Span<int> span = span_varray;
EXPECT_EQ(span.size(), 10);
@@ -222,4 +223,36 @@ TEST(virtual_array, MaterializeCompressed)
}
}
+TEST(virtual_array, EmptySpanWrapper)
+{
+ {
+ VArray<int> varray;
+ VArraySpan<int> span1 = varray;
+ EXPECT_TRUE(span1.is_empty());
+ VArraySpan<int> span2 = std::move(span1);
+ EXPECT_TRUE(span2.is_empty());
+ }
+ {
+ VMutableArray<int> varray;
+ MutableVArraySpan<int> span1 = varray;
+ EXPECT_TRUE(span1.is_empty());
+ MutableVArraySpan<int> span2 = std::move(span1);
+ EXPECT_TRUE(span2.is_empty());
+ }
+ {
+ GVArray varray;
+ GVArraySpan span1 = varray;
+ EXPECT_TRUE(span1.is_empty());
+ GVArraySpan span2 = std::move(span1);
+ EXPECT_TRUE(span2.is_empty());
+ }
+ {
+ GVMutableArray varray;
+ GMutableVArraySpan span1 = varray;
+ EXPECT_TRUE(span1.is_empty());
+ GMutableVArraySpan span2 = std::move(span1);
+ EXPECT_TRUE(span2.is_empty());
+ }
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 973965ada50..f0d390677bb 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2732,6 +2732,8 @@ void blo_lib_link_restore(Main *oldmain,
LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
lib_link_workspace_layout_restore(id_map, newmain, layout);
}
+ workspace->pin_scene = restore_pointer_by_name(
+ id_map, (ID *)workspace->pin_scene, USER_IGNORE);
}
LISTBASE_FOREACH (wmWindow *, win, &curwm->windows) {
@@ -2745,6 +2747,7 @@ void blo_lib_link_restore(Main *oldmain,
if (win->scene == NULL) {
win->scene = curscene;
}
+ win->unpinned_scene = restore_pointer_by_name(id_map, (ID *)win->unpinned_scene, USER_IGNORE);
if (BKE_view_layer_find(win->scene, win->view_layer_name) == NULL) {
STRNCPY(win->view_layer_name, cur_view_layer->name);
}
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 67b6ad25d8b..ffa224ea9e0 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -425,14 +425,14 @@ static void do_versions_windowmanager_2_50(bScreen *screen)
}
}
-static void versions_gpencil_add_main(ListBase *lb, ID *id, const char *name)
+static void versions_gpencil_add_main(Main *bmain, ListBase *lb, ID *id, const char *name)
{
BLI_addtail(lb, id);
id->us = 1;
id->flag = LIB_FAKEUSER;
*((short *)id->name) = ID_GD;
- BKE_id_new_name_validate(lb, id, name, false);
+ BKE_id_new_name_validate(bmain, lb, id, name, false);
/* alphabetic insertion: is in BKE_id_new_name_validate */
if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) {
@@ -455,21 +455,21 @@ static void do_versions_gpencil_2_50(Main *main, bScreen *screen)
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->gpd) {
- versions_gpencil_add_main(&main->gpencils, (ID *)v3d->gpd, "GPencil View3D");
+ versions_gpencil_add_main(main, &main->gpencils, (ID *)v3d->gpd, "GPencil View3D");
v3d->gpd = NULL;
}
}
else if (sl->spacetype == SPACE_NODE) {
SpaceNode *snode = (SpaceNode *)sl;
if (snode->gpd) {
- versions_gpencil_add_main(&main->gpencils, (ID *)snode->gpd, "GPencil Node");
+ versions_gpencil_add_main(main, &main->gpencils, (ID *)snode->gpd, "GPencil Node");
snode->gpd = NULL;
}
}
else if (sl->spacetype == SPACE_SEQ) {
SpaceSeq *sseq = (SpaceSeq *)sl;
if (sseq->gpd) {
- versions_gpencil_add_main(&main->gpencils, (ID *)sseq->gpd, "GPencil Node");
+ versions_gpencil_add_main(main, &main->gpencils, (ID *)sseq->gpd, "GPencil Node");
sseq->gpd = NULL;
}
}
@@ -477,7 +477,7 @@ static void do_versions_gpencil_2_50(Main *main, bScreen *screen)
SpaceImage *sima = (SpaceImage *)sl;
#if 0 /* see comment on r28002 */
if (sima->gpd) {
- versions_gpencil_add_main(&main->gpencil, (ID *)sima->gpd, "GPencil Image");
+ versions_gpencil_add_main(main, &main->gpencil, (ID *)sima->gpd, "GPencil Image");
sima->gpd = NULL;
}
#else
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index eeec55a7b06..cd2132ddae9 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -73,6 +73,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_node.h"
#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
@@ -1569,8 +1570,8 @@ void do_versions_after_linking_280(Main *bmain, ReportList *UNUSED(reports))
if (!MAIN_VERSION_ATLEAST(bmain, 281, 2)) {
/* Replace Multiply and Additive blend mode by Alpha Blend
- * now that we use dualsource blending. */
- /* We take care of doing only nodetrees that are always part of materials
+ * now that we use dual-source blending. */
+ /* We take care of doing only node-trees that are always part of materials
* with old blending modes. */
for (Material *ma = bmain->materials.first; ma; ma = ma->id.next) {
bNodeTree *ntree = ma->nodetree;
@@ -2408,7 +2409,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
scene->toolsettings->snap_mode = (1 << 1); /* SCE_SNAP_MODE_EDGE */
break;
case 3:
- scene->toolsettings->snap_mode = (1 << 2); /* SCE_SNAP_MODE_FACE */
+ scene->toolsettings->snap_mode = (1 << 2); /* SCE_SNAP_MODE_FACE_RAYCAST */
break;
case 4:
scene->toolsettings->snap_mode = (1 << 3); /* SCE_SNAP_MODE_VOLUME */
@@ -3548,7 +3549,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 280, 43)) {
ListBase *lb = which_libbase(bmain, ID_BR);
- BKE_main_id_repair_duplicate_names_listbase(lb);
+ BKE_main_id_repair_duplicate_names_listbase(bmain, lb);
}
if (!MAIN_VERSION_ATLEAST(bmain, 280, 44)) {
@@ -4102,7 +4103,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_DataTransfer) {
- /* Now datatransfer's mix factor is multiplied with weights when any,
+ /* Now data-transfer's mix factor is multiplied with weights when any,
* instead of being ignored,
* we need to take care of that to keep 'old' files compatible. */
DataTransferModifierData *dtmd = (DataTransferModifierData *)md;
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 585ada3b2d8..9ab744337a8 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -160,7 +160,7 @@ static void seq_convert_transform_crop(const Scene *scene,
const uint32_t use_transform_flag = (1 << 16);
const uint32_t use_crop_flag = (1 << 17);
- const StripElem *s_elem = SEQ_render_give_stripelem(seq, seq->start);
+ const StripElem *s_elem = seq->strip->stripdata;
if (s_elem != NULL) {
image_size_x = s_elem->orig_width;
image_size_y = s_elem->orig_height;
@@ -285,7 +285,7 @@ static void seq_convert_transform_crop_2(const Scene *scene,
Sequence *seq,
const eSpaceSeq_Proxy_RenderSize render_size)
{
- const StripElem *s_elem = SEQ_render_give_stripelem(seq, seq->start);
+ const StripElem *s_elem = seq->strip->stripdata;
if (s_elem == NULL) {
return;
}
@@ -347,8 +347,10 @@ static void seq_convert_transform_crop_lb_2(const Scene *scene,
}
}
-static void seq_update_meta_disp_range(Editing *ed)
+static void seq_update_meta_disp_range(Scene *scene)
{
+ Editing *ed = SEQ_editing_get(scene);
+
if (ed == NULL) {
return;
}
@@ -356,13 +358,14 @@ static void seq_update_meta_disp_range(Editing *ed)
LISTBASE_FOREACH_BACKWARD (MetaStack *, ms, &ed->metastack) {
/* Update ms->disp_range from meta. */
if (ms->disp_range[0] == ms->disp_range[1]) {
- copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
+ ms->disp_range[0] = SEQ_time_left_handle_frame_get(scene, ms->parseq);
+ ms->disp_range[1] = SEQ_time_right_handle_frame_get(scene, ms->parseq);
}
/* Update meta strip endpoints. */
- SEQ_time_left_handle_frame_set(ms->parseq, ms->disp_range[0]);
- SEQ_time_right_handle_frame_set(ms->parseq, ms->disp_range[1]);
- SEQ_transform_fix_single_image_seq_offsets(ms->parseq);
+ SEQ_time_left_handle_frame_set(scene, ms->parseq, ms->disp_range[0]);
+ SEQ_time_right_handle_frame_set(scene, ms->parseq, ms->disp_range[1]);
+ SEQ_transform_fix_single_image_seq_offsets(scene, ms->parseq);
/* Recalculate effects using meta strip. */
LISTBASE_FOREACH (Sequence *, seq, ms->oldbasep) {
@@ -647,7 +650,7 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports))
if (!MAIN_VERSION_ATLEAST(bmain, 293, 16)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- seq_update_meta_disp_range(SEQ_editing_get(scene));
+ seq_update_meta_disp_range(scene);
}
/* Add a separate socket for Grid node X and Y size. */
@@ -846,7 +849,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
short id_codes[] = {ID_BR, ID_PAL};
for (int i = 0; i < ARRAY_SIZE(id_codes); i++) {
ListBase *lb = which_libbase(bmain, id_codes[i]);
- BKE_main_id_repair_duplicate_names_listbase(lb);
+ BKE_main_id_repair_duplicate_names_listbase(bmain, lb);
}
}
@@ -1446,7 +1449,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
view_layer->eevee.render_passes &= ~EEVEE_RENDER_PASS_UNUSED_8;
}
- /* Rename Renderlayer Socket `VolumeScatterCol` to `VolumeDir` */
+ /* Rename Render-layer Socket `VolumeScatterCol` to `VolumeDir`. */
if (scene->nodetree) {
LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
if (node->type == CMP_NODE_R_LAYERS) {
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index 74621a477cd..bbbeba4d687 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -25,10 +25,12 @@
#include "DNA_collection_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
+#include "DNA_curves_types.h"
#include "DNA_genfile.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_lineart_types.h"
#include "DNA_listBase.h"
+#include "DNA_mask_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
@@ -44,6 +46,7 @@
#include "BKE_asset.h"
#include "BKE_attribute.h"
#include "BKE_collection.h"
+#include "BKE_colortools.h"
#include "BKE_curve.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h"
@@ -63,7 +66,7 @@
#include "RNA_prototypes.h"
#include "BLO_readfile.h"
-#include "MEM_guardedalloc.h"
+
#include "readfile.h"
#include "SEQ_channels.h"
@@ -71,8 +74,6 @@
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
-#include "RNA_access.h"
-
#include "versioning_common.h"
static CLG_LogRef LOG = {"blo.readfile.doversion"};
@@ -407,7 +408,9 @@ static void do_versions_sequencer_speed_effect_recursive(Scene *scene, const Lis
v->speed_control_type = SEQ_SPEED_MULTIPLY;
v->speed_fader = globalSpeed *
((float)seq->seq1->len /
- max_ff((float)(seq->seq1->enddisp - seq->seq1->start), 1.0f));
+ max_ff((float)(SEQ_time_right_handle_frame_get(scene, seq->seq1) -
+ seq->seq1->start),
+ 1.0f));
}
}
else if (v->flags & SEQ_SPEED_INTEGRATE) {
@@ -592,6 +595,39 @@ static bNodeTree *add_realize_node_tree(Main *bmain)
return node_tree;
}
+static void seq_speed_factor_fix_rna_path(Sequence *seq, ListBase *fcurves)
+{
+ char name_esc[(sizeof(seq->name) - 2) * 2];
+ BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc));
+ char *path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].pitch", name_esc);
+ FCurve *fcu = BKE_fcurve_find(fcurves, path, 0);
+ if (fcu != NULL) {
+ MEM_freeN(fcu->rna_path);
+ fcu->rna_path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].speed_factor", name_esc);
+ }
+ MEM_freeN(path);
+}
+
+static bool seq_speed_factor_set(Sequence *seq, void *user_data)
+{
+ const Scene *scene = user_data;
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ /* Move `pitch` animation to `speed_factor` */
+ if (scene->adt && scene->adt->action) {
+ seq_speed_factor_fix_rna_path(seq, &scene->adt->action->curves);
+ }
+ if (scene->adt && !BLI_listbase_is_empty(&scene->adt->drivers)) {
+ seq_speed_factor_fix_rna_path(seq, &scene->adt->drivers);
+ }
+
+ seq->speed_factor = seq->pitch;
+ }
+ else {
+ seq->speed_factor = 1.0f;
+ }
+ return true;
+}
+
void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
{
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@@ -795,13 +831,16 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
continue;
}
SpaceSeq *sseq = (SpaceSeq *)sl;
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
sseq->flag |= SEQ_CLAMP_VIEW;
if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
continue;
}
- ARegion *timeline_region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ ARegion *timeline_region = BKE_region_find_in_listbase_by_type(regionbase,
+ RGN_TYPE_WINDOW);
if (timeline_region == NULL) {
continue;
@@ -813,6 +852,17 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
}
}
}
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 5)) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ Editing *ed = SEQ_editing_get(scene);
+ if (ed == NULL) {
+ continue;
+ }
+ SEQ_for_each_callback(&ed->seqbase, seq_speed_factor_set, scene);
+ }
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
@@ -1000,6 +1050,9 @@ static void do_version_subsurface_methods(bNode *node)
static void version_geometry_nodes_add_attribute_input_settings(NodesModifierData *nmd)
{
+ if (nmd->settings.properties == NULL) {
+ return;
+ }
/* Before versioning the properties, make sure it hasn't been done already. */
LISTBASE_FOREACH (const IDProperty *, property, &nmd->settings.properties->data.group) {
if (strstr(property->name, "_use_attribute") || strstr(property->name, "_attribute_name")) {
@@ -1371,6 +1424,275 @@ static void version_liboverride_rnacollections_insertion_animdata(ID *id)
}
}
+static void versioning_replace_legacy_combined_and_separate_color_nodes(bNodeTree *ntree)
+{
+ /* In geometry nodes, replace shader combine/separate color nodes with function nodes */
+ if (ntree->type == NTREE_GEOMETRY) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = FN_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = FN_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "FunctionNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with
+ * combine/separate color */
+ if (ntree->type == NTREE_COMPOSIT) {
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha");
+
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue");
+ version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha");
+
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue");
+ version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case CMP_NODE_COMBRGBA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBHSVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYCCA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_COMBYUVA_LEGACY: {
+ node->type = CMP_NODE_COMBINE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPRGBA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPHSVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYCCA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
+ storage->ycc_mode = node->custom1;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case CMP_NODE_SEPYUVA_LEGACY: {
+ node->type = CMP_NODE_SEPARATE_COLOR;
+ NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
+ sizeof(NodeCMPCombSepColor), __func__);
+ storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
+ strcpy(node->idname, "CompositorNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+
+ /* In texture nodes, replace combine/separate RGBA with combine/separate color */
+ if (ntree->type == NTREE_TEXTURE) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case TEX_NODE_COMPOSE_LEGACY: {
+ node->type = TEX_NODE_COMBINE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeCombineColor");
+ break;
+ }
+ case TEX_NODE_DECOMPOSE_LEGACY: {
+ node->type = TEX_NODE_SEPARATE_COLOR;
+ node->custom1 = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "TextureNodeSeparateColor");
+ break;
+ }
+ }
+ }
+ }
+
+ /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */
+ if (ntree->type == NTREE_SHADER) {
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
+ version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green");
+ version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
+ version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green");
+ version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue");
+
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ switch (node->type) {
+ case SH_NODE_COMBRGB_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_COMBHSV_LEGACY: {
+ node->type = SH_NODE_COMBINE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeCombineColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPRGB_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_RGB;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ case SH_NODE_SEPHSV_LEGACY: {
+ node->type = SH_NODE_SEPARATE_COLOR;
+ NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
+ __func__);
+ storage->mode = NODE_COMBSEP_COLOR_HSV;
+ strcpy(node->idname, "ShaderNodeSeparateColor");
+ node->storage = storage;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void version_fix_image_format_copy(Main *bmain, ImageFormatData *format)
+{
+ /* Fix bug where curves in image format were not properly copied to file output
+ * node, incorrectly sharing a pointer with the scene settings. Copy the data
+ * structure now as it should have been done in the first place. */
+ if (format->view_settings.curve_mapping) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (format != &scene->r.im_format && ELEM(format->view_settings.curve_mapping,
+ scene->view_settings.curve_mapping,
+ scene->r.im_format.view_settings.curve_mapping)) {
+ format->view_settings.curve_mapping = BKE_curvemapping_copy(
+ format->view_settings.curve_mapping);
+ break;
+ }
+ }
+
+ /* Remove any invalid curves with missing data. */
+ if (format->view_settings.curve_mapping->cm[0].curve == NULL) {
+ BKE_curvemapping_free(format->view_settings.curve_mapping);
+ format->view_settings.curve_mapping = NULL;
+ format->view_settings.flag &= ~COLORMANAGE_VIEW_USE_CURVES;
+ }
+ }
+}
+
/* NOLINTNEXTLINE: readability-function-size */
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
@@ -1695,7 +2017,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Font names were copied directly into ID names, see: T90417. */
if (!MAIN_VERSION_ATLEAST(bmain, 300, 16)) {
ListBase *lb = which_libbase(bmain, ID_VF);
- BKE_main_id_repair_duplicate_names_listbase(lb);
+ BKE_main_id_repair_duplicate_names_listbase(bmain, lb);
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 17)) {
@@ -2489,8 +2811,8 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
/* Rebuild active/render color attribute references. */
if (!MAIN_VERSION_ATLEAST(bmain, 302, 6)) {
LISTBASE_FOREACH (Brush *, br, &bmain->brushes) {
- /* buggy code in wm_toolsystem broke smear in old files,
- reset to defaults */
+ /* Buggy code in wm_toolsystem broke smear in old files,
+ * reset to defaults. */
if (br->sculpt_tool == SCULPT_TOOL_SMEAR) {
br->alpha = 1.0f;
br->spacing = 5;
@@ -2594,16 +2916,19 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
&sl->regionbase;
- ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
+ ARegion *region = BKE_region_find_in_listbase_by_type(regionbase, RGN_TYPE_CHANNELS);
if (!region) {
- ARegion *tools_region = BKE_area_find_region_type(area, RGN_TYPE_TOOLS);
+ /* Find sequencer tools region. */
+ ARegion *tools_region = BKE_region_find_in_listbase_by_type(regionbase,
+ RGN_TYPE_TOOLS);
region = do_versions_add_region(RGN_TYPE_CHANNELS, "channels region");
BLI_insertlinkafter(regionbase, tools_region, region);
region->alignment = RGN_ALIGN_LEFT;
region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
}
- ARegion *timeline_region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ ARegion *timeline_region = BKE_region_find_in_listbase_by_type(regionbase,
+ RGN_TYPE_WINDOW);
if (timeline_region != NULL) {
timeline_region->v2d.flag |= V2D_VIEWSYNC_AREA_VERTICAL;
}
@@ -2777,256 +3102,129 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /**
- * Versioning code until next subversion bump goes here.
- *
- * \note Be sure to check when bumping the version:
- * - "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. */
-
- /* Replace legacy combine/separate color nodes */
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 1)) {
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- /* In geometry nodes, replace shader combine/separate color nodes with function nodes */
- if (ntree->type == NTREE_GEOMETRY) {
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
- version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
+ versioning_replace_legacy_combined_and_separate_color_nodes(ntree);
+ }
+ FOREACH_NODETREE_END;
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
- version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+ /* Initialize brush curves sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
+ continue;
+ }
+ if (brush->curves_sculpt_settings->points_per_curve == 0) {
+ brush->curves_sculpt_settings->points_per_curve = 8;
+ }
+ }
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- switch (node->type) {
- case SH_NODE_COMBRGB_LEGACY: {
- node->type = FN_NODE_COMBINE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "FunctionNodeCombineColor");
- node->storage = storage;
- break;
- }
- case SH_NODE_SEPRGB_LEGACY: {
- node->type = FN_NODE_SEPARATE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "FunctionNodeSeparateColor");
- node->storage = storage;
- break;
- }
- }
+ /* UDIM Packing. */
+ if (!DNA_struct_elem_find(fd->filesdna, "ImagePackedFile", "int", "tile_number")) {
+ for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
+ int view;
+ LISTBASE_FOREACH_INDEX (ImagePackedFile *, imapf, &ima->packedfiles, view) {
+ imapf->view = view;
+ imapf->tile_number = 1001;
}
}
+ }
- /* In compositing nodes, replace combine/separate RGBA/HSVA/YCbCrA/YCCA nodes with
- * combine/separate color */
- if (ntree->type == NTREE_COMPOSIT) {
- version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "R", "Red");
- version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "G", "Green");
- version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "B", "Blue");
- version_node_input_socket_name(ntree, CMP_NODE_COMBRGBA_LEGACY, "A", "Alpha");
-
- version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "H", "Red");
- version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "S", "Green");
- version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "V", "Blue");
- version_node_input_socket_name(ntree, CMP_NODE_COMBHSVA_LEGACY, "A", "Alpha");
-
- version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Y", "Red");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cb", "Green");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "Cr", "Blue");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYCCA_LEGACY, "A", "Alpha");
-
- version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "Y", "Red");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "U", "Green");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "V", "Blue");
- version_node_input_socket_name(ntree, CMP_NODE_COMBYUVA_LEGACY, "A", "Alpha");
-
- version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "R", "Red");
- version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "G", "Green");
- version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "B", "Blue");
- version_node_output_socket_name(ntree, CMP_NODE_SEPRGBA_LEGACY, "A", "Alpha");
-
- version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "H", "Red");
- version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "S", "Green");
- version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "V", "Blue");
- version_node_output_socket_name(ntree, CMP_NODE_SEPHSVA_LEGACY, "A", "Alpha");
-
- version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Y", "Red");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cb", "Green");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "Cr", "Blue");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYCCA_LEGACY, "A", "Alpha");
-
- version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "Y", "Red");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "U", "Green");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "V", "Blue");
- version_node_output_socket_name(ntree, CMP_NODE_SEPYUVA_LEGACY, "A", "Alpha");
+ /* Merge still offsets into start/end offsets. */
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ Editing *ed = SEQ_editing_get(scene);
+ if (ed != NULL) {
+ SEQ_for_each_callback(&ed->seqbase, version_merge_still_offsets, NULL);
+ }
+ }
+ /* Use the curves type enum for the set spline type node, instead of a special one. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- switch (node->type) {
- case CMP_NODE_COMBRGBA_LEGACY: {
- node->type = CMP_NODE_COMBINE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "CompositorNodeCombineColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_COMBHSVA_LEGACY: {
- node->type = CMP_NODE_COMBINE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
- strcpy(node->idname, "CompositorNodeCombineColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_COMBYCCA_LEGACY: {
- node->type = CMP_NODE_COMBINE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
- storage->ycc_mode = node->custom1;
- strcpy(node->idname, "CompositorNodeCombineColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_COMBYUVA_LEGACY: {
- node->type = CMP_NODE_COMBINE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
- strcpy(node->idname, "CompositorNodeCombineColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_SEPRGBA_LEGACY: {
- node->type = CMP_NODE_SEPARATE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "CompositorNodeSeparateColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_SEPHSVA_LEGACY: {
- node->type = CMP_NODE_SEPARATE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_HSV;
- strcpy(node->idname, "CompositorNodeSeparateColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_SEPYCCA_LEGACY: {
- node->type = CMP_NODE_SEPARATE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_YCC;
- storage->ycc_mode = node->custom1;
- strcpy(node->idname, "CompositorNodeSeparateColor");
- node->storage = storage;
- break;
- }
- case CMP_NODE_SEPYUVA_LEGACY: {
- node->type = CMP_NODE_SEPARATE_COLOR;
- NodeCMPCombSepColor *storage = (NodeCMPCombSepColor *)MEM_callocN(
- sizeof(NodeCMPCombSepColor), __func__);
- storage->mode = CMP_NODE_COMBSEP_COLOR_YUV;
- strcpy(node->idname, "CompositorNodeSeparateColor");
- node->storage = storage;
- break;
+ if (node->type == GEO_NODE_CURVE_SPLINE_TYPE) {
+ NodeGeometryCurveSplineType *storage = (NodeGeometryCurveSplineType *)node->storage;
+ switch (storage->spline_type) {
+ case 0: /* GEO_NODE_SPLINE_TYPE_BEZIER */
+ storage->spline_type = CURVE_TYPE_BEZIER;
+ break;
+ case 1: /* GEO_NODE_SPLINE_TYPE_NURBS */
+ storage->spline_type = CURVE_TYPE_NURBS;
+ break;
+ case 2: /* GEO_NODE_SPLINE_TYPE_POLY */
+ storage->spline_type = CURVE_TYPE_POLY;
+ break;
}
}
}
}
+ }
+ FOREACH_NODETREE_END;
- /* In texture nodes, replace combine/separate RGBA with combine/separate color */
- if (ntree->type == NTREE_TEXTURE) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- switch (node->type) {
- case TEX_NODE_COMPOSE_LEGACY: {
- node->type = TEX_NODE_COMBINE_COLOR;
- node->custom1 = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "TextureNodeCombineColor");
- break;
- }
- case TEX_NODE_DECOMPOSE_LEGACY: {
- node->type = TEX_NODE_SEPARATE_COLOR;
- node->custom1 = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "TextureNodeSeparateColor");
- break;
- }
- }
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (GpencilModifierData *, gpd, &ob->greasepencil_modifiers) {
+ if (gpd->type == eGpencilModifierType_Lineart) {
+ LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)gpd;
+ lmd->shadow_camera_near = 0.1f;
+ lmd->shadow_camera_far = 200.0f;
+ lmd->shadow_camera_size = 200.0f;
}
}
+ }
+ }
- /* In shader nodes, replace combine/separate RGB/HSV with combine/separate color */
- if (ntree->type == NTREE_SHADER) {
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "R", "Red");
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "G", "Green");
- version_node_input_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "B", "Blue");
- version_node_output_socket_name(ntree, SH_NODE_COMBRGB_LEGACY, "Image", "Color");
-
- version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "H", "Red");
- version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "S", "Green");
- version_node_input_socket_name(ntree, SH_NODE_COMBHSV_LEGACY, "V", "Blue");
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 2)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_CLIP) {
+ ((SpaceClip *)sl)->mask_info.blend_factor = 1.0;
+ }
+ }
+ }
+ }
+ }
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "R", "Red");
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "G", "Green");
- version_node_output_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "B", "Blue");
- version_node_input_socket_name(ntree, SH_NODE_SEPRGB_LEGACY, "Image", "Color");
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 3)) {
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_CLIP) {
+ ((SpaceClip *)sl)->mask_info.draw_flag |= MASK_DRAWFLAG_SPLINE;
+ }
+ else if (sl->spacetype == SPACE_IMAGE) {
+ ((SpaceImage *)sl)->mask_info.draw_flag |= MASK_DRAWFLAG_SPLINE;
+ }
+ }
+ }
+ }
- version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "H", "Red");
- version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "S", "Green");
- version_node_output_socket_name(ntree, SH_NODE_SEPHSV_LEGACY, "V", "Blue");
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ ToolSettings *tool_settings = scene->toolsettings;
+ /* Zero isn't a valid value, use for versioning. */
+ if (tool_settings->snap_face_nearest_steps == 0) {
+ /* Minimum of snap steps for face nearest is 1. */
+ tool_settings->snap_face_nearest_steps = 1;
+ /* Set snap to edited and non-edited as default. */
+ tool_settings->snap_flag |= SCE_SNAP_TO_INCLUDE_EDITED | SCE_SNAP_TO_INCLUDE_NONEDITED;
+ }
+ }
+ }
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 4)) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- switch (node->type) {
- case SH_NODE_COMBRGB_LEGACY: {
- node->type = SH_NODE_COMBINE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "ShaderNodeCombineColor");
- node->storage = storage;
- break;
- }
- case SH_NODE_COMBHSV_LEGACY: {
- node->type = SH_NODE_COMBINE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_HSV;
- strcpy(node->idname, "ShaderNodeCombineColor");
- node->storage = storage;
- break;
- }
- case SH_NODE_SEPRGB_LEGACY: {
- node->type = SH_NODE_SEPARATE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_RGB;
- strcpy(node->idname, "ShaderNodeSeparateColor");
- node->storage = storage;
- break;
+ if (node->type == CMP_NODE_OUTPUT_FILE) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ if (sock->storage) {
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
+ version_fix_image_format_copy(bmain, &sockdata->format);
+ }
}
- case SH_NODE_SEPHSV_LEGACY: {
- node->type = SH_NODE_SEPARATE_COLOR;
- NodeCombSepColor *storage = (NodeCombSepColor *)MEM_callocN(sizeof(NodeCombSepColor),
- __func__);
- storage->mode = NODE_COMBSEP_COLOR_HSV;
- strcpy(node->idname, "ShaderNodeSeparateColor");
- node->storage = storage;
- break;
+
+ if (node->storage) {
+ NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
+ version_fix_image_format_copy(bmain, &nimf->format);
}
}
}
@@ -3034,32 +3232,56 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
FOREACH_NODETREE_END;
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ version_fix_image_format_copy(bmain, &scene->r.im_format);
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(bmain, 303, 5)) {
+ /* Fix for T98925 - remove channels region, that was initialized in incorrect editor types. */
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (ELEM(sl->spacetype, SPACE_ACTION, SPACE_CLIP, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ)) {
+ continue;
+ }
+
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ ARegion *channels_region = BKE_region_find_in_listbase_by_type(regionbase,
+ RGN_TYPE_CHANNELS);
+ if (channels_region) {
+ BLI_freelinkN(regionbase, channels_region);
+ }
+ }
+ }
+ }
+ }
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "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. */
+
/* Initialize brush curves sculpt settings. */
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
continue;
}
- if (brush->curves_sculpt_settings->points_per_curve == 0) {
- brush->curves_sculpt_settings->points_per_curve = 8;
- }
- }
-
- /* UDIM Packing. */
- if (!DNA_struct_elem_find(fd->filesdna, "ImagePackedFile", "int", "tile_number")) {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- int view;
- LISTBASE_FOREACH_INDEX (ImagePackedFile *, imapf, &ima->packedfiles, view) {
- imapf->view = view;
- imapf->tile_number = 1001;
- }
- }
+ brush->curves_sculpt_settings->density_add_attempts = 100;
}
- /* Merge still offsets into start/end offsets. */
- LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
- Editing *ed = SEQ_editing_get(scene);
- if (ed != NULL) {
- SEQ_for_each_callback(&ed->seqbase, version_merge_still_offsets, NULL);
+ /* Disable 'show_bounds' option of curve objects. Option was set as there was no object mode
+ * outline implementation. See T95933. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_CURVES) {
+ ob->dtx &= ~OB_DRAWBOUNDOX;
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index f65976ee55f..dfd98cb94f3 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -23,6 +23,7 @@
#include "DNA_curveprofile_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_light_types.h"
+#include "DNA_mask_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -184,6 +185,8 @@ static void blo_update_defaults_screen(bScreen *screen,
else if (area->spacetype == SPACE_CLIP) {
SpaceClip *sclip = area->spacedata.first;
sclip->around = V3D_AROUND_CENTER_MEDIAN;
+ sclip->mask_info.blend_factor = 0.7f;
+ sclip->mask_info.draw_flag = MASK_DRAWFLAG_SPLINE;
}
}
@@ -476,8 +479,10 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
/* Default only has one window. */
if (layout->screen) {
bScreen *screen = layout->screen;
- BLI_strncpy(screen->id.name + 2, workspace->id.name + 2, sizeof(screen->id.name) - 2);
- BLI_libblock_ensure_unique_name(bmain, screen->id.name);
+ if (!STREQ(screen->id.name + 2, workspace->id.name + 2)) {
+ BLI_strncpy(screen->id.name + 2, workspace->id.name + 2, sizeof(screen->id.name) - 2);
+ BLI_libblock_ensure_unique_name(bmain, screen->id.name);
+ }
}
/* For some reason we have unused screens, needed until re-saving.
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 4c27b8b9016..75cc333e4b5 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -1468,7 +1468,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (me = bmain->meshes.first; me; me = me->id.next) {
if (!me->medge) {
- BKE_mesh_calc_edges_legacy(me, true); /* true = use mface->edcode */
+ BKE_mesh_calc_edges_legacy(me, true); /* true = use #MFace.edcode. */
}
else {
BKE_mesh_strip_loose_faces(me);
@@ -2296,7 +2296,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
psys->vgroup[PSYS_VG_VEL] = paf->vertgroup_v;
psys->vgroup[PSYS_VG_LENGTH] = paf->vertgroup_v;
- /* dupliobjects */
+ /* Dupli-objects. */
if (ob->transflag & OB_DUPLIVERTS) {
Object *dup = bmain->objects.first;
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 4525c5f6ad3..08f6b57845c 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -55,259 +55,6 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
#define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(userdef, ver, subver)
#define FROM_DEFAULT_V4_UCHAR(member) copy_v4_v4_uchar(btheme->member, U_theme_default.member)
- if (!USER_VERSION_ATLEAST(280, 25)) {
- copy_v4_v4_uchar(btheme->space_action.anim_preview_range, btheme->space_action.anim_active);
- copy_v4_v4_uchar(btheme->space_nla.anim_preview_range, btheme->space_nla.anim_active);
- copy_v4_v4_uchar(btheme->space_graph.anim_preview_range, btheme->space_action.anim_active);
- }
-
- if (!USER_VERSION_ATLEAST(280, 26)) {
- FROM_DEFAULT_V4_UCHAR(tui.icon_collection);
- FROM_DEFAULT_V4_UCHAR(tui.icon_object);
- FROM_DEFAULT_V4_UCHAR(tui.icon_object_data);
- FROM_DEFAULT_V4_UCHAR(tui.icon_modifier);
- FROM_DEFAULT_V4_UCHAR(tui.icon_shading);
- }
-
- if (!USER_VERSION_ATLEAST(280, 27)) {
- FROM_DEFAULT_V4_UCHAR(space_action.shade2);
- FROM_DEFAULT_V4_UCHAR(space_action.hilite);
- FROM_DEFAULT_V4_UCHAR(space_action.group);
- FROM_DEFAULT_V4_UCHAR(space_action.group_active);
- FROM_DEFAULT_V4_UCHAR(space_action.strip_select);
- FROM_DEFAULT_V4_UCHAR(space_action.ds_channel);
- FROM_DEFAULT_V4_UCHAR(space_action.ds_subchannel);
- FROM_DEFAULT_V4_UCHAR(space_action.keytype_movehold);
- FROM_DEFAULT_V4_UCHAR(space_action.keytype_movehold_select);
- }
-
- if (!USER_VERSION_ATLEAST(280, 28)) {
- FROM_DEFAULT_V4_UCHAR(space_action.ds_ipoline);
- }
-
- if (!USER_VERSION_ATLEAST(280, 29)) {
- FROM_DEFAULT_V4_UCHAR(space_properties.navigation_bar);
- }
- if (!USER_VERSION_ATLEAST(280, 31)) {
- FROM_DEFAULT_V4_UCHAR(space_clip.list_text);
- }
-
- if (!USER_VERSION_ATLEAST(280, 36)) {
- FROM_DEFAULT_V4_UCHAR(tui.wcol_state.inner_changed);
- FROM_DEFAULT_V4_UCHAR(tui.wcol_state.inner_changed_sel);
- }
-
- if (!USER_VERSION_ATLEAST(280, 39)) {
- FROM_DEFAULT_V4_UCHAR(space_clip.metadatabg);
- FROM_DEFAULT_V4_UCHAR(space_clip.metadatatext);
- }
-
- if (!USER_VERSION_ATLEAST(280, 40)) {
- FROM_DEFAULT_V4_UCHAR(space_preferences.navigation_bar);
- copy_v4_v4_uchar(btheme->space_preferences.execution_buts,
- btheme->space_preferences.navigation_bar);
- }
-
- if (!USER_VERSION_ATLEAST(280, 41)) {
- FROM_DEFAULT_V4_UCHAR(space_view3d.back);
- }
-
- if (!USER_VERSION_ATLEAST(280, 52)) {
- FROM_DEFAULT_V4_UCHAR(space_info.info_info);
- }
-
- if (!USER_VERSION_ATLEAST(280, 64)) {
- FROM_DEFAULT_V4_UCHAR(tui.icon_scene);
-
- if (btheme->space_view3d.obcenter_dia == 0) {
- btheme->space_view3d.obcenter_dia = U_theme_default.space_view3d.obcenter_dia;
- }
-
- FROM_DEFAULT_V4_UCHAR(space_graph.text);
- FROM_DEFAULT_V4_UCHAR(space_action.text);
- FROM_DEFAULT_V4_UCHAR(space_nla.text);
- FROM_DEFAULT_V4_UCHAR(space_sequencer.text);
- FROM_DEFAULT_V4_UCHAR(space_clip.text);
-
- FROM_DEFAULT_V4_UCHAR(space_graph.time_scrub_background);
- FROM_DEFAULT_V4_UCHAR(space_action.time_scrub_background);
- FROM_DEFAULT_V4_UCHAR(space_nla.time_scrub_background);
- FROM_DEFAULT_V4_UCHAR(space_sequencer.time_scrub_background);
- FROM_DEFAULT_V4_UCHAR(space_clip.time_scrub_background);
- }
-
- if (!USER_VERSION_ATLEAST(280, 67)) {
- FROM_DEFAULT_V4_UCHAR(space_outliner.selected_object);
- FROM_DEFAULT_V4_UCHAR(space_outliner.active_object);
- FROM_DEFAULT_V4_UCHAR(space_outliner.edited_object);
- FROM_DEFAULT_V4_UCHAR(space_outliner.row_alternate);
- }
-
- if (!USER_VERSION_ATLEAST(281, 3)) {
- FROM_DEFAULT_V4_UCHAR(space_outliner.selected_highlight);
- FROM_DEFAULT_V4_UCHAR(space_outliner.active);
- }
-
- if (!USER_VERSION_ATLEAST(281, 14)) {
- FROM_DEFAULT_V4_UCHAR(space_file.execution_buts);
- FROM_DEFAULT_V4_UCHAR(tui.icon_folder);
- FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_before);
- FROM_DEFAULT_V4_UCHAR(space_clip.path_keyframe_after);
- copy_v4_v4_uchar(btheme->space_nla.nla_track, btheme->space_nla.header);
- }
-
- if (!USER_VERSION_ATLEAST(282, 5)) {
- FROM_DEFAULT_V4_UCHAR(space_sequencer.anim_preview_range);
- FROM_DEFAULT_V4_UCHAR(space_text.line_numbers);
- FROM_DEFAULT_V4_UCHAR(tui.widget_text_cursor);
- FROM_DEFAULT_V4_UCHAR(space_view3d.face_back);
- FROM_DEFAULT_V4_UCHAR(space_view3d.face_front);
- }
-
- if (!USER_VERSION_ATLEAST(283, 1)) {
- FROM_DEFAULT_V4_UCHAR(space_view3d.bone_locked_weight);
- }
-
- if (!USER_VERSION_ATLEAST(283, 2)) {
- FROM_DEFAULT_V4_UCHAR(space_info.info_property);
- FROM_DEFAULT_V4_UCHAR(space_info.info_property_text);
- FROM_DEFAULT_V4_UCHAR(space_info.info_operator);
- FROM_DEFAULT_V4_UCHAR(space_info.info_operator_text);
- }
-
- if (!USER_VERSION_ATLEAST(283, 5)) {
- FROM_DEFAULT_V4_UCHAR(space_graph.time_marker_line);
- FROM_DEFAULT_V4_UCHAR(space_action.time_marker_line);
- FROM_DEFAULT_V4_UCHAR(space_nla.time_marker_line);
- FROM_DEFAULT_V4_UCHAR(space_sequencer.time_marker_line);
- FROM_DEFAULT_V4_UCHAR(space_clip.time_marker_line);
- FROM_DEFAULT_V4_UCHAR(space_graph.time_marker_line_selected);
- FROM_DEFAULT_V4_UCHAR(space_action.time_marker_line_selected);
- FROM_DEFAULT_V4_UCHAR(space_nla.time_marker_line_selected);
- FROM_DEFAULT_V4_UCHAR(space_sequencer.time_marker_line_selected);
- FROM_DEFAULT_V4_UCHAR(space_clip.time_marker_line_selected);
- }
-
- if (!USER_VERSION_ATLEAST(283, 6)) {
- btheme->space_node.grid_levels = U_theme_default.space_node.grid_levels;
- }
-
- if (!USER_VERSION_ATLEAST(283, 9)) {
- FROM_DEFAULT_V4_UCHAR(space_info.info_warning);
- }
-
- if (!USER_VERSION_ATLEAST(283, 10)) {
- FROM_DEFAULT_V4_UCHAR(tui.gizmo_view_align);
-
- FROM_DEFAULT_V4_UCHAR(space_sequencer.active_strip);
- FROM_DEFAULT_V4_UCHAR(space_sequencer.selected_strip);
- FROM_DEFAULT_V4_UCHAR(space_sequencer.color_strip);
- FROM_DEFAULT_V4_UCHAR(space_sequencer.mask);
- }
-
- if (!USER_VERSION_ATLEAST(283, 11)) {
- FROM_DEFAULT_V4_UCHAR(tui.transparent_checker_primary);
- FROM_DEFAULT_V4_UCHAR(tui.transparent_checker_secondary);
- btheme->tui.transparent_checker_size = U_theme_default.tui.transparent_checker_size;
- }
- if (!USER_VERSION_ATLEAST(291, 2)) {
- /* The new defaults for the file browser theme are the same as
- * the outliner's, and it's less disruptive to just copy them. */
- copy_v4_v4_uchar(btheme->space_file.back, btheme->space_outliner.back);
- copy_v4_v4_uchar(btheme->space_file.row_alternate, btheme->space_outliner.row_alternate);
-
- FROM_DEFAULT_V4_UCHAR(space_image.grid);
- }
-
- if (!USER_VERSION_ATLEAST(291, 3)) {
- for (int i = 0; i < COLLECTION_COLOR_TOT; ++i) {
- FROM_DEFAULT_V4_UCHAR(collection_color[i].color);
- }
-
- FROM_DEFAULT_V4_UCHAR(space_properties.match);
-
- /* New grid theme color defaults are the same as the existing background colors,
- * so they are copied to limit disruption. */
- copy_v3_v3_uchar(btheme->space_clip.grid, btheme->space_clip.back);
- btheme->space_clip.grid[3] = 255.0f;
-
- copy_v3_v3_uchar(btheme->space_node.grid, btheme->space_node.back);
- }
-
- if (!USER_VERSION_ATLEAST(291, 9)) {
- FROM_DEFAULT_V4_UCHAR(space_graph.vertex_active);
- }
-
- if (!USER_VERSION_ATLEAST(292, 5)) {
- for (int i = 0; i < COLLECTION_COLOR_TOT; ++i) {
- FROM_DEFAULT_V4_UCHAR(collection_color[i].color);
- }
- FROM_DEFAULT_V4_UCHAR(space_sequencer.row_alternate);
- FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_geometry);
- FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_attribute);
- }
-
- if (!USER_VERSION_ATLEAST(292, 12)) {
- FROM_DEFAULT_V4_UCHAR(space_node.nodeclass_shader);
- }
-
- if (!USER_VERSION_ATLEAST(293, 15)) {
- FROM_DEFAULT_V4_UCHAR(space_properties.active);
-
- FROM_DEFAULT_V4_UCHAR(space_info.info_error);
- FROM_DEFAULT_V4_UCHAR(space_info.info_warning);
- FROM_DEFAULT_V4_UCHAR(space_info.info_info);
- FROM_DEFAULT_V4_UCHAR(space_info.info_debug);
- FROM_DEFAULT_V4_UCHAR(space_info.info_debug_text);
- FROM_DEFAULT_V4_UCHAR(space_info.info_property);
- FROM_DEFAULT_V4_UCHAR(space_info.info_error);
- FROM_DEFAULT_V4_UCHAR(space_info.info_operator);
-
- btheme->space_spreadsheet = btheme->space_outliner;
- }
-
- if (!USER_VERSION_ATLEAST(300, 5)) {
- FROM_DEFAULT_V4_UCHAR(space_spreadsheet.active);
- FROM_DEFAULT_V4_UCHAR(space_spreadsheet.list);
- FROM_DEFAULT_V4_UCHAR(space_spreadsheet.list_text);
- FROM_DEFAULT_V4_UCHAR(space_spreadsheet.list_text_hi);
- FROM_DEFAULT_V4_UCHAR(space_spreadsheet.hilite);
- FROM_DEFAULT_V4_UCHAR(space_spreadsheet.selected_highlight);
- }
-
- if (!USER_VERSION_ATLEAST(300, 15)) {
- copy_v4_uchar(btheme->space_sequencer.grid, 33);
- btheme->space_sequencer.grid[3] = 255;
- }
-
- if (!USER_VERSION_ATLEAST(300, 30)) {
- FROM_DEFAULT_V4_UCHAR(space_node.wire);
- }
-
- if (!USER_VERSION_ATLEAST(300, 31)) {
- for (int i = 0; i < SEQUENCE_COLOR_TOT; ++i) {
- FROM_DEFAULT_V4_UCHAR(strip_color[i].color);
- }
- }
-
- 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));
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 65c42545a77..68171f26a66 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -977,7 +977,7 @@ static void write_libraries(WriteData *wd, Main *main)
if (main->curlib->packedfile) {
BKE_packedfile_blend_write(&writer, main->curlib->packedfile);
if (wd->use_memfile == false) {
- CLOG_INFO(&LOG, 2, "Write packed .blend: %s\n", main->curlib->filepath);
+ CLOG_INFO(&LOG, 2, "Write packed .blend: %s", main->curlib->filepath);
}
}
@@ -990,7 +990,7 @@ static void write_libraries(WriteData *wd, Main *main)
if (!BKE_idtype_idcode_is_linkable(GS(id->name))) {
CLOG_ERROR(&LOG,
"Data-block '%s' from lib '%s' is not linkable, but is flagged as "
- "directly linked\n",
+ "directly linked",
id->name,
main->curlib->filepath_abs);
}
@@ -1498,7 +1498,7 @@ void BLO_write_struct_array_by_name(BlendWriter *writer,
{
int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
if (UNLIKELY(struct_id == -1)) {
- CLOG_ERROR(&LOG, "Can't find SDNA code <%s>\n", struct_name);
+ CLOG_ERROR(&LOG, "Can't find SDNA code <%s>", struct_name);
return;
}
BLO_write_struct_array_by_id(writer, struct_id, array_size, data_ptr);
@@ -1546,7 +1546,7 @@ void BLO_write_struct_list_by_name(BlendWriter *writer, const char *struct_name,
{
int struct_id = BLO_get_struct_id_by_name(writer, struct_name);
if (UNLIKELY(struct_id == -1)) {
- CLOG_ERROR(&LOG, "Can't find SDNA code <%s>\n", struct_name);
+ CLOG_ERROR(&LOG, "Can't find SDNA code <%s>", struct_name);
return;
}
BLO_write_struct_list_by_id(writer, struct_id, list);
diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h
index ebb0f604df7..129eba3de2f 100644
--- a/source/blender/blentranslation/BLT_translation.h
+++ b/source/blender/blentranslation/BLT_translation.h
@@ -28,13 +28,6 @@ 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. */
#define N_(msgid) msgid
#define CTX_N_(context, msgid) msgid
diff --git a/source/blender/blentranslation/intern/blt_lang.c b/source/blender/blentranslation/intern/blt_lang.c
index b015057ad2d..cb04b3ac0dc 100644
--- a/source/blender/blentranslation/intern/blt_lang.c
+++ b/source/blender/blentranslation/intern/blt_lang.c
@@ -345,12 +345,3 @@ void BLT_lang_locale_explode(const char *locale,
MEM_freeN(_t);
}
}
-
-bool BLT_lang_is_ime_supported(void)
-{
-#ifdef WITH_INPUT_IME
- return true;
-#else
- return false;
-#endif
-}
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index ff8506f1868..a7637d2712c 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -60,8 +60,11 @@ void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr,
}
/* prototypes */
-static void bm_loop_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude);
+static void bm_loop_attrs_copy(BMesh *bm_src,
+ BMesh *bm_dst,
+ const BMLoop *l_src,
+ BMLoop *l_dst,
+ eCustomDataMask mask_exclude);
BMFace *BM_face_create_quad_tri(BMesh *bm,
BMVert *v1,
@@ -321,7 +324,7 @@ void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
/*************************************************************/
static void bm_vert_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMVert *v_src, BMVert *v_dst, CustomDataMask mask_exclude)
+ BMesh *bm_src, BMesh *bm_dst, const BMVert *v_src, BMVert *v_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (v_src == v_dst)) {
BLI_assert_msg(0, "BMVert: source and target match");
@@ -336,7 +339,7 @@ static void bm_vert_attrs_copy(
}
static void bm_edge_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMEdge *e_src, BMEdge *e_dst, CustomDataMask mask_exclude)
+ BMesh *bm_src, BMesh *bm_dst, const BMEdge *e_src, BMEdge *e_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (e_src == e_dst)) {
BLI_assert_msg(0, "BMEdge: source and target match");
@@ -348,7 +351,7 @@ static void bm_edge_attrs_copy(
}
static void bm_loop_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, CustomDataMask mask_exclude)
+ BMesh *bm_src, BMesh *bm_dst, const BMLoop *l_src, BMLoop *l_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (l_src == l_dst)) {
BLI_assert_msg(0, "BMLoop: source and target match");
@@ -360,7 +363,7 @@ static void bm_loop_attrs_copy(
}
static void bm_face_attrs_copy(
- BMesh *bm_src, BMesh *bm_dst, const BMFace *f_src, BMFace *f_dst, CustomDataMask mask_exclude)
+ BMesh *bm_src, BMesh *bm_dst, const BMFace *f_src, BMFace *f_dst, eCustomDataMask mask_exclude)
{
if ((bm_src == bm_dst) && (f_src == f_dst)) {
BLI_assert_msg(0, "BMFace: source and target match");
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index ee8c22df630..4391a6a92d7 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -460,7 +460,7 @@ void BM_mesh_edgeloops_calc_order(BMesh *UNUSED(bm), ListBase *eloops, const boo
for (el_store = eloops->first; el_store; el_store = el_store->next) {
float len_sq;
if (use_normals) {
- /* scale the length by how close the loops are to pointing at eachother */
+ /* Scale the length by how close the loops are to pointing at each other. */
float dir[3];
sub_v3_v3v3(dir, co, el_store->co);
len_sq = normalize_v3(dir);
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 2f5827bdc4c..0c3db31dd1f 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -894,6 +894,27 @@ void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
}
}
+bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name)
+{
+ CustomData olddata = *data;
+ olddata.layers = (olddata.layers) ? MEM_dupallocN(olddata.layers) : NULL;
+
+ /* the pool is now owned by olddata and must not be shared */
+ data->pool = NULL;
+
+ const bool has_layer = CustomData_free_layer_named(data, name, 0);
+
+ if (has_layer) {
+ update_data_blocks(bm, &olddata, data);
+ }
+
+ if (olddata.layers) {
+ MEM_freeN(olddata.layers);
+ }
+
+ return has_layer;
+}
+
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
{
CustomData olddata;
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index a2f1dfc706d..2cf9dffceec 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -59,6 +59,10 @@ void BM_data_interp_face_vert_edge(
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);
+/**
+ * Remove a named custom data layer, if it existed. Return true if the layer was removed.
+ */
+bool BM_data_layer_free_named(BMesh *bm, CustomData *data, const char *name);
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);
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index a81ae934629..64e6c63e9f0 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -34,42 +34,41 @@
struct BMLogEntry {
struct BMLogEntry *next, *prev;
- /* The following GHashes map from an element ID to one of the log
- * types above */
+ /* The following #GHash members map from an element ID to one of the log types above. */
- /* Elements that were in the previous entry, but have been
- * deleted */
+ /** Elements that were in the previous entry, but have been deleted. */
GHash *deleted_verts;
GHash *deleted_faces;
- /* Elements that were not in the previous entry, but are in the
- * result of this entry */
+ /** Elements that were not in the previous entry, but are in the result of this entry. */
GHash *added_verts;
GHash *added_faces;
- /* Vertices whose coordinates, mask value, or hflag have changed */
+ /** Vertices whose coordinates, mask value, or hflag have changed. */
GHash *modified_verts;
GHash *modified_faces;
BLI_mempool *pool_verts;
BLI_mempool *pool_faces;
- /* This is only needed for dropping BMLogEntries while still in
+ /**
+ * This is only needed for dropping BMLogEntries while still in
* dynamic-topology mode, as that should release vert/face IDs
- * back to the BMLog but no BMLog pointer is available at that
- * time.
+ * back to the BMLog but no BMLog pointer is available at that time.
*
* This field is not guaranteed to be valid, any use of it should
- * check for NULL. */
+ * check for NULL.
+ */
BMLog *log;
};
struct BMLog {
- /* Tree of free IDs */
+ /** Tree of free IDs */
struct RangeTreeUInt *unused_ids;
- /* Mapping from unique IDs to vertices and faces
+ /**
+ * Mapping from unique IDs to vertices and faces
*
- * Each vertex and face in the log gets a unique uinteger
+ * Each vertex and face in the log gets a unique `uint`
* assigned. That ID is taken from the set managed by the
* unused_ids range tree.
*
@@ -79,10 +78,11 @@ struct BMLog {
GHash *id_to_elem;
GHash *elem_to_id;
- /* All BMLogEntrys, ordered from earliest to most recent */
+ /** All #BMLogEntrys, ordered from earliest to most recent. */
ListBase entries;
- /* The current log entry from entries list
+ /**
+ * The current log entry from entries list
*
* If null, then the original mesh from before any of the log
* entries is current (i.e. there is nothing left to undo.)
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 189aa97509f..5daa5dd9a68 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -14,12 +14,13 @@ struct RangeTreeUInt;
typedef struct BMLog BMLog;
typedef struct BMLogEntry BMLogEntry;
-/* Allocate and initialize a new BMLog */
-/* Allocate, initialize, and assign 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
+/**
+ * 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.
@@ -29,20 +30,21 @@ BMLog *BM_log_create(BMesh *bm);
*/
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 */
+/**
+ * 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 */
+/**
+ * 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 */
+/** Apply a consistent ordering to BMesh vertices and faces. */
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
+/**
+ * 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.
@@ -54,35 +56,36 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log);
*/
BMLogEntry *BM_log_entry_add(BMLog *log);
-/* Mark all used ids as unused for this node */
+/** 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
+/**
+ * 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.
+ * 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
+/**
+ * Undo one #BMLogEntry.
*
- * Has no effect if there's nothing left to undo */
+ * Has no effect if there's nothing left to undo.
+ */
void BM_log_undo(BMesh *bm, BMLog *log);
-/* Redo one BMLogEntry */
-/* Redo one BMLogEntry
+/**
+ * Redo one #BMLogEntry.
*
- * Has no effect if there's nothing left to redo */
+ * 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 */
-/* Log a vertex before it is modified
+/**
+ * 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
@@ -107,8 +110,8 @@ void BM_log_redo(BMesh *bm, BMLog *log);
*/
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 */
-/* Log a new vertex as added to the BMesh
+/**
+ * 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
@@ -116,16 +119,16 @@ void BM_log_vert_before_modified(BMLog *log, struct BMVert *v, int cd_vert_mask_
*/
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
+/**
+ * Log a face before it is modified.
*
* This is intended to handle only header flags and we always
- * assume face has been added before
+ * 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
+/**
+ * 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
@@ -133,8 +136,8 @@ void BM_log_face_modified(BMLog *log, struct BMFace *f);
*/
void BM_log_face_added(BMLog *log, struct BMFace *f);
-/* Log a vertex as removed from the BMesh */
-/* Log a vertex as removed from the BMesh
+/**
+ * Log a vertex as removed from the #BMesh.
*
* A couple things can happen here:
*
@@ -142,7 +145,7 @@ void BM_log_face_added(BMLog *log, struct BMFace *f);
* 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
+ * 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.
@@ -152,8 +155,8 @@ void BM_log_face_added(BMLog *log, struct BMFace *f);
*/
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
+/**
+ * Log a face as removed from the #BMesh.
*
* A couple things can happen here:
*
@@ -161,43 +164,45 @@ void BM_log_vert_removed(BMLog *log, struct BMVert *v, int cd_vert_mask_offset);
* 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
+ * 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 */
+/**
+ * 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 */
+/** 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
+/**
+ * Get the logged coordinates of a vertex.
*
- * Does not modify the log or the 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
+/**
+ * Get the logged normal of a vertex
*
- * Does not modify the log or the 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
+/** Get the logged mask of a vertex
*
- * Does not modify the log or the 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) */
+/** 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 float **r_no);
-/* For internal use only (unit testing) */
-/* 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) */
+/** For internal use only (unit testing) */
struct RangeTreeUInt *BM_log_unused_ids(BMLog *log);
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index 40f1d7c496d..884f6b5388a 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -225,9 +225,6 @@ 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 (params->calc_vert_normal) {
vert_normals = BKE_mesh_vertex_normals_ensure(me);
@@ -934,7 +931,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 == nullptr which can crash T28625. */
+ * end up with 'me->totface' and `me->mface == nullptr` which can crash T28625. */
me->totface = 0;
me->act_face = -1;
diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c
index aa7f0f511ec..1339efb3057 100644
--- a/source/blender/bmesh/operators/bmo_join_triangles.c
+++ b/source/blender/bmesh/operators/bmo_join_triangles.c
@@ -145,7 +145,7 @@ static bool bm_edge_is_contiguous_loop_cd_all(const BMEdge *e,
}
static bool bm_edge_delimit_cdata(CustomData *ldata,
- CustomDataType type,
+ eCustomDataType type,
struct DelimitData_CD *r_delim_cd)
{
const int layer_len = CustomData_number_of_layers(ldata, type);
diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h
index e0164b9162d..eba61e07e1a 100644
--- a/source/blender/compositor/intern/COM_Converter.h
+++ b/source/blender/compositor/intern/COM_Converter.h
@@ -37,8 +37,8 @@ Node *COM_convert_bnode(bNode *b_node);
bool COM_bnode_is_fast_node(const bNode &b_node);
/**
- * \brief This function will add a datetype conversion rule when the to-socket does not support the
- * from-socket actual data type.
+ * \brief This function will add a date-type conversion rule when the to-socket does not support
+ * the from-socket actual data type.
*/
NodeOperation *COM_convert_data_type(const NodeOperationOutput &from,
const NodeOperationInput &to);
diff --git a/source/blender/compositor/intern/COM_NodeConverter.h b/source/blender/compositor/intern/COM_NodeConverter.h
index a90531bad0e..ceaf04f11a0 100644
--- a/source/blender/compositor/intern/COM_NodeConverter.h
+++ b/source/blender/compositor/intern/COM_NodeConverter.h
@@ -90,7 +90,7 @@ class NodeConverter {
/**
* When a node has no valid data
- * \note missing image / group pointer, or missing renderlayer from EXR
+ * \note missing image / group pointer, or missing render-layer from EXR.
*/
NodeOperation *set_invalid_output(NodeOutput *output);
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc
index e8b61ff229e..c0cc3fa1ba4 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cc
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cc
@@ -5,6 +5,7 @@
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_scene.h"
#include "RE_pipeline.h"
@@ -164,8 +165,8 @@ void CompositorOperation::execute_region(rcti *rect, unsigned int /*tile_number*
* Full frame
*/
- int full_width = rd->xsch * rd->size / 100;
- int full_height = rd->ysch * rd->size / 100;
+ int full_width, full_height;
+ BKE_render_resolution(rd, false, &full_width, &full_height);
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;
@@ -214,8 +215,8 @@ void CompositorOperation::update_memory_buffer_partial(MemoryBuffer *UNUSED(outp
void CompositorOperation::determine_canvas(const rcti &UNUSED(preferred_area), rcti &r_area)
{
- int width = rd_->xsch * rd_->size / 100;
- int height = rd_->ysch * rd_->size / 100;
+ int width, height;
+ BKE_render_resolution(rd_, false, &width, &height);
/* Check actual render resolution with cropping it may differ with cropped border.rendering
* Fix for T31777 Border Crop gives black (easy). */
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
index 341541b4cdd..760ed94f882 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
@@ -21,7 +21,7 @@ OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOpe
const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
- ImageFormatData *format,
+ const ImageFormatData *format,
const char *path,
const char *view_name,
const bool save_as_render)
@@ -243,7 +243,7 @@ OutputStereoOperation::OutputStereoOperation(const Scene *scene,
const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
- ImageFormatData *format,
+ const ImageFormatData *format,
const char *path,
const char *name,
const char *view_name,
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
index 69f4011d340..e36999e5cf1 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
@@ -22,7 +22,7 @@ class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOpera
const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
- ImageFormatData *format,
+ const ImageFormatData *format,
const char *path,
const char *view_name,
bool save_as_render);
@@ -57,7 +57,7 @@ class OutputStereoOperation : public OutputSingleLayerOperation {
const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
- struct ImageFormatData *format,
+ const struct ImageFormatData *format,
const char *path,
const char *name,
const char *view_name,
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index 49de275c256..1d22f3e8cd2 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
@@ -204,7 +204,7 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(const Scene *scene,
const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
- ImageFormatData *format,
+ const ImageFormatData *format,
const char *path,
const char *view_name,
const bool save_as_render)
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index 875defe00e9..df1d68838d9 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -35,7 +35,7 @@ class OutputSingleLayerOperation : public MultiThreadedOperation {
const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
- ImageFormatData *format,
+ const ImageFormatData *format,
const char *path,
const char *view_name,
bool save_as_render);
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
index 8bf8e339697..9c19f55e04f 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc
@@ -43,6 +43,11 @@ BLI_INLINE void warp_coord(float x, float y, float matrix[3][3], float uv[2], fl
uv[0] = vec[0] / vec[2];
uv[1] = vec[1] / vec[2];
+ /* Offset so that pixel center corresponds to a (0.5, 0.5), which helps keeping transformed
+ * image sharp. */
+ uv[0] += 0.5f;
+ uv[1] += 0.5f;
+
deriv[0][0] = (matrix[0][0] - matrix[0][2] * uv[0]) / vec[2];
deriv[1][0] = (matrix[0][1] - matrix[0][2] * uv[1]) / vec[2];
deriv[0][1] = (matrix[1][0] - matrix[1][2] * uv[0]) / vec[2];
@@ -66,9 +71,18 @@ void PlaneDistortWarpImageOperation::calculate_corners(const float corners[4][2]
const NodeOperation *image = get_input_operation(0);
const int width = image->get_width();
const int height = image->get_height();
+
+ MotionSample *sample_data = &samples_[sample];
+
+ /* If the image which is to be warped empty assume unit transform and don't attempt to calculate
+ * actual homography (otherwise homography solver will attempt to deal with singularity). */
+ if (width == 0 || height == 0) {
+ unit_m3(sample_data->perspective_matrix);
+ return;
+ }
+
float frame_corners[4][2] = {
{0.0f, 0.0f}, {(float)width, 0.0f}, {(float)width, (float)height}, {0.0f, (float)height}};
- MotionSample *sample_data = &samples_[sample];
BKE_tracking_homography_between_two_quads(
sample_data->frame_space_corners, frame_corners, sample_data->perspective_matrix);
}
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cc b/source/blender/compositor/operations/COM_RenderLayersProg.cc
index 522086658f8..40f2187b27b 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cc
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc
@@ -109,8 +109,8 @@ void RenderLayersProg::execute_pixel_sampled(float output[4],
/* 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;
+ int full_width, full_height;
+ BKE_render_resolution(rd, false, &full_width, &full_height);
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;
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cc b/source/blender/compositor/operations/COM_TextureOperation.cc
index 8b27c3aded4..c1c8db2ae3f 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cc
+++ b/source/blender/compositor/operations/COM_TextureOperation.cc
@@ -6,6 +6,7 @@
#include "BKE_image.h"
#include "BKE_node.h"
+#include "BKE_scene.h"
#include "NOD_texture.h"
@@ -59,8 +60,8 @@ void TextureBaseOperation::determine_canvas(const rcti &preferred_area, rcti &r_
{
r_area = preferred_area;
if (BLI_rcti_is_empty(&preferred_area)) {
- int width = rd_->xsch * rd_->size / 100;
- int height = rd_->ysch * rd_->size / 100;
+ int width, height;
+ BKE_render_resolution(rd_, false, &width, &height);
r_area.xmax = preferred_area.xmin + width;
r_area.ymax = preferred_area.ymin + height;
}
diff --git a/source/blender/compositor/operations/COM_TonemapOperation.h b/source/blender/compositor/operations/COM_TonemapOperation.h
index 84ee9c563fd..7868aa140dc 100644
--- a/source/blender/compositor/operations/COM_TonemapOperation.h
+++ b/source/blender/compositor/operations/COM_TonemapOperation.h
@@ -81,8 +81,8 @@ class TonemapOperation : public MultiThreadedOperation {
};
/**
- * \brief class of tonemap, implementing the photoreceptor tonemap
- * most parts have already been done in TonemapOperation
+ * \brief class of tone-map, implementing the photo-receptor tone-map
+ * most parts have already been done in #TonemapOperation.
* \ingroup operation
*/
diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cc b/source/blender/compositor/operations/COM_ViewerOperation.cc
index 58392b8a638..aeadf8f255d 100644
--- a/source/blender/compositor/operations/COM_ViewerOperation.cc
+++ b/source/blender/compositor/operations/COM_ViewerOperation.cc
@@ -104,8 +104,8 @@ void ViewerOperation::execute_region(rcti *rect, unsigned int /*tile_number*/)
void ViewerOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
{
- const int scene_render_width = rd_->xsch * rd_->size / 100;
- const int scene_render_height = rd_->ysch * rd_->size / 100;
+ int scene_render_width, scene_render_height;
+ BKE_render_resolution(rd_, false, &scene_render_width, &scene_render_height);
rcti local_preferred = preferred_area;
local_preferred.xmax = local_preferred.xmin + scene_render_width;
diff --git a/source/blender/datatoc/datatoc_icon.py b/source/blender/datatoc/datatoc_icon.py
index cce464dbc41..7373df71318 100755
--- a/source/blender/datatoc/datatoc_icon.py
+++ b/source/blender/datatoc/datatoc_icon.py
@@ -1,7 +1,5 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-
-# <pep8 compliant>
_IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little')
diff --git a/source/blender/datatoc/datatoc_icon_split.py b/source/blender/datatoc/datatoc_icon_split.py
index fcfd63f8707..8edafeda328 100755
--- a/source/blender/datatoc/datatoc_icon_split.py
+++ b/source/blender/datatoc/datatoc_icon_split.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
This script dices up PNG into small files to store in version control.
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc
index 8ee94ab0a34..1fec1fb3219 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder.cc
@@ -54,16 +54,16 @@ bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base)
return id_node->has_base;
}
-/*******************************************************************************
- * Base class for builders.
- */
+/* -------------------------------------------------------------------- */
+/** \name Base Class for Builders
+ * \{ */
DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache)
: bmain_(bmain), graph_(graph), cache_(cache)
{
}
-bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
+bool DepsgraphBuilder::need_pull_base_into_graph(const Base *base)
{
/* Simple check: enabled bases are always part of dependency graph. */
const int base_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT :
@@ -74,7 +74,7 @@ bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
/* More involved check: since we don't support dynamic changes in dependency graph topology and
* all visible objects are to be part of dependency graph, we pull all objects which has animated
* visibility. */
- Object *object = base->object;
+ const Object *object = base->object;
AnimatedPropertyID property_id;
if (graph_->mode == DAG_EVAL_VIEWPORT) {
property_id = AnimatedPropertyID(&object->id, &RNA_Object, "hide_viewport");
@@ -89,7 +89,7 @@ bool DepsgraphBuilder::need_pull_base_into_graph(Base *base)
return cache_->isPropertyAnimated(&object->id, property_id);
}
-bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel *pchan)
+bool DepsgraphBuilder::check_pchan_has_bbone(const Object *object, const bPoseChannel *pchan)
{
BLI_assert(object->type == OB_ARMATURE);
if (pchan == nullptr || pchan->bone == nullptr) {
@@ -109,20 +109,23 @@ bool DepsgraphBuilder::check_pchan_has_bbone(Object *object, const bPoseChannel
cache_->isPropertyAnimated(&armature->id, property_id);
}
-bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan)
+bool DepsgraphBuilder::check_pchan_has_bbone_segments(const Object *object,
+ const bPoseChannel *pchan)
{
return check_pchan_has_bbone(object, pchan);
}
-bool DepsgraphBuilder::check_pchan_has_bbone_segments(Object *object, const char *bone_name)
+bool DepsgraphBuilder::check_pchan_has_bbone_segments(const Object *object, const char *bone_name)
{
const bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name);
return check_pchan_has_bbone_segments(object, pchan);
}
-/*******************************************************************************
- * Builder finalizer.
- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Builder Finalizer.
+ * \{ */
namespace {
@@ -138,6 +141,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
comp_node->affects_directly_visible |= id_node->is_directly_visible;
}
}
+
for (OperationNode *op_node : graph->operations) {
op_node->custom_flags = 0;
op_node->num_links_pending = 0;
@@ -151,6 +155,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
op_node->custom_flags |= DEG_NODE_VISITED;
}
}
+
while (!BLI_stack_is_empty(stack)) {
OperationNode *op_node;
BLI_stack_pop(stack, &op_node);
@@ -198,7 +203,7 @@ void deg_graph_build_flush_visibility(Depsgraph *graph)
void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
{
- /* Make sure dependencies of visible ID datablocks are visible. */
+ /* Make sure dependencies of visible ID data-blocks are visible. */
deg_graph_build_flush_visibility(graph);
deg_graph_remove_unused_noops(graph);
@@ -233,4 +238,6 @@ void deg_graph_build_finalize(Main *bmain, Depsgraph *graph)
}
}
+/** \} */
+
} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h
index 8fbe255ed9d..950ebfb35ba 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder.h
@@ -13,8 +13,7 @@ struct Main;
struct Object;
struct bPoseChannel;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
class DepsgraphBuilderCache;
@@ -23,11 +22,11 @@ class DepsgraphBuilder {
public:
virtual ~DepsgraphBuilder() = default;
- virtual bool need_pull_base_into_graph(Base *base);
+ virtual bool need_pull_base_into_graph(const Base *base);
- virtual bool check_pchan_has_bbone(Object *object, const bPoseChannel *pchan);
- virtual bool check_pchan_has_bbone_segments(Object *object, const bPoseChannel *pchan);
- virtual bool check_pchan_has_bbone_segments(Object *object, const char *bone_name);
+ virtual bool check_pchan_has_bbone(const Object *object, const bPoseChannel *pchan);
+ virtual bool check_pchan_has_bbone_segments(const Object *object, const bPoseChannel *pchan);
+ virtual bool check_pchan_has_bbone_segments(const Object *object, const char *bone_name);
protected:
/* NOTE: The builder does NOT take ownership over any of those resources. */
@@ -43,5 +42,4 @@ bool deg_check_id_in_depsgraph(const Depsgraph *graph, ID *id_orig);
bool deg_check_base_in_depsgraph(const Depsgraph *graph, Base *base);
void deg_graph_build_finalize(Main *bmain, Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
index 7f88f54fdca..6474f853390 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.cc
@@ -35,13 +35,13 @@ AnimatedPropertyID::AnimatedPropertyID(const PointerRNA &pointer_rna,
{
}
-AnimatedPropertyID::AnimatedPropertyID(ID *id, StructRNA *type, const char *property_name)
+AnimatedPropertyID::AnimatedPropertyID(const ID *id, StructRNA *type, const char *property_name)
: data(id)
{
property_rna = RNA_struct_type_find_property(type, property_name);
}
-AnimatedPropertyID::AnimatedPropertyID(ID * /*id*/,
+AnimatedPropertyID::AnimatedPropertyID(const ID * /*id*/,
StructRNA *type,
void *data,
const char *property_name)
@@ -100,13 +100,13 @@ AnimatedPropertyStorage::AnimatedPropertyStorage() : is_fully_initialized(false)
{
}
-void AnimatedPropertyStorage::initializeFromID(DepsgraphBuilderCache *builder_cache, ID *id)
+void AnimatedPropertyStorage::initializeFromID(DepsgraphBuilderCache *builder_cache, const ID *id)
{
AnimatedPropertyCallbackData data;
- RNA_id_pointer_create(id, &data.pointer_rna);
+ RNA_id_pointer_create(const_cast<ID *>(id), &data.pointer_rna);
data.animated_property_storage = this;
data.builder_cache = builder_cache;
- BKE_fcurves_id_cb(id, animated_property_cb, &data);
+ BKE_fcurves_id_cb(const_cast<ID *>(id), animated_property_cb, &data);
}
void AnimatedPropertyStorage::tagPropertyAsAnimated(const AnimatedPropertyID &property_id)
@@ -147,13 +147,14 @@ DepsgraphBuilderCache::~DepsgraphBuilderCache()
}
}
-AnimatedPropertyStorage *DepsgraphBuilderCache::ensureAnimatedPropertyStorage(ID *id)
+AnimatedPropertyStorage *DepsgraphBuilderCache::ensureAnimatedPropertyStorage(const ID *id)
{
return animated_property_storage_map_.lookup_or_add_cb(
id, []() { return new AnimatedPropertyStorage(); });
}
-AnimatedPropertyStorage *DepsgraphBuilderCache::ensureInitializedAnimatedPropertyStorage(ID *id)
+AnimatedPropertyStorage *DepsgraphBuilderCache::ensureInitializedAnimatedPropertyStorage(
+ const ID *id)
{
AnimatedPropertyStorage *animated_property_storage = ensureAnimatedPropertyStorage(id);
if (!animated_property_storage->is_fully_initialized) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cache.h b/source/blender/depsgraph/intern/builder/deg_builder_cache.h
index 2d2bdeaf825..d85269c0f8b 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cache.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cache.h
@@ -17,8 +17,7 @@ struct ID;
struct PointerRNA;
struct PropertyRNA;
-namespace blender {
-namespace deg {
+namespace blender::deg {
class DepsgraphBuilderCache;
@@ -28,14 +27,14 @@ class AnimatedPropertyID {
AnimatedPropertyID();
AnimatedPropertyID(const PointerRNA *pointer_rna, const PropertyRNA *property_rna);
AnimatedPropertyID(const PointerRNA &pointer_rna, const PropertyRNA *property_rna);
- AnimatedPropertyID(ID *id, StructRNA *type, const char *property_name);
- AnimatedPropertyID(ID *id, StructRNA *type, void *data, const char *property_name);
+ AnimatedPropertyID(const ID *id, StructRNA *type, const char *property_name);
+ AnimatedPropertyID(const ID *id, StructRNA *type, void *data, const char *property_name);
uint64_t hash() const;
friend bool operator==(const AnimatedPropertyID &a, const AnimatedPropertyID &b);
/* Corresponds to PointerRNA.data. */
- void *data;
+ const void *data;
const PropertyRNA *property_rna;
MEM_CXX_CLASS_ALLOC_FUNCS("AnimatedPropertyID");
@@ -45,7 +44,7 @@ class AnimatedPropertyStorage {
public:
AnimatedPropertyStorage();
- void initializeFromID(DepsgraphBuilderCache *builder_cache, ID *id);
+ void initializeFromID(DepsgraphBuilderCache *builder_cache, const ID *id);
void tagPropertyAsAnimated(const AnimatedPropertyID &property_id);
void tagPropertyAsAnimated(const PointerRNA *pointer_rna, const PropertyRNA *property_rna);
@@ -59,7 +58,7 @@ class AnimatedPropertyStorage {
bool is_fully_initialized;
/* indexed by PointerRNA.data. */
- Set<void *> animated_objects_set;
+ Set<const void *> animated_objects_set;
Set<AnimatedPropertyID> animated_properties_set;
MEM_CXX_CLASS_ALLOC_FUNCS("AnimatedPropertyStorage");
@@ -71,8 +70,8 @@ class DepsgraphBuilderCache {
~DepsgraphBuilderCache();
/* Makes sure storage for animated properties exists and initialized for the given ID. */
- AnimatedPropertyStorage *ensureAnimatedPropertyStorage(ID *id);
- AnimatedPropertyStorage *ensureInitializedAnimatedPropertyStorage(ID *id);
+ AnimatedPropertyStorage *ensureAnimatedPropertyStorage(const ID *id);
+ AnimatedPropertyStorage *ensureInitializedAnimatedPropertyStorage(const ID *id);
/* Shortcuts to go through ensureInitializedAnimatedPropertyStorage and its
* isPropertyAnimated.
@@ -82,7 +81,7 @@ class DepsgraphBuilderCache {
*
* TODO(sergey): Technically, this makes this class something else than just a cache, but what is
* the better name? */
- template<typename... Args> bool isPropertyAnimated(ID *id, Args... args)
+ template<typename... Args> bool isPropertyAnimated(const ID *id, Args... args)
{
AnimatedPropertyStorage *animated_property_storage = ensureInitializedAnimatedPropertyStorage(
id);
@@ -96,10 +95,9 @@ class DepsgraphBuilderCache {
return animated_property_storage->isAnyPropertyAnimated(ptr);
}
- Map<ID *, AnimatedPropertyStorage *> animated_property_storage_map_;
+ Map<const ID *, AnimatedPropertyStorage *> animated_property_storage_map_;
MEM_CXX_CLASS_ALLOC_FUNCS("DepsgraphBuilderCache");
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
index d632c4e2f7e..8ba6c840a59 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc
@@ -42,9 +42,7 @@ struct StackEntry {
struct CyclesSolverState {
CyclesSolverState(Depsgraph *graph)
- : graph(graph),
- traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")),
- num_cycles(0)
+ : graph(graph), traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack"))
{
/* pass */
}
@@ -57,7 +55,7 @@ struct CyclesSolverState {
}
Depsgraph *graph;
BLI_Stack *traversal_stack;
- int num_cycles;
+ int num_cycles = 0;
};
inline void set_node_visited_state(Node *node, eCyclicCheckVisitedState state)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.h b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
index 8e94e0ae21f..83d25f8c23f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h
@@ -7,13 +7,11 @@
#pragma once
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
/* Detect and solve dependency cycles. */
void deg_graph_detect_cycles(Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.h b/source/blender/depsgraph/intern/builder/deg_builder_map.h
index 50ebadeb382..2b2b4d089e9 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_map.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_map.h
@@ -11,8 +11,7 @@
struct ID;
-namespace blender {
-namespace deg {
+namespace blender::deg {
class BuilderMap {
public:
@@ -60,5 +59,4 @@ class BuilderMap {
Map<ID *, int> id_tags_;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index c6fc3cd5d0b..473dda2290c 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -78,6 +78,7 @@
#include "BKE_modifier.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -173,15 +174,13 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
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);
+ OperationCode::COPY_ON_WRITE);
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);
+ nullptr, OperationCode::VISIBILITY);
/* 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;
@@ -1083,7 +1082,8 @@ void DepsgraphNodeBuilder::build_animation_images(ID *id)
bool has_image_animation = false;
if (ELEM(GS(id->name), ID_MA, ID_WO)) {
bNodeTree *ntree = *BKE_ntree_ptr_from_id(id);
- if (ntree != nullptr && ntree->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+ if (ntree != nullptr &&
+ ntree->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
has_image_animation = true;
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index be9983edf85..18e28311132 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -50,8 +50,7 @@ struct bNodeTree;
struct bPoseChannel;
struct bSound;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct ComponentNode;
struct Depsgraph;
@@ -306,5 +305,4 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
BuilderMap built_map_;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
index 2f98c8b419c..afb3a3c22bd 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h
@@ -9,8 +9,7 @@
#include "intern/depsgraph_type.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct RootPChanMap {
/** Debug contents of map. */
@@ -30,5 +29,4 @@ struct RootPChanMap {
Map<StringRefNull, Set<StringRefNull>> map_;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 0d4f9103149..4fe8a626af5 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -71,6 +71,7 @@
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
@@ -691,7 +692,7 @@ void DepsgraphRelationBuilder::build_object(Object *object)
const BuilderStack::ScopedEntry stack_entry = stack_.trace(object->id);
- /* Object Transforms */
+ /* Object Transforms. */
OperationCode base_op = (object->parent) ? OperationCode::TRANSFORM_PARENT :
OperationCode::TRANSFORM_LOCAL;
OperationKey base_op_key(&object->id, NodeType::TRANSFORM, base_op);
@@ -704,9 +705,12 @@ void DepsgraphRelationBuilder::build_object(Object *object)
OperationKey final_transform_key(
&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL);
OperationKey ob_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL);
+
add_relation(init_transform_key, local_transform_key, "Transform Init");
+
/* Various flags, flushing from bases/collections. */
build_object_layer_component_relations(object);
+
/* Parenting. */
if (object->parent != nullptr) {
/* Make sure parent object's relations are built. */
@@ -716,30 +720,35 @@ void DepsgraphRelationBuilder::build_object(Object *object)
/* Local -> parent. */
add_relation(local_transform_key, parent_transform_key, "ObLocal -> ObParent");
}
+
/* Modifiers. */
if (object->modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
BKE_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
+
/* Grease Pencil Modifiers. */
if (object->greasepencil_modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
BKE_gpencil_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
+
/* Shader FX. */
if (object->shader_fx.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
BKE_shaderfx_foreach_ID_link(object, modifier_walk, &data);
}
+
/* Constraints. */
if (object->constraints.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
BKE_constraints_id_loop(&object->constraints, constraint_walk, &data);
}
+
/* Object constraints. */
OperationKey object_transform_simulation_init_key(
&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT);
@@ -766,30 +775,39 @@ void DepsgraphRelationBuilder::build_object(Object *object)
final_transform_key,
"Simulation -> Final Transform");
}
+
build_idproperties(object->id.properties);
+
/* Animation data */
build_animdata(&object->id);
+
/* Object data. */
build_object_data(object);
+
/* Particle systems. */
if (object->particlesystem.first != nullptr) {
build_particle_systems(object);
}
+
/* Force field Texture. */
if ((object->pd != nullptr) && (object->pd->forcefield == PFIELD_TEXTURE) &&
(object->pd->tex != nullptr)) {
build_texture(object->pd->tex);
}
+
/* Object dupligroup. */
if (object->instance_collection != nullptr) {
build_collection(nullptr, object, object->instance_collection);
}
+
/* Point caches. */
build_object_pointcache(object);
+
/* Synchronization back to original object. */
OperationKey synchronize_key(
&object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL);
add_relation(final_transform_key, synchronize_key, "Synchronize to Original");
+
/* Parameters. */
build_parameters(&object->id);
}
@@ -1136,6 +1154,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
/* Add dependencies for each constraint in turn. */
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+ ListBase targets = {nullptr, nullptr};
/* Invalid constraint type. */
if (cti == nullptr) {
continue;
@@ -1187,9 +1206,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(cache_key, constraint_op_key, cti->name);
}
}
- else if (cti->get_constraint_targets) {
- ListBase targets = {nullptr, nullptr};
- cti->get_constraint_targets(con, &targets);
+ else if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == nullptr) {
continue;
@@ -1299,9 +1316,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(target_transform_key, constraint_op_key, cti->name);
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, true);
- }
+ BKE_constraint_targets_flush(con, &targets, true);
}
}
}
@@ -1459,7 +1474,8 @@ void DepsgraphRelationBuilder::build_animation_images(ID *id)
bool has_image_animation = false;
if (ELEM(GS(id->name), ID_MA, ID_WO)) {
bNodeTree *ntree = *BKE_ntree_ptr_from_id(id);
- if (ntree != nullptr && ntree->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
+ if (ntree != nullptr &&
+ ntree->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) {
has_image_animation = true;
}
}
@@ -1712,6 +1728,37 @@ void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
}
add_relation(variable_exit_key, driver_key, "RNA Target -> Driver");
+ /* It is possible that RNA path points to a property of a different ID than the target_id:
+ * for example, paths like "data" on Object, "camera" on Scene.
+ *
+ * For the demonstration purposes lets consider a driver variable uses Scene ID as target
+ * and "camera.location.x" as its RNA path. If the scene has 2 different cameras at
+ * 2 different locations changing the active scene camera is expected to immediately be
+ * reflected in the variable value. In order to achieve this behavior we create a relation
+ * from the target ID to the driver so that if the ID property of the target ID changes the
+ * driver is re-evaluated.
+ *
+ * The most straightforward (at the moment of writing this comment) way of figuring out
+ * such relation is to use copy-on-write operation of the target ID. There are two down
+ * sides of this approach which are considered a design limitation as there is a belief
+ * that they are not common in practice or are not reliable due to other issues:
+ *
+ * - IDs which are not covered with the copy-on-write mechanism.
+ *
+ * Such IDs are either do not have ID properties, or are not part of the dependency
+ * graph.
+ *
+ * - Modifications of evaluated IDs from a Python handler.
+ * Such modifications are not fully integrated in the dependency graph evaluation as it
+ * has issues with copy-on-write tagging and the fact that relations are defined by the
+ * original main database status. */
+ if (target_id != variable_exit_key.ptr.owner_id) {
+ if (deg_copy_on_write_is_needed(GS(target_id->name))) {
+ ComponentKey target_id_key(target_id, NodeType::COPY_ON_WRITE);
+ add_relation(target_id_key, driver_key, "Target ID -> Driver");
+ }
+ }
+
/* The RNA getter for `object.data` can write to the mesh datablock due
* to the call to `BKE_mesh_wrapper_ensure_subdivision()`. This relation
* ensures it is safe to call when the driver is evaluated.
@@ -2159,9 +2206,9 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx);
}
- if (BKE_object_modifier_use_time(scene_, object, md)) {
+ if (BKE_modifier_depends_ontime(scene_, md)) {
TimeSourceKey time_src_key;
- add_relation(time_src_key, obdata_ubereval_key, "Time Source");
+ add_relation(time_src_key, obdata_ubereval_key, "Time Source -> Modifier");
}
}
}
@@ -2178,7 +2225,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
mti->updateDepsgraph(md, &ctx, graph_->mode);
}
- if (BKE_object_modifier_gpencil_use_time(object, md)) {
+ if (BKE_gpencil_modifier_depends_ontime(md)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, obdata_ubereval_key, "Time Source");
}
@@ -2196,7 +2243,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object)
ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle);
fxi->updateDepsgraph(fx, &ctx);
}
- if (BKE_object_shaderfx_use_time(object, fx)) {
+ if (BKE_shaderfx_depends_ontime(fx)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, obdata_ubereval_key, "Time Source");
}
@@ -2429,6 +2476,13 @@ void DepsgraphRelationBuilder::build_camera(Camera *camera)
ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS);
ComponentKey dof_ob_key(&camera->dof.focus_object->id, NodeType::TRANSFORM);
add_relation(dof_ob_key, camera_parameters_key, "Camera DOF");
+ if (camera->dof.focus_subtarget[0]) {
+ OperationKey target_key(&camera->dof.focus_object->id,
+ NodeType::BONE,
+ camera->dof.focus_subtarget,
+ OperationCode::BONE_DONE);
+ add_relation(target_key, camera_parameters_key, "Camera DOF subtarget");
+ }
}
}
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 64bdd2334d8..0cb0b60dfb0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -70,8 +70,7 @@ struct bSound;
struct PropertyRNA;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct ComponentNode;
struct DepsNodeHandle;
@@ -381,7 +380,6 @@ struct DepsNodeHandle {
const char *default_name;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
#include "intern/builder/deg_builder_relations_impl.h"
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 e517dd6a927..9860b17fd56 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_drivers.h
@@ -15,8 +15,7 @@
struct FCurve;
-namespace blender {
-namespace deg {
+namespace blender::deg {
/* Helper class for determining which relations are needed between driver evaluation nodes. */
class DriverDescriptor {
@@ -59,5 +58,4 @@ class DriverDescriptor {
bool resolve_rna();
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
index aba4a011e72..76066ce97a7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -15,8 +15,7 @@
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
template<typename KeyType>
OperationNode *DepsgraphRelationBuilder::find_operation_node(const KeyType &key)
@@ -209,5 +208,4 @@ bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency(const KeyFrom &k
return true;
}
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h
index 922d2d7dc05..ad10eb7cd10 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_remove_noop.h
@@ -7,13 +7,11 @@
#pragma once
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
/* Remove all no-op nodes that have zero outgoing relations. */
void deg_graph_remove_unused_noops(Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 8a81adf0aeb..5202ada5408 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -39,7 +39,7 @@ namespace blender::deg {
class RNANodeQueryIDData {
public:
- explicit RNANodeQueryIDData(const ID *id) : id_(id), constraint_to_pchan_map_(nullptr)
+ explicit RNANodeQueryIDData(const ID *id) : id_(id)
{
}
@@ -77,7 +77,7 @@ class RNANodeQueryIDData {
/* indexed by bConstraint*, returns pose channel which contains that
* constraint. */
- Map<const bConstraint *, const bPoseChannel *> *constraint_to_pchan_map_;
+ Map<const bConstraint *, const bPoseChannel *> *constraint_to_pchan_map_ = nullptr;
};
/* ***************************** Node Identifier **************************** */
@@ -271,7 +271,8 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
RNA_struct_is_a(ptr->type, &RNA_LatticePoint) ||
RNA_struct_is_a(ptr->type, &RNA_MeshUVLoop) ||
RNA_struct_is_a(ptr->type, &RNA_MeshLoopColor) ||
- RNA_struct_is_a(ptr->type, &RNA_VertexGroupElement)) {
+ RNA_struct_is_a(ptr->type, &RNA_VertexGroupElement) ||
+ RNA_struct_is_a(ptr->type, &RNA_ShaderFx)) {
/* When modifier is used as FROM operation this is likely referencing to
* the property (for example, modifier's influence).
* But when it's used as TO operation, this is geometry component. */
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
index 4f482d4352d..9baa956bd80 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h
@@ -14,8 +14,7 @@ struct ID;
struct PointerRNA;
struct PropertyRNA;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
struct Node;
@@ -94,5 +93,4 @@ class RNANodeQuery {
bool rna_prop_affects_parameters_node(const PointerRNA *ptr, const PropertyRNA *prop);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.h b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
index 8b208610203..63016431eec 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.h
@@ -7,13 +7,11 @@
#pragma once
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
/* Performs a transitive reduction to remove redundant relations. */
void deg_graph_transitive_reduction(Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/pipeline.cc b/source/blender/depsgraph/intern/builder/pipeline.cc
index 540b8e173f1..815a06d03d1 100644
--- a/source/blender/depsgraph/intern/builder/pipeline.cc
+++ b/source/blender/depsgraph/intern/builder/pipeline.cc
@@ -90,7 +90,7 @@ void AbstractBuilderPipeline::build_step_finalize()
}
#endif
/* Relations are up to date. */
- deg_graph_->need_update = false;
+ deg_graph_->need_update_relations = false;
}
unique_ptr<DepsgraphNodeBuilder> AbstractBuilderPipeline::construct_node_builder()
diff --git a/source/blender/depsgraph/intern/builder/pipeline.h b/source/blender/depsgraph/intern/builder/pipeline.h
index b106e73b97c..7568aa78106 100644
--- a/source/blender/depsgraph/intern/builder/pipeline.h
+++ b/source/blender/depsgraph/intern/builder/pipeline.h
@@ -16,8 +16,7 @@ struct Main;
struct Scene;
struct ViewLayer;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
class DepsgraphNodeBuilder;
@@ -57,5 +56,4 @@ class AbstractBuilderPipeline {
virtual void build_relations(DepsgraphRelationBuilder &relation_builder) = 0;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/pipeline_all_objects.cc b/source/blender/depsgraph/intern/builder/pipeline_all_objects.cc
index 74d151c65d7..6bc3b59a9d6 100644
--- a/source/blender/depsgraph/intern/builder/pipeline_all_objects.cc
+++ b/source/blender/depsgraph/intern/builder/pipeline_all_objects.cc
@@ -20,7 +20,7 @@ class AllObjectsNodeBuilder : public DepsgraphNodeBuilder {
{
}
- bool need_pull_base_into_graph(Base * /*base*/) override
+ bool need_pull_base_into_graph(const Base * /*base*/) override
{
return true;
}
@@ -33,7 +33,7 @@ class AllObjectsRelationBuilder : public DepsgraphRelationBuilder {
{
}
- bool need_pull_base_into_graph(Base * /*base*/) override
+ bool need_pull_base_into_graph(const Base * /*base*/) override
{
return true;
}
diff --git a/source/blender/depsgraph/intern/builder/pipeline_all_objects.h b/source/blender/depsgraph/intern/builder/pipeline_all_objects.h
index 75d9605dec7..fde5e7e2163 100644
--- a/source/blender/depsgraph/intern/builder/pipeline_all_objects.h
+++ b/source/blender/depsgraph/intern/builder/pipeline_all_objects.h
@@ -9,8 +9,7 @@
#include "pipeline_view_layer.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
/* Builds a dependency graph that contains all objects in the view layer.
* This is contrary to the regular ViewLayerBuilderPipeline, which is limited to visible objects
@@ -24,5 +23,4 @@ class AllObjectsBuilderPipeline : public ViewLayerBuilderPipeline {
virtual unique_ptr<DepsgraphRelationBuilder> construct_relation_builder() override;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/pipeline_compositor.h b/source/blender/depsgraph/intern/builder/pipeline_compositor.h
index 3325741c94a..304f2d4ec9a 100644
--- a/source/blender/depsgraph/intern/builder/pipeline_compositor.h
+++ b/source/blender/depsgraph/intern/builder/pipeline_compositor.h
@@ -11,8 +11,7 @@
struct bNodeTree;
-namespace blender {
-namespace deg {
+namespace blender::deg {
class CompositorBuilderPipeline : public AbstractBuilderPipeline {
public:
@@ -26,5 +25,4 @@ class CompositorBuilderPipeline : public AbstractBuilderPipeline {
bNodeTree *nodetree_;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc b/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc
index ee10b28a306..e256c8271f2 100644
--- a/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc
+++ b/source/blender/depsgraph/intern/builder/pipeline_from_ids.cc
@@ -39,7 +39,7 @@ class DepsgraphFromIDsNodeBuilder : public DepsgraphNodeBuilder {
{
}
- bool need_pull_base_into_graph(Base *base) override
+ bool need_pull_base_into_graph(const Base *base) override
{
if (!filter_.contains(&base->object->id)) {
return false;
@@ -61,7 +61,7 @@ class DepsgraphFromIDsRelationBuilder : public DepsgraphRelationBuilder {
{
}
- bool need_pull_base_into_graph(Base *base) override
+ bool need_pull_base_into_graph(const Base *base) override
{
if (!filter_.contains(&base->object->id)) {
return false;
diff --git a/source/blender/depsgraph/intern/builder/pipeline_from_ids.h b/source/blender/depsgraph/intern/builder/pipeline_from_ids.h
index a2c75c048cb..c277d44aaad 100644
--- a/source/blender/depsgraph/intern/builder/pipeline_from_ids.h
+++ b/source/blender/depsgraph/intern/builder/pipeline_from_ids.h
@@ -9,8 +9,7 @@
#include "pipeline.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
/* Optimized builders for dependency graph built from a given set of IDs.
*
@@ -37,5 +36,4 @@ class FromIDsBuilderPipeline : public AbstractBuilderPipeline {
Span<ID *> ids_;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/pipeline_render.h b/source/blender/depsgraph/intern/builder/pipeline_render.h
index cb704f84c59..7eb65168ea6 100644
--- a/source/blender/depsgraph/intern/builder/pipeline_render.h
+++ b/source/blender/depsgraph/intern/builder/pipeline_render.h
@@ -9,8 +9,7 @@
#include "pipeline.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
class RenderBuilderPipeline : public AbstractBuilderPipeline {
public:
@@ -21,5 +20,4 @@ class RenderBuilderPipeline : public AbstractBuilderPipeline {
virtual void build_relations(DepsgraphRelationBuilder &relation_builder) override;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/builder/pipeline_view_layer.h b/source/blender/depsgraph/intern/builder/pipeline_view_layer.h
index 18b9ce5d5ff..ffd6fa07776 100644
--- a/source/blender/depsgraph/intern/builder/pipeline_view_layer.h
+++ b/source/blender/depsgraph/intern/builder/pipeline_view_layer.h
@@ -9,8 +9,7 @@
#include "pipeline.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
class ViewLayerBuilderPipeline : public AbstractBuilderPipeline {
public:
@@ -21,5 +20,4 @@ class ViewLayerBuilderPipeline : public AbstractBuilderPipeline {
virtual void build_relations(DepsgraphRelationBuilder &relation_builder) override;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/debug/deg_debug.h b/source/blender/depsgraph/intern/debug/deg_debug.h
index ee6c5b046b7..8f18bd70d36 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug.h
+++ b/source/blender/depsgraph/intern/debug/deg_debug.h
@@ -14,8 +14,7 @@
#include "DEG_depsgraph_debug.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
class DepsgraphDebug {
public:
@@ -74,5 +73,4 @@ bool terminal_do_color(void);
string color_for_pointer(const void *pointer);
string color_end(void);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/debug/deg_time_average.h b/source/blender/depsgraph/intern/debug/deg_time_average.h
index cc47f03b221..d4eb05a9ddb 100644
--- a/source/blender/depsgraph/intern/debug/deg_time_average.h
+++ b/source/blender/depsgraph/intern/debug/deg_time_average.h
@@ -7,8 +7,7 @@
#pragma once
-namespace blender {
-namespace deg {
+namespace blender::deg {
/* Utility class which takes care of calculating average of time series, such as FPS counters. */
template<int MaxSamples> class AveragedTimeSampler {
@@ -52,5 +51,4 @@ template<int MaxSamples> class AveragedTimeSampler {
int next_sample_index_;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index 4514084059a..d460a68747d 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -45,9 +45,9 @@ namespace blender::deg {
Depsgraph::Depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, eEvaluationMode mode)
: time_source(nullptr),
- need_update(true),
- need_visibility_update(true),
- need_visibility_time_update(false),
+ need_update_relations(true),
+ need_tag_id_on_graph_visibility_update(true),
+ need_tag_id_on_graph_visibility_time_update(false),
bmain(bmain),
scene(scene),
view_layer(view_layer),
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index ca4ce058904..33d97e4b8b2 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -31,8 +31,7 @@ struct ID;
struct Scene;
struct ViewLayer;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct IDNode;
struct Node;
@@ -90,12 +89,12 @@ struct Depsgraph {
TimeSourceNode *time_source;
/* Indicates whether relations needs to be updated. */
- bool need_update;
+ bool need_update_relations;
/* Indicated whether IDs in this graph are to be tagged as if they first appear visible, with
* an optional tag for their animation (time) update. */
- bool need_visibility_update;
- bool need_visibility_time_update;
+ bool need_tag_id_on_graph_visibility_update;
+ bool need_tag_id_on_graph_visibility_time_update;
/* Indicates which ID types were updated. */
char id_type_updated[INDEX_ID_MAX];
@@ -162,5 +161,4 @@ struct Depsgraph {
MEM_CXX_CLASS_ALLOC_FUNCS("Depsgraph");
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index c64b7bc1eb7..a207c13d646 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -270,7 +270,7 @@ void DEG_graph_tag_relations_update(Depsgraph *graph)
{
DEG_DEBUG_PRINTF(graph, TAG, "%s: Tagging relations for update.\n", __func__);
deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(graph);
- deg_graph->need_update = true;
+ deg_graph->need_update_relations = true;
/* NOTE: When relations are updated, it's quite possible that
* we've got new bases in the scene. This means, we need to
* re-create flat array of bases in view layer.
@@ -286,7 +286,7 @@ void DEG_graph_tag_relations_update(Depsgraph *graph)
void DEG_graph_relations_update(Depsgraph *graph)
{
deg::Depsgraph *deg_graph = (deg::Depsgraph *)graph;
- if (!deg_graph->need_update) {
+ if (!deg_graph->need_update_relations) {
/* Graph is up to date, nothing to do. */
return;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_physics.h b/source/blender/depsgraph/intern/depsgraph_physics.h
index a8d37f76b09..2105eb62ce1 100644
--- a/source/blender/depsgraph/intern/depsgraph_physics.h
+++ b/source/blender/depsgraph/intern/depsgraph_physics.h
@@ -10,8 +10,7 @@
struct Collection;
struct ListBase;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -21,5 +20,4 @@ ListBase *build_collision_relations(Depsgraph *graph,
unsigned int modifier_type);
void clear_physics_relations(Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
index 6ffc711a475..9a047c70d01 100644
--- a/source/blender/depsgraph/intern/depsgraph_query.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -328,7 +328,7 @@ bool DEG_is_fully_evaluated(const struct Depsgraph *depsgraph)
{
const deg::Depsgraph *deg_graph = (const deg::Depsgraph *)depsgraph;
/* Check whether relations are up to date. */
- if (deg_graph->need_update) {
+ if (deg_graph->need_update_relations) {
return false;
}
/* Check whether IDs are up to date. */
diff --git a/source/blender/depsgraph/intern/depsgraph_registry.h b/source/blender/depsgraph/intern/depsgraph_registry.h
index 2746f17590a..4ab63dcc77d 100644
--- a/source/blender/depsgraph/intern/depsgraph_registry.h
+++ b/source/blender/depsgraph/intern/depsgraph_registry.h
@@ -11,8 +11,7 @@
struct Main;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -20,5 +19,4 @@ void register_graph(Depsgraph *depsgraph);
void unregister_graph(Depsgraph *depsgraph);
Span<Depsgraph *> get_all_registered_graphs(Main *bmain);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph_relation.h b/source/blender/depsgraph/intern/depsgraph_relation.h
index 4d51ad85878..1bacb9abfa6 100644
--- a/source/blender/depsgraph/intern/depsgraph_relation.h
+++ b/source/blender/depsgraph/intern/depsgraph_relation.h
@@ -9,8 +9,7 @@
#include "MEM_guardedalloc.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Node;
@@ -49,5 +48,4 @@ struct Relation {
MEM_CXX_CLASS_ALLOC_FUNCS("Relation");
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index b50081458ad..9cd5980d8fe 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -494,19 +494,19 @@ void deg_graph_node_tag_zero(Main *bmain,
void graph_tag_on_visible_update(Depsgraph *graph, const bool do_time)
{
- graph->need_visibility_update = true;
- graph->need_visibility_time_update |= do_time;
+ graph->need_tag_id_on_graph_visibility_update = true;
+ graph->need_tag_id_on_graph_visibility_time_update |= do_time;
}
} /* namespace */
void graph_tag_ids_for_visible_update(Depsgraph *graph)
{
- if (!graph->need_visibility_update) {
+ if (!graph->need_tag_id_on_graph_visibility_update) {
return;
}
- const bool do_time = graph->need_visibility_time_update;
+ const bool do_time = graph->need_tag_id_on_graph_visibility_time_update;
Main *bmain = graph->bmain;
/* NOTE: It is possible to have this function called with `do_time=false` first and later (prior
@@ -561,8 +561,8 @@ void graph_tag_ids_for_visible_update(Depsgraph *graph)
id_node->previously_visible_components_mask = id_node->visible_components_mask;
}
- graph->need_visibility_update = false;
- graph->need_visibility_time_update = false;
+ graph->need_tag_id_on_graph_visibility_update = false;
+ graph->need_tag_id_on_graph_visibility_time_update = false;
}
NodeType geometry_tag_to_component(const ID *id)
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.h b/source/blender/depsgraph/intern/depsgraph_tag.h
index a0518420bfb..b722aab5719 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.h
+++ b/source/blender/depsgraph/intern/depsgraph_tag.h
@@ -10,8 +10,7 @@
struct ID;
struct Main;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -29,5 +28,4 @@ void graph_id_tag_update(
* Will do nothing if the graph is not tagged for visibility update. */
void graph_tag_ids_for_visible_update(Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph_type.h b/source/blender/depsgraph/intern/depsgraph_type.h
index 9cf14a831bc..9e21d124f83 100644
--- a/source/blender/depsgraph/intern/depsgraph_type.h
+++ b/source/blender/depsgraph/intern/depsgraph_type.h
@@ -34,8 +34,7 @@ struct Depsgraph;
struct CustomData_MeshMasks;
-namespace blender {
-namespace deg {
+namespace blender::deg {
/* Commonly used types. */
using std::deque;
@@ -153,5 +152,4 @@ struct DEGCustomDataMeshMasks {
}
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/depsgraph_update.h b/source/blender/depsgraph/intern/depsgraph_update.h
index 18f8e6acab6..c5a72157bd2 100644
--- a/source/blender/depsgraph/intern/depsgraph_update.h
+++ b/source/blender/depsgraph/intern/depsgraph_update.h
@@ -10,12 +10,10 @@
struct DEGEditorUpdateContext;
struct ID;
-namespace blender {
-namespace deg {
+namespace blender::deg {
void deg_editors_id_update(const DEGEditorUpdateContext *update_ctx, struct ID *id);
void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, bool updated);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index 2d9d40aede6..9ac1f5275ac 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -302,8 +302,28 @@ void schedule_node_to_queue(OperationNode *node,
BLI_gsqueue_push(evaluation_queue, &node);
}
-void evaluate_graph_single_threaded(DepsgraphEvalState *state)
+/* Evaluate given stage of the dependency graph evaluation using multiple threads.
+ *
+ * NOTE: Will assign the `state->stage` to the given stage. */
+void evaluate_graph_threaded_stage(DepsgraphEvalState *state,
+ TaskPool *task_pool,
+ const EvaluationStage stage)
{
+ state->stage = stage;
+
+ schedule_graph(state, schedule_node_to_pool, task_pool);
+ BLI_task_pool_work_and_wait(task_pool);
+}
+
+/* Evaluate remaining operations of the dependency graph in a single threaded manner. */
+void evaluate_graph_single_threaded_if_needed(DepsgraphEvalState *state)
+{
+ if (!state->need_single_thread_pass) {
+ return;
+ }
+
+ state->stage = EvaluationStage::SINGLE_THREADED_WORKAROUND;
+
GSQueue *evaluation_queue = BLI_gsqueue_new(sizeof(OperationNode *));
schedule_graph(state, schedule_node_to_queue, evaluation_queue);
@@ -334,9 +354,7 @@ void depsgraph_ensure_view_layer(Depsgraph *graph)
deg_update_copy_on_write_datablock(graph, scene_id_node);
}
-} // namespace
-
-static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
+TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
{
if (G.debug & G_DEBUG_DEPSGRAPH_NO_THREADS) {
return BLI_task_pool_create_no_threads(state);
@@ -345,6 +363,8 @@ static TaskPool *deg_evaluate_task_pool_create(DepsgraphEvalState *state)
return BLI_task_pool_create_suspended(state, TASK_PRIORITY_HIGH);
}
+} // namespace
+
void deg_evaluate_on_refresh(Depsgraph *graph)
{
/* Nothing to update, early out. */
@@ -361,33 +381,37 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
graph->is_evaluating = true;
depsgraph_ensure_view_layer(graph);
+
/* Set up evaluation state. */
DepsgraphEvalState state;
state.graph = graph;
state.do_stats = graph->debug.do_time_debug();
state.need_single_thread_pass = false;
+
/* Prepare all nodes for evaluation. */
initialize_execution(&state, graph);
- /* Do actual evaluation now. */
- /* First, process all Copy-On-Write nodes. */
- state.stage = EvaluationStage::COPY_ON_WRITE;
+ /* Evaluation happens in several incremental steps:
+ *
+ * - Start with the copy-on-write operations which never form dependency cycles. This will ensure
+ * that if a dependency graph has a cycle evaluation functions will always "see" valid expanded
+ * datablock. It might not be evaluated yet, but at least the datablock will be valid.
+ *
+ * - Multi-threaded evaluation of all possible nodes.
+ * Certain operations (and their subtrees) could be ignored. For example, meta-balls are not
+ * safe from threading point of view, so the threaded evaluation will stop at the metaball
+ * operation node.
+ *
+ * - Single-threaded pass of all remaining operations. */
+
TaskPool *task_pool = deg_evaluate_task_pool_create(&state);
- schedule_graph(&state, schedule_node_to_pool, task_pool);
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
- /* After that, process all other nodes. */
- state.stage = EvaluationStage::THREADED_EVALUATION;
- task_pool = deg_evaluate_task_pool_create(&state);
- schedule_graph(&state, schedule_node_to_pool, task_pool);
- BLI_task_pool_work_and_wait(task_pool);
+ evaluate_graph_threaded_stage(&state, task_pool, EvaluationStage::COPY_ON_WRITE);
+ evaluate_graph_threaded_stage(&state, task_pool, EvaluationStage::THREADED_EVALUATION);
+
BLI_task_pool_free(task_pool);
- if (state.need_single_thread_pass) {
- state.stage = EvaluationStage::SINGLE_THREADED_WORKAROUND;
- evaluate_graph_single_threaded(&state);
- }
+ evaluate_graph_single_threaded_if_needed(&state);
/* Finalize statistics gathering. This is because we only gather single
* operation timing here, without aggregating anything to avoid any extra
@@ -395,6 +419,7 @@ void deg_evaluate_on_refresh(Depsgraph *graph)
if (state.do_stats) {
deg_eval_stats_aggregate(graph);
}
+
/* Clear any uncleared tags - just in case. */
deg_graph_clear_tags(graph);
graph->is_evaluating = false;
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h
index ba86e1a349d..6937231d81a 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval.h
@@ -9,8 +9,7 @@
#pragma once
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -23,5 +22,4 @@ struct Depsgraph;
*/
void deg_evaluate_on_refresh(Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
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 29322d58218..cbf450aa3f1 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
@@ -27,8 +27,7 @@ struct ID;
struct Depsgraph;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
class DepsgraphNodeBuilder;
@@ -77,5 +76,4 @@ bool deg_copy_on_write_is_expanded(const struct ID *id_cow);
bool deg_copy_on_write_is_needed(const ID *id_orig);
bool deg_copy_on_write_is_needed(const ID_Type id_type);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
index 6eb232e76e5..614ca66faed 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h
@@ -9,8 +9,7 @@
#pragma once
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -24,5 +23,4 @@ void deg_graph_flush_updates(struct Depsgraph *graph);
*/
void deg_graph_clear_tags(struct Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
index deb21715a28..3d9b308c5ad 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.h
@@ -17,8 +17,7 @@
#include "intern/eval/deg_eval_runtime_backup_sound.h"
#include "intern/eval/deg_eval_runtime_backup_volume.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -59,5 +58,4 @@ class RuntimeBackup {
GPencilBackup gpencil_backup;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h
index 92847b330e8..807cc91242e 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_animation.h
@@ -11,8 +11,7 @@
#include "intern/depsgraph_type.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -46,5 +45,4 @@ class AnimationBackup {
Vector<AnimationValueBackup> values_backup;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h
index 68eff01fd60..95c0ca3a2fe 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.h
@@ -9,8 +9,7 @@
struct bGPdata;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -25,5 +24,4 @@ class GPencilBackup {
const Depsgraph *depsgraph;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h
index faec8f7c065..ee51204b24c 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_modifier.h
@@ -11,8 +11,7 @@
struct ModifierData;
-namespace blender {
-namespace deg {
+namespace blender::deg {
class ModifierDataBackup {
public:
@@ -22,5 +21,4 @@ class ModifierDataBackup {
void *runtime;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h
index 0e826e8f72a..aa13914d8c8 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_movieclip.h
@@ -11,8 +11,7 @@ struct MovieClip;
struct MovieClipCache;
struct anim;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -30,5 +29,4 @@ class MovieClipBackup {
struct MovieClipCache *cache;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h
index 3b138feec0b..c9cc167d927 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_object.h
@@ -17,8 +17,7 @@
struct Object;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -46,5 +45,4 @@ class ObjectRuntimeBackup {
Map<SessionUUID, bPoseChannel_Runtime> pose_channel_runtime_data;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h
index 8fd5de44001..2f6a3dd4371 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_pose.h
@@ -11,8 +11,6 @@
#include "DNA_action_types.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
-}
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h
index 17683966a22..155cb42a96d 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_scene.h
@@ -11,8 +11,7 @@
struct Scene;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -40,5 +39,4 @@ class SceneBackup {
SequencerBackup sequencer_backup;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h
index 95fbd2a3e4e..f97b6b200e9 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequence.h
@@ -11,8 +11,7 @@
struct Sequence;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -32,5 +31,4 @@ class SequenceBackup {
ListBase anims;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h
index 19e1a63ab4c..38fb8e81cc3 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sequencer.h
@@ -16,8 +16,7 @@
struct Scene;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -34,5 +33,4 @@ class SequencerBackup {
Map<SessionUUID, SequenceBackup> sequences_backup;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h
index c4267be1421..9e1d15251e8 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_sound.h
@@ -9,8 +9,7 @@
struct bSound;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -29,5 +28,4 @@ class SoundBackup {
void *playback_handle;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h
index bc263cc58f8..60cba64f120 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_volume.h
@@ -10,8 +10,7 @@
struct Volume;
struct VolumeGridVector;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
@@ -27,5 +26,4 @@ class VolumeBackup {
char filepath[1024]; /* FILE_MAX */
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_stats.h b/source/blender/depsgraph/intern/eval/deg_eval_stats.h
index a1e3cdaca76..c24c5f07135 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_stats.h
+++ b/source/blender/depsgraph/intern/eval/deg_eval_stats.h
@@ -7,13 +7,11 @@
#pragma once
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
/* Aggregate operation timings to overall component and ID nodes timing. */
void deg_eval_stats_aggregate(Depsgraph *graph);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index 509867ad47a..5b33528df33 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -18,8 +18,7 @@
struct ID;
struct Scene;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct Depsgraph;
struct OperationNode;
@@ -217,5 +216,4 @@ struct Node {
void deg_register_base_depsnodes();
-} // namespace deg
-} // namespace blender
+} // 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 6958866af3b..375a26ab49b 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -22,8 +22,7 @@
struct ID;
struct bPoseChannel;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct BoneComponentNode;
struct Depsgraph;
@@ -56,32 +55,45 @@ struct ComponentNode : public Node {
virtual string identifier() const override;
- /* Find an existing operation, if requested operation does not exist
- * nullptr will be returned. */
+ /* Find an existing operation, if requested operation does not exist nullptr will be returned.
+ * See #add_operation for the meaning and examples of #name and #name_tag.
+ */
OperationNode *find_operation(OperationIDKey key) const;
- OperationNode *find_operation(OperationCode opcode, const char *name, int name_tag) const;
+ OperationNode *find_operation(OperationCode opcode,
+ const char *name = "",
+ int name_tag = -1) const;
- /* Find an existing operation, will throw an assert() if it does not exist. */
+ /* Find an existing operation, will throw an assert() if it does not exist.
+ * See #add_operation for the meaning and examples of #name and #name_tag. */
OperationNode *get_operation(OperationIDKey key) const;
- OperationNode *get_operation(OperationCode opcode, const char *name, int name_tag) const;
+ OperationNode *get_operation(OperationCode opcode,
+ const char *name = "",
+ int name_tag = -1) const;
/* Check operation exists and return it. */
bool has_operation(OperationIDKey key) const;
- bool has_operation(OperationCode opcode, const char *name, int name_tag) const;
+ bool has_operation(OperationCode opcode, const char *name = "", int name_tag = -1) const;
/**
* Create a new node for representing an operation and add this to graph
+ *
* \warning If an existing node is found, it will be modified. This helps
* when node may have been partially created earlier (e.g. parent ref before
* parent item is added)
*
* \param opcode: The operation to perform.
- * \param name: Identifier for operation - used to find/locate it again.
+ * \param name: An optional identifier for operation. It will be used to tell operation nodes
+ * with the same code apart. For example, parameter operation code will have name
+ * set to the corresponding custom property name
+ * \param name_tag: An optional integer tag for the name. Is an additional way to tell operations
+ * apart. For example, RNA path to an array property will have the same opcode
+ * of PARAMETERS, name corresponding to the property name, and name tag
+ * corresponding to the array index within the property.
*/
OperationNode *add_operation(const DepsEvalOperationCb &op,
OperationCode opcode,
- const char *name,
- int name_tag);
+ const char *name = "",
+ int name_tag = -1);
/* Entry/exit operations management.
*
@@ -182,7 +194,6 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(ShadingParameters);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Transform);
DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(ObjectFromLayer);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Dupli);
-DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
@@ -190,6 +201,25 @@ DEG_COMPONENT_NODE_DECLARE_NO_COW(Visibility);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeOutput);
+/* Synchronization Component. */
+struct SynchronizationComponentNode : public ComponentNode {
+ SynchronizationComponentNode()
+ {
+ /* Enforce "visibility" of the synchronization component.
+ *
+ * This component is never connected to other ID nodes, and hence can not be handled in the
+ * same way as other components needed for evaluation. It is only needed for proper
+ * evaluation of the ID node it belongs to.
+ *
+ * The design is such that the synchronization is supposed to happen whenever any part of the
+ * ID changed/evaluated. Here we mark the component as "visible" so that genetic recalc flag
+ * flushing and scheduling will handle the component in a generic manner. */
+ affects_directly_visible = true;
+ }
+
+ DEG_COMPONENT_NODE_DECLARE;
+};
+
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
/** Initialize 'bone component' node - from pointer data given. */
@@ -218,5 +248,4 @@ struct ParametersComponentNode : public ComponentNode {
void deg_register_component_depsnodes();
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/node/deg_node_factory.h b/source/blender/depsgraph/intern/node/deg_node_factory.h
index 6caf99ac9ba..ec5029e8352 100644
--- a/source/blender/depsgraph/intern/node/deg_node_factory.h
+++ b/source/blender/depsgraph/intern/node/deg_node_factory.h
@@ -14,9 +14,7 @@
struct ID;
-namespace blender {
-namespace deg {
-
+namespace blender::deg {
struct DepsNodeFactory {
virtual NodeType type() const = 0;
virtual const char *type_name() const = 0;
@@ -41,7 +39,6 @@ void register_node_typeinfo(DepsNodeFactory *factory);
/* Get typeinfo for specified type */
DepsNodeFactory *type_get_factory(NodeType type);
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
#include "intern/node/deg_node_factory_impl.h"
diff --git a/source/blender/depsgraph/intern/node/deg_node_factory_impl.h b/source/blender/depsgraph/intern/node/deg_node_factory_impl.h
index 76a91860cc1..d9d0a1c1e3e 100644
--- a/source/blender/depsgraph/intern/node/deg_node_factory_impl.h
+++ b/source/blender/depsgraph/intern/node/deg_node_factory_impl.h
@@ -11,8 +11,7 @@
struct ID;
-namespace blender {
-namespace deg {
+namespace blender::deg {
template<class ModeObjectType> NodeType DepsNodeFactoryImpl<ModeObjectType>::type() const
{
@@ -48,5 +47,4 @@ Node *DepsNodeFactoryImpl<ModeObjectType>::create_node(const ID *id,
return node;
}
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h
index a8b6294b482..406ca828049 100644
--- a/source/blender/depsgraph/intern/node/deg_node_id.h
+++ b/source/blender/depsgraph/intern/node/deg_node_id.h
@@ -12,8 +12,7 @@
#include "DNA_ID.h"
#include "intern/node/deg_node.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct ComponentNode;
@@ -117,5 +116,4 @@ struct IDNode : public Node {
DEG_DEPSNODE_DECLARE;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index c29aeefd9b2..3029379d141 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -32,6 +32,8 @@ const char *operationCodeAsString(OperationCode opcode)
return "PARAMETERS_EVAL";
case OperationCode::PARAMETERS_EXIT:
return "PARAMETERS_EXIT";
+ case OperationCode::VISIBILITY:
+ return "VISIBILITY";
/* Animation, Drivers, etc. */
case OperationCode::ANIMATION_ENTRY:
return "ANIMATION_ENTRY";
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index d4916be1113..fd772fbce9d 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -13,8 +13,7 @@
struct Depsgraph;
-namespace blender {
-namespace deg {
+namespace blender::deg {
struct ComponentNode;
@@ -34,6 +33,7 @@ enum class OperationCode {
PARAMETERS_ENTRY,
PARAMETERS_EVAL,
PARAMETERS_EXIT,
+ VISIBILITY,
/* Animation, Drivers, etc. --------------------------------------------- */
/* NLA + Action */
@@ -202,13 +202,16 @@ const char *operationCodeAsString(OperationCode opcode);
enum OperationFlag {
/* Node needs to be updated. */
DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
+
/* Node was directly modified, causing need for update. */
DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
+
/* Node was updated due to user input. */
DEPSOP_FLAG_USER_MODIFIED = (1 << 2),
- /* Node may not be removed, even when it has no evaluation callback and no
- * outgoing relations. This is for NO-OP nodes that are purely used to indicate a
- * relation between components/IDs, and not for connecting to an operation. */
+
+ /* Node may not be removed, even when it has no evaluation callback and no outgoing relations.
+ * This is for NO-OP nodes that are purely used to indicate a relation between components/IDs,
+ * and not for connecting to an operation. */
DEPSOP_FLAG_PINNED = (1 << 3),
/* Set of flags which gets flushed along the relations. */
@@ -268,5 +271,4 @@ struct OperationNode : public Node {
void deg_register_operation_depsnodes();
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/depsgraph/intern/node/deg_node_time.h b/source/blender/depsgraph/intern/node/deg_node_time.h
index fcfe9a0fa80..3946b63384d 100644
--- a/source/blender/depsgraph/intern/node/deg_node_time.h
+++ b/source/blender/depsgraph/intern/node/deg_node_time.h
@@ -9,8 +9,7 @@
#include "intern/node/deg_node.h"
-namespace blender {
-namespace deg {
+namespace blender::deg {
/* Time Source Node. */
struct TimeSourceNode : public Node {
@@ -25,5 +24,4 @@ struct TimeSourceNode : public Node {
DEG_DEPSNODE_DECLARE;
};
-} // namespace deg
-} // namespace blender
+} // namespace blender::deg
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 3381dbadbab..55d789f64b0 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -39,8 +39,8 @@ set(INC
set(SRC
intern/draw_cache.c
intern/draw_cache_extract_mesh.cc
- intern/draw_cache_extract_mesh_render_data.c
- intern/mesh_extractors/extract_mesh.c
+ intern/draw_cache_extract_mesh_render_data.cc
+ intern/mesh_extractors/extract_mesh.cc
intern/mesh_extractors/extract_mesh_ibo_edituv.cc
intern/mesh_extractors/extract_mesh_ibo_fdots.cc
intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -75,7 +75,7 @@ set(SRC
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_gpencil.c
intern/draw_cache_impl_lattice.c
- intern/draw_cache_impl_mesh.c
+ intern/draw_cache_impl_mesh.cc
intern/draw_cache_impl_metaball.c
intern/draw_cache_impl_particles.c
intern/draw_cache_impl_pointcloud.c
@@ -136,13 +136,16 @@ set(SRC
engines/eevee/eevee_volumes.c
engines/eevee_next/eevee_camera.cc
engines/eevee_next/eevee_engine.cc
+ engines/eevee_next/eevee_film.cc
engines/eevee_next/eevee_instance.cc
engines/eevee_next/eevee_material.cc
engines/eevee_next/eevee_pipeline.cc
+ engines/eevee_next/eevee_renderbuffers.cc
+ engines/eevee_next/eevee_sampling.cc
engines/eevee_next/eevee_shader.cc
engines/eevee_next/eevee_sync.cc
- engines/eevee_next/eevee_view.cc
engines/eevee_next/eevee_velocity.cc
+ engines/eevee_next/eevee_view.cc
engines/eevee_next/eevee_world.cc
engines/workbench/workbench_data.c
engines/workbench/workbench_effect_antialiasing.c
@@ -191,6 +194,7 @@ set(SRC
engines/overlay/overlay_paint.c
engines/overlay/overlay_particle.c
engines/overlay/overlay_sculpt.c
+ engines/overlay/overlay_sculpt_curves.cc
engines/overlay/overlay_shader.c
engines/overlay/overlay_volume.c
engines/overlay/overlay_wireframe.c
@@ -201,7 +205,7 @@ set(SRC
intern/DRW_render.h
intern/draw_attributes.h
intern/draw_cache.h
- intern/draw_cache_extract.h
+ intern/draw_cache_extract.hh
intern/draw_cache_impl.h
intern/draw_cache_inline.h
intern/draw_color_management.h
@@ -221,7 +225,7 @@ set(SRC
intern/draw_texture_pool.h
intern/draw_view.h
intern/draw_view_data.h
- intern/mesh_extractors/extract_mesh.h
+ intern/mesh_extractors/extract_mesh.hh
intern/smaa_textures.h
engines/basic/basic_engine.h
engines/basic/basic_private.h
@@ -357,6 +361,9 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_attributes_lib.glsl
engines/eevee_next/shaders/eevee_camera_lib.glsl
+ engines/eevee_next/shaders/eevee_film_comp.glsl
+ engines/eevee_next/shaders/eevee_film_frag.glsl
+ engines/eevee_next/shaders/eevee_film_lib.glsl
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
@@ -452,108 +459,117 @@ set(GLSL_SRC
engines/select/shaders/select_id_vert.glsl
engines/select/shaders/select_id_frag.glsl
- engines/basic/shaders/conservative_depth_geom.glsl
- engines/basic/shaders/depth_vert.glsl
- engines/basic/shaders/depth_pointcloud_vert.glsl
- engines/basic/shaders/depth_frag.glsl
-
- engines/overlay/shaders/common_overlay_lib.glsl
- engines/overlay/shaders/antialiasing_frag.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_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_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_gpencil_frag.glsl
- engines/overlay/shaders/outline_prepass_geom.glsl
- engines/overlay/shaders/outline_prepass_gpencil_vert.glsl
- engines/overlay/shaders/outline_prepass_pointcloud_vert.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/basic/shaders/basic_conservative_depth_geom.glsl
+ engines/basic/shaders/basic_depth_vert.glsl
+ engines/basic/shaders/basic_depth_curves_vert.glsl
+ engines/basic/shaders/basic_depth_pointcloud_vert.glsl
+ engines/basic/shaders/basic_depth_frag.glsl
+
+ engines/overlay/shaders/overlay_antialiasing_frag.glsl
+ engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_dof_vert.glsl
+ engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
+ engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
+ engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
+ engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
+ engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
+ engines/overlay/shaders/overlay_armature_stick_frag.glsl
+ engines/overlay/shaders/overlay_armature_stick_vert.glsl
+ engines/overlay/shaders/overlay_armature_wire_frag.glsl
+ engines/overlay/shaders/overlay_armature_wire_vert.glsl
+ engines/overlay/shaders/overlay_background_frag.glsl
+ engines/overlay/shaders/overlay_clipbound_vert.glsl
+ engines/overlay/shaders/overlay_common_lib.glsl
+ engines/overlay/shaders/overlay_depth_only_frag.glsl
+ engines/overlay/shaders/overlay_depth_only_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
+ engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
+ engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
+ engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
+ engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
+ engines/overlay/shaders/overlay_edit_mesh_frag.glsl
+ engines/overlay/shaders/overlay_edit_mesh_geom.glsl
+ engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
+ engines/overlay/shaders/overlay_edit_mesh_vert.glsl
+ engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
+ engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
+ engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
+ engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
+ engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
+ engines/overlay/shaders/overlay_extra_frag.glsl
+ engines/overlay/shaders/overlay_extra_groundline_vert.glsl
+ engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
+ engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
+ engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
+ engines/overlay/shaders/overlay_extra_point_vert.glsl
+ engines/overlay/shaders/overlay_extra_vert.glsl
+ engines/overlay/shaders/overlay_extra_wire_frag.glsl
+ engines/overlay/shaders/overlay_extra_wire_vert.glsl
+ engines/overlay/shaders/overlay_facing_frag.glsl
+ engines/overlay/shaders/overlay_facing_vert.glsl
+ engines/overlay/shaders/overlay_grid_background_frag.glsl
+ engines/overlay/shaders/overlay_grid_frag.glsl
+ engines/overlay/shaders/overlay_grid_vert.glsl
+ engines/overlay/shaders/overlay_image_frag.glsl
+ engines/overlay/shaders/overlay_image_vert.glsl
+ engines/overlay/shaders/overlay_motion_path_line_frag.glsl
+ engines/overlay/shaders/overlay_motion_path_line_geom.glsl
+ engines/overlay/shaders/overlay_motion_path_line_vert.glsl
+ engines/overlay/shaders/overlay_motion_path_point_vert.glsl
+ engines/overlay/shaders/overlay_outline_detect_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl
+ engines/overlay/shaders/overlay_outline_prepass_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_geom.glsl
+ engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
+ engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
+ engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
+ engines/overlay/shaders/overlay_outline_prepass_vert.glsl
+ engines/overlay/shaders/overlay_paint_face_vert.glsl
+ engines/overlay/shaders/overlay_paint_point_vert.glsl
+ engines/overlay/shaders/overlay_paint_texture_frag.glsl
+ engines/overlay/shaders/overlay_paint_texture_vert.glsl
+ engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
+ engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
+ engines/overlay/shaders/overlay_paint_weight_frag.glsl
+ engines/overlay/shaders/overlay_paint_weight_vert.glsl
+ engines/overlay/shaders/overlay_paint_wire_vert.glsl
+ engines/overlay/shaders/overlay_particle_frag.glsl
+ engines/overlay/shaders/overlay_particle_vert.glsl
+ engines/overlay/shaders/overlay_point_varying_color_frag.glsl
+ engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
+ engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl
+ engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl
+ engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
+ engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
+ engines/overlay/shaders/overlay_uniform_color_frag.glsl
+ engines/overlay/shaders/overlay_varying_color.glsl
+ engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
+ engines/overlay/shaders/overlay_volume_velocity_vert.glsl
+ engines/overlay/shaders/overlay_wireframe_frag.glsl
+ engines/overlay/shaders/overlay_wireframe_vert.glsl
+ engines/overlay/shaders/overlay_xray_fade_frag.glsl
engines/overlay/overlay_shader_shared.h
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 00822946fe5..dec7a22aadb 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -23,6 +23,9 @@ struct DrawEngineType;
struct GHash;
struct GPUMaterial;
struct GPUOffScreen;
+struct GPUVertFormat;
+struct CustomDataLayer;
+struct CustomData;
struct GPUViewport;
struct ID;
struct Main;
@@ -218,6 +221,12 @@ void DRW_opengl_context_activate(bool drw_state);
*/
void DRW_draw_cursor_2d_ex(const struct ARegion *region, const float cursor[2]);
+void DRW_cdlayer_attr_aliases_add(struct GPUVertFormat *format,
+ const char *base_name,
+ const struct CustomData *data,
+ const struct CustomDataLayer *cl,
+ bool is_active_render,
+ bool is_active_layer);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c
index 04a3c27959d..975d9e299bf 100644
--- a/source/blender/draw/engines/basic/basic_engine.c
+++ b/source/blender/draw/engines/basic/basic_engine.c
@@ -53,6 +53,7 @@ typedef struct BASIC_PrivateData {
DRWShadingGroup *depth_shgrp[2];
DRWShadingGroup *depth_shgrp_cull[2];
DRWShadingGroup *depth_hair_shgrp[2];
+ DRWShadingGroup *depth_curves_shgrp[2];
DRWShadingGroup *depth_pointcloud_shgrp[2];
bool use_material_slot_selection;
} BASIC_PrivateData; /* Transient data */
@@ -99,6 +100,9 @@ static void basic_cache_init(void *vedata)
stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create(
BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg), psl->depth_pass[i]);
+ stl->g_data->depth_curves_shgrp[i] = grp = DRW_shgroup_create(
+ BASIC_shaders_curves_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;
@@ -156,8 +160,12 @@ static void basic_cache_populate(void *vedata, Object *ob)
basic_cache_populate_particles(vedata, ob);
}
- /* Make flat object selectable in ortho view if wireframe is enabled. */
const bool do_in_front = (ob->dtx & OB_DRAW_IN_FRONT) != 0;
+ if (ob->type == OB_CURVES) {
+ DRW_shgroup_curves_create_sub(ob, stl->g_data->depth_curves_shgrp[do_in_front], NULL);
+ }
+
+ /* Make flat object selectable in ortho view if wireframe is enabled. */
if ((draw_ctx->v3d->overlay.flag & V3D_OVERLAY_WIREFRAMES) ||
(draw_ctx->v3d->shading.type == OB_WIRE) || (ob->dtx & OB_DRAWWIRE) || (ob->dt == OB_WIRE)) {
int flat_axis = 0;
diff --git a/source/blender/draw/engines/basic/basic_private.h b/source/blender/draw/engines/basic/basic_private.h
index 22b458baca2..197831b9ee8 100644
--- a/source/blender/draw/engines/basic/basic_private.h
+++ b/source/blender/draw/engines/basic/basic_private.h
@@ -11,6 +11,7 @@ extern "C" {
GPUShader *BASIC_shaders_depth_sh_get(eGPUShaderConfig config);
GPUShader *BASIC_shaders_pointcloud_depth_sh_get(eGPUShaderConfig config);
+GPUShader *BASIC_shaders_curves_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);
diff --git a/source/blender/draw/engines/basic/basic_shader.c b/source/blender/draw/engines/basic/basic_shader.c
index d7a8f23e3b3..5b7636ca9fd 100644
--- a/source/blender/draw/engines/basic/basic_shader.c
+++ b/source/blender/draw/engines/basic/basic_shader.c
@@ -11,9 +11,9 @@
#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_basic_depth_frag_glsl[];
+extern char datatoc_basic_depth_vert_glsl[];
+extern char datatoc_basic_conservative_depth_geom_glsl[];
extern char datatoc_common_view_lib_glsl[];
extern char datatoc_common_pointcloud_lib_glsl[];
@@ -24,6 +24,7 @@ typedef struct BASIC_Shaders {
/* Depth Pre Pass */
struct GPUShader *depth;
struct GPUShader *pointcloud_depth;
+ struct GPUShader *curves_depth;
struct GPUShader *depth_conservative;
struct GPUShader *pointcloud_depth_conservative;
} BASIC_Shaders;
@@ -53,6 +54,16 @@ GPUShader *BASIC_shaders_pointcloud_depth_sh_get(eGPUShaderConfig config)
return sh_data->pointcloud_depth;
}
+GPUShader *BASIC_shaders_curves_depth_sh_get(eGPUShaderConfig config)
+{
+ BASIC_Shaders *sh_data = &e_data.sh_data[config];
+ if (sh_data->curves_depth == NULL) {
+ sh_data->curves_depth = GPU_shader_create_from_info_name(
+ config == GPU_SHADER_CFG_CLIPPED ? "basic_depth_curves_clipped" : "basic_depth_curves");
+ }
+ return sh_data->curves_depth;
+}
+
GPUShader *BASIC_shaders_depth_conservative_sh_get(eGPUShaderConfig config)
{
BASIC_Shaders *sh_data = &e_data.sh_data[config];
diff --git a/source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl b/source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl
index d478f37691e..d478f37691e 100644
--- a/source/blender/draw/engines/basic/shaders/conservative_depth_geom.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_conservative_depth_geom.glsl
diff --git a/source/blender/draw/engines/basic/shaders/basic_depth_curves_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_curves_vert.glsl
new file mode 100644
index 00000000000..b0da9754fc6
--- /dev/null
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_curves_vert.glsl
@@ -0,0 +1,27 @@
+
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ float time, thick_time, thickness;
+ vec3 world_pos, tan, binor;
+ hair_get_pos_tan_binor_time(is_persp,
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz,
+ ViewMatrixInverse[2].xyz,
+ world_pos,
+ tan,
+ binor,
+ time,
+ thickness,
+ thick_time);
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ view_clipping_distances(world_pos);
+}
diff --git a/source/blender/draw/engines/basic/shaders/depth_frag.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl
index ff4a015c335..ff4a015c335 100644
--- a/source/blender/draw/engines/basic/shaders/depth_frag.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_frag.glsl
diff --git a/source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl
index b82edc61cee..b82edc61cee 100644
--- a/source/blender/draw/engines/basic/shaders/depth_pointcloud_vert.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_pointcloud_vert.glsl
diff --git a/source/blender/draw/engines/basic/shaders/depth_vert.glsl b/source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl
index 7046979cf97..7046979cf97 100644
--- a/source/blender/draw/engines/basic/shaders/depth_vert.glsl
+++ b/source/blender/draw/engines/basic/shaders/basic_depth_vert.glsl
diff --git a/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh b/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
index 9914d264c63..561cef0e442 100644
--- a/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
+++ b/source/blender/draw/engines/basic/shaders/infos/basic_depth_info.hh
@@ -10,7 +10,7 @@
GPU_SHADER_CREATE_INFO(basic_conservative)
.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3)
- .geometry_source("conservative_depth_geom.glsl");
+ .geometry_source("basic_conservative_depth_geom.glsl");
/** \} */
@@ -20,13 +20,16 @@ GPU_SHADER_CREATE_INFO(basic_conservative)
GPU_SHADER_CREATE_INFO(basic_mesh)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("depth_vert.glsl")
+ .vertex_source("basic_depth_vert.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(basic_pointcloud)
- .vertex_source("depth_pointcloud_vert.glsl")
+ .vertex_source("basic_depth_pointcloud_vert.glsl")
.additional_info("draw_pointcloud");
+GPU_SHADER_CREATE_INFO(basic_curves)
+ .vertex_source("basic_depth_curves_vert.glsl")
+ .additional_info("draw_hair");
/** \} */
/* -------------------------------------------------------------------- */
@@ -46,7 +49,8 @@ GPU_SHADER_CREATE_INFO(basic_pointcloud)
#define BASIC_OBTYPE_VARIATIONS(prefix, ...) \
BASIC_CONSERVATIVE_VARIATIONS(prefix##_mesh, "basic_mesh", __VA_ARGS__) \
- BASIC_CONSERVATIVE_VARIATIONS(prefix##_pointcloud, "basic_pointcloud", __VA_ARGS__)
+ BASIC_CONSERVATIVE_VARIATIONS(prefix##_pointcloud, "basic_pointcloud", __VA_ARGS__) \
+ BASIC_CLIPPING_VARIATIONS(prefix##_curves, "basic_curves", __VA_ARGS__)
/** \} */
@@ -54,7 +58,7 @@ GPU_SHADER_CREATE_INFO(basic_pointcloud)
/** \name Depth shader types.
* \{ */
-GPU_SHADER_CREATE_INFO(basic_depth).fragment_source("depth_frag.glsl");
+GPU_SHADER_CREATE_INFO(basic_depth).fragment_source("basic_depth_frag.glsl");
BASIC_OBTYPE_VARIATIONS(basic_depth, "basic_depth");
diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c
index d12ce7213f9..4528027a9ea 100644
--- a/source/blender/draw/engines/eevee/eevee_bloom.c
+++ b/source/blender/draw/engines/eevee/eevee_bloom.c
@@ -125,7 +125,8 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name,
struct GPUShader *sh,
DRWPass **pass,
bool upsample,
- bool resolve)
+ bool resolve,
+ bool resolve_add_base)
{
struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
@@ -141,7 +142,7 @@ static DRWShadingGroup *eevee_create_bloom_pass(const char *name,
}
if (resolve) {
DRW_shgroup_uniform_vec3(grp, "bloomColor", effects->bloom_color, 1);
- DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", true);
+ DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", resolve_add_base);
}
return grp;
@@ -193,18 +194,21 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved
EEVEE_shaders_bloom_downsample_get(use_antiflicker),
&psl->bloom_downsample_first,
false,
+ false,
false);
eevee_create_bloom_pass("Bloom Downsample",
effects,
EEVEE_shaders_bloom_downsample_get(false),
&psl->bloom_downsample,
false,
+ false,
false);
eevee_create_bloom_pass("Bloom Upsample",
effects,
EEVEE_shaders_bloom_upsample_get(use_highres),
&psl->bloom_upsample,
true,
+ false,
false);
grp = eevee_create_bloom_pass("Bloom Blit",
@@ -212,6 +216,7 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved
EEVEE_shaders_bloom_blit_get(use_antiflicker),
&psl->bloom_blit,
false,
+ false,
false);
DRW_shgroup_uniform_vec4(grp, "curveThreshold", effects->bloom_curve_threshold, 1);
DRW_shgroup_uniform_float(grp, "clampIntensity", &effects->bloom_clamp, 1);
@@ -221,6 +226,7 @@ void EEVEE_bloom_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *ved
EEVEE_shaders_bloom_resolve_get(use_highres),
&psl->bloom_resolve,
true,
+ true,
true);
}
}
@@ -304,13 +310,13 @@ void EEVEE_bloom_output_init(EEVEE_ViewLayerData *UNUSED(sldata),
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->bloom_accum)});
/* Create Pass and shgroup. */
- DRWShadingGroup *grp = eevee_create_bloom_pass("Bloom Accumulate",
- effects,
- EEVEE_shaders_bloom_resolve_get(use_highres),
- &psl->bloom_accum_ps,
- true,
- true);
- DRW_shgroup_uniform_bool_copy(grp, "bloomAddBase", false);
+ eevee_create_bloom_pass("Bloom Accumulate",
+ effects,
+ EEVEE_shaders_bloom_resolve_get(use_highres),
+ &psl->bloom_accum_ps,
+ true,
+ true,
+ false);
}
void EEVEE_bloom_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
diff --git a/source/blender/draw/engines/eevee/eevee_cryptomatte.c b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
index 33063e14c03..53ea66bdea0 100644
--- a/source/blender/draw/engines/eevee/eevee_cryptomatte.c
+++ b/source/blender/draw/engines/eevee/eevee_cryptomatte.c
@@ -94,7 +94,7 @@ BLI_INLINE int eevee_cryptomatte_pixel_stride(const ViewLayer *view_layer)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Init Renderpasses
+/** \name Init Render-Passes
* \{ */
void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata)
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index 227757bad23..ffe0863fb9f 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -312,12 +312,12 @@ static void eevee_draw_scene(void *vedata)
/* Volumetrics Resolve Opaque */
EEVEE_volumes_resolve(sldata, vedata);
- /* Renderpasses */
+ /* Render-passes. */
EEVEE_renderpasses_output_accumulate(sldata, vedata, false);
/* Transparent */
- /* TODO(fclem): should be its own Frame-buffer.
- * This is needed because dualsource blending only works with 1 color buffer. */
+ /* TODO(@fclem): should be its own Frame-buffer.
+ * This is needed because dual-source blending only works with 1 color buffer. */
GPU_framebuffer_texture_attach(fbl->main_color_fb, dtxl->depth, 0, 0);
GPU_framebuffer_bind(fbl->main_color_fb);
DRW_draw_pass(psl->transparent_pass);
@@ -451,8 +451,8 @@ static void eevee_render_to_image(void *vedata,
}
EEVEE_PrivateData *g_data = ved->stl->g_data;
- int initial_frame = CFRA;
- float initial_subframe = SUBFRA;
+ int initial_frame = scene->r.cfra;
+ float initial_subframe = scene->r.subframe;
float shuttertime = (do_motion_blur) ? scene->eevee.motion_blur_shutter : 0.0f;
int time_steps_tot = (do_motion_blur) ? max_ii(1, scene->eevee.motion_blur_steps) : 1;
g_data->render_timesteps = time_steps_tot;
@@ -588,7 +588,7 @@ static void eevee_render_to_image(void *vedata,
/* Restore original viewport size. */
DRW_render_viewport_size_set((int[2]){g_data->size_orig[0], g_data->size_orig[1]});
- if (CFRA != initial_frame || SUBFRA != initial_subframe) {
+ if (scene->r.cfra != initial_frame || scene->r.subframe != initial_subframe) {
/* Restore original frame number. This is because the render pipeline expects it. */
RE_engine_frame_set(engine, initial_frame, initial_subframe);
}
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 0a7c8e185c4..8d47d80987c 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -671,7 +671,7 @@ typedef struct EEVEE_HairMotionData {
/** Allocator will alloc enough slot for all particle systems. Or 1 if it's a curves object. */
int psys_len;
struct {
- /* The vbos and textures are not owned. */
+ /* The VBO's and textures are not owned. */
EEVEE_HairMotionStepData step_data[2]; /* Data for time = t +/- step. */
} psys[0];
} EEVEE_HairMotionData;
@@ -682,7 +682,7 @@ typedef struct EEVEE_GeometryMotionData {
/** To disable deform mb if vertcount mismatch. */
int use_deform;
- /* The batch and vbos are not owned. */
+ /* The batch and VBOs are not owned. */
struct GPUBatch *batch; /* Batch for time = t. */
struct GPUVertBuf *vbo[2]; /* VBO for time = t +/- step. */
} EEVEE_GeometryMotionData;
@@ -1050,7 +1050,7 @@ typedef struct EEVEE_PrivateData {
float studiolight_glossy_clamp;
float studiolight_filter_quality;
- /* Renderpasses */
+ /* Render-passes */
/* Bitmask containing the active render_passes */
eViewLayerEEVEEPassType render_passes;
uint aov_hash;
diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c
index bef19c589c2..82944f237ea 100644
--- a/source/blender/draw/engines/eevee/eevee_render.c
+++ b/source/blender/draw/engines/eevee/eevee_render.c
@@ -24,6 +24,7 @@
#include "DEG_depsgraph_query.h"
#include "GPU_capabilities.h"
+#include "GPU_context.h"
#include "GPU_framebuffer.h"
#include "GPU_state.h"
@@ -646,6 +647,10 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl
/* XXX Seems to fix TDR issue with NVidia drivers on linux. */
GPU_finish();
+ /* Perform render step between samples to allow
+ * flushing of freed GPUBackend resources. */
+ GPU_render_step();
+
RE_engine_update_progress(engine, (float)(render_samples++) / (float)tot_sample);
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_sampling.c b/source/blender/draw/engines/eevee/eevee_sampling.c
index a1a3e98f34f..34d3cd74b36 100644
--- a/source/blender/draw/engines/eevee/eevee_sampling.c
+++ b/source/blender/draw/engines/eevee/eevee_sampling.c
@@ -74,7 +74,8 @@ void EEVEE_sample_ellipse(int sample_ofs,
BLI_halton_2d(ht_primes, ht_offset, sample_ofs, ht_point);
- /* Decorelate AA and shadow samples. (see T68594) */
+ /* Decorrelate AA and shadow samples. (see T68594) */
+
ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
@@ -97,7 +98,7 @@ void EEVEE_random_rotation_m4(int sample_ofs, float scale, float r_mat[4][4])
BLI_halton_3d(ht_primes, ht_offset, sample_ofs, ht_point);
- /* Decorelate AA and shadow samples. (see T68594) */
+ /* Decorrelate AA and shadow samples. (see T68594) */
ht_point[0] = fmod(ht_point[0] * 1151.0, 1.0);
ht_point[1] = fmod(ht_point[1] * 1069.0, 1.0);
ht_point[2] = fmod(ht_point[2] * 1151.0, 1.0);
diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
index 5af794c9158..0d0e551f3dc 100644
--- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
+++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c
@@ -198,7 +198,7 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
if (((effects->enabled_effects & EFFECT_SSR) != 0) && stl->g_data->valid_double_buffer) {
DRW_stats_group_start("SSR");
- /* Raytrace. */
+ /* Ray-trace. */
GPU_framebuffer_bind(fbl->screen_tracing_fb);
DRW_draw_pass(psl->ssr_raytrace);
diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c
index 6fd5d97089d..5709621fc05 100644
--- a/source/blender/draw/engines/eevee/eevee_shaders.c
+++ b/source/blender/draw/engines/eevee/eevee_shaders.c
@@ -718,7 +718,7 @@ GPUShader *EEVEE_shaders_cryptomatte_sh_get(bool is_hair)
if (e_data.cryptomatte_sh[index] == NULL) {
DynStr *ds = BLI_dynstr_new();
BLI_dynstr_append(ds, SHADER_DEFINES);
- BLI_dynstr_append(ds, "#define attrib_load(a) \n");
+ BLI_dynstr_append(ds, "#define attrib_load() \n");
if (is_hair) {
BLI_dynstr_append(ds, "#define HAIR_SHADER\n");
}
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index b8bef61f8b1..533e71b9b32 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -306,9 +306,14 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
return;
}
+ GPUShader *sh = GPU_material_get_shader(mat);
+ if (sh == NULL) {
+ return;
+ }
+
/* TODO(fclem): Reuse main shading group to avoid shading binding cost just like for surface
* shaders. */
- DRWShadingGroup *grp = DRW_shgroup_material_create(mat, vedata->psl->volumetric_objects_ps);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, vedata->psl->volumetric_objects_ps);
grp = DRW_shgroup_volume_create_sub(scene, ob, grp, mat);
@@ -316,6 +321,8 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata,
return;
}
+ DRW_shgroup_add_material_resources(grp, mat);
+
/* TODO(fclem): remove those "unnecessary" UBOs */
DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo);
DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo);
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
index 0f5290a7c07..ffca97b6b8f 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_surface_lib.glsl
@@ -181,6 +181,8 @@ Closure closure_eval(ClosureDiffuse diffuse, ClosureReflection reflection)
/* Glue with the old system. */
CLOSURE_VARS_DECLARE_2(Diffuse, Glossy);
+ /* WORKAROUND: This is to avoid regression in 3.2 and avoid messing with EEVEE-Next. */
+ in_common.occlusion = (diffuse.sss_radius.g == -1.0) ? diffuse.sss_radius.r : 1.0;
in_Diffuse_0.N = diffuse.N;
in_Diffuse_0.albedo = diffuse.color;
in_Glossy_1.N = reflection.N;
@@ -207,6 +209,8 @@ Closure closure_eval(ClosureDiffuse diffuse,
/* Glue with the old system. */
CLOSURE_VARS_DECLARE_3(Diffuse, Glossy, Glossy);
+ /* WORKAROUND: This is to avoid regression in 3.2 and avoid messing with EEVEE-Next. */
+ in_common.occlusion = (diffuse.sss_radius.g == -1.0) ? diffuse.sss_radius.r : 1.0;
in_Diffuse_0.N = diffuse.N;
in_Diffuse_0.albedo = diffuse.color;
in_Glossy_1.N = reflection.N;
diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index 21d347942ca..4070ede116b 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
@@ -24,7 +24,7 @@ struct Closure {
float holdout;
#endif
-/* Metal Default Constructor - Requred for C++ constructor syntax. */
+/* Metal Default Constructor - Required for C++ constructor syntax. */
#ifdef GPU_METAL
inline Closure() = default;
# ifdef VOLUMETRICS
diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
index 2926f8c5a89..57d70334651 100644
--- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl
@@ -73,7 +73,7 @@ int g_curves_attr_id = 0;
int curves_attribute_element_id()
{
int id = hairStrandID;
- if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ if (drw_curves.is_point_attribute[g_curves_attr_id][0] != 0) {
id = hair_get_base_id();
}
diff --git a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
index ace6c7d788d..2a212b757c2 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_frag.glsl
@@ -152,7 +152,8 @@ void main()
/* Only supported attrib for world/background shaders. */
vec3 attr_load_orco(vec4 orco)
{
- return g_data.P;
+ /* Retain precision better than g_data.P (see T99128). */
+ return transform_direction(ViewMatrixInverse, normalize(viewPosition));
}
/* Unsupported. */
vec4 attr_load_tangent(vec4 tangent)
diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
index 8e1bafe8d92..80c6b935187 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl
@@ -97,7 +97,7 @@ GlobalData init_globals(void)
GlobalData surf;
# if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
- surf.P = -cameraVec(worldPosition);
+ surf.P = transform_direction(ViewMatrixInverse, viewCameraVec(viewPosition));
surf.N = surf.Ng = -surf.P;
surf.ray_length = 0.0;
# else
diff --git a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
index a8e95e13b12..4a3a91b8534 100644
--- a/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/surface_vert.glsl
@@ -80,7 +80,7 @@ int g_curves_attr_id = 0;
int curves_attribute_element_id()
{
int id = hairStrandID;
- if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ if (drw_curves.is_point_attribute[g_curves_attr_id][0] != 0) {
id = hair_get_base_id();
}
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index a81d37f4e6f..c6de723ac25 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -86,6 +86,8 @@ void main()
discard;
return;
}
+#else /* WORLD_SHADER */
+ volumeOrco = worldPosition;
#endif
#ifdef CLEAR
@@ -157,7 +159,7 @@ float attr_load_float(sampler3D tex)
}
/* TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on
- * the engine side. But as of now, the engines are reponsible for loading the attributes. */
+ * the engine side. But as of now, the engines are responsible for loading the attributes. */
float attr_load_temperature_post(float attr)
{
#ifdef MESH_SHADER
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
index 186f438b03b..b3b9c7af19c 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_vert.glsl
@@ -77,3 +77,13 @@ vec3 coordinate_incoming(vec3 P)
{
return vec3(0.0);
}
+
+float attr_load_temperature_post(float attr)
+{
+ return attr;
+}
+
+vec4 attr_load_color_post(vec4 attr)
+{
+ return attr;
+}
diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.cc b/source/blender/draw/engines/eevee_next/eevee_camera.cc
index e6d2e2db764..1f65f887d46 100644
--- a/source/blender/draw/engines/eevee_next/eevee_camera.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_camera.cc
@@ -77,9 +77,10 @@ void Camera::init()
void Camera::sync()
{
const Object *camera_eval = inst_.camera_eval_object;
- CameraData &data = data_.current();
- data.filter_size = inst_.scene->r.gauss;
+ data_.swap();
+
+ CameraData &data = data_.current();
if (inst_.drw_view) {
DRW_view_viewmat_get(inst_.drw_view, data.viewmat.ptr(), false);
@@ -127,6 +128,10 @@ void Camera::sync()
data.equirect_scale *= data.uv_scale;
data.equirect_scale_inv = 1.0f / data.equirect_scale;
+#else
+ data.fisheye_fov = data.fisheye_lens = -1.0f;
+ data.equirect_bias = float2(0.0f);
+ data.equirect_scale = float2(0.0f);
#endif
}
else if (inst_.drw_view) {
@@ -143,7 +148,7 @@ void Camera::sync()
/* Detect changes in parameters. */
if (data_.current() != data_.previous()) {
- // inst_.sampling.reset();
+ inst_.sampling.reset();
}
}
diff --git a/source/blender/draw/engines/eevee_next/eevee_camera.hh b/source/blender/draw/engines/eevee_next/eevee_camera.hh
index dfec738b1f3..3b3586190c4 100644
--- a/source/blender/draw/engines/eevee_next/eevee_camera.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_camera.hh
@@ -61,8 +61,7 @@ inline bool operator==(const CameraData &a, const CameraData &b)
return compare_m4m4(a.persmat.ptr(), b.persmat.ptr(), FLT_MIN) && (a.uv_scale == b.uv_scale) &&
(a.uv_bias == b.uv_bias) && (a.equirect_scale == b.equirect_scale) &&
(a.equirect_bias == b.equirect_bias) && (a.fisheye_fov == b.fisheye_fov) &&
- (a.fisheye_lens == b.fisheye_lens) && (a.filter_size == b.filter_size) &&
- (a.type == b.type);
+ (a.fisheye_lens == b.fisheye_lens) && (a.type == b.type);
}
inline bool operator!=(const CameraData &a, const CameraData &b)
diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh
index 7141928a20d..1e7979b594e 100644
--- a/source/blender/draw/engines/eevee_next/eevee_defines.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh
@@ -12,7 +12,7 @@
#pragma once
/**
- Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536.
+ * Number of items in a culling batch. Needs to be Power of 2. Must be <= to 65536.
* Current limiting factor is the sorting phase which is single pass and only sort within a
* thread-group which maximum size is 1024.
*/
@@ -43,3 +43,5 @@
/* Minimum visibility size. */
#define LIGHTPROBE_FILTER_VIS_GROUP_SIZE 16
+
+#define FILM_GROUP_SIZE 16
diff --git a/source/blender/draw/engines/eevee_next/eevee_engine.cc b/source/blender/draw/engines/eevee_next/eevee_engine.cc
index be0adfad568..37b4bde324e 100644
--- a/source/blender/draw/engines/eevee_next/eevee_engine.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_engine.cc
@@ -12,6 +12,8 @@
#include "DRW_render.h"
+#include "RE_pipeline.h"
+
#include "eevee_engine.h" /* Own include. */
#include "eevee_instance.hh"
@@ -97,6 +99,8 @@ static void eevee_draw_scene(void *vedata)
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
ved->instance->draw_viewport(dfbl);
STRNCPY(ved->info, ved->instance->info.c_str());
+ /* Reset view for other following engines. */
+ DRW_view_set_active(nullptr);
}
static void eevee_cache_init(void *vedata)
@@ -144,7 +148,23 @@ static void eevee_render_to_image(void *UNUSED(vedata),
if (!GPU_shader_storage_buffer_objects_support()) {
return;
}
- UNUSED_VARS(engine, layer);
+
+ eevee::Instance *instance = new eevee::Instance();
+
+ Render *render = engine->re;
+ Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
+ Object *camera_original_ob = RE_GetCamera(engine->re);
+ const char *viewname = RE_GetActiveRenderView(engine->re);
+ int size[2] = {engine->resolution_x, engine->resolution_y};
+
+ rctf view_rect;
+ rcti rect;
+ RE_GetViewPlane(render, &view_rect, &rect);
+
+ instance->init(size, &rect, engine, depsgraph, nullptr, camera_original_ob, layer);
+ instance->render_frame(layer, viewname);
+
+ delete instance;
}
static void eevee_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
diff --git a/source/blender/draw/engines/eevee_next/eevee_film.cc b/source/blender/draw/engines/eevee_next/eevee_film.cc
new file mode 100644
index 00000000000..1fd4c278c88
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_film.cc
@@ -0,0 +1,579 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * A film is a fullscreen buffer (usually at output extent)
+ * that will be able to accumulate sample in any distorted camera_type
+ * using a pixel filter.
+ *
+ * Input needs to be jittered so that the filter converges to the right result.
+ */
+
+#include "BLI_hash.h"
+#include "BLI_rect.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
+
+#include "DRW_render.h"
+#include "RE_pipeline.h"
+
+#include "eevee_film.hh"
+#include "eevee_instance.hh"
+
+namespace blender::eevee {
+
+ENUM_OPERATORS(eViewLayerEEVEEPassType, 1 << EEVEE_RENDER_PASS_MAX_BIT)
+
+/* -------------------------------------------------------------------- */
+/** \name Arbitrary Output Variables
+ * \{ */
+
+void Film::init_aovs()
+{
+ Vector<ViewLayerAOV *> aovs;
+
+ aovs_info.display_id = -1;
+ aovs_info.display_is_value = false;
+ aovs_info.value_len = aovs_info.color_len = 0;
+
+ if (inst_.is_viewport()) {
+ /* Viewport case. */
+ if (inst_.v3d->shading.render_pass == EEVEE_RENDER_PASS_AOV) {
+ /* AOV display, request only a single AOV. */
+ ViewLayerAOV *aov = (ViewLayerAOV *)BLI_findstring(
+ &inst_.view_layer->aovs, inst_.v3d->shading.aov_name, offsetof(ViewLayerAOV, name));
+
+ if (aov == nullptr) {
+ /* AOV not found in view layer. */
+ return;
+ }
+
+ aovs.append(aov);
+ aovs_info.display_id = 0;
+ aovs_info.display_is_value = (aov->type == AOV_TYPE_VALUE);
+ }
+ else {
+ /* TODO(fclem): The realtime compositor could ask for several AOVs. */
+ }
+ }
+ else {
+ /* Render case. */
+ LISTBASE_FOREACH (ViewLayerAOV *, aov, &inst_.view_layer->aovs) {
+ aovs.append(aov);
+ }
+ }
+
+ if (aovs.size() > AOV_MAX) {
+ inst_.info = "Error: Too many AOVs";
+ return;
+ }
+
+ for (ViewLayerAOV *aov : aovs) {
+ bool is_value = (aov->type == AOV_TYPE_VALUE);
+ uint &index = is_value ? aovs_info.value_len : aovs_info.color_len;
+ uint &hash = is_value ? aovs_info.hash_value[index] : aovs_info.hash_color[index];
+ hash = BLI_hash_string(aov->name);
+ index++;
+ }
+}
+
+float *Film::read_aov(ViewLayerAOV *aov)
+{
+ bool is_value = (aov->type == AOV_TYPE_VALUE);
+ Texture &accum_tx = is_value ? value_accum_tx_ : color_accum_tx_;
+
+ Span<uint> aovs_hash(is_value ? aovs_info.hash_value : aovs_info.hash_color,
+ is_value ? aovs_info.value_len : aovs_info.color_len);
+ /* Find AOV index. */
+ uint hash = BLI_hash_string(aov->name);
+ int aov_index = -1;
+ int i = 0;
+ for (uint candidate_hash : aovs_hash) {
+ if (candidate_hash == hash) {
+ aov_index = i;
+ break;
+ }
+ i++;
+ }
+
+ accum_tx.ensure_layer_views();
+
+ int index = aov_index + (is_value ? data_.aov_value_id : data_.aov_color_id);
+ GPUTexture *pass_tx = accum_tx.layer_view(index);
+
+ return (float *)GPU_texture_read(pass_tx, GPU_DATA_FLOAT, 0);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mist Pass
+ * \{ */
+
+void Film::sync_mist()
+{
+ const CameraData &cam = inst_.camera.data_get();
+ const ::World *world = inst_.scene->world;
+ float mist_start = world ? world->miststa : cam.clip_near;
+ float mist_distance = world ? world->mistdist : fabsf(cam.clip_far - cam.clip_near);
+ int mist_type = world ? world->mistype : (int)WO_MIST_LINEAR;
+
+ switch (mist_type) {
+ case WO_MIST_QUADRATIC:
+ data_.mist_exponent = 2.0f;
+ break;
+ case WO_MIST_LINEAR:
+ data_.mist_exponent = 1.0f;
+ break;
+ case WO_MIST_INVERSE_QUADRATIC:
+ data_.mist_exponent = 0.5f;
+ break;
+ }
+
+ data_.mist_scale = 1.0 / mist_distance;
+ data_.mist_bias = -mist_start / mist_distance;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name FilmData
+ * \{ */
+
+inline bool operator==(const FilmData &a, const FilmData &b)
+{
+ return (a.extent == b.extent) && (a.offset == b.offset) && (a.filter_size == b.filter_size) &&
+ (a.scaling_factor == b.scaling_factor);
+}
+
+inline bool operator!=(const FilmData &a, const FilmData &b)
+{
+ return !(a == b);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Film
+ * \{ */
+
+void Film::init(const int2 &extent, const rcti *output_rect)
+{
+ init_aovs();
+
+ {
+ /* Enable passes that need to be rendered. */
+ eViewLayerEEVEEPassType render_passes;
+
+ if (inst_.is_viewport()) {
+ /* Viewport Case. */
+ render_passes = eViewLayerEEVEEPassType(inst_.v3d->shading.render_pass);
+
+ if (inst_.overlays_enabled() || inst_.gpencil_engine_enabled) {
+ /* Overlays and Grease Pencil needs the depth for correct compositing.
+ * Using the render pass ensure we store the center depth. */
+ render_passes |= EEVEE_RENDER_PASS_Z;
+ }
+ }
+ else {
+ /* Render Case. */
+ render_passes = eViewLayerEEVEEPassType(inst_.view_layer->eevee.render_passes);
+
+ render_passes |= EEVEE_RENDER_PASS_COMBINED;
+
+#define ENABLE_FROM_LEGACY(name_legacy, name_eevee) \
+ SET_FLAG_FROM_TEST(render_passes, \
+ (inst_.view_layer->passflag & SCE_PASS_##name_legacy) != 0, \
+ EEVEE_RENDER_PASS_##name_eevee);
+
+ ENABLE_FROM_LEGACY(Z, Z)
+ ENABLE_FROM_LEGACY(MIST, MIST)
+ ENABLE_FROM_LEGACY(NORMAL, NORMAL)
+ ENABLE_FROM_LEGACY(SHADOW, SHADOW)
+ ENABLE_FROM_LEGACY(AO, AO)
+ ENABLE_FROM_LEGACY(EMIT, EMIT)
+ ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT)
+ ENABLE_FROM_LEGACY(DIFFUSE_COLOR, DIFFUSE_COLOR)
+ ENABLE_FROM_LEGACY(GLOSSY_COLOR, SPECULAR_COLOR)
+ ENABLE_FROM_LEGACY(DIFFUSE_DIRECT, DIFFUSE_LIGHT)
+ ENABLE_FROM_LEGACY(GLOSSY_DIRECT, SPECULAR_LIGHT)
+ ENABLE_FROM_LEGACY(ENVIRONMENT, ENVIRONMENT)
+
+#undef ENABLE_FROM_LEGACY
+ }
+
+ /* Filter obsolete passes. */
+ render_passes &= ~(EEVEE_RENDER_PASS_UNUSED_8 | EEVEE_RENDER_PASS_BLOOM);
+
+ /* TODO(@fclem): Can't we rely on depsgraph update notification? */
+ if (assign_if_different(enabled_passes_, render_passes)) {
+ inst_.sampling.reset();
+ }
+ }
+ {
+ rcti fallback_rect;
+ if (BLI_rcti_is_empty(output_rect)) {
+ BLI_rcti_init(&fallback_rect, 0, extent[0], 0, extent[1]);
+ output_rect = &fallback_rect;
+ }
+
+ FilmData data = data_;
+ data.extent = int2(BLI_rcti_size_x(output_rect), BLI_rcti_size_y(output_rect));
+ data.offset = int2(output_rect->xmin, output_rect->ymin);
+ data.filter_size = clamp_f(inst_.scene->r.gauss, 0.0f, 100.0f);
+ /* TODO(fclem): parameter hidden in experimental.
+ * We need to figure out LOD bias first in order to preserve texture crispiness. */
+ data.scaling_factor = 1;
+
+ FilmData &data_prev_ = data_;
+ if (assign_if_different(data_prev_, data)) {
+ inst_.sampling.reset();
+ }
+
+ const eViewLayerEEVEEPassType data_passes = EEVEE_RENDER_PASS_Z | EEVEE_RENDER_PASS_NORMAL |
+ EEVEE_RENDER_PASS_VECTOR;
+ const eViewLayerEEVEEPassType color_passes_1 = EEVEE_RENDER_PASS_DIFFUSE_LIGHT |
+ EEVEE_RENDER_PASS_SPECULAR_LIGHT |
+ EEVEE_RENDER_PASS_VOLUME_LIGHT |
+ EEVEE_RENDER_PASS_EMIT;
+ const eViewLayerEEVEEPassType color_passes_2 = EEVEE_RENDER_PASS_DIFFUSE_COLOR |
+ EEVEE_RENDER_PASS_SPECULAR_COLOR |
+ EEVEE_RENDER_PASS_ENVIRONMENT |
+ EEVEE_RENDER_PASS_MIST |
+ EEVEE_RENDER_PASS_SHADOW | EEVEE_RENDER_PASS_AO;
+
+ data_.exposure = 1.0f /* TODO */;
+ data_.has_data = (enabled_passes_ & data_passes) != 0;
+ data_.any_render_pass_1 = (enabled_passes_ & color_passes_1) != 0;
+ data_.any_render_pass_2 = (enabled_passes_ & color_passes_2) != 0;
+ }
+ {
+ /* Set pass offsets. */
+
+ data_.display_id = aovs_info.display_id;
+ data_.display_is_value = aovs_info.display_is_value;
+
+ /* Combined is in a separate buffer. */
+ data_.combined_id = (enabled_passes_ & EEVEE_RENDER_PASS_COMBINED) ? 0 : -1;
+ /* Depth is in a separate buffer. */
+ data_.depth_id = (enabled_passes_ & EEVEE_RENDER_PASS_Z) ? 0 : -1;
+
+ data_.color_len = 0;
+ data_.value_len = 0;
+
+ auto pass_index_get = [&](eViewLayerEEVEEPassType pass_type) {
+ bool is_value = pass_is_value(pass_type);
+ int index = (enabled_passes_ & pass_type) ?
+ (is_value ? data_.value_len : data_.color_len)++ :
+ -1;
+ if (inst_.is_viewport() && inst_.v3d->shading.render_pass == pass_type) {
+ data_.display_id = index;
+ data_.display_is_value = is_value;
+ }
+ return index;
+ };
+
+ data_.mist_id = pass_index_get(EEVEE_RENDER_PASS_MIST);
+ data_.normal_id = pass_index_get(EEVEE_RENDER_PASS_NORMAL);
+ data_.vector_id = pass_index_get(EEVEE_RENDER_PASS_VECTOR);
+ data_.diffuse_light_id = pass_index_get(EEVEE_RENDER_PASS_DIFFUSE_LIGHT);
+ data_.diffuse_color_id = pass_index_get(EEVEE_RENDER_PASS_DIFFUSE_COLOR);
+ data_.specular_light_id = pass_index_get(EEVEE_RENDER_PASS_SPECULAR_LIGHT);
+ data_.specular_color_id = pass_index_get(EEVEE_RENDER_PASS_SPECULAR_COLOR);
+ data_.volume_light_id = pass_index_get(EEVEE_RENDER_PASS_VOLUME_LIGHT);
+ data_.emission_id = pass_index_get(EEVEE_RENDER_PASS_EMIT);
+ data_.environment_id = pass_index_get(EEVEE_RENDER_PASS_ENVIRONMENT);
+ data_.shadow_id = pass_index_get(EEVEE_RENDER_PASS_SHADOW);
+ data_.ambient_occlusion_id = pass_index_get(EEVEE_RENDER_PASS_AO);
+
+ data_.aov_color_id = data_.color_len;
+ data_.aov_value_id = data_.value_len;
+
+ data_.aov_color_len = aovs_info.color_len;
+ data_.aov_value_len = aovs_info.value_len;
+
+ data_.color_len += data_.aov_color_len;
+ data_.value_len += data_.aov_value_len;
+ }
+ {
+ /* TODO(@fclem): Over-scans. */
+
+ render_extent_ = math::divide_ceil(extent, int2(data_.scaling_factor));
+ int2 weight_extent = inst_.camera.is_panoramic() ? data_.extent : int2(data_.scaling_factor);
+
+ eGPUTextureFormat color_format = GPU_RGBA16F;
+ eGPUTextureFormat float_format = GPU_R16F;
+ eGPUTextureFormat weight_format = GPU_R32F;
+ eGPUTextureFormat depth_format = GPU_R32F;
+
+ int reset = 0;
+ reset += depth_tx_.ensure_2d(depth_format, data_.extent);
+ reset += combined_tx_.current().ensure_2d(color_format, data_.extent);
+ reset += combined_tx_.next().ensure_2d(color_format, data_.extent);
+ /* Two layers, one for nearest sample weight and one for weight accumulation. */
+ reset += weight_tx_.current().ensure_2d_array(weight_format, weight_extent, 2);
+ reset += weight_tx_.next().ensure_2d_array(weight_format, weight_extent, 2);
+ reset += color_accum_tx_.ensure_2d_array(color_format,
+ (data_.color_len > 0) ? data_.extent : int2(1),
+ (data_.color_len > 0) ? data_.color_len : 1);
+ reset += value_accum_tx_.ensure_2d_array(float_format,
+ (data_.value_len > 0) ? data_.extent : int2(1),
+ (data_.value_len > 0) ? data_.value_len : 1);
+
+ if (reset > 0) {
+ inst_.sampling.reset();
+ data_.use_history = 0;
+ data_.use_reprojection = 0;
+
+ /* Avoid NaN in uninitialized texture memory making history blending dangerous. */
+ color_accum_tx_.clear(float4(0.0f));
+ value_accum_tx_.clear(float4(0.0f));
+ combined_tx_.current().clear(float4(0.0f));
+ weight_tx_.current().clear(float4(0.0f));
+ depth_tx_.clear(float4(0.0f));
+ }
+ }
+}
+
+void Film::sync()
+{
+ /* We use a fragment shader for viewport because we need to output the depth. */
+ bool use_compute = (inst_.is_viewport() == false);
+
+ eShaderType shader = use_compute ? FILM_COMP : FILM_FRAG;
+
+ /* TODO(fclem): Shader variation for panoramic & scaled resolution. */
+
+ RenderBuffers &rbuffers = inst_.render_buffers;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS;
+ accumulate_ps_ = DRW_pass_create("Film.Accumulate", state);
+ GPUShader *sh = inst_.shaders.static_shader_get(shader);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, accumulate_ps_);
+ DRW_shgroup_uniform_block_ref(grp, "film_buf", &data_);
+ DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &rbuffers.depth_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "combined_tx", &rbuffers.combined_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "normal_tx", &rbuffers.normal_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "vector_tx", &rbuffers.vector_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "diffuse_light_tx", &rbuffers.diffuse_light_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "diffuse_color_tx", &rbuffers.diffuse_color_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "specular_light_tx", &rbuffers.specular_light_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "specular_color_tx", &rbuffers.specular_color_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "volume_light_tx", &rbuffers.volume_light_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "emission_tx", &rbuffers.emission_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "environment_tx", &rbuffers.environment_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "shadow_tx", &rbuffers.shadow_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "ambient_occlusion_tx", &rbuffers.ambient_occlusion_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "aov_color_tx", &rbuffers.aov_color_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "aov_value_tx", &rbuffers.aov_value_tx);
+ /* NOTE(@fclem): 16 is the max number of sampled texture in many implementations.
+ * If we need more, we need to pack more of the similar passes in the same textures as arrays or
+ * use image binding instead. */
+ DRW_shgroup_uniform_image_ref(grp, "in_weight_img", &weight_tx_.current());
+ DRW_shgroup_uniform_image_ref(grp, "out_weight_img", &weight_tx_.next());
+ DRW_shgroup_uniform_image_ref(grp, "in_combined_img", &combined_tx_.current());
+ DRW_shgroup_uniform_image_ref(grp, "out_combined_img", &combined_tx_.next());
+ DRW_shgroup_uniform_image_ref(grp, "depth_img", &depth_tx_);
+ DRW_shgroup_uniform_image_ref(grp, "color_accum_img", &color_accum_tx_);
+ DRW_shgroup_uniform_image_ref(grp, "value_accum_img", &value_accum_tx_);
+ /* Sync with rendering passes. */
+ DRW_shgroup_barrier(grp, GPU_BARRIER_TEXTURE_FETCH);
+ /* Sync with rendering passes. */
+ DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS);
+ if (use_compute) {
+ int2 dispatch_size = math::divide_ceil(data_.extent, int2(FILM_GROUP_SIZE));
+ DRW_shgroup_call_compute(grp, UNPACK2(dispatch_size), 1);
+ }
+ else {
+ DRW_shgroup_call_procedural_triangles(grp, nullptr, 1);
+ }
+}
+
+void Film::end_sync()
+{
+ if (inst_.sampling.is_reset()) {
+ data_.use_history = 0;
+ }
+
+ // if (camera.changed_type) {
+ // data_.use_reprojection = false;
+ // }
+
+ aovs_info.push_update();
+
+ sync_mist();
+}
+
+float2 Film::pixel_jitter_get() const
+{
+ float2 jitter = inst_.sampling.rng_2d_get(SAMPLING_FILTER_U);
+
+ if (data_.filter_size < M_SQRT1_2 && !inst_.camera.is_panoramic()) {
+ /* For filter size less than a pixel, change sampling strategy and use a uniform disk
+ * distribution covering the filter shape. This avoids putting samples in areas without any
+ * weights. */
+ /* TODO(fclem): Importance sampling could be a better option here. */
+ jitter = Sampling::sample_disk(jitter) * data_.filter_size;
+ }
+ else {
+ /* Jitter the size of a whole pixel. */
+ jitter = jitter * 2.0f - 1.0f;
+ }
+ /* TODO(fclem): Mixed-resolution rendering: We need to offset to each of the target pixel covered
+ * by a render pixel, ideally, by choosing one randomly using another sampling dimension, or by
+ * repeating the same sample RNG sequence for each pixel offset. */
+ return jitter;
+}
+
+void Film::update_sample_table()
+{
+ data_.subpixel_offset = pixel_jitter_get();
+
+ int filter_size_ceil = ceilf(data_.filter_size);
+ float filter_size_sqr = square_f(data_.filter_size);
+
+ data_.samples_len = 0;
+ if (data_.filter_size < 0.01f) {
+ /* Disable filtering. */
+ data_.samples[0].texel = int2(0, 0);
+ data_.samples[0].weight = 1.0f;
+ data_.samples_weight_total = 1.0f;
+ data_.samples_len = 1;
+ }
+ /* NOTE: Threshold determined by hand until we don't hit the assert bellow. */
+ else if (data_.filter_size < 2.20f) {
+ /* Small filter Size. */
+ int closest_index = 0;
+ float closest_distance = FLT_MAX;
+ data_.samples_weight_total = 0.0f;
+ /* TODO(fclem): For optimization, could try Z-tile ordering. */
+ for (int y = -filter_size_ceil; y <= filter_size_ceil; y++) {
+ for (int x = -filter_size_ceil; x <= filter_size_ceil; x++) {
+ float2 pixel_offset = float2(x, y) - data_.subpixel_offset;
+ float distance_sqr = math::length_squared(pixel_offset);
+ if (distance_sqr < filter_size_sqr) {
+ if (data_.samples_len >= FILM_PRECOMP_SAMPLE_MAX) {
+ BLI_assert_msg(0, "Precomputed sample table is too small.");
+ break;
+ }
+ FilmSample &sample = data_.samples[data_.samples_len];
+ sample.texel = int2(x, y);
+ sample.weight = film_filter_weight(data_.filter_size, distance_sqr);
+ data_.samples_weight_total += sample.weight;
+
+ if (distance_sqr < closest_distance) {
+ closest_distance = distance_sqr;
+ closest_index = data_.samples_len;
+ }
+ data_.samples_len++;
+ }
+ }
+ }
+ /* Put the closest one in first position. */
+ if (closest_index != 0) {
+ SWAP(FilmSample, data_.samples[closest_index], data_.samples[0]);
+ }
+ }
+ else {
+ /* Large Filter Size. */
+ MutableSpan<FilmSample> sample_table(data_.samples, FILM_PRECOMP_SAMPLE_MAX);
+ /* To avoid hitting driver TDR and slowing rendering too much we use random sampling. */
+ /* TODO(fclem): This case needs more work. We could distribute the samples better to avoid
+ * loading the same pixel twice. */
+ data_.samples_len = sample_table.size();
+ data_.samples_weight_total = 0.0f;
+
+ int i = 0;
+ for (FilmSample &sample : sample_table) {
+ /* TODO(fclem): Own RNG. */
+ float2 random_2d = inst_.sampling.rng_2d_get(SAMPLING_FILTER_U);
+ /* This randomization makes sure we converge to the right result but also makes nearest
+ * neighbor filtering not converging rapidly. */
+ random_2d.x = (random_2d.x + i) / float(FILM_PRECOMP_SAMPLE_MAX);
+
+ float2 pixel_offset = math::floor(Sampling::sample_spiral(random_2d) * data_.filter_size);
+ sample.texel = int2(pixel_offset);
+
+ float distance_sqr = math::length_squared(pixel_offset - data_.subpixel_offset);
+ sample.weight = film_filter_weight(data_.filter_size, distance_sqr);
+ data_.samples_weight_total += sample.weight;
+ i++;
+ }
+ }
+}
+
+void Film::accumulate(const DRWView *view)
+{
+ if (inst_.is_viewport()) {
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data_.offset), UNPACK2(data_.extent));
+ }
+
+ update_sample_table();
+
+ data_.display_only = false;
+ data_.push_update();
+
+ DRW_view_set_active(view);
+ DRW_draw_pass(accumulate_ps_);
+
+ combined_tx_.swap();
+ weight_tx_.swap();
+
+ /* Use history after first sample. */
+ if (data_.use_history == 0) {
+ data_.use_history = 1;
+ data_.use_reprojection = 1;
+ }
+}
+
+void Film::display()
+{
+ BLI_assert(inst_.is_viewport());
+
+ /* Acquire dummy render buffers for correct binding. They will not be used. */
+ inst_.render_buffers.acquire(int2(1), (void *)this);
+
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_viewport_set(dfbl->default_fb, UNPACK2(data_.offset), UNPACK2(data_.extent));
+
+ data_.display_only = true;
+ data_.push_update();
+
+ DRW_view_set_active(nullptr);
+ DRW_draw_pass(accumulate_ps_);
+
+ inst_.render_buffers.release();
+
+ /* IMPORTANT: Do not swap! No accumulation has happened. */
+}
+
+float *Film::read_pass(eViewLayerEEVEEPassType pass_type)
+{
+
+ bool is_value = pass_is_value(pass_type);
+ Texture &accum_tx = (pass_type == EEVEE_RENDER_PASS_COMBINED) ?
+ combined_tx_.current() :
+ (pass_type == EEVEE_RENDER_PASS_Z) ?
+ depth_tx_ :
+ (is_value ? value_accum_tx_ : color_accum_tx_);
+
+ accum_tx.ensure_layer_views();
+
+ int index = pass_id_get(pass_type);
+ GPUTexture *pass_tx = accum_tx.layer_view(index);
+
+ GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
+
+ return (float *)GPU_texture_read(pass_tx, GPU_DATA_FLOAT, 0);
+}
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_film.hh b/source/blender/draw/engines/eevee_next/eevee_film.hh
new file mode 100644
index 00000000000..7ffbd4e45c6
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_film.hh
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * The film class handles accumulation of samples with any distorted camera_type
+ * using a pixel filter. Inputs needs to be jittered so that the filter converges to the right
+ * result.
+ */
+
+#pragma once
+
+#include "DRW_render.h"
+
+#include "eevee_shader_shared.hh"
+
+namespace blender::eevee {
+
+class Instance;
+
+/* -------------------------------------------------------------------- */
+/** \name Film
+ * \{ */
+
+class Film {
+ public:
+ /** Stores indirection table of AOVs based on their name hash and their type. */
+ AOVsInfoDataBuf aovs_info;
+
+ private:
+ Instance &inst_;
+
+ /** Main accumulation textures containing every render-pass except depth and combined. */
+ Texture color_accum_tx_;
+ Texture value_accum_tx_;
+ /** Depth accumulation texture. Separated because using a different format. */
+ Texture depth_tx_;
+ /** Combined "Color" buffer. Double buffered to allow re-projection. */
+ SwapChain<Texture, 2> combined_tx_;
+ /** Weight buffers. Double buffered to allow updating it during accumulation. */
+ SwapChain<Texture, 2> weight_tx_;
+ /** Extent used by the render buffers when rendering the main views. */
+ int2 render_extent_ = int2(-1);
+
+ DRWPass *accumulate_ps_ = nullptr;
+
+ FilmDataBuf data_;
+
+ eViewLayerEEVEEPassType enabled_passes_ = eViewLayerEEVEEPassType(0);
+
+ public:
+ Film(Instance &inst) : inst_(inst){};
+ ~Film(){};
+
+ void init(const int2 &full_extent, const rcti *output_rect);
+
+ void sync();
+ void end_sync();
+
+ /** Accumulate the newly rendered sample contained in #RenderBuffers and blit to display. */
+ void accumulate(const DRWView *view);
+
+ /** Blit to display. No rendered sample needed. */
+ void display();
+
+ float *read_pass(eViewLayerEEVEEPassType pass_type);
+ float *read_aov(ViewLayerAOV *aov);
+
+ int2 render_extent_get() const
+ {
+ return render_extent_;
+ }
+
+ float2 pixel_jitter_get() const;
+
+ eViewLayerEEVEEPassType enabled_passes_get() const
+ {
+ return enabled_passes_;
+ }
+
+ static bool pass_is_value(eViewLayerEEVEEPassType pass_type)
+ {
+ switch (pass_type) {
+ case EEVEE_RENDER_PASS_Z:
+ case EEVEE_RENDER_PASS_MIST:
+ case EEVEE_RENDER_PASS_SHADOW:
+ case EEVEE_RENDER_PASS_AO:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /* Returns layer offset in the accumulation texture. -1 if the pass is not enabled. */
+ int pass_id_get(eViewLayerEEVEEPassType pass_type) const
+ {
+ switch (pass_type) {
+ case EEVEE_RENDER_PASS_COMBINED:
+ return data_.combined_id;
+ case EEVEE_RENDER_PASS_Z:
+ return data_.depth_id;
+ case EEVEE_RENDER_PASS_MIST:
+ return data_.mist_id;
+ case EEVEE_RENDER_PASS_NORMAL:
+ return data_.normal_id;
+ case EEVEE_RENDER_PASS_DIFFUSE_LIGHT:
+ return data_.diffuse_light_id;
+ case EEVEE_RENDER_PASS_DIFFUSE_COLOR:
+ return data_.diffuse_color_id;
+ case EEVEE_RENDER_PASS_SPECULAR_LIGHT:
+ return data_.specular_light_id;
+ case EEVEE_RENDER_PASS_SPECULAR_COLOR:
+ return data_.specular_color_id;
+ case EEVEE_RENDER_PASS_VOLUME_LIGHT:
+ return data_.volume_light_id;
+ case EEVEE_RENDER_PASS_EMIT:
+ return data_.emission_id;
+ case EEVEE_RENDER_PASS_ENVIRONMENT:
+ return data_.environment_id;
+ case EEVEE_RENDER_PASS_SHADOW:
+ return data_.shadow_id;
+ case EEVEE_RENDER_PASS_AO:
+ return data_.ambient_occlusion_id;
+ case EEVEE_RENDER_PASS_CRYPTOMATTE:
+ return -1; /* TODO */
+ case EEVEE_RENDER_PASS_VECTOR:
+ return data_.vector_id;
+ default:
+ return -1;
+ }
+ }
+
+ static const char *pass_to_render_pass_name(eViewLayerEEVEEPassType pass_type)
+ {
+ switch (pass_type) {
+ case EEVEE_RENDER_PASS_COMBINED:
+ return RE_PASSNAME_COMBINED;
+ case EEVEE_RENDER_PASS_Z:
+ return RE_PASSNAME_Z;
+ case EEVEE_RENDER_PASS_MIST:
+ return RE_PASSNAME_MIST;
+ case EEVEE_RENDER_PASS_NORMAL:
+ return RE_PASSNAME_NORMAL;
+ case EEVEE_RENDER_PASS_DIFFUSE_LIGHT:
+ return RE_PASSNAME_DIFFUSE_DIRECT;
+ case EEVEE_RENDER_PASS_DIFFUSE_COLOR:
+ return RE_PASSNAME_DIFFUSE_COLOR;
+ case EEVEE_RENDER_PASS_SPECULAR_LIGHT:
+ return RE_PASSNAME_GLOSSY_DIRECT;
+ case EEVEE_RENDER_PASS_SPECULAR_COLOR:
+ return RE_PASSNAME_GLOSSY_COLOR;
+ case EEVEE_RENDER_PASS_VOLUME_LIGHT:
+ return RE_PASSNAME_VOLUME_LIGHT;
+ case EEVEE_RENDER_PASS_EMIT:
+ return RE_PASSNAME_EMIT;
+ case EEVEE_RENDER_PASS_ENVIRONMENT:
+ return RE_PASSNAME_ENVIRONMENT;
+ case EEVEE_RENDER_PASS_SHADOW:
+ return RE_PASSNAME_SHADOW;
+ case EEVEE_RENDER_PASS_AO:
+ return RE_PASSNAME_AO;
+ case EEVEE_RENDER_PASS_CRYPTOMATTE:
+ BLI_assert_msg(0, "Cryptomatte is not implemented yet.");
+ return ""; /* TODO */
+ case EEVEE_RENDER_PASS_VECTOR:
+ return RE_PASSNAME_VECTOR;
+ default:
+ BLI_assert(0);
+ return "";
+ }
+ }
+
+ private:
+ void init_aovs();
+ void sync_mist();
+
+ /**
+ * Precompute sample weights if they are uniform across the whole film extent.
+ */
+ void update_sample_table();
+};
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc
index 606630bcdef..6098d78b81c 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc
@@ -17,6 +17,7 @@
#include "DNA_ID.h"
#include "DNA_lightprobe_types.h"
#include "DNA_modifier_types.h"
+#include "RE_pipeline.h"
#include "eevee_instance.hh"
@@ -43,7 +44,7 @@ void Instance::init(const int2 &output_res,
const View3D *v3d_,
const RegionView3D *rv3d_)
{
- UNUSED_VARS(light_probe_, output_rect);
+ UNUSED_VARS(light_probe_);
render = render_;
depsgraph = depsgraph_;
camera_orig_object = camera_object_;
@@ -56,7 +57,10 @@ void Instance::init(const int2 &output_res,
update_eval_members();
- main_view.init(output_res);
+ sampling.init(scene);
+ camera.init();
+ film.init(output_res, output_rect);
+ main_view.init();
}
void Instance::set_time(float time)
@@ -90,9 +94,14 @@ void Instance::begin_sync()
materials.begin_sync();
velocity.begin_sync();
+ gpencil_engine_enabled = false;
+
+ render_buffers.sync();
pipelines.sync();
main_view.sync();
world.sync();
+ camera.sync();
+ film.sync();
}
void Instance::object_sync(Object *ob)
@@ -146,13 +155,36 @@ void Instance::object_sync(Object *ob)
ob_handle.reset_recalc_flag();
}
+/* Wrapper to use with DRW_render_object_iter. */
+void Instance::object_sync_render(void *instance_,
+ Object *ob,
+ RenderEngine *engine,
+ Depsgraph *depsgraph)
+{
+ UNUSED_VARS(engine, depsgraph);
+ Instance &inst = *reinterpret_cast<Instance *>(instance_);
+ inst.object_sync(ob);
+}
+
void Instance::end_sync()
{
velocity.end_sync();
+ sampling.end_sync();
+ film.end_sync();
}
void Instance::render_sync()
{
+ DRW_cache_restart();
+
+ begin_sync();
+ DRW_render_object_iter(this, render, depsgraph, object_sync_render);
+ end_sync();
+
+ DRW_render_instance_buffer_finish();
+ /* Also we weed to have a correct FBO bound for #DRW_hair_update */
+ // GPU_framebuffer_bind();
+ // DRW_hair_update();
}
/** \} */
@@ -167,6 +199,18 @@ void Instance::render_sync()
**/
void Instance::render_sample()
{
+ if (sampling.finished()) {
+ film.display();
+ return;
+ }
+
+ /* Motion blur may need to do re-sync after a certain number of sample. */
+ if (!is_viewport() && sampling.do_render_sync()) {
+ render_sync();
+ }
+
+ sampling.step();
+
main_view.render();
}
@@ -178,7 +222,36 @@ void Instance::render_sample()
void Instance::render_frame(RenderLayer *render_layer, const char *view_name)
{
- UNUSED_VARS(render_layer, view_name);
+ while (!sampling.finished()) {
+ this->render_sample();
+ /* TODO(fclem) print progression. */
+ }
+
+ /* Read Results. */
+ eViewLayerEEVEEPassType pass_bits = film.enabled_passes_get();
+ for (auto i : IndexRange(EEVEE_RENDER_PASS_MAX_BIT)) {
+ eViewLayerEEVEEPassType pass_type = eViewLayerEEVEEPassType(pass_bits & (1 << i));
+ if (pass_type == 0) {
+ continue;
+ }
+
+ const char *pass_name = Film::pass_to_render_pass_name(pass_type);
+ RenderPass *rp = RE_pass_find_by_name(render_layer, pass_name, view_name);
+ if (rp) {
+ float *result = film.read_pass(pass_type);
+ if (result) {
+ std::cout << "read " << pass_name << std::endl;
+ BLI_mutex_lock(&render->update_render_passes_mutex);
+ /* WORKAROUND: We use texture read to avoid using a framebuffer to get the render result.
+ * However, on some implementation, we need a buffer with a few extra bytes for the read to
+ * happen correctly (see GLTexture::read()). So we need a custom memory allocation. */
+ /* Avoid memcpy(), replace the pointer directly. */
+ MEM_SAFE_FREE(rp->rect);
+ rp->rect = result;
+ BLI_mutex_unlock(&render->update_render_passes_mutex);
+ }
+ }
+ }
}
void Instance::draw_viewport(DefaultFramebufferList *dfbl)
@@ -187,6 +260,10 @@ void Instance::draw_viewport(DefaultFramebufferList *dfbl)
render_sample();
velocity.step_swap();
+ if (!sampling.finished_viewport()) {
+ DRW_viewport_request_redraw();
+ }
+
if (materials.queued_shaders_count > 0) {
std::stringstream ss;
ss << "Compiling Shaders " << materials.queued_shaders_count;
diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh
index 84be59fc5f0..f47d4f20363 100644
--- a/source/blender/draw/engines/eevee_next/eevee_instance.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh
@@ -16,8 +16,11 @@
#include "DRW_render.h"
#include "eevee_camera.hh"
+#include "eevee_film.hh"
#include "eevee_material.hh"
#include "eevee_pipeline.hh"
+#include "eevee_renderbuffers.hh"
+#include "eevee_sampling.hh"
#include "eevee_shader.hh"
#include "eevee_sync.hh"
#include "eevee_view.hh"
@@ -38,7 +41,10 @@ class Instance {
MaterialModule materials;
PipelineModule pipelines;
VelocityModule velocity;
+ Sampling sampling;
Camera camera;
+ Film film;
+ RenderBuffers render_buffers;
MainView main_view;
World world;
@@ -57,6 +63,9 @@ class Instance {
const View3D *v3d;
const RegionView3D *rv3d;
+ /** True if the grease pencil engine might be running. */
+ bool gpencil_engine_enabled;
+
/* Info string displayed at the top of the render / viewport. */
std::string info = "";
@@ -67,7 +76,10 @@ class Instance {
materials(*this),
pipelines(*this),
velocity(*this),
+ sampling(*this),
camera(*this),
+ film(*this),
+ render_buffers(*this),
main_view(*this),
world(*this){};
~Instance(){};
@@ -92,12 +104,17 @@ class Instance {
void draw_viewport(DefaultFramebufferList *dfbl);
- bool is_viewport(void)
+ bool is_viewport() const
+ {
+ return render == nullptr;
+ }
+
+ bool overlays_enabled() const
{
- return !DRW_state_is_scene_render();
+ return (!v3d) || ((v3d->flag & V3D_HIDE_OVERLAYS) == 0);
}
- bool use_scene_lights(void) const
+ bool use_scene_lights() const
{
return (!v3d) ||
((v3d->shading.type == OB_MATERIAL) &&
@@ -107,7 +124,7 @@ class Instance {
}
/* Light the scene using the selected HDRI in the viewport shading pop-over. */
- bool use_studio_light(void) const
+ bool use_studio_light() const
{
return (v3d) && (((v3d->shading.type == OB_MATERIAL) &&
((v3d->shading.flag & V3D_SHADING_SCENE_WORLD) == 0)) ||
@@ -116,6 +133,10 @@ class Instance {
}
private:
+ static void object_sync_render(void *instance_,
+ Object *ob,
+ RenderEngine *engine,
+ Depsgraph *depsgraph);
void render_sample();
void mesh_sync(Object *ob, ObjectHandle &ob_handle);
diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc
index 1676c89d679..b3161a67092 100644
--- a/source/blender/draw/engines/eevee_next/eevee_material.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_material.cc
@@ -195,7 +195,7 @@ MaterialPass MaterialModule::material_pass_get(::Material *blender_mat,
BLI_assert(GPU_material_status(matpass.gpumat) == GPU_MAT_SUCCESS);
if (GPU_material_recalc_flag_get(matpass.gpumat)) {
- // inst_.sampling.reset();
+ inst_.sampling.reset();
}
if ((pipeline_type == MAT_PIPE_DEFERRED) &&
diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
index 33853eba06c..7b3cfbf5899 100644
--- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc
@@ -24,6 +24,8 @@ namespace blender::eevee {
void WorldPipeline::sync(GPUMaterial *gpumat)
{
+ RenderBuffers &rbufs = inst_.render_buffers;
+
DRWState state = DRW_STATE_WRITE_COLOR;
world_ps_ = DRW_pass_create("World", state);
@@ -34,6 +36,19 @@ void WorldPipeline::sync(GPUMaterial *gpumat)
DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, world_ps_);
DRW_shgroup_uniform_texture(grp, "utility_tx", inst_.pipelines.utility_tx);
DRW_shgroup_call_obmat(grp, DRW_cache_fullscreen_quad_get(), camera_mat.ptr());
+ /* AOVs. */
+ DRW_shgroup_uniform_image_ref(grp, "aov_color_img", &rbufs.aov_color_tx);
+ DRW_shgroup_uniform_image_ref(grp, "aov_value_img", &rbufs.aov_value_tx);
+ DRW_shgroup_storage_block_ref(grp, "aov_buf", &inst_.film.aovs_info);
+ /* RenderPasses. Cleared by background (even if bad practice). */
+ DRW_shgroup_uniform_image_ref(grp, "rp_normal_img", &rbufs.normal_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_light_img", &rbufs.diffuse_light_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_color_img", &rbufs.diffuse_color_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_specular_light_img", &rbufs.specular_light_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_specular_color_img", &rbufs.specular_color_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_emission_img", &rbufs.emission_tx);
+ /* To allow opaque pass rendering over it. */
+ DRW_shgroup_barrier(grp, GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
void WorldPipeline::render()
@@ -83,6 +98,7 @@ void ForwardPipeline::sync()
DRWShadingGroup *ForwardPipeline::material_opaque_add(::Material *blender_mat, GPUMaterial *gpumat)
{
+ RenderBuffers &rbufs = inst_.render_buffers;
DRWPass *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? opaque_culled_ps_ : opaque_ps_;
// LightModule &lights = inst_.lights;
// LightProbeModule &lightprobes = inst_.lightprobes;
@@ -97,6 +113,18 @@ DRWShadingGroup *ForwardPipeline::material_opaque_add(::Material *blender_mat, G
// DRW_shgroup_uniform_texture_ref(grp, "lightprobe_grid_tx", lightprobes.grid_tx_ref_get());
// DRW_shgroup_uniform_texture_ref(grp, "lightprobe_cube_tx", lightprobes.cube_tx_ref_get());
DRW_shgroup_uniform_texture(grp, "utility_tx", inst_.pipelines.utility_tx);
+ /* AOVs. */
+ DRW_shgroup_uniform_image_ref(grp, "aov_color_img", &rbufs.aov_color_tx);
+ DRW_shgroup_uniform_image_ref(grp, "aov_value_img", &rbufs.aov_value_tx);
+ DRW_shgroup_storage_block_ref(grp, "aov_buf", &inst_.film.aovs_info);
+ /* RenderPasses. */
+ DRW_shgroup_uniform_image_ref(grp, "rp_normal_img", &rbufs.normal_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_light_img", &rbufs.diffuse_light_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_diffuse_color_img", &rbufs.diffuse_color_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_specular_light_img", &rbufs.specular_light_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_specular_color_img", &rbufs.specular_color_tx);
+ DRW_shgroup_uniform_image_ref(grp, "rp_emission_img", &rbufs.emission_tx);
+
/* TODO(fclem): Make this only needed if material uses it ... somehow. */
// if (true) {
// DRW_shgroup_uniform_texture_ref(
diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc
new file mode 100644
index 00000000000..6e30ba989df
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.cc
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * A film is a fullscreen buffer (usually at output extent)
+ * that will be able to accumulate sample in any distorted camera_type
+ * using a pixel filter.
+ *
+ * Input needs to be jittered so that the filter converges to the right result.
+ */
+
+#include "BLI_rect.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
+
+#include "DRW_render.h"
+
+#include "eevee_film.hh"
+#include "eevee_instance.hh"
+
+namespace blender::eevee {
+
+void RenderBuffers::sync()
+{
+ depth_tx.sync();
+ combined_tx.sync();
+
+ normal_tx.sync();
+ vector_tx.sync();
+ diffuse_light_tx.sync();
+ diffuse_color_tx.sync();
+ specular_light_tx.sync();
+ specular_color_tx.sync();
+ volume_light_tx.sync();
+ emission_tx.sync();
+ environment_tx.sync();
+ shadow_tx.sync();
+ ambient_occlusion_tx.sync();
+}
+
+void RenderBuffers::acquire(int2 extent, void *owner)
+{
+ auto pass_extent = [&](eViewLayerEEVEEPassType pass_bit) -> int2 {
+ /* Use dummy texture for disabled passes. Allows correct bindings. */
+ return (inst_.film.enabled_passes_get() & pass_bit) ? extent : int2(1);
+ };
+
+ eGPUTextureFormat color_format = GPU_RGBA16F;
+ eGPUTextureFormat float_format = GPU_R16F;
+
+ /* Depth and combined are always needed. */
+ depth_tx.acquire(extent, GPU_DEPTH24_STENCIL8, owner);
+ combined_tx.acquire(extent, color_format, owner);
+
+ normal_tx.acquire(pass_extent(EEVEE_RENDER_PASS_NORMAL), color_format, owner);
+ vector_tx.acquire(pass_extent(EEVEE_RENDER_PASS_VECTOR), color_format, owner);
+ diffuse_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_LIGHT), color_format, owner);
+ diffuse_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_DIFFUSE_COLOR), color_format, owner);
+ specular_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_LIGHT), color_format, owner);
+ specular_color_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SPECULAR_COLOR), color_format, owner);
+ volume_light_tx.acquire(pass_extent(EEVEE_RENDER_PASS_VOLUME_LIGHT), color_format, owner);
+ emission_tx.acquire(pass_extent(EEVEE_RENDER_PASS_EMIT), color_format, owner);
+ environment_tx.acquire(pass_extent(EEVEE_RENDER_PASS_ENVIRONMENT), color_format, owner);
+ shadow_tx.acquire(pass_extent(EEVEE_RENDER_PASS_SHADOW), float_format, owner);
+ ambient_occlusion_tx.acquire(pass_extent(EEVEE_RENDER_PASS_AO), float_format, owner);
+
+ const AOVsInfoData &aovs = inst_.film.aovs_info;
+ aov_color_tx.ensure_2d_array(
+ color_format, (aovs.color_len > 0) ? extent : int2(1), max_ii(1, aovs.color_len));
+ aov_value_tx.ensure_2d_array(
+ float_format, (aovs.value_len > 0) ? extent : int2(1), max_ii(1, aovs.value_len));
+}
+
+void RenderBuffers::release()
+{
+ depth_tx.release();
+ combined_tx.release();
+
+ normal_tx.release();
+ vector_tx.release();
+ diffuse_light_tx.release();
+ diffuse_color_tx.release();
+ specular_light_tx.release();
+ specular_color_tx.release();
+ volume_light_tx.release();
+ emission_tx.release();
+ environment_tx.release();
+ shadow_tx.release();
+ ambient_occlusion_tx.release();
+}
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh
new file mode 100644
index 00000000000..8c91fed2f0f
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_renderbuffers.hh
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * Render buffers are textures that are filled during a view rendering.
+ * Their content is then added to the accumulation buffers of the film class.
+ * They are short lived and can be reused when doing multi view rendering.
+ */
+
+#pragma once
+
+#include "DRW_render.h"
+
+#include "eevee_shader_shared.hh"
+
+namespace blender::eevee {
+
+class Instance;
+
+class RenderBuffers {
+ public:
+ TextureFromPool depth_tx;
+ TextureFromPool combined_tx;
+
+ // TextureFromPool mist_tx; /* Derived from depth_tx during accumulation. */
+ TextureFromPool normal_tx;
+ TextureFromPool vector_tx;
+ TextureFromPool diffuse_light_tx;
+ TextureFromPool diffuse_color_tx;
+ TextureFromPool specular_light_tx;
+ TextureFromPool specular_color_tx;
+ TextureFromPool volume_light_tx;
+ TextureFromPool emission_tx;
+ TextureFromPool environment_tx;
+ TextureFromPool shadow_tx;
+ TextureFromPool ambient_occlusion_tx;
+ // TextureFromPool cryptomatte_tx; /* TODO */
+ /* TODO(fclem): Use texture from pool once they support texture array. */
+ Texture aov_color_tx;
+ Texture aov_value_tx;
+
+ private:
+ Instance &inst_;
+
+ public:
+ RenderBuffers(Instance &inst) : inst_(inst){};
+
+ void sync();
+ /* Acquires (also ensures) the render buffer before rendering to them. */
+ void acquire(int2 extent, void *owner);
+ void release();
+};
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_sampling.cc b/source/blender/draw/engines/eevee_next/eevee_sampling.cc
new file mode 100644
index 00000000000..2f180e58a0b
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_sampling.cc
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * Random number generator, contains persistent state and sample count logic.
+ */
+
+#include "BLI_rand.h"
+
+#include "eevee_instance.hh"
+#include "eevee_sampling.hh"
+
+namespace blender::eevee {
+
+/* -------------------------------------------------------------------- */
+/** \name Sampling
+ * \{ */
+
+void Sampling::init(const Scene *scene)
+{
+ sample_count_ = inst_.is_viewport() ? scene->eevee.taa_samples : scene->eevee.taa_render_samples;
+
+ if (sample_count_ == 0) {
+ BLI_assert(inst_.is_viewport());
+ sample_count_ = infinite_sample_count_;
+ }
+
+ motion_blur_steps_ = !inst_.is_viewport() ? scene->eevee.motion_blur_steps : 1;
+ sample_count_ = divide_ceil_u(sample_count_, motion_blur_steps_);
+
+ if (scene->eevee.flag & SCE_EEVEE_DOF_JITTER) {
+ if (sample_count_ == infinite_sample_count_) {
+ /* Special case for viewport continuous rendering. We clamp to a max sample
+ * to avoid the jittered dof never converging. */
+ dof_ring_count_ = 6;
+ }
+ else {
+ dof_ring_count_ = sampling_web_ring_count_get(dof_web_density_, sample_count_);
+ }
+ dof_sample_count_ = sampling_web_sample_count_get(dof_web_density_, dof_ring_count_);
+ /* Change total sample count to fill the web pattern entirely. */
+ sample_count_ = divide_ceil_u(sample_count_, dof_sample_count_) * dof_sample_count_;
+ }
+ else {
+ dof_ring_count_ = 0;
+ dof_sample_count_ = 1;
+ }
+
+ /* Only multiply after to have full the full DoF web pattern for each time steps. */
+ sample_count_ *= motion_blur_steps_;
+}
+
+void Sampling::end_sync()
+{
+ if (reset_) {
+ viewport_sample_ = 0;
+ if (inst_.is_viewport()) {
+ interactive_mode_ = true;
+ }
+ }
+
+ if (interactive_mode_) {
+ int interactive_sample_count = min_ii(interactive_sample_max_, sample_count_);
+
+ if (viewport_sample_ < interactive_sample_count) {
+ /* Loop over the same starting samples. */
+ sample_ = sample_ % interactive_sample_count;
+ }
+ else {
+ /* Break out of the loop and resume normal pattern. */
+ sample_ = interactive_sample_count;
+ interactive_mode_ = false;
+ }
+ }
+}
+
+void Sampling::step()
+{
+ {
+ /* TODO(fclem) we could use some persistent states to speedup the computation. */
+ double2 r, offset = {0, 0};
+ /* Using 2,3 primes as per UE4 Temporal AA presentation.
+ * http://advances.realtimerendering.com/s2014/epic/TemporalAA.pptx (slide 14) */
+ uint2 primes = {2, 3};
+ BLI_halton_2d(primes, offset, sample_ + 1, r);
+ /* WORKAROUND: We offset the distribution to make the first sample (0,0). This way, we are
+ * assured that at least one of the samples inside the TAA rotation will match the one from the
+ * draw manager. This makes sure overlays are correctly composited in static scene. */
+ data_.dimensions[SAMPLING_FILTER_U] = fractf(r[0] + (1.0 / 2.0));
+ data_.dimensions[SAMPLING_FILTER_V] = fractf(r[1] + (2.0 / 3.0));
+ /* TODO de-correlate. */
+ data_.dimensions[SAMPLING_TIME] = r[0];
+ data_.dimensions[SAMPLING_CLOSURE] = r[1];
+ data_.dimensions[SAMPLING_RAYTRACE_X] = r[0];
+ }
+ {
+ double2 r, offset = {0, 0};
+ uint2 primes = {5, 7};
+ BLI_halton_2d(primes, offset, sample_ + 1, r);
+ data_.dimensions[SAMPLING_LENS_U] = r[0];
+ data_.dimensions[SAMPLING_LENS_V] = r[1];
+ /* TODO de-correlate. */
+ data_.dimensions[SAMPLING_LIGHTPROBE] = r[0];
+ data_.dimensions[SAMPLING_TRANSPARENCY] = r[1];
+ }
+ {
+ /* Using leaped Halton sequence so we can reused the same primes as lens. */
+ double3 r, offset = {0, 0, 0};
+ uint64_t leap = 11;
+ uint3 primes = {5, 4, 7};
+ BLI_halton_3d(primes, offset, sample_ * leap, r);
+ data_.dimensions[SAMPLING_SHADOW_U] = r[0];
+ data_.dimensions[SAMPLING_SHADOW_V] = r[1];
+ data_.dimensions[SAMPLING_SHADOW_W] = r[2];
+ /* TODO de-correlate. */
+ data_.dimensions[SAMPLING_RAYTRACE_U] = r[0];
+ data_.dimensions[SAMPLING_RAYTRACE_V] = r[1];
+ data_.dimensions[SAMPLING_RAYTRACE_W] = r[2];
+ }
+ {
+ /* Using leaped Halton sequence so we can reused the same primes. */
+ double2 r, offset = {0, 0};
+ uint64_t leap = 5;
+ uint2 primes = {2, 3};
+ BLI_halton_2d(primes, offset, sample_ * leap, r);
+ data_.dimensions[SAMPLING_SHADOW_X] = r[0];
+ data_.dimensions[SAMPLING_SHADOW_Y] = r[1];
+ /* TODO de-correlate. */
+ data_.dimensions[SAMPLING_SSS_U] = r[0];
+ data_.dimensions[SAMPLING_SSS_V] = r[1];
+ }
+
+ data_.push_update();
+
+ viewport_sample_++;
+ sample_++;
+
+ std::cout << sample_ << " " << viewport_sample_ << std::endl;
+
+ reset_ = false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sampling patterns
+ * \{ */
+
+float3 Sampling::sample_ball(const float3 &rand)
+{
+ float3 sample;
+ sample.z = rand.x * 2.0f - 1.0f; /* cos theta */
+
+ float r = sqrtf(fmaxf(0.0f, 1.0f - square_f(sample.z))); /* sin theta */
+
+ float omega = rand.y * 2.0f * M_PI;
+ sample.x = r * cosf(omega);
+ sample.y = r * sinf(omega);
+
+ sample *= sqrtf(sqrtf(rand.z));
+ return sample;
+}
+
+float2 Sampling::sample_disk(const float2 &rand)
+{
+ float omega = rand.y * 2.0f * M_PI;
+ return sqrtf(rand.x) * float2(cosf(omega), sinf(omega));
+}
+
+float2 Sampling::sample_spiral(const float2 &rand)
+{
+ /* Fibonacci spiral. */
+ float omega = M_PI * (1.0f + sqrtf(5.0f)) * rand.x;
+ float r = sqrtf(rand.x);
+ /* Random rotation. */
+ omega += rand.y * 2.0f * M_PI;
+ return r * float2(cosf(omega), sinf(omega));
+}
+
+void Sampling::dof_disk_sample_get(float *r_radius, float *r_theta) const
+{
+ if (dof_ring_count_ == 0) {
+ *r_radius = *r_theta = 0.0f;
+ return;
+ }
+
+ int s = sample_ - 1;
+ int ring = 0;
+ int ring_sample_count = 1;
+ int ring_sample = 1;
+
+ s = s * (dof_web_density_ - 1);
+ s = s % dof_sample_count_;
+
+ /* Choosing sample to we get faster convergence.
+ * The issue here is that we cannot map a low discrepancy sequence to this sampling pattern
+ * because the same sample could be chosen twice in relatively short intervals. */
+ /* For now just use an ascending sequence with an offset. This gives us relatively quick
+ * initial coverage and relatively high distance between samples. */
+ /* TODO(@fclem) We can try to order samples based on a LDS into a table to avoid duplicates.
+ * The drawback would be some memory consumption and initialize time. */
+ int samples_passed = 1;
+ while (s >= samples_passed) {
+ ring++;
+ ring_sample_count = ring * dof_web_density_;
+ ring_sample = s - samples_passed;
+ ring_sample = (ring_sample + 1) % ring_sample_count;
+ samples_passed += ring_sample_count;
+ }
+
+ *r_radius = ring / (float)dof_ring_count_;
+ *r_theta = 2.0f * M_PI * ring_sample / (float)ring_sample_count;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sampling patterns
+ * \{ */
+
+/* Creates a discrete cumulative distribution function table from a given curvemapping.
+ * Output cdf vector is expected to already be sized according to the wanted resolution. */
+void Sampling::cdf_from_curvemapping(const CurveMapping &curve, Vector<float> &cdf)
+{
+ BLI_assert(cdf.size() > 1);
+ cdf[0] = 0.0f;
+ /* Actual CDF evaluation. */
+ for (int u : cdf.index_range()) {
+ float x = (float)(u + 1) / (float)(cdf.size() - 1);
+ cdf[u + 1] = cdf[u] + BKE_curvemapping_evaluateF(&curve, 0, x);
+ }
+ /* Normalize the CDF. */
+ for (int u : cdf.index_range()) {
+ cdf[u] /= cdf.last();
+ }
+ /* Just to make sure. */
+ cdf.last() = 1.0f;
+}
+
+/* Inverts a cumulative distribution function.
+ * Output vector is expected to already be sized according to the wanted resolution. */
+void Sampling::cdf_invert(Vector<float> &cdf, Vector<float> &inverted_cdf)
+{
+ for (int u : inverted_cdf.index_range()) {
+ float x = (float)u / (float)(inverted_cdf.size() - 1);
+ for (int i : cdf.index_range()) {
+ if (i == cdf.size() - 1) {
+ inverted_cdf[u] = 1.0f;
+ }
+ else if (cdf[i] >= x) {
+ float t = (x - cdf[i]) / (cdf[i + 1] - cdf[i]);
+ inverted_cdf[u] = ((float)i + t) / (float)(cdf.size() - 1);
+ break;
+ }
+ }
+ }
+}
+
+/** \} */
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_sampling.hh b/source/blender/draw/engines/eevee_next/eevee_sampling.hh
new file mode 100644
index 00000000000..11daa21629a
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_sampling.hh
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+/** \file
+ * \ingroup eevee
+ *
+ * Random number generator, contains persistent state and sample count logic.
+ */
+
+#pragma once
+
+#include "BKE_colortools.h"
+#include "BLI_system.h"
+#include "BLI_vector.hh"
+#include "DNA_scene_types.h"
+#include "DRW_render.h"
+
+#include "eevee_shader_shared.hh"
+
+namespace blender::eevee {
+
+class Instance;
+
+class Sampling {
+ private:
+ Instance &inst_;
+
+ /* Number of samples in the first ring of jittered depth of field. */
+ constexpr static uint64_t dof_web_density_ = 6;
+ /* High number of sample for viewport infinite rendering. */
+ constexpr static uint64_t infinite_sample_count_ = 0xFFFFFFu;
+ /* During interactive rendering, loop over the first few samples. */
+ constexpr static uint64_t interactive_sample_max_ = 8;
+
+ /** 0 based current sample. */
+ uint64_t sample_ = 0;
+ /** Target sample count. */
+ uint64_t sample_count_ = 64;
+ /** Number of ring in the web pattern of the jittered Depth of Field. */
+ uint64_t dof_ring_count_ = 0;
+ /** Number of samples in the web pattern of the jittered Depth of Field. */
+ uint64_t dof_sample_count_ = 1;
+ /** Motion blur steps. */
+ uint64_t motion_blur_steps_ = 1;
+ /** Increases if the view and the scene is static. */
+ int64_t viewport_sample_ = 0;
+ /** Tag to reset sampling for the next sample. */
+ bool reset_ = false;
+ /**
+ * Switch between interactive and static accumulation.
+ * In interactive mode, image stability is prioritized over quality.
+ */
+ bool interactive_mode_ = false;
+
+ SamplingDataBuf data_;
+
+ public:
+ Sampling(Instance &inst) : inst_(inst){};
+ ~Sampling(){};
+
+ void init(const Scene *scene);
+ void end_sync();
+ void step();
+
+ /* Viewport Only: Function to call to notify something in the scene changed.
+ * This will reset accumulation. Do not call after end_sync() or during sample rendering. */
+ void reset()
+ {
+ reset_ = true;
+ }
+
+ /* Viewport Only: true if an update happened in the scene and accumulation needs reset. */
+ bool is_reset() const
+ {
+ return reset_;
+ }
+
+ void bind_resources(DRWShadingGroup *grp)
+ {
+ DRW_shgroup_storage_block_ref(grp, "sampling_buf", &data_);
+ }
+
+ /* Returns a pseudo random number in [0..1] range. Each dimension are de-correlated. */
+ float rng_get(eSamplingDimension dimension) const
+ {
+ return data_.dimensions[dimension];
+ }
+
+ /* Returns a pseudo random number in [0..1] range. Each dimension are de-correlated. */
+ float2 rng_2d_get(eSamplingDimension starting_dimension) const
+ {
+ return *reinterpret_cast<const float2 *>(&data_.dimensions[starting_dimension]);
+ }
+
+ /* Returns a pseudo random number in [0..1] range. Each dimension are de-correlated. */
+ float3 rng_3d_get(eSamplingDimension starting_dimension) const
+ {
+ return *reinterpret_cast<const float3 *>(&data_.dimensions[starting_dimension]);
+ }
+
+ /* Returns true if rendering has finished. */
+ bool finished() const
+ {
+ return (sample_ >= sample_count_ - 1);
+ }
+
+ /* Returns true if viewport smoothing and sampling has finished. */
+ bool finished_viewport() const
+ {
+ return finished() && (viewport_sample_ >= interactive_sample_max_);
+ }
+
+ /* Return true if we are starting a new motion blur step. We need to run sync again since
+ * depsgraph was updated by MotionBlur::step(). */
+ bool do_render_sync() const
+ {
+ return ((sample_ % (sample_count_ / motion_blur_steps_)) == 0);
+ }
+
+ /**
+ * Special ball distribution:
+ * Point are distributed in a way that when they are orthogonally
+ * projected into any plane, the resulting distribution is (close to)
+ * a uniform disc distribution.
+ * \a rand is 3 random float in the [0..1] range.
+ * Returns point in a ball of radius 1 and centered on the origin.
+ */
+ static float3 sample_ball(const float3 &rand);
+
+ /**
+ * Uniform disc distribution.
+ * \a rand is 2 random float in the [0..1] range.
+ * Returns point in a disk of radius 1 and centered on the origin.
+ */
+ static float2 sample_disk(const float2 &rand);
+
+ /**
+ * Uniform disc distribution using Fibonacci spiral sampling.
+ * \a rand is 2 random float in the [0..1] range.
+ * Returns point in a disk of radius 1 and centered on the origin.
+ */
+ static float2 sample_spiral(const float2 &rand);
+
+ /**
+ * Special RNG for depth of field.
+ * Returns \a radius and \a theta angle offset to apply to the web sampling pattern.
+ */
+ void dof_disk_sample_get(float *r_radius, float *r_theta) const;
+
+ /**
+ * Returns sample count inside the jittered depth of field web pattern.
+ */
+ uint64_t dof_ring_count_get() const
+ {
+ return dof_ring_count_;
+ }
+
+ /**
+ * Returns sample count inside the jittered depth of field web pattern.
+ */
+ uint64_t dof_sample_count_get() const
+ {
+ return dof_sample_count_;
+ }
+
+ /* Cumulative Distribution Function Utils. */
+ static void cdf_from_curvemapping(const CurveMapping &curve, Vector<float> &cdf);
+ static void cdf_invert(Vector<float> &cdf, Vector<float> &inverted_cdf);
+};
+
+} // namespace blender::eevee
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc
index 09aa97e49e9..f5d4af2914e 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc
@@ -78,6 +78,10 @@ ShaderModule::~ShaderModule()
const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_type)
{
switch (shader_type) {
+ case FILM_FRAG:
+ return "eevee_film_frag";
+ case FILM_COMP:
+ return "eevee_film_comp";
case VELOCITY_RESOLVE:
return "eevee_velocity_resolve";
/* To avoid compiler warning about missing case. */
@@ -161,7 +165,6 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
}
}
info.vertex_inputs_.clear();
- info.additional_info("draw_curves_infos");
break;
case MAT_GEOM_WORLD:
/**
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh
index 0f42e880a10..7a0867820af 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh
@@ -26,7 +26,10 @@ namespace blender::eevee {
/* Keep alphabetical order and clean prefix. */
enum eShaderType {
- VELOCITY_RESOLVE = 0,
+ FILM_FRAG = 0,
+ FILM_COMP,
+
+ VELOCITY_RESOLVE,
MAX_SHADER_TYPE,
};
diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
index 1261c855a82..62eb5a2b965 100644
--- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh
@@ -12,7 +12,7 @@
# include "BLI_memory_utils.hh"
# include "DRW_gpu_wrapper.hh"
-// # include "eevee_defines.hh"
+# include "eevee_defines.hh"
# include "GPU_shader_shared.h"
@@ -28,6 +28,63 @@ using draw::TextureFromPool;
#define UBO_MIN_MAX_SUPPORTED_SIZE 1 << 14
/* -------------------------------------------------------------------- */
+/** \name Sampling
+ * \{ */
+
+enum eSamplingDimension : uint32_t {
+ SAMPLING_FILTER_U = 0u,
+ SAMPLING_FILTER_V = 1u,
+ SAMPLING_LENS_U = 2u,
+ SAMPLING_LENS_V = 3u,
+ SAMPLING_TIME = 4u,
+ SAMPLING_SHADOW_U = 5u,
+ SAMPLING_SHADOW_V = 6u,
+ SAMPLING_SHADOW_W = 7u,
+ SAMPLING_SHADOW_X = 8u,
+ SAMPLING_SHADOW_Y = 9u,
+ SAMPLING_CLOSURE = 10u,
+ SAMPLING_LIGHTPROBE = 11u,
+ SAMPLING_TRANSPARENCY = 12u,
+ SAMPLING_SSS_U = 13u,
+ SAMPLING_SSS_V = 14u,
+ SAMPLING_RAYTRACE_U = 15u,
+ SAMPLING_RAYTRACE_V = 16u,
+ SAMPLING_RAYTRACE_W = 17u,
+ SAMPLING_RAYTRACE_X = 18u
+};
+
+/**
+ * IMPORTANT: Make sure the array can contain all sampling dimensions.
+ * Also note that it needs to be multiple of 4.
+ */
+#define SAMPLING_DIMENSION_COUNT 20
+
+/* NOTE(@fclem): Needs to be used in #StorageBuffer because of arrays of scalar. */
+struct SamplingData {
+ /** Array containing random values from Low Discrepancy Sequence in [0..1) range. */
+ float dimensions[SAMPLING_DIMENSION_COUNT];
+};
+BLI_STATIC_ASSERT_ALIGN(SamplingData, 16)
+
+/* Returns total sample count in a web pattern of the given size. */
+static inline int sampling_web_sample_count_get(int web_density, int ring_count)
+{
+ return ((ring_count * ring_count + ring_count) / 2) * web_density + 1;
+}
+
+/* Returns lowest possible ring count that contains at least sample_count samples. */
+static inline int sampling_web_ring_count_get(int web_density, int sample_count)
+{
+ /* Inversion of web_sample_count_get(). */
+ float x = 2.0f * (float(sample_count) - 1.0f) / float(web_density);
+ /* Solving polynomial. We only search positive solution. */
+ float discriminant = 1.0f + 4.0f * x;
+ return int(ceilf(0.5f * (sqrtf(discriminant) - 1.0f)));
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Camera
* \{ */
@@ -65,15 +122,137 @@ struct CameraData {
/** Clipping distances. */
float clip_near;
float clip_far;
- /** Film pixel filter radius. */
- float filter_size;
eCameraType type;
+
+ int _pad0;
};
BLI_STATIC_ASSERT_ALIGN(CameraData, 16)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Film
+ * \{ */
+
+#define FILM_PRECOMP_SAMPLE_MAX 16
+
+struct FilmSample {
+ int2 texel;
+ float weight;
+ /** Used for accumulation. */
+ float weight_sum_inv;
+};
+BLI_STATIC_ASSERT_ALIGN(FilmSample, 16)
+
+struct FilmData {
+ /** Size of the film in pixels. */
+ int2 extent;
+ /** Offset of the film in the full-res frame, in pixels. */
+ int2 offset;
+ /** Sub-pixel offset applied to the window matrix.
+ * NOTE: In final film pixel unit.
+ * NOTE: Positive values makes the view translate in the negative axes direction.
+ * NOTE: The origin is the center of the lower left film pixel of the area covered by a render
+ * pixel if using scaled resolution rendering.
+ */
+ float2 subpixel_offset;
+ /** Is true if history is valid and can be sampled. Bypass history to resets accumulation. */
+ bool1 use_history;
+ /** Is true if combined buffer is valid and can be re-projected to reduce variance. */
+ bool1 use_reprojection;
+ /** Is true if accumulation of non-filtered passes is needed. */
+ bool1 has_data;
+ /** Is true if accumulation of filtered passes is needed. */
+ bool1 any_render_pass_1;
+ bool1 any_render_pass_2;
+ int _pad0, _pad1;
+ /** Output counts per type. */
+ int color_len, value_len;
+ /** Index in color_accum_img or value_accum_img of each pass. -1 if pass is not enabled. */
+ int mist_id;
+ int normal_id;
+ int vector_id;
+ int diffuse_light_id;
+ int diffuse_color_id;
+ int specular_light_id;
+ int specular_color_id;
+ int volume_light_id;
+ int emission_id;
+ int environment_id;
+ int shadow_id;
+ int ambient_occlusion_id;
+ /** Not indexed but still not -1 if enabled. */
+ int depth_id;
+ int combined_id;
+ /** Id of the render-pass to be displayed. -1 for combined. */
+ int display_id;
+ /** True if the render-pass to be displayed is from the value accum buffer. */
+ bool1 display_is_value;
+ /** True if we bypass the accumulation and directly output the accumulation buffer. */
+ bool1 display_only;
+ /** Start of AOVs and number of aov. */
+ int aov_color_id, aov_color_len;
+ int aov_value_id, aov_value_len;
+ /** Settings to render mist pass */
+ float mist_scale, mist_bias, mist_exponent;
+ /** Scene exposure used for better noise reduction. */
+ float exposure;
+ /** Scaling factor for scaled resolution rendering. */
+ int scaling_factor;
+ /** Film pixel filter radius. */
+ float filter_size;
+ /** Precomputed samples. First in the table is the closest one. The rest is unordered. */
+ int samples_len;
+ /** Sum of the weights of all samples in the sample table. */
+ float samples_weight_total;
+ FilmSample samples[FILM_PRECOMP_SAMPLE_MAX];
+};
+BLI_STATIC_ASSERT_ALIGN(FilmData, 16)
+
+static inline float film_filter_weight(float filter_size, float sample_distance_sqr)
+{
+#if 1 /* Faster */
+ /* Gaussian fitted to Blackman-Harris. */
+ float r = sample_distance_sqr / (filter_size * filter_size);
+ const float sigma = 0.284;
+ const float fac = -0.5 / (sigma * sigma);
+ float weight = expf(fac * r);
+#else
+ /* Blackman-Harris filter. */
+ float r = M_2PI * saturate(0.5 + sqrtf(sample_distance_sqr) / (2.0 * filter_size));
+ float weight = 0.35875 - 0.48829 * cosf(r) + 0.14128 * cosf(2.0 * r) - 0.01168 * cosf(3.0 * r);
+#endif
+ return weight;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Arbitrary Output Variables
+ * \{ */
+
+/* Theoretical max is 128 as we are using texture array and VRAM usage.
+ * However, the output_aov() function perform a linear search inside all the hashes.
+ * If we find a way to avoid this we could bump this number up. */
+#define AOV_MAX 16
+
+/* NOTE(@fclem): Needs to be used in #StorageBuffer because of arrays of scalar. */
+struct AOVsInfoData {
+ uint hash_value[AOV_MAX];
+ uint hash_color[AOV_MAX];
+ /* Length of used data. */
+ uint color_len;
+ uint value_len;
+ /** Id of the AOV to be displayed (from the start of the AOV array). -1 for combined. */
+ int display_id;
+ /** True if the AOV to be displayed is from the value accum buffer. */
+ bool1 display_is_value;
+};
+BLI_STATIC_ASSERT_ALIGN(AOVsInfoData, 16)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name VelocityModule
* \{ */
@@ -126,7 +305,7 @@ BLI_STATIC_ASSERT_ALIGN(VelocityGeometryIndex, 16)
* \{ */
enum eClosureBits : uint32_t {
- /** NOTE: Theses are used as stencil bits. So we are limited to 8bits. */
+ /** NOTE: These are used as stencil bits. So we are limited to 8bits. */
CLOSURE_DIFFUSE = (1u << 0u),
CLOSURE_SSS = (1u << 1u),
CLOSURE_REFLECTION = (1u << 2u),
@@ -178,10 +357,13 @@ float4 utility_tx_sample(sampler2DArray util_tx, float2 uv, float layer)
#ifdef __cplusplus
+using AOVsInfoDataBuf = draw::StorageBuffer<AOVsInfoData>;
using CameraDataBuf = draw::UniformBuffer<CameraData>;
+using FilmDataBuf = draw::UniformBuffer<FilmData>;
+using SamplingDataBuf = draw::StorageBuffer<SamplingData>;
+using VelocityGeometryBuf = draw::StorageArrayBuffer<float4, 16, true>;
using VelocityIndexBuf = draw::StorageArrayBuffer<VelocityIndex, 16>;
using VelocityObjectBuf = draw::StorageArrayBuffer<float4x4, 16>;
-using VelocityGeometryBuf = draw::StorageArrayBuffer<float4, 16, true>;
} // namespace blender::eevee
#endif
diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc
index 42af251d770..e2d4b0ac1c2 100644
--- a/source/blender/draw/engines/eevee_next/eevee_sync.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc
@@ -47,7 +47,7 @@ ObjectHandle &SyncModule::sync_object(Object *ob)
const int recalc_flags = ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_SHADING |
ID_RECALC_GEOMETRY;
if ((eevee_dd.recalc & recalc_flags) != 0) {
- // inst_.sampling.reset();
+ inst_.sampling.reset();
UNUSED_VARS(inst_);
}
@@ -63,7 +63,7 @@ WorldHandle &SyncModule::sync_world(::World *world)
const int recalc_flags = ID_RECALC_ALL;
if ((eevee_dd.recalc & recalc_flags) != 0) {
- // inst_.sampling.reset();
+ inst_.sampling.reset();
}
return eevee_dd;
}
@@ -253,7 +253,10 @@ static void gpencil_stroke_sync(bGPDlayer *UNUSED(gpl),
void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle)
{
/* TODO(fclem): Waiting for a user option to use the render engine instead of gpencil engine. */
- return;
+ if (true) {
+ inst_.gpencil_engine_enabled = true;
+ return;
+ }
gpIterData iter(inst_, ob, ob_handle);
@@ -280,7 +283,12 @@ static void shgroup_curves_call(MaterialPass &matpass,
if (matpass.shgrp == nullptr) {
return;
}
- DRW_shgroup_hair_create_sub(ob, part_sys, modifier_data, matpass.shgrp, matpass.gpumat);
+ if (part_sys != nullptr) {
+ DRW_shgroup_hair_create_sub(ob, part_sys, modifier_data, matpass.shgrp, matpass.gpumat);
+ }
+ else {
+ DRW_shgroup_curves_create_sub(ob, matpass.shgrp, matpass.gpumat);
+ }
}
void SyncModule::sync_curves(Object *ob, ObjectHandle &ob_handle, ModifierData *modifier_data)
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc
index 9f8dce43910..4bd0af8204e 100644
--- a/source/blender/draw/engines/eevee_next/eevee_velocity.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc
@@ -162,7 +162,7 @@ bool VelocityModule::step_object_sync(Object *ob,
}
/* TODO(@fclem): Reset sampling here? Should ultimately be covered by depsgraph update tags. */
- // inst_.sampling.reset();
+ inst_.sampling.reset();
return true;
}
@@ -185,7 +185,7 @@ void VelocityModule::step_swap()
dst_ofs += src_len;
}
/* TODO(@fclem): Fail gracefully (disable motion blur + warning print) if
- `tot_len * sizeof(float4)` is greater than max SSBO size. */
+ * `tot_len * sizeof(float4)` is greater than max SSBO size. */
geometry_steps[step_]->resize(max_ii(16, dst_ofs));
for (VelocityGeometryData &geom : geometry_map.values()) {
@@ -264,7 +264,7 @@ void VelocityModule::end_sync()
}
if (deleted_obj.size() > 0) {
- // inst_.sampling.reset();
+ inst_.sampling.reset();
}
for (auto key : deleted_obj) {
diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.hh b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
index 1bfd9f8c18f..e2606c061e1 100644
--- a/source/blender/draw/engines/eevee_next/eevee_velocity.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_velocity.hh
@@ -111,7 +111,7 @@ class VelocityModule {
void step_sync(eVelocityStep step, float time);
/* Gather motion data. Returns true if the object **can** have motion. */
- bool step_object_sync(Object *ob, ObjectKey &ob_key, int recalc = 0);
+ bool step_object_sync(Object *ob, ObjectKey &object_key, int recalc = 0);
/* Moves next frame data to previous frame data. Nullify next frame data. */
void step_swap();
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc
index e21342c5ef6..f4dba47721d 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_view.cc
@@ -34,17 +34,19 @@ void ShadingView::init()
// mb_.init();
}
-void ShadingView::sync(int2 render_extent_)
+void ShadingView::sync()
{
+ int2 render_extent = inst_.film.render_extent_get();
+
if (false /* inst_.camera.is_panoramic() */) {
- int64_t render_pixel_count = render_extent_.x * (int64_t)render_extent_.y;
+ int64_t render_pixel_count = render_extent.x * (int64_t)render_extent.y;
/* Divide pixel count between the 6 views. Rendering to a square target. */
extent_[0] = extent_[1] = ceilf(sqrtf(1 + (render_pixel_count / 6)));
/* TODO(@fclem): Clip unused views here. */
is_enabled_ = true;
}
else {
- extent_ = render_extent_;
+ extent_ = render_extent;
/* Only enable -Z view. */
is_enabled_ = (StringRefNull(name_) == "negZ_view");
}
@@ -54,31 +56,23 @@ void ShadingView::sync(int2 render_extent_)
}
/* Create views. */
- // const CameraData &data = inst_.camera.data_get();
+ const CameraData &cam = inst_.camera.data_get();
float4x4 viewmat, winmat;
const float(*viewmat_p)[4] = viewmat.ptr(), (*winmat_p)[4] = winmat.ptr();
-#if 0
if (false /* inst_.camera.is_panoramic() */) {
/* TODO(@fclem) Over-scans. */
/* For now a mandatory 5% over-scan for DoF. */
- float side = data.clip_near * 1.05f;
- float near = data.clip_near;
- float far = data.clip_far;
+ float side = cam.clip_near * 1.05f;
+ float near = cam.clip_near;
+ float far = cam.clip_far;
perspective_m4(winmat.ptr(), -side, side, -side, side, near, far);
- viewmat = face_matrix_ * data.viewmat;
+ viewmat = face_matrix_ * cam.viewmat;
}
else {
- viewmat_p = data.viewmat.ptr();
- winmat_p = data.winmat.ptr();
+ viewmat_p = cam.viewmat.ptr();
+ winmat_p = cam.winmat.ptr();
}
-#else
- /* TEMP */
- UNUSED_VARS(face_matrix_);
- const DRWView *default_view = DRW_view_default_get();
- DRW_view_winmat_get(default_view, winmat.ptr(), false);
- DRW_view_viewmat_get(default_view, viewmat.ptr(), false);
-#endif
main_view_ = DRW_view_create(viewmat_p, winmat_p, nullptr, nullptr, nullptr);
sub_view_ = DRW_view_create_sub(main_view_, viewmat_p, winmat_p);
@@ -93,7 +87,6 @@ void ShadingView::sync(int2 render_extent_)
// inst_.hiz_front.view_sync(extent_);
// inst_.gbuffer.view_sync(extent_);
- combined_tx_.sync();
postfx_tx_.sync();
}
@@ -108,22 +101,18 @@ void ShadingView::render()
* With this, we can reuse the same texture across views. */
DrawEngineType *owner = (DrawEngineType *)name_;
- DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
-
- depth_tx_.ensure_2d(GPU_DEPTH24_STENCIL8, extent_);
- combined_tx_.acquire(extent_, GPU_RGBA16F, owner);
+ RenderBuffers &rbufs = inst_.render_buffers;
+ rbufs.acquire(extent_, owner);
velocity_.acquire(extent_);
- // combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_), GPU_ATTACHMENT_TEXTURE(combined_tx_));
- // prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx_),
- // GPU_ATTACHMENT_TEXTURE(velocity_.view_vectors_get()));
- combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color));
- prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(dtxl->depth),
+ combined_fb_.ensure(GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx),
+ GPU_ATTACHMENT_TEXTURE(rbufs.combined_tx));
+ prepass_fb_.ensure(GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx),
GPU_ATTACHMENT_TEXTURE(velocity_.view_vectors_get()));
update_view();
DRW_stats_group_start(name_);
- // DRW_view_set_active(render_view_);
+ DRW_view_set_active(render_view_);
float4 clear_velocity(VELOCITY_INVALID);
GPU_framebuffer_bind(prepass_fb_);
@@ -142,31 +131,22 @@ void ShadingView::render()
// inst_.lookdev.render_overlay(view_fb_);
- inst_.pipelines.forward.render(render_view_, prepass_fb_, combined_fb_, depth_tx_, combined_tx_);
+ inst_.pipelines.forward.render(
+ render_view_, prepass_fb_, combined_fb_, rbufs.depth_tx, rbufs.combined_tx);
// inst_.lights.debug_draw(view_fb_);
// inst_.shadows.debug_draw(view_fb_);
- // velocity_.resolve(depth_tx_);
- velocity_.resolve(dtxl->depth);
-
- // if (inst_.render_passes.vector) {
- // inst_.render_passes.vector->accumulate(velocity_.camera_vectors_get(), sub_view_);
- // }
+ velocity_.resolve(rbufs.depth_tx);
// GPUTexture *final_radiance_tx = render_post(combined_tx_);
- // if (inst_.render_passes.combined) {
- // inst_.render_passes.combined->accumulate(final_radiance_tx, sub_view_);
- // }
+ inst_.film.accumulate(sub_view_);
- // if (inst_.render_passes.depth) {
- // inst_.render_passes.depth->accumulate(depth_tx_, sub_view_);
- // }
+ rbufs.release();
DRW_stats_group_end();
- combined_tx_.release();
postfx_tx_.release();
velocity_.release();
}
@@ -197,11 +177,15 @@ void ShadingView::update_view()
DRW_view_viewmat_get(main_view_, viewmat.ptr(), false);
DRW_view_winmat_get(main_view_, winmat.ptr(), false);
+ /* TODO(fclem): Mixed-resolution rendering: We need to make sure we render with exactly the same
+ * distances between pixels to line up render samples and target pixels.
+ * So if the target resolution is not a multiple of the resolution divisor, we need to make the
+ * projection window bigger in the +X and +Y directions. */
+
/* Anti-Aliasing / Super-Sampling jitter. */
- // float jitter_u = 2.0f * (inst_.sampling.rng_get(SAMPLING_FILTER_U) - 0.5f) / extent_[0];
- // float jitter_v = 2.0f * (inst_.sampling.rng_get(SAMPLING_FILTER_V) - 0.5f) / extent_[1];
+ float2 jitter = inst_.film.pixel_jitter_get() / float2(extent_);
- // window_translate_m4(winmat.ptr(), winmat.ptr(), jitter_u, jitter_v);
+ window_translate_m4(winmat.ptr(), winmat.ptr(), UNPACK2(jitter));
DRW_view_update_sub(sub_view_, viewmat.ptr(), winmat.ptr());
/* FIXME(fclem): The offset may be is noticeably large and the culling might make object pop
diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh
index 95ec1760c63..30e06df9716 100644
--- a/source/blender/draw/engines/eevee_next/eevee_view.hh
+++ b/source/blender/draw/engines/eevee_next/eevee_view.hh
@@ -41,7 +41,7 @@ class ShadingView {
/** Matrix to apply to the viewmat. */
const float (*face_matrix_)[4];
- /** Post-fx modules. */
+ /** Post-FX modules. */
// DepthOfField dof_;
// MotionBlur mb_;
VelocityView velocity_;
@@ -52,8 +52,6 @@ class ShadingView {
Framebuffer prepass_fb_;
Framebuffer combined_fb_;
- Texture depth_tx_;
- TextureFromPool combined_tx_;
TextureFromPool postfx_tx_;
/** Main views is created from the camera (or is from the viewport). It is not jittered. */
@@ -77,7 +75,7 @@ class ShadingView {
void init();
- void sync(int2 render_extent_);
+ void sync();
void render();
@@ -94,7 +92,7 @@ class ShadingView {
*
* Container for all views needed to render the final image.
* We might need up to 6 views for panoramic cameras.
- * All views are always available but only enabled for if need.
+ * All views are always available but only enabled for if needed.
* \{ */
class MainView {
@@ -109,8 +107,6 @@ class MainView {
ShadingView shading_views_4;
ShadingView shading_views_5;
#define shading_views_ (&shading_views_0)
- /** Internal render size. */
- int render_extent_[2];
public:
MainView(Instance &inst)
@@ -123,15 +119,8 @@ class MainView {
{
}
- void init(const int2 full_extent_)
+ void init()
{
- /* TODO(fclem) parameter hidden in experimental. We need to figure out mipmap bias to preserve
- * texture crispiness. */
- float resolution_scale = 1.0f;
- for (int i = 0; i < 2; i++) {
- render_extent_[i] = max_ii(1, roundf(full_extent_[i] * resolution_scale));
- }
-
for (auto i : IndexRange(6)) {
shading_views_[i].init();
}
@@ -140,7 +129,7 @@ class MainView {
void sync()
{
for (auto i : IndexRange(6)) {
- shading_views_[i].sync(render_extent_);
+ shading_views_[i].sync();
}
}
diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc
index b9cb24fe30a..56cb0f127db 100644
--- a/source/blender/draw/engines/eevee_next/eevee_world.cc
+++ b/source/blender/draw/engines/eevee_next/eevee_world.cc
@@ -79,7 +79,7 @@ void World::sync()
/* TODO(fclem) This should be detected to scene level. */
::World *orig_world = (::World *)DEG_get_original_id(&bl_world->id);
if (assign_if_different(prev_original_world, orig_world)) {
- // inst_.sampling.reset();
+ inst_.sampling.reset();
}
bNodeTree *ntree = (bl_world->nodetree && bl_world->use_nodes) ?
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
index 1b113e529b6..326481a1db6 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_attributes_lib.glsl
@@ -131,8 +131,10 @@ int g_curves_attr_id = 0;
int curves_attribute_element_id()
{
int id = interp.curves_strand_id;
- if (drw_curves.is_point_attribute[g_curves_attr_id] != 0) {
+ if (drw_curves.is_point_attribute[g_curves_attr_id][0] != 0) {
+# ifdef COMMON_HAIR_LIB
id = hair_get_base_id();
+# endif
}
g_curves_attr_id += 1;
@@ -285,7 +287,7 @@ vec3 attr_load_uv(vec3 attr)
/** \name Volume Attribute post
*
* TODO(@fclem): These implementation details should concern the DRWManager and not be a fix on
- * the engine side. But as of now, the engines are reponsible for loading the attributes.
+ * the engine side. But as of now, the engines are responsible for loading the attributes.
*
* \{ */
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_film_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_film_comp.glsl
new file mode 100644
index 00000000000..ce1f19edf53
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_film_comp.glsl
@@ -0,0 +1,13 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_film_lib.glsl)
+
+void main()
+{
+ ivec2 texel_film = ivec2(gl_GlobalInvocationID.xy);
+ /* Not used. */
+ vec4 out_color;
+ float out_depth;
+
+ film_process_data(texel_film, out_color, out_depth);
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_film_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_film_frag.glsl
new file mode 100644
index 00000000000..6716c0f126e
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_film_frag.glsl
@@ -0,0 +1,29 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_film_lib.glsl)
+
+void main()
+{
+ ivec2 texel_film = ivec2(gl_FragCoord.xy);
+ float out_depth;
+
+ if (film_buf.display_only) {
+ out_depth = imageLoad(depth_img, texel_film).r;
+
+ if (film_buf.display_id == -1) {
+ out_color = imageLoad(in_combined_img, texel_film);
+ }
+ else if (film_buf.display_is_value) {
+ out_color.rgb = imageLoad(value_accum_img, ivec3(texel_film, film_buf.display_id)).rrr;
+ out_color.a = 1.0;
+ }
+ else {
+ out_color = imageLoad(color_accum_img, ivec3(texel_film, film_buf.display_id));
+ }
+ }
+ else {
+ film_process_data(texel_film, out_color, out_depth);
+ }
+
+ gl_FragDepth = get_depth_from_view_z(-out_depth);
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl
new file mode 100644
index 00000000000..03af34f27ef
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_film_lib.glsl
@@ -0,0 +1,387 @@
+
+/**
+ * Film accumulation utils functions.
+ **/
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(eevee_camera_lib.glsl)
+
+/* Return scene linear Z depth from the camera or radial depth for panoramic cameras. */
+float film_depth_convert_to_scene(float depth)
+{
+ if (false /* Panoramic */) {
+ /* TODO */
+ return 1.0;
+ }
+ return abs(get_view_z_from_depth(depth));
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Filter
+ * \{ */
+
+FilmSample film_sample_get(int sample_n, ivec2 texel_film)
+{
+#ifdef PANORAMIC
+ /* TODO(fclem): Panoramic projection will be more complex. The samples will have to be retrieve
+ * at runtime, maybe by scanning a whole region. Offset and weight will have to be computed by
+ * reprojecting the incoming pixel data into film pixel space. */
+#else
+
+# ifdef SCALED_RENDERING
+ texel_film /= film_buf.scaling_factor;
+# endif
+
+ FilmSample film_sample = film_buf.samples[sample_n];
+ film_sample.texel += texel_film;
+ /* Use extend on borders. */
+ film_sample.texel = clamp(film_sample.texel, ivec2(0, 0), film_buf.extent - 1);
+
+ /* TODO(fclem): Panoramic projection will need to compute the sample weight in the shader
+ * instead of precomputing it on CPU. */
+# ifdef SCALED_RENDERING
+ /* We need to compute the real distance and weight since a sample
+ * can be used by many final pixel. */
+ vec2 offset = film_buf.subpixel_offset - vec2(texel_film % film_buf.scaling_factor);
+ film_sample.weight = film_filter_weight(film_buf.filter_size, len_squared(offset));
+# endif
+
+#endif /* PANORAMIC */
+
+ /* Always return a weight above 0 to avoid blind spots between samples. */
+ film_sample.weight = max(film_sample.weight, 1e-6);
+
+ return film_sample;
+}
+
+/* Returns the combined weights of all samples affecting this film pixel. */
+float film_weight_accumulation(ivec2 texel_film)
+{
+#if 0 /* TODO(fclem): Reference implementation, also needed for panoramic cameras. */
+ float weight = 0.0;
+ for (int i = 0; i < film_buf.samples_len; i++) {
+ weight += film_sample_get(i, texel_film).weight;
+ }
+ return weight;
+#endif
+ return film_buf.samples_weight_total;
+}
+
+void film_sample_accum(FilmSample samp, int pass_id, sampler2D tex, inout vec4 accum)
+{
+ if (pass_id == -1) {
+ return;
+ }
+ accum += texelFetch(tex, samp.texel, 0) * samp.weight;
+}
+
+void film_sample_accum(FilmSample samp, int pass_id, sampler2D tex, inout float accum)
+{
+ if (pass_id == -1) {
+ return;
+ }
+ accum += texelFetch(tex, samp.texel, 0).x * samp.weight;
+}
+
+void film_sample_accum(FilmSample samp, int pass_id, sampler2DArray tex, inout vec4 accum)
+{
+ if (pass_id == -1) {
+ return;
+ }
+ accum += texelFetch(tex, ivec3(samp.texel, pass_id), 0) * samp.weight;
+}
+
+void film_sample_accum(FilmSample samp, int pass_id, sampler2DArray tex, inout float accum)
+{
+ if (pass_id == -1) {
+ return;
+ }
+ accum += texelFetch(tex, ivec3(samp.texel, pass_id), 0).x * samp.weight;
+}
+
+void film_sample_accum_mist(FilmSample samp, inout float accum)
+{
+ if (film_buf.mist_id == -1) {
+ return;
+ }
+ float depth = texelFetch(depth_tx, samp.texel, 0).x;
+ vec2 uv = (vec2(samp.texel) + 0.5) / textureSize(depth_tx, 0).xy;
+ vec3 vP = get_view_space_from_depth(uv, depth);
+ bool is_persp = ProjectionMatrix[3][3] == 0.0;
+ float mist = (is_persp) ? length(vP) : abs(vP.z);
+ /* Remap to 0..1 range. */
+ mist = saturate(mist * film_buf.mist_scale + film_buf.mist_bias);
+ /* Falloff. */
+ mist = pow(mist, film_buf.mist_exponent);
+ accum += mist * samp.weight;
+}
+
+void film_sample_accum_combined(FilmSample samp, inout vec4 accum)
+{
+ if (film_buf.combined_id == -1) {
+ return;
+ }
+ vec4 color = texelFetch(combined_tx, samp.texel, 0);
+ /* Convert transmittance to opacity. */
+ color.a = saturate(1.0 - color.a);
+ /* TODO(fclem) Pre-expose. */
+ color.rgb = log2(1.0 + color.rgb);
+
+ accum += color * samp.weight;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Load/Store Data
+ * \{ */
+
+#define WEIGHT_lAYER_ACCUMULATION 0
+#define WEIGHT_lAYER_DISTANCE 1
+
+/* Returns the distance used to store nearest interpolation data. */
+float film_distance_load(ivec2 texel)
+{
+ /* Repeat texture coordinates as the weight can be optimized to a small portion of the film. */
+ texel = texel % imageSize(in_weight_img).xy;
+
+ if (film_buf.use_history == false) {
+ return 1.0e16;
+ }
+ return imageLoad(in_weight_img, ivec3(texel, WEIGHT_lAYER_DISTANCE)).x;
+}
+
+float film_weight_load(ivec2 texel)
+{
+ /* Repeat texture coordinates as the weight can be optimized to a small portion of the film. */
+ texel = texel % imageSize(in_weight_img).xy;
+
+ if (film_buf.use_history == false) {
+ return 0.0;
+ }
+ return imageLoad(in_weight_img, ivec3(texel, WEIGHT_lAYER_ACCUMULATION)).x;
+}
+
+/* Return the motion in pixels. */
+void film_motion_load()
+{
+ // ivec2 texel_sample = film_sample_get(0, texel_film, distance_sample);
+ // vec4 vector = texelFetch(vector_tx, texel_sample);
+
+ // vector.xy *= film_buf.extent;
+}
+
+/* Returns resolved final color. */
+void film_store_combined(FilmSample dst, vec4 color, inout vec4 display)
+{
+ if (film_buf.combined_id == -1) {
+ return;
+ }
+
+ /* Could we assume safe color from earlier pass? */
+ color = safe_color(color);
+ if (false) {
+ /* Re-projection using motion vectors. */
+ // ivec2 texel_combined = texel_film + film_motion_load(texel_film);
+ // float weight_combined = film_weight_load(texel_combined);
+ }
+#ifdef USE_NEIGHBORHOOD_CLAMPING
+ /* Only do that for combined pass as it has a non-negligeable performance impact. */
+ // color = clamp_bbox(color, min, max);
+#endif
+
+ vec4 dst_color = imageLoad(in_combined_img, dst.texel);
+
+ color = (dst_color * dst.weight + color) * dst.weight_sum_inv;
+
+ /* TODO(fclem) undo Pre-expose. */
+ // color.rgb = exp2(color.rgb) - 1.0;
+
+ if (film_buf.display_id == -1) {
+ display = color;
+ }
+ imageStore(out_combined_img, dst.texel, color);
+}
+
+void film_store_color(FilmSample dst, int pass_id, vec4 color, inout vec4 display)
+{
+ if (pass_id == -1) {
+ return;
+ }
+
+ vec4 data_film = imageLoad(color_accum_img, ivec3(dst.texel, pass_id));
+
+ color = (data_film * dst.weight + color) * dst.weight_sum_inv;
+
+ if (film_buf.display_id == pass_id) {
+ display = color;
+ }
+ imageStore(color_accum_img, ivec3(dst.texel, pass_id), color);
+}
+
+void film_store_value(FilmSample dst, int pass_id, float value, inout vec4 display)
+{
+ if (pass_id == -1) {
+ return;
+ }
+
+ float data_film = imageLoad(value_accum_img, ivec3(dst.texel, pass_id)).x;
+
+ value = (data_film * dst.weight + value) * dst.weight_sum_inv;
+
+ if (film_buf.display_id == pass_id) {
+ display = vec4(value, value, value, 1.0);
+ }
+ imageStore(value_accum_img, ivec3(dst.texel, pass_id), vec4(value));
+}
+
+/* Nearest sample variant. Always stores the data. */
+void film_store_data(ivec2 texel_film, int pass_id, vec4 data_sample, inout vec4 display)
+{
+ if (pass_id == -1) {
+ return;
+ }
+
+ if (film_buf.display_id == pass_id) {
+ display = data_sample;
+ }
+ imageStore(color_accum_img, ivec3(texel_film, pass_id), data_sample);
+}
+
+void film_store_depth(ivec2 texel_film, float value, out float out_depth)
+{
+ if (film_buf.depth_id == -1) {
+ return;
+ }
+
+ out_depth = film_depth_convert_to_scene(value);
+
+ imageStore(depth_img, texel_film, vec4(out_depth));
+}
+
+void film_store_distance(ivec2 texel, float value)
+{
+ imageStore(out_weight_img, ivec3(texel, WEIGHT_lAYER_DISTANCE), vec4(value));
+}
+
+void film_store_weight(ivec2 texel, float value)
+{
+ imageStore(out_weight_img, ivec3(texel, WEIGHT_lAYER_ACCUMULATION), vec4(value));
+}
+
+/** \} */
+
+/** NOTE: out_depth is scene linear depth from the camera origin. */
+void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth)
+{
+ out_color = vec4(0.0);
+ out_depth = 0.0;
+
+ float weight_accum = film_weight_accumulation(texel_film);
+ float film_weight = film_weight_load(texel_film);
+ float weight_sum = film_weight + weight_accum;
+ film_store_weight(texel_film, weight_sum);
+
+ FilmSample dst;
+ dst.texel = texel_film;
+ dst.weight = film_weight;
+ dst.weight_sum_inv = 1.0 / weight_sum;
+
+ /* NOTE: We split the accumulations into separate loops to avoid using too much registers and
+ * maximize occupancy. */
+
+ if (film_buf.has_data) {
+ float film_weight = film_distance_load(texel_film);
+
+ /* Get sample closest to target texel. It is always sample 0. */
+ FilmSample film_sample = film_sample_get(0, texel_film);
+
+ if (film_sample.weight < film_weight) {
+ float depth = texelFetch(depth_tx, film_sample.texel, 0).x;
+ vec4 normal = texelFetch(normal_tx, film_sample.texel, 0);
+ vec4 vector = texelFetch(vector_tx, film_sample.texel, 0);
+
+ film_store_depth(texel_film, depth, out_depth);
+ film_store_data(texel_film, film_buf.normal_id, normal, out_color);
+ film_store_data(texel_film, film_buf.vector_id, vector, out_color);
+ film_store_distance(texel_film, film_sample.weight);
+ }
+ else {
+ out_depth = imageLoad(depth_img, texel_film).r;
+ }
+ }
+
+ if (film_buf.combined_id != -1) {
+ vec4 combined_accum = vec4(0.0);
+
+ for (int i = 0; i < film_buf.samples_len; i++) {
+ FilmSample src = film_sample_get(i, texel_film);
+ film_sample_accum_combined(src, combined_accum);
+ }
+ film_store_combined(dst, combined_accum, out_color);
+ }
+
+ if (film_buf.any_render_pass_1) {
+ vec4 diffuse_light_accum = vec4(0.0);
+ vec4 specular_light_accum = vec4(0.0);
+ vec4 volume_light_accum = vec4(0.0);
+ vec4 emission_accum = vec4(0.0);
+
+ for (int i = 0; i < film_buf.samples_len; i++) {
+ FilmSample src = film_sample_get(i, texel_film);
+ film_sample_accum(src, film_buf.diffuse_light_id, diffuse_light_tx, diffuse_light_accum);
+ film_sample_accum(src, film_buf.specular_light_id, specular_light_tx, specular_light_accum);
+ film_sample_accum(src, film_buf.volume_light_id, volume_light_tx, volume_light_accum);
+ film_sample_accum(src, film_buf.emission_id, emission_tx, emission_accum);
+ }
+ film_store_color(dst, film_buf.diffuse_light_id, diffuse_light_accum, out_color);
+ film_store_color(dst, film_buf.specular_light_id, specular_light_accum, out_color);
+ film_store_color(dst, film_buf.volume_light_id, volume_light_accum, out_color);
+ film_store_color(dst, film_buf.emission_id, emission_accum, out_color);
+ }
+
+ if (film_buf.any_render_pass_2) {
+ vec4 diffuse_color_accum = vec4(0.0);
+ vec4 specular_color_accum = vec4(0.0);
+ vec4 environment_accum = vec4(0.0);
+ float mist_accum = 0.0;
+ float shadow_accum = 0.0;
+ float ao_accum = 0.0;
+
+ for (int i = 0; i < film_buf.samples_len; i++) {
+ FilmSample src = film_sample_get(i, texel_film);
+ film_sample_accum(src, film_buf.diffuse_color_id, diffuse_color_tx, diffuse_color_accum);
+ film_sample_accum(src, film_buf.specular_color_id, specular_color_tx, specular_color_accum);
+ film_sample_accum(src, film_buf.environment_id, environment_tx, environment_accum);
+ film_sample_accum(src, film_buf.shadow_id, shadow_tx, shadow_accum);
+ film_sample_accum(src, film_buf.ambient_occlusion_id, ambient_occlusion_tx, ao_accum);
+ film_sample_accum_mist(src, mist_accum);
+ }
+ film_store_color(dst, film_buf.diffuse_color_id, diffuse_color_accum, out_color);
+ film_store_color(dst, film_buf.specular_color_id, specular_color_accum, out_color);
+ film_store_color(dst, film_buf.environment_id, environment_accum, out_color);
+ film_store_value(dst, film_buf.shadow_id, shadow_accum, out_color);
+ film_store_value(dst, film_buf.ambient_occlusion_id, ao_accum, out_color);
+ film_store_value(dst, film_buf.mist_id, mist_accum, out_color);
+ }
+
+ for (int aov = 0; aov < film_buf.aov_color_len; aov++) {
+ vec4 aov_accum = vec4(0.0);
+
+ for (int i = 0; i < film_buf.samples_len; i++) {
+ FilmSample src = film_sample_get(i, texel_film);
+ film_sample_accum(src, aov, aov_color_tx, aov_accum);
+ }
+ film_store_color(dst, film_buf.aov_color_id + aov, aov_accum, out_color);
+ }
+
+ for (int aov = 0; aov < film_buf.aov_value_len; aov++) {
+ float aov_accum = 0.0;
+
+ for (int i = 0; i < film_buf.samples_len; i++) {
+ FilmSample src = film_sample_get(i, texel_film);
+ film_sample_accum(src, aov, aov_value_tx, aov_accum);
+ }
+ film_store_value(dst, film_buf.aov_value_id + aov, aov_accum, out_color);
+ }
+}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
index 277b2e35d8b..71921d0477a 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_nodetree_lib.glsl
@@ -29,7 +29,7 @@ bool closure_select(float weight, inout float total_weight, inout float r)
float x = weight / total_weight;
bool chosen = (r < x);
/* Assuming that if r is in the interval [0,x] or [x,1], it's still uniformly distributed within
- * that interval, so you remaping to [0,1] again to explore this space of probability. */
+ * that interval, so you remapping to [0,1] again to explore this space of probability. */
r = (chosen) ? (r / x) : ((r - x) / (1.0 - x));
return chosen;
}
@@ -245,6 +245,20 @@ float F_eta(float a, float b)
}
void output_aov(vec4 color, float value, uint hash)
{
+#if defined(MAT_AOV_SUPPORT) && defined(GPU_FRAGMENT_SHADER)
+ for (int i = 0; i < AOV_MAX && i < aov_buf.color_len; i++) {
+ if (aov_buf.hash_color[i] == hash) {
+ imageStore(aov_color_img, ivec3(gl_FragCoord.xy, i), color);
+ return;
+ }
+ }
+ for (int i = 0; i < AOV_MAX && i < aov_buf.value_len; i++) {
+ if (aov_buf.hash_value[i] == hash) {
+ imageStore(aov_value_img, ivec3(gl_FragCoord.xy, i), vec4(value));
+ return;
+ }
+ }
+#endif
}
#ifdef EEVEE_MATERIAL_STUBS
@@ -333,7 +347,7 @@ vec3 coordinate_screen(vec3 P)
window.xy = vec2(0.5);
}
else {
- /* TODO(fclem): Actual camera tranform. */
+ /* TODO(fclem): Actual camera transform. */
window.xy = project_point(ViewProjectionMatrix, P).xy * 0.5 + 0.5;
window.xy = window.xy * CameraTexCoFactors.xy + CameraTexCoFactors.zw;
}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl
index 143e88dbe68..48ced4e5374 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_forward_frag.glsl
@@ -53,21 +53,45 @@ void main()
g_holdout = saturate(g_holdout);
+ vec3 diffuse_light = vec3(saturate(g_diffuse_data.N.z * 0.5 + 0.5));
+ vec3 reflection_light = vec3(spec_light(g_reflection_data));
+ vec3 refraction_light = vec3(saturate(g_refraction_data.N.z * 0.5 + 0.5));
+
+ g_diffuse_data.color *= g_diffuse_data.weight;
+ g_reflection_data.color *= g_reflection_data.weight;
+ g_refraction_data.color *= g_refraction_data.weight;
+ diffuse_light *= step(1e-5, g_diffuse_data.weight);
+ reflection_light *= step(1e-5, g_reflection_data.weight);
+ refraction_light *= step(1e-5, g_refraction_data.weight);
+
out_radiance.rgb = g_emission;
- out_radiance.rgb += g_diffuse_data.color * g_diffuse_data.weight *
- saturate(g_diffuse_data.N.z * 0.5 + 0.5);
- out_radiance.rgb += g_reflection_data.color * g_reflection_data.weight *
- spec_light(g_reflection_data);
- out_radiance.rgb += g_refraction_data.color * g_refraction_data.weight *
- saturate(g_refraction_data.N.z * 0.5 + 0.5);
+ out_radiance.rgb += g_diffuse_data.color * diffuse_light;
+ out_radiance.rgb += g_reflection_data.color * reflection_light;
+ out_radiance.rgb += g_refraction_data.color * refraction_light;
out_radiance.a = 0.0;
+ vec3 specular_light = reflection_light + refraction_light;
+ vec3 specular_color = g_reflection_data.color + g_refraction_data.color;
+
+ /* TODO(fclem): This feels way too complex for what is it. */
+ bool has_any_bsdf_weight = g_diffuse_data.weight != 0.0 || g_reflection_data.weight != 0.0 ||
+ g_refraction_data.weight != 0.0;
+ vec3 out_normal = has_any_bsdf_weight ? vec3(0.0) : g_data.N;
+ out_normal += g_diffuse_data.N * g_diffuse_data.weight;
+ out_normal += g_reflection_data.N * g_reflection_data.weight;
+ out_normal += g_refraction_data.N * g_refraction_data.weight;
+ out_normal = safe_normalize(out_normal);
+
+ ivec2 out_texel = ivec2(gl_FragCoord.xy);
+ imageStore(rp_normal_img, out_texel, vec4(out_normal, 1.0));
+ imageStore(rp_diffuse_light_img, out_texel, vec4(diffuse_light, 1.0));
+ imageStore(rp_diffuse_color_img, out_texel, vec4(g_diffuse_data.color, 1.0));
+ imageStore(rp_specular_light_img, out_texel, vec4(specular_light, 1.0));
+ imageStore(rp_specular_color_img, out_texel, vec4(specular_color, 1.0));
+ imageStore(rp_emission_img, out_texel, vec4(g_emission, 1.0));
+
out_radiance.rgb *= 1.0 - g_holdout;
out_transmittance.rgb = g_transmittance;
out_transmittance.a = saturate(avg(g_transmittance));
-
- /* Test */
- out_transmittance.a = 1.0 - out_transmittance.a;
- out_radiance.a = 1.0 - out_radiance.a;
}
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl
index ac657afc922..b32c3c1c4eb 100644
--- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl
+++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_world_frag.glsl
@@ -24,6 +24,14 @@ void main()
g_holdout = saturate(g_holdout);
+ ivec2 out_texel = ivec2(gl_FragCoord.xy);
+ imageStore(rp_normal_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
+ imageStore(rp_diffuse_light_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
+ imageStore(rp_diffuse_color_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
+ imageStore(rp_specular_light_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
+ imageStore(rp_specular_color_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
+ imageStore(rp_emission_img, out_texel, vec4(0.0, 0.0, 0.0, 1.0));
+
out_background.rgb = safe_color(g_emission) * (1.0 - g_holdout);
out_background.a = saturate(avg(g_transmittance)) * g_holdout;
}
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_film_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_film_info.hh
new file mode 100644
index 00000000000..eec7b8ae615
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_film_info.hh
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "eevee_defines.hh"
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(eevee_film)
+ .uniform_buf(1, "FilmData", "film_buf")
+ .sampler(0, ImageType::DEPTH_2D, "depth_tx")
+ .sampler(1, ImageType::FLOAT_2D, "combined_tx")
+ .sampler(2, ImageType::FLOAT_2D, "normal_tx")
+ .sampler(3, ImageType::FLOAT_2D, "vector_tx")
+ .sampler(4, ImageType::FLOAT_2D, "diffuse_light_tx")
+ .sampler(5, ImageType::FLOAT_2D, "diffuse_color_tx")
+ .sampler(6, ImageType::FLOAT_2D, "specular_light_tx")
+ .sampler(7, ImageType::FLOAT_2D, "specular_color_tx")
+ .sampler(8, ImageType::FLOAT_2D, "volume_light_tx")
+ .sampler(9, ImageType::FLOAT_2D, "emission_tx")
+ .sampler(10, ImageType::FLOAT_2D, "environment_tx")
+ .sampler(11, ImageType::FLOAT_2D, "shadow_tx")
+ .sampler(12, ImageType::FLOAT_2D, "ambient_occlusion_tx")
+ .sampler(13, ImageType::FLOAT_2D_ARRAY, "aov_color_tx")
+ .sampler(14, ImageType::FLOAT_2D_ARRAY, "aov_value_tx")
+ // .sampler(15, ImageType::FLOAT_2D, "cryptomatte_tx") /* TODO */
+ .image(0, GPU_R32F, Qualifier::READ, ImageType::FLOAT_2D_ARRAY, "in_weight_img")
+ .image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img")
+ .image(2, GPU_RGBA16F, Qualifier::READ, ImageType::FLOAT_2D, "in_combined_img")
+ .image(3, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "out_combined_img")
+ .image(4, GPU_R32F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "depth_img")
+ .image(5, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D_ARRAY, "color_accum_img")
+ .image(6, GPU_R16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D_ARRAY, "value_accum_img")
+ .additional_info("eevee_shared")
+ .additional_info("draw_view");
+
+GPU_SHADER_CREATE_INFO(eevee_film_frag)
+ .do_static_compilation(true)
+ .fragment_out(0, Type::VEC4, "out_color")
+ .fragment_source("eevee_film_frag.glsl")
+ .additional_info("draw_fullscreen", "eevee_film");
+
+GPU_SHADER_CREATE_INFO(eevee_film_comp)
+ .do_static_compilation(true)
+ .local_group_size(FILM_GROUP_SIZE, FILM_GROUP_SIZE)
+ .compute_source("eevee_film_comp.glsl")
+ .additional_info("eevee_film");
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
index 49250b5741e..950164f5b86 100644
--- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
@@ -39,7 +39,10 @@ GPU_SHADER_CREATE_INFO(eevee_geom_curves)
.additional_info("eevee_shared")
.define("MAT_GEOM_CURVES")
.vertex_source("eevee_geom_curves_vert.glsl")
- .additional_info("draw_hair", "draw_resource_id_varying", "draw_resource_handle");
+ .additional_info("draw_hair",
+ "draw_curves_infos",
+ "draw_resource_id_varying",
+ "draw_resource_handle");
GPU_SHADER_CREATE_INFO(eevee_geom_world)
.additional_info("eevee_shared")
@@ -67,6 +70,14 @@ GPU_SHADER_INTERFACE_INFO(eevee_surf_iface, "interp")
#define image_out(slot, qualifier, format, name) \
image(slot, format, qualifier, ImageType::FLOAT_2D, name, Frequency::PASS)
+#define image_array_out(slot, qualifier, format, name) \
+ image(slot, format, qualifier, ImageType::FLOAT_2D_ARRAY, name, Frequency::PASS)
+
+GPU_SHADER_CREATE_INFO(eevee_aov_out)
+ .define("MAT_AOV_SUPPORT")
+ .image_array_out(6, Qualifier::WRITE, GPU_RGBA16F, "aov_color_img")
+ .image_array_out(7, Qualifier::WRITE, GPU_R16F, "aov_value_img")
+ .storage_buf(7, Qualifier::READ, "AOVsInfoData", "aov_buf");
GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
.vertex_out(eevee_surf_iface)
@@ -82,31 +93,38 @@ GPU_SHADER_CREATE_INFO(eevee_surf_deferred)
// .image_out(3, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_reflection_color")
// .image_out(4, Qualifier::WRITE, GPU_RGBA16F, "gbuff_reflection_normal")
// .image_out(5, Qualifier::WRITE, GPU_R11F_G11F_B10F, "gbuff_emission")
- /* Renderpasses. */
+ /* Render-passes. */
// .image_out(6, Qualifier::READ_WRITE, GPU_RGBA16F, "rpass_volume_light")
/* TODO: AOVs maybe? */
.fragment_source("eevee_surf_deferred_frag.glsl")
- // .additional_info("eevee_sampling_data", "eevee_utility_texture")
+ // .additional_info("eevee_aov_out", "eevee_sampling_data", "eevee_utility_texture")
;
-#undef image_out
-
GPU_SHADER_CREATE_INFO(eevee_surf_forward)
.auto_resource_location(true)
.vertex_out(eevee_surf_iface)
+ /* Early fragment test is needed for render passes support for forward surfaces. */
+ /* NOTE: This removes the possibility of using gl_FragDepth. */
+ .early_fragment_test(true)
.fragment_out(0, Type::VEC4, "out_radiance", DualBlend::SRC_0)
.fragment_out(0, Type::VEC4, "out_transmittance", DualBlend::SRC_1)
.fragment_source("eevee_surf_forward_frag.glsl")
- // .additional_info("eevee_sampling_data",
- // "eevee_lightprobe_data",
- /* Optionally added depending on the material. */
- // "eevee_raytrace_data",
- // "eevee_transmittance_data",
- // "eevee_utility_texture",
- // "eevee_light_data",
- // "eevee_shadow_data"
- // )
- ;
+ .image_out(0, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_normal_img")
+ .image_out(1, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_light_img")
+ .image_out(2, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_color_img")
+ .image_out(3, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_light_img")
+ .image_out(4, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img")
+ .image_out(5, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img")
+ .additional_info("eevee_aov_out"
+ // "eevee_sampling_data",
+ // "eevee_lightprobe_data",
+ /* Optionally added depending on the material. */
+ // "eevee_raytrace_data",
+ // "eevee_transmittance_data",
+ // "eevee_utility_texture",
+ // "eevee_light_data",
+ // "eevee_shadow_data"
+ );
GPU_SHADER_CREATE_INFO(eevee_surf_depth)
.vertex_out(eevee_surf_iface)
@@ -116,10 +134,20 @@ GPU_SHADER_CREATE_INFO(eevee_surf_depth)
GPU_SHADER_CREATE_INFO(eevee_surf_world)
.vertex_out(eevee_surf_iface)
+ .image_out(0, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_normal_img")
+ .image_out(1, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_light_img")
+ .image_out(2, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_diffuse_color_img")
+ .image_out(3, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_light_img")
+ .image_out(4, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_specular_color_img")
+ .image_out(5, Qualifier::READ_WRITE, GPU_RGBA16F, "rp_emission_img")
.fragment_out(0, Type::VEC4, "out_background")
.fragment_source("eevee_surf_world_frag.glsl")
- // .additional_info("eevee_utility_texture")
- ;
+ .additional_info("eevee_aov_out"
+ //"eevee_utility_texture"
+ );
+
+#undef image_out
+#undef image_array_out
/** \} */
@@ -166,7 +194,7 @@ GPU_SHADER_CREATE_INFO(eevee_material_stub).define("EEVEE_MATERIAL_STUBS");
# define EEVEE_MAT_GEOM_VARIATIONS(prefix, ...) \
EEVEE_MAT_FINAL_VARIATION(prefix##_world, "eevee_geom_world", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_gpencil, "eevee_geom_gpencil", __VA_ARGS__) \
- EEVEE_MAT_FINAL_VARIATION(prefix##_hair, "eevee_geom_curves", __VA_ARGS__) \
+ EEVEE_MAT_FINAL_VARIATION(prefix##_curves, "eevee_geom_curves", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__)
# define EEVEE_MAT_PIPE_VARIATIONS(name, ...) \
diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
index a5f16363466..c6cbf9b1456 100644
--- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
+++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_create_info.hh"
diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c
index 9f2f2b4b23d..b9c09e2bc4f 100644
--- a/source/blender/draw/engines/external/external_engine.c
+++ b/source/blender/draw/engines/external/external_engine.c
@@ -36,8 +36,8 @@
#define EXTERNAL_ENGINE "BLENDER_EXTERNAL"
-extern char datatoc_depth_frag_glsl[];
-extern char datatoc_depth_vert_glsl[];
+extern char datatoc_basic_depth_frag_glsl[];
+extern char datatoc_basic_depth_vert_glsl[];
extern char datatoc_common_view_lib_glsl[];
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
index 75bd3d30d68..6671c16aa0b 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -344,7 +344,7 @@ float stroke_thickness_modulate(float thickness)
}
else {
/* World space point size. */
- thickness *= thicknessWorldScale * ProjectionMatrix[1][1] * sizeViewport.y;
+ thickness *= thicknessWorldScale * drw_view.winmat[1][1] * sizeViewport.y;
}
return thickness;
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
index e162c5bf45e..2fca8b69183 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
@@ -5,5 +5,5 @@ void main()
int v = gl_VertexID % 3;
float x = -1.0 + float((v & 1) << 2);
float y = -1.0 + float((v & 2) << 1);
- gl_Position = ViewProjectionMatrix * (model_matrix * vec4(x, y, 0.0, 1.0));
+ gl_Position = drw_view.persmat * (model_matrix * vec4(x, y, 0.0, 1.0));
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
index af8aec85598..b0ee059cb9d 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
@@ -32,7 +32,7 @@ void main()
vec3 vert_N;
gpMaterial gp_mat = materials[ma1.x + gpMaterialOffset];
- gpMaterialFlag gp_flag = floatBitsToInt(gp_mat._flag);
+ gpMaterialFlag gp_flag = floatBitsToUint(gp_mat._flag);
gl_Position = gpencil_vertex(ma,
ma1,
@@ -125,7 +125,7 @@ void main()
gpencil_color_output(fill_col, fcol_decode, 1.0, gp_mat._fill_texture_mix);
gp_interp.mat_flag = gp_flag & GP_FILL_FLAGS;
- gp_interp.mat_flag |= uint(ma1.x) << GPENCIl_MATID_SHIFT;
+ gp_interp.mat_flag |= uint(ma1.x + gpMaterialOffset) << GPENCIl_MATID_SHIFT;
gp_interp.uv = mat2(gp_mat.fill_uv_rot_scale.xy, gp_mat.fill_uv_rot_scale.zw) * uv1.xy +
gp_mat._fill_uv_offset;
diff --git a/source/blender/draw/engines/overlay/overlay_antialiasing.c b/source/blender/draw/engines/overlay/overlay_antialiasing.c
index 27ee479cf36..780915b7fc4 100644
--- a/source/blender/draw/engines/overlay/overlay_antialiasing.c
+++ b/source/blender/draw/engines/overlay/overlay_antialiasing.c
@@ -52,7 +52,7 @@ void OVERLAY_antialiasing_init(OVERLAY_Data *vedata)
OVERLAY_PrivateData *pd = vedata->stl->pd;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
- /* Small texture which will have very small impact on rendertime. */
+ /* Small texture which will have very small impact on render-time. */
if (txl->dummy_depth_tx == NULL) {
const float pixel[1] = {1.0f};
txl->dummy_depth_tx = DRW_texture_create_2d(1, 1, GPU_DEPTH_COMPONENT24, 0, pixel);
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index ea0c2f287a6..e38695c76ab 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -2102,7 +2102,7 @@ static void pchan_culling_calc_bsphere(const Object *ob,
{
float min[3], max[3];
INIT_MINMAX(min, max);
- BKE_pchan_minmax(ob, pchan, min, max);
+ BKE_pchan_minmax(ob, pchan, true, min, max);
mid_v3_v3v3(r_bsphere->center, min, max);
r_bsphere->radius = len_v3v3(min, r_bsphere->center);
}
diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c
index acfd2f98044..4cfe9fcea4e 100644
--- a/source/blender/draw/engines/overlay/overlay_edit_uv.c
+++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c
@@ -115,7 +115,7 @@ void OVERLAY_edit_uv_init(OVERLAY_Data *vedata)
const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
const bool do_edges_only = (ts->uv_flag & UV_SYNC_SELECTION) ?
/* NOTE: Ignore #SCE_SELECT_EDGE because a single selected edge
- * on the mesh may cause singe UV vertices to be selected. */
+ * on the mesh may cause single UV vertices to be selected. */
false :
(ts->uv_selectmode == UV_SELECT_EDGE);
const bool do_faces = ((sima->flag & SI_NO_DRAWFACES) == 0);
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index f8c28394b16..5edd68bffff 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -192,6 +192,8 @@ static void OVERLAY_cache_init(void *vedata)
OVERLAY_edit_curves_cache_init(vedata);
break;
case CTX_MODE_SCULPT_CURVES:
+ OVERLAY_sculpt_curves_cache_init(vedata);
+ break;
case CTX_MODE_OBJECT:
break;
default:
@@ -308,8 +310,12 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
(pd->ctx_mode == CTX_MODE_PARTICLE);
const bool in_paint_mode = (ob == draw_ctx->obact) &&
(draw_ctx->object_mode & OB_MODE_ALL_PAINT);
+ const bool in_sculpt_curve_mode = (ob == draw_ctx->obact) &&
+ (draw_ctx->object_mode & OB_MODE_SCULPT_CURVES);
const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL) &&
(ob->sculpt->mode_type == OB_MODE_SCULPT);
+ const bool in_curves_sculpt_mode = (ob == draw_ctx->obact) &&
+ (ob->mode == OB_MODE_SCULPT_CURVES);
const bool has_surface = ELEM(ob->type,
OB_MESH,
OB_CURVES_LEGACY,
@@ -329,8 +335,8 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0;
const bool draw_wires = draw_surface && has_surface &&
(pd->wireframe_mode || !pd->hide_overlays);
- const bool draw_outlines = !in_edit_mode && !in_paint_mode && renderable && has_surface &&
- !instance_parent_in_edit_mode &&
+ const bool draw_outlines = !in_edit_mode && !in_paint_mode && !in_sculpt_curve_mode &&
+ renderable && has_surface && !instance_parent_in_edit_mode &&
(pd->v3d_flag & V3D_SELECT_OUTLINE) &&
(ob->base_flag & BASE_SELECTED);
const bool draw_bone_selection = (ob->type == OB_MESH) && pd->armature.do_pose_fade_geom &&
@@ -428,6 +434,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
if (in_sculpt_mode) {
OVERLAY_sculpt_cache_populate(vedata, ob);
}
+ else if (in_curves_sculpt_mode) {
+ OVERLAY_sculpt_curves_cache_populate(vedata, ob);
+ }
if (draw_motion_paths) {
OVERLAY_motion_path_cache_populate(vedata, ob);
@@ -591,6 +600,9 @@ static void OVERLAY_draw_scene(void *vedata)
case CTX_MODE_SCULPT:
OVERLAY_sculpt_draw(vedata);
break;
+ case CTX_MODE_SCULPT_CURVES:
+ OVERLAY_sculpt_curves_draw(vedata);
+ break;
case CTX_MODE_EDIT_MESH:
case CTX_MODE_POSE:
case CTX_MODE_PAINT_WEIGHT:
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index 5d8ba06e181..4354777986c 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -1310,16 +1310,19 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
}
else {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
+ ListBase targets = {NULL, NULL};
- if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag & (1 << 0))) {
- ListBase targets = {NULL, NULL};
+ if ((curcon->ui_expand_flag & (1 << 0)) && BKE_constraint_targets_get(curcon, &targets)) {
bConstraintTarget *ct;
- cti->get_constraint_targets(curcon, &targets);
+ BKE_constraint_custom_object_space_init(cob, curcon);
for (ct = targets.first; ct; ct = ct->next) {
/* calculate target's matrix */
- if (cti->get_target_matrix) {
+ if (ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE) {
+ copy_m4_m4(ct->matrix, cob->space_obj_world_matrix);
+ }
+ else if (cti->get_target_matrix) {
cti->get_target_matrix(depsgraph, curcon, cob, ct, DEG_get_ctime(depsgraph));
}
else {
@@ -1328,9 +1331,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color);
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 1);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 1);
}
}
}
@@ -1357,7 +1358,7 @@ static void OVERLAY_volume_extra(OVERLAY_ExtraCallBuffers *cb,
/* Don't show smoke before simulation starts, this could be made an option in the future. */
const bool draw_velocity = (fds->draw_velocity && fds->fluid &&
- CFRA >= fds->point_cache[0]->startframe);
+ scene->r.cfra >= fds->point_cache[0]->startframe);
/* Show gridlines only for slices with no interpolation. */
const bool show_gridlines = (fds->show_gridlines && fds->fluid &&
@@ -1550,8 +1551,9 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob)
(md = BKE_modifiers_findby_type(ob, eModifierType_Fluid)) &&
(BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) &&
(((FluidModifierData *)md)->domain != NULL) &&
- (CFRA >= (((FluidModifierData *)md)->domain->cache_frame_start)) &&
- (CFRA <= (((FluidModifierData *)md)->domain->cache_frame_end));
+ (scene->r.cfra >=
+ (((FluidModifierData *)md)->domain->cache_frame_start)) &&
+ (scene->r.cfra <= (((FluidModifierData *)md)->domain->cache_frame_end));
float *color;
int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color);
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
index eea9a1a1bef..f2e2acc98a9 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.c
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -133,6 +133,10 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps);
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", 0.0);
+
+ GPUShader *sh_curves = OVERLAY_shader_outline_prepass_curves();
+ pd->outlines_curves_grp = grp = DRW_shgroup_create(sh_curves, psl->outlines_prepass_ps);
+ DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
}
/* outlines_prepass_ps is still needed for selection of probes. */
@@ -267,6 +271,12 @@ static void OVERLAY_outline_volume(OVERLAY_PrivateData *pd, Object *ob)
DRW_shgroup_call(shgroup, geom, ob);
}
+static void OVERLAY_outline_curves(OVERLAY_PrivateData *pd, Object *ob)
+{
+ DRWShadingGroup *shgroup = pd->outlines_curves_grp;
+ DRW_shgroup_curves_create_sub(ob, shgroup, NULL);
+}
+
void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
Object *ob,
OVERLAY_DupliData *dupli,
@@ -293,6 +303,11 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
return;
}
+ if (ob->type == OB_CURVES) {
+ OVERLAY_outline_curves(pd, ob);
+ return;
+ }
+
if (ob->type == OB_POINTCLOUD && pd->wireframe_mode) {
/* Looks bad in this case. Could be relaxed if we draw a
* wireframe of some sort in the future. */
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index 23c20a186a0..7d216ca54cf 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -116,6 +116,7 @@ typedef struct OVERLAY_PassList {
DRWPass *particle_ps;
DRWPass *pointcloud_ps;
DRWPass *sculpt_mask_ps;
+ DRWPass *sculpt_curves_selection_ps;
DRWPass *volume_ps;
DRWPass *wireframe_ps;
DRWPass *wireframe_xray_ps;
@@ -267,6 +268,7 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *motion_path_lines_grp;
DRWShadingGroup *motion_path_points_grp;
DRWShadingGroup *outlines_grp;
+ DRWShadingGroup *outlines_curves_grp;
DRWShadingGroup *outlines_ptcloud_grp;
DRWShadingGroup *outlines_gpencil_grp;
DRWShadingGroup *paint_depth_grp;
@@ -279,6 +281,7 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *particle_shapes_grp;
DRWShadingGroup *pointcloud_dots_grp;
DRWShadingGroup *sculpt_mask_grp;
+ DRWShadingGroup *sculpt_curves_selection_grp;
DRWShadingGroup *volume_selection_surface_grp;
DRWShadingGroup *wires_grp[2][2]; /* With and without coloring. */
DRWShadingGroup *wires_all_grp[2][2]; /* With and without coloring. */
@@ -669,6 +672,10 @@ void OVERLAY_sculpt_cache_init(OVERLAY_Data *vedata);
void OVERLAY_sculpt_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_sculpt_draw(OVERLAY_Data *vedata);
+void OVERLAY_sculpt_curves_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_sculpt_curves_draw(OVERLAY_Data *vedata);
+
void OVERLAY_wireframe_init(OVERLAY_Data *vedata);
void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata);
void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
@@ -737,6 +744,7 @@ GPUShader *OVERLAY_shader_motion_path_line(void);
GPUShader *OVERLAY_shader_motion_path_vert(void);
GPUShader *OVERLAY_shader_uniform_color(void);
GPUShader *OVERLAY_shader_outline_prepass(bool use_wire);
+GPUShader *OVERLAY_shader_outline_prepass_curves(void);
GPUShader *OVERLAY_shader_outline_prepass_gpencil(void);
GPUShader *OVERLAY_shader_outline_prepass_pointcloud(void);
GPUShader *OVERLAY_shader_extra_grid(void);
@@ -750,6 +758,7 @@ GPUShader *OVERLAY_shader_paint_wire(void);
GPUShader *OVERLAY_shader_particle_dot(void);
GPUShader *OVERLAY_shader_particle_shape(void);
GPUShader *OVERLAY_shader_sculpt_mask(void);
+GPUShader *OVERLAY_shader_sculpt_curves_selection(void);
GPUShader *OVERLAY_shader_volume_velocity(bool use_needle, bool use_mac);
GPUShader *OVERLAY_shader_volume_gridlines(bool color_with_flags, bool color_range);
GPUShader *OVERLAY_shader_wireframe(bool custom_bias);
diff --git a/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc b/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc
new file mode 100644
index 00000000000..b8021124f27
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_sculpt_curves.cc
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "draw_cache_impl.h"
+#include "overlay_private.h"
+
+#include "BKE_curves.hh"
+
+void OVERLAY_sculpt_curves_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+
+ const DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->sculpt_curves_selection_ps, state | pd->clipping_state);
+
+ GPUShader *sh = OVERLAY_shader_sculpt_curves_selection();
+ pd->sculpt_curves_selection_grp = DRW_shgroup_create(sh, psl->sculpt_curves_selection_ps);
+ DRWShadingGroup *grp = pd->sculpt_curves_selection_grp;
+
+ /* Reuse the same mask opacity from sculpt mode, since it wasn't worth it to add a different
+ * property yet. */
+ DRW_shgroup_uniform_float_copy(grp, "selection_opacity", pd->overlay.sculpt_mode_mask_opacity);
+}
+
+static bool everything_selected(const Curves &curves_id)
+{
+ if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
+ /* When the selection is disabled, conceptually everything is selected. */
+ return true;
+ }
+ const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
+ curves_id.geometry);
+ blender::VArray<float> selection;
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT:
+ selection = curves.selection_point_float();
+ break;
+ case ATTR_DOMAIN_CURVE:
+ selection = curves.selection_curve_float();
+ break;
+ }
+ return selection.is_single() && selection.get_internal_single() == 1.0f;
+}
+
+void OVERLAY_sculpt_curves_cache_populate(OVERLAY_Data *vedata, Object *object)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ Curves *curves = static_cast<Curves *>(object->data);
+
+ /* As an optimization, return early if everything is selected. */
+ if (everything_selected(*curves)) {
+ return;
+ }
+
+ /* Retrieve the location of the texture. */
+ const char *name = curves->selection_domain == ATTR_DOMAIN_POINT ? ".selection_point_float" :
+ ".selection_curve_float";
+
+ bool is_point_domain;
+ GPUTexture **texture = DRW_curves_texture_for_evaluated_attribute(
+ curves, name, &is_point_domain);
+ if (texture == nullptr) {
+ return;
+ }
+
+ /* Evaluate curves and their attributes if necessary. */
+ DRWShadingGroup *grp = DRW_shgroup_curves_create_sub(
+ object, pd->sculpt_curves_selection_grp, nullptr);
+ if (*texture == nullptr) {
+ return;
+ }
+
+ DRW_shgroup_uniform_bool_copy(grp, "is_point_domain", is_point_domain);
+ DRW_shgroup_uniform_texture(grp, "selection_tx", *texture);
+}
+
+void OVERLAY_sculpt_curves_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(pd->painting.in_front ? fbl->overlay_in_front_fb :
+ fbl->overlay_default_fb);
+ }
+
+ DRW_draw_pass(psl->sculpt_curves_selection_ps);
+}
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index 48146fbddfb..2373363ab9d 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -76,6 +76,7 @@ typedef struct OVERLAY_Shaders {
GPUShader *motion_path_line;
GPUShader *motion_path_vert;
GPUShader *outline_prepass;
+ GPUShader *outline_prepass_curves;
GPUShader *outline_prepass_gpencil;
GPUShader *outline_prepass_pointcloud;
GPUShader *outline_prepass_wire;
@@ -90,6 +91,7 @@ typedef struct OVERLAY_Shaders {
GPUShader *particle_shape;
GPUShader *pointcloud_dot;
GPUShader *sculpt_mask;
+ GPUShader *sculpt_curves_selection;
GPUShader *uniform_color;
GPUShader *volume_velocity_needle_sh;
GPUShader *volume_velocity_mac_sh;
@@ -650,6 +652,18 @@ GPUShader *OVERLAY_shader_outline_prepass(bool use_wire)
return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass;
}
+GPUShader *OVERLAY_shader_outline_prepass_curves()
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->outline_prepass_curves) {
+ sh_data->outline_prepass_curves = GPU_shader_create_from_info_name(
+ draw_ctx->sh_cfg ? "overlay_outline_prepass_curves_clipped" :
+ "overlay_outline_prepass_curves");
+ }
+ return sh_data->outline_prepass_curves;
+}
+
GPUShader *OVERLAY_shader_outline_prepass_gpencil(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -792,6 +806,18 @@ GPUShader *OVERLAY_shader_sculpt_mask(void)
return sh_data->sculpt_mask;
}
+GPUShader *OVERLAY_shader_sculpt_curves_selection(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->sculpt_curves_selection) {
+ sh_data->sculpt_curves_selection = GPU_shader_create_from_info_name(
+ draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED ? "overlay_sculpt_curves_selection_clipped" :
+ "overlay_sculpt_curves_selection");
+ }
+ return sh_data->sculpt_curves_selection;
+}
+
struct GPUShader *OVERLAY_shader_uniform_color(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
diff --git a/source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
index fe67dd473b7..0dba8b54e35 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/antialiasing_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
@@ -9,7 +9,7 @@ GPU_SHADER_CREATE_INFO(overlay_antialiasing)
.sampler(2, ImageType::FLOAT_2D, "lineTex")
.push_constant(Type::BOOL, "doSmoothLines")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("antialiasing_frag.glsl")
+ .fragment_source("overlay_antialiasing_frag.glsl")
.additional_info("draw_fullscreen", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_xray_fade)
@@ -18,5 +18,5 @@ GPU_SHADER_CREATE_INFO(overlay_xray_fade)
.sampler(1, ImageType::DEPTH_2D, "xrayDepthTex")
.push_constant(Type::FLOAT, "opacity")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("xray_fade_frag.glsl")
+ .fragment_source("overlay_xray_fade_frag.glsl")
.additional_info("draw_fullscreen");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/armature_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh
index d89272a50cf..9f2acceed97 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/armature_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_armature_info.hh
@@ -25,8 +25,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_sphere_outline)
/* Per instance. */
.vertex_in(1, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_sphere_outline_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_sphere_outline_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_sphere_outline_clipped)
@@ -47,8 +47,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_sphere_solid)
.vertex_in(2, Type::MAT4, "inst_obmat")
// .depth_layout(DepthLayout::GREATER) /* TODO */
.vertex_out(overlay_armature_sphere_solid_iface)
- .vertex_source("armature_sphere_solid_vert.glsl")
- .fragment_source("armature_sphere_solid_frag.glsl")
+ .vertex_source("overlay_armature_sphere_solid_vert.glsl")
+ .fragment_source("overlay_armature_sphere_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_sphere_solid_clipped)
@@ -79,9 +79,9 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_outline)
.vertex_out(overlay_armature_shape_outline_iface)
.geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2)
.geometry_out(overlay_armature_wire_iface)
- .vertex_source("armature_shape_outline_vert.glsl")
- .geometry_source("armature_shape_outline_geom.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_shape_outline_vert.glsl")
+ .geometry_source("overlay_armature_shape_outline_geom.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_outline_clipped)
@@ -100,8 +100,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_solid)
.vertex_in(2, Type::MAT4, "inst_obmat")
.depth_write(DepthWrite::GREATER)
.vertex_out(overlay_armature_shape_solid_iface)
- .vertex_source("armature_shape_solid_vert.glsl")
- .fragment_source("armature_shape_solid_frag.glsl")
+ .vertex_source("overlay_armature_shape_solid_vert.glsl")
+ .fragment_source("overlay_armature_shape_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_solid_clipped)
@@ -115,8 +115,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_shape_wire)
/* Per instance. */
.vertex_in(2, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_shape_wire_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_shape_wire_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_shape_wire_clipped)
@@ -140,8 +140,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_envelope_outline)
.vertex_in(5, Type::VEC4, "outlineColorSize")
.vertex_in(6, Type::VEC3, "xAxis")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_envelope_outline_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_envelope_outline_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_envelope_outline_clipped)
@@ -164,8 +164,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_envelope_solid)
.vertex_in(5, Type::VEC3, "boneColor")
.vertex_out(overlay_armature_envelope_solid_iface)
.push_constant(Type::BOOL, "isDistance")
- .vertex_source("armature_envelope_solid_vert.glsl")
- .fragment_source("armature_envelope_solid_frag.glsl")
+ .vertex_source("overlay_armature_envelope_solid_vert.glsl")
+ .fragment_source("overlay_armature_envelope_solid_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common");
GPU_SHADER_CREATE_INFO(overlay_armature_envelope_solid_clipped)
@@ -198,8 +198,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_stick)
.vertex_in(7, Type::VEC4, "tailColor")
.define("do_wire", "(wireColor.a > 0.0)")
.vertex_out(overlay_armature_stick_iface)
- .vertex_source("armature_stick_vert.glsl")
- .fragment_source("armature_stick_frag.glsl")
+ .vertex_source("overlay_armature_stick_vert.glsl")
+ .fragment_source("overlay_armature_stick_frag.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_stick_clipped)
@@ -218,12 +218,12 @@ GPU_SHADER_CREATE_INFO(overlay_armature_dof)
.vertex_in(1, Type::VEC4, "color")
.vertex_in(2, Type::MAT4, "inst_obmat")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_dof_vert.glsl")
+ .vertex_source("overlay_armature_dof_vert.glsl")
.additional_info("overlay_frag_output", "overlay_armature_common", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire)
.do_static_compilation(true)
- .fragment_source("armature_dof_solid_frag.glsl")
+ .fragment_source("overlay_armature_dof_solid_frag.glsl")
.additional_info("overlay_armature_dof");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire_clipped)
@@ -232,7 +232,7 @@ GPU_SHADER_CREATE_INFO(overlay_armature_dof_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_armature_dof_solid)
.do_static_compilation(true)
- .fragment_source("armature_dof_solid_frag.glsl")
+ .fragment_source("overlay_armature_dof_solid_frag.glsl")
.additional_info("overlay_armature_dof");
GPU_SHADER_CREATE_INFO(overlay_armature_dof_solid_clipped)
@@ -251,8 +251,8 @@ GPU_SHADER_CREATE_INFO(overlay_armature_wire)
.vertex_in(1, Type::VEC4, "color")
.push_constant(Type::FLOAT, "alpha")
.vertex_out(overlay_armature_wire_iface)
- .vertex_source("armature_wire_vert.glsl")
- .fragment_source("armature_wire_frag.glsl")
+ .vertex_source("overlay_armature_wire_vert.glsl")
+ .fragment_source("overlay_armature_wire_frag.glsl")
.additional_info("overlay_frag_output", "draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_armature_wire_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/background_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh
index c96d302d861..88a012c35c9 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/background_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_background_info.hh
@@ -9,17 +9,15 @@ GPU_SHADER_CREATE_INFO(overlay_background)
.sampler(1, ImageType::DEPTH_2D, "depthBuffer")
.push_constant(Type::INT, "bgType")
.push_constant(Type::VEC4, "colorOverride")
- .fragment_source("background_frag.glsl")
+ .fragment_source("overlay_background_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_fullscreen", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_clipbound)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.push_constant(Type::VEC4, "color")
.push_constant(Type::VEC3, "boundbox", 8)
- .vertex_source("clipbound_vert.glsl")
+ .vertex_source("overlay_clipbound_vert.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_view");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
index e6f15046838..58f96110887 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/edit_mode_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
@@ -19,7 +19,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_common)
.push_constant(Type::BOOL, "selectEdges")
.push_constant(Type::FLOAT, "alpha")
.push_constant(Type::IVEC4, "dataMask")
- .vertex_source("edit_mesh_vert.glsl")
+ .vertex_source("overlay_edit_mesh_vert.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_vert_iface, "")
@@ -29,13 +29,12 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_vert_iface, "")
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_vert)
.do_static_compilation(true)
.builtins(BuiltinBits::POINT_SIZE)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.define("VERT")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::IVEC4, "data")
.vertex_in(2, Type::VEC3, "vnor")
.vertex_out(overlay_edit_mesh_vert_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_edge_iface, "geometry_in")
@@ -58,8 +57,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge)
.vertex_out(overlay_edit_mesh_edge_iface)
.geometry_out(overlay_edit_mesh_edge_geom_iface)
.geometry_layout(PrimitiveIn::LINES, PrimitiveOut::TRIANGLE_STRIP, 4)
- .geometry_source("edit_mesh_geom.glsl")
- .fragment_source("edit_mesh_frag.glsl")
+ .geometry_source("overlay_edit_mesh_geom.glsl")
+ .fragment_source("overlay_edit_mesh_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge_flat)
@@ -69,13 +68,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_edge_flat)
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_face)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.define("FACE")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::IVEC4, "data")
.vertex_in(2, Type::VEC3, "vnor")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_facedot)
@@ -86,12 +84,11 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_facedot)
.vertex_in(2, Type::VEC4, "norAndFlag")
.define("vnor", "norAndFlag.xyz")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_mesh_common");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_normal)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "lnor")
.vertex_in(2, Type::VEC4, "vnor")
@@ -103,8 +100,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_normal)
.push_constant(Type::BOOL, "isConstantScreenSizeNormals")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_mesh_normal_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_mesh_normal_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat_instanced_attr", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_mesh_analysis_iface, "").smooth(Type::VEC4, "weightColor");
@@ -116,20 +113,19 @@ GPU_SHADER_CREATE_INFO(overlay_edit_mesh_analysis)
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.fragment_out(0, Type::VEC4, "fragColor")
.vertex_out(overlay_edit_mesh_analysis_iface)
- .vertex_source("edit_mesh_analysis_vert.glsl")
- .fragment_source("edit_mesh_analysis_frag.glsl")
+ .vertex_source("overlay_edit_mesh_analysis_vert.glsl")
+ .fragment_source("overlay_edit_mesh_analysis_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_skin_root)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* Colors are already in linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "size")
.vertex_in(2, Type::VEC3, "local_pos")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_mesh_skin_root_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_mesh_skin_root_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat_instanced_attr", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_mesh_vert_clipped)
@@ -193,9 +189,9 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges)
.push_constant(Type::FLOAT, "alpha")
.push_constant(Type::FLOAT, "dashLength")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_edges_vert.glsl")
- .geometry_source("edit_uv_edges_geom.glsl")
- .fragment_source("edit_uv_edges_frag.glsl")
+ .vertex_source("overlay_edit_uv_edges_vert.glsl")
+ .geometry_source("overlay_edit_uv_edges_geom.glsl")
+ .fragment_source("overlay_edit_uv_edges_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges_select)
@@ -205,28 +201,24 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_edges_select)
GPU_SHADER_CREATE_INFO(overlay_edit_uv_faces)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "uvOpacity")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_faces_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_faces_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_face_dots)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "pointSize")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_face_dots_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_face_dots_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_INTERFACE_INFO(overlay_edit_uv_vert_iface, "")
@@ -236,8 +228,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_uv_vert_iface, "")
GPU_SHADER_CREATE_INFO(overlay_edit_uv_verts)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "au")
.vertex_in(1, Type::INT, "flag")
.push_constant(Type::FLOAT, "pointSize")
@@ -245,19 +235,17 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_verts)
.push_constant(Type::VEC4, "color")
.vertex_out(overlay_edit_uv_vert_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_verts_vert.glsl")
- .fragment_source("edit_uv_verts_frag.glsl")
+ .vertex_source("overlay_edit_uv_verts_vert.glsl")
+ .fragment_source("overlay_edit_uv_verts_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_tiled_image_borders)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_INTERFACE_INFO(edit_uv_image_iface, "").smooth(Type::VEC2, "uvs");
@@ -266,13 +254,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_stencil_image)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
.vertex_out(edit_uv_image_iface)
- .vertex_source("edit_uv_image_vert.glsl")
+ .vertex_source("overlay_edit_uv_image_vert.glsl")
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.push_constant(Type::BOOL, "imgPremultiplied")
.push_constant(Type::BOOL, "imgAlphaBlend")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("image_frag.glsl")
+ .fragment_source("overlay_image_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
@@ -282,8 +270,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_image_vert.glsl")
- .fragment_source("edit_uv_image_mask_frag.glsl")
+ .vertex_source("overlay_edit_uv_image_vert.glsl")
+ .fragment_source("overlay_edit_uv_image_mask_frag.glsl")
.additional_info("draw_mesh");
/** \} */
@@ -293,14 +281,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_uv_mask_image)
* \{ */
GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC2, "pos")
.push_constant(Type::VEC2, "aspect")
.vertex_out(overlay_edit_nopersp_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_stretching_vert.glsl")
- .fragment_source("gpu_shader_2D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_stretching_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_uv_stretching_area)
@@ -328,8 +314,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type::IN
GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle)
.do_static_compilation(true)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_curve_handle_iface)
@@ -338,9 +322,9 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle)
.push_constant(Type::BOOL, "showCurveHandles")
.push_constant(Type::INT, "curveHandleDisplay")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_handle_vert.glsl")
- .geometry_source("edit_curve_handle_geom.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_handle_vert.glsl")
+ .geometry_source("overlay_edit_curve_handle_geom.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_clipped)
@@ -350,16 +334,14 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_curve_point)
.do_static_compilation(true)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
.push_constant(Type::BOOL, "showCurveHandles")
.push_constant(Type::INT, "curveHandleDisplay")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_point_clipped)
@@ -368,8 +350,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC3, "nor")
.vertex_in(2, Type::VEC3, "tan")
@@ -377,8 +357,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire)
.push_constant(Type::FLOAT, "normalSize")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_curve_wire_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_edit_curve_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat", "draw_resource_id_uniform", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire_clipped)
@@ -393,14 +373,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_lattice_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_lattice_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point_clipped)
@@ -409,15 +387,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "weight")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.vertex_out(overlay_edit_smooth_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_lattice_wire_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_lattice_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped)
@@ -432,16 +408,14 @@ GPU_SHADER_CREATE_INFO(overlay_edit_lattice_wire_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "color")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.push_constant(Type::BOOL, "useWeight")
.vertex_out(overlay_edit_smooth_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_particle_strand_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_edit_particle_strand_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped)
@@ -450,14 +424,12 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_strand_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_particle_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "color")
.vertex_out(overlay_edit_flat_color_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_particle_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_particle_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_particle_point_clipped)
@@ -472,8 +444,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil)
.typedef_source("overlay_shader_shared.h")
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "ma")
.vertex_in(2, Type::UINT, "vflag")
@@ -487,13 +457,13 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil)
.push_constant(Type::VEC4, "gpEditColor")
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_gpencil_vert.glsl")
+ .vertex_source("overlay_edit_gpencil_vert.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_wire)
.do_static_compilation(true)
.vertex_out(overlay_edit_smooth_color_iface)
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_edit_gpencil");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_wire_clipped)
@@ -504,7 +474,7 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point)
.do_static_compilation(true)
.define("USE_POINTS")
.vertex_out(overlay_edit_flat_color_iface)
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("overlay_edit_gpencil");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point_clipped)
@@ -514,8 +484,6 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_point_clipped)
/* TODO(fclem): Refactor this to take list of point instead of drawing 1 point per drawcall. */
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::INT, "data")
.vertex_out(overlay_edit_flat_color_iface)
@@ -523,8 +491,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point)
.push_constant(Type::FLOAT, "pSize")
.push_constant(Type::VEC4, "pColor")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_gpencil_guide_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_edit_gpencil_guide_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point_clipped)
@@ -542,8 +510,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_gpencil_guide_point_clipped)
GPU_SHADER_CREATE_INFO(overlay_depth_only)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("depth_only_vert.glsl")
- .fragment_source("gpu_shader_depth_only_frag.glsl")
+ .vertex_source("overlay_depth_only_vert.glsl")
+ .fragment_source("overlay_depth_only_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_depth_only_clipped)
@@ -558,13 +526,11 @@ GPU_SHADER_CREATE_INFO(overlay_depth_only_clipped)
GPU_SHADER_CREATE_INFO(overlay_uniform_color)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("depth_only_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_depth_only_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_uniform_color_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh
index b9b1b73dbd4..5b50bbcaa55 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/extra_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh
@@ -21,8 +21,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra)
.vertex_out(overlay_extra_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_extra_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_select)
@@ -53,8 +53,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_grid)
.push_constant(Type::BOOL, "isTransform")
.vertex_out(overlay_extra_grid_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("extra_lightprobe_grid_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_extra_lightprobe_grid_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_grid_clipped)
@@ -75,8 +75,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_groundline)
.vertex_out(overlay_extra_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_groundline_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_extra_groundline_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_groundline_clipped)
@@ -103,8 +103,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_wire)
.vertex_out(overlay_extra_wire_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_wire_vert.glsl")
- .fragment_source("extra_wire_frag.glsl")
+ .vertex_source("overlay_extra_wire_vert.glsl")
+ .fragment_source("overlay_extra_wire_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_wire_select)
@@ -148,8 +148,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_point)
.push_constant(Type::VEC4, "color")
.vertex_out(overlay_extra_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("extra_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_varying_outline_aa_frag.glsl")
+ .vertex_source("overlay_extra_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_varying_outline_aa_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_point_clipped)
@@ -165,8 +165,8 @@ GPU_SHADER_CREATE_INFO(overlay_extra_loose_point)
.vertex_out(overlay_extra_loose_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("extra_loose_point_vert.glsl")
- .fragment_source("extra_loose_point_frag.glsl")
+ .vertex_source("overlay_extra_loose_point_vert.glsl")
+ .fragment_source("overlay_extra_loose_point_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_extra_loose_point_clipped)
@@ -194,9 +194,9 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_line)
.geometry_out(overlay_motion_path_line_iface)
.geometry_layout(PrimitiveIn::LINES, PrimitiveOut::TRIANGLE_STRIP, 4)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("motion_path_line_vert.glsl")
- .geometry_source("motion_path_line_geom.glsl")
- .fragment_source("motion_path_line_frag.glsl")
+ .vertex_source("overlay_motion_path_line_vert.glsl")
+ .geometry_source("overlay_motion_path_line_geom.glsl")
+ .fragment_source("overlay_motion_path_line_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_motion_path_line_clipped)
@@ -215,8 +215,8 @@ GPU_SHADER_CREATE_INFO(overlay_motion_path_point)
.push_constant(Type::VEC3, "customColor")
.vertex_out(overlay_motion_path_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("motion_path_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_motion_path_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_motion_path_point_clipped)
@@ -242,8 +242,8 @@ GPU_SHADER_CREATE_INFO(overlay_image)
.vertex_out(overlay_image_iface)
.sampler(0, ImageType::FLOAT_2D, "imgTexture")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("image_vert.glsl")
- .fragment_source("image_frag.glsl")
+ .vertex_source("overlay_image_vert.glsl")
+ .fragment_source("overlay_image_frag.glsl")
.additional_info("draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_image_clipped)
@@ -266,8 +266,8 @@ GPU_SHADER_CREATE_INFO(overlay_gpencil_canvas)
.push_constant(Type::INT, "halfLineCount")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .vertex_source("edit_gpencil_canvas_vert.glsl")
- .fragment_source("extra_frag.glsl")
+ .vertex_source("overlay_edit_gpencil_canvas_vert.glsl")
+ .fragment_source("overlay_extra_frag.glsl")
.additional_info("draw_mesh", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_gpencil_canvas_clipped)
@@ -289,7 +289,7 @@ GPU_SHADER_CREATE_INFO(overlay_particle)
.vertex_in(1, Type::VEC4, "part_rot")
.vertex_in(2, Type::FLOAT, "part_val")
.vertex_out(overlay_particle_iface)
- .vertex_source("particle_vert.glsl")
+ .vertex_source("overlay_particle_vert.glsl")
.additional_info("draw_globals");
GPU_SHADER_CREATE_INFO(overlay_particle_dot)
@@ -299,7 +299,7 @@ GPU_SHADER_CREATE_INFO(overlay_particle_dot)
.define("pos", "vec3(0.0)")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .fragment_source("particle_frag.glsl")
+ .fragment_source("overlay_particle_frag.glsl")
.additional_info("overlay_particle", "draw_mesh");
GPU_SHADER_CREATE_INFO(overlay_particle_dot_clipped)
@@ -308,13 +308,11 @@ GPU_SHADER_CREATE_INFO(overlay_particle_dot_clipped)
GPU_SHADER_CREATE_INFO(overlay_particle_shape)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
/* Instantiated Attrs. */
.vertex_in(3, Type::VEC3, "pos")
.vertex_in(4, Type::INT, "vclass")
.fragment_out(0, Type::VEC4, "fragColor")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("overlay_particle", "draw_modelmat", "draw_resource_id_uniform");
GPU_SHADER_CREATE_INFO(overlay_particle_shape_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/facing_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh
index 6d6806eaa80..6d528bbba62 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/facing_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_facing_info.hh
@@ -5,8 +5,8 @@
GPU_SHADER_CREATE_INFO(overlay_facing)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("facing_vert.glsl")
- .fragment_source("facing_frag.glsl")
+ .vertex_source("overlay_facing_vert.glsl")
+ .fragment_source("overlay_facing_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_mesh", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/grid_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh
index d02014c98a0..a8f1281d53a 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/grid_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_grid_info.hh
@@ -15,8 +15,8 @@ GPU_SHADER_CREATE_INFO(overlay_grid)
.uniform_buf(3, "OVERLAY_GridData", "grid_buf")
.push_constant(Type::VEC3, "plane_axes")
.push_constant(Type::INT, "grid_flag")
- .vertex_source("grid_vert.glsl")
- .fragment_source("grid_frag.glsl")
+ .vertex_source("overlay_grid_vert.glsl")
+ .fragment_source("overlay_grid_frag.glsl")
.additional_info("draw_view", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_grid_background)
@@ -25,17 +25,15 @@ GPU_SHADER_CREATE_INFO(overlay_grid_background)
.sampler(0, ImageType::DEPTH_2D, "depthBuffer")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("grid_background_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_grid_background_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_grid_image)
.do_static_compilation(true)
- /* NOTE: Color already in Linear space. Which is what we want. */
- .define("srgbTarget", "false")
.vertex_in(0, Type::VEC3, "pos")
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("edit_uv_tiled_image_borders_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_edit_uv_tiled_image_borders_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_modelmat");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/outline_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh
index 21575747efa..288fb3b3cbd 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/outline_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_outline_info.hh
@@ -13,13 +13,13 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass)
.vertex_out(overlay_outline_prepass_iface)
/* Using uint because 16bit uint can contain more ids than int. */
.fragment_out(0, Type::UINT, "out_object_id")
- .fragment_source("outline_prepass_frag.glsl")
+ .fragment_source("overlay_outline_prepass_frag.glsl")
.additional_info("draw_resource_handle");
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_mesh)
.do_static_compilation(true)
.vertex_in(0, Type::VEC3, "pos")
- .vertex_source("outline_prepass_vert.glsl")
+ .vertex_source("overlay_outline_prepass_vert.glsl")
.additional_info("draw_mesh", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -29,6 +29,16 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_mesh_clipped)
GPU_SHADER_INTERFACE_INFO(overlay_outline_prepass_wire_iface, "vert").flat(Type::VEC3, "pos");
+GPU_SHADER_CREATE_INFO(overlay_outline_prepass_curves)
+ .do_static_compilation(true)
+ .vertex_source("overlay_outline_prepass_curves_vert.glsl")
+ .additional_info("draw_hair", "overlay_outline_prepass")
+ .additional_info("draw_object_infos");
+
+GPU_SHADER_CREATE_INFO(overlay_outline_prepass_curves_clipped)
+ .do_static_compilation(true)
+ .additional_info("overlay_outline_prepass_curves", "drw_clipped");
+
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire)
.do_static_compilation(true)
.define("USE_GEOM")
@@ -36,8 +46,8 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_wire)
.vertex_out(overlay_outline_prepass_wire_iface)
.geometry_layout(PrimitiveIn::LINES_ADJACENCY, PrimitiveOut::LINE_STRIP, 2)
.geometry_out(overlay_outline_prepass_iface)
- .vertex_source("outline_prepass_vert.glsl")
- .geometry_source("outline_prepass_geom.glsl")
+ .vertex_source("overlay_outline_prepass_vert.glsl")
+ .geometry_source("overlay_outline_prepass_geom.glsl")
.additional_info("draw_mesh", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -56,12 +66,12 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil)
.push_constant(Type::BOOL, "isTransform")
.vertex_out(overlay_outline_prepass_iface)
.vertex_out(overlay_outline_prepass_gpencil_iface)
- .vertex_source("outline_prepass_gpencil_vert.glsl")
+ .vertex_source("overlay_outline_prepass_gpencil_vert.glsl")
.push_constant(Type::BOOL, "gpStrokeOrder3d") /* TODO(fclem): Move to a GPencil object UBO. */
.push_constant(Type::VEC4, "gpDepthPlane") /* TODO(fclem): Move to a GPencil object UBO. */
/* Using uint because 16bit uint can contain more ids than int. */
.fragment_out(0, Type::UINT, "out_object_id")
- .fragment_source("outline_prepass_gpencil_frag.glsl")
+ .fragment_source("overlay_outline_prepass_gpencil_frag.glsl")
.additional_info("draw_gpencil", "draw_resource_handle");
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped)
@@ -70,7 +80,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_prepass_gpencil_clipped)
GPU_SHADER_CREATE_INFO(overlay_outline_prepass_pointcloud)
.do_static_compilation(true)
- .vertex_source("outline_prepass_pointcloud_vert.glsl")
+ .vertex_source("overlay_outline_prepass_pointcloud_vert.glsl")
.additional_info("draw_pointcloud", "overlay_outline_prepass")
.additional_info("draw_object_infos");
@@ -95,7 +105,7 @@ GPU_SHADER_CREATE_INFO(overlay_outline_detect)
.sampler(2, ImageType::DEPTH_2D, "sceneDepth")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
- .fragment_source("outline_detect_frag.glsl")
+ .fragment_source("overlay_outline_detect_frag.glsl")
.additional_info("draw_fullscreen", "draw_view", "draw_globals");
/** \} */
diff --git a/source/blender/draw/engines/overlay/shaders/infos/paint_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh
index bbec79d515f..3083d5a463b 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/paint_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_paint_info.hh
@@ -10,13 +10,12 @@
GPU_SHADER_CREATE_INFO(overlay_paint_face)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* NOTE: Color already in Linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "nor") /* Select flag on the 4th component. */
.push_constant(Type::VEC4, "color")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_face_vert.glsl")
- .fragment_source("gpu_shader_uniform_color_frag.glsl")
+ .vertex_source("overlay_paint_face_vert.glsl")
+ .fragment_source("overlay_uniform_color_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_face_clipped)
@@ -40,8 +39,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_point)
.vertex_in(1, Type::VEC4, "nor") /* Select flag on the 4th component. */
.vertex_out(overlay_overlay_paint_point_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_point_vert.glsl")
- .fragment_source("gpu_shader_point_varying_color_frag.glsl")
+ .vertex_source("overlay_paint_point_vert.glsl")
+ .fragment_source("overlay_point_varying_color_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_point_clipped)
@@ -70,8 +69,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_texture)
.push_constant(Type::BOOL, "maskInvertStencil")
.push_constant(Type::BOOL, "maskImagePremultiplied")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_texture_vert.glsl")
- .fragment_source("paint_texture_frag.glsl")
+ .vertex_source("overlay_paint_texture_vert.glsl")
+ .fragment_source("overlay_paint_texture_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_texture_clipped)
@@ -97,8 +96,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_vertcol)
.push_constant(Type::FLOAT, "opacity") /* `1.0` by default. */
.push_constant(Type::BOOL, "useAlphaBlend") /* `false` by default. */
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_vertcol_vert.glsl")
- .fragment_source("paint_vertcol_frag.glsl")
+ .vertex_source("overlay_paint_vertcol_vert.glsl")
+ .fragment_source("overlay_paint_vertcol_frag.glsl")
.additional_info("draw_modelmat");
GPU_SHADER_CREATE_INFO(overlay_paint_vertcol_clipped)
@@ -129,8 +128,8 @@ GPU_SHADER_CREATE_INFO(overlay_paint_weight)
.push_constant(Type::FLOAT, "opacity") /* `1.0` by default. */
.push_constant(Type::BOOL, "drawContours") /* `false` by default. */
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_weight_vert.glsl")
- .fragment_source("paint_weight_frag.glsl")
+ .vertex_source("overlay_paint_weight_vert.glsl")
+ .fragment_source("overlay_paint_weight_frag.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_weight_fake_shading)
@@ -162,14 +161,13 @@ GPU_SHADER_INTERFACE_INFO(overlay_paint_wire_iface, "").flat(Type::VEC4, "finalC
GPU_SHADER_CREATE_INFO(overlay_paint_wire)
.do_static_compilation(true)
- .define("srgbTarget", "false") /* NOTE: Color already in Linear space. */
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::VEC4, "nor") /* flag stored in w */
.vertex_out(overlay_paint_wire_iface)
.push_constant(Type::BOOL, "useSelect")
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("paint_wire_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_paint_wire_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_modelmat", "draw_globals");
GPU_SHADER_CREATE_INFO(overlay_paint_wire_clipped)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_curves_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_curves_info.hh
new file mode 100644
index 00000000000..46e3943b293
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_curves_info.hh
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_INTERFACE_INFO(overlay_sculpt_curves_selection_iface, "")
+ .smooth(Type::FLOAT, "mask_weight");
+
+GPU_SHADER_CREATE_INFO(overlay_sculpt_curves_selection)
+ .do_static_compilation(true)
+ .push_constant(Type::BOOL, "is_point_domain")
+ .push_constant(Type::FLOAT, "selection_opacity")
+ .sampler(0, ImageType::FLOAT_BUFFER, "selection_tx")
+ .vertex_out(overlay_sculpt_curves_selection_iface)
+ .vertex_source("overlay_sculpt_curves_selection_vert.glsl")
+ .fragment_source("overlay_sculpt_curves_selection_frag.glsl")
+ .fragment_out(0, Type::VEC4, "out_color")
+ .additional_info("draw_hair", "draw_globals");
+
+GPU_SHADER_CREATE_INFO(overlay_sculpt_curves_selection_clipped)
+ .do_static_compilation(true)
+ .additional_info("overlay_sculpt_curves_selection", "drw_clipped");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
index d4f1ca44362..3a53bd388a6 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/sculpt_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
@@ -15,8 +15,8 @@ GPU_SHADER_CREATE_INFO(overlay_sculpt_mask)
.vertex_in(1, Type::VEC3, "fset")
.vertex_in(2, Type::FLOAT, "msk")
.vertex_out(overlay_sculpt_mask_iface)
- .vertex_source("sculpt_mask_vert.glsl")
- .fragment_source("sculpt_mask_frag.glsl")
+ .vertex_source("overlay_sculpt_mask_vert.glsl")
+ .fragment_source("overlay_sculpt_mask_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.additional_info("draw_mesh", "draw_object_infos", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh
index 5853e974eeb..3740b42ba26 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/volume_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_volume_info.hh
@@ -10,8 +10,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_volume_velocity_iface, "").smooth(Type::VEC4,
GPU_SHADER_CREATE_INFO(overlay_volume_velocity)
.do_static_compilation(true)
- /* Colors are already in linear space. */
- .define("srgbTarget", "false")
.sampler(0, ImageType::FLOAT_3D, "velocityX")
.sampler(1, ImageType::FLOAT_3D, "velocityY")
.sampler(2, ImageType::FLOAT_3D, "velocityZ")
@@ -28,8 +26,8 @@ GPU_SHADER_CREATE_INFO(overlay_volume_velocity)
.push_constant(Type::IVEC3, "adaptiveCellOffset")
.vertex_out(overlay_volume_velocity_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("volume_velocity_vert.glsl")
- .fragment_source("gpu_shader_3D_smooth_color_frag.glsl")
+ .vertex_source("overlay_volume_velocity_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_volume");
GPU_SHADER_CREATE_INFO(overlay_volume_velocity_mac)
@@ -55,8 +53,6 @@ GPU_SHADER_INTERFACE_INFO(overlay_volume_gridlines_iface, "").flat(Type::VEC4, "
GPU_SHADER_CREATE_INFO(overlay_volume_gridlines)
.do_static_compilation(true)
- /* Colors are already in linear space. */
- .define("srgbTarget", "false")
.push_constant(Type::FLOAT, "slicePosition")
.push_constant(Type::INT, "sliceAxis")
/* FluidDomainSettings.res */
@@ -69,8 +65,8 @@ GPU_SHADER_CREATE_INFO(overlay_volume_gridlines)
.push_constant(Type::IVEC3, "adaptiveCellOffset")
.vertex_out(overlay_volume_gridlines_iface)
.fragment_out(0, Type::VEC4, "fragColor")
- .vertex_source("volume_gridlines_vert.glsl")
- .fragment_source("gpu_shader_flat_color_frag.glsl")
+ .vertex_source("overlay_volume_gridlines_vert.glsl")
+ .fragment_source("overlay_varying_color.glsl")
.additional_info("draw_volume");
GPU_SHADER_CREATE_INFO(overlay_volume_gridlines_flags)
diff --git a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
index 16b59f6bb7d..1899b191741 100644
--- a/source/blender/draw/engines/overlay/shaders/infos/wireframe_info.hh
+++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
@@ -23,8 +23,8 @@ GPU_SHADER_CREATE_INFO(overlay_wireframe)
.vertex_in(1, Type::VEC3, "nor")
.vertex_in(2, Type::FLOAT, "wd") /* wire-data. */
.vertex_out(overlay_wireframe_iface)
- .vertex_source("wireframe_vert.glsl")
- .fragment_source("wireframe_frag.glsl")
+ .vertex_source("overlay_wireframe_vert.glsl")
+ .fragment_source("overlay_wireframe_frag.glsl")
.fragment_out(0, Type::VEC4, "fragColor")
.fragment_out(1, Type::VEC4, "lineOutput")
.additional_info("draw_mesh", "draw_object_infos", "draw_globals");
diff --git a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl
index f28a809fdab..f28a809fdab 100644
--- a/source/blender/draw/engines/overlay/shaders/antialiasing_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_antialiasing_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
index d46abbf79ee..d46abbf79ee 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_dof_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl
index b3c9ce5dfd2..b3c9ce5dfd2 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_dof_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_dof_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
index 0a8e279e9b0..612ce8c6300 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_outline_vert.glsl
@@ -17,8 +17,8 @@ vec2 compute_dir(vec2 v0, vec2 v1, vec2 v2)
mat3 compute_mat(vec4 sphere, vec3 bone_vec, out float z_ofs)
{
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
- vec3 cam_ray = (is_persp) ? sphere.xyz - ViewMatrixInverse[3].xyz : -ViewMatrixInverse[2].xyz;
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
+ vec3 cam_ray = (is_persp) ? sphere.xyz - drw_view.viewinv[3].xyz : -drw_view.viewinv[2].xyz;
/* Sphere center distance from the camera (persp) in world space. */
float cam_dist = length(cam_ray);
@@ -88,13 +88,13 @@ vec3 get_outline_point(vec2 pos,
void main()
{
- float dst_head = distance(headSphere.xyz, ViewMatrixInverse[3].xyz);
- float dst_tail = distance(tailSphere.xyz, ViewMatrixInverse[3].xyz);
- // float dst_head = -dot(headSphere.xyz, ViewMatrix[2].xyz);
- // float dst_tail = -dot(tailSphere.xyz, ViewMatrix[2].xyz);
+ float dst_head = distance(headSphere.xyz, drw_view.viewinv[3].xyz);
+ float dst_tail = distance(tailSphere.xyz, drw_view.viewinv[3].xyz);
+ // float dst_head = -dot(headSphere.xyz, drw_view.viewmat[2].xyz);
+ // float dst_tail = -dot(tailSphere.xyz, drw_view.viewmat[2].xyz);
vec4 sph_near, sph_far;
- if ((dst_head > dst_tail) && (ProjectionMatrix[3][3] == 0.0)) {
+ if ((dst_head > dst_tail) && (drw_view.winmat[3][3] == 0.0)) {
sph_near = tailSphere;
sph_far = headSphere;
}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
index a90d2e3e406..a90d2e3e406 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
index 2dd86a57dfd..4d21ffd96b5 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_envelope_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_envelope_solid_vert.glsl
@@ -30,7 +30,7 @@ void main()
sp = bone_mat * sp.xzy + headSphere.xyz;
nor = bone_mat * nor.xzy;
- normalView = mat3(ViewMatrix) * nor;
+ normalView = mat3(drw_view.viewmat) * nor;
finalStateColor = stateColor;
finalBoneColor = boneColor;
@@ -38,5 +38,5 @@ void main()
view_clipping_distances(sp);
vec4 pos_4d = vec4(sp, 1.0);
- gl_Position = ViewProjectionMatrix * pos_4d;
+ gl_Position = drw_view.persmat * pos_4d;
}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
index 47c5dada708..b485b0a7807 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_geom.glsl
@@ -5,7 +5,7 @@ void main(void)
{
finalColor = vec4(geom_in[0].vColSize.rgb, 1.0);
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
vec3 view_vec = (is_persp) ? normalize(geom_in[1].vPos) : vec3(0.0, 0.0, -1.0);
vec3 v10 = geom_in[0].vPos - geom_in[1].vPos;
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
index 29319b3f7ac..91eb6265192 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_outline_vert.glsl
@@ -14,10 +14,10 @@ void main()
mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
vec4 world_pos = model_mat * vec4(pos, 1.0);
- vec4 view_pos = ViewMatrix * world_pos;
+ vec4 view_pos = drw_view.viewmat * world_pos;
geom_in.vPos = view_pos.xyz;
- geom_in.pPos = ProjectionMatrix * view_pos;
+ geom_in.pPos = drw_view.winmat * view_pos;
geom_in.inverted = int(dot(cross(model_mat[0].xyz, model_mat[1].xyz), model_mat[2].xyz) < 0.0);
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
index 8e1768846dc..8e1768846dc 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
index cdbe8c3d7df..68f7e75673f 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_solid_vert.glsl
@@ -25,7 +25,7 @@ void main()
finalColor.a = 1.0;
vec4 world_pos = model_mat * vec4(pos, 1.0);
- gl_Position = ViewProjectionMatrix * world_pos;
+ gl_Position = drw_view.persmat * world_pos;
view_clipping_distances(world_pos.xyz);
}
diff --git a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
index cee86956c43..cee86956c43 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_shape_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_shape_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
index 31369e0c3df..4d79fab718f 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_outline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_outline_vert.glsl
@@ -13,10 +13,10 @@ void main()
vec4 bone_color, state_color;
mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
- mat4 model_view_matrix = ViewMatrix * model_mat;
+ mat4 model_view_matrix = drw_view.viewmat * model_mat;
mat4 sphereMatrix = inverse(model_view_matrix);
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
/* This is the local space camera ray (not normalize).
* In perspective mode it's also the viewspace position
@@ -58,8 +58,8 @@ void main()
vec3 cam_pos0 = x_axis * pos.x + y_axis * pos.y + z_axis * z_ofs;
vec4 V = model_view_matrix * vec4(cam_pos0, 1.0);
- gl_Position = ProjectionMatrix * V;
- vec4 center = ProjectionMatrix * vec4(model_view_matrix[3].xyz, 1.0);
+ gl_Position = drw_view.winmat * V;
+ vec4 center = drw_view.winmat * vec4(model_view_matrix[3].xyz, 1.0);
/* Offset away from the center to avoid overlap with solid shape. */
vec2 ofs_dir = normalize(proj(gl_Position) - proj(center));
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
index e60b6e94492..150701b78df 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_frag.glsl
@@ -5,7 +5,7 @@ void main()
{
const float sphere_radius = 0.05;
- bool is_perp = (ProjectionMatrix[3][3] == 0.0);
+ bool is_perp = (drw_view.winmat[3][3] == 0.0);
vec3 ray_ori_view = (is_perp) ? vec3(0.0) : viewPosition.xyz;
vec3 ray_dir_view = (is_perp) ? viewPosition : vec3(0.0, 0.0, -1.0);
diff --git a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
index abbaad8cd10..3d2dfc018bb 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_sphere_solid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl
@@ -10,10 +10,10 @@ void main()
vec4 bone_color, state_color;
mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color);
- mat4 model_view_matrix = ViewMatrix * model_mat;
+ mat4 model_view_matrix = drw_view.viewmat * model_mat;
sphereMatrix = inverse(model_view_matrix);
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
/* This is the local space camera ray (not normalize).
* In perspective mode it's also the viewspace position
@@ -65,7 +65,7 @@ void main()
vec4 pos_4d = vec4(cam_pos, 1.0);
vec4 V = model_view_matrix * pos_4d;
- gl_Position = ProjectionMatrix * V;
+ gl_Position = drw_view.winmat * V;
viewPosition = V.xyz;
finalStateColor = state_color.xyz;
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl
index 2e42cdf0517..2e42cdf0517 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_stick_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl
index b5edcd2858b..e7917a46312 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_stick_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_stick_vert.glsl
@@ -31,12 +31,12 @@ void main()
vec4 boneStart_4d = vec4(boneStart, 1.0);
vec4 boneEnd_4d = vec4(boneEnd, 1.0);
- vec4 v0 = ViewMatrix * boneStart_4d;
- vec4 v1 = ViewMatrix * boneEnd_4d;
+ vec4 v0 = drw_view.viewmat * boneStart_4d;
+ vec4 v1 = drw_view.viewmat * boneEnd_4d;
/* Clip the bone to the camera origin plane (not the clip plane)
* to avoid glitches if one end is behind the camera origin (in persp). */
- float clip_dist = (ProjectionMatrix[3][3] == 0.0) ?
+ float clip_dist = (drw_view.winmat[3][3] == 0.0) ?
-1e-7 :
1e20; /* hardcoded, -1e-8 is giving gliches. */
vec3 bvec = v1.xyz - v0.xyz;
@@ -48,8 +48,8 @@ void main()
v1.xyz = clip_pt;
}
- vec4 p0 = ProjectionMatrix * v0;
- vec4 p1 = ProjectionMatrix * v1;
+ vec4 p0 = drw_view.winmat * v0;
+ vec4 p1 = drw_view.winmat * v1;
float h = (is_head) ? p0.w : p1.w;
@@ -58,7 +58,7 @@ void main()
/* 2D screen aligned pos at the point */
vec2 vpos = pos.x * x_screen_vec + pos.y * y_screen_vec;
- vpos *= (ProjectionMatrix[3][3] == 0.0) ? h : 1.0;
+ vpos *= (drw_view.winmat[3][3] == 0.0) ? h : 1.0;
vpos *= (do_wire) ? 1.0 : 0.5;
if (finalInnerColor.a > 0.0) {
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl
index 2c454a8becd..2c454a8becd 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_wire_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl
index c89d0249e4f..c89d0249e4f 100644
--- a/source/blender/draw/engines/overlay/shaders/armature_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/background_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl
index b25dcae9fca..b25dcae9fca 100644
--- a/source/blender/draw/engines/overlay/shaders/background_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_background_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl
index c065a66414f..c065a66414f 100644
--- a/source/blender/draw/engines/overlay/shaders/clipbound_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_clipbound_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl b/source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl
index 65aeb81a4ef..65aeb81a4ef 100644
--- a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_common_lib.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl
new file mode 100644
index 00000000000..59efdd8d538
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl
@@ -0,0 +1,6 @@
+
+void main()
+{
+ /* No color output, only depth (line below is implicit). */
+ // gl_FragDepth = gl_FragCoord.z;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl
index d403890f44e..d403890f44e 100644
--- a/source/blender/draw/engines/overlay/shaders/depth_only_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
index 7d92baea595..7d92baea595 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
index 186cc010f45..186cc010f45 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_handle_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_handle_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
index a30496177c3..a30496177c3 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
index 183df7e5450..183df7e5450 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_curve_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_curve_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
index 47d9439ed80..47d9439ed80 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_canvas_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
index a5091345539..a5091345539 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_guide_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
index f5d6e89d016..f5d6e89d016 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_gpencil_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
index 38ba80a981a..38ba80a981a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_lattice_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
index 440dfdc1482..440dfdc1482 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_lattice_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_lattice_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
index 430ace8726a..430ace8726a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
index 1e163dc9a9a..1e163dc9a9a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_analysis_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_analysis_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
index 72b0a43cdb4..72b0a43cdb4 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_common_lib.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_common_lib.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl
index 2fd155f715c..2fd155f715c 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl
index 82f957b2071..82f957b2071 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_geom.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
index 6ff8d0665d1..dc5c43f417e 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_normal_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_normal_vert.glsl
@@ -45,7 +45,7 @@ void main()
if (gl_VertexID == 0) {
if (isConstantScreenSizeNormals) {
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
if (is_persp) {
float dist_fac = length(cameraPos - world_pos);
float cos_fac = dot(cameraForward, cameraVec(world_pos));
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
index f1fbdac7847..76a944c6987 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_skin_root_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_skin_root_vert.glsl
@@ -9,7 +9,7 @@ void main()
vec3 up = normalize(imat * screenVecs[1].xyz);
vec3 screen_pos = (right * pos.x + up * pos.z) * size;
vec4 pos_4d = ModelMatrix * vec4(local_pos + screen_pos, 1.0);
- gl_Position = ViewProjectionMatrix * pos_4d;
+ gl_Position = drw_view.persmat * pos_4d;
/* Manual stipple: one segment out of 2 is transparent. */
finalColor = ((gl_VertexID & 1) == 0) ? colorSkinRoot : vec4(0.0);
diff --git a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl
index 166ac1a37b0..a50bc5e6e68 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_mesh_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert.glsl
@@ -1,7 +1,7 @@
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
-#pragma BLENDER_REQUIRE(edit_mesh_common_lib.glsl)
+#pragma BLENDER_REQUIRE(overlay_edit_mesh_common_lib.glsl)
#ifdef EDGE
/* Ugly but needed to keep the same vertex shader code for other passes. */
@@ -74,7 +74,7 @@ void main()
finalColor = EDIT_MESH_facedot_color(norAndFlag.w);
/* Bias Facedot Z position in clipspace. */
- gl_Position.z -= (ProjectionMatrix[3][3] == 0.0) ? 0.00035 : 1e-6;
+ gl_Position.z -= (drw_view.winmat[3][3] == 0.0) ? 0.00035 : 1e-6;
gl_PointSize = sizeFaceDot;
bool occluded = test_occlusion();
@@ -87,7 +87,7 @@ void main()
/* Facing based color blend */
vec3 vpos = point_world_to_view(world_pos);
vec3 view_normal = normalize(normal_object_to_view(vnor) + 1e-4);
- vec3 view_vec = (ProjectionMatrix[3][3] == 0.0) ? normalize(vpos) : vec3(0.0, 0.0, 1.0);
+ vec3 view_vec = (drw_view.winmat[3][3] == 0.0) ? normalize(vpos) : vec3(0.0, 0.0, 1.0);
float facing = dot(view_vec, view_normal);
facing = 1.0 - abs(facing) * 0.2;
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
index 956b27e948d..956b27e948d 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_particle_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
index 6a92206d524..6a92206d524 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_particle_strand_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_particle_strand_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
index 9c0ce4ecc8a..a849cb5160a 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_frag.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(common_overlay_lib.glsl)
+#pragma BLENDER_REQUIRE(overlay_common_lib.glsl)
/**
* We want to know how much a pixel is covered by a line.
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
index ac8d33cd727..8b19f671139 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_geom.glsl
@@ -1,4 +1,4 @@
-#pragma BLENDER_REQUIRE(common_overlay_lib.glsl)
+#pragma BLENDER_REQUIRE(overlay_common_lib.glsl)
void do_vertex(
vec4 pos, float selection_fac, vec2 stipple_start, vec2 stipple_pos, float coord, vec2 offset)
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
index 23f1a44c321..23f1a44c321 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_edges_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
index 280b31ea463..c0d4393f2da 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_face_dots_vert.glsl
@@ -5,6 +5,6 @@ void main()
vec3 world_pos = point_object_to_world(vec3(au, 0.0));
gl_Position = point_world_to_ndc(world_pos);
- finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorVertexSelect : vec4(colorWire.rgb, 1.0);
+ finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorFaceDot : vec4(colorWire.rgb, 1.0);
gl_PointSize = pointSize;
}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
index 80ea6228675..80ea6228675 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_faces_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
index a1392abbb92..a1392abbb92 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_image_mask_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_mask_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
index 7ecbb513265..7ecbb513265 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_image_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_image_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
index bb086e8d9f5..bb086e8d9f5 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_stretching_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
index bc5235b9cab..bc5235b9cab 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_tiled_image_borders_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
index c0ea6aebe10..c0ea6aebe10 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
index 9f9b02ce19d..9f9b02ce19d 100644
--- a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_uv_verts_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl
index bf29b2b057e..bf29b2b057e 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl
index ff7aae523e7..ff7aae523e7 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_groundline_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_groundline_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
index 1eee7ab251b..1eee7ab251b 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_lightprobe_grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_lightprobe_grid_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
index d92b947ef89..d92b947ef89 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
index f283934816c..f283934816c 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_loose_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_loose_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl
index de999c241c0..de999c241c0 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl
index b2578970c9b..acaf04219c0 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl
@@ -198,8 +198,8 @@ void main()
vec3 edge = obmat[3].xyz - world_pos;
vec3 n0 = normalize(cross(edge, p0 - world_pos));
vec3 n1 = normalize(cross(edge, world_pos - p1));
- bool persp = (ProjectionMatrix[3][3] == 0.0);
- vec3 V = (persp) ? normalize(ViewMatrixInverse[3].xyz - world_pos) : ViewMatrixInverse[2].xyz;
+ bool persp = (drw_view.winmat[3][3] == 0.0);
+ vec3 V = (persp) ? normalize(drw_view.viewinv[3].xyz - world_pos) : drw_view.viewinv[2].xyz;
/* Discard non-silhouette edges. */
bool facing0 = dot(n0, V) > 0.0;
bool facing1 = dot(n1, V) > 0.0;
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl
index f32e3a8564e..f32e3a8564e 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_wire_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl
index cd217021e8f..cd217021e8f 100644
--- a/source/blender/draw/engines/overlay/shaders/extra_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl
index 8208689d113..8208689d113 100644
--- a/source/blender/draw/engines/overlay/shaders/facing_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_facing_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl
index d98caee6a25..d98caee6a25 100644
--- a/source/blender/draw/engines/overlay/shaders/facing_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_facing_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl
index 37958319b44..37958319b44 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_background_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_background_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl
index 25f4984f119..54a4231590e 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_frag.glsl
@@ -53,7 +53,7 @@ void main()
P += cameraPos * plane_axes;
float dist, fade;
- bool is_persp = ProjectionMatrix[3][3] == 0.0;
+ bool is_persp = drw_view.winmat[3][3] == 0.0;
if (is_persp) {
vec3 V = cameraPos - P;
dist = length(V);
@@ -83,7 +83,7 @@ void main()
dist = 1.0; /* Avoid branch after. */
if (flag_test(grid_flag, PLANE_XY)) {
- float angle = 1.0 - abs(ViewMatrixInverse[2].z);
+ float angle = 1.0 - abs(drw_view.viewinv[2].z);
dist = 1.0 + angle * 2.0;
angle *= angle;
fade *= 1.0 - angle * angle;
diff --git a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl
index b81f1a24358..b43b1eb4a52 100644
--- a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_grid_vert.glsl
@@ -39,5 +39,5 @@ void main()
local_pos.z = clamp(local_pos.z, -1.0, 0.0);
}
- gl_Position = ViewProjectionMatrix * vec4(real_pos, 1.0);
+ gl_Position = drw_view.persmat * vec4(real_pos, 1.0);
}
diff --git a/source/blender/draw/engines/overlay/shaders/image_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl
index e0339507e0f..e0339507e0f 100644
--- a/source/blender/draw/engines/overlay/shaders/image_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_image_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/image_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl
index 45cddb3610d..45cddb3610d 100644
--- a/source/blender/draw/engines/overlay/shaders/image_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_image_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl
index 324d22501f9..324d22501f9 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl
index 29346a44863..25e13e7c212 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_geom.glsl
@@ -15,7 +15,7 @@ void main(void)
vec2 edge_dir = compute_dir(interp_in[0].ss_pos, interp_in[1].ss_pos) *
drw_view.viewport_size_inverse;
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
float line_size = float(lineThickness) * sizePixel;
view_clipping_distances_set(gl_in[0]);
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl
index bc74a436f5e..e6281f75b8f 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_line_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_line_vert.glsl
@@ -18,7 +18,7 @@ vec2 proj(vec4 pos)
void main()
{
- gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+ gl_Position = drw_view.persmat * vec4(pos, 1.0);
interp.ss_pos = proj(gl_Position);
diff --git a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl
index 5027525b9b3..70892954cd8 100644
--- a/source/blender/draw/engines/overlay/shaders/motion_path_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_motion_path_point_vert.glsl
@@ -9,7 +9,7 @@
void main()
{
- gl_Position = ViewProjectionMatrix * vec4(pos, 1.0);
+ gl_Position = drw_view.persmat * vec4(pos, 1.0);
gl_PointSize = float(pointSize + 2);
int frame = gl_VertexID + cacheStart;
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl
index 472a589f441..472a589f441 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_detect_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl
new file mode 100644
index 00000000000..f9ec475d21f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_curves_vert.glsl
@@ -0,0 +1,81 @@
+
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+
+uint outline_colorid_get(void)
+{
+ int flag = int(abs(ObjectInfo.w));
+ bool is_active = (flag & DRW_BASE_ACTIVE) != 0;
+
+ if (isTransform) {
+ return 0u; /* colorTransform */
+ }
+ else if (is_active) {
+ return 3u; /* colorActive */
+ }
+ else {
+ return 1u; /* colorSelect */
+ }
+
+ return 0u;
+}
+
+/* Replace top 2 bits (of the 16bit output) by outlineId.
+ * This leaves 16K different IDs to create outlines between objects.
+ vec3 world_pos = point_object_to_world(pos);
+ * SHIFT = (32 - (16 - 2)) */
+#define SHIFT 18u
+
+void main()
+{
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
+ float time, thickness;
+ vec3 center_wpos, tan, binor;
+
+ hair_get_center_pos_tan_binor_time(is_persp,
+ ModelMatrixInverse,
+ drw_view.viewinv[3].xyz,
+ drw_view.viewinv[2].xyz,
+ center_wpos,
+ tan,
+ binor,
+ time,
+ thickness);
+ vec3 world_pos;
+ if (hairThicknessRes > 1) {
+ /* Calculate the thickness, thicktime, worldpos taken into account the outline. */
+ float outline_width = point_world_to_ndc(center_wpos).w * 1.25 *
+ drw_view.viewport_size_inverse.y * drw_view.wininv[1][1];
+ thickness += outline_width;
+ float thick_time = float(gl_VertexID % hairThicknessRes) / float(hairThicknessRes - 1);
+ thick_time = thickness * (thick_time * 2.0 - 1.0);
+ /* Take object scale into account.
+ * NOTE: This only works fine with uniform scaling. */
+ float scale = 1.0 / length(mat3(ModelMatrixInverse) * binor);
+ world_pos = center_wpos + binor * thick_time * scale;
+ }
+ else {
+ world_pos = center_wpos;
+ }
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+#ifdef USE_GEOM
+ vert.pos = point_world_to_view(world_pos);
+#endif
+
+ /* Small bias to always be on top of the geom. */
+ gl_Position.z -= 1e-3;
+
+ /* ID 0 is nothing (background) */
+ interp.ob_id = uint(resource_handle + 1);
+
+ /* Should be 2 bits only [0..3]. */
+ uint outline_id = outline_colorid_get();
+
+ /* Combine for 16bit uint target. */
+ interp.ob_id = (outline_id << 14u) | ((interp.ob_id << SHIFT) >> SHIFT);
+
+ view_clipping_distances(world_pos);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl
index d1abd74a7b3..d1abd74a7b3 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl
index 8a196620af9..5e0074e9f0b 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_geom.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_geom.glsl
@@ -11,7 +11,7 @@ void vert_from_gl_in(int v)
void main()
{
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
vec3 view_vec = (is_persp) ? normalize(vert[1].pos) : vec3(0.0, 0.0, -1.0);
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
index b6d5cd96c12..92be9ec3bcb 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_frag.glsl
@@ -22,14 +22,14 @@ void main()
if (!gpStrokeOrder3d) {
/* Stroke order 2D. Project to gpDepthPlane. */
- bool is_persp = ProjectionMatrix[3][3] == 0.0;
+ bool is_persp = drw_view.winmat[3][3] == 0.0;
vec2 uvs = vec2(gl_FragCoord.xy) * drw_view.viewport_size_inverse;
vec3 pos_ndc = vec3(uvs, gl_FragCoord.z) * 2.0 - 1.0;
- vec4 pos_world = ViewProjectionMatrixInverse * vec4(pos_ndc, 1.0);
+ vec4 pos_world = drw_view.persinv * vec4(pos_ndc, 1.0);
vec3 pos = pos_world.xyz / pos_world.w;
vec3 ray_ori = pos;
- vec3 ray_dir = (is_persp) ? (ViewMatrixInverse[3].xyz - pos) : ViewMatrixInverse[2].xyz;
+ vec3 ray_dir = (is_persp) ? (drw_view.viewinv[3].xyz - pos) : drw_view.viewinv[2].xyz;
vec3 isect = ray_plane_intersection(ray_ori, ray_dir, gpDepthPlane);
vec4 ndc = point_world_to_ndc(isect);
gl_FragDepth = (ndc.z / ndc.w) * 0.5 + 0.5;
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
index 4b1470e5723..4b1470e5723 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_gpencil_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_gpencil_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
index 371ff628c59..371ff628c59 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_pointcloud_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_pointcloud_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl
index 1d0b08f51b2..1d0b08f51b2 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_outline_prepass_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl
index 22906bf1526..22906bf1526 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_face_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_face_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl
index 8736b2a87db..8736b2a87db 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_point_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_point_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl
index e5af0e7bd88..e5af0e7bd88 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_texture_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl
index f93d0050950..f93d0050950 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_texture_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_texture_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
index 193fabc65cb..193fabc65cb 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_vertcol_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
index 650070dcfd5..650070dcfd5 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_vertcol_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_vertcol_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl
index 1befe7506c4..1befe7506c4 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_weight_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl
index cff79d606d6..cff79d606d6 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_weight_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_weight_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl
index 749cc92f082..749cc92f082 100644
--- a/source/blender/draw/engines/overlay/shaders/paint_wire_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_paint_wire_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl
index a2bcca7b820..a2bcca7b820 100644
--- a/source/blender/draw/engines/overlay/shaders/particle_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl
index fb981a8167a..c48e7cce550 100644
--- a/source/blender/draw/engines/overlay/shaders/particle_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_particle_vert.glsl
@@ -23,7 +23,7 @@ void main()
#ifdef USE_DOTS
gl_Position = point_world_to_ndc(world_pos);
/* World sized points. */
- gl_PointSize = sizePixel * draw_size * ProjectionMatrix[1][1] * sizeViewport.y / gl_Position.w;
+ gl_PointSize = sizePixel * draw_size * drw_view.winmat[1][1] * sizeViewport.y / gl_Position.w;
#else
if ((vclass & VCLASS_SCREENALIGNED) != 0) {
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl
new file mode 100644
index 00000000000..b0da035ef09
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_frag.glsl
@@ -0,0 +1,23 @@
+
+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;
+ }
+
+#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/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
new file mode 100644
index 00000000000..c0ea6aebe10
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_point_varying_color_varying_outline_aa_frag.glsl
@@ -0,0 +1,27 @@
+
+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/draw/engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl
new file mode 100644
index 00000000000..7af6bdb9fdb
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_curves_selection_frag.glsl
@@ -0,0 +1,5 @@
+
+void main()
+{
+ out_color = vec4(vec3(0.0), 1.0 - mask_weight);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl
new file mode 100644
index 00000000000..7be3c8e6dfb
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_curves_selection_vert.glsl
@@ -0,0 +1,34 @@
+#pragma BLENDER_REQUIRE(common_hair_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+
+float retrieve_selection()
+{
+ if (is_point_domain) {
+ return texelFetch(selection_tx, hair_get_base_id()).r;
+ }
+ return texelFetch(selection_tx, hair_get_strand_id()).r;
+}
+
+void main()
+{
+ bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ float time, thick_time, thickness;
+ vec3 world_pos, tan, binor;
+ hair_get_pos_tan_binor_time(is_persp,
+ ModelMatrixInverse,
+ ViewMatrixInverse[3].xyz,
+ ViewMatrixInverse[2].xyz,
+ world_pos,
+ tan,
+ binor,
+ time,
+ thickness,
+ thick_time);
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ mask_weight = 1.0 - (selection_opacity - retrieve_selection() * selection_opacity);
+
+ view_clipping_distances(world_pos);
+}
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
index 9650af755c5..9650af755c5 100644
--- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
index 36c0e6a0acf..36c0e6a0acf 100644
--- a/source/blender/draw/engines/overlay/shaders/sculpt_mask_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_sculpt_mask_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl
new file mode 100644
index 00000000000..e1a4a3602e3
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_uniform_color_frag.glsl
@@ -0,0 +1,4 @@
+void main()
+{
+ fragColor = color;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl b/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl
new file mode 100644
index 00000000000..a27e2849bb3
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/overlay_varying_color.glsl
@@ -0,0 +1,4 @@
+void main()
+{
+ fragColor = finalColor;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
index 11a04dddd2a..11a04dddd2a 100644
--- a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_volume_gridlines_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl
index a33d27676c3..a33d27676c3 100644
--- a/source/blender/draw/engines/overlay/shaders/volume_velocity_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_volume_velocity_vert.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl
index bc28d7a8a36..bc28d7a8a36 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_frag.glsl
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl
index 41bd7791dd7..d189ab1b72c 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_wireframe_vert.glsl
@@ -72,7 +72,7 @@ void wire_object_color_get(out vec3 rim_col, out vec3 wire_col)
void main()
{
bool no_attr = all(equal(nor, vec3(0)));
- vec3 wnor = no_attr ? ViewMatrixInverse[2].xyz : normalize(normal_object_to_world(nor));
+ vec3 wnor = no_attr ? drw_view.viewinv[2].xyz : normalize(normal_object_to_world(nor));
vec3 wpos = point_object_to_world(pos);
if (isHair) {
@@ -81,8 +81,8 @@ void main()
wnor = -normalize(mat3(obmat) * nor);
}
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
- vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz;
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
+ vec3 V = (is_persp) ? normalize(drw_view.viewinv[3].xyz - wpos) : drw_view.viewinv[2].xyz;
float facing = dot(wnor, V);
diff --git a/source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl
index 9aa2fdc3796..9aa2fdc3796 100644
--- a/source/blender/draw/engines/overlay/shaders/xray_fade_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/overlay_xray_fade_frag.glsl
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 880f17b0c9d..e7ca868a4ff 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl
@@ -31,9 +31,9 @@ void cavity_compute(vec2 screenco,
/* find the offset in screen space by multiplying a point
* in camera space at the depth of the point by the projection matrix. */
vec2 offset;
- float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3];
- offset.x = ProjectionMatrix[0][0] * world_data.cavity_distance / homcoord;
- offset.y = ProjectionMatrix[1][1] * world_data.cavity_distance / homcoord;
+ float homcoord = drw_view.winmat[2][3] * position.z + drw_view.winmat[3][3];
+ offset.x = drw_view.winmat[0][0] * world_data.cavity_distance / homcoord;
+ offset.y = drw_view.winmat[1][1] * world_data.cavity_distance / homcoord;
/* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */
offset *= 0.5;
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 d8f8a1cc03f..11d7c85d43a 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
@@ -16,7 +16,7 @@
(dof_aperturesize * (dof_distance / zdepth - 1.0) * dof_invsensorsize)
#define linear_depth(z) \
- ((ProjectionMatrix[3][3] == 0.0) ? \
+ ((drw_view.winmat[3][3] == 0.0) ? \
(nearFar.x * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) : \
(z * 2.0 - 1.0) * nearFar.y)
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 cfc94ef7c9a..04fef8d8b32 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
@@ -43,13 +43,13 @@ void workbench_hair_random_material(float rand,
void main()
{
- bool is_persp = (ProjectionMatrix[3][3] == 0.0);
+ bool is_persp = (drw_view.winmat[3][3] == 0.0);
float time, thick_time, thickness;
vec3 world_pos, tan, binor;
hair_get_pos_tan_binor_time(is_persp,
ModelMatrixInverse,
- ViewMatrixInverse[3].xyz,
- ViewMatrixInverse[2].xyz,
+ drw_view.viewinv[3].xyz,
+ drw_view.viewinv[2].xyz,
world_pos,
tan,
binor,
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 d8f1b83d747..213279b1913 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
@@ -24,7 +24,7 @@ float linear_zdepth(float depth, vec4 viewvecs[2], mat4 proj_mat)
*/
float calculate_transparent_weight(void)
{
- float z = linear_zdepth(gl_FragCoord.z, ViewVecs, ProjectionMatrix);
+ float z = linear_zdepth(gl_FragCoord.z, drw_view.viewvecs, drw_view.winmat);
#if 0
/* Eq 10 : Good for surfaces with varying opacity (like particles) */
float a = min(1.0, alpha * 10.0) + 0.01;
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 49e26cd3e0c..afba3a0d784 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -237,7 +237,7 @@ void main()
fragColor = vec4(Lscat, Tr);
#else
vec2 screen_uv = gl_FragCoord.xy / vec2(textureSize(depthBuffer, 0).xy);
- bool is_persp = ProjectionMatrix[3][3] == 0.0;
+ bool is_persp = drw_view.winmat[3][3] == 0.0;
vec3 volume_center = ModelMatrix[3].xyz;
diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c
index fb20bde2f65..9eb35c25bf4 100644
--- a/source/blender/draw/engines/workbench/workbench_engine.c
+++ b/source/blender/draw/engines/workbench/workbench_engine.c
@@ -97,7 +97,7 @@ static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd,
{
const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR);
if (use_single_drawcall) {
- DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL);
+ DRWShadingGroup *grp = workbench_material_setup(wpd, ob, ob->actcol, color_type, NULL);
DRW_shgroup_call_sculpt(grp, ob, false, false);
}
else {
@@ -323,7 +323,8 @@ static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd,
}
}
- if (is_sculpt_pbvh && color_type == V3D_SHADING_TEXTURE_COLOR) {
+ if (is_sculpt_pbvh && color_type == V3D_SHADING_TEXTURE_COLOR &&
+ BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_FACES) {
/* Force use of material color for sculpt. */
color_type = V3D_SHADING_MATERIAL_COLOR;
}
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index e5dcf6c5624..931f6a2dc92 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -17,6 +17,7 @@
#include "ED_view3d.h"
+#include "GPU_context.h"
#include "GPU_shader.h"
#include "DEG_depsgraph.h"
@@ -188,6 +189,10 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer
workbench_draw_finish(data);
+ /* Perform render step between samples to allow
+ * flushing of freed GPUBackend resources. */
+ GPU_render_step();
+
/* Write render output. */
const char *viewname = RE_GetActiveRenderView(engine->re);
RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
index 257f01a5562..8e61c25be71 100644
--- a/source/blender/draw/intern/DRW_gpu_wrapper.hh
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -558,6 +558,7 @@ class Texture : NonCopyable {
/**
* Ensure the availability of mipmap views.
* Layer views covers all layers of array textures.
+ * Returns true if the views were (re)created.
*/
bool ensure_layer_views(bool cube_as_array = false)
{
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 07105757b2c..bb913c53500 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -639,10 +639,10 @@ void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup,
DRW_shgroup_uniform_block_ex(shgroup, name, ubo, __FILE__, __LINE__)
# define DRW_shgroup_uniform_block_ref(shgroup, name, ubo) \
DRW_shgroup_uniform_block_ref_ex(shgroup, name, ubo, __FILE__, __LINE__)
-# define DRW_shgroup_storage_block(shgroup, name, ubo) \
- DRW_shgroup_storage_block_ex(shgroup, name, ubo, __FILE__, __LINE__)
-# define DRW_shgroup_storage_block_ref(shgroup, name, ubo) \
- DRW_shgroup_storage_block_ref_ex(shgroup, name, ubo, __FILE__, __LINE__)
+# define DRW_shgroup_storage_block(shgroup, name, ssbo) \
+ DRW_shgroup_storage_block_ex(shgroup, name, ssbo, __FILE__, __LINE__)
+# define DRW_shgroup_storage_block_ref(shgroup, name, ssbo) \
+ DRW_shgroup_storage_block_ref_ex(shgroup, name, ssbo, __FILE__, __LINE__)
#else
# define DRW_shgroup_vertex_buffer(shgroup, name, vert) \
DRW_shgroup_vertex_buffer_ex(shgroup, name, vert)
@@ -652,10 +652,10 @@ void DRW_shgroup_buffer_texture_ref(DRWShadingGroup *shgroup,
DRW_shgroup_uniform_block_ex(shgroup, name, ubo)
# define DRW_shgroup_uniform_block_ref(shgroup, name, ubo) \
DRW_shgroup_uniform_block_ref_ex(shgroup, name, ubo)
-# define DRW_shgroup_storage_block(shgroup, name, ubo) \
- DRW_shgroup_storage_block_ex(shgroup, name, ubo)
-# define DRW_shgroup_storage_block_ref(shgroup, name, ubo) \
- DRW_shgroup_storage_block_ref_ex(shgroup, name, ubo)
+# define DRW_shgroup_storage_block(shgroup, name, ssbo) \
+ DRW_shgroup_storage_block_ex(shgroup, name, ssbo)
+# define DRW_shgroup_storage_block_ref(shgroup, name, ssbo) \
+ DRW_shgroup_storage_block_ref_ex(shgroup, name, ssbo)
#endif
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
@@ -837,7 +837,7 @@ 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).
+ * \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,
@@ -850,6 +850,7 @@ void DRW_custom_pipeline(DrawEngineType *draw_engine_type,
void DRW_cache_restart(void);
/* ViewLayers */
+
void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type);
void **DRW_view_layer_engine_data_ensure_ex(struct ViewLayer *view_layer,
DrawEngineType *engine_type,
@@ -858,6 +859,7 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type,
void (*callback)(void *storage));
/* DrawData */
+
DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type);
DrawData *DRW_drawdata_ensure(ID *id,
DrawEngineType *engine_type,
diff --git a/source/blender/draw/intern/draw_attributes.cc b/source/blender/draw/intern/draw_attributes.cc
index 714f1dbb3d1..3f187aef8e6 100644
--- a/source/blender/draw/intern/draw_attributes.cc
+++ b/source/blender/draw/intern/draw_attributes.cc
@@ -65,9 +65,10 @@ bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b)
}
DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
- CustomDataType type,
- int layer,
- AttributeDomain domain)
+ const char *name,
+ const eCustomDataType type,
+ const int layer_index,
+ const eAttrDomain domain)
{
if (attrs->num_requests >= GPU_MAX_ATTR) {
return nullptr;
@@ -75,7 +76,8 @@ DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
DRW_AttributeRequest *req = &attrs->requests[attrs->num_requests];
req->cd_type = type;
- req->layer_index = layer;
+ BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name));
+ req->layer_index = layer_index;
req->domain = domain;
attrs->num_requests += 1;
return req;
@@ -84,9 +86,9 @@ DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
bool drw_custom_data_match_attribute(const CustomData *custom_data,
const char *name,
int *r_layer_index,
- int *r_type)
+ eCustomDataType *r_type)
{
- const int possible_attribute_types[7] = {
+ const eCustomDataType possible_attribute_types[7] = {
CD_PROP_BOOL,
CD_PROP_INT8,
CD_PROP_INT32,
@@ -97,7 +99,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data,
};
for (int i = 0; i < ARRAY_SIZE(possible_attribute_types); i++) {
- const int attr_type = possible_attribute_types[i];
+ const eCustomDataType attr_type = possible_attribute_types[i];
int layer_index = CustomData_get_named_layer(custom_data, attr_type, name);
if (layer_index == -1) {
continue;
diff --git a/source/blender/draw/intern/draw_attributes.h b/source/blender/draw/intern/draw_attributes.h
index 192ffa43337..b577c6c4162 100644
--- a/source/blender/draw/intern/draw_attributes.h
+++ b/source/blender/draw/intern/draw_attributes.h
@@ -25,9 +25,9 @@ extern "C" {
#endif
typedef struct DRW_AttributeRequest {
- CustomDataType cd_type;
+ eCustomDataType cd_type;
int layer_index;
- AttributeDomain domain;
+ eAttrDomain domain;
char attribute_name[64];
} DRW_AttributeRequest;
@@ -46,14 +46,15 @@ void drw_attributes_merge(DRW_Attributes *dst,
bool drw_attributes_overlap(const DRW_Attributes *a, const DRW_Attributes *b);
DRW_AttributeRequest *drw_attributes_add_request(DRW_Attributes *attrs,
- CustomDataType type,
- int layer,
- AttributeDomain domain);
+ const char *name,
+ eCustomDataType data_type,
+ int layer_index,
+ eAttrDomain domain);
bool drw_custom_data_match_attribute(const CustomData *custom_data,
const char *name,
int *r_layer_index,
- int *r_type);
+ eCustomDataType *r_type);
#ifdef __cplusplus
}
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index fb074cc728e..f846251c66b 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -3410,3 +3410,35 @@ void DRW_batch_cache_free_old(Object *ob, int ctime)
}
/** \} */
+
+void DRW_cdlayer_attr_aliases_add(GPUVertFormat *format,
+ const char *base_name,
+ const CustomData *UNUSED(data),
+ const CustomDataLayer *cl,
+ bool is_active_render,
+ bool is_active_layer)
+{
+ char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
+ const char *layer_name = cl->name;
+
+ GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
+
+ /* Attribute layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "%s%s", base_name, attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
+
+ /* Auto layer name. */
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
+ GPU_vertformat_alias_add(format, attr_name);
+
+ /* Active render layer name. */
+ if (is_active_render) {
+ GPU_vertformat_alias_add(format, base_name);
+ }
+
+ /* Active display layer name. */
+ if (is_active_layer) {
+ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", base_name);
+ GPU_vertformat_alias_add(format, attr_name);
+ }
+}
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.hh
index ce3ad9923da..c7127d169e1 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.hh
@@ -7,11 +7,13 @@
#pragma once
-struct DRWSubdivCache;
-struct MeshRenderData;
-struct TaskGraph;
+#include <algorithm>
+
+#include "BLI_utildefines.h"
#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_view3d_enums.h"
#include "BKE_attribute.h"
#include "BKE_object.h"
@@ -22,8 +24,12 @@ struct TaskGraph;
#include "draw_attributes.h"
+struct DRWSubdivCache;
+struct MeshRenderData;
+struct TaskGraph;
+
/* Vertex Group Selection and display options */
-typedef struct DRW_MeshWeightState {
+struct DRW_MeshWeightState {
int defgroup_active;
int defgroup_len;
@@ -31,13 +37,13 @@ typedef struct DRW_MeshWeightState {
char alert_mode;
/* Set of all selected bones for Multi-paint. */
- bool *defgroup_sel; /* [defgroup_len] */
+ bool *defgroup_sel; /* #defgroup_len */
int defgroup_sel_count;
/* Set of all locked and unlocked deform bones for Lock Relative mode. */
- bool *defgroup_locked; /* [defgroup_len] */
- bool *defgroup_unlocked; /* [defgroup_len] */
-} DRW_MeshWeightState;
+ bool *defgroup_locked; /* #defgroup_len */
+ bool *defgroup_unlocked; /* #defgroup_len */
+};
/* DRW_MeshWeightState.flags */
enum {
@@ -46,30 +52,32 @@ enum {
DRW_MESH_WEIGHT_STATE_LOCK_RELATIVE = (1 << 2),
};
-typedef struct DRW_MeshCDMask {
+struct DRW_MeshCDMask {
uint32_t uv : 8;
uint32_t tan : 8;
uint32_t vcol : 8;
uint32_t orco : 1;
uint32_t tan_orco : 1;
uint32_t sculpt_overlays : 1;
- /** Edit uv layer is from the base edit mesh as
- * modifiers could remove it. (see T68857) */
+ /**
+ * Edit uv layer is from the base edit mesh as modifiers could remove it. (see T68857)
+ */
uint32_t edit_uv : 1;
-} DRW_MeshCDMask;
-/* Keep `DRW_MeshCDMask` struct within an `uint32_t`.
+};
+/* Keep `DRW_MeshCDMask` struct within a `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(uint32_t), "DRW_MeshCDMask exceeds 32 bits")
-typedef enum eMRIterType {
+
+enum eMRIterType {
MR_ITER_LOOPTRI = 1 << 0,
MR_ITER_POLY = 1 << 1,
MR_ITER_LEDGE = 1 << 2,
MR_ITER_LVERT = 1 << 3,
-} eMRIterType;
+};
ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT)
-typedef enum eMRDataType {
+enum eMRDataType {
MR_DATA_NONE = 0,
MR_DATA_POLY_NOR = 1 << 1,
MR_DATA_LOOP_NOR = 1 << 2,
@@ -78,29 +86,24 @@ typedef enum eMRDataType {
/** Force loop normals calculation. */
MR_DATA_TAN_LOOP_NOR = 1 << 5,
MR_DATA_POLYS_SORTED = 1 << 6,
-} eMRDataType;
+};
ENUM_OPERATORS(eMRDataType, MR_DATA_POLYS_SORTED)
-#ifdef __cplusplus
-extern "C" {
-#endif
-
BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me)
{
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 std::max<int>(1, editmesh_eval_final->totcol);
}
}
- return MAX2(1, me->totcol);
+ return std::max<int>(1, me->totcol);
}
-typedef struct MeshBufferList {
- /* Every VBO below contains at least enough
- * data for every loops in the mesh (except fdots and skin roots).
- * For some VBOs, it extends to (in this exact order) :
- * loops + loose_edges*2 + loose_verts */
+struct MeshBufferList {
+ /* Every VBO below contains at least enough data for every loop in the mesh
+ * (except fdots and skin roots). For some VBOs, it extends to (in this exact order) :
+ * loops + loose_edges * 2 + loose_verts */
struct {
GPUVertBuf *pos_nor; /* extend */
GPUVertBuf *lnor; /* extend */
@@ -133,14 +136,17 @@ typedef struct MeshBufferList {
/* Index Buffers:
* Only need to be updated when topology changes. */
struct {
- /* Indices to vloops. */
- GPUIndexBuf *tris; /* Ordered per material. */
- GPUIndexBuf *lines; /* Loose edges last. */
- GPUIndexBuf *lines_loose; /* sub buffer of `lines` only containing the loose edges. */
+ /* Indices to vloops. Ordered per material. */
+ GPUIndexBuf *tris;
+ /* Loose edges last. */
+ GPUIndexBuf *lines;
+ /* Sub buffer of `lines` only containing the loose edges. */
+ GPUIndexBuf *lines_loose;
GPUIndexBuf *points;
GPUIndexBuf *fdots;
/* 3D overlays. */
- GPUIndexBuf *lines_paint_mask; /* no loose edges. */
+ /* no loose edges. */
+ GPUIndexBuf *lines_paint_mask;
GPUIndexBuf *lines_adjacency;
/* Uv overlays. (visibility can differ from 3D view) */
GPUIndexBuf *edituv_tris;
@@ -148,9 +154,9 @@ typedef struct MeshBufferList {
GPUIndexBuf *edituv_points;
GPUIndexBuf *edituv_fdots;
} ibo;
-} MeshBufferList;
+};
-typedef struct MeshBatchList {
+struct MeshBatchList {
/* Surfaces / Render */
GPUBatch *surface;
GPUBatch *surface_weights;
@@ -180,19 +186,22 @@ typedef struct MeshBatchList {
GPUBatch *all_edges;
GPUBatch *loose_edges;
GPUBatch *edge_detection;
- GPUBatch *wire_edges; /* Individual edges with face normals. */
- GPUBatch *wire_loops; /* Loops around faces. no edges between selected faces */
- GPUBatch *wire_loops_uvs; /* Same as wire_loops but only has uvs. */
+ /* Individual edges with face normals. */
+ GPUBatch *wire_edges;
+ /* Loops around faces. no edges between selected faces */
+ GPUBatch *wire_loops;
+ /* Same as wire_loops but only has uvs. */
+ GPUBatch *wire_loops_uvs;
GPUBatch *sculpt_overlays;
-} MeshBatchList;
+};
#define MBC_BATCH_LEN (sizeof(MeshBatchList) / sizeof(void *))
-#define MBC_VBO_LEN (sizeof(((MeshBufferList){0}).vbo) / sizeof(void *))
-#define MBC_IBO_LEN (sizeof(((MeshBufferList){0}).ibo) / sizeof(void *))
+#define MBC_VBO_LEN (sizeof(MeshBufferList::vbo) / sizeof(void *))
+#define MBC_IBO_LEN (sizeof(MeshBufferList::ibo) / sizeof(void *))
#define MBC_BATCH_INDEX(batch) (offsetof(MeshBatchList, batch) / sizeof(void *))
-typedef enum DRWBatchFlag {
+enum DRWBatchFlag {
MBC_SURFACE = (1u << MBC_BATCH_INDEX(surface)),
MBC_SURFACE_WEIGHTS = (1u << MBC_BATCH_INDEX(surface_weights)),
MBC_EDIT_TRIANGLES = (1u << MBC_BATCH_INDEX(edit_triangles)),
@@ -221,23 +230,25 @@ typedef enum DRWBatchFlag {
MBC_WIRE_LOOPS = (1u << MBC_BATCH_INDEX(wire_loops)),
MBC_WIRE_LOOPS_UVS = (1u << MBC_BATCH_INDEX(wire_loops_uvs)),
MBC_SCULPT_OVERLAYS = (1u << MBC_BATCH_INDEX(sculpt_overlays)),
-} DRWBatchFlag;
+ MBC_SURFACE_PER_MAT = (1u << MBC_BATCH_LEN),
+};
+ENUM_OPERATORS(DRWBatchFlag, MBC_SURFACE_PER_MAT);
BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields");
-typedef struct MeshExtractLooseGeom {
+struct MeshExtractLooseGeom {
int edge_len;
int vert_len;
int *verts;
int *edges;
-} MeshExtractLooseGeom;
+};
/**
* Data that are kept around between extractions to reduce rebuilding time.
*
* - Loose geometry.
*/
-typedef struct MeshBufferCache {
+struct MeshBufferCache {
MeshBufferList buff;
MeshExtractLooseGeom loose_geom;
@@ -247,7 +258,7 @@ typedef struct MeshBufferCache {
int *mat_tri_len;
int visible_tri_len;
} poly_sorted;
-} MeshBufferCache;
+};
#define FOREACH_MESH_BUFFER_CACHE(batch_cache, mbc) \
for (MeshBufferCache *mbc = &batch_cache->final; \
@@ -256,7 +267,7 @@ typedef struct MeshBufferCache {
&batch_cache->cage : \
((mbc == &batch_cache->cage) ? &batch_cache->uv_cage : NULL))
-typedef struct MeshBatchCache {
+struct MeshBatchCache {
MeshBufferCache final, cage, uv_cage;
MeshBatchList batch;
@@ -266,22 +277,23 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
- struct DRWSubdivCache *subdiv_cache;
+ DRWSubdivCache *subdiv_cache;
- DRWBatchFlag batch_requested; /* DRWBatchFlag */
- DRWBatchFlag batch_ready; /* DRWBatchFlag */
+ DRWBatchFlag batch_requested;
+ DRWBatchFlag batch_ready;
- /* settings to determine if cache is invalid */
+ /* Settings to determine if cache is invalid. */
int edge_len;
int tri_len;
int poly_len;
int vert_len;
int mat_len;
- bool is_dirty; /* Instantly invalidates cache, skipping mesh check */
+ /* Instantly invalidates cache, skipping mesh check */
+ bool is_dirty;
bool is_editmode;
bool is_uvsyncsel;
- struct DRW_MeshWeightState weight_state;
+ DRW_MeshWeightState weight_state;
DRW_MeshCDMask cd_used, cd_needed, cd_used_over_time;
@@ -302,13 +314,15 @@ typedef struct MeshBatchCache {
eV3DShadingColorType color_type;
bool pbvh_is_drawing;
-} MeshBatchCache;
+};
#define MBC_EDITUV \
(MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE | MBC_EDITUV_FACES | \
MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_EDITUV_FACEDOTS | MBC_WIRE_LOOPS_UVS)
-void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
+namespace blender::draw {
+
+void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
Object *object,
@@ -320,14 +334,12 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
bool do_final,
bool do_uvedit,
const Scene *scene,
- const struct ToolSettings *ts,
+ const ToolSettings *ts,
bool use_hide);
void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
MeshBufferCache *mbc,
- struct DRWSubdivCache *subdiv_cache,
- struct MeshRenderData *mr);
+ DRWSubdivCache *subdiv_cache,
+ MeshRenderData *mr);
-#ifdef __cplusplus
-}
-#endif
+} // namespace blender::draw
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 3d44d3d1b3f..380736ef656 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -24,11 +24,11 @@
#include "GPU_capabilities.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_inline.h"
#include "draw_subdivision.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
// #define DEBUG_TIME
@@ -155,7 +155,7 @@ struct ExtractTaskData {
bool use_threading = false;
ExtractTaskData(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
ExtractorRunDatas *extractors,
MeshBufferList *mbuflist,
const bool use_threading)
@@ -193,7 +193,7 @@ static void extract_task_data_free(void *data)
* \{ */
BLI_INLINE void extract_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
ExtractorRunDatas &extractors,
MeshBufferList *mbuflist,
void *data_stack)
@@ -209,7 +209,7 @@ BLI_INLINE void extract_init(const MeshRenderData *mr,
}
BLI_INLINE void extract_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
const ExtractorRunDatas &extractors,
void *data_stack)
{
@@ -551,21 +551,21 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t
/** \name Extract Loop
* \{ */
-static 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,
- const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide)
+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,
+ const float obmat[4][4],
+ const bool do_final,
+ const bool do_uvedit,
+ const Scene *scene,
+ const ToolSettings *ts,
+ const bool use_hide)
{
/* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
* This sub-graph starts with an extract_render_data_node. This fills/converts the required
@@ -772,10 +772,10 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
/** \name Subdivision Extract Loop
* \{ */
-static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
- MeshBufferCache *mbc,
- DRWSubdivCache *subdiv_cache,
- MeshRenderData *mr)
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ MeshRenderData *mr)
{
/* Create an array containing all the extractors that needs to be executed. */
ExtractorRunDatas extractors;
@@ -908,46 +908,3 @@ static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
/** \} */
} // 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,
- const bool is_paint_mode,
- const bool is_mode_active,
- const float obmat[4][4],
- const bool do_final,
- const bool do_uvedit,
- const Scene *scene,
- const ToolSettings *ts,
- const bool use_hide)
-{
- blender::draw::mesh_buffer_cache_create_requested(task_graph,
- cache,
- mbc,
- object,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- obmat,
- do_final,
- do_uvedit,
- scene,
- ts,
- use_hide);
-}
-
-void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
- MeshBufferCache *mbc,
- DRWSubdivCache *subdiv_cache,
- MeshRenderData *mr)
-{
- blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, mr);
-}
-
-} // 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.cc
index 0a93f346b37..77cbb5efa12 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc
@@ -9,7 +9,7 @@
#include "MEM_guardedalloc.h"
-#include "BLI_alloca.h"
+#include "BLI_array.hh"
#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -22,7 +22,7 @@
#include "ED_mesh.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
/* ---------------------------------------------------------------------- */
/** \name Update Loose Geometry
@@ -78,7 +78,8 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
{
BLI_bitmap *lvert_map = BLI_BITMAP_NEW(mr->vert_len, __func__);
- cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__);
+ cache->loose_geom.edges = static_cast<int *>(
+ MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__));
const MEdge *med = mr->medge;
for (int med_index = 0; med_index < mr->edge_len; med_index++, med++) {
if (med->flag & ME_LOOSEEDGE) {
@@ -89,19 +90,20 @@ static void mesh_render_data_loose_geom_mesh(const MeshRenderData *mr, MeshBuffe
BLI_BITMAP_ENABLE(lvert_map, med->v2);
}
if (cache->loose_geom.edge_len < mr->edge_len) {
- cache->loose_geom.edges = MEM_reallocN(
- cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges));
+ cache->loose_geom.edges = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)));
}
- cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__);
+ cache->loose_geom.verts = static_cast<int *>(
+ MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__));
for (int v = 0; v < mr->vert_len; v++) {
if (!BLI_BITMAP_TEST(lvert_map, v)) {
cache->loose_geom.verts[cache->loose_geom.vert_len++] = v;
}
}
if (cache->loose_geom.vert_len < mr->vert_len) {
- cache->loose_geom.verts = MEM_reallocN(
- cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts));
+ cache->loose_geom.verts = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)));
}
MEM_freeN(lvert_map);
@@ -112,15 +114,16 @@ static void mesh_render_data_lverts_bm(const MeshRenderData *mr, MeshBufferCache
int elem_id;
BMIter iter;
BMVert *eve;
- cache->loose_geom.verts = MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__);
+ cache->loose_geom.verts = static_cast<int *>(
+ MEM_mallocN(mr->vert_len * sizeof(*cache->loose_geom.verts), __func__));
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, elem_id) {
- if (eve->e == NULL) {
+ if (eve->e == nullptr) {
cache->loose_geom.verts[cache->loose_geom.vert_len++] = elem_id;
}
}
if (cache->loose_geom.vert_len < mr->vert_len) {
- cache->loose_geom.verts = MEM_reallocN(
- cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts));
+ cache->loose_geom.verts = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.verts, cache->loose_geom.vert_len * sizeof(*cache->loose_geom.verts)));
}
}
@@ -129,15 +132,16 @@ static void mesh_render_data_ledges_bm(const MeshRenderData *mr, MeshBufferCache
int elem_id;
BMIter iter;
BMEdge *ede;
- cache->loose_geom.edges = MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__);
+ cache->loose_geom.edges = static_cast<int *>(
+ MEM_mallocN(mr->edge_len * sizeof(*cache->loose_geom.edges), __func__));
BM_ITER_MESH_INDEX (ede, &iter, bm, BM_EDGES_OF_MESH, elem_id) {
- if (ede->l == NULL) {
+ if (ede->l == nullptr) {
cache->loose_geom.edges[cache->loose_geom.edge_len++] = elem_id;
}
}
if (cache->loose_geom.edge_len < mr->edge_len) {
- cache->loose_geom.edges = MEM_reallocN(
- cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges));
+ cache->loose_geom.edges = static_cast<int *>(MEM_reallocN(
+ cache->loose_geom.edges, cache->loose_geom.edge_len * sizeof(*cache->loose_geom.edges)));
}
}
@@ -192,12 +196,13 @@ static void mesh_render_data_polys_sorted_ensure(MeshRenderData *mr, MeshBufferC
static void mesh_render_data_polys_sorted_build(MeshRenderData *mr, MeshBufferCache *cache)
{
- int *tri_first_index = MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__);
+ int *tri_first_index = static_cast<int *>(
+ MEM_mallocN(sizeof(*tri_first_index) * mr->poly_len, __func__));
int *mat_tri_len = mesh_render_data_mat_tri_len_build(mr);
/* Apply offset. */
int visible_tri_len = 0;
- int *mat_tri_offs = BLI_array_alloca(mat_tri_offs, mr->mat_len);
+ blender::Array<int, 32> mat_tri_offs(mr->mat_len);
{
for (int i = 0; i < mr->mat_len; i++) {
mat_tri_offs[i] = visible_tri_len;
@@ -245,8 +250,8 @@ static void mesh_render_data_mat_tri_len_bm_range_fn(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
- MeshRenderData *mr = userdata;
- int *mat_tri_len = tls->userdata_chunk;
+ MeshRenderData *mr = static_cast<MeshRenderData *>(userdata);
+ int *mat_tri_len = static_cast<int *>(tls->userdata_chunk);
BMesh *bm = mr->bm;
BMFace *efa = BM_face_at_index(bm, iter);
@@ -260,8 +265,8 @@ static void mesh_render_data_mat_tri_len_mesh_range_fn(void *__restrict userdata
const int iter,
const TaskParallelTLS *__restrict tls)
{
- MeshRenderData *mr = userdata;
- int *mat_tri_len = tls->userdata_chunk;
+ MeshRenderData *mr = static_cast<MeshRenderData *>(userdata);
+ int *mat_tri_len = static_cast<int *>(tls->userdata_chunk);
const MPoly *mp = &mr->mpoly[iter];
if (!(mr->use_hide && (mp->flag & ME_HIDE))) {
@@ -274,9 +279,9 @@ static void mesh_render_data_mat_tri_len_reduce_fn(const void *__restrict userda
void *__restrict chunk_join,
void *__restrict chunk)
{
- const MeshRenderData *mr = userdata;
- int *dst_mat_len = chunk_join;
- int *src_mat_len = chunk;
+ const MeshRenderData *mr = static_cast<const MeshRenderData *>(userdata);
+ int *dst_mat_len = static_cast<int *>(chunk_join);
+ int *src_mat_len = static_cast<int *>(chunk);
for (int i = 0; i < mr->mat_len; i++) {
dst_mat_len[i] += src_mat_len[i];
}
@@ -288,7 +293,7 @@ static int *mesh_render_data_mat_tri_len_build_threaded(MeshRenderData *mr,
{
/* Extending the #MatOffsetUserData with an int per material slot. */
size_t mat_tri_len_size = sizeof(int) * mr->mat_len;
- int *mat_tri_len = MEM_callocN(mat_tri_len_size, __func__);
+ int *mat_tri_len = static_cast<int *>(MEM_callocN(mat_tri_len_size, __func__));
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -330,8 +335,9 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* NOTE(campbell): It's possible to skip allocating tessellation,
* the tessellation can be calculated as part of the iterator, see: P2188.
* The overall advantage is small (around 1%), so keep this as-is. */
- mr->mlooptri = MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI");
- if (mr->poly_normals != NULL) {
+ mr->mlooptri = static_cast<MLoopTri *>(
+ MEM_mallocN(sizeof(*mr->mlooptri) * mr->tri_len, "MR_DATATYPE_LOOPTRI"));
+ if (mr->poly_normals != nullptr) {
BKE_mesh_recalc_looptri_with_normals(me->mloop,
me->mpoly,
me->mvert,
@@ -350,7 +356,7 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* #BMesh */
if ((iter_type & MR_ITER_LOOPTRI) || (data_flag & MR_DATA_LOOPTRI)) {
/* Edit mode ensures this is valid, no need to calculate. */
- BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != NULL));
+ BLI_assert((mr->bm->totloop == 0) || (mr->edit_bmesh->looptris != nullptr));
}
}
}
@@ -368,8 +374,10 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
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);
+ mr->loop_normals = static_cast<float(*)[3]>(
+ MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__));
+ short(*clnors)[2] = static_cast<short(*)[2]>(
+ CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL));
BKE_mesh_normals_loop_split(mr->me->mvert,
mr->vert_normals,
mr->vert_len,
@@ -383,9 +391,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
mr->poly_len,
is_auto_smooth,
split_angle,
- NULL,
+ nullptr,
clnors,
- NULL);
+ nullptr);
}
}
else {
@@ -395,9 +403,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
- const float(*vert_coords)[3] = NULL;
- const float(*vert_normals)[3] = NULL;
- const float(*poly_normals)[3] = NULL;
+ const float(*vert_coords)[3] = nullptr;
+ const float(*vert_normals)[3] = nullptr;
+ const float(*poly_normals)[3] = nullptr;
if (mr->edit_data && mr->edit_data->vertexCos) {
vert_coords = mr->bm_vert_coords;
@@ -405,7 +413,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
poly_normals = mr->bm_poly_normals;
}
- mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
+ mr->loop_normals = static_cast<float(*)[3]>(
+ MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__));
const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL);
BM_loops_calc_normal_vcos(mr->bm,
vert_coords,
@@ -414,8 +423,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
is_auto_smooth,
split_angle,
mr->loop_normals,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
clnors_offset,
false);
}
@@ -432,7 +441,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
const bool do_uvedit,
const ToolSettings *ts)
{
- MeshRenderData *mr = MEM_callocN(sizeof(*mr), __func__);
+ MeshRenderData *mr = static_cast<MeshRenderData *>(MEM_callocN(sizeof(*mr), __func__));
mr->toolsettings = ts;
mr->mat_len = mesh_render_mat_len_get(object, me);
@@ -446,7 +455,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->bm = me->edit_mesh->bm;
mr->edit_bmesh = me->edit_mesh;
mr->me = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
- mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : NULL;
+ mr->edit_data = is_mode_active ? mr->me->runtime.edit_data : nullptr;
if (mr->edit_data) {
EditMeshData *emd = mr->edit_data;
@@ -491,9 +500,12 @@ MeshRenderData *mesh_render_data_create(Object *object,
#endif
if (use_mapped) {
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
}
@@ -502,20 +514,23 @@ MeshRenderData *mesh_render_data_create(Object *object,
/* Seems like the mesh_eval_final do not have the right origin indices.
* Force not mapped in this case. */
- if (has_mdata && do_final && editmesh_eval_final != editmesh_eval_cage) {
- // mr->edit_bmesh = NULL;
+ if (use_mapped && do_final && editmesh_eval_final != editmesh_eval_cage) {
+ // mr->edit_bmesh = nullptr;
mr->extract_type = MR_EXTRACT_MESH;
}
}
else {
mr->me = me;
- mr->edit_bmesh = NULL;
+ mr->edit_bmesh = nullptr;
bool use_mapped = is_paint_mode && mr->me && !mr->me->runtime.is_original;
if (use_mapped) {
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(
+ CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
use_mapped = (mr->v_origindex || mr->e_origindex || mr->p_origindex);
}
@@ -531,14 +546,14 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->poly_len = mr->me->totpoly;
mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len);
- mr->mvert = CustomData_get_layer(&mr->me->vdata, CD_MVERT);
- mr->medge = CustomData_get_layer(&mr->me->edata, CD_MEDGE);
- mr->mloop = CustomData_get_layer(&mr->me->ldata, CD_MLOOP);
- mr->mpoly = CustomData_get_layer(&mr->me->pdata, CD_MPOLY);
+ mr->mvert = static_cast<MVert *>(CustomData_get_layer(&mr->me->vdata, CD_MVERT));
+ mr->medge = static_cast<MEdge *>(CustomData_get_layer(&mr->me->edata, CD_MEDGE));
+ mr->mloop = static_cast<MLoop *>(CustomData_get_layer(&mr->me->ldata, CD_MLOOP));
+ mr->mpoly = static_cast<MPoly *>(CustomData_get_layer(&mr->me->pdata, CD_MPOLY));
- mr->v_origindex = CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX);
- mr->e_origindex = CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX);
- mr->p_origindex = CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX);
+ mr->v_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<const int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
}
else {
/* #BMesh */
@@ -560,8 +575,8 @@ void mesh_render_data_free(MeshRenderData *mr)
MEM_SAFE_FREE(mr->loop_normals);
/* Loose geometry are owned by #MeshBufferCache. */
- mr->ledges = NULL;
- mr->lverts = NULL;
+ mr->ledges = nullptr;
+ mr->lverts = nullptr;
MEM_freeN(mr);
}
diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h
index 0755d5967d5..91dbef8d7b1 100644
--- a/source/blender/draw/intern/draw_cache_impl.h
+++ b/source/blender/draw/intern/draw_cache_impl.h
@@ -156,11 +156,25 @@ struct GPUBatch *DRW_lattice_batch_cache_get_edit_verts(struct Lattice *lt);
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Hair
+/** \name Curves
* \{ */
int DRW_curves_material_count_get(struct Curves *curves);
+/**
+ * Provide GPU access to a specific evaluated attribute on curves.
+ *
+ * \return A pointer to location where the texture will be
+ * stored, which will be filled by #DRW_shgroup_curves_create_sub.
+ */
+struct GPUTexture **DRW_curves_texture_for_evaluated_attribute(struct Curves *curves,
+ const char *name,
+ bool *r_is_point_domain);
+
+struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves);
+
+void DRW_curves_batch_cache_create_requested(struct Object *ob);
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -352,16 +366,6 @@ struct GPUBatch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *ob
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Curves
- * \{ */
-
-struct GPUBatch *DRW_curves_batch_cache_get_edit_points(struct Curves *curves);
-
-void DRW_curves_batch_cache_create_requested(const struct Object *ob);
-
-/** \} */
-
#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 ebcdabe4942..695c348d8e2 100644
--- a/source/blender/draw/intern/draw_cache_impl_curve.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curve.cc
@@ -108,7 +108,7 @@ static void curve_eval_render_wire_verts_edges_len_get(const blender::bke::Curve
const blender::VArray<bool> cyclic = curves.cyclic();
for (const int i : curves.curves_range()) {
const IndexRange points = curves.evaluated_points_for_curve(i);
- *r_edge_len += blender::bke::curves::curve_segment_num(points.size(), cyclic[i]);
+ *r_edge_len += blender::bke::curves::segments_num(points.size(), cyclic[i]);
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index f9cf0021fcd..1d3d6222f8f 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -52,11 +52,14 @@ struct CurvesBatchCache {
GPUBatch *edit_points;
- /* To determine if cache is invalid. */
+ /* Whether the cache is invalid. */
bool is_dirty;
- /** Needed when updating material data (e.g. attributes) as the same curves might be used for
- * multiple objects with different materials. */
+ /**
+ * The draw cache extraction is currently not multi-threaded for multiple objects, but if it was,
+ * some locking would be necessary because multiple objects can use the same curves data with
+ * different materials, etc. This is a placeholder to make multi-threading easier in the future.
+ */
ThreadMutex render_mutex;
};
@@ -72,25 +75,26 @@ static void curves_batch_cache_init(Curves &curves)
if (!cache) {
cache = MEM_cnew<CurvesBatchCache>(__func__);
- BLI_mutex_init(&cache->render_mutex);
curves.batch_cache = cache;
}
else {
memset(cache, 0, sizeof(*cache));
}
+ BLI_mutex_init(&cache->render_mutex);
+
cache->is_dirty = false;
}
static void curves_discard_attributes(CurvesEvalCache &curves_cache)
{
- for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
GPU_VERTBUF_DISCARD_SAFE(curves_cache.proc_attributes_buf[i]);
DRW_TEXTURE_FREE_SAFE(curves_cache.proc_attributes_tex[i]);
}
- for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
- for (int j = 0; j < GPU_MAX_ATTR; j++) {
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
+ for (const int j : IndexRange(GPU_MAX_ATTR)) {
GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].attributes_buf[j]);
DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].attributes_tex[j]);
}
@@ -112,10 +116,10 @@ static void curves_batch_cache_clear_data(CurvesEvalCache &curves_cache)
DRW_TEXTURE_FREE_SAFE(curves_cache.strand_tex);
DRW_TEXTURE_FREE_SAFE(curves_cache.strand_seg_tex);
- for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
GPU_VERTBUF_DISCARD_SAFE(curves_cache.final[i].proc_buf);
DRW_TEXTURE_FREE_SAFE(curves_cache.final[i].proc_tex);
- for (int j = 0; j < MAX_THICKRES; j++) {
+ for (const int j : IndexRange(MAX_THICKRES)) {
GPU_BATCH_DISCARD_SAFE(curves_cache.final[i].proc_hairs[j]);
}
}
@@ -160,7 +164,7 @@ void DRW_curves_batch_cache_dirty_tag(Curves *curves, int mode)
cache->is_dirty = true;
break;
default:
- BLI_assert(0);
+ BLI_assert_unreachable();
}
}
@@ -181,7 +185,7 @@ void DRW_curves_batch_cache_free_old(Curves *curves, int ctime)
bool do_discard = false;
- for (int i = 0; i < MAX_HAIR_SUBDIV; i++) {
+ for (const int i : IndexRange(MAX_HAIR_SUBDIV)) {
CurvesEvalFinalCache &final_cache = cache->curves_cache.final[i];
if (drw_attributes_overlap(&final_cache.attr_used_over_time, &final_cache.attr_used)) {
@@ -255,7 +259,7 @@ static void curves_batch_cache_fill_segments_proc_pos(
}
}
-static void curves_batch_cache_ensure_procedural_pos(Curves &curves,
+static void curves_batch_cache_ensure_procedural_pos(const Curves &curves,
CurvesEvalCache &cache,
GPUMaterial *gpu_material)
{
@@ -308,8 +312,11 @@ void drw_curves_get_attribute_sampler_name(const char *layer_name, char r_sample
BLI_snprintf(r_sampler_name, 32, "a%s", attr_safe_name);
}
-static void curves_batch_cache_ensure_procedural_final_attr(
- CurvesEvalCache &cache, GPUVertFormat *format, int subdiv, int index, const char *name)
+static void curves_batch_cache_ensure_procedural_final_attr(CurvesEvalCache &cache,
+ const GPUVertFormat *format,
+ const int subdiv,
+ const int index,
+ const char *name)
{
CurvesEvalFinalCache &final_cache = cache.final[subdiv];
final_cache.attributes_buf[index] = GPU_vertbuf_create_with_format_ex(format,
@@ -330,8 +337,8 @@ static void curves_batch_cache_ensure_procedural_final_attr(
static void curves_batch_ensure_attribute(const Curves &curves,
CurvesEvalCache &cache,
const DRW_AttributeRequest &request,
- int subdiv,
- int index)
+ const int subdiv,
+ const int index)
{
GPU_VERTBUF_DISCARD_SAFE(cache.proc_attributes_buf[index]);
DRW_TEXTURE_FREE_SAFE(cache.proc_attributes_tex[index]);
@@ -351,20 +358,20 @@ static void curves_batch_ensure_attribute(const Curves &curves,
request.domain == ATTR_DOMAIN_POINT ? curves.geometry.point_num :
curves.geometry.curve_num);
- CurveComponent component;
- component.replace(const_cast<Curves *>(&curves), GeometryOwnershipType::ReadOnly);
+ const blender::bke::AttributeAccessor attributes =
+ blender::bke::CurvesGeometry::wrap(curves.geometry).attributes();
/* TODO(@kevindietrich): float4 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 state swizzle to map the attribute correctly as for volume attributes, so we
* can control the conversion ourselves. */
- blender::VArray<ColorGeometry4f> attribute = component.attribute_get_for_read<ColorGeometry4f>(
+ blender::VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>(
request.attribute_name, request.domain, {0.0f, 0.0f, 0.0f, 1.0f});
MutableSpan<ColorGeometry4f> vbo_span{
static_cast<ColorGeometry4f *>(GPU_vertbuf_get_data(attr_vbo)),
- component.attribute_domain_num(request.domain)};
+ attributes.domain_size(request.domain)};
attribute.materialize(vbo_span);
@@ -506,64 +513,45 @@ static bool curves_ensure_attributes(const Curves &curves,
ThreadMutex *render_mutex = &cache.render_mutex;
const CustomData *cd_curve = &curves.geometry.curve_data;
const CustomData *cd_point = &curves.geometry.point_data;
+ CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
- DRW_Attributes attrs_needed;
- drw_attributes_clear(&attrs_needed);
- ListBase gpu_attrs = GPU_material_attributes(gpu_material);
- LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
- const char *name = gpu_attr->name;
- int type = gpu_attr->type;
- int layer = -1;
- AttributeDomain domain;
-
- if (drw_custom_data_match_attribute(cd_curve, name, &layer, &type)) {
- domain = ATTR_DOMAIN_CURVE;
- }
- else if (drw_custom_data_match_attribute(cd_point, name, &layer, &type)) {
- domain = ATTR_DOMAIN_POINT;
- }
- else {
- continue;
- }
-
- switch (type) {
- default:
- break;
- case CD_PROP_BOOL:
- case CD_PROP_INT8:
- case CD_PROP_INT32:
- case CD_PROP_FLOAT:
- case CD_PROP_FLOAT2:
- case CD_PROP_FLOAT3:
- case CD_PROP_COLOR: {
- if (layer != -1) {
- DRW_AttributeRequest *req = drw_attributes_add_request(
- &attrs_needed, (CustomDataType)type, layer, domain);
- if (req) {
- BLI_strncpy(req->attribute_name, name, sizeof(req->attribute_name));
- }
- }
- break;
+ if (gpu_material) {
+ DRW_Attributes attrs_needed;
+ drw_attributes_clear(&attrs_needed);
+ ListBase gpu_attrs = GPU_material_attributes(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
+ const char *name = gpu_attr->name;
+
+ int layer_index;
+ eCustomDataType type;
+ eAttrDomain domain;
+ if (drw_custom_data_match_attribute(cd_curve, name, &layer_index, &type)) {
+ domain = ATTR_DOMAIN_CURVE;
+ }
+ else if (drw_custom_data_match_attribute(cd_point, name, &layer_index, &type)) {
+ domain = ATTR_DOMAIN_POINT;
+ }
+ else {
+ continue;
}
- }
- }
- CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
+ drw_attributes_add_request(&attrs_needed, name, type, layer_index, domain);
+ }
- const bool attr_overlap = drw_attributes_overlap(&final_cache.attr_used, &attrs_needed);
- if (attr_overlap == false) {
- /* Some new attributes have been added, free all and start over. */
- for (int i = 0; i < GPU_MAX_ATTR; i++) {
- GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]);
- DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]);
+ if (!drw_attributes_overlap(&final_cache.attr_used, &attrs_needed)) {
+ /* Some new attributes have been added, free all and start over. */
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
+ GPU_VERTBUF_DISCARD_SAFE(cache.curves_cache.proc_attributes_buf[i]);
+ DRW_TEXTURE_FREE_SAFE(cache.curves_cache.proc_attributes_tex[i]);
+ }
+ drw_attributes_merge(&final_cache.attr_used, &attrs_needed, render_mutex);
}
- drw_attributes_merge(&final_cache.attr_used, &attrs_needed, render_mutex);
+ drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, render_mutex);
}
- drw_attributes_merge(&final_cache.attr_used_over_time, &attrs_needed, render_mutex);
bool need_tf_update = false;
- for (int i = 0; i < final_cache.attr_used.num_requests; i++) {
+ for (const int i : IndexRange(final_cache.attr_used.num_requests)) {
const DRW_AttributeRequest &request = final_cache.attr_used.requests[i];
if (cache.curves_cache.proc_attributes_buf[i] != nullptr) {
@@ -580,16 +568,15 @@ static bool curves_ensure_attributes(const Curves &curves,
return need_tf_update;
}
-bool curves_ensure_procedural_data(Object *object,
+bool curves_ensure_procedural_data(Curves *curves,
CurvesEvalCache **r_hair_cache,
GPUMaterial *gpu_material,
const int subdiv,
const int thickness_res)
{
bool need_ft_update = false;
- Curves &curves = *static_cast<Curves *>(object->data);
- CurvesBatchCache &cache = curves_batch_cache_get(curves);
+ CurvesBatchCache &cache = curves_batch_cache_get(*curves);
*r_hair_cache = &cache.curves_cache;
const int steps = 3; /* TODO: don't hard-code? */
@@ -597,14 +584,14 @@ bool curves_ensure_procedural_data(Object *object,
/* Refreshed on combing and simulation. */
if ((*r_hair_cache)->proc_point_buf == nullptr) {
- ensure_seg_pt_count(curves, cache.curves_cache);
- curves_batch_cache_ensure_procedural_pos(curves, cache.curves_cache, gpu_material);
+ ensure_seg_pt_count(*curves, cache.curves_cache);
+ curves_batch_cache_ensure_procedural_pos(*curves, cache.curves_cache, gpu_material);
need_ft_update = true;
}
/* Refreshed if active layer or custom data changes. */
if ((*r_hair_cache)->strand_tex == nullptr) {
- curves_batch_cache_ensure_procedural_strand_data(curves, cache.curves_cache);
+ curves_batch_cache_ensure_procedural_strand_data(*curves, cache.curves_cache);
}
/* Refreshed only on subdiv count change. */
@@ -614,12 +601,10 @@ bool curves_ensure_procedural_data(Object *object,
}
if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) {
curves_batch_cache_ensure_procedural_indices(
- curves, cache.curves_cache, thickness_res, subdiv);
+ *curves, cache.curves_cache, thickness_res, subdiv);
}
- if (gpu_material) {
- need_ft_update |= curves_ensure_attributes(curves, cache, gpu_material, subdiv);
- }
+ need_ft_update |= curves_ensure_attributes(*curves, cache, gpu_material, subdiv);
return need_ft_update;
}
@@ -635,7 +620,71 @@ GPUBatch *DRW_curves_batch_cache_get_edit_points(Curves *curves)
return DRW_batch_request(&cache.edit_points);
}
-void DRW_curves_batch_cache_create_requested(const Object *ob)
+static void request_attribute(Curves &curves, const char *name)
+{
+ CurvesBatchCache &cache = curves_batch_cache_get(curves);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ const int subdiv = scene->r.hair_subdiv;
+ CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
+
+ DRW_Attributes attributes{};
+
+ blender::bke::CurvesGeometry &curves_geometry = blender::bke::CurvesGeometry::wrap(
+ curves.geometry);
+ std::optional<blender::bke::AttributeMetaData> meta_data =
+ curves_geometry.attributes().lookup_meta_data(name);
+ if (!meta_data) {
+ return;
+ }
+ const eAttrDomain domain = meta_data->domain;
+ const eCustomDataType type = meta_data->data_type;
+ const CustomData &custom_data = domain == ATTR_DOMAIN_POINT ? curves.geometry.point_data :
+ curves.geometry.curve_data;
+
+ drw_attributes_add_request(
+ &attributes, name, type, CustomData_get_named_layer(&custom_data, type, name), domain);
+
+ drw_attributes_merge(&final_cache.attr_used, &attributes, &cache.render_mutex);
+}
+
+GPUTexture **DRW_curves_texture_for_evaluated_attribute(Curves *curves,
+ const char *name,
+ bool *r_is_point_domain)
+{
+ CurvesBatchCache &cache = curves_batch_cache_get(*curves);
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const Scene *scene = draw_ctx->scene;
+ const int subdiv = scene->r.hair_subdiv;
+ CurvesEvalFinalCache &final_cache = cache.curves_cache.final[subdiv];
+
+ request_attribute(*curves, name);
+
+ int request_i = -1;
+ for (const int i : IndexRange(final_cache.attr_used.num_requests)) {
+ if (STREQ(final_cache.attr_used.requests[i].attribute_name, name)) {
+ request_i = i;
+ break;
+ }
+ }
+ if (request_i == -1) {
+ *r_is_point_domain = false;
+ return nullptr;
+ }
+ switch (final_cache.attr_used.requests[request_i].domain) {
+ case ATTR_DOMAIN_POINT:
+ *r_is_point_domain = true;
+ return &final_cache.attributes_tex[request_i];
+ case ATTR_DOMAIN_CURVE:
+ *r_is_point_domain = false;
+ return &cache.curves_cache.proc_attributes_tex[request_i];
+ default:
+ BLI_assert_unreachable();
+ return nullptr;
+ }
+}
+
+void DRW_curves_batch_cache_create_requested(Object *ob)
{
Curves *curves = static_cast<Curves *>(ob->data);
CurvesBatchCache &cache = curves_batch_cache_get(*curves);
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.cc
index a6ab2176d16..e93b1a66b66 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc
@@ -7,15 +7,19 @@
* \brief Mesh API for render engines
*/
+#include <optional>
+
#include "MEM_guardedalloc.h"
-#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_buffer.h"
#include "BLI_edgehash.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
+#include "BLI_map.hh"
#include "BLI_math_bits.h"
#include "BLI_math_vector.h"
+#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -52,13 +56,17 @@
#include "ED_mesh.h"
#include "ED_uvedit.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_inline.h"
#include "draw_subdivision.h"
#include "draw_cache_impl.h" /* own include */
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
+
+using blender::IndexRange;
+using blender::Map;
+using blender::Span;
/* ---------------------------------------------------------------------- */
/** \name Dependencies between buffer and batch
@@ -69,21 +77,7 @@
#define BUFFER_INDEX(buff_name) ((offsetof(MeshBufferList, buff_name) - offsetof(MeshBufferList, vbo)) / sizeof(void *))
#define BUFFER_LEN (sizeof(MeshBufferList) / sizeof(void *))
-#define _BATCH_FLAG1(b) (1u << MBC_BATCH_INDEX(b))
-#define _BATCH_FLAG2(b1, b2) _BATCH_FLAG1(b1) | _BATCH_FLAG1(b2)
-#define _BATCH_FLAG3(b1, b2, b3) _BATCH_FLAG2(b1, b2) | _BATCH_FLAG1(b3)
-#define _BATCH_FLAG4(b1, b2, b3, b4) _BATCH_FLAG3(b1, b2, b3) | _BATCH_FLAG1(b4)
-#define _BATCH_FLAG5(b1, b2, b3, b4, b5) _BATCH_FLAG4(b1, b2, b3, b4) | _BATCH_FLAG1(b5)
-#define _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) _BATCH_FLAG5(b1, b2, b3, b4, b5) | _BATCH_FLAG1(b6)
-#define _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) _BATCH_FLAG6(b1, b2, b3, b4, b5, b6) | _BATCH_FLAG1(b7)
-#define _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) _BATCH_FLAG7(b1, b2, b3, b4, b5, b6, b7) | _BATCH_FLAG1(b8)
-#define _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) _BATCH_FLAG8(b1, b2, b3, b4, b5, b6, b7, b8) | _BATCH_FLAG1(b9)
-#define _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) _BATCH_FLAG9(b1, b2, b3, b4, b5, b6, b7, b8, b9) | _BATCH_FLAG1(b10)
-#define _BATCH_FLAG18(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18) _BATCH_FLAG10(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10) | _BATCH_FLAG8(b11, b12, b13, b14, b15, b16, b17, b18)
-
-#define BATCH_FLAG(...) VA_NARGS_CALL_OVERLOAD(_BATCH_FLAG, __VA_ARGS__)
-
-#define _BATCH_MAP1(a) g_buffer_deps[BUFFER_INDEX(a)]
+#define _BATCH_MAP1(a) batches_that_use_buffer(BUFFER_INDEX(a))
#define _BATCH_MAP2(a, b) _BATCH_MAP1(a) | _BATCH_MAP1(b)
#define _BATCH_MAP3(a, b, c) _BATCH_MAP2(a, b) | _BATCH_MAP1(c)
#define _BATCH_MAP4(a, b, c, d) _BATCH_MAP3(a, b, c) | _BATCH_MAP1(d)
@@ -96,132 +90,110 @@
#define BATCH_MAP(...) VA_NARGS_CALL_OVERLOAD(_BATCH_MAP, __VA_ARGS__)
-#ifndef NDEBUG
-# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag) \
- g_buffer_deps_d[buffer_index] |= batch_flag; \
- BLI_assert(g_buffer_deps[buffer_index] & batch_flag)
-
-# define _MDEPS_ASSERT2(b, n1) MDEPS_ASSERT_INDEX(BUFFER_INDEX(n1), b)
-# define _MDEPS_ASSERT3(b, n1, n2) _MDEPS_ASSERT2(b, n1); _MDEPS_ASSERT2(b, n2)
-# define _MDEPS_ASSERT4(b, n1, n2, n3) _MDEPS_ASSERT3(b, n1, n2); _MDEPS_ASSERT2(b, n3)
-# define _MDEPS_ASSERT5(b, n1, n2, n3, n4) _MDEPS_ASSERT4(b, n1, n2, n3); _MDEPS_ASSERT2(b, n4)
-# 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__)
-# define MDEPS_ASSERT_MAP_INDEX(buff_index) BLI_assert(g_buffer_deps_d[buff_index] == g_buffer_deps[buff_index])
-# define MDEPS_ASSERT_MAP(buff_name) MDEPS_ASSERT_MAP_INDEX(BUFFER_INDEX(buff_name))
-#else
-# define MDEPS_ASSERT_INDEX(buffer_index, batch_flag)
-# define MDEPS_ASSERT_FLAG(...)
-# define MDEPS_ASSERT(batch_name, ...)
-# define MDEPS_ASSERT_MAP_INDEX(buff_index)
-# define MDEPS_ASSERT_MAP(buff_name)
-#endif
-
/* clang-format on */
#define TRIS_PER_MAT_INDEX BUFFER_LEN
-#define SURFACE_PER_MAT_FLAG (1u << MBC_BATCH_LEN)
-
-static const DRWBatchFlag g_buffer_deps[] = {
- [BUFFER_INDEX(vbo.pos_nor)] = BATCH_FLAG(surface,
- surface_weights,
- edit_triangles,
- edit_vertices,
- edit_edges,
- edit_vnor,
- edit_lnor,
- edit_mesh_analysis,
- edit_selection_verts,
- edit_selection_edges,
- edit_selection_faces,
- all_verts,
- all_edges,
- loose_edges,
- edge_detection,
- wire_edges,
- wire_loops,
- sculpt_overlays) |
- SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.lnor)] = BATCH_FLAG(surface, edit_lnor, wire_loops) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.edge_fac)] = BATCH_FLAG(wire_edges),
- [BUFFER_INDEX(vbo.weights)] = BATCH_FLAG(surface_weights),
- [BUFFER_INDEX(vbo.uv)] = BATCH_FLAG(surface,
- edituv_faces_stretch_area,
- edituv_faces_stretch_angle,
- edituv_faces,
- edituv_edges,
- edituv_verts,
- wire_loops_uvs) |
- SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.tan)] = SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.vcol)] = BATCH_FLAG(surface) | SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.sculpt_data)] = BATCH_FLAG(sculpt_overlays),
- [BUFFER_INDEX(vbo.orco)] = SURFACE_PER_MAT_FLAG,
- [BUFFER_INDEX(vbo.edit_data)] = BATCH_FLAG(edit_triangles, edit_edges, edit_vertices),
- [BUFFER_INDEX(vbo.edituv_data)] = BATCH_FLAG(edituv_faces,
- edituv_faces_stretch_area,
- edituv_faces_stretch_angle,
- edituv_edges,
- edituv_verts),
- [BUFFER_INDEX(vbo.edituv_stretch_area)] = BATCH_FLAG(edituv_faces_stretch_area),
- [BUFFER_INDEX(vbo.edituv_stretch_angle)] = BATCH_FLAG(edituv_faces_stretch_angle),
- [BUFFER_INDEX(vbo.mesh_analysis)] = BATCH_FLAG(edit_mesh_analysis),
- [BUFFER_INDEX(vbo.fdots_pos)] = BATCH_FLAG(edit_fdots, edit_selection_fdots),
- [BUFFER_INDEX(vbo.fdots_nor)] = BATCH_FLAG(edit_fdots),
- [BUFFER_INDEX(vbo.fdots_uv)] = BATCH_FLAG(edituv_fdots),
- [BUFFER_INDEX(vbo.fdots_edituv_data)] = BATCH_FLAG(edituv_fdots),
- [BUFFER_INDEX(vbo.skin_roots)] = BATCH_FLAG(edit_skin_roots),
- [BUFFER_INDEX(vbo.vert_idx)] = BATCH_FLAG(edit_selection_verts),
- [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,
- edit_triangles,
- edit_lnor,
- edit_mesh_analysis,
- edit_selection_faces,
- sculpt_overlays),
- [BUFFER_INDEX(ibo.lines)] = BATCH_FLAG(
- edit_edges, edit_selection_edges, all_edges, wire_edges),
- [BUFFER_INDEX(ibo.lines_loose)] = BATCH_FLAG(loose_edges),
- [BUFFER_INDEX(ibo.points)] = BATCH_FLAG(edit_vnor, edit_vertices, edit_selection_verts),
- [BUFFER_INDEX(ibo.fdots)] = BATCH_FLAG(edit_fdots, edit_selection_fdots),
- [BUFFER_INDEX(ibo.lines_paint_mask)] = BATCH_FLAG(wire_loops),
- [BUFFER_INDEX(ibo.lines_adjacency)] = BATCH_FLAG(edge_detection),
- [BUFFER_INDEX(ibo.edituv_tris)] = BATCH_FLAG(
- edituv_faces, edituv_faces_stretch_area, edituv_faces_stretch_angle),
- [BUFFER_INDEX(ibo.edituv_lines)] = BATCH_FLAG(edituv_edges, wire_loops_uvs),
- [BUFFER_INDEX(ibo.edituv_points)] = BATCH_FLAG(edituv_verts),
- [BUFFER_INDEX(ibo.edituv_fdots)] = BATCH_FLAG(edituv_fdots),
- [TRIS_PER_MAT_INDEX] = SURFACE_PER_MAT_FLAG,
-};
-
-#ifndef NDEBUG
-static DRWBatchFlag g_buffer_deps_d[ARRAY_SIZE(g_buffer_deps)] = {0};
-#endif
+
+static constexpr DRWBatchFlag batches_that_use_buffer(const int buffer_index)
+{
+ switch (buffer_index) {
+ case BUFFER_INDEX(vbo.pos_nor):
+ return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_VERTICES |
+ MBC_EDIT_EDGES | MBC_EDIT_VNOR | MBC_EDIT_LNOR | MBC_EDIT_MESH_ANALYSIS |
+ MBC_EDIT_SELECTION_VERTS | MBC_EDIT_SELECTION_EDGES | MBC_EDIT_SELECTION_FACES |
+ MBC_ALL_VERTS | MBC_ALL_EDGES | MBC_LOOSE_EDGES | MBC_EDGE_DETECTION |
+ MBC_WIRE_EDGES | MBC_WIRE_LOOPS | MBC_SCULPT_OVERLAYS | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.lnor):
+ return MBC_SURFACE | MBC_EDIT_LNOR | MBC_WIRE_LOOPS | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.edge_fac):
+ return MBC_WIRE_EDGES;
+ case BUFFER_INDEX(vbo.weights):
+ return MBC_SURFACE_WEIGHTS;
+ case BUFFER_INDEX(vbo.uv):
+ return MBC_SURFACE | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE |
+ MBC_EDITUV_FACES | MBC_EDITUV_EDGES | MBC_EDITUV_VERTS | MBC_WIRE_LOOPS_UVS |
+ MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.tan):
+ return MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.vcol):
+ return MBC_SURFACE | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.sculpt_data):
+ return MBC_SCULPT_OVERLAYS;
+ case BUFFER_INDEX(vbo.orco):
+ return MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(vbo.edit_data):
+ return MBC_EDIT_TRIANGLES | MBC_EDIT_EDGES | MBC_EDIT_VERTICES;
+ case BUFFER_INDEX(vbo.edituv_data):
+ return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE |
+ MBC_EDITUV_EDGES | MBC_EDITUV_VERTS;
+ case BUFFER_INDEX(vbo.edituv_stretch_area):
+ return MBC_EDITUV_FACES_STRETCH_AREA;
+ case BUFFER_INDEX(vbo.edituv_stretch_angle):
+ return MBC_EDITUV_FACES_STRETCH_ANGLE;
+ case BUFFER_INDEX(vbo.mesh_analysis):
+ return MBC_EDIT_MESH_ANALYSIS;
+ case BUFFER_INDEX(vbo.fdots_pos):
+ return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_nor):
+ return MBC_EDIT_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_uv):
+ return MBC_EDITUV_FACEDOTS;
+ case BUFFER_INDEX(vbo.fdots_edituv_data):
+ return MBC_EDITUV_FACEDOTS;
+ case BUFFER_INDEX(vbo.skin_roots):
+ return MBC_SKIN_ROOTS;
+ case BUFFER_INDEX(vbo.vert_idx):
+ return MBC_EDIT_SELECTION_VERTS;
+ case BUFFER_INDEX(vbo.edge_idx):
+ return MBC_EDIT_SELECTION_EDGES;
+ case BUFFER_INDEX(vbo.poly_idx):
+ return MBC_EDIT_SELECTION_FACES;
+ case BUFFER_INDEX(vbo.fdot_idx):
+ return MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(vbo.attr[0]):
+ case BUFFER_INDEX(vbo.attr[1]):
+ case BUFFER_INDEX(vbo.attr[2]):
+ case BUFFER_INDEX(vbo.attr[3]):
+ case BUFFER_INDEX(vbo.attr[4]):
+ case BUFFER_INDEX(vbo.attr[5]):
+ case BUFFER_INDEX(vbo.attr[6]):
+ case BUFFER_INDEX(vbo.attr[7]):
+ case BUFFER_INDEX(vbo.attr[8]):
+ case BUFFER_INDEX(vbo.attr[9]):
+ case BUFFER_INDEX(vbo.attr[10]):
+ case BUFFER_INDEX(vbo.attr[11]):
+ case BUFFER_INDEX(vbo.attr[12]):
+ case BUFFER_INDEX(vbo.attr[13]):
+ case BUFFER_INDEX(vbo.attr[14]):
+ return MBC_SURFACE | MBC_SURFACE_PER_MAT;
+ case BUFFER_INDEX(ibo.tris):
+ return MBC_SURFACE | MBC_SURFACE_WEIGHTS | MBC_EDIT_TRIANGLES | MBC_EDIT_LNOR |
+ MBC_EDIT_MESH_ANALYSIS | MBC_EDIT_SELECTION_FACES | MBC_SCULPT_OVERLAYS;
+ case BUFFER_INDEX(ibo.lines):
+ return MBC_EDIT_EDGES | MBC_EDIT_SELECTION_EDGES | MBC_ALL_EDGES | MBC_WIRE_EDGES;
+ case BUFFER_INDEX(ibo.lines_loose):
+ return MBC_LOOSE_EDGES;
+ case BUFFER_INDEX(ibo.points):
+ return MBC_EDIT_VNOR | MBC_EDIT_VERTICES | MBC_EDIT_SELECTION_VERTS;
+ case BUFFER_INDEX(ibo.fdots):
+ return MBC_EDIT_FACEDOTS | MBC_EDIT_SELECTION_FACEDOTS;
+ case BUFFER_INDEX(ibo.lines_paint_mask):
+ return MBC_WIRE_LOOPS;
+ case BUFFER_INDEX(ibo.lines_adjacency):
+ return MBC_EDGE_DETECTION;
+ case BUFFER_INDEX(ibo.edituv_tris):
+ return MBC_EDITUV_FACES | MBC_EDITUV_FACES_STRETCH_AREA | MBC_EDITUV_FACES_STRETCH_ANGLE;
+ case BUFFER_INDEX(ibo.edituv_lines):
+ return MBC_EDITUV_EDGES | MBC_WIRE_LOOPS_UVS;
+ case BUFFER_INDEX(ibo.edituv_points):
+ return MBC_EDITUV_VERTS;
+ case BUFFER_INDEX(ibo.edituv_fdots):
+ return MBC_EDITUV_FACEDOTS;
+ case TRIS_PER_MAT_INDEX:
+ return MBC_SURFACE_PER_MAT;
+ }
+ return (DRWBatchFlag)0;
+}
static void mesh_batch_cache_discard_surface_batches(MeshBatchCache *cache);
static void mesh_batch_cache_clear(Mesh *me);
@@ -229,14 +201,14 @@ static void mesh_batch_cache_clear(Mesh *me);
static void mesh_batch_cache_discard_batch(MeshBatchCache *cache, const DRWBatchFlag batch_map)
{
for (int i = 0; i < MBC_BATCH_LEN; i++) {
- DRWBatchFlag batch_requested = (1u << i);
+ DRWBatchFlag batch_requested = (DRWBatchFlag)(1u << i);
if (batch_map & batch_requested) {
GPU_BATCH_DISCARD_SAFE(((GPUBatch **)&cache->batch)[i]);
cache->batch_ready &= ~batch_requested;
}
}
- if (batch_map & SURFACE_PER_MAT_FLAG) {
+ if (batch_map & MBC_SURFACE_PER_MAT) {
mesh_batch_cache_discard_surface_batches(cache);
}
}
@@ -266,9 +238,9 @@ BLI_INLINE void mesh_cd_layers_type_clear(DRW_MeshCDMask *a)
BLI_INLINE const Mesh *editmesh_final_or_this(const Object *object, const Mesh *me)
{
- if (me->edit_mesh != NULL) {
+ if (me->edit_mesh != nullptr) {
Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object);
- if (editmesh_eval_final != NULL) {
+ if (editmesh_eval_final != nullptr) {
return editmesh_eval_final;
}
}
@@ -374,14 +346,15 @@ static void mesh_cd_calc_active_mloopcol_layer(const Object *object,
DRW_MeshCDMask *cd_used)
{
const Mesh *me_final = editmesh_final_or_this(object, me);
- Mesh me_query = {0};
+ Mesh me_query = blender::dna::shallow_zero_initialize();
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
- BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id);
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me_query.id);
int layer_i = BKE_id_attribute_to_index(
&me_query.id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -395,8 +368,8 @@ static uint mesh_cd_calc_gpu_layers_vcol_used(const Mesh *me_query,
const CustomData *cd_ldata,
const char name[])
{
- CustomDataLayer *layer = NULL;
- AttributeDomain domain;
+ const CustomDataLayer *layer = nullptr;
+ eAttrDomain domain;
if (name[0]) {
int layer_i = 0;
@@ -451,10 +424,10 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
/* Create a mesh with final customdata domains
* we can query with attribute API. */
- Mesh me_query = {0};
+ Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
- ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, NULL, &me_query.id);
+ ID_ME, cd_vdata, cd_edata, cd_ldata, cd_pdata, nullptr, &me_query.id);
/* See: DM_vertex_attributes_from_gpu for similar logic */
DRW_MeshCDMask cd_used;
@@ -466,10 +439,9 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
ListBase gpu_attrs = GPU_material_attributes(gpumat);
LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
const char *name = gpu_attr->name;
- int type = gpu_attr->type;
+ eCustomDataType type = static_cast<eCustomDataType>(gpu_attr->type);
int layer = -1;
- /* ATTR_DOMAIN_NUM is standard for "invalid value". */
- AttributeDomain domain = ATTR_DOMAIN_NUM;
+ std::optional<eAttrDomain> domain;
if (type == CD_AUTO_FROM_NAME) {
/* We need to deduce what exact layer is used.
@@ -535,7 +507,6 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
else {
layer = -1;
- domain = ATTR_DOMAIN_NUM;
}
}
@@ -602,8 +573,8 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
break;
}
- if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_attributes_add_request(attributes, type, layer, domain);
+ if (layer != -1 && domain.has_value()) {
+ drw_attributes_add_request(attributes, name, type, layer, *domain);
}
break;
}
@@ -613,11 +584,13 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
case CD_PROP_INT32:
case CD_PROP_FLOAT:
case CD_PROP_FLOAT2: {
- if (layer != -1 && domain != ATTR_DOMAIN_NUM) {
- drw_attributes_add_request(attributes, type, layer, domain);
+ if (layer != -1 && domain.has_value()) {
+ drw_attributes_add_request(attributes, name, type, layer, *domain);
}
break;
}
+ default:
+ break;
}
}
}
@@ -654,13 +627,14 @@ static void drw_mesh_weight_state_copy(struct DRW_MeshWeightState *wstate_dst,
memcpy(wstate_dst, wstate_src, sizeof(*wstate_dst));
if (wstate_src->defgroup_sel) {
- wstate_dst->defgroup_sel = MEM_dupallocN(wstate_src->defgroup_sel);
+ wstate_dst->defgroup_sel = static_cast<bool *>(MEM_dupallocN(wstate_src->defgroup_sel));
}
if (wstate_src->defgroup_locked) {
- wstate_dst->defgroup_locked = MEM_dupallocN(wstate_src->defgroup_locked);
+ wstate_dst->defgroup_locked = static_cast<bool *>(MEM_dupallocN(wstate_src->defgroup_locked));
}
if (wstate_src->defgroup_unlocked) {
- wstate_dst->defgroup_unlocked = MEM_dupallocN(wstate_src->defgroup_unlocked);
+ wstate_dst->defgroup_unlocked = static_cast<bool *>(
+ MEM_dupallocN(wstate_src->defgroup_unlocked));
}
}
@@ -764,14 +738,15 @@ BLI_INLINE void mesh_batch_cache_add_request(MeshBatchCache *cache, DRWBatchFlag
static bool mesh_batch_cache_valid(Object *object, Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return false;
}
if (object->sculpt && object->sculpt->pbvh) {
- if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh)) {
+ if (cache->pbvh_is_drawing != BKE_pbvh_is_drawing(object->sculpt->pbvh) ||
+ BKE_pbvh_draw_cache_invalid(object->sculpt->pbvh)) {
return false;
}
@@ -781,7 +756,7 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
}
}
- if (cache->is_editmode != (me->edit_mesh != NULL)) {
+ if (cache->is_editmode != (me->edit_mesh != nullptr)) {
return false;
}
@@ -798,16 +773,17 @@ static bool mesh_batch_cache_valid(Object *object, Mesh *me)
static void mesh_batch_cache_init(Object *object, Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
if (!cache) {
- cache = me->runtime.batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ me->runtime.batch_cache = MEM_cnew<MeshBatchCache>(__func__);
+ cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
}
else {
memset(cache, 0, sizeof(*cache));
}
- cache->is_editmode = me->edit_mesh != NULL;
+ cache->is_editmode = me->edit_mesh != nullptr;
if (object->sculpt && object->sculpt->pbvh) {
cache->pbvh_is_drawing = BKE_pbvh_is_drawing(object->sculpt->pbvh);
@@ -821,12 +797,14 @@ static void mesh_batch_cache_init(Object *object, Mesh *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__);
+ cache->surface_per_mat = static_cast<GPUBatch **>(
+ MEM_callocN(sizeof(*cache->surface_per_mat) * cache->mat_len, __func__));
+ cache->tris_per_mat = static_cast<GPUIndexBuf **>(
+ MEM_callocN(sizeof(*cache->tris_per_mat) * cache->mat_len, __func__));
cache->is_dirty = false;
- cache->batch_ready = 0;
- cache->batch_requested = 0;
+ cache->batch_ready = (DRWBatchFlag)0;
+ cache->batch_requested = (DRWBatchFlag)0;
drw_mesh_weight_state_clear(&cache->weight_state);
}
@@ -841,7 +819,7 @@ void DRW_mesh_batch_cache_validate(Object *object, Mesh *me)
static MeshBatchCache *mesh_batch_cache_get(Mesh *me)
{
- return me->runtime.batch_cache;
+ return static_cast<MeshBatchCache *>(me->runtime.batch_cache);
}
static void mesh_batch_cache_check_vertex_group(MeshBatchCache *cache,
@@ -950,8 +928,8 @@ static void mesh_batch_cache_discard_uvedit_select(MeshBatchCache *cache)
void DRW_mesh_batch_cache_dirty_tag(Mesh *me, eMeshBatchDirtyMode mode)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
- if (cache == NULL) {
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
+ if (cache == nullptr) {
return;
}
DRWBatchFlag batch_map;
@@ -1032,13 +1010,13 @@ 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;
+ cache->subdiv_cache = nullptr;
}
}
static void mesh_batch_cache_clear(Mesh *me)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
if (!cache) {
return;
}
@@ -1061,7 +1039,7 @@ static void mesh_batch_cache_clear(Mesh *me)
MEM_SAFE_FREE(cache->surface_per_mat);
cache->mat_len = 0;
- cache->batch_ready = 0;
+ cache->batch_ready = (DRWBatchFlag)0;
drw_mesh_weight_state_clear(&cache->weight_state);
mesh_batch_cache_free_subdiv_cache(cache);
@@ -1110,11 +1088,12 @@ static void sculpt_request_active_vcol(MeshBatchCache *cache, Object *object, Me
const CustomData *cd_vdata = mesh_cd_vdata_get_from_mesh(me_final);
const CustomData *cd_ldata = mesh_cd_ldata_get_from_mesh(me_final);
- Mesh me_query = {0};
- BKE_id_attribute_copy_domains_temp(ID_ME, cd_vdata, NULL, cd_ldata, NULL, NULL, &me_query.id);
+ Mesh me_query = blender::dna::shallow_zero_initialize();
+ BKE_id_attribute_copy_domains_temp(
+ ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render = BKE_id_attributes_render_color_get(&me_query.id);
int active_i = BKE_id_attribute_to_index(
&me_query.id, active, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -1157,7 +1136,7 @@ GPUBatch *DRW_mesh_batch_cache_get_loose_edges(Mesh *me)
MeshBatchCache *cache = mesh_batch_cache_get(me);
mesh_batch_cache_add_request(cache, MBC_LOOSE_EDGES);
if (cache->no_loose_wire) {
- return NULL;
+ return nullptr;
}
return DRW_batch_request(&cache->batch.loose_edges);
@@ -1276,7 +1255,7 @@ GPUVertBuf *DRW_mesh_batch_cache_pos_vertbuf_get(Mesh *me)
/* Request surface to trigger the vbo filling. Otherwise it may do nothing. */
mesh_batch_cache_request_surface_batches(cache);
- DRW_vbo_request(NULL, &cache->final.buff.vbo.pos_nor);
+ DRW_vbo_request(nullptr, &cache->final.buff.vbo.pos_nor);
return cache->final.buff.vbo.pos_nor;
}
@@ -1398,10 +1377,10 @@ GPUBatch *DRW_mesh_batch_cache_get_edituv_faces_stretch_area(Object *object,
edituv_request_active_uv(cache, object, me);
mesh_batch_cache_add_request(cache, MBC_EDITUV_FACES_STRETCH_AREA);
- if (tot_area != NULL) {
+ if (tot_area != nullptr) {
*tot_area = &cache->tot_area;
}
- if (tot_uv_area != NULL) {
+ if (tot_uv_area != nullptr) {
*tot_uv_area = &cache->tot_uv_area;
}
return DRW_batch_request(&cache->batch.edituv_faces_stretch_area);
@@ -1471,9 +1450,9 @@ GPUBatch *DRW_mesh_batch_cache_get_surface_edges(Object *object, Mesh *me)
void DRW_mesh_batch_cache_free_old(Mesh *me, int ctime)
{
- MeshBatchCache *cache = me->runtime.batch_cache;
+ MeshBatchCache *cache = static_cast<MeshBatchCache *>(me->runtime.batch_cache);
- if (cache == NULL) {
+ if (cache == nullptr) {
return;
}
@@ -1513,7 +1492,7 @@ static void drw_mesh_batch_cache_check_available(struct TaskGraph *task_graph, M
* happening in release builds). */
BLI_task_graph_work_and_wait(task_graph);
for (int i = 0; i < MBC_BATCH_LEN; i++) {
- BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], 0));
+ BLI_assert(!DRW_batch_requested(((GPUBatch **)&cache->batch)[i], (GPUPrimType)0));
}
for (int i = 0; i < MBC_VBO_LEN; i++) {
BLI_assert(!DRW_vbo_requested(((GPUVertBuf **)&cache->final.buff.vbo)[i]));
@@ -1544,7 +1523,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
const bool use_hide)
{
BLI_assert(task_graph);
- const ToolSettings *ts = NULL;
+ const ToolSettings *ts = nullptr;
if (scene) {
ts = scene->toolsettings;
}
@@ -1559,24 +1538,43 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
return;
}
+#ifdef DEBUG
+ /* Map the index of a buffer to a flag containing all batches that use it. */
+ Map<int, DRWBatchFlag> batches_that_use_buffer_local;
+
+ auto assert_deps_valid = [&](DRWBatchFlag batch_flag, Span<int> used_buffer_indices) {
+ for (const int buffer_index : used_buffer_indices) {
+ batches_that_use_buffer_local.add_or_modify(
+ buffer_index,
+ [&](DRWBatchFlag *value) { *value = batch_flag; },
+ [&](DRWBatchFlag *value) { *value |= batch_flag; });
+ BLI_assert(batches_that_use_buffer(buffer_index) & batch_flag);
+ }
+ };
+#else
+ auto assert_deps_valid = [&](DRWBatchFlag UNUSED(batch_flag),
+ Span<int> UNUSED(used_buffer_indices)) {};
+
+#endif
+
/* Sanity check. */
- if ((me->edit_mesh != NULL) && (ob->mode & OB_MODE_EDIT)) {
- BLI_assert(BKE_object_get_editmesh_eval_final(ob) != NULL);
+ if ((me->edit_mesh != nullptr) && (ob->mode & OB_MODE_EDIT)) {
+ BLI_assert(BKE_object_get_editmesh_eval_final(ob) != nullptr);
}
- const bool is_editmode = (me->edit_mesh != NULL) &&
- (BKE_object_get_editmesh_eval_final(ob) != NULL) &&
+ const bool is_editmode = (me->edit_mesh != nullptr) &&
+ (BKE_object_get_editmesh_eval_final(ob) != nullptr) &&
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);
DRWBatchFlag batch_requested = cache->batch_requested;
- cache->batch_requested = 0;
+ cache->batch_requested = (DRWBatchFlag)0;
if (batch_requested & MBC_SURFACE_WEIGHTS) {
/* Check vertex weights. */
- if ((cache->batch.surface_weights != NULL) && (ts != NULL)) {
+ if ((cache->batch.surface_weights != nullptr) && (ts != nullptr)) {
struct DRW_MeshWeightState wstate;
BLI_assert(ob->type == OB_MESH);
drw_mesh_weight_state_extract(ob, me, ts, is_paint_mode, &wstate);
@@ -1593,7 +1591,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
if (cache->cd_needed.orco != 0) {
/* Orco is always extracted from final mesh. */
Mesh *me_final = (me->edit_mesh) ? BKE_object_get_editmesh_eval_final(ob) : me;
- if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == NULL) {
+ if (CustomData_get_layer(&me_final->vdata, CD_ORCO) == nullptr) {
/* Skip orco calculation */
cache->cd_needed.orco = 0;
}
@@ -1692,7 +1690,7 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
* per redraw when smooth shading is enabled. */
const bool do_update_sculpt_normals = ob->sculpt && ob->sculpt->pbvh;
if (do_update_sculpt_normals) {
- Mesh *mesh = ob->data;
+ Mesh *mesh = static_cast<Mesh *>(ob->data);
BKE_pbvh_update_normals(ob->sculpt->pbvh, mesh->runtime.subdiv_ccg);
}
@@ -1712,27 +1710,15 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
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,
- 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]);
+ assert_deps_valid(
+ MBC_SURFACE,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor),
+ BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.attr[0]),
+ BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]), BUFFER_INDEX(vbo.attr[3]),
+ BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]), BUFFER_INDEX(vbo.attr[6]),
+ BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]), BUFFER_INDEX(vbo.attr[9]),
+ BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]), BUFFER_INDEX(vbo.attr[12]),
+ BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(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. */
@@ -1746,52 +1732,61 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
}
drw_add_attributes_vbo(cache->batch.surface, mbuflist, &cache->attr_used);
}
- MDEPS_ASSERT(all_verts, vbo.pos_nor);
+ assert_deps_valid(MBC_ALL_VERTS, {BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.all_verts, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.all_verts, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(sculpt_overlays, ibo.tris, vbo.pos_nor, vbo.sculpt_data);
+ assert_deps_valid(
+ MBC_SCULPT_OVERLAYS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.sculpt_data)});
if (DRW_batch_requested(cache->batch.sculpt_overlays, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.sculpt_overlays, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.sculpt_overlays, &mbuflist->vbo.sculpt_data);
}
- MDEPS_ASSERT(all_edges, ibo.lines, vbo.pos_nor);
+ assert_deps_valid(MBC_ALL_EDGES, {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.all_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.all_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.all_edges, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(loose_edges, ibo.lines_loose, vbo.pos_nor);
+ assert_deps_valid(MBC_LOOSE_EDGES, {BUFFER_INDEX(ibo.lines_loose), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.loose_edges, GPU_PRIM_LINES)) {
- DRW_ibo_request(NULL, &mbuflist->ibo.lines);
+ DRW_ibo_request(nullptr, &mbuflist->ibo.lines);
DRW_ibo_request(cache->batch.loose_edges, &mbuflist->ibo.lines_loose);
DRW_vbo_request(cache->batch.loose_edges, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(edge_detection, ibo.lines_adjacency, vbo.pos_nor);
+ assert_deps_valid(MBC_EDGE_DETECTION,
+ {BUFFER_INDEX(ibo.lines_adjacency), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.edge_detection, GPU_PRIM_LINES_ADJ)) {
DRW_ibo_request(cache->batch.edge_detection, &mbuflist->ibo.lines_adjacency);
DRW_vbo_request(cache->batch.edge_detection, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(surface_weights, ibo.tris, vbo.pos_nor, vbo.weights);
+ assert_deps_valid(
+ MBC_SURFACE_WEIGHTS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.weights)});
if (DRW_batch_requested(cache->batch.surface_weights, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.surface_weights, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.surface_weights, &mbuflist->vbo.weights);
}
- MDEPS_ASSERT(wire_loops, ibo.lines_paint_mask, vbo.lnor, vbo.pos_nor);
+ assert_deps_valid(
+ MBC_WIRE_LOOPS,
+ {BUFFER_INDEX(ibo.lines_paint_mask), BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.wire_loops, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops, &mbuflist->ibo.lines_paint_mask);
/* Order matters. First ones override latest VBO's attributes. */
DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.lnor);
DRW_vbo_request(cache->batch.wire_loops, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(wire_edges, ibo.lines, vbo.pos_nor, vbo.edge_fac);
+ assert_deps_valid(
+ MBC_WIRE_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_fac)});
if (DRW_batch_requested(cache->batch.wire_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.wire_edges, &mbuflist->vbo.edge_fac);
}
- MDEPS_ASSERT(wire_loops_uvs, ibo.edituv_lines, vbo.uv);
+ assert_deps_valid(MBC_WIRE_LOOPS_UVS, {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv)});
if (DRW_batch_requested(cache->batch.wire_loops_uvs, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.wire_loops_uvs, &mbuflist->ibo.edituv_lines);
/* For paint overlay. Active layer should have been queried. */
@@ -1799,7 +1794,9 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
DRW_vbo_request(cache->batch.wire_loops_uvs, &mbuflist->vbo.uv);
}
}
- MDEPS_ASSERT(edit_mesh_analysis, ibo.tris, vbo.pos_nor, vbo.mesh_analysis);
+ assert_deps_valid(
+ MBC_EDIT_MESH_ANALYSIS,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.mesh_analysis)});
if (DRW_batch_requested(cache->batch.edit_mesh_analysis, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_mesh_analysis, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_mesh_analysis, &mbuflist->vbo.pos_nor);
@@ -1807,29 +1804,16 @@ 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,
- 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);
+ assert_deps_valid(
+ MBC_SURFACE_PER_MAT,
+ {BUFFER_INDEX(vbo.lnor), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.tan), BUFFER_INDEX(vbo.vcol), BUFFER_INDEX(vbo.orco),
+ BUFFER_INDEX(vbo.attr[0]), BUFFER_INDEX(vbo.attr[1]), BUFFER_INDEX(vbo.attr[2]),
+ BUFFER_INDEX(vbo.attr[3]), BUFFER_INDEX(vbo.attr[4]), BUFFER_INDEX(vbo.attr[5]),
+ BUFFER_INDEX(vbo.attr[6]), BUFFER_INDEX(vbo.attr[7]), BUFFER_INDEX(vbo.attr[8]),
+ BUFFER_INDEX(vbo.attr[9]), BUFFER_INDEX(vbo.attr[10]), BUFFER_INDEX(vbo.attr[11]),
+ BUFFER_INDEX(vbo.attr[12]), BUFFER_INDEX(vbo.attr[13]), BUFFER_INDEX(vbo.attr[14])});
+ assert_deps_valid(MBC_SURFACE_PER_MAT, {TRIS_PER_MAT_INDEX});
for (int i = 0; i < cache->mat_len; i++) {
if (DRW_batch_requested(cache->surface_per_mat[i], GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->surface_per_mat[i], &cache->tris_per_mat[i]);
@@ -1855,66 +1839,83 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mbuflist = (do_cage) ? &cache->cage.buff : &cache->final.buff;
/* Edit Mesh */
- MDEPS_ASSERT(edit_triangles, ibo.tris, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_TRIANGLES,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_triangles, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_triangles, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_triangles, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_vertices, ibo.points, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_VERTICES,
+ {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_vertices, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_vertices, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_vertices, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_edges, ibo.lines, vbo.pos_nor, vbo.edit_data);
+ assert_deps_valid(
+ MBC_EDIT_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edit_data)});
if (DRW_batch_requested(cache->batch.edit_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edit_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_edges, &mbuflist->vbo.edit_data);
}
- MDEPS_ASSERT(edit_vnor, ibo.points, vbo.pos_nor);
+ assert_deps_valid(MBC_EDIT_VNOR, {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor)});
if (DRW_batch_requested(cache->batch.edit_vnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_vnor, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_vnor, &mbuflist->vbo.pos_nor);
}
- MDEPS_ASSERT(edit_lnor, ibo.tris, vbo.pos_nor, vbo.lnor);
+ assert_deps_valid(MBC_EDIT_LNOR,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.lnor)});
if (DRW_batch_requested(cache->batch.edit_lnor, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_lnor, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_lnor, &mbuflist->vbo.lnor);
}
- MDEPS_ASSERT(edit_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdots_nor);
+ assert_deps_valid(
+ MBC_EDIT_FACEDOTS,
+ {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdots_nor)});
if (DRW_batch_requested(cache->batch.edit_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_fdots, &mbuflist->ibo.fdots);
DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_pos);
DRW_vbo_request(cache->batch.edit_fdots, &mbuflist->vbo.fdots_nor);
}
- MDEPS_ASSERT(edit_skin_roots, vbo.skin_roots);
+ assert_deps_valid(MBC_SKIN_ROOTS, {BUFFER_INDEX(vbo.skin_roots)});
if (DRW_batch_requested(cache->batch.edit_skin_roots, GPU_PRIM_POINTS)) {
DRW_vbo_request(cache->batch.edit_skin_roots, &mbuflist->vbo.skin_roots);
}
/* Selection */
- MDEPS_ASSERT(edit_selection_verts, ibo.points, vbo.pos_nor, vbo.vert_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_VERTS,
+ {BUFFER_INDEX(ibo.points), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.vert_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_selection_verts, &mbuflist->ibo.points);
DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_verts, &mbuflist->vbo.vert_idx);
}
- MDEPS_ASSERT(edit_selection_edges, ibo.lines, vbo.pos_nor, vbo.edge_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_EDGES,
+ {BUFFER_INDEX(ibo.lines), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.edge_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edit_selection_edges, &mbuflist->ibo.lines);
DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_edges, &mbuflist->vbo.edge_idx);
}
- MDEPS_ASSERT(edit_selection_faces, ibo.tris, vbo.pos_nor, vbo.poly_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_FACES,
+ {BUFFER_INDEX(ibo.tris), BUFFER_INDEX(vbo.pos_nor), BUFFER_INDEX(vbo.poly_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edit_selection_faces, &mbuflist->ibo.tris);
DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.pos_nor);
DRW_vbo_request(cache->batch.edit_selection_faces, &mbuflist->vbo.poly_idx);
}
- MDEPS_ASSERT(edit_selection_fdots, ibo.fdots, vbo.fdots_pos, vbo.fdot_idx);
+ assert_deps_valid(
+ MBC_EDIT_SELECTION_FACEDOTS,
+ {BUFFER_INDEX(ibo.fdots), BUFFER_INDEX(vbo.fdots_pos), BUFFER_INDEX(vbo.fdot_idx)});
if (DRW_batch_requested(cache->batch.edit_selection_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edit_selection_fdots, &mbuflist->ibo.fdots);
DRW_vbo_request(cache->batch.edit_selection_fdots, &mbuflist->vbo.fdots_pos);
@@ -1929,131 +1930,145 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mbuflist = (do_uvcage) ? &cache->uv_cage.buff : &cache->final.buff;
/* Edit UV */
- MDEPS_ASSERT(edituv_faces, ibo.edituv_tris, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_FACES,
+ {BUFFER_INDEX(ibo.edituv_tris), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_faces, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_faces_stretch_area,
- ibo.edituv_tris,
- vbo.uv,
- vbo.edituv_data,
- vbo.edituv_stretch_area);
+ assert_deps_valid(MBC_EDITUV_FACES_STRETCH_AREA,
+ {BUFFER_INDEX(ibo.edituv_tris),
+ BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.edituv_data),
+ BUFFER_INDEX(vbo.edituv_stretch_area)});
if (DRW_batch_requested(cache->batch.edituv_faces_stretch_area, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_data);
DRW_vbo_request(cache->batch.edituv_faces_stretch_area, &mbuflist->vbo.edituv_stretch_area);
}
- MDEPS_ASSERT(edituv_faces_stretch_angle,
- ibo.edituv_tris,
- vbo.uv,
- vbo.edituv_data,
- vbo.edituv_stretch_angle);
+ assert_deps_valid(MBC_EDITUV_FACES_STRETCH_ANGLE,
+ {BUFFER_INDEX(ibo.edituv_tris),
+ BUFFER_INDEX(vbo.uv),
+ BUFFER_INDEX(vbo.edituv_data),
+ BUFFER_INDEX(vbo.edituv_stretch_angle)});
if (DRW_batch_requested(cache->batch.edituv_faces_stretch_angle, GPU_PRIM_TRIS)) {
DRW_ibo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->ibo.edituv_tris);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_data);
DRW_vbo_request(cache->batch.edituv_faces_stretch_angle, &mbuflist->vbo.edituv_stretch_angle);
}
- MDEPS_ASSERT(edituv_edges, ibo.edituv_lines, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_EDGES,
+ {BUFFER_INDEX(ibo.edituv_lines), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_edges, GPU_PRIM_LINES)) {
DRW_ibo_request(cache->batch.edituv_edges, &mbuflist->ibo.edituv_lines);
DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_edges, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_verts, ibo.edituv_points, vbo.uv, vbo.edituv_data);
+ assert_deps_valid(
+ MBC_EDITUV_VERTS,
+ {BUFFER_INDEX(ibo.edituv_points), BUFFER_INDEX(vbo.uv), BUFFER_INDEX(vbo.edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_verts, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edituv_verts, &mbuflist->ibo.edituv_points);
DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.uv);
DRW_vbo_request(cache->batch.edituv_verts, &mbuflist->vbo.edituv_data);
}
- MDEPS_ASSERT(edituv_fdots, ibo.edituv_fdots, vbo.fdots_uv, vbo.fdots_edituv_data);
+ assert_deps_valid(MBC_EDITUV_FACEDOTS,
+ {BUFFER_INDEX(ibo.edituv_fdots),
+ BUFFER_INDEX(vbo.fdots_uv),
+ BUFFER_INDEX(vbo.fdots_edituv_data)});
if (DRW_batch_requested(cache->batch.edituv_fdots, GPU_PRIM_POINTS)) {
DRW_ibo_request(cache->batch.edituv_fdots, &mbuflist->ibo.edituv_fdots);
DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_uv);
DRW_vbo_request(cache->batch.edituv_fdots, &mbuflist->vbo.fdots_edituv_data);
}
- MDEPS_ASSERT_MAP(vbo.lnor);
- MDEPS_ASSERT_MAP(vbo.pos_nor);
- MDEPS_ASSERT_MAP(vbo.uv);
- MDEPS_ASSERT_MAP(vbo.vcol);
- MDEPS_ASSERT_MAP(vbo.sculpt_data);
- MDEPS_ASSERT_MAP(vbo.weights);
- MDEPS_ASSERT_MAP(vbo.edge_fac);
- MDEPS_ASSERT_MAP(vbo.mesh_analysis);
- MDEPS_ASSERT_MAP(vbo.tan);
- MDEPS_ASSERT_MAP(vbo.orco);
- MDEPS_ASSERT_MAP(vbo.edit_data);
- MDEPS_ASSERT_MAP(vbo.fdots_pos);
- MDEPS_ASSERT_MAP(vbo.fdots_nor);
- MDEPS_ASSERT_MAP(vbo.skin_roots);
- MDEPS_ASSERT_MAP(vbo.vert_idx);
- MDEPS_ASSERT_MAP(vbo.edge_idx);
- MDEPS_ASSERT_MAP(vbo.poly_idx);
- MDEPS_ASSERT_MAP(vbo.fdot_idx);
- MDEPS_ASSERT_MAP(vbo.edituv_data);
- MDEPS_ASSERT_MAP(vbo.edituv_stretch_area);
- 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);
- MDEPS_ASSERT_MAP(ibo.lines_loose);
- MDEPS_ASSERT_MAP(ibo.lines_adjacency);
- MDEPS_ASSERT_MAP(ibo.lines_paint_mask);
- MDEPS_ASSERT_MAP(ibo.points);
- MDEPS_ASSERT_MAP(ibo.fdots);
- MDEPS_ASSERT_MAP(ibo.edituv_tris);
- MDEPS_ASSERT_MAP(ibo.edituv_lines);
- MDEPS_ASSERT_MAP(ibo.edituv_points);
- MDEPS_ASSERT_MAP(ibo.edituv_fdots);
-
- MDEPS_ASSERT_MAP_INDEX(TRIS_PER_MAT_INDEX);
+#ifdef DEBUG
+ auto assert_final_deps_valid = [&](const int buffer_index) {
+ BLI_assert(batches_that_use_buffer(buffer_index) ==
+ batches_that_use_buffer_local.lookup(buffer_index));
+ };
+ assert_final_deps_valid(BUFFER_INDEX(vbo.lnor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.pos_nor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.uv));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.vcol));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.sculpt_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.weights));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edge_fac));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.mesh_analysis));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.tan));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.orco));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edit_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_pos));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_nor));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.skin_roots));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.vert_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edge_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.poly_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdot_idx));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_data));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_area));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.edituv_stretch_angle));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_uv));
+ assert_final_deps_valid(BUFFER_INDEX(vbo.fdots_edituv_data));
+ for (const int i : IndexRange(GPU_MAX_ATTR)) {
+ assert_final_deps_valid(BUFFER_INDEX(vbo.attr[i]));
+ }
+
+ assert_final_deps_valid(BUFFER_INDEX(ibo.tris));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_loose));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_adjacency));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.lines_paint_mask));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.points));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.fdots));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_tris));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_lines));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_points));
+ assert_final_deps_valid(BUFFER_INDEX(ibo.edituv_fdots));
+
+ assert_final_deps_valid(TRIS_PER_MAT_INDEX);
+#endif
if (do_uvcage) {
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->uv_cage,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- false,
- true,
- scene,
- ts,
- true);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->uv_cage,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ false,
+ true,
+ scene,
+ ts,
+ true);
}
if (do_cage) {
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->cage,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- false,
- false,
- scene,
- ts,
- true);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->cage,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ false,
+ false,
+ scene,
+ ts,
+ true);
}
if (do_subdivision) {
- DRW_create_subdivision(scene,
- ob,
+ DRW_create_subdivision(ob,
me,
cache,
&cache->final,
@@ -2072,20 +2087,20 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
mesh_batch_cache_free_subdiv_cache(cache);
}
- mesh_buffer_cache_create_requested(task_graph,
- cache,
- &cache->final,
- ob,
- me,
- is_editmode,
- is_paint_mode,
- is_mode_active,
- ob->obmat,
- true,
- false,
- scene,
- ts,
- use_hide);
+ blender::draw::mesh_buffer_cache_create_requested(task_graph,
+ cache,
+ &cache->final,
+ ob,
+ me,
+ is_editmode,
+ is_paint_mode,
+ is_mode_active,
+ ob->obmat,
+ true,
+ false,
+ scene,
+ ts,
+ use_hide);
/* Ensure that all requested batches have finished.
* Ideally we want to remove this sync, but there are cases where this doesn't work.
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
index c1d609bf648..dee7a8cec37 100644
--- a/source/blender/draw/intern/draw_cache_impl_particles.c
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -24,6 +24,7 @@
#include "BKE_customdata.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.c b/source/blender/draw/intern/draw_cache_impl_pointcloud.c
index d715899e291..55d0eee00e5 100644
--- a/source/blender/draw/intern/draw_cache_impl_pointcloud.c
+++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.c
@@ -18,6 +18,7 @@
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
+#include "BKE_customdata.h"
#include "BKE_pointcloud.h"
#include "GPU_batch.h"
@@ -139,7 +140,11 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *
}
PointCloud *pointcloud = ob->data;
- const bool has_radius = pointcloud->radius != NULL;
+ const float(*positions)[3] = (float(*)[3])CustomData_get_layer_named(
+ &pointcloud->pdata, CD_PROP_FLOAT3, "position");
+ const float *radii = (float *)CustomData_get_layer_named(
+ &pointcloud->pdata, CD_PROP_FLOAT, "radius");
+ const bool has_radius = radii != NULL;
static GPUVertFormat format = {0};
static GPUVertFormat format_no_radius = {0};
@@ -162,14 +167,14 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache *
if (has_radius) {
float(*vbo_data)[4] = (float(*)[4])GPU_vertbuf_get_data(cache->pos);
for (int i = 0; i < pointcloud->totpoint; i++) {
- copy_v3_v3(vbo_data[i], pointcloud->co[i]);
+ copy_v3_v3(vbo_data[i], positions[i]);
/* TODO(fclem): remove multiplication here.
* Here only for keeping the size correct for now. */
- vbo_data[i][3] = pointcloud->radius[i] * 100.0f;
+ vbo_data[i][3] = radii[i] * 100.0f;
}
}
else {
- GPU_vertbuf_attr_fill(cache->pos, pos, pointcloud->co);
+ GPU_vertbuf_attr_fill(cache->pos, pos, positions);
}
}
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index a0c7e064e00..cde2b59ea23 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -39,10 +39,10 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-#include "draw_cache_extract.h"
+#include "draw_cache_extract.hh"
#include "draw_cache_impl.h"
#include "draw_cache_inline.h"
-#include "mesh_extractors/extract_mesh.h"
+#include "mesh_extractors/extract_mesh.hh"
extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[];
extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[];
@@ -221,7 +221,7 @@ static GPUShader *get_patch_evaluation_shader(int shader_type)
"#define OSD_PATCH_BASIS_GLSL\n"
"#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
"#define FDOTS_EVALUATION\n"
- "#define FOTS_NORMALS\n";
+ "#define FDOTS_NORMALS\n";
}
else if (shader_type == SHADER_PATCH_EVALUATION_ORCO) {
defines =
@@ -575,6 +575,7 @@ static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache)
void draw_subdiv_cache_free(DRWSubdivCache *cache)
{
GPU_VERTBUF_DISCARD_SAFE(cache->patch_coords);
+ GPU_VERTBUF_DISCARD_SAFE(cache->corner_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);
@@ -780,7 +781,7 @@ struct DRWCacheBuildingContext {
DRWSubdivCache *cache;
- /* Pointers into DRWSubdivCache buffers for easier access during traversal. */
+ /* Pointers into #DRWSubdivCache buffers for easier access during traversal. */
CompressedPatchCoord *patch_coords;
int *subdiv_loop_vert_index;
int *subdiv_loop_subdiv_vert_index;
@@ -792,9 +793,9 @@ struct DRWCacheBuildingContext {
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. */
+ /* #CD_ORIGINDEX layers from the mesh to directly look up during traversal the original-index
+ * 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. */
const int *v_origindex;
const int *e_origindex;
};
@@ -834,6 +835,11 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops);
+ cache->corner_patch_coords = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->corner_patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->corner_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);
@@ -861,10 +867,10 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
ctx->subdiv_loop_subdiv_edge_index = cache->subdiv_loop_subdiv_edge_index;
ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index;
- ctx->v_origindex = static_cast<int *>(
+ ctx->v_origindex = static_cast<const int *>(
CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX));
- ctx->e_origindex = static_cast<int *>(
+ ctx->e_origindex = static_cast<const int *>(
CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX));
if (cache->num_subdiv_verts) {
@@ -1046,14 +1052,10 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
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 SubsurfRuntimeData *runtime_data)
{
- 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.resolution = runtime_data->resolution;
to_mesh_settings.use_optimal_display = false;
if (cache->resolution != to_mesh_settings.resolution) {
@@ -1124,6 +1126,31 @@ static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
cache->resolution = to_mesh_settings.resolution;
cache->num_coarse_poly = mesh_eval->totpoly;
+ /* To avoid floating point precision issues when evaluating patches at patch boundaries,
+ * ensure that all loops sharing a vertex use the same patch coordinate. This could cause
+ * the mesh to not be watertight, leading to shadowing artifacts (see T97877). */
+ blender::Vector<int> first_loop_index(cache->num_subdiv_verts, -1);
+
+ /* Save coordinates for corners, as attributes may vary for each loop connected to the same
+ * vertex. */
+ memcpy(GPU_vertbuf_get_data(cache->corner_patch_coords),
+ cache_building_context.patch_coords,
+ sizeof(CompressedPatchCoord) * cache->num_subdiv_loops);
+
+ for (int i = 0; i < cache->num_subdiv_loops; i++) {
+ const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i];
+ if (first_loop_index[vertex] != -1) {
+ continue;
+ }
+ first_loop_index[vertex] = i;
+ }
+
+ for (int i = 0; i < cache->num_subdiv_loops; i++) {
+ const int vertex = cache_building_context.subdiv_loop_subdiv_vert_index[i];
+ cache_building_context.patch_coords[i] =
+ cache_building_context.patch_coords[first_loop_index[vertex]];
+ }
+
/* Cleanup. */
MEM_SAFE_FREE(cache_building_context.vert_origindex_map);
MEM_SAFE_FREE(cache_building_context.edge_origindex_map);
@@ -1177,8 +1204,8 @@ struct DRWSubdivUboStorage {
* of out of bond accesses as compute dispatch are of fixed size. */
uint total_dispatch_size;
- int _pad0;
- int _pad2;
+ int is_edit_mode;
+ int use_hide;
int _pad3;
};
@@ -1209,6 +1236,8 @@ static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache,
ubo->coarse_face_hidden_mask = SUBDIV_COARSE_FACE_FLAG_HIDDEN_MASK;
ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK;
ubo->total_dispatch_size = total_dispatch_size;
+ ubo->is_edit_mode = cache->is_edit_mode;
+ ubo->use_hide = cache->use_hide;
}
static void draw_subdiv_ubo_update_and_bind(const DRWSubdivCache *cache,
@@ -1405,7 +1434,7 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(src_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, binding_point++);
- GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->corner_patch_coords, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
@@ -1441,6 +1470,11 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
{
GPUShader *shader = nullptr;
+ if (!draw_subdiv_cache_need_polygon_data(cache)) {
+ /* Happens on meshes with only loose geometry. */
+ return;
+ }
+
if (dimensions == 1) {
shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_1D,
"#define SUBDIV_POLYGON_OFFSET\n"
@@ -1480,7 +1514,7 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(src_data, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, binding_point++);
- GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->corner_patch_coords, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
GPU_vertbuf_bind_as_ssbo(dst_data, binding_point++);
BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
@@ -1806,6 +1840,7 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++);
/* Outputs */
GPU_vertbuf_bind_as_ssbo(lnor, binding_point++);
@@ -1974,10 +2009,9 @@ static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
MEM_freeN(per_polygon_mat_offset);
}
-static bool draw_subdiv_create_requested_buffers(const Scene *scene,
- Object *ob,
+static bool draw_subdiv_create_requested_buffers(Object *ob,
Mesh *mesh,
- struct MeshBatchCache *batch_cache,
+ MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
const bool is_editmode,
const bool is_paint_mode,
@@ -1989,16 +2023,10 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
const bool use_hide,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- SubsurfModifierData *smd = reinterpret_cast<SubsurfModifierData *>(
- BKE_modifiers_findby_session_uuid(ob, &mesh->runtime.subsurf_session_uuid));
- 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);
+ SubsurfRuntimeData *runtime_data = mesh->runtime.subsurf_runtime_data;
+ BLI_assert(runtime_data && runtime_data->has_gpu_subdiv);
- if (settings.level == 0) {
+ if (runtime_data->settings.level == 0) {
return false;
}
@@ -2009,9 +2037,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
bm = mesh->edit_mesh->bm;
}
- BKE_subsurf_modifier_ensure_runtime(smd);
-
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true);
if (!subdiv) {
return false;
}
@@ -2019,7 +2045,7 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
draw_subdiv_invalidate_evaluator_for_orco(subdiv, mesh_eval);
if (!BKE_subdiv_eval_begin_from_mesh(
- subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
+ subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GPU, evaluator_cache)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
@@ -2032,13 +2058,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
}
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)) {
+ if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, runtime_data)) {
return false;
}
/* Edges which do not come from coarse edges should not be drawn in edit mode, only in object
* mode when optimal display in turned off. */
- const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges) || is_editmode;
+ const bool optimal_display = runtime_data->use_optimal_display || is_editmode;
draw_cache->bm = bm;
draw_cache->mesh = mesh_eval;
@@ -2046,14 +2072,13 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
draw_cache->optimal_display = optimal_display;
draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
- /* Copy topology information for stats display. Use `mesh` directly, as `mesh_eval` could be the
- * edit mesh. */
- mesh->runtime.subsurf_totvert = draw_cache->num_subdiv_verts;
- mesh->runtime.subsurf_totedge = draw_cache->num_subdiv_edges;
- mesh->runtime.subsurf_totpoly = draw_cache->num_subdiv_quads;
- mesh->runtime.subsurf_totloop = draw_cache->num_subdiv_loops;
+ /* Copy topology information for stats display. */
+ runtime_data->stats_totvert = draw_cache->num_subdiv_verts;
+ runtime_data->stats_totedge = draw_cache->num_subdiv_edges;
+ runtime_data->stats_totpoly = draw_cache->num_subdiv_quads;
+ runtime_data->stats_totloop = draw_cache->num_subdiv_loops;
- draw_cache->use_custom_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals) &&
+ draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) &&
(mesh_eval->flag & ME_AUTOSMOOTH) &&
CustomData_has_layer(&mesh_eval->ldata,
CD_CUSTOMLOOPNORMAL);
@@ -2065,10 +2090,16 @@ static bool draw_subdiv_create_requested_buffers(const Scene *scene,
MeshRenderData *mr = mesh_render_data_create(
ob, mesh, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
mr->use_hide = use_hide;
+ draw_cache->use_hide = use_hide;
+
+ /* Used for setting loop normals flags. Mapped extraction is only used during edit mode.
+ * See comments in #extract_lnor_iter_poly_mesh.
+ */
+ draw_cache->is_edit_mode = mr->edit_bmesh != nullptr;
draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval, mr);
- mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr);
+ blender::draw::mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, mr);
mesh_render_data_free(mr);
@@ -2175,10 +2206,9 @@ blender::Span<DRWSubdivLooseVertex> draw_subdiv_cache_get_loose_verts(const DRWS
static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
-void DRW_create_subdivision(const Scene *scene,
- Object *ob,
+void DRW_create_subdivision(Object *ob,
Mesh *mesh,
- struct MeshBatchCache *batch_cache,
+ MeshBatchCache *batch_cache,
MeshBufferCache *mbc,
const bool is_editmode,
const bool is_paint_mode,
@@ -2190,7 +2220,7 @@ void DRW_create_subdivision(const Scene *scene,
const bool use_hide)
{
if (g_evaluator_cache == nullptr) {
- g_evaluator_cache = openSubdiv_createEvaluatorCache(OPENSUBDIV_EVALUATOR_GLSL_COMPUTE);
+ g_evaluator_cache = openSubdiv_createEvaluatorCache(OPENSUBDIV_EVALUATOR_GPU);
}
#undef TIME_SUBDIV
@@ -2199,8 +2229,7 @@ void DRW_create_subdivision(const Scene *scene,
const double begin_time = PIL_check_seconds_timer();
#endif
- if (!draw_subdiv_create_requested_buffers(scene,
- ob,
+ if (!draw_subdiv_create_requested_buffers(ob,
mesh,
batch_cache,
mbc,
diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h
index b6b0c94f4bf..d31c98e0dee 100644
--- a/source/blender/draw/intern/draw_common.h
+++ b/source/blender/draw/intern/draw_common.h
@@ -93,7 +93,7 @@ void DRW_curves_free(void);
/**
* Add attributes bindings of volume grids to an existing shading group.
* No draw call is added so the caller can decide how to use the data.
- * \return nullptr if there is something to draw.
+ * \return nullptr if there is nothing to draw.
*/
struct DRWShadingGroup *DRW_shgroup_volume_create_sub(struct Scene *scene,
struct Object *ob,
diff --git a/source/blender/draw/intern/draw_curves.cc b/source/blender/draw/intern/draw_curves.cc
index d90c63b680e..233af08c363 100644
--- a/source/blender/draw/intern/draw_curves.cc
+++ b/source/blender/draw/intern/draw_curves.cc
@@ -13,6 +13,9 @@
#include "DNA_curves_types.h"
#include "DNA_customdata_types.h"
+#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
+
#include "GPU_batch.h"
#include "GPU_capabilities.h"
#include "GPU_compute.h"
@@ -81,9 +84,9 @@ struct CurvesUniformBufPool {
{
if (used >= ubos.size()) {
ubos.append(std::make_unique<CurvesInfosBuf>());
- return *ubos.last().get();
+ return *ubos.last();
}
- return *ubos[used++].get();
+ return *ubos[used++];
}
};
@@ -243,13 +246,14 @@ static void drw_curves_cache_update_transform_feedback(CurvesEvalCache *cache, c
}
}
-static CurvesEvalCache *drw_curves_cache_get(Object *object,
+static CurvesEvalCache *drw_curves_cache_get(Curves &curves,
GPUMaterial *gpu_material,
int subdiv,
int thickness_res)
{
CurvesEvalCache *cache;
- bool update = curves_ensure_procedural_data(object, &cache, gpu_material, subdiv, thickness_res);
+ const bool update = curves_ensure_procedural_data(
+ &curves, &cache, gpu_material, subdiv, thickness_res);
if (update) {
if (drw_curves_shader_type_get() == PART_REFINE_SHADER_COMPUTE) {
@@ -265,12 +269,13 @@ static CurvesEvalCache *drw_curves_cache_get(Object *object,
GPUVertBuf *DRW_curves_pos_buffer_get(Object *object)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
+ const Scene *scene = draw_ctx->scene;
- int subdiv = scene->r.hair_subdiv;
- int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
+ const int subdiv = scene->r.hair_subdiv;
+ const int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
- CurvesEvalCache *cache = drw_curves_cache_get(object, nullptr, subdiv, thickness_res);
+ Curves &curves = *static_cast<Curves *>(object->data);
+ CurvesEvalCache *cache = drw_curves_cache_get(curves, nullptr, subdiv, thickness_res);
return cache->final[subdiv].proc_buf;
}
@@ -300,15 +305,16 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
GPUMaterial *gpu_material)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
+ const Scene *scene = draw_ctx->scene;
CurvesUniformBufPool *pool = DST.vmempool->curves_ubos;
CurvesInfosBuf &curves_infos = pool->alloc();
+ Curves &curves_id = *static_cast<Curves *>(object->data);
- int subdiv = scene->r.hair_subdiv;
- int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
+ const int subdiv = scene->r.hair_subdiv;
+ const int thickness_res = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 1 : 2;
CurvesEvalCache *curves_cache = drw_curves_cache_get(
- object, gpu_material, subdiv, thickness_res);
+ curves_id, gpu_material, subdiv, thickness_res);
DRWShadingGroup *shgrp = DRW_shgroup_create_sub(shgrp_parent);
@@ -325,6 +331,25 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
float hair_rad_tip = 0.0f;
bool hair_close_tip = true;
+ /* Use the radius of the root and tip of the first curve for now. This is a workaround that we
+ * use for now because we can't use a per-point radius yet. */
+ const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
+ curves_id.geometry);
+ if (curves.curves_num() >= 1) {
+ blender::VArray<float> radii = curves.attributes().lookup_or_default(
+ "radius", ATTR_DOMAIN_POINT, 0.005f);
+ const blender::IndexRange first_curve_points = curves.points_for_curve(0);
+ const float first_radius = radii[first_curve_points.first()];
+ const float last_radius = radii[first_curve_points.last()];
+ const float middle_radius = radii[first_curve_points.size() / 2];
+ hair_rad_root = radii[first_curve_points.first()];
+ hair_rad_tip = radii[first_curve_points.last()];
+ hair_rad_shape = std::clamp(
+ safe_divide(middle_radius - first_radius, last_radius - first_radius) * 2.0f - 1.0f,
+ -1.0f,
+ 1.0f);
+ }
+
DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", curves_cache->final[subdiv].proc_tex);
if (curves_cache->length_tex) {
DRW_shgroup_uniform_texture(shgrp, "hairLen", curves_cache->length_tex);
@@ -358,7 +383,7 @@ DRWShadingGroup *DRW_shgroup_curves_create_sub(Object *object,
* attributes. */
const int index = attribute_index_in_material(gpu_material, request.attribute_name);
if (index != -1) {
- curves_infos.is_point_attribute[index] = request.domain == ATTR_DOMAIN_POINT;
+ curves_infos.is_point_attribute[index][0] = request.domain == ATTR_DOMAIN_POINT;
}
}
diff --git a/source/blender/draw/intern/draw_curves_private.h b/source/blender/draw/intern/draw_curves_private.h
index ed4dd50dfbe..31122ed5248 100644
--- a/source/blender/draw/intern/draw_curves_private.h
+++ b/source/blender/draw/intern/draw_curves_private.h
@@ -16,6 +16,12 @@
extern "C" {
#endif
+struct Curves;
+struct GPUVertBuf;
+struct GPUIndexBuf;
+struct GPUBatch;
+struct GPUTexture;
+
#define MAX_THICKRES 2 /* see eHairType */
#define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */
@@ -25,32 +31,31 @@ typedef enum CurvesEvalShader {
} CurvesEvalShader;
#define CURVES_EVAL_SHADER_NUM 3
-struct GPUVertBuf;
-struct GPUIndexBuf;
-struct GPUBatch;
-struct GPUTexture;
-
typedef struct CurvesEvalFinalCache {
/* Output of the subdivision stage: vertex buffer sized to subdiv level. */
GPUVertBuf *proc_buf;
GPUTexture *proc_tex;
- /* Just contains a huge index buffer used to draw the final curves. */
+ /** Just contains a huge index buffer used to draw the final curves. */
GPUBatch *proc_hairs[MAX_THICKRES];
- /* Points per curve, at least 2. */
+ /** Points per curve, at least 2. */
int strands_res;
- /* Attributes currently being or about to be drawn. */
+ /** Attributes currently being drawn or about to be drawn. */
DRW_Attributes attr_used;
- /* Attributes which were used at some point. This is used for garbage collection, to remove
- * attributes which are not used in shaders anymore due to user edits. */
+ /**
+ * Attributes that were used at some point. This is used for garbage collection, to remove
+ * attributes that are not used in shaders anymore due to user edits.
+ */
DRW_Attributes attr_used_over_time;
- /* Last time, in seconds, the `attr_used` and `attr_used_over_time` were exactly the same.
+ /**
+ * The last time in seconds that the `attr_used` and `attr_used_over_time` were exactly the same.
* If the delta between this time and the current scene time is greater than the timeout set in
- * user preferences (`U.vbotimeout`) then garbage collection is performed. */
+ * user preferences (`U.vbotimeout`) then garbage collection is performed.
+ */
int last_attr_matching_time;
/* Output of the subdivision stage: vertex buffers sized to subdiv level. This is only attributes
@@ -61,7 +66,7 @@ typedef struct CurvesEvalFinalCache {
/* Curves procedural display: Evaluation is done on the GPU. */
typedef struct CurvesEvalCache {
- /* Input control points */
+ /* Input control point positions combined with parameter data. */
GPUVertBuf *proc_point_buf;
GPUTexture *point_tex;
@@ -78,8 +83,8 @@ typedef struct CurvesEvalCache {
CurvesEvalFinalCache final[MAX_HAIR_SUBDIV];
- /* For point attributes, which need subdivision, these are the input data.
- * For spline attributes, which need not subdivision, these are the final data. */
+ /* For point attributes, which need subdivision, these buffers contain the input data.
+ * For curve domain attributes, which do not need subdivision, these are the final data. */
GPUVertBuf *proc_attributes_buf[GPU_MAX_ATTR];
GPUTexture *proc_attributes_tex[GPU_MAX_ATTR];
@@ -89,9 +94,9 @@ typedef struct CurvesEvalCache {
} CurvesEvalCache;
/**
- * Ensure all textures and buffers needed for GPU accelerated drawing.
+ * Ensure all necessary textures and buffers exist for GPU accelerated drawing.
*/
-bool curves_ensure_procedural_data(struct Object *object,
+bool curves_ensure_procedural_data(struct Curves *curves,
struct CurvesEvalCache **r_hair_cache,
struct GPUMaterial *gpu_material,
int subdiv,
diff --git a/source/blender/draw/intern/draw_hair.cc b/source/blender/draw/intern/draw_hair.cc
index 0a3c16e0d71..dc791314333 100644
--- a/source/blender/draw/intern/draw_hair.cc
+++ b/source/blender/draw/intern/draw_hair.cc
@@ -27,8 +27,11 @@
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
+#include "DRW_gpu_wrapper.hh"
+
#include "draw_hair_private.h"
#include "draw_shader.h"
+#include "draw_shader_shared.h"
#ifndef __APPLE__
# define USE_TRANSFORM_FEEDBACK
@@ -65,6 +68,7 @@ static int g_tf_target_height;
static GPUVertBuf *g_dummy_vbo = nullptr;
static GPUTexture *g_dummy_texture = nullptr;
static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */
+static blender::draw::UniformBuffer<CurvesInfos> *g_dummy_curves_info = nullptr;
static GPUShader *hair_refine_shader_get(ParticleRefineShader refinement)
{
@@ -93,6 +97,13 @@ void DRW_hair_init(void)
GPU_vertbuf_use(g_dummy_vbo);
g_dummy_texture = GPU_texture_create_from_vertbuf("hair_dummy_attr", g_dummy_vbo);
+
+ g_dummy_curves_info = MEM_new<blender::draw::UniformBuffer<CurvesInfos>>(
+ "g_dummy_curves_info");
+ memset(g_dummy_curves_info->is_point_attribute,
+ 0,
+ sizeof(g_dummy_curves_info->is_point_attribute));
+ g_dummy_curves_info->push_update();
}
}
@@ -276,6 +287,8 @@ DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object,
if (hair_cache->length_tex) {
DRW_shgroup_uniform_texture(shgrp, "l", hair_cache->length_tex);
}
+
+ DRW_shgroup_uniform_block(shgrp, "drw_curves", *g_dummy_curves_info);
DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &hair_cache->final[subdiv].strands_res, 1);
DRW_shgroup_uniform_int_copy(shgrp, "hairThicknessRes", thickness_res);
DRW_shgroup_uniform_float_copy(shgrp, "hairRadShape", hair_rad_shape);
@@ -374,4 +387,5 @@ void DRW_hair_free(void)
{
GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo);
DRW_TEXTURE_FREE_SAFE(g_dummy_texture);
+ MEM_delete(g_dummy_curves_info);
}
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 1372b843442..5d21ab75650 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -44,7 +44,6 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_world_types.h"
-#include "draw_manager.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -236,7 +235,7 @@ bool DRW_object_use_hide_faces(const struct Object *ob)
return (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
case OB_MODE_VERTEX_PAINT:
case OB_MODE_WEIGHT_PAINT:
- return (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)) != 0;
+ return true;
}
}
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index f0960c5324b..188d9114cd7 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1238,7 +1238,8 @@ static void drw_sculpt_generate_calls(DRWSculptCallbackData *scd)
&update_frustum,
&draw_frustum,
(void (*)(void *, GPU_PBVH_Buffers *))sculpt_draw_cb,
- scd);
+ scd,
+ scd->use_mats);
if (SCULPT_DEBUG_BUFFERS) {
int debug_node_nr = 0;
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index 94c0c53dab7..e8944442607 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -87,9 +87,9 @@ BLI_STATIC_ASSERT_ALIGN(VolumeInfos, 16)
struct CurvesInfos {
/* Per attribute scope, follows loading order.
- * NOTE: uint as bool in GLSL is 4 bytes. */
- uint is_point_attribute[DRW_ATTRIBUTE_PER_CURVES_MAX];
- int _pad;
+ * NOTE: uint as bool in GLSL is 4 bytes.
+ * NOTE: GLSL pad arrays of scalar to 16 bytes (std140). */
+ uint4 is_point_attribute[DRW_ATTRIBUTE_PER_CURVES_MAX];
};
BLI_STATIC_ASSERT_ALIGN(CurvesInfos, 16)
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
index 15c770a51c4..ef580fc116a 100644
--- a/source/blender/draw/intern/draw_subdivision.h
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -104,8 +104,10 @@ typedef struct DRWSubdivCache {
bool optimal_display;
bool use_custom_loop_normals;
- /* Coordinates used to evaluate patches for UVs, positions, and normals. */
+ /* Coordinates used to evaluate patches for positions and normals. */
struct GPUVertBuf *patch_coords;
+ /* Coordinates used to evaluate patches for attributes. */
+ struct GPUVertBuf *corner_patch_coords;
/* Coordinates used to evaluate patches for the face centers (or face dots) in edit-mode. */
struct GPUVertBuf *fdots_patch_coords;
@@ -175,6 +177,10 @@ typedef struct DRWSubdivCache {
/* UBO to store settings for the various compute shaders. */
struct GPUUniformBuf *ubo;
+
+ /* Extra flags, passed to the UBO. */
+ bool is_edit_mode;
+ bool use_hide;
} DRWSubdivCache;
/* Only frees the data of the cache, caller is responsible to free the cache itself if necessary.
@@ -183,8 +189,7 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache);
/** \} */
-void DRW_create_subdivision(const struct Scene *scene,
- struct Object *ob,
+void DRW_create_subdivision(struct Object *ob,
struct Mesh *mesh,
struct MeshBatchCache *batch_cache,
struct MeshBufferCache *mbc,
diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc
index 8d9a6f486e2..c4e58ab24cb 100644
--- a/source/blender/draw/intern/draw_volume.cc
+++ b/source/blender/draw/intern/draw_volume.cc
@@ -129,12 +129,14 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob,
volume_infos.temperature_bias = 0.0f;
/* Bind volume grid textures. */
- int grid_id = 0;
+ int grid_id = 0, grids_len = 0;
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, attrs) {
const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, attr->name);
const DRWVolumeGrid *drw_grid = (volume_grid) ?
DRW_volume_batch_cache_get_grid(volume, volume_grid) :
nullptr;
+ /* Count number of valid attributes. */
+ grids_len += int(volume_grid != nullptr);
/* Handle 3 cases here:
* - Grid exists and texture was loaded -> use texture.
@@ -145,7 +147,13 @@ static DRWShadingGroup *drw_volume_object_grids_init(Object *ob,
grid_default_texture(attr->default_value);
DRW_shgroup_uniform_texture(grp, attr->input_name, grid_tex);
- copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(), drw_grid->object_to_texture);
+ copy_m4_m4(volume_infos.grids_xform[grid_id++].ptr(),
+ (drw_grid) ? drw_grid->object_to_texture : g_data.dummy_grid_mat);
+ }
+ /* Render nothing if there is no attribute for the shader to render.
+ * This also avoids an assert caused by the bounding box being zero in size. */
+ if (grids_len == 0) {
+ return nullptr;
}
volume_infos.push_update();
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.c b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
index 9dc82fa3d32..ec7d3a933b4 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.c
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.cc
@@ -13,7 +13,7 @@
#include "ED_uvedit.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -29,7 +29,7 @@ void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuf
eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
{
- eMRIterType type = 0;
+ eMRIterType type = (eMRIterType)0;
SET_FLAG_FROM_TEST(type, (ext->iter_looptri_bm || ext->iter_looptri_mesh), MR_ITER_LOOPTRI);
SET_FLAG_FROM_TEST(type, (ext->iter_poly_bm || ext->iter_poly_mesh), MR_ITER_POLY);
SET_FLAG_FROM_TEST(type, (ext->iter_ledge_bm || ext->iter_ledge_mesh), MR_ITER_LEDGE);
@@ -128,7 +128,7 @@ void mesh_render_data_loop_flag(const MeshRenderData *mr,
return;
}
MLoopUV *luv = (MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_ofs);
- if (luv != NULL && (luv->flag & MLOOPUV_PINNED)) {
+ if (luv != nullptr && (luv->flag & MLOOPUV_PINNED)) {
eattr->v_flag |= VFLAG_VERT_UV_PINNED;
}
if (uvedit_uv_select_test_ex(mr->toolsettings, l, cd_ofs)) {
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
index b88cd9e77d2..8052b277d45 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh
@@ -17,11 +17,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "draw_cache_extract.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "draw_cache_extract.hh"
struct DRWSubdivCache;
@@ -31,13 +27,13 @@ struct DRWSubdivCache;
/** \name Mesh Render Data
* \{ */
-typedef enum eMRExtractType {
+enum eMRExtractType {
MR_EXTRACT_BMESH,
MR_EXTRACT_MAPPED,
MR_EXTRACT_MESH,
-} eMRExtractType;
+};
-typedef struct MeshRenderData {
+struct MeshRenderData {
eMRExtractType extract_type;
int poly_len, edge_len, vert_len, loop_len;
@@ -95,7 +91,7 @@ typedef struct MeshRenderData {
int *mat_tri_len;
int visible_tri_len;
} poly_sorted;
-} MeshRenderData;
+};
BLI_INLINE BMFace *bm_original_face_get(const MeshRenderData *mr, int idx)
{
@@ -159,71 +155,71 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e
/* TODO(jbakker): move parameters inside a struct. */
-typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data);
-typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
- const MLoopTri *mlt,
- int elt_index,
- void *data);
-typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
- const BMFace *f,
- int f_index,
- void *data);
-typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
- const MPoly *mp,
- int mp_index,
+using ExtractTriBMeshFn = void(const MeshRenderData *mr, BMLoop **elt, int elt_index, void *data);
+using ExtractTriMeshFn = void(const MeshRenderData *mr,
+ const MLoopTri *mlt,
+ int elt_index,
+ void *data);
+using ExtractPolyBMeshFn = void(const MeshRenderData *mr,
+ const BMFace *f,
+ int f_index,
void *data);
-typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
- const BMEdge *eed,
- int ledge_index,
- void *data);
-typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
- const MEdge *med,
+using ExtractPolyMeshFn = void(const MeshRenderData *mr,
+ const MPoly *mp,
+ int mp_index,
+ void *data);
+using ExtractLEdgeBMeshFn = void(const MeshRenderData *mr,
+ const BMEdge *eed,
int ledge_index,
void *data);
-typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
- const BMVert *eve,
- int lvert_index,
- void *data);
-typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
- const MVert *mv,
+using ExtractLEdgeMeshFn = void(const MeshRenderData *mr,
+ const MEdge *med,
+ int ledge_index,
+ void *data);
+using ExtractLVertBMeshFn = void(const MeshRenderData *mr,
+ const BMVert *eve,
int lvert_index,
void *data);
-typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
- void *buffer,
- void *data);
-typedef void(ExtractInitFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer,
- void *r_data);
-typedef void(ExtractFinishFn)(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buffer,
- 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,
+using ExtractLVertMeshFn = void(const MeshRenderData *mr,
+ const MVert *mv,
+ int lvert_index,
+ void *data);
+using ExtractLooseGeomSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *buffer,
+ void *data);
+using ExtractInitFn = void(const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *r_data);
+using ExtractFinishFn = void(const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *data);
+using ExtractTaskReduceFn = void(void *userdata, void *task_userdata);
+
+using ExtractInitSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buf,
+ void *data);
+using ExtractIterSubdivBMeshFn = void(const 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 {
+ const BMFace *coarse_quad);
+using ExtractIterSubdivMeshFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *data,
+ uint subdiv_quad_index,
+ const MPoly *coarse_quad);
+using ExtractFinishSubdivFn = void(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buf,
+ void *data);
+
+struct MeshExtract {
/** Executed on main thread and return user data for iteration functions. */
ExtractInitFn *init;
/** Executed on one (or more if use_threading) worker thread(s). */
@@ -254,7 +250,7 @@ typedef struct MeshExtract {
* buffer.
*/
size_t mesh_buffer_offset;
-} MeshExtract;
+};
/** \} */
@@ -291,14 +287,14 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
/* draw_cache_extract_mesh_extractors.c */
-typedef struct EditLoopData {
+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;
+};
void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist);
eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
@@ -359,7 +355,3 @@ 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
-}
-#endif
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 2c4e7bfa802..2ff093d0bd8 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
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -22,7 +22,7 @@ struct MeshExtract_EditUvElem_Data {
};
static void extract_edituv_tris_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -69,7 +69,7 @@ static void extract_edituv_tris_iter_looptri_mesh(const MeshRenderData *mr,
}
static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -142,7 +142,7 @@ static void extract_edituv_tris_iter_subdiv_mesh(const DRWSubdivCache *UNUSED(su
static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -176,7 +176,7 @@ constexpr MeshExtract create_extractor_edituv_tris()
* \{ */
static void extract_edituv_lines_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -236,7 +236,7 @@ static void extract_edituv_lines_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -307,7 +307,7 @@ static void extract_edituv_lines_iter_subdiv_mesh(const DRWSubdivCache *subdiv_c
static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -341,7 +341,7 @@ constexpr MeshExtract create_extractor_edituv_lines()
* \{ */
static void extract_edituv_points_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -394,7 +394,7 @@ static void extract_edituv_points_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -459,7 +459,7 @@ static void extract_edituv_points_iter_subdiv_mesh(const DRWSubdivCache *subdiv_
static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -493,7 +493,7 @@ constexpr MeshExtract create_extractor_edituv_points()
* \{ */
static void extract_edituv_fdots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -557,7 +557,7 @@ static void extract_edituv_fdots_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -584,9 +584,7 @@ constexpr MeshExtract create_extractor_edituv_fdots()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_tris = blender::draw::create_extractor_edituv_tris();
const MeshExtract extract_edituv_lines = blender::draw::create_extractor_edituv_lines();
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 4bf732caf0a..cc0b383f12b 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
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -15,7 +15,7 @@ namespace blender::draw {
* \{ */
static void extract_fdots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
@@ -68,7 +68,7 @@ static void extract_fdots_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_fdots_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_userdata)
{
@@ -95,6 +95,4 @@ 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 3cecaf81b8a..e6c0d815963 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
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -18,7 +18,7 @@ namespace blender::draw {
* \{ */
static void extract_lines_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
@@ -132,7 +132,7 @@ static void extract_lines_task_reduce(void *_userdata_to, void *_userdata_from)
}
static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *data)
{
@@ -143,7 +143,7 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buffer,
void *UNUSED(data))
{
@@ -183,10 +183,44 @@ static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
uint *flags_data = static_cast<uint *>(GPU_vertbuf_get_data(flags));
- const MEdge *medge = mr->medge;
+ switch (mr->extract_type) {
+ case MR_EXTRACT_MESH: {
+ const MEdge *medge = mr->medge;
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ *flags_data++ = (medge[edge.coarse_edge_index].flag & ME_HIDE) != 0;
+ }
+ break;
+ }
+ case MR_EXTRACT_MAPPED: {
+ if (mr->bm) {
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ const BMEdge *bm_edge = bm_original_edge_get(mr, edge.coarse_edge_index);
+ *flags_data++ = BM_elem_flag_test_bool(bm_edge, BM_ELEM_HIDDEN) != 0;
+ }
+ }
+ else {
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ int e = edge.coarse_edge_index;
+
+ if (mr->e_origindex && mr->e_origindex[e] != ORIGINDEX_NONE) {
+ *flags_data++ = (mr->medge[mr->e_origindex[e]].flag & ME_HIDE) != 0;
+ }
+ else {
+ *flags_data++ = false;
+ }
+ }
+ }
- for (DRWSubdivLooseEdge edge : loose_edges) {
- *flags_data++ = (medge[edge.coarse_edge_index].flag & ME_HIDE) != 0;
+ break;
+ }
+ case MR_EXTRACT_BMESH: {
+ BMesh *bm = mr->bm;
+ for (DRWSubdivLooseEdge edge : loose_edges) {
+ const BMEdge *bm_edge = BM_edge_at_index(bm, edge.coarse_edge_index);
+ *flags_data++ = BM_elem_flag_test_bool(bm_edge, BM_ELEM_HIDDEN) != 0;
+ }
+ break;
+ }
}
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
@@ -221,7 +255,7 @@ constexpr MeshExtract create_extractor_lines()
/** \name Extract Lines and Loose Edges Sub Buffer
* \{ */
-static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshBatchCache *cache)
+static void extract_lines_loose_subbuffer(const MeshRenderData *mr, MeshBatchCache *cache)
{
BLI_assert(cache->final.buff.ibo.lines);
/* Multiply by 2 because these are edges indices. */
@@ -233,7 +267,7 @@ static void extract_lines_loose_subbuffer(const MeshRenderData *mr, struct MeshB
}
static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *data)
{
@@ -245,7 +279,7 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
static void extract_lines_with_lines_loose_finish_subdiv(const struct DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *UNUSED(buf),
void *UNUSED(_data))
{
@@ -284,7 +318,7 @@ constexpr MeshExtract create_extractor_lines_with_lines_loose()
* \{ */
static void extract_lines_loose_only_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
@@ -295,7 +329,7 @@ static void extract_lines_loose_only_init(const MeshRenderData *mr,
static void extract_lines_loose_only_init_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -320,9 +354,7 @@ constexpr MeshExtract create_extractor_lines_loose_only()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lines = blender::draw::create_extractor_lines();
const MeshExtract extract_lines_with_lines_loose =
blender::draw::create_extractor_lines_with_lines_loose();
const MeshExtract extract_lines_loose_only = blender::draw::create_extractor_lines_loose_only();
-}
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 de464fb286f..c2cfb66ec28 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
@@ -11,7 +11,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -42,7 +42,7 @@ static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data,
}
static void extract_lines_adjacency_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
@@ -132,7 +132,7 @@ static void extract_lines_adjacency_iter_looptri_mesh(const MeshRenderData *mr,
}
static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -166,7 +166,7 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *_data)
{
@@ -222,7 +222,7 @@ static void extract_lines_adjacency_iter_subdiv_mesh(const DRWSubdivCache *subdi
static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -253,6 +253,4 @@ constexpr MeshExtract create_extractor_lines_adjacency()
} // 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 286c7ea9c43..11c71d61775 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
@@ -12,7 +12,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -26,7 +26,7 @@ struct MeshExtract_LinePaintMask_Data {
};
static void extract_lines_paint_mask_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -78,7 +78,7 @@ static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -126,7 +126,8 @@ static void extract_lines_paint_mask_iter_subdiv_mesh(const DRWSubdivCache *subd
if (!((mr->use_hide && (me->flag & ME_HIDE)) ||
((mr->extract_type == MR_EXTRACT_MAPPED) && (mr->e_origindex) &&
(mr->e_origindex[coarse_edge_index] == ORIGINDEX_NONE)))) {
- const uint ml_index_other = (loop_idx == end_loop_idx) ? start_loop_idx : loop_idx + 1;
+ const uint ml_index_other = (loop_idx == (end_loop_idx - 1)) ? start_loop_idx :
+ loop_idx + 1;
if (coarse_quad->flag & ME_FACE_SEL) {
if (BLI_BITMAP_TEST_AND_SET_ATOMIC(data->select_map, coarse_edge_index)) {
/* Hide edge as it has more than 2 selected loop. */
@@ -154,7 +155,7 @@ static void extract_lines_paint_mask_iter_subdiv_mesh(const DRWSubdivCache *subd
static void extract_lines_paint_mask_finish_subdiv(
const struct DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -181,6 +182,4 @@ constexpr MeshExtract create_extractor_lines_paint_mask()
} // 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 503ce0e79e9..f7c5505422b 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
@@ -10,7 +10,7 @@
#include "MEM_guardedalloc.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ namespace blender::draw {
* \{ */
static void extract_points_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
@@ -131,7 +131,7 @@ static void extract_points_task_reduce(void *_userdata_to, void *_userdata_from)
}
static void extract_points_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_userdata)
{
@@ -142,7 +142,7 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr),
static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buffer),
void *data)
{
@@ -285,7 +285,7 @@ static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_userdata)
{
@@ -322,6 +322,4 @@ constexpr MeshExtract create_extractor_points()
} // 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 6ca5692f387..9fc18620d11 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
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -25,7 +25,7 @@ static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_fro
* \{ */
static void extract_tris_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -81,7 +81,7 @@ static void extract_tris_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_tris_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -111,7 +111,7 @@ 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,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -157,7 +157,7 @@ constexpr MeshExtract create_extractor_tris()
* \{ */
static void extract_tris_single_mat_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
@@ -199,7 +199,7 @@ static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr,
}
static void extract_tris_single_mat_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *_data)
{
@@ -243,7 +243,5 @@ constexpr MeshExtract create_extractor_tris_single_mat()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_tris = blender::draw::create_extractor_tris();
const MeshExtract extract_tris_single_mat = blender::draw::create_extractor_tris_single_mat();
-}
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
index d595abc6dd3..b98af3be17f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -16,7 +16,7 @@
#include "draw_attributes.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -24,24 +24,19 @@ namespace blender::draw {
/** \name Extract Attributes
* \{ */
-static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, AttributeDomain domain)
+static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, eAttrDomain domain)
{
switch (domain) {
- default: {
- return nullptr;
- }
- case ATTR_DOMAIN_POINT: {
+ case ATTR_DOMAIN_POINT:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- }
- case ATTR_DOMAIN_CORNER: {
+ case ATTR_DOMAIN_CORNER:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- }
- case ATTR_DOMAIN_FACE: {
+ case ATTR_DOMAIN_FACE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->pdata : &mr->me->pdata;
- }
- case ATTR_DOMAIN_EDGE: {
+ case ATTR_DOMAIN_EDGE:
return (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->edata : &mr->me->edata;
- }
+ default:
+ return nullptr;
}
}
@@ -50,7 +45,7 @@ static CustomData *get_custom_data_for_domain(const MeshRenderData *mr, Attribut
* 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 {
+template<typename AttributeType, typename VBOType> struct AttributeTypeConverter {
static VBOType convert_value(AttributeType value)
{
if constexpr (std::is_same_v<AttributeType, VBOType>) {
@@ -67,7 +62,7 @@ struct gpuMeshCol {
ushort r, g, b, a;
};
-template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
+template<> struct AttributeTypeConverter<MPropCol, gpuMeshCol> {
static gpuMeshCol convert_value(MPropCol value)
{
gpuMeshCol result;
@@ -80,64 +75,52 @@ template<> struct attribute_type_converter<MPropCol, gpuMeshCol> {
};
/* 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)
+static uint gpu_component_size_for_attribute_type(eCustomDataType type)
{
switch (type) {
case CD_PROP_BOOL:
case CD_PROP_INT8:
case CD_PROP_INT32:
- case CD_PROP_FLOAT: {
+ 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: {
+ case CD_PROP_FLOAT2:
return 2;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
return 3;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return 4;
- }
- default: {
+ default:
return 0;
- }
}
}
-static GPUVertFetchMode get_fetch_mode_for_type(CustomDataType type)
+static GPUVertFetchMode get_fetch_mode_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_FETCH_INT_TO_FLOAT;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_FETCH_INT_TO_FLOAT_UNIT;
- }
- default: {
+ default:
return GPU_FETCH_FLOAT;
- }
}
}
-static GPUVertCompType get_comp_type_for_type(CustomDataType type)
+static GPUVertCompType get_comp_type_for_type(eCustomDataType type)
{
switch (type) {
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
return GPU_COMP_I32;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
return GPU_COMP_U16;
- }
- default: {
+ default:
return GPU_COMP_F32;
- }
}
}
-static void init_vbo_for_attribute(const MeshRenderData *mr,
- GPUVertBuf *vbo,
+static void init_vbo_for_attribute(GPUVertBuf *vbo,
const DRW_AttributeRequest &request,
bool build_on_device,
uint32_t len)
@@ -148,11 +131,8 @@ static void init_vbo_for_attribute(const MeshRenderData *mr,
/* 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);
+ GPU_vertformat_safe_attr_name(request.attribute_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);
@@ -184,41 +164,36 @@ static void fill_vertbuf_with_attribute(const MeshRenderData *mr,
const AttributeType *attr_data = static_cast<const AttributeType *>(
CustomData_get_layer_n(custom_data, request.cd_type, layer_index));
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
switch (request.domain) {
- default: {
- BLI_assert(false);
- break;
- }
- case ATTR_DOMAIN_POINT: {
+ 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]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->v]);
}
break;
- }
- case ATTR_DOMAIN_CORNER: {
+ 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]);
+ *vbo_data = Converter::convert_value(attr_data[ml_index]);
}
break;
- }
- case ATTR_DOMAIN_EDGE: {
+ 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]);
+ *vbo_data = Converter::convert_value(attr_data[mloop->e]);
}
break;
- }
- case ATTR_DOMAIN_FACE: {
+ 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]);
+ const VBOType value = Converter::convert_value(attr_data[mp_index]);
for (int l = 0; l < poly.totloop; l++) {
*vbo_data++ = value;
}
}
break;
- }
+ default:
+ BLI_assert_unreachable();
+ break;
}
}
@@ -231,9 +206,9 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
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);
+ const int cd_ofs = CustomData_get_n_offset(custom_data, request.cd_type, layer_index);
- using converter = attribute_type_converter<AttributeType, VBOType>;
+ using Converter = AttributeTypeConverter<AttributeType, VBOType>;
BMIter f_iter;
BMFace *efa;
@@ -255,10 +230,10 @@ static void fill_vertbuf_with_attribute_bm(const MeshRenderData *mr,
attr_data = static_cast<const AttributeType *>(BM_ELEM_CD_GET_VOID_P(l_iter->e, cd_ofs));
}
else {
- BLI_assert(false);
+ BLI_assert_unreachable();
continue;
}
- *vbo_data = converter::convert_value(*attr_data);
+ *vbo_data = Converter::convert_value(*attr_data);
vbo_data++;
} while ((l_iter = l_iter->next) != l_first);
}
@@ -279,55 +254,44 @@ static void extract_attr_generic(const MeshRenderData *mr,
}
}
-static void extract_attr_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(tls_data),
- int index)
+static void extract_attr_init(
+ const MeshRenderData *mr, MeshBatchCache *cache, void *buf, void *UNUSED(tls_data), int index)
{
const DRW_Attributes *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));
+ init_vbo_for_attribute(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: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, vbo, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, vbo, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, vbo, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
}
@@ -353,46 +317,42 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop));
switch (request.cd_type) {
- case CD_PROP_BOOL: {
+ case CD_PROP_BOOL:
extract_attr_generic<bool, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT8: {
+ case CD_PROP_INT8:
extract_attr_generic<int8_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_INT32: {
+ case CD_PROP_INT32:
extract_attr_generic<int32_t, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT: {
+ case CD_PROP_FLOAT:
extract_attr_generic<float, float3>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT2: {
+ case CD_PROP_FLOAT2:
extract_attr_generic<float2>(mr, src_data, request);
break;
- }
- case CD_PROP_FLOAT3: {
+ case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, src_data, request);
break;
- }
- case CD_PROP_COLOR: {
+ case CD_PROP_COLOR:
extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
break;
- }
- default: {
- BLI_assert(false);
- }
+ default:
+ BLI_assert_unreachable();
}
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops);
+ init_vbo_for_attribute(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, false);
+ draw_subdiv_interp_custom_data(subdiv_cache,
+ src_data,
+ dst_buffer,
+ static_cast<int>(dimensions),
+ 0,
+ request.cd_type == CD_PROP_COLOR);
GPU_vertbuf_discard(src_data);
}
@@ -401,13 +361,13 @@ static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
* 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) \
+ const MeshRenderData *mr, 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, \
+ MeshBatchCache *cache, \
void *buf, \
void *tls_data) \
{ \
@@ -430,7 +390,7 @@ EXTRACT_INIT_WRAPPER(12)
EXTRACT_INIT_WRAPPER(13)
EXTRACT_INIT_WRAPPER(14)
-template<int index>
+template<int Index>
constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn)
{
MeshExtract extractor = {nullptr};
@@ -439,7 +399,7 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
- extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[index]);
+ extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.attr[Index]);
return extractor;
}
@@ -447,7 +407,6 @@ constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivF
} // 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)
@@ -469,4 +428,3 @@ const MeshExtract extract_attr[GPU_MAX_ATTR] = {
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 f3b41efe1c3..eb6e800023a 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
@@ -10,7 +10,7 @@
#include "GPU_capabilities.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -43,7 +43,7 @@ static float loop_edge_factor_get(const float f_no[3],
}
static void extract_edge_fac_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -167,7 +167,7 @@ static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr,
}
static void extract_edge_fac_finish(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *_data)
{
@@ -218,7 +218,7 @@ static GPUVertFormat *get_subdiv_edge_fac_format()
static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -303,6 +303,4 @@ constexpr MeshExtract create_extractor_edge_fac()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edge_fac = blender::draw::create_extractor_edge_fac();
-}
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 1e158a7e6d7..27fd6546b8c 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
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -112,7 +112,7 @@ static GPUVertFormat *get_edit_data_format()
}
static void extract_edit_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -367,6 +367,4 @@ constexpr MeshExtract create_extractor_edit_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edit_data = blender::draw::create_extractor_edit_data();
-}
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 f79fe345f5a..0b9043e3289 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
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -43,7 +43,7 @@ static void extract_edituv_data_init_common(const MeshRenderData *mr,
}
static void extract_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -199,6 +199,4 @@ constexpr MeshExtract create_extractor_edituv_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_data = blender::draw::create_extractor_edituv_data();
-}
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 fb4b95885fc..969ff9f6f09 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
@@ -9,7 +9,7 @@
#include "BKE_mesh.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -74,7 +74,7 @@ static void edituv_get_edituv_stretch_angle(float auv[2][2],
}
static void extract_edituv_stretch_angle_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -212,7 +212,7 @@ static GPUVertFormat *get_edituv_stretch_angle_format_subdiv()
static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(tls_data))
{
@@ -292,7 +292,5 @@ constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_stretch_angle =
blender::draw::create_extractor_edituv_edituv_stretch_angle();
-}
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 ab397cc1717..2bb786303c4 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
@@ -9,7 +9,7 @@
#include "BKE_mesh.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -20,7 +20,7 @@ namespace blender::draw {
* \{ */
static void extract_edituv_stretch_area_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -89,7 +89,7 @@ static void compute_area_ratio(const MeshRenderData *mr,
}
static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(data))
{
@@ -131,7 +131,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_edituv_stretch_area()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_edituv_stretch_area =
blender::draw::create_extractor_edituv_stretch_area();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
index 1c4f6112877..27d1975d67b 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_edituv_data.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_cache_impl.h"
@@ -21,7 +21,7 @@ struct MeshExtract_EditUVFdotData_Data {
};
static void extract_fdots_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -81,6 +81,4 @@ constexpr MeshExtract create_extractor_fdots_edituv_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_edituv_data = blender::draw::create_extractor_fdots_edituv_data();
-}
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 909c9ac2300..c2af7f2c9bd 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
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ namespace blender::draw {
#define NOR_AND_FLAG_HIDDEN -2
static void extract_fdots_nor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -34,7 +34,7 @@ static void extract_fdots_nor_init(const MeshRenderData *mr,
}
static void extract_fdots_nor_finish(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(data))
{
@@ -101,7 +101,7 @@ constexpr MeshExtract create_extractor_fdots_nor()
* \{ */
static void extract_fdots_nor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -116,7 +116,7 @@ static void extract_fdots_nor_hq_init(const MeshRenderData *mr,
}
static void extract_fdots_nor_hq_finish(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(data))
{
@@ -180,7 +180,5 @@ constexpr MeshExtract create_extractor_fdots_nor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_nor = blender::draw::create_extractor_fdots_nor();
const MeshExtract extract_fdots_nor_hq = blender::draw::create_extractor_fdots_nor_hq();
-}
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 1671a1cd1e7..c391cb6ca5a 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
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -36,7 +36,7 @@ static GPUVertFormat *get_fdots_nor_format_subdiv()
}
static void extract_fdots_pos_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -101,7 +101,7 @@ 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,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -139,6 +139,4 @@ constexpr MeshExtract create_extractor_fdots_pos()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_pos = blender::draw::create_extractor_fdots_pos();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
index e7a3cb03903..b0403cf7c4c 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_uv.cc
@@ -7,7 +7,7 @@
#include "BLI_bitmap.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -22,7 +22,7 @@ struct MeshExtract_FdotUV_Data {
};
static void extract_fdots_uv_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -109,6 +109,4 @@ constexpr MeshExtract create_extractor_fdots_uv()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_fdots_uv = blender::draw::create_extractor_fdots_uv();
-}
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 8bc8b32fdf3..ac517269e7d 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
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -16,7 +16,7 @@ namespace blender::draw {
* \{ */
static void extract_lnor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -105,7 +105,7 @@ static GPUVertFormat *get_subdiv_lnor_format()
static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -141,7 +141,7 @@ struct gpuHQNor {
};
static void extract_lnor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -234,7 +234,5 @@ constexpr MeshExtract create_extractor_lnor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_lnor = blender::draw::create_extractor_lnor();
const MeshExtract extract_lnor_hq = blender::draw::create_extractor_lnor_hq();
-}
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 968c1f693fb..951990466d0 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
@@ -14,7 +14,7 @@
#include "BKE_editmesh_bvh.h"
#include "BKE_editmesh_cache.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -23,7 +23,7 @@ namespace blender::draw {
* \{ */
static void extract_mesh_analysis_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -587,7 +587,7 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
}
static void extract_analysis_iter_finish_mesh(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(data))
{
@@ -633,6 +633,4 @@ constexpr MeshExtract create_extractor_mesh_analysis()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_mesh_analysis = blender::draw::create_extractor_mesh_analysis();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
index 94674a54f12..4fcbdb1fc7c 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_orco.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ struct MeshExtract_Orco_Data {
};
static void extract_orco_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -94,6 +94,4 @@ constexpr MeshExtract create_extractor_orco()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_orco = blender::draw::create_extractor_orco();
-}
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 f80b33e28f2..9788beabeb5 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
@@ -7,7 +7,7 @@
#include "MEM_guardedalloc.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -28,7 +28,7 @@ struct MeshExtract_PosNor_Data {
};
static void extract_pos_nor_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -171,7 +171,7 @@ static void extract_pos_nor_iter_lvert_mesh(const MeshRenderData *mr,
}
static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *_data)
{
@@ -201,7 +201,7 @@ static GPUVertFormat *get_custom_normals_format()
static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -234,7 +234,7 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh;
- const float(*lnors)[3] = static_cast<float(*)[3]>(
+ const float(*lnors)[3] = static_cast<const float(*)[3]>(
CustomData_get_layer(&coarse_mesh->ldata, CD_NORMAL));
BLI_assert(lnors != nullptr);
@@ -372,7 +372,7 @@ struct MeshExtract_PosNorHQ_Data {
};
static void extract_pos_nor_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -521,7 +521,7 @@ static void extract_pos_nor_hq_iter_lvert_mesh(const MeshRenderData *mr,
}
static void extract_pos_nor_hq_finish(const MeshRenderData *UNUSED(mr),
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *_data)
{
@@ -552,7 +552,5 @@ constexpr MeshExtract create_extractor_pos_nor_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_pos_nor = blender::draw::create_extractor_pos_nor();
const MeshExtract extract_pos_nor_hq = blender::draw::create_extractor_pos_nor_hq();
-}
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 5658ed85c8b..492721b4853 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
@@ -12,7 +12,7 @@
#include "BKE_paint.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -31,7 +31,7 @@ static GPUVertFormat *get_sculpt_data_format()
}
static void extract_sculpt_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -113,7 +113,7 @@ 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),
+ MeshBatchCache *UNUSED(cache),
void *buffer,
void *UNUSED(data))
{
@@ -215,6 +215,4 @@ constexpr MeshExtract create_extractor_sculpt_data()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_sculpt_data = blender::draw::create_extractor_sculpt_data();
-}
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 f4c54b2f881..9e0d171c9e4 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
@@ -6,7 +6,7 @@
*/
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -30,7 +30,7 @@ static void extract_select_idx_init_impl(const MeshRenderData *UNUSED(mr),
}
static void extract_select_idx_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -366,7 +366,7 @@ constexpr MeshExtract create_extractor_vert_idx()
}
static void extract_fdot_idx_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *tls_data)
{
@@ -411,9 +411,7 @@ constexpr MeshExtract create_extractor_fdot_idx()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_poly_idx = blender::draw::create_extractor_poly_idx();
const MeshExtract extract_edge_idx = blender::draw::create_extractor_edge_idx();
const MeshExtract extract_vert_idx = blender::draw::create_extractor_vert_idx();
const MeshExtract extract_fdot_idx = blender::draw::create_extractor_fdot_idx();
-}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
index bb6331dd377..f7655658bdd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_skin_roots.cc
@@ -5,7 +5,7 @@
* \ingroup draw
*/
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ struct SkinRootData {
};
static void extract_skin_roots_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
+ MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
@@ -72,6 +72,4 @@ constexpr MeshExtract create_extractor_skin_roots()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_skin_roots = blender::draw::create_extractor_skin_roots();
-}
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 91cd675d32f..049fa416523 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
@@ -14,7 +14,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_tangent.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
#include "draw_subdivision.h"
@@ -25,7 +25,7 @@ namespace blender::draw {
* \{ */
static void extract_tan_init_common(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
GPUVertFormat *format,
GPUVertCompType comp_type,
GPUVertFetchMode fetch_mode,
@@ -161,7 +161,7 @@ static void extract_tan_init_common(const MeshRenderData *mr,
}
static void extract_tan_ex_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
GPUVertBuf *vbo,
const bool do_hq)
{
@@ -235,7 +235,7 @@ static void extract_tan_ex_init(const MeshRenderData *mr,
}
static void extract_tan_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
@@ -254,7 +254,7 @@ static GPUVertFormat *get_coarse_tan_format()
static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -344,7 +344,7 @@ constexpr MeshExtract create_extractor_tan()
* \{ */
static void extract_tan_hq_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
@@ -367,7 +367,5 @@ constexpr MeshExtract create_extractor_tan_hq()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_tan = blender::draw::create_extractor_tan();
const MeshExtract extract_tan_hq = blender::draw::create_extractor_tan_hq();
-}
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 2808a0a3a71..6606912850d 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
@@ -8,7 +8,7 @@
#include "BLI_string.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -19,7 +19,7 @@ namespace blender::draw {
/* 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,
+ MeshBatchCache *cache,
CustomData *cd_ldata,
eMRExtractType extract_type,
uint32_t &r_uv_layers)
@@ -72,7 +72,7 @@ static bool mesh_extract_uv_format_init(GPUVertFormat *format,
}
static void extract_uv_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
@@ -120,7 +120,7 @@ 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,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
@@ -168,6 +168,4 @@ constexpr MeshExtract create_extractor_uv()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_uv = blender::draw::create_extractor_uv();
-}
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 fa5bf35198b..419cbb0267f 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
@@ -12,11 +12,13 @@
#include "BLI_vector.hh"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
+
+namespace blender::draw {
struct VColRef {
const CustomDataLayer *layer;
- AttributeDomain domain;
+ eAttrDomain domain;
};
/** Get all vcol layers as AttributeRefs.
@@ -25,14 +27,14 @@ struct VColRef {
* corresponds to the integer position of the attribute
* within the global color attribute list.
*/
-static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
- const CustomData *cd_ldata,
- const uint vcol_layers)
+static Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
+ const CustomData *cd_ldata,
+ const uint vcol_layers)
{
- blender::Vector<VColRef> refs;
+ Vector<VColRef> refs;
uint layeri = 0;
- auto buildList = [&](const CustomData *cdata, AttributeDomain domain) {
+ auto buildList = [&](const CustomData *cdata, eAttrDomain domain) {
for (int i = 0; i < cdata->totlayer; i++) {
const CustomDataLayer *layer = cdata->layers + i;
@@ -64,8 +66,6 @@ static blender::Vector<VColRef> get_vcol_refs(const CustomData *cd_vdata,
return refs;
}
-namespace blender::draw {
-
/* ---------------------------------------------------------------------- */
/** \name Extract VCol
* \{ */
@@ -73,16 +73,16 @@ namespace blender::draw {
/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
static void init_vcol_format(GPUVertFormat *format,
const MeshBatchCache *cache,
- CustomData *cd_vdata,
- CustomData *cd_ldata,
- CustomDataLayer *active,
- CustomDataLayer *render)
+ const CustomData *cd_vdata,
+ const CustomData *cd_ldata,
+ const CustomDataLayer *active,
+ const CustomDataLayer *render)
{
GPU_vertformat_deinterleave(format);
const uint32_t vcol_layers = cache->cd_used.vcol;
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
for (const VColRef &ref : refs) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
@@ -111,35 +111,37 @@ 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_attr_add(&format, "cCol", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_alias_add(&format, "c");
GPU_vertformat_alias_add(&format, "ac");
}
return &format;
}
-using gpuMeshVcol = struct gpuMeshVcol {
+struct gpuMeshVcol {
ushort r, g, b, a;
};
static void extract_vcol_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
GPUVertFormat format = {0};
- CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ const CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata :
+ &mr->me->vdata;
+ const CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata :
+ &mr->me->ldata;
Mesh me_query = blender::dna::shallow_zero_initialize();
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
const uint32_t vcol_layers = cache->cd_used.vcol;
init_vcol_format(&format, cache, cd_vdata, cd_ldata, active_color, render_color);
@@ -149,10 +151,10 @@ static void extract_vcol_init(const MeshRenderData *mr,
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
for (const VColRef &ref : refs) {
- CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
+ const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
if (mr->extract_type == MR_EXTRACT_BMESH) {
int cd_ofs = ref.layer->offset;
@@ -168,10 +170,10 @@ static void extract_vcol_init(const MeshRenderData *mr,
BMFace *f;
BM_ITER_MESH (f, &iter, mr->bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter = f->l_first;
+ const BMLoop *l_iter = f->l_first;
do {
- BMElem *elem = is_point ? reinterpret_cast<BMElem *>(l_iter->v) :
- reinterpret_cast<BMElem *>(l_iter);
+ const BMElem *elem = is_point ? reinterpret_cast<const BMElem *>(l_iter->v) :
+ reinterpret_cast<const BMElem *>(l_iter);
if (is_byte) {
const MLoopCol *mloopcol = (const MLoopCol *)BM_ELEM_CD_GET_VOID_P(elem, cd_ofs);
vcol_data->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
@@ -193,17 +195,17 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
else {
int totloop = mr->loop_len;
- int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
+ const int idx = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
- MLoopCol *mcol = nullptr;
- MPropCol *pcol = nullptr;
+ const MLoopCol *mcol = nullptr;
+ const MPropCol *pcol = nullptr;
const MLoop *mloop = mr->mloop;
if (ref.layer->type == CD_PROP_COLOR) {
- pcol = static_cast<MPropCol *>(cdata->layers[idx].data);
+ pcol = static_cast<const MPropCol *>(cdata->layers[idx].data);
}
else {
- mcol = static_cast<MLoopCol *>(cdata->layers[idx].data);
+ mcol = static_cast<const MLoopCol *>(cdata->layers[idx].data);
}
const bool is_corner = ref.domain == ATTR_DOMAIN_CORNER;
@@ -232,12 +234,12 @@ static void extract_vcol_init(const MeshRenderData *mr,
static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
{
GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
- Mesh *coarse_mesh = subdiv_cache->mesh;
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
bool extract_bmesh = mr->extract_type == MR_EXTRACT_BMESH;
@@ -245,13 +247,14 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
&coarse_mesh->vdata;
const CustomData *cd_ldata = extract_bmesh ? &coarse_mesh->edit_mesh->bm->ldata :
&coarse_mesh->ldata;
+ const int totloop = extract_bmesh ? coarse_mesh->edit_mesh->bm->totloop : coarse_mesh->totloop;
Mesh me_query = blender::dna::shallow_copy(*coarse_mesh);
BKE_id_attribute_copy_domains_temp(
ID_ME, cd_vdata, nullptr, cd_ldata, nullptr, nullptr, &me_query.id);
- CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active_color = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render_color = BKE_id_attributes_render_color_get(&me_query.id);
GPUVertFormat format = {0};
init_vcol_format(
@@ -263,13 +266,13 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
/* 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);
+ GPU_vertbuf_data_alloc(src_data, totloop);
gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data);
const uint vcol_layers = cache->cd_used.vcol;
- blender::Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
+ Vector<VColRef> refs = get_vcol_refs(cd_vdata, cd_ldata, vcol_layers);
/* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
* a single buffer. */
@@ -279,8 +282,6 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++;
const CustomData *cdata = ref.domain == ATTR_DOMAIN_POINT ? cd_vdata : cd_ldata;
- const MLoop *ml = coarse_mesh->mloop;
-
int layer_i = CustomData_get_named_layer_index(cdata, ref.layer->type, ref.layer->name);
if (layer_i == -1) {
@@ -289,15 +290,6 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
gpuMeshVcol *vcol = mesh_vcol;
- MLoopCol *mcol = nullptr;
- MPropCol *pcol = nullptr;
-
- if (ref.layer->type == CD_PROP_COLOR) {
- pcol = static_cast<MPropCol *>(cdata->layers[layer_i].data);
- }
- else {
- mcol = static_cast<MLoopCol *>(cdata->layers[layer_i].data);
- }
const bool is_vert = ref.domain == ATTR_DOMAIN_POINT;
@@ -309,14 +301,15 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
const bool is_byte = ref.layer->type == CD_PROP_BYTE_COLOR;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- BMLoop *l_iter = f->l_first;
+ const BMLoop *l_iter = f->l_first;
do {
- BMElem *elem = is_vert ? reinterpret_cast<BMElem *>(l_iter->v) :
- reinterpret_cast<BMElem *>(l_iter);
+ const BMElem *elem = is_vert ? reinterpret_cast<const BMElem *>(l_iter->v) :
+ reinterpret_cast<const BMElem *>(l_iter);
if (is_byte) {
- MLoopCol *mcol2 = static_cast<MLoopCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
+ const MLoopCol *mcol2 = static_cast<const MLoopCol *>(
+ BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
@@ -324,17 +317,31 @@ static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
vcol->a = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
}
else {
- MPropCol *pcol2 = static_cast<MPropCol *>(BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
+ const MPropCol *pcol2 = static_cast<const MPropCol *>(
+ BM_ELEM_CD_GET_VOID_P(elem, cd_ofs));
vcol->r = unit_float_to_ushort_clamp(pcol2->color[0]);
vcol->g = unit_float_to_ushort_clamp(pcol2->color[1]);
vcol->b = unit_float_to_ushort_clamp(pcol2->color[2]);
vcol->a = unit_float_to_ushort_clamp(pcol2->color[3]);
}
+
+ vcol++;
} while ((l_iter = l_iter->next) != f->l_first);
}
}
else {
+ const MLoop *ml = coarse_mesh->mloop;
+ const MLoopCol *mcol = nullptr;
+ const MPropCol *pcol = nullptr;
+
+ if (ref.layer->type == CD_PROP_COLOR) {
+ pcol = static_cast<const MPropCol *>(cdata->layers[layer_i].data);
+ }
+ else {
+ mcol = static_cast<const MLoopCol *>(cdata->layers[layer_i].data);
+ }
+
for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, ml++) {
int idx = is_vert ? ml->v : ml_index;
@@ -377,6 +384,4 @@ constexpr MeshExtract create_extractor_vcol()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_vcol = blender::draw::create_extractor_vcol();
-}
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 89aa16ca0c7..ba194a4b167 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
@@ -10,7 +10,7 @@
#include "BKE_deform.h"
#include "draw_subdivision.h"
-#include "extract_mesh.h"
+#include "extract_mesh.hh"
namespace blender::draw {
@@ -79,7 +79,7 @@ static float evaluate_vertex_weight(const MDeformVert *dvert, const DRW_MeshWeig
}
static void extract_weights_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buf,
void *tls_data)
{
@@ -154,7 +154,7 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *mr,
- struct MeshBatchCache *cache,
+ MeshBatchCache *cache,
void *buffer,
void *_data)
{
@@ -208,6 +208,4 @@ constexpr MeshExtract create_extractor_weights()
} // namespace blender::draw
-extern "C" {
const MeshExtract extract_weights = blender::draw::create_extractor_weights();
-}
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index dfa2f307800..b82df4a51dc 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -5,6 +5,8 @@
* of data the CPU has to precompute and transfer for each update.
*/
+#define COMMON_HAIR_LIB
+
/* TODO(fclem): Keep documentation but remove the uniform declaration. */
#ifndef USE_GPU_SHADER_CREATE_INFO
@@ -162,16 +164,15 @@ float hair_shaperadius(float shape, float root, float tip, float time)
in float dummy;
# endif
-void hair_get_pos_tan_binor_time(bool is_persp,
- mat4 invmodel_mat,
- vec3 camera_pos,
- vec3 camera_z,
- out vec3 wpos,
- out vec3 wtan,
- out vec3 wbinor,
- out float time,
- out float thickness,
- out float thick_time)
+void hair_get_center_pos_tan_binor_time(bool is_persp,
+ mat4 invmodel_mat,
+ vec3 camera_pos,
+ vec3 camera_z,
+ out vec3 wpos,
+ out vec3 wtan,
+ out vec3 wbinor,
+ out float time,
+ out float thickness)
{
int id = hair_get_base_id();
vec4 data = texelFetch(hairPointBuffer, id);
@@ -200,15 +201,27 @@ void hair_get_pos_tan_binor_time(bool is_persp,
wbinor = normalize(cross(camera_vec, wtan));
thickness = hair_shaperadius(hairRadShape, hairRadRoot, hairRadTip, time);
+}
+void hair_get_pos_tan_binor_time(bool is_persp,
+ mat4 invmodel_mat,
+ vec3 camera_pos,
+ vec3 camera_z,
+ out vec3 wpos,
+ out vec3 wtan,
+ out vec3 wbinor,
+ out float time,
+ out float thickness,
+ out float thick_time)
+{
+ hair_get_center_pos_tan_binor_time(
+ is_persp, invmodel_mat, camera_pos, camera_z, wpos, wtan, wbinor, time, thickness);
if (hairThicknessRes > 1) {
thick_time = float(gl_VertexID % hairThicknessRes) / float(hairThicknessRes - 1);
thick_time = thickness * (thick_time * 2.0 - 1.0);
-
/* Take object scale into account.
* NOTE: This only works fine with uniform scaling. */
float scale = 1.0 / length(mat3(invmodel_mat) * wbinor);
-
wpos += wbinor * thick_time * scale;
}
else {
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
index 3244b7960d8..eacdf8e6333 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
@@ -35,7 +35,7 @@ void emit_line(uint line_offset, uint quad_index, uint start_loop_index, uint co
uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
coarse_poly_count);
- if (is_face_hidden(coarse_quad_index) ||
+ if (use_hide && is_face_hidden(coarse_quad_index) ||
(input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display)) {
output_lines[line_offset + 0] = 0xffffffff;
output_lines[line_offset + 1] = 0xffffffff;
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
index ce3c8478d3f..a46d69eca88 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
@@ -45,7 +45,7 @@ void main()
int triangle_loop_index = (int(quad_index) + mat_offset) * 6;
#endif
- if (is_face_hidden(coarse_quad_index)) {
+ if (use_hide && is_face_hidden(coarse_quad_index)) {
output_tris[triangle_loop_index + 0] = 0xffffffff;
output_tris[triangle_loop_index + 1] = 0xffffffff;
output_tris[triangle_loop_index + 2] = 0xffffffff;
diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
index 55e4ac20271..4183b4a1cd3 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
@@ -36,6 +36,10 @@ layout(std140) uniform shader_data
/* Total number of elements to process. */
uint total_dispatch_size;
+
+ bool is_edit_mode;
+
+ bool use_hide;
};
uint get_global_invocation_index()
@@ -139,20 +143,20 @@ void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos)
vertex_data.z = pos.z;
}
-void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint 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)
{
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)
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, float flag)
{
- set_vertex_nor(vertex_data, nor, 0);
+ set_vertex_nor(vertex_data, nor);
+ vertex_data.flag = flag;
}
void add_newell_cross_v3_v3v3(inout vec3 n, vec3 v_prev, vec3 v_curr)
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
index 0ffb216fc6f..81e346863c2 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -427,7 +427,7 @@ void main()
output_nors[coarse_quad_index] = fnor;
# endif
- if (is_face_hidden(coarse_quad_index)) {
+ if (use_hide && is_face_hidden(coarse_quad_index)) {
output_indices[coarse_quad_index] = 0xffffffff;
}
else {
@@ -459,9 +459,9 @@ void main()
vec3 nor = vec3(0.0);
int origindex = input_vert_origindex[loop_index];
- uint flag = 0;
+ float flag = 0.0;
if (origindex == -1) {
- flag = -1;
+ flag = -1.0;
}
PosNorLoop vertex_data;
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
index b7bcfd2d369..97c07704c06 100644
--- a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
@@ -11,7 +11,12 @@ layout(std430, binding = 2) readonly buffer extraCoarseFaceData
uint extra_coarse_face_data[];
};
-layout(std430, binding = 3) writeonly buffer outputLoopNormals
+layout(std430, binding = 3) readonly buffer inputVertOrigIndices
+{
+ int input_vert_origindex[];
+};
+
+layout(std430, binding = 4) writeonly buffer outputLoopNormals
{
LoopNormal output_lnor[];
};
@@ -21,6 +26,23 @@ bool is_face_selected(uint coarse_quad_index)
return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0;
}
+bool is_face_hidden(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_hidden_mask) != 0;
+}
+
+/* Flag for paint mode overlay and normals drawing in edit-mode. */
+float get_loop_flag(uint coarse_quad_index, int vert_origindex)
+{
+ if (is_face_hidden(coarse_quad_index) || (is_edit_mode && vert_origindex == -1)) {
+ return -1.0;
+ }
+ if (is_face_selected(coarse_quad_index)) {
+ return 1.0;
+ }
+ return 0.0;
+}
+
void main()
{
/* We execute for each quad. */
@@ -39,7 +61,11 @@ void main()
/* 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_normal_and_flag(pos_nor_loop);
+ int origindex = input_vert_origindex[start_loop_index + i];
+ LoopNormal loop_normal = get_normal_and_flag(pos_nor_loop);
+ loop_normal.flag = get_loop_flag(coarse_quad_index, origindex);
+
+ output_lnor[start_loop_index + i] = loop_normal;
}
}
else {
@@ -60,13 +86,11 @@ void main()
loop_normal.nx = face_normal.x;
loop_normal.ny = face_normal.y;
loop_normal.nz = face_normal.z;
- loop_normal.flag = 0.0;
-
- if (is_face_selected(coarse_quad_index)) {
- loop_normal.flag = 1.0;
- }
for (int i = 0; i < 4; i++) {
+ int origindex = input_vert_origindex[start_loop_index + i];
+ loop_normal.flag = get_loop_flag(coarse_quad_index, origindex);
+
output_lnor[start_loop_index + i] = loop_normal;
}
}
diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc
index 2bc0c9af895..e7baac63aae 100644
--- a/source/blender/draw/tests/shaders_test.cc
+++ b/source/blender/draw/tests/shaders_test.cc
@@ -256,6 +256,7 @@ static void test_overlay_glsl_shaders()
EXPECT_NE(OVERLAY_shader_uniform_color(), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass(false), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass(true), nullptr);
+ EXPECT_NE(OVERLAY_shader_outline_prepass_curves(), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass_gpencil(), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass_pointcloud(), nullptr);
EXPECT_NE(OVERLAY_shader_extra_grid(), nullptr);
@@ -270,6 +271,7 @@ static void test_overlay_glsl_shaders()
EXPECT_NE(OVERLAY_shader_particle_dot(), nullptr);
EXPECT_NE(OVERLAY_shader_particle_shape(), nullptr);
EXPECT_NE(OVERLAY_shader_sculpt_mask(), nullptr);
+ EXPECT_NE(OVERLAY_shader_sculpt_curves_selection(), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(false, false), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(false, true), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(true, false), nullptr);
@@ -397,6 +399,7 @@ static void test_basic_glsl_shaders()
eGPUShaderConfig sh_cfg = static_cast<eGPUShaderConfig>(i);
BASIC_shaders_depth_sh_get(sh_cfg);
BASIC_shaders_pointcloud_depth_sh_get(sh_cfg);
+ BASIC_shaders_curves_depth_sh_get(sh_cfg);
BASIC_shaders_depth_conservative_sh_get(sh_cfg);
BASIC_shaders_pointcloud_depth_conservative_sh_get(sh_cfg);
}
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index c2d517588b2..729e8533d50 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -3123,7 +3123,7 @@ static bAnimChannelType ACF_DSSIMULATION = {
/* TODO: just get this from RNA? */
static int acf_dsgpencil_icon(bAnimListElem *UNUSED(ale))
{
- return ICON_GREASEPENCIL;
+ return ICON_OUTLINER_DATA_GREASEPENCIL;
}
/* Get the appropriate flag(s) for the setting when it is valid. */
@@ -4351,15 +4351,15 @@ void ANIM_channel_setting_set(bAnimContext *ac,
/* --------------------------- */
-/* size of icons */
+/** Size of icons. */
#define ICON_WIDTH (0.85f * U.widget_unit)
-/* width of sliders */
+/** Width of sliders. */
#define SLIDER_WIDTH (4 * U.widget_unit)
-/* min-width of rename textboxes */
+/** Min-width of rename text-boxes. */
#define RENAME_TEXT_MIN_WIDTH (U.widget_unit)
-/* width of graph editor color bands */
+/** Width of graph editor color bands. */
#define GRAPH_COLOR_BAND_WIDTH (0.3f * U.widget_unit)
-/* extra offset for the visibility icons in the graph editor */
+/** Extra offset for the visibility icons in the graph editor. */
#define GRAPH_ICON_VISIBILITY_OFFSET (GRAPH_COLOR_BAND_WIDTH * 1.5f)
/* Helper - Check if a channel needs renaming */
@@ -4747,13 +4747,13 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
RNA_id_pointer_create(id, &id_ptr);
/* Get NLA context for value remapping */
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(
&nla_cache, &id_ptr, adt, &anim_eval_context);
/* get current frame and apply NLA-mapping to it (if applicable) */
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
/* Get flags for keyframing. */
flag = ANIM_get_keyframing_flags(scene, true);
@@ -4803,8 +4803,8 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
RNA_id_pointer_create((ID *)key, &id_ptr);
/* Get NLA context for value remapping */
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(
&nla_cache, &id_ptr, key->adt, &anim_eval_context);
@@ -4872,7 +4872,7 @@ static void achannel_setting_slider_nla_curve_cb(bContext *C,
float cfra;
/* get current frame - *no* NLA mapping should be done */
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
/* get flags for keyframing */
flag = ANIM_get_keyframing_flags(scene, true);
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index f148bb5b77d..8464f280c29 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -711,14 +711,14 @@ static bool animedit_poll_channels_active(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* Poll callback for Animation Editor channels list region + not in NLA-tweak-mode for NLA. */
@@ -730,21 +730,21 @@ static bool animedit_poll_channels_nla_tweakmode_off(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
- return 0;
+ return false;
}
/* NLA tweak-mode test. */
if (area->spacetype == SPACE_NLA) {
if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) {
- return 0;
+ return false;
}
}
- return 1;
+ return true;
}
/* ****************** Rearrange Channels Operator ******************* */
@@ -791,7 +791,7 @@ static bool rearrange_island_ok(tReorderChannelIsland *island)
{
/* island must not be untouchable */
if (island->flag & REORDER_ISLAND_UNTOUCHABLE) {
- return 0;
+ return false;
}
/* island should be selected to be moved */
@@ -809,10 +809,10 @@ static bool rearrange_island_top(ListBase *list, tReorderChannelIsland *island)
/* make it first element */
BLI_insertlinkbefore(list, list->first, island);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
@@ -833,11 +833,11 @@ static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
/* push it up */
BLI_insertlinkbefore(list, prev, island);
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island)
@@ -1083,7 +1083,7 @@ static bool rearrange_animchannel_islands(ListBase *list,
/* don't waste effort on an empty list */
if (BLI_listbase_is_empty(list)) {
- return 0;
+ return false;
}
/* group channels into islands */
@@ -1589,7 +1589,7 @@ static bool animchannels_grouping_poll(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test - must be suitable modes only */
@@ -1602,7 +1602,7 @@ static bool animchannels_grouping_poll(bContext *C)
/* dopesheet and action only - all others are for other datatypes or have no groups */
if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0) {
- return 0;
+ return false;
}
break;
@@ -1612,17 +1612,17 @@ static bool animchannels_grouping_poll(bContext *C)
/* drivers can't have groups... */
if (sipo->mode != SIPO_MODE_ANIMATION) {
- return 0;
+ return false;
}
break;
}
/* unsupported... */
default:
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* ----------------------------------------------------------- */
@@ -2033,7 +2033,7 @@ static void setflag_anim_channels(bAnimContext *ac,
if ((ac->spacetype == SPACE_GRAPH) && (ac->regiontype != RGN_TYPE_CHANNELS)) {
/* graph editor (case 2) */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
}
else {
/* standard case */
@@ -2428,15 +2428,15 @@ static bool animchannels_enable_poll(bContext *C)
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, area, CTX_wm_region(C))) {
- return 0;
+ return false;
}
/* animation editor test - Action/Dopesheet/etc. and Graph only */
if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op))
@@ -2504,7 +2504,7 @@ static bool animchannels_select_filter_poll(bContext *C)
ScrArea *area = CTX_wm_area(C);
if (area == NULL) {
- return 0;
+ return false;
}
/* animation editor with dopesheet */
@@ -2791,13 +2791,35 @@ static bool rename_anim_channels(bAnimContext *ac, int channel_index)
return false;
}
- /* don't allow renaming linked channels */
- if ((ale->fcurve_owner_id != NULL &&
- (ID_IS_LINKED(ale->fcurve_owner_id) || ID_IS_OVERRIDE_LIBRARY(ale->fcurve_owner_id))) ||
- (ale->id != NULL && (ID_IS_LINKED(ale->id) || ID_IS_OVERRIDE_LIBRARY(ale->id)))) {
+ /* Don't allow renaming linked/liboverride channels. */
+ if (ale->fcurve_owner_id != NULL &&
+ (ID_IS_LINKED(ale->fcurve_owner_id) || ID_IS_OVERRIDE_LIBRARY(ale->fcurve_owner_id))) {
ANIM_animdata_freelist(&anim_data);
return false;
}
+ if (ale->id != NULL) {
+ if (ID_IS_LINKED(ale->id)) {
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ /* There is one exception to not allowing renaming on liboverride channels: locally-inserted
+ * NLA tracks. */
+ if (ID_IS_OVERRIDE_LIBRARY(ale->id)) {
+ switch (ale->type) {
+ case ANIMTYPE_NLATRACK: {
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ if ((nlt->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) == 0) {
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ break;
+ }
+ default:
+ ANIM_animdata_freelist(&anim_data);
+ return false;
+ }
+ }
+ }
/* check that channel can be renamed */
acf = ANIM_channel_get_typeinfo(ale);
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index d80eac2422e..ff53ad42e84 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -356,7 +356,7 @@ void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
if (ale->update & ANIM_UPDATE_HANDLES) {
ale->update &= ~ANIM_UPDATE_HANDLES;
if (fcu) {
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
}
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index ee1522c7b76..d9dcbf1d57e 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -120,9 +120,9 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d)
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
- if (SFRA < EFRA) {
- immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
- immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ if (scene->r.sfra < scene->r.efra) {
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)scene->r.sfra, v2d->cur.ymax);
+ immRectf(pos, (float)scene->r.efra, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
else {
immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
@@ -135,11 +135,11 @@ void ANIM_draw_framerange(Scene *scene, View2D *v2d)
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, (float)SFRA, v2d->cur.ymin);
- immVertex2f(pos, (float)SFRA, v2d->cur.ymax);
+ immVertex2f(pos, (float)scene->r.sfra, v2d->cur.ymin);
+ immVertex2f(pos, (float)scene->r.sfra, v2d->cur.ymax);
- immVertex2f(pos, (float)EFRA, v2d->cur.ymin);
- immVertex2f(pos, (float)EFRA, v2d->cur.ymax);
+ immVertex2f(pos, (float)scene->r.efra, v2d->cur.ymin);
+ immVertex2f(pos, (float)scene->r.efra, v2d->cur.ymax);
immEnd();
immUnbindProgram();
@@ -530,7 +530,7 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
bool donenext = false, doneprev = false;
int nextcount = 0, prevcount = 0;
- cfranext = cfraprev = (float)(CFRA);
+ cfranext = cfraprev = (float)(scene->r.cfra);
/* seed up dummy dopesheet context with flags to perform necessary filtering */
if ((scene->flag & SCE_KEYS_NO_SELONLY) == 0) {
@@ -559,7 +559,7 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
aknext = ED_keylist_find_next(keylist, cfranext);
if (aknext) {
- if (CFRA == (int)aknext->cfra) {
+ if (scene->r.cfra == (int)aknext->cfra) {
/* make this the new starting point for the search and ignore */
cfranext = aknext->cfra;
}
@@ -577,7 +577,7 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
akprev = ED_keylist_find_prev(keylist, cfraprev);
if (akprev) {
- if (CFRA == (int)akprev->cfra) {
+ if (scene->r.cfra == (int)akprev->cfra) {
/* make this the new starting point for the search */
}
else {
@@ -599,14 +599,14 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
*r_prevfra = cfraprev;
}
else {
- *r_prevfra = CFRA - (cfranext - CFRA);
+ *r_prevfra = scene->r.cfra - (cfranext - scene->r.cfra);
}
if (donenext) {
*r_nextfra = cfranext;
}
else {
- *r_nextfra = CFRA + (CFRA - cfraprev);
+ *r_nextfra = scene->r.cfra + (scene->r.cfra - cfraprev);
}
return true;
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index a75944fa2f2..d9eeed94868 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -1807,11 +1807,13 @@ static size_t animdata_filter_gpencil_data(ListBase *anim_data,
ListBase tmp_data = {NULL, NULL};
size_t tmp_items = 0;
- /* add gpencil animation channels */
- BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_GPD(gpd)) {
- tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
+ if (!(filter_mode & ANIMFILTER_FCURVESONLY)) {
+ /* add gpencil animation channels */
+ BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_GPD(gpd)) {
+ tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
+ }
+ END_ANIMFILTER_SUBCHANNELS;
}
- END_ANIMFILTER_SUBCHANNELS;
/* did we find anything? */
if (tmp_items) {
@@ -1925,6 +1927,9 @@ static size_t animdata_filter_ds_gpencil(
tmp_items += animfilter_block_data(ac, &tmp_data, ads, &gpd->id, filter_mode);
/* add Grease Pencil layers */
+ if (!(filter_mode & ANIMFILTER_FCURVESONLY)) {
+ tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
+ }
/* TODO: do these need a separate expander?
* XXX: what order should these go in? */
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 8519b2061f2..3608140a29d 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -104,7 +104,7 @@ int ED_markers_post_apply_transform(
ListBase *markers, Scene *scene, int mode, float value, char side)
{
TimeMarker *marker;
- float cfra = (float)CFRA;
+ float cfra = (float)scene->r.cfra;
int changed_tot = 0;
/* sanity check - no markers, or locked markers */
@@ -543,7 +543,6 @@ void ED_markers_draw(const bContext *C, int flag)
View2D *v2d = UI_view2d_fromcontext(C);
int cfra = CTX_data_scene(C)->r.cfra;
- const float line_width = GPU_line_width_get();
GPU_line_width(1.0f);
rctf markers_region_rect;
@@ -578,7 +577,6 @@ void ED_markers_draw(const bContext *C, int flag)
}
}
- GPU_line_width(line_width);
GPU_matrix_pop();
}
@@ -1499,8 +1497,8 @@ static void ED_markers_select_leftright(bAnimContext *ac,
}
LISTBASE_FOREACH (TimeMarker *, marker, markers) {
- if ((mode == MARKERS_LRSEL_LEFT && marker->frame <= CFRA) ||
- (mode == MARKERS_LRSEL_RIGHT && marker->frame >= CFRA)) {
+ if ((mode == MARKERS_LRSEL_LEFT && marker->frame <= scene->r.cfra) ||
+ (mode == MARKERS_LRSEL_RIGHT && marker->frame >= scene->r.cfra)) {
marker->flag |= SELECT;
}
}
@@ -1590,12 +1588,13 @@ static void MARKER_OT_delete(wmOperatorType *ot)
ot->idname = "MARKER_OT_delete";
/* api callbacks */
- ot->invoke = WM_operator_confirm;
+ ot->invoke = WM_operator_confirm_or_exec;
ot->exec = ed_marker_delete_exec;
ot->poll = ed_markers_poll_selected_no_locked_markers;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ WM_operator_properties_confirm_or_exec(ot);
}
/** \} */
@@ -1756,11 +1755,11 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- marker = ED_markers_find_nearest_marker(markers, CFRA);
- if ((marker == NULL) || (marker->frame != CFRA)) {
+ marker = ED_markers_find_nearest_marker(markers, scene->r.cfra);
+ if ((marker == NULL) || (marker->frame != scene->r.cfra)) {
marker = MEM_callocN(sizeof(TimeMarker), "Camera TimeMarker");
marker->flag = SELECT;
- marker->frame = CFRA;
+ marker->frame = scene->r.cfra;
BLI_addtail(markers, marker);
/* deselect all others, so that the user can then move it without problems */
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index b15bd3db678..23c1d68b4d6 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -391,7 +391,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
return;
}
- const int cfra = CFRA;
+ const int cfra = scene->r.cfra;
int sfra = INT_MAX, efra = INT_MIN;
switch (range) {
case ANIMVIZ_CALC_RANGE_CURRENT_FRAME:
@@ -485,7 +485,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
sfra,
efra,
efra - sfra + 1);
- for (CFRA = sfra; CFRA <= efra; CFRA++) {
+ for (scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) {
if (range == ANIMVIZ_CALC_RANGE_CURRENT_FRAME) {
/* For current frame, only update tagged. */
BKE_scene_graph_update_tagged(depsgraph, bmain);
@@ -496,14 +496,14 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
}
/* perform baking for targets */
- motionpaths_calc_bake_targets(targets, CFRA);
+ motionpaths_calc_bake_targets(targets, scene->r.cfra);
}
/* reset original environment */
/* NOTE: We don't always need to reevaluate the main scene, as the depsgraph
* may be a temporary one that works on a subset of the data.
* We always have to restore the current frame though. */
- CFRA = cfra;
+ scene->r.cfra = cfra;
if (range != ANIMVIZ_CALC_RANGE_CURRENT_FRAME && restore) {
motionpaths_calc_update_scene(depsgraph);
}
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 84f99ec0ac0..c7e755fb6df 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -111,9 +111,9 @@ static int seq_frame_apply_snap(bContext *C, Scene *scene, const int timeline_fr
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
seq_frame_snap_update_best(
- SEQ_time_left_handle_frame_get(seq), timeline_frame, &best_frame, &best_distance);
+ SEQ_time_left_handle_frame_get(scene, seq), timeline_frame, &best_frame, &best_distance);
seq_frame_snap_update_best(
- SEQ_time_right_handle_frame_get(seq), timeline_frame, &best_frame, &best_distance);
+ SEQ_time_right_handle_frame_get(scene, seq), timeline_frame, &best_frame, &best_distance);
}
SEQ_collection_free(strips);
@@ -142,14 +142,14 @@ static void change_frame_apply(bContext *C, wmOperator *op)
/* set the new frame number */
if (scene->r.flag & SCER_SHOW_SUBFRAME) {
- CFRA = (int)frame;
- SUBFRA = frame - (int)frame;
+ scene->r.cfra = (int)frame;
+ scene->r.subframe = frame - (int)frame;
}
else {
- CFRA = round_fl_to_int(frame);
- SUBFRA = 0.0f;
+ scene->r.cfra = round_fl_to_int(frame);
+ scene->r.subframe = 0.0f;
}
- FRAMENUMBER_MIN_CLAMP(CFRA);
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
/* do updates */
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
@@ -382,7 +382,7 @@ static int anim_set_sfra_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- frame = CFRA;
+ frame = scene->r.cfra;
/* if Preview Range is defined, set the 'start' frame for that */
if (PRVRANGEON) {
@@ -437,7 +437,7 @@ static int anim_set_efra_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- frame = CFRA;
+ frame = scene->r.cfra;
/* if Preview Range is defined, set the 'end' frame for that */
if (PRVRANGEON) {
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 1b759f5dfa2..effedd4307d 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -124,7 +124,7 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[],
insert_vert_fcurve(
fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
}
@@ -180,7 +180,7 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
}
else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) &&
(RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) {
- /* Rotation Source: radians -> normal, so convert src to degrees
+ /* Rotation Source: radians -> normal, so convert src to degrees
* (However, if both input and output is a rotation, don't apply such corrections)
*/
BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression));
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 6f31472907b..d2f0ee622c4 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -1020,7 +1020,7 @@ bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *c
/* adding or removing the Cycles modifier requires an update to handles */
if (curve && BKE_fcurve_is_cyclic(curve) != was_cyclic) {
- calchandles_fcurve(curve);
+ BKE_fcurve_handles_recalc(curve);
}
/* did we succeed? */
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index f8277cf6a85..706db498a82 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -444,7 +444,7 @@ void ANIM_animdata_keyframe_callback(bAnimContext *ac,
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, callback_fn, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, callback_fn, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -831,7 +831,7 @@ static short snap_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
{
const Scene *scene = ked->scene;
if (bezt->f2 & SELECT) {
- bezt->vec[1][0] = (float)CFRA;
+ bezt->vec[1][0] = (float)scene->r.cfra;
}
return 0;
}
@@ -929,7 +929,7 @@ static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
const Scene *scene = ked->scene;
if (bezt->f2 & SELECT) {
- mirror_bezier_xaxis_ex(bezt, CFRA);
+ mirror_bezier_xaxis_ex(bezt, scene->r.cfra);
}
return 0;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 00e2f221117..7723c221a40 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -47,77 +47,6 @@
/* **************************************************** */
-void delete_fcurve_key(FCurve *fcu, int index, bool do_recalc)
-{
- /* sanity check */
- if (fcu == NULL) {
- return;
- }
-
- /* verify the index:
- * 1) cannot be greater than the number of available keyframes
- * 2) negative indices are for specifying a value from the end of the array
- */
- if (abs(index) >= fcu->totvert) {
- return;
- }
- if (index < 0) {
- index += fcu->totvert;
- }
-
- /* Delete this keyframe */
- memmove(
- &fcu->bezt[index], &fcu->bezt[index + 1], sizeof(BezTriple) * (fcu->totvert - index - 1));
- fcu->totvert--;
-
- if (fcu->totvert == 0) {
- MEM_SAFE_FREE(fcu->bezt);
- }
-
- /* recalc handles - only if it won't cause problems */
- if (do_recalc) {
- calchandles_fcurve(fcu);
- }
-}
-
-bool delete_fcurve_keys(FCurve *fcu)
-{
- bool changed = false;
-
- if (fcu->bezt == NULL) { /* ignore baked curves */
- return false;
- }
-
- /* Delete selected BezTriples */
- for (int i = 0; i < fcu->totvert; i++) {
- if (fcu->bezt[i].f2 & SELECT) {
- if (i == fcu->active_keyframe_index) {
- BKE_fcurve_active_keyframe_set(fcu, NULL);
- }
- memmove(&fcu->bezt[i], &fcu->bezt[i + 1], sizeof(BezTriple) * (fcu->totvert - i - 1));
- fcu->totvert--;
- i--;
- changed = true;
- }
- }
-
- /* Free the array of BezTriples if there are not keyframes */
- if (fcu->totvert == 0) {
- clear_fcurve_keys(fcu);
- }
-
- return changed;
-}
-
-void clear_fcurve_keys(FCurve *fcu)
-{
- MEM_SAFE_FREE(fcu->bezt);
-
- fcu->totvert = 0;
-}
-
-/* ---------------- */
-
bool duplicate_fcurve_keys(FCurve *fcu)
{
bool changed = false;
@@ -282,7 +211,7 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo
}
if (fcu->bezt->vec[1][1] == default_value) {
- clear_fcurve_keys(fcu);
+ BKE_fcurve_delete_keys_all(fcu);
/* check if curve is really unused and if it is, return signal for deletion */
if (BKE_fcurve_is_empty(fcu)) {
@@ -679,7 +608,7 @@ void smooth_fcurve(FCurve *fcu)
}
/* recalculate handles */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* ---------------- */
@@ -762,7 +691,7 @@ void sample_fcurve(FCurve *fcu)
}
/* recalculate channel's handles? */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* **************************************************** */
@@ -921,7 +850,7 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
}
/* in case 'relative' paste method is used */
- animcopy_cfra = CFRA;
+ animcopy_cfra = scene->r.cfra;
/* everything went fine */
return 0;
@@ -1121,7 +1050,7 @@ static void paste_animedit_keys_fcurve(
case KEYFRAME_PASTE_MERGE_OVER:
/* remove all keys */
- clear_fcurve_keys(fcu);
+ BKE_fcurve_delete_keys_all(fcu);
break;
case KEYFRAME_PASTE_MERGE_OVER_RANGE:
@@ -1148,7 +1077,7 @@ static void paste_animedit_keys_fcurve(
}
/* remove frames in the range */
- delete_fcurve_keys(fcu);
+ BKE_fcurve_delete_keys_selected(fcu);
}
break;
}
@@ -1182,7 +1111,7 @@ static void paste_animedit_keys_fcurve(
}
/* recalculate F-Curve's handles? */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
const EnumPropertyItem rna_enum_keyframe_paste_offset_items[] = {
@@ -1217,11 +1146,11 @@ const EnumPropertyItem rna_enum_keyframe_paste_merge_items[] = {
{0, NULL, 0, NULL, NULL},
};
-short paste_animedit_keys(bAnimContext *ac,
- ListBase *anim_data,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
- bool flip)
+eKeyPasteError paste_animedit_keys(bAnimContext *ac,
+ ListBase *anim_data,
+ const eKeyPasteOffset offset_mode,
+ const eKeyMergeMode merge_mode,
+ bool flip)
{
bAnimListElem *ale;
@@ -1235,25 +1164,23 @@ short paste_animedit_keys(bAnimContext *ac,
/* check if buffer is empty */
if (BLI_listbase_is_empty(&animcopybuf)) {
- BKE_report(ac->reports, RPT_ERROR, "No animation data in buffer to paste");
- return -1;
+ return KEYFRAME_PASTE_NOTHING_TO_PASTE;
}
if (BLI_listbase_is_empty(anim_data)) {
- BKE_report(ac->reports, RPT_ERROR, "No selected F-Curves to paste into");
- return -1;
+ return KEYFRAME_PASTE_NOWHERE_TO_PASTE;
}
/* methods of offset */
switch (offset_mode) {
case KEYFRAME_PASTE_OFFSET_CFRA_START:
- offset = (float)(CFRA - animcopy_firstframe);
+ offset = (float)(scene->r.cfra - animcopy_firstframe);
break;
case KEYFRAME_PASTE_OFFSET_CFRA_END:
- offset = (float)(CFRA - animcopy_lastframe);
+ offset = (float)(scene->r.cfra - animcopy_lastframe);
break;
case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
- offset = (float)(CFRA - animcopy_cfra);
+ offset = (float)(scene->r.cfra - animcopy_cfra);
break;
case KEYFRAME_PASTE_OFFSET_NONE:
offset = 0.0f;
@@ -1335,7 +1262,7 @@ short paste_animedit_keys(bAnimContext *ac,
ANIM_animdata_update(ac, anim_data);
- return 0;
+ return KEYFRAME_PASTE_OK;
}
/* **************************************************** */
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index 3356ef4d47d..8dc598e6e2d 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -132,7 +132,7 @@ static void ED_keylist_runtime_init_listbase(AnimKeylist *keylist)
return;
}
- keylist->runtime.list_wrapper.first = &keylist->runtime.key_columns[0];
+ keylist->runtime.list_wrapper.first = keylist->runtime.key_columns.data();
keylist->runtime.list_wrapper.last = &keylist->runtime.key_columns[keylist->column_len - 1];
}
@@ -309,7 +309,7 @@ static void keylist_first_last(const struct AnimKeylist *keylist,
const struct ActKeyColumn **last_column)
{
if (keylist->is_runtime_initialized) {
- *first_column = &keylist->runtime.key_columns[0];
+ *first_column = keylist->runtime.key_columns.data();
*last_column = &keylist->runtime.key_columns[keylist->column_len - 1];
}
else {
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 941125b9ad5..9084b9bb214 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -639,7 +639,7 @@ int insert_vert_fcurve(
* - we may calculate twice (due to auto-handle needing to be calculated twice)
*/
if ((flag & INSERTKEY_FAST) == 0) {
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* return the index at which the keyframe was added */
@@ -1282,10 +1282,12 @@ static bool insert_keyframe_value(ReportList *reports,
/* delete keyframe immediately before/after newly added */
switch (insert_mode) {
case KEYNEEDED_DELPREV:
- delete_fcurve_key(fcu, fcu->totvert - 2, 1);
+ BKE_fcurve_delete_key(fcu, fcu->totvert - 2);
+ BKE_fcurve_handles_recalc(fcu);
break;
case KEYNEEDED_DELNEXT:
- delete_fcurve_key(fcu, 1, 1);
+ BKE_fcurve_delete_key(fcu, 1);
+ BKE_fcurve_handles_recalc(fcu);
break;
}
@@ -1683,7 +1685,8 @@ static bool delete_keyframe_fcurve(AnimData *adt, FCurve *fcu, float cfra)
i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
if (found) {
/* delete the key at the index (will sanity check + do recalc afterwards) */
- delete_fcurve_key(fcu, i, 1);
+ BKE_fcurve_delete_key(fcu, i);
+ BKE_fcurve_handles_recalc(fcu);
/* Only delete curve too if it won't be doing anything anymore */
if (BKE_fcurve_is_empty(fcu)) {
@@ -1947,7 +1950,8 @@ static int insert_key_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
bool ob_edit_mode = false;
- float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
+ float cfra = (float)
+ scene->r.cfra; /* XXX for now, don't bother about all the yucky offset crap */
int num_channels;
const bool confirm = op->flag & OP_IS_INVOKE;
@@ -2168,7 +2172,8 @@ static int delete_key_exec(bContext *C, wmOperator *op)
static int delete_key_using_keying_set(bContext *C, wmOperator *op, KeyingSet *ks)
{
Scene *scene = CTX_data_scene(C);
- float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
+ float cfra = (float)
+ scene->r.cfra; /* XXX for now, don't bother about all the yucky offset crap */
int num_channels;
const bool confirm = op->flag & OP_IS_INVOKE;
@@ -2344,7 +2349,7 @@ void ANIM_OT_keyframe_clear_v3d(wmOperatorType *ot)
static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- float cfra = (float)CFRA;
+ float cfra = (float)scene->r.cfra;
int selected_objects_len = 0;
int selected_objects_success_len = 0;
@@ -2494,7 +2499,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
char *path;
uiBut *but;
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
- CTX_data_depsgraph_pointer(C), (float)CFRA);
+ CTX_data_depsgraph_pointer(C), (float)scene->r.cfra);
bool changed = false;
int index;
const bool all = RNA_boolean_get(op->ptr, "all");
@@ -2663,7 +2668,8 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
PropertyRNA *prop = NULL;
Main *bmain = CTX_data_main(C);
char *path;
- float cfra = (float)CFRA; /* XXX for now, don't bother about all the yucky offset crap */
+ float cfra = (float)
+ scene->r.cfra; /* XXX for now, don't bother about all the yucky offset crap */
bool changed = false;
int index;
const bool all = RNA_boolean_get(op->ptr, "all");
@@ -2706,7 +2712,8 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
if (found) {
/* delete the key at the index (will sanity check + do recalc afterwards) */
- delete_fcurve_key(fcu, i, 1);
+ BKE_fcurve_delete_key(fcu, i);
+ BKE_fcurve_handles_recalc(fcu);
changed = true;
}
}
@@ -2835,7 +2842,7 @@ void ANIM_OT_keyframe_clear_button(wmOperatorType *ot)
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
{
- float cfra = (float)CFRA; /* XXX for now, this will do */
+ float cfra = (float)scene->r.cfra; /* XXX for now, this will do */
/* only filter if auto-key mode requires this */
if (IS_AUTOKEY_ON(scene) == 0) {
@@ -3065,7 +3072,7 @@ bool ED_autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks
* 3) Free the extra info.
*/
ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
BLI_freelistN(&dsources);
return true;
@@ -3085,7 +3092,7 @@ bool ED_autokeyframe_pchan(
* 3) Free the extra info.
*/
ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
BLI_freelistN(&dsources);
return true;
@@ -3094,8 +3101,13 @@ bool ED_autokeyframe_pchan(
return false;
}
-bool ED_autokeyframe_property(
- bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra)
+bool ED_autokeyframe_property(bContext *C,
+ Scene *scene,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ int rnaindex,
+ float cfra,
+ const bool only_if_property_keyed)
{
Main *bmain = CTX_data_main(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -3114,7 +3126,9 @@ bool ED_autokeyframe_property(
fcu = BKE_fcurve_find_by_rna_context_ui(
C, ptr, prop, rnaindex_check, NULL, &action, &driven, &special);
- if (fcu == NULL) {
+ /* Only early out when we actually want an existing F-curve already
+ * (e.g. auto-keyframing from buttons). */
+ if (fcu == NULL && (driven || special || only_if_property_keyed)) {
return changed;
}
@@ -3150,23 +3164,28 @@ bool ED_autokeyframe_property(
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
const eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene, true);
+ char *path = RNA_path_from_ID_to_property(ptr, prop);
- /* NOTE: We use rnaindex instead of fcu->array_index,
- * because a button may control all items of an array at once.
- * E.g., color wheels (see T42567). */
- BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
+ if (only_if_property_keyed) {
+ /* NOTE: We use rnaindex instead of fcu->array_index,
+ * because a button may control all items of an array at once.
+ * E.g., color wheels (see T42567). */
+ BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
+ }
changed = insert_keyframe(bmain,
reports,
id,
action,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
+ (fcu && fcu->grp) ? fcu->grp->name : NULL,
+ fcu ? fcu->rna_path : path,
rnaindex,
&anim_eval_context,
ts->keyframe_type,
NULL,
flag) != 0;
-
+ if (path) {
+ MEM_freeN(path);
+ }
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
}
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index f9b973733af..2071f056f9e 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -375,13 +375,10 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
/* does this constraint have a subtarget in
* this armature?
*/
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
+ if (BKE_constraint_targets_get(curcon, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
@@ -409,9 +406,7 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 0);
}
}
}
@@ -427,7 +422,7 @@ static void updateDuplicateActionConstraintSettings(
float mat[4][4];
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
- BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+ BKE_constraint_custom_object_space_init(&cob, curcon);
unit_m4(mat);
bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
@@ -581,7 +576,7 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob,
unit_m4(local_mat);
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
- BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+ BKE_constraint_custom_object_space_init(&cob, curcon);
BKE_constraint_mat_convertspace(
ob, pchan, &cob, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
@@ -636,7 +631,7 @@ static void updateDuplicateTransformConstraintSettings(Object *ob,
float target_mat[4][4], own_mat[4][4], imat[4][4];
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
- BKE_constraint_custom_object_space_get(cob.space_obj_world_matrix, curcon);
+ BKE_constraint_custom_object_space_init(&cob, curcon);
unit_m4(own_mat);
BKE_constraint_mat_convertspace(
@@ -1152,7 +1147,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
if (axis_delta == 0.0f) {
- /* both mirrored bones exist and point to eachother and overlap exactly.
+ /* Both mirrored bones exist and point to each other and overlap exactly.
*
* in this case there's no well defined solution, so de-select both and skip.
*/
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 963d7ea1149..3c445f46902 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -229,7 +229,7 @@ typedef enum eCalcRollTypes {
} eCalcRollTypes;
static const EnumPropertyItem prop_calc_roll_types[] = {
- {0, "", 0, N_("Positive"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Positive"), NULL),
{CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
{CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
@@ -237,8 +237,7 @@ static const EnumPropertyItem prop_calc_roll_types[] = {
{CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
{CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
- {0, "", 0, N_("Negative"), ""},
-
+ RNA_ENUM_ITEM_HEADING(N_("Negative"), NULL),
{CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
{CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
@@ -246,7 +245,7 @@ static const EnumPropertyItem prop_calc_roll_types[] = {
{CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
{CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
- {0, "", 0, N_("Other"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Other"), NULL),
{CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
{CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
{CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index e1f2605481f..4f329dbe449 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -13,6 +13,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
@@ -109,13 +110,10 @@ static void constraint_bone_name_fix(Object *ob,
bConstraintTarget *ct;
for (curcon = conlist->first; curcon; curcon = curcon->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(curcon, &targets);
-
+ if (BKE_constraint_targets_get(curcon, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == ob) {
if (STREQ(ct->subtarget, oldname)) {
@@ -124,9 +122,7 @@ static void constraint_bone_name_fix(Object *ob,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(curcon, &targets, 0);
- }
+ BKE_constraint_targets_flush(curcon, &targets, 0);
}
/* action constraints */
@@ -286,6 +282,17 @@ void ED_armature_bone_rename(Main *bmain,
}
}
+ /* fix camera focus */
+ if (ob->type == OB_CAMERA) {
+ Camera *cam = (Camera *)ob->data;
+ if ((cam->dof.focus_object != NULL) && (cam->dof.focus_object->data == arm)) {
+ if (STREQ(cam->dof.focus_subtarget, oldname)) {
+ BLI_strncpy(cam->dof.focus_subtarget, newname, MAXBONENAME);
+ DEG_id_tag_update(&cam->id, ID_RECALC_COPY_ON_WRITE);
+ }
+ }
+ }
+
/* fix grease pencil modifiers and vertex groups */
if (ob->type == OB_GPENCIL) {
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index be4829c02be..0825d6968c6 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -68,14 +68,11 @@ static void joined_armature_fix_links_constraints(Main *bmain,
bool changed = false;
for (con = lb->first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == srcArm) {
if (ct->subtarget[0] == '\0') {
@@ -90,9 +87,7 @@ static void joined_armature_fix_links_constraints(Main *bmain,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
/* action constraint? (pose constraints only) */
@@ -164,6 +159,11 @@ static void joined_armature_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data
ChannelDriver *driver = fcu->driver;
DriverVar *dvar;
+ /* Ensure that invalid drivers gets re-evaluated in case they become valid once the join
+ * operation is finished. */
+ fcu->flag &= ~FCURVE_DISABLED;
+ driver->flag &= ~DRIVER_FLAG_INVALID;
+
/* Fix driver references to invalid ID's */
for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
/* only change the used targets, since the others will need fixing manually anyway */
@@ -459,14 +459,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
if (ob->type == OB_ARMATURE) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
/* Any targets which point to original armature
* are redirected to the new one only if:
@@ -487,9 +484,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
}
@@ -498,14 +493,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
/* fix object-level constraints */
if (ob != origArm) {
for (con = ob->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
/* any targets which point to original armature are redirected to the new one only if:
* - the target isn't origArm/newArm itself
@@ -525,9 +517,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
}
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index d0f0bd55eea..1b78d3cc77e 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -42,6 +42,7 @@
static bool pose_group_poll(bContext *C)
{
if (!ED_operator_posemode_context(C)) {
+ CTX_wm_operator_poll_msg_set(C, "Bone groups can only be edited in pose mode");
return false;
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index e0e5693c79b..ff187a52154 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -24,6 +24,7 @@
#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
+#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -448,7 +449,7 @@ static int poselib_add_menu_invoke(bContext *C, wmOperator *op, const wmEvent *U
ICON_NONE,
"POSELIB_OT_pose_add",
"frame",
- CFRA);
+ scene->r.cfra);
/* Replace existing - sub-menu. */
uiItemMenuF(
@@ -615,7 +616,8 @@ static int poselib_remove_exec(bContext *C, wmOperator *op)
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
/* check if remove */
if (IS_EQF(bezt->vec[1][0], (float)marker->frame)) {
- delete_fcurve_key(fcu, i, 1);
+ BKE_fcurve_delete_key(fcu, i);
+ BKE_fcurve_handles_recalc(fcu);
break;
}
}
@@ -1113,7 +1115,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, tPoseLib_PreviewData
/* perform actual auto-keying now */
if (autokey) {
/* insert keyframes for all relevant bones in one go */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
BLI_freelistN(&dsources);
}
@@ -1431,7 +1433,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
ret = OPERATOR_PASS_THROUGH;
break;
- /* quicky compare to original */
+ /* Quickly compare to original. */
case EVT_TABKEY:
pld->flag &= ~PL_PREVIEW_SHOWORIGINAL;
pld->redraw = PL_PREVIEW_REDRAWALL;
@@ -1578,7 +1580,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
case EVT_PADMINUS:
if (pld->searchstr[0]) {
/* searching... */
- poselib_preview_handle_search(pld, event->type, event->ascii);
+ poselib_preview_handle_search(pld, event->type, WM_event_utf8_to_ascii(event));
}
else {
/* view manipulation (see above) */
@@ -1589,7 +1591,7 @@ static int poselib_preview_handle_event(bContext *UNUSED(C), wmOperator *op, con
/* otherwise, assume that searching might be able to handle it */
default:
- poselib_preview_handle_search(pld, event->type, event->ascii);
+ poselib_preview_handle_search(pld, event->type, WM_event_utf8_to_ascii(event));
break;
}
diff --git a/source/blender/editors/armature/pose_lib_2.c b/source/blender/editors/armature/pose_lib_2.c
index 9ee289145c4..d866062cec0 100644
--- a/source/blender/editors/armature/pose_lib_2.c
+++ b/source/blender/editors/armature/pose_lib_2.c
@@ -134,7 +134,7 @@ static void poselib_keytag_pose(bContext *C, Scene *scene, PoseBlendData *pbd)
}
/* Perform actual auto-keying. */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
BLI_freelistN(&dsources);
/* send notifiers for this */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 8790a10f3e5..b6b5d3ee495 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -680,13 +680,10 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
Object *ob = ct->tar;
@@ -702,9 +699,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 1);
- }
+ BKE_constraint_targets_flush(con, &targets, 1);
}
}
}
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 0efa32ec63a..38c99c2ef60 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -2061,12 +2061,12 @@ static int pose_propagate_exec(bContext *C, wmOperator *op)
if (mode == POSE_PROPAGATE_SMART_HOLDS) {
/* We store in endFrame the end frame of the "long keyframe" (i.e. a held value) starting
* from the keyframe that occurs after the current frame. */
- modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)CFRA);
+ modeData.end_frame = pose_propagate_get_boneHoldEndFrame(pfl, (float)scene->r.cfra);
}
/* Go through propagating pose to keyframes, curve by curve. */
for (ld = pfl->fcurves.first; ld; ld = ld->next) {
- pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)CFRA, modeData);
+ pose_propagate_fcurve(op, pfl->ob, (FCurve *)ld->data, (float)scene->r.cfra, modeData);
}
}
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index f0b0218d7e0..cfc6b0b6b6e 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -1201,7 +1201,7 @@ static int pose_clear_transform_generic_exec(bContext *C,
KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
/* insert keyframes */
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)scene->r.cfra);
/* now recalculate paths */
if (ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
@@ -1343,8 +1343,8 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
const bool only_select = RNA_boolean_get(op->ptr, "only_selected");
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob) {
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 9da9845116d..24302aca59b 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -4729,6 +4729,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
bool ED_curve_editnurb_select_pick(bContext *C,
const int mval[2],
const int dist_px,
+ const bool vert_without_handles,
const struct SelectPick_Params *params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@@ -4744,6 +4745,9 @@ bool ED_curve_editnurb_select_pick(bContext *C,
ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, mval);
+ const bool use_handle_select = vert_without_handles &&
+ (vc.v3d->overlay.handle_display != CURVE_HANDLE_NONE);
+
bool found = ED_curve_pick_vert_ex(&vc, 1, dist_px, &nu, &bezt, &bp, &hand, &basact);
if (params->sel_op == SEL_OP_SET) {
@@ -4779,7 +4783,12 @@ bool ED_curve_editnurb_select_pick(bContext *C,
case SEL_OP_ADD: {
if (bezt) {
if (hand == 1) {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 |= SELECT;
+ }
+ else {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ }
}
else {
if (hand == 0) {
@@ -4800,7 +4809,12 @@ bool ED_curve_editnurb_select_pick(bContext *C,
case SEL_OP_SUB: {
if (bezt) {
if (hand == 1) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 &= ~SELECT;
+ }
+ else {
+ select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ }
if (bezt == vert) {
cu->actvert = CU_ACT_NONE;
}
@@ -4824,13 +4838,23 @@ bool ED_curve_editnurb_select_pick(bContext *C,
if (bezt) {
if (hand == 1) {
if (bezt->f2 & SELECT) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 &= ~SELECT;
+ }
+ else {
+ select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ }
if (bezt == vert) {
cu->actvert = CU_ACT_NONE;
}
}
else {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 |= SELECT;
+ }
+ else {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ }
BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
}
@@ -4861,7 +4885,12 @@ bool ED_curve_editnurb_select_pick(bContext *C,
if (bezt) {
if (hand == 1) {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ if (use_handle_select) {
+ bezt->f2 |= SELECT;
+ }
+ else {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ }
}
else {
if (hand == 0) {
@@ -5533,7 +5562,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Curve *cu;
float location[3];
const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
- (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
+ (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE_RAYCAST));
Nurb *nu;
BezTriple *bezt;
@@ -5566,11 +5595,13 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
vc.depsgraph,
vc.region,
vc.v3d,
- SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_FACE_RAYCAST,
&(const struct SnapObjectParams){
- .snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
+ .snap_target_select = (vc.obedit != NULL) ? SCE_SNAP_TARGET_NOT_ACTIVE :
+ SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,
},
+ NULL,
mval,
NULL,
NULL,
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index ba5a7409ba7..ee6376ca95f 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -87,6 +87,8 @@ static const char *get_surf_defname(int type)
return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "SurfCircle");
case CU_PRIM_PATCH:
return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "SurfPatch");
+ case CU_PRIM_TUBE:
+ return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "SurfCylinder");
case CU_PRIM_SPHERE:
return CTX_DATA_(BLT_I18NCONTEXT_ID_CURVE_LEGACY, "SurfSphere");
case CU_PRIM_DONUT:
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index 598779c6ace..6946c09e6f1 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -105,7 +105,7 @@ struct CurveDrawData {
} radius;
struct {
- float mouse[2];
+ float mval[2];
/* Used in case we can't calculate the depth. */
float location_world[3];
@@ -463,8 +463,8 @@ static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
}
copy_v3_v3(cdd->prev.location_world, selem->location_world);
- float len_sq = len_squared_v2v2(cdd->prev.mouse, selem->mval);
- copy_v2_v2(cdd->prev.mouse, selem->mval);
+ float len_sq = len_squared_v2v2(cdd->prev.mval, selem->mval);
+ copy_v2_v2(cdd->prev.mval, selem->mval);
if (cdd->sample.use_substeps && cdd->prev.selem) {
const struct StrokeElem selem_target = *selem;
@@ -1165,7 +1165,7 @@ static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
if (cdd->state == CURVE_DRAW_PAINTING) {
const float mval_fl[2] = {UNPACK2(event->mval)};
- if (len_squared_v2v2(mval_fl, cdd->prev.mouse) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) {
+ if (len_squared_v2v2(mval_fl, cdd->prev.mval) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) {
curve_draw_event_add(op, event);
}
}
diff --git a/source/blender/editors/curve/editcurve_pen.c b/source/blender/editors/curve/editcurve_pen.c
index fca850076ae..729ad46877a 100644
--- a/source/blender/editors/curve/editcurve_pen.c
+++ b/source/blender/editors/curve/editcurve_pen.c
@@ -843,7 +843,7 @@ static bool insert_point_to_segment(const ViewContext *vc, const wmEvent *event)
{
Curve *cu = vc->obedit->data;
CutData cd = init_cut_data(event);
- float mval[2] = {UNPACK2(event->mval)};
+ const float mval[2] = {UNPACK2(event->mval)};
const float threshold_dist_px = ED_view3d_select_dist_px() * SEL_DIST_FACTOR;
const bool near_spline = update_cut_data_for_all_nurbs(
vc, BKE_curve_editNurbs_get(cu), mval, threshold_dist_px, &cd);
@@ -985,7 +985,7 @@ static void extrude_vertices_from_selected_endpoints(EditNurb *editnurb,
else {
BPoint *last_bp = nu1->bp + nu1->pntsu - 1;
const bool first_sel = nu1->bp->f1 & SELECT;
- const bool last_sel = last_bp->f1 & SELECT;
+ const bool last_sel = last_bp->f1 & SELECT && nu1->pntsu > 1;
if (first_sel) {
if (last_sel) {
BPoint *new_bp = (BPoint *)MEM_mallocN((nu1->pntsu + 2) * sizeof(BPoint), __func__);
@@ -1134,7 +1134,7 @@ static bool is_spline_nearby(ViewContext *vc,
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
CutData cd = init_cut_data(event);
- float mval[2] = {UNPACK2(event->mval)};
+ const float mval[2] = {UNPACK2(event->mval)};
const bool nearby = update_cut_data_for_all_nurbs(vc, nurbs, mval, sel_dist, &cd);
if (nearby) {
@@ -1655,7 +1655,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event)
else if (ELEM(event->type, LEFTMOUSE)) {
if (ELEM(event->val, KM_RELEASE, KM_DBL_CLICK)) {
if (delete_point && !cpd->new_point && !cpd->dragging) {
- if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, &params)) {
+ if (ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, &params)) {
cpd->acted = delete_point_under_mouse(&vc, event);
}
}
@@ -1714,7 +1714,7 @@ static int curve_pen_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (select_point) {
- ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, &params);
+ ED_curve_editnurb_select_pick(C, event->mval, threshold_dist_px, false, &params);
}
}
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 611dbb2e80c..ceed12dcff1 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -59,7 +59,7 @@ static int kill_selection(Object *obedit, int ins);
/** \name Internal Utilities
* \{ */
-static char32_t findaccent(char32_t char1, uint code)
+static char32_t findaccent(char32_t char1, const char code)
{
char32_t new = 0;
@@ -1638,12 +1638,11 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
- static int accentcode = 0;
- uintptr_t ascii = event->ascii;
+ static bool accentcode = false;
const bool alt = event->modifier & KM_ALT;
const bool shift = event->modifier & KM_SHIFT;
const bool ctrl = event->modifier & KM_CTRL;
- int event_type = event->type, event_val = event->val;
+ char32_t insert_char_override = 0;
char32_t inserted_text[2] = {0};
if (RNA_struct_property_is_set(op->ptr, "text")) {
@@ -1652,48 +1651,47 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (RNA_struct_property_is_set(op->ptr, "accent")) {
if (ef->len != 0 && ef->pos > 0) {
- accentcode = 1;
+ accentcode = true;
}
return OPERATOR_FINISHED;
}
- /* tab should exit editmode, but we allow it to be typed using modifier keys */
- if (event_type == EVT_TABKEY) {
- if ((alt || ctrl || shift) == 0) {
- return OPERATOR_PASS_THROUGH;
- }
-
- ascii = 9;
- }
-
- if (event_type == EVT_BACKSPACEKEY) {
+ if (event->type == EVT_BACKSPACEKEY) {
if (alt && ef->len != 0 && ef->pos > 0) {
- accentcode = 1;
+ accentcode = true;
}
return OPERATOR_PASS_THROUGH;
}
- if (event_val && (ascii || event->utf8_buf[0])) {
- /* handle case like TAB (== 9) */
- if ((ascii > 31 && ascii < 254 && ascii != 127) || (ELEM(ascii, 13, 10)) || (ascii == 8) ||
- (event->utf8_buf[0])) {
+ /* Tab typically exit edit-mode, but we allow it to be typed using modifier keys. */
+ if (event->type == EVT_TABKEY) {
+ if ((alt || ctrl || shift) == 0) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ insert_char_override = '\t';
+ }
+ if (insert_char_override || event->utf8_buf[0]) {
+ if (insert_char_override) {
+ /* Handle case like TAB ('\t'). */
+ inserted_text[0] = insert_char_override;
+ insert_into_textbuf(obedit, insert_char_override);
+ text_update_edited(C, obedit, FO_EDIT);
+ }
+ else {
+ BLI_assert(event->utf8_buf[0]);
if (accentcode) {
if (ef->pos > 0) {
- inserted_text[0] = findaccent(ef->textbuf[ef->pos - 1], ascii);
+ inserted_text[0] = findaccent(ef->textbuf[ef->pos - 1],
+ BLI_str_utf8_as_unicode(event->utf8_buf));
ef->textbuf[ef->pos - 1] = inserted_text[0];
}
- accentcode = 0;
+ accentcode = false;
}
else if (event->utf8_buf[0]) {
inserted_text[0] = BLI_str_utf8_as_unicode(event->utf8_buf);
- ascii = inserted_text[0];
- insert_into_textbuf(obedit, ascii);
- accentcode = 0;
- }
- else if (ascii) {
- insert_into_textbuf(obedit, ascii);
- accentcode = 0;
+ insert_into_textbuf(obedit, inserted_text[0]);
+ accentcode = false;
}
else {
BLI_assert(0);
@@ -1702,11 +1700,6 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
kill_selection(obedit, 1);
text_update_edited(C, obedit, FO_EDIT);
}
- else {
- inserted_text[0] = ascii;
- insert_into_textbuf(obedit, ascii);
- text_update_edited(C, obedit, FO_EDIT);
- }
}
else {
return OPERATOR_PASS_THROUGH;
@@ -1720,11 +1713,6 @@ static int insert_text_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_string_set(op->ptr, "text", inserted_utf8);
}
- /* reset property? */
- if (event_val == 0) {
- accentcode = 0;
- }
-
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/curves/CMakeLists.txt b/source/blender/editors/curves/CMakeLists.txt
index a5d8390e7f2..303d2fb71dc 100644
--- a/source/blender/editors/curves/CMakeLists.txt
+++ b/source/blender/editors/curves/CMakeLists.txt
@@ -7,6 +7,8 @@ set(INC
../../blentranslation
../../depsgraph
../../functions
+ ../../geometry
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
@@ -26,5 +28,17 @@ set(LIB
bf_blenlib
)
+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()
+
blender_add_lib(bf_editor_curves "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
add_dependencies(bf_editor_curves bf_rna)
diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc
index 552ef1d96c8..79916253207 100644
--- a/source/blender/editors/curves/intern/curves_add.cc
+++ b/source/blender/editors/curves/intern/curves_add.cc
@@ -6,12 +6,96 @@
#include "BLI_rand.hh"
+#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "ED_curves.h"
+#include "ED_node.h"
+#include "ED_object.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
namespace blender::ed::curves {
+static bool has_surface_deformation_node(const bNodeTree &ntree)
+{
+ LISTBASE_FOREACH (const bNode *, node, &ntree.nodes) {
+ if (node->type == GEO_NODE_DEFORM_CURVES_ON_SURFACE) {
+ return true;
+ }
+ if (node->type == NODE_GROUP) {
+ if (node->id != nullptr) {
+ if (has_surface_deformation_node(*reinterpret_cast<const bNodeTree *>(node->id))) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool has_surface_deformation_node(const Object &curves_ob)
+{
+ LISTBASE_FOREACH (const ModifierData *, md, &curves_ob.modifiers) {
+ if (md->type != eModifierType_Nodes) {
+ continue;
+ }
+ const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
+ if (nmd->node_group == nullptr) {
+ continue;
+ }
+ if (has_surface_deformation_node(*nmd->node_group)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob)
+{
+ if (has_surface_deformation_node(curves_ob)) {
+ return;
+ }
+
+ Main *bmain = CTX_data_main(&C);
+ Scene *scene = CTX_data_scene(&C);
+
+ ModifierData *md = ED_object_modifier_add(
+ nullptr, bmain, scene, &curves_ob, "Surface Deform", eModifierType_Nodes);
+ NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
+ nmd.node_group = ntreeAddTree(bmain, "Surface Deform", "GeometryNodeTree");
+
+ bNodeTree *ntree = nmd.node_group;
+ ntreeAddSocketInterface(ntree, SOCK_IN, "NodeSocketGeometry", "Geometry");
+ ntreeAddSocketInterface(ntree, SOCK_OUT, "NodeSocketGeometry", "Geometry");
+ bNode *group_input = nodeAddStaticNode(&C, ntree, NODE_GROUP_INPUT);
+ bNode *group_output = nodeAddStaticNode(&C, ntree, NODE_GROUP_OUTPUT);
+ bNode *deform_node = nodeAddStaticNode(&C, ntree, GEO_NODE_DEFORM_CURVES_ON_SURFACE);
+
+ ED_node_tree_propagate_change(&C, bmain, nmd.node_group);
+
+ nodeAddLink(ntree,
+ group_input,
+ static_cast<bNodeSocket *>(group_input->outputs.first),
+ deform_node,
+ nodeFindSocket(deform_node, SOCK_IN, "Curves"));
+ nodeAddLink(ntree,
+ deform_node,
+ nodeFindSocket(deform_node, SOCK_OUT, "Curves"),
+ group_output,
+ static_cast<bNodeSocket *>(group_output->inputs.first));
+
+ group_input->locx = -200;
+ group_output->locx = 200;
+ deform_node->locx = 0;
+
+ ED_node_tree_propagate_change(&C, bmain, nmd.node_group);
+}
+
bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int points_per_curve)
{
bke::CurvesGeometry curves(points_per_curve * curves_size, curves_size);
diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc
index 5588f7440a8..f4d1c8046f1 100644
--- a/source/blender/editors/curves/intern/curves_ops.cc
+++ b/source/blender/editors/curves/intern/curves_ops.cc
@@ -6,19 +6,26 @@
#include <atomic>
+#include "BLI_devirtualize_parameters.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector_set.hh"
#include "ED_curves.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "WM_api.h"
+#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_object.h"
#include "BKE_paint.h"
@@ -37,8 +44,11 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "RNA_prototypes.h"
+#include "GEO_reverse_uv_sampler.hh"
+
/**
* The code below uses a suffix naming convention to indicate the coordinate space:
* `cu`: Local space of the curves object that is being edited.
@@ -49,6 +59,41 @@
namespace blender::ed::curves {
+static bool object_has_editable_curves(const Main &bmain, const Object &object)
+{
+ if (object.type != OB_CURVES) {
+ return false;
+ }
+ if (!ELEM(object.mode, OB_MODE_SCULPT_CURVES, OB_MODE_EDIT)) {
+ return false;
+ }
+ if (!BKE_id_is_editable(&bmain, static_cast<const ID *>(object.data))) {
+ return false;
+ }
+ return true;
+}
+
+VectorSet<Curves *> get_unique_editable_curves(const bContext &C)
+{
+ VectorSet<Curves *> unique_curves;
+
+ const Main &bmain = *CTX_data_main(&C);
+
+ Object *object = CTX_data_active_object(&C);
+ if (object && object_has_editable_curves(bmain, *object)) {
+ unique_curves.add_new(static_cast<Curves *>(object->data));
+ }
+
+ CTX_DATA_BEGIN (&C, Object *, object, selected_objects) {
+ if (object_has_editable_curves(bmain, *object)) {
+ unique_curves.add(static_cast<Curves *>(object->data));
+ }
+ }
+ CTX_DATA_END;
+
+ return unique_curves;
+}
+
using bke::CurvesGeometry;
namespace convert_to_particle_system {
@@ -143,25 +188,20 @@ static void try_convert_single_object(Object &curves_ob,
}
Mesh &surface_me = *static_cast<Mesh *>(surface_ob.data);
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_me, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
const Span<float3> positions_cu = curves.positions();
- const VArray<int> looptri_indices = curves.surface_triangle_indices();
const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&surface_me),
BKE_mesh_runtime_looptri_len(&surface_me)};
- /* Find indices of curves that can be transferred to the old hair system. */
- Vector<int> curves_indices_to_transfer;
- for (const int curve_i : curves.curves_range()) {
- const int looptri_i = looptri_indices[curve_i];
- if (looptri_i >= 0 && looptri_i < looptris.size()) {
- curves_indices_to_transfer.append(curve_i);
- }
- else {
- *r_could_not_convert_some_curves = true;
- }
+ if (looptris.is_empty()) {
+ *r_could_not_convert_some_curves = true;
}
- const int hairs_num = curves_indices_to_transfer.size();
- if (hairs_num == 0) {
+ const int hair_num = curves.curves_num();
+ if (hair_num == 0) {
return;
}
@@ -187,13 +227,13 @@ static void try_convert_single_object(Object &curves_ob,
psys_changed_type(&surface_ob, particle_system);
MutableSpan<ParticleData> particles{
- static_cast<ParticleData *>(MEM_calloc_arrayN(hairs_num, sizeof(ParticleData), __func__)),
- hairs_num};
+ static_cast<ParticleData *>(MEM_calloc_arrayN(hair_num, sizeof(ParticleData), __func__)),
+ hair_num};
/* The old hair system still uses #MFace, so make sure those are available on the mesh. */
BKE_mesh_tessface_calc(&surface_me);
- /* Prepare utility data structure to map hair roots to mfaces. */
+ /* Prepare utility data structure to map hair roots to #MFace's. */
const Span<int> mface_to_poly_map{
static_cast<const int *>(CustomData_get_layer(&surface_me.fdata, CD_ORIGINDEX)),
surface_me.totface};
@@ -204,22 +244,25 @@ static void try_convert_single_object(Object &curves_ob,
}
/* Prepare transformation matrices. */
- const float4x4 curves_to_world_mat = curves_ob.obmat;
- const float4x4 surface_to_world_mat = surface_ob.obmat;
- const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
- const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat;
+ const bke::CurvesSurfaceTransforms transforms{curves_ob, &surface_ob};
- for (const int new_hair_i : curves_indices_to_transfer.index_range()) {
- const int curve_i = curves_indices_to_transfer[new_hair_i];
+ for (const int new_hair_i : IndexRange(hair_num)) {
+ const int curve_i = new_hair_i;
const IndexRange points = curves.points_for_curve(curve_i);
- const int looptri_i = looptri_indices[curve_i];
+ const float3 &root_pos_cu = positions_cu[points.first()];
+ const float3 root_pos_su = transforms.curves_to_surface * root_pos_cu;
+
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(
+ surface_bvh.tree, root_pos_su, &nearest, surface_bvh.nearest_callback, &surface_bvh);
+ BLI_assert(nearest.index >= 0);
+
+ const int looptri_i = nearest.index;
const MLoopTri &looptri = looptris[looptri_i];
const int poly_i = looptri.poly;
- const float3 &root_pos_cu = positions_cu[points.first()];
- const float3 root_pos_su = curves_to_surface_mat * root_pos_cu;
-
const int mface_i = find_mface_for_root_position(
surface_me, poly_to_mface_map[poly_i], root_pos_su);
const MFace &mface = surface_me.mface[mface_i];
@@ -248,7 +291,7 @@ static void try_convert_single_object(Object &curves_ob,
for (const int key_i : hair_keys.index_range()) {
const float3 &key_pos_cu = positions_cu[points[key_i]];
- const float3 key_pos_su = curves_to_surface_mat * key_pos_cu;
+ const float3 key_pos_su = transforms.curves_to_surface * key_pos_cu;
const float3 key_pos_ha = surface_to_hair_mat * key_pos_su;
HairKey &key = hair_keys[key_i];
@@ -422,7 +465,6 @@ static int curves_convert_from_particle_system_exec(bContext *C, wmOperator *UNU
}
Object *ob_new = BKE_object_add(&bmain, &view_layer, OB_CURVES, psys_eval->name);
- ob_new->dtx |= OB_DRAWBOUNDOX; /* TODO: Remove once there is actual drawing. */
Curves *curves_id = static_cast<Curves *>(ob_new->data);
BKE_object_apply_mat4(ob_new, ob_from_orig->obmat, true, false);
bke::CurvesGeometry::wrap(curves_id->geometry) = particles_to_curves(*ob_from_eval, *psys_eval);
@@ -475,133 +517,169 @@ static bool snap_curves_to_surface_poll(bContext *C)
return true;
}
-static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
+static void snap_curves_to_surface_exec_object(Object &curves_ob,
+ const Object &surface_ob,
+ const AttachMode attach_mode,
+ bool *r_invalid_uvs,
+ bool *r_missing_uvs)
{
- const AttachMode attach_mode = static_cast<AttachMode>(RNA_enum_get(op->ptr, "attach_mode"));
+ Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
- std::atomic<bool> found_invalid_looptri_index = false;
+ Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data);
- CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) {
- if (curves_ob->type != OB_CURVES) {
- continue;
- }
- Curves &curves_id = *static_cast<Curves *>(curves_ob->data);
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
- if (curves_id.surface == nullptr) {
- continue;
- }
- Object &surface_ob = *curves_id.surface;
- if (surface_ob.type != OB_MESH) {
- continue;
- }
- Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data);
-
- MutableSpan<float3> positions_cu = curves.positions_for_write();
- MutableSpan<int> surface_triangle_indices = curves.surface_triangle_indices_for_write();
- MutableSpan<float2> surface_triangle_coords = curves.surface_triangle_coords_for_write();
-
- const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
- BKE_mesh_runtime_looptri_len(&surface_mesh)};
-
- const float4x4 curves_to_world_mat = curves_ob->obmat;
- const float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
- const float4x4 surface_to_world_mat = surface_ob.obmat;
- const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
- const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat;
- const float4x4 surface_to_curves_mat = world_to_curves_mat * surface_to_world_mat;
-
- switch (attach_mode) {
- case AttachMode::Nearest: {
- BVHTreeFromMesh surface_bvh;
- BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_mesh, BVHTREE_FROM_LOOPTRI, 2);
- BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
-
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
- for (const int curve_i : curves_range) {
- const IndexRange points = curves.points_for_curve(curve_i);
- const int first_point_i = points.first();
- const float3 old_first_point_pos_cu = positions_cu[first_point_i];
- const float3 old_first_point_pos_su = curves_to_surface_mat * old_first_point_pos_cu;
-
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(surface_bvh.tree,
- old_first_point_pos_su,
- &nearest,
- surface_bvh.nearest_callback,
- &surface_bvh);
- const int looptri_index = nearest.index;
- if (looptri_index == -1) {
- continue;
- }
-
- const float3 new_first_point_pos_su = nearest.co;
- const float3 new_first_point_pos_cu = surface_to_curves_mat * new_first_point_pos_su;
- const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
-
- for (float3 &pos_cu : positions_cu.slice(points)) {
- pos_cu += pos_diff_cu;
- }
-
- surface_triangle_indices[curve_i] = looptri_index;
+ VArraySpan<float2> surface_uv_map;
+ if (curves_id.surface_uv_map != nullptr) {
+ const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(surface_mesh);
+ surface_uv_map = surface_attributes
+ .lookup(curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
+ .typed<float2>();
+ }
+
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
+
+ const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
+ BKE_mesh_runtime_looptri_len(&surface_mesh)};
+
+ const bke::CurvesSurfaceTransforms transforms{curves_ob, &surface_ob};
+
+ switch (attach_mode) {
+ case AttachMode::Nearest: {
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_mesh, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const int first_point_i = points.first();
+ const float3 old_first_point_pos_cu = positions_cu[first_point_i];
+ const float3 old_first_point_pos_su = transforms.curves_to_surface *
+ old_first_point_pos_cu;
+
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(surface_bvh.tree,
+ old_first_point_pos_su,
+ &nearest,
+ surface_bvh.nearest_callback,
+ &surface_bvh);
+ const int looptri_index = nearest.index;
+ if (looptri_index == -1) {
+ continue;
+ }
+ const float3 new_first_point_pos_su = nearest.co;
+ const float3 new_first_point_pos_cu = transforms.surface_to_curves *
+ new_first_point_pos_su;
+ const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
+
+ for (float3 &pos_cu : positions_cu.slice(points)) {
+ pos_cu += pos_diff_cu;
+ }
+
+ if (!surface_uv_map.is_empty()) {
const MLoopTri &looptri = surface_looptris[looptri_index];
- const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
- const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
- const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
+ const int corner0 = looptri.tri[0];
+ const int corner1 = looptri.tri[1];
+ const int corner2 = looptri.tri[2];
+ const float2 &uv0 = surface_uv_map[corner0];
+ const float2 &uv1 = surface_uv_map[corner1];
+ const float2 &uv2 = surface_uv_map[corner2];
+ const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[corner0].v].co;
+ const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[corner1].v].co;
+ const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[corner2].v].co;
float3 bary_coords;
interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
- surface_triangle_coords[curve_i] = bke::curves::encode_surface_bary_coord(bary_coords);
+ const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
+ surface_uv_coords[curve_i] = uv;
}
- });
+ }
+ });
+ break;
+ }
+ case AttachMode::Deform: {
+ if (surface_uv_map.is_empty()) {
+ *r_missing_uvs = true;
break;
}
- case AttachMode::Deform: {
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
- for (const int curve_i : curves_range) {
- const IndexRange points = curves.points_for_curve(curve_i);
- const int first_point_i = points.first();
- const float3 old_first_point_pos_cu = positions_cu[first_point_i];
-
- const int looptri_index = surface_triangle_indices[curve_i];
- if (!surface_looptris.index_range().contains(looptri_index)) {
- found_invalid_looptri_index = true;
- continue;
- }
-
- const MLoopTri &looptri = surface_looptris[looptri_index];
+ using geometry::ReverseUVSampler;
+ ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
+
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const int first_point_i = points.first();
+ const float3 old_first_point_pos_cu = positions_cu[first_point_i];
+
+ const float2 uv = surface_uv_coords[curve_i];
+ ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv);
+ if (lookup_result.type != ReverseUVSampler::ResultType::Ok) {
+ *r_invalid_uvs = true;
+ continue;
+ }
- const float3 bary_coords = bke::curves::decode_surface_bary_coord(
- surface_triangle_coords[curve_i]);
+ const MLoopTri &looptri = *lookup_result.looptri;
+ const float3 &bary_coords = lookup_result.bary_weights;
- const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
- const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
- const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
+ const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
- float3 new_first_point_pos_su;
- interp_v3_v3v3v3(new_first_point_pos_su, p0_su, p1_su, p2_su, bary_coords);
- const float3 new_first_point_pos_cu = surface_to_curves_mat * new_first_point_pos_su;
+ float3 new_first_point_pos_su;
+ interp_v3_v3v3v3(new_first_point_pos_su, p0_su, p1_su, p2_su, bary_coords);
+ const float3 new_first_point_pos_cu = transforms.surface_to_curves *
+ new_first_point_pos_su;
- const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
- for (float3 &pos_cu : positions_cu.slice(points)) {
- pos_cu += pos_diff_cu;
- }
+ const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
+ for (float3 &pos_cu : positions_cu.slice(points)) {
+ pos_cu += pos_diff_cu;
}
- });
- break;
- }
+ }
+ });
+ break;
}
+ }
+
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+}
+
+static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
+{
+ const AttachMode attach_mode = static_cast<AttachMode>(RNA_enum_get(op->ptr, "attach_mode"));
- DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ bool found_invalid_uvs = false;
+ bool found_missing_uvs = false;
+
+ CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) {
+ if (curves_ob->type != OB_CURVES) {
+ continue;
+ }
+ Curves &curves_id = *static_cast<Curves *>(curves_ob->data);
+ if (curves_id.surface == nullptr) {
+ continue;
+ }
+ if (curves_id.surface->type != OB_MESH) {
+ continue;
+ }
+ snap_curves_to_surface_exec_object(
+ *curves_ob, *curves_id.surface, attach_mode, &found_invalid_uvs, &found_missing_uvs);
}
CTX_DATA_END;
- if (found_invalid_looptri_index) {
+ if (found_missing_uvs) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Curves do not have attachment information that can be used for deformation");
+ }
+ if (found_invalid_uvs) {
BKE_report(op->reports, RPT_INFO, "Could not snap some curves to the surface");
}
- WM_main_add_notifier(NC_OBJECT | ND_DRAW, nullptr);
+ /* Refresh the entire window to also clear eventual modifier and nodes editor warnings.*/
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
return OPERATOR_FINISHED;
}
@@ -645,6 +723,305 @@ static void CURVES_OT_snap_curves_to_surface(wmOperatorType *ot)
"How to find the point on the surface to attach to");
}
+bool selection_operator_poll(bContext *C)
+{
+ const Object *object = CTX_data_active_object(C);
+ if (object == nullptr) {
+ return false;
+ }
+ if (object->type != OB_CURVES) {
+ return false;
+ }
+ if (!BKE_id_is_editable(CTX_data_main(C), static_cast<const ID *>(object->data))) {
+ return false;
+ }
+ return true;
+}
+
+namespace set_selection_domain {
+
+static int curves_set_selection_domain_exec(bContext *C, wmOperator *op)
+{
+ const eAttrDomain domain = eAttrDomain(RNA_enum_get(op->ptr, "domain"));
+
+ for (Curves *curves_id : get_unique_editable_curves(*C)) {
+ if (curves_id->selection_domain == domain && (curves_id->flag & CV_SCULPT_SELECTION_ENABLED)) {
+ continue;
+ }
+
+ const eAttrDomain old_domain = eAttrDomain(curves_id->selection_domain);
+ curves_id->selection_domain = domain;
+ curves_id->flag |= CV_SCULPT_SELECTION_ENABLED;
+
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
+
+ if (old_domain == ATTR_DOMAIN_POINT && domain == ATTR_DOMAIN_CURVE) {
+ VArray<float> curve_selection = curves.adapt_domain(
+ curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ curve_selection.materialize(curves.selection_curve_float_for_write());
+ attributes.remove(".selection_point_float");
+ }
+ else if (old_domain == ATTR_DOMAIN_CURVE && domain == ATTR_DOMAIN_POINT) {
+ VArray<float> point_selection = curves.adapt_domain(
+ curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ point_selection.materialize(curves.selection_point_float_for_write());
+ attributes.remove(".selection_curve_float");
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace set_selection_domain
+
+static void CURVES_OT_set_selection_domain(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Set Select Mode";
+ ot->idname = __func__;
+ ot->description = "Change the mode used for selection masking in curves sculpt mode";
+
+ ot->exec = set_selection_domain::curves_set_selection_domain_exec;
+ ot->poll = selection_operator_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = prop = RNA_def_enum(
+ ot->srna, "domain", rna_enum_attribute_curves_domain_items, 0, "Domain", "");
+ RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
+}
+
+namespace disable_selection {
+
+static int curves_disable_selection_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ for (Curves *curves_id : get_unique_editable_curves(*C)) {
+ curves_id->flag &= ~CV_SCULPT_SELECTION_ENABLED;
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace disable_selection
+
+static void CURVES_OT_disable_selection(wmOperatorType *ot)
+{
+ ot->name = "Disable Selection";
+ ot->idname = __func__;
+ ot->description = "Disable the drawing of influence of selection in sculpt mode";
+
+ ot->exec = disable_selection::curves_disable_selection_exec;
+ ot->poll = selection_operator_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static bool varray_contains_nonzero(const VArray<float> &data)
+{
+ bool contains_nonzero = false;
+ devirtualize_varray(data, [&](const auto array) {
+ for (const int i : data.index_range()) {
+ if (array[i] != 0.0f) {
+ contains_nonzero = true;
+ break;
+ }
+ }
+ });
+ return contains_nonzero;
+}
+
+bool has_anything_selected(const Curves &curves_id)
+{
+ const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT:
+ return varray_contains_nonzero(curves.selection_point_float());
+ case ATTR_DOMAIN_CURVE:
+ return varray_contains_nonzero(curves.selection_curve_float());
+ }
+ BLI_assert_unreachable();
+ return false;
+}
+
+static bool any_point_selected(const CurvesGeometry &curves)
+{
+ return varray_contains_nonzero(curves.selection_point_float());
+}
+
+static bool any_point_selected(const Span<Curves *> curves_ids)
+{
+ for (const Curves *curves_id : curves_ids) {
+ if (any_point_selected(CurvesGeometry::wrap(curves_id->geometry))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+namespace select_all {
+
+static void invert_selection(MutableSpan<float> selection)
+{
+ threading::parallel_for(selection.index_range(), 2048, [&](IndexRange range) {
+ for (const int i : range) {
+ selection[i] = 1.0f - selection[i];
+ }
+ });
+}
+
+static int select_all_exec(bContext *C, wmOperator *op)
+{
+ int action = RNA_enum_get(op->ptr, "action");
+
+ VectorSet<Curves *> unique_curves = get_unique_editable_curves(*C);
+
+ if (action == SEL_TOGGLE) {
+ action = any_point_selected(unique_curves) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ for (Curves *curves_id : unique_curves) {
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ if (action == SEL_SELECT) {
+ /* As an optimization, just remove the selection attributes when everything is selected. */
+ bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
+ attributes.remove(".selection_point_float");
+ attributes.remove(".selection_curve_float");
+ }
+ else {
+ MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
+ curves.selection_point_float_for_write() :
+ curves.selection_curve_float_for_write();
+ if (action == SEL_DESELECT) {
+ selection.fill(0.0f);
+ }
+ else if (action == SEL_INVERT) {
+ invert_selection(selection);
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace select_all
+
+static void SCULPT_CURVES_OT_select_all(wmOperatorType *ot)
+{
+ ot->name = "(De)select All";
+ ot->idname = __func__;
+ ot->description = "(De)select all control points";
+
+ ot->exec = select_all::select_all_exec;
+ ot->poll = selection_operator_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+namespace surface_set {
+
+static bool surface_set_poll(bContext *C)
+{
+ const Object *object = CTX_data_active_object(C);
+ if (object == nullptr) {
+ return false;
+ }
+ if (object->type != OB_MESH) {
+ return false;
+ }
+ return true;
+}
+
+static int surface_set_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+
+ Object &new_surface_ob = *CTX_data_active_object(C);
+
+ Mesh &new_surface_mesh = *static_cast<Mesh *>(new_surface_ob.data);
+ const char *new_uv_map_name = CustomData_get_active_layer_name(&new_surface_mesh.ldata,
+ CD_MLOOPUV);
+
+ CTX_DATA_BEGIN (C, Object *, selected_ob, selected_objects) {
+ if (selected_ob->type != OB_CURVES) {
+ continue;
+ }
+ Object &curves_ob = *selected_ob;
+ Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
+
+ MEM_SAFE_FREE(curves_id.surface_uv_map);
+ if (new_uv_map_name != nullptr) {
+ curves_id.surface_uv_map = BLI_strdup(new_uv_map_name);
+ }
+
+ bool missing_uvs;
+ bool invalid_uvs;
+ snap_curves_to_surface::snap_curves_to_surface_exec_object(
+ curves_ob,
+ new_surface_ob,
+ snap_curves_to_surface::AttachMode::Nearest,
+ &invalid_uvs,
+ &missing_uvs);
+
+ /* Add deformation modifier if necessary. */
+ blender::ed::curves::ensure_surface_deformation_node_exists(*C, curves_ob);
+
+ curves_id.surface = &new_surface_ob;
+ ED_object_parent_set(
+ op->reports, C, scene, &curves_ob, &new_surface_ob, PAR_OBJECT, false, true, nullptr);
+
+ DEG_id_tag_update(&curves_ob.id, ID_RECALC_TRANSFORM);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id);
+
+ /* Required for deformation. */
+ new_surface_ob.modifier_flag |= OB_MODIFIER_FLAG_ADD_REST_POSITION;
+ DEG_id_tag_update(&new_surface_ob.id, ID_RECALC_GEOMETRY);
+ }
+ CTX_DATA_END;
+
+ DEG_relations_tag_update(bmain);
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace surface_set
+
+static void CURVES_OT_surface_set(wmOperatorType *ot)
+{
+ ot->name = "Set Curves Surface Object";
+ ot->idname = __func__;
+ ot->description =
+ "Use the active object as surface for selected curves objects and set it as the parent";
+
+ ot->exec = surface_set::surface_set_exec;
+ ot->poll = surface_set::surface_set_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
} // namespace blender::ed::curves
void ED_operatortypes_curves()
@@ -653,4 +1030,8 @@ void ED_operatortypes_curves()
WM_operatortype_append(CURVES_OT_convert_to_particle_system);
WM_operatortype_append(CURVES_OT_convert_from_particle_system);
WM_operatortype_append(CURVES_OT_snap_curves_to_surface);
+ WM_operatortype_append(CURVES_OT_set_selection_domain);
+ WM_operatortype_append(SCULPT_CURVES_OT_select_all);
+ WM_operatortype_append(CURVES_OT_disable_selection);
+ WM_operatortype_append(CURVES_OT_surface_set);
}
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 59370b53995..9da2c4819a3 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -776,9 +776,12 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curves.sculpt_comb
ops.curves.sculpt_cut
ops.curves.sculpt_delete
+ ops.curves.sculpt_density
ops.curves.sculpt_grow_shrink
ops.curves.sculpt_pinch
ops.curves.sculpt_puff
+ ops.curves.sculpt_slide
+ ops.curves.sculpt_smooth
ops.curves.sculpt_snake_hook
ops.generic.cursor
ops.generic.select
@@ -930,6 +933,7 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/mask.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/mix.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/nudge.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/paint_select.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/pinch.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/scrape.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/smear.png SRC)
@@ -967,6 +971,19 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_hard.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/gp_brush_erase_stroke.png SRC)
+ # curve sculpt
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_add.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_comb.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_cut.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_delete.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_density.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_grow_shrink.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_pinch.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_puff.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_slide.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_smooth.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/curves_sculpt_snake_hook.png SRC)
+
endif()
data_to_c_simple(../../../../release/datafiles/startup.blend SRC)
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index cfc158b117f..4cf14334ac7 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -33,6 +33,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "ED_geometry.h"
#include "ED_object.h"
#include "geometry_intern.hh"
@@ -43,9 +44,9 @@ namespace blender::ed::geometry {
static bool geometry_attributes_poll(bContext *C)
{
- Object *ob = ED_object_context(C);
- Main *bmain = CTX_data_main(C);
- ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
+ const Object *ob = ED_object_context(C);
+ const Main *bmain = CTX_data_main(C);
+ const ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr;
return (ob && BKE_id_is_editable(bmain, &ob->id) && data && BKE_id_is_editable(bmain, data)) &&
BKE_id_attributes_supported(data);
}
@@ -89,8 +90,8 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
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");
+ eCustomDataType type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type");
+ eAttrDomain domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain");
CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
if (layer == nullptr) {
@@ -105,7 +106,7 @@ static int geometry_attribute_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_render)
+static void next_color_attribute(ID *id, CustomDataLayer *layer, bool is_render)
{
int index = BKE_id_attribute_to_index(id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -128,7 +129,7 @@ static void next_color_attribute(struct ID *id, CustomDataLayer *layer, bool is_
}
}
-static void next_color_attributes(struct ID *id, CustomDataLayer *layer)
+static void next_color_attributes(ID *id, CustomDataLayer *layer)
{
next_color_attribute(id, layer, false); /* active */
next_color_attribute(id, layer, true); /* render */
@@ -181,7 +182,7 @@ static int geometry_attribute_remove_exec(bContext *C, wmOperator *op)
next_color_attributes(id, layer);
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ if (!BKE_id_attribute_remove(id, layer->name, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -218,8 +219,8 @@ static int geometry_color_attribute_add_exec(bContext *C, wmOperator *op)
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");
+ eCustomDataType type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type");
+ eAttrDomain domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain");
CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports);
float color[4];
@@ -260,8 +261,11 @@ static bool geometry_attribute_convert_poll(bContext *C)
if (GS(data->name) != ID_ME) {
return false;
}
- CustomDataLayer *layer = BKE_id_attributes_active_get(data);
- if (layer == nullptr) {
+ if (CTX_data_edit_object(C) != nullptr) {
+ CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode");
+ return false;
+ }
+ if (BKE_id_attributes_active_get(data) == nullptr) {
return false;
}
return true;
@@ -278,8 +282,7 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
RNA_enum_get(op->ptr, "mode"));
Mesh *mesh = reinterpret_cast<Mesh *>(ob_data);
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
/* General conversion steps are always the same:
* 1. Convert old data to right domain and data type.
@@ -288,9 +291,8 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
* 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>(
+ const eAttrDomain dst_domain = static_cast<eAttrDomain>(RNA_enum_get(op->ptr, "domain"));
+ const eCustomDataType dst_type = static_cast<eCustomDataType>(
RNA_enum_get(op->ptr, "data_type"));
if (ELEM(dst_type, CD_PROP_STRING)) {
@@ -298,33 +300,33 @@ static int geometry_attribute_convert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type);
+ GVArray src_varray = attributes.lookup_or_default(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));
+ attributes.remove(name);
+ attributes.add(name, dst_domain, dst_type, blender::bke::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>(
+ VArray<float2> src_varray = attributes.lookup_or_default<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);
+ attributes.remove(name);
CustomData_add_layer_named(
&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, 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>(
+ VArray<float> src_varray = attributes.lookup_or_default<float>(
name, ATTR_DOMAIN_POINT, 0.0f);
src_varray.materialize(src_weights);
- mesh_component.attribute_try_delete(name);
+ attributes.remove(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);
@@ -402,7 +404,7 @@ void GEOMETRY_OT_color_attribute_add(wmOperatorType *ot)
static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
prop = RNA_def_float_color(
- ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
+ ot->srna, "color", 4, nullptr, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
RNA_def_property_float_array_default(prop, default_color);
}
@@ -465,7 +467,7 @@ static int geometry_color_attribute_remove_exec(bContext *C, wmOperator *op)
next_color_attributes(id, layer);
- if (!BKE_id_attribute_remove(id, layer, op->reports)) {
+ if (!BKE_id_attribute_remove(id, layer->name, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -495,6 +497,7 @@ static bool geometry_color_attributes_remove_poll(bContext *C)
return false;
}
+
void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
{
/* identifiers */
@@ -510,6 +513,64 @@ void GEOMETRY_OT_color_attribute_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static int geometry_color_attribute_duplicate_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_context(C);
+ ID *id = static_cast<ID *>(ob->data);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(id);
+
+ if (layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ CustomDataLayer *new_layer = BKE_id_attribute_duplicate(id, layer->name, op->reports);
+ if (new_layer == nullptr) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_id_attributes_active_color_set(id, new_layer);
+
+ DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, id);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool geometry_color_attributes_duplicate_poll(bContext *C)
+{
+ if (!geometry_attributes_poll(C)) {
+ return false;
+ }
+ if (CTX_data_edit_object(C) != nullptr) {
+ CTX_wm_operator_poll_msg_set(C, "Operation is not allowed in edit mode");
+ return false;
+ }
+
+ Object *ob = ED_object_context(C);
+ ID *data = ob ? static_cast<ID *>(ob->data) : nullptr;
+
+ if (BKE_id_attributes_active_color_get(data) != nullptr) {
+ return true;
+ }
+
+ return false;
+}
+
+void GEOMETRY_OT_color_attribute_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Duplicate Color Attribute";
+ ot->description = "Duplicate color attribute";
+ ot->idname = "GEOMETRY_OT_color_attribute_duplicate";
+
+ /* api callbacks */
+ ot->exec = geometry_color_attribute_duplicate_exec;
+ ot->poll = geometry_color_attributes_duplicate_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
@@ -572,3 +633,39 @@ void GEOMETRY_OT_attribute_convert(wmOperatorType *ot)
}
} // namespace blender::ed::geometry
+
+using blender::CPPType;
+using blender::GVArray;
+
+bool ED_geometry_attribute_convert(Mesh *mesh,
+ const char *layer_name,
+ eCustomDataType old_type,
+ eAttrDomain old_domain,
+ eCustomDataType new_type,
+ eAttrDomain new_domain)
+{
+ CustomDataLayer *layer = BKE_id_attribute_find(&mesh->id, layer_name, old_type, old_domain);
+ const std::string name = layer->name;
+
+ if (!layer) {
+ return false;
+ }
+
+ blender::bke::MutableAttributeAccessor attributes = blender::bke::mesh_attributes_for_write(
+ *mesh);
+
+ GVArray src_varray = attributes.lookup_or_default(name, new_domain, new_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);
+ attributes.remove(name);
+ attributes.add(name, new_domain, new_type, blender::bke::AttributeInitMove(new_data));
+
+ int *active_index = BKE_id_attributes_active_index_p(&mesh->id);
+ if (*active_index > 0) {
+ *active_index -= 1;
+ }
+
+ return true;
+}
diff --git a/source/blender/editors/geometry/geometry_intern.hh b/source/blender/editors/geometry/geometry_intern.hh
index bbcb682d6bf..a1000a5d01f 100644
--- a/source/blender/editors/geometry/geometry_intern.hh
+++ b/source/blender/editors/geometry/geometry_intern.hh
@@ -17,6 +17,7 @@ void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_add(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_remove(struct wmOperatorType *ot);
void GEOMETRY_OT_color_attribute_render_set(struct wmOperatorType *ot);
+void GEOMETRY_OT_color_attribute_duplicate(struct wmOperatorType *ot);
void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot);
} // namespace blender::ed::geometry
diff --git a/source/blender/editors/geometry/geometry_ops.cc b/source/blender/editors/geometry/geometry_ops.cc
index 23f6e6f29f4..acac757ecf1 100644
--- a/source/blender/editors/geometry/geometry_ops.cc
+++ b/source/blender/editors/geometry/geometry_ops.cc
@@ -22,5 +22,6 @@ void ED_operatortypes_geometry(void)
WM_operatortype_append(GEOMETRY_OT_color_attribute_add);
WM_operatortype_append(GEOMETRY_OT_color_attribute_remove);
WM_operatortype_append(GEOMETRY_OT_color_attribute_render_set);
+ WM_operatortype_append(GEOMETRY_OT_color_attribute_duplicate);
WM_operatortype_append(GEOMETRY_OT_attribute_convert);
}
diff --git a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
index 5b514e02099..429bf39234f 100644
--- a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
+++ b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
@@ -7,6 +7,8 @@
#include "../gizmo_geometry.h"
+/* The numerical values in the `verts` array are used in arrow3d_gizmo.c
+ * If you change this mesh geometry, update the selection code also. */
static float verts[][3] = {
{-0.000000, 0.012320, 0.000000}, {-0.000000, 0.012320, 0.974306},
{0.008711, 0.008711, 0.000000}, {0.008711, 0.008711, 0.974306},
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 a1fb0e205b1..cde702294d0 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -50,16 +50,19 @@
/* to use custom arrows exported to geom_arrow_gizmo.c */
//#define USE_GIZMO_CUSTOM_ARROWS
-/** Margins to add when selecting the arrow stem. */
-#define ARROW_SELECT_THRESHOLD_PX_STEM (5 * UI_DPI_FAC)
-/** Margins to add when selecting the arrow head. */
-#define ARROW_SELECT_THRESHOLD_PX_HEAD (12 * UI_DPI_FAC)
+/* Margin to add when selecting the arrow. */
+#define ARROW_SELECT_THRESHOLD_PX (5)
typedef struct ArrowGizmo3D {
wmGizmo gizmo;
GizmoCommonData data;
} ArrowGizmo3D;
+typedef struct ArrowGizmoInteraction {
+ GizmoInteraction inter;
+ float init_arrow_length;
+} ArrowGizmoInteraction;
+
/* -------------------------------------------------------------------- */
static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
@@ -70,7 +73,10 @@ static void gizmo_arrow_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4]
madd_v3_v3fl(r_matrix[3], arrow->gizmo.matrix_basis[2], arrow->data.offset);
}
-static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const float color[4])
+static void arrow_draw_geom(const ArrowGizmo3D *arrow,
+ const bool select,
+ const float color[4],
+ const float arrow_length)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
bool unbind_shader = true;
@@ -113,16 +119,14 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
#ifdef USE_GIZMO_CUSTOM_ARROWS
wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_arrow, select, color);
#else
- const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length");
-
const float vec[2][3] = {
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, arrow_length},
};
if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_STEM) {
- const float stem_width = (arrow->gizmo.line_width * U.pixelsize) +
- (select ? ARROW_SELECT_THRESHOLD_PX_STEM : 0);
+ const float stem_width = arrow->gizmo.line_width * U.pixelsize +
+ (select ? ARROW_SELECT_THRESHOLD_PX * U.dpi_fac : 0);
immUniform1f("lineWidth", stem_width);
wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_STRIP);
}
@@ -134,7 +138,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
GPU_matrix_push();
- /* NOTE: ideally #ARROW_SELECT_THRESHOLD_PX_HEAD would be added here, however adding a
+ /* NOTE: ideally #ARROW_SELECT_THRESHOLD_PX would be added here, however adding a
* margin in pixel space isn't so simple, nor is it as important as for the arrow stem. */
if (draw_style == ED_GIZMO_ARROW_STYLE_BOX) {
const float size = 0.05f;
@@ -178,6 +182,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool highlight)
{
wmGizmo *gz = &arrow->gizmo;
+ const float arrow_length = RNA_float_get(gz->ptr, "length");
float color[4];
float matrix_final[4][4];
@@ -188,19 +193,20 @@ static void arrow_draw_intern(ArrowGizmo3D *arrow, const bool select, const bool
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
- arrow_draw_geom(arrow, select, color);
+ arrow_draw_geom(arrow, select, color, arrow_length);
GPU_blend(GPU_BLEND_NONE);
GPU_matrix_pop();
if (gz->interaction_data) {
- GizmoInteraction *inter = gz->interaction_data;
+ ArrowGizmoInteraction *arrow_inter = gz->interaction_data;
GPU_matrix_push();
- GPU_matrix_mul(inter->init_matrix_final);
+ GPU_matrix_mul(arrow_inter->inter.init_matrix_final);
GPU_blend(GPU_BLEND_ALPHA);
- arrow_draw_geom(arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f});
+ arrow_draw_geom(
+ arrow, select, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}, arrow_inter->init_arrow_length);
GPU_blend(GPU_BLEND_NONE);
GPU_matrix_pop();
@@ -223,9 +229,15 @@ static void gizmo_arrow_draw(const bContext *UNUSED(C), wmGizmo *gz)
*/
static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
{
+ /* This following values are based on manual inspection of `verts[]` defined in
+ * geom_arrow_gizmo.c */
+ const float head_center_z = (0.974306f + 1.268098f) / 2;
+ const float head_geo_x = 0.051304f;
+ const float stem_geo_x = 0.012320f;
+
/* Project into 2D space since it simplifies pixel threshold tests. */
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
- const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length");
+ const float arrow_length = RNA_float_get(arrow->gizmo.ptr, "length") * head_center_z;
float matrix_final[4][4];
WM_gizmo_calc_matrix_final(gz, matrix_final);
@@ -239,12 +251,15 @@ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m
copy_v2_v2(arrow_end, co);
}
+ const float scale_final = mat4_to_scale(matrix_final);
+ const float head_width = ARROW_SELECT_THRESHOLD_PX * scale_final * head_geo_x;
+ const float stem_width = ARROW_SELECT_THRESHOLD_PX * scale_final * stem_geo_x;
+ float select_threshold_base = gz->line_width * U.pixelsize;
+
const float mval_fl[2] = {UNPACK2(mval)};
- const float arrow_stem_threshold_px = ARROW_SELECT_THRESHOLD_PX_STEM;
- const float arrow_head_threshold_px = ARROW_SELECT_THRESHOLD_PX_HEAD;
/* Distance to arrow head. */
- if (len_squared_v2v2(mval_fl, arrow_end) < square_f(arrow_head_threshold_px)) {
+ if (len_squared_v2v2(mval_fl, arrow_end) < square_f(select_threshold_base + head_width)) {
return 0;
}
@@ -253,8 +268,8 @@ static int gizmo_arrow_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m
const float lambda = closest_to_line_v2(co_isect, mval_fl, arrow_start, arrow_end);
/* Clamp inside the line, to avoid overlapping with other gizmos,
* especially around the start of the arrow. */
- if (lambda >= 0.0 && lambda <= 1.0) {
- if (len_squared_v2v2(mval_fl, co_isect) < square_f(arrow_stem_threshold_px)) {
+ if (lambda >= 0.0f && lambda <= 1.0f) {
+ if (len_squared_v2v2(mval_fl, co_isect) < square_f(select_threshold_base + stem_width)) {
return 0;
}
}
@@ -373,7 +388,7 @@ static void gizmo_arrow_setup(wmGizmo *gz)
static int gizmo_arrow_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
{
ArrowGizmo3D *arrow = (ArrowGizmo3D *)gz;
- GizmoInteraction *inter = MEM_callocN(sizeof(GizmoInteraction), __func__);
+ GizmoInteraction *inter = MEM_callocN(sizeof(ArrowGizmoInteraction), __func__);
wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
/* Some gizmos don't use properties. */
@@ -389,6 +404,8 @@ static int gizmo_arrow_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *e
gizmo_arrow_matrix_basis_get(gz, inter->init_matrix_basis);
WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
+ ((ArrowGizmoInteraction *)inter)->init_arrow_length = RNA_float_get(gz->ptr, "length");
+
gz->interaction_data = inter;
return OPERATOR_RUNNING_MODAL;
@@ -513,7 +530,8 @@ static void GIZMO_GT_arrow_3d(wmGizmoType *gzt)
"");
RNA_def_enum_flag(gzt->srna, "transform", rna_enum_transform_items, 0, "Transform", "");
- RNA_def_float(gzt->srna, "length", 1.0f, 0.0f, FLT_MAX, "Arrow Line Length", "", 0.0f, FLT_MAX);
+ RNA_def_float(
+ gzt->srna, "length", 1.0f, -FLT_MAX, FLT_MAX, "Arrow Line Length", "", -FLT_MAX, FLT_MAX);
RNA_def_float_vector(
gzt->srna, "aspect", 2, NULL, 0, FLT_MAX, "Aspect", "Cone/box style only", 0.0f, FLT_MAX);
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 a0e30c7518a..2c886230f10 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -57,8 +57,6 @@ typedef struct ButtonGizmo2D {
GPUBatch *shape_batch[2];
} ButtonGizmo2D;
-#define CIRCLE_RESOLUTION 32
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -68,11 +66,17 @@ typedef struct ButtonGizmo2D {
static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float color[4],
const float fill_alpha,
- const bool select)
+ const bool select,
+ const float screen_scale)
{
float viewport[4];
GPU_viewport_size_get_f(viewport);
+ const float max_pixel_error = 0.25f;
+ int nsegments = (int)(ceilf(M_PI / acosf(1.0f - max_pixel_error / screen_scale)));
+ nsegments = max_ff(nsegments, 8);
+ nsegments = min_ff(nsegments, 1000);
+
GPUVertFormat *format = immVertexFormat();
/* NOTE(Metal): Prefer 3D coordinate for 2D rendering when using 3D shader. */
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
@@ -81,14 +85,14 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
if (color[3] == 1.0 && fill_alpha == 1.0 && select == false) {
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
- imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
- imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
else {
@@ -97,7 +101,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float fill_color[4] = {UNPACK3(color), fill_alpha * color[3]};
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(fill_color);
- imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_fill_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
@@ -107,7 +111,7 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
immUniform2fv("viewportSize", &viewport[2]);
immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
- imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, CIRCLE_RESOLUTION);
+ imm_draw_circle_wire_3d(pos, 0.0f, 0.0f, 1.0f, nsegments);
immUnbindProgram();
}
}
@@ -173,6 +177,7 @@ static void button2d_draw_intern(const bContext *C,
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
+ float screen_scale = 200.0f;
if (is_3d) {
RegionView3D *rv3d = CTX_wm_region_view3d(C);
float matrix_align[4][4];
@@ -183,10 +188,13 @@ static void button2d_draw_intern(const bContext *C,
transpose_m4(matrix_align);
GPU_matrix_mul(matrix_align);
}
+ else {
+ screen_scale = mat4_to_scale(matrix_final);
+ }
if (select) {
BLI_assert(is_3d);
- button2d_geom_draw_backdrop(gz, color, 1.0, select);
+ button2d_geom_draw_backdrop(gz, color, 1.0, select, screen_scale);
}
else {
@@ -194,7 +202,7 @@ static void button2d_draw_intern(const bContext *C,
if (draw_options & ED_GIZMO_BUTTON_SHOW_BACKDROP) {
const float fill_alpha = RNA_float_get(gz->ptr, "backdrop_fill_alpha");
- button2d_geom_draw_backdrop(gz, color, fill_alpha, select);
+ button2d_geom_draw_backdrop(gz, color, fill_alpha, select, screen_scale);
}
if (button->shape_batch[0] != NULL) {
@@ -315,10 +323,11 @@ static int gizmo_button2d_cursor_get(wmGizmo *gz)
return WM_CURSOR_DEFAULT;
}
+#define CIRCLE_RESOLUTION_3D 32
static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box)
{
ScrArea *area = CTX_wm_area(C);
- float rad = CIRCLE_RESOLUTION * U.dpi_fac / 2.0f;
+ float rad = CIRCLE_RESOLUTION_3D * U.dpi_fac / 2.0f;
const float *co = NULL;
float matrix_final[4][4];
float co_proj[3];
@@ -342,6 +351,7 @@ static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box
}
}
else {
+ rad = mat4_to_scale(matrix_final);
co = matrix_final[3];
}
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 1d9fc35eda8..9b7b157dc7e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -77,6 +77,21 @@ typedef struct DialInteraction {
#define DIAL_CLIP_BIAS 0.02
/* -------------------------------------------------------------------- */
+struct Dial3dParams {
+ int draw_options;
+ float angle_ofs;
+ float angle_delta;
+ float angle_increment;
+ float arc_partial_angle;
+ float arc_inner_factor;
+ float *clip_plane;
+};
+static void dial_3d_draw_util(const float matrix_basis[4][4],
+ const float matrix_final[4][4],
+ const float line_width,
+ const float color[4],
+ const bool select,
+ struct Dial3dParams *params);
static void dial_geom_draw(const float color[4],
const float line_width,
@@ -411,23 +426,26 @@ static void dial_draw_intern(
if (WM_gizmo_target_property_is_valid(gz_prop)) {
angle_delta = WM_gizmo_target_property_float_get(gz, gz_prop);
}
+ if (gz->state & WM_GIZMO_STATE_MODAL) {
+ angle_increment = RNA_float_get(gz->ptr, "incremental_angle");
+ }
}
}
- ED_gizmotypes_dial_3d_draw_util(gz->matrix_basis,
- matrix_final,
- gz->line_width,
- color,
- select,
- &(struct Dial3dParams){
- .draw_options = draw_options,
- .angle_ofs = angle_ofs,
- .angle_delta = angle_delta,
- .angle_increment = angle_increment,
- .arc_partial_angle = arc_partial_angle,
- .arc_inner_factor = arc_inner_factor,
- .clip_plane = clip_plane,
- });
+ dial_3d_draw_util(gz->matrix_basis,
+ matrix_final,
+ gz->line_width,
+ color,
+ select,
+ &(struct Dial3dParams){
+ .draw_options = draw_options,
+ .angle_ofs = angle_ofs,
+ .angle_delta = angle_delta,
+ .angle_increment = angle_increment,
+ .arc_partial_angle = arc_partial_angle,
+ .arc_inner_factor = arc_inner_factor,
+ .clip_plane = clip_plane,
+ });
}
static void gizmo_dial_draw_select(const bContext *C, wmGizmo *gz, int select_id)
@@ -479,6 +497,10 @@ static int gizmo_dial_modal(bContext *C,
eWM_GizmoFlagTweak tweak_flag)
{
DialInteraction *inter = gz->interaction_data;
+ if (!inter) {
+ return OPERATOR_CANCELLED;
+ }
+
if ((event->type != MOUSEMOVE) && (inter->prev.tweak_flag == tweak_flag)) {
return OPERATOR_RUNNING_MODAL;
}
@@ -519,30 +541,33 @@ static int gizmo_dial_modal(bContext *C,
static void gizmo_dial_exit(bContext *C, wmGizmo *gz, const bool cancel)
{
DialInteraction *inter = gz->interaction_data;
- bool use_reset_value = false;
- float reset_value = 0.0f;
- if (cancel) {
- /* Set the property for the operator and call its modal function. */
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
- if (WM_gizmo_target_property_is_valid(gz_prop)) {
- use_reset_value = true;
- reset_value = inter->init.prop_angle;
- }
- }
- else {
- if (inter->has_drag == false) {
- PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value");
- if (RNA_property_is_set(gz->ptr, prop)) {
+ if (inter) {
+ bool use_reset_value = false;
+ float reset_value = 0.0f;
+
+ if (cancel) {
+ /* Set the property for the operator and call its modal function. */
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
use_reset_value = true;
- reset_value = RNA_property_float_get(gz->ptr, prop);
+ reset_value = inter->init.prop_angle;
+ }
+ }
+ else {
+ if (inter->has_drag == false) {
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "click_value");
+ if (RNA_property_is_set(gz->ptr, prop)) {
+ use_reset_value = true;
+ reset_value = RNA_property_float_get(gz->ptr, prop);
+ }
}
}
- }
- if (use_reset_value) {
- wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
- if (WM_gizmo_target_property_is_valid(gz_prop)) {
- WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value);
+ if (use_reset_value) {
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
+ if (WM_gizmo_target_property_is_valid(gz_prop)) {
+ WM_gizmo_target_property_float_set(C, gz, gz_prop, reset_value);
+ }
}
}
@@ -564,6 +589,11 @@ static void gizmo_dial_setup(wmGizmo *gz)
static int gizmo_dial_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
{
+ if (gz->custom_modal) {
+ /* #DialInteraction is only used for the inner modal. */
+ return OPERATOR_RUNNING_MODAL;
+ }
+
DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__);
inter->init.mval[0] = event->mval[0];
@@ -583,12 +613,12 @@ static int gizmo_dial_invoke(bContext *UNUSED(C), wmGizmo *gz, const wmEvent *ev
/** \name Dial Gizmo API
* \{ */
-void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
- const float matrix_final[4][4],
- const float line_width,
- const float color[4],
- const bool select,
- struct Dial3dParams *params)
+static void dial_3d_draw_util(const float matrix_basis[4][4],
+ const float matrix_final[4][4],
+ const float line_width,
+ const float color[4],
+ const bool select,
+ struct Dial3dParams *params)
{
GPU_matrix_push();
GPU_matrix_mul(matrix_final);
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 46fede8f6be..af1f09d7e25 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -278,12 +278,13 @@ static int gizmo_move_modal(bContext *C,
CTX_data_ensure_evaluated_depsgraph(C),
region,
CTX_wm_view3d(C),
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST),
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_EDIT,
.use_occlusion_test = true,
},
+ NULL,
mval_fl,
NULL,
&dist_px,
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 1659afb1254..c5a542c0bf3 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -96,7 +96,7 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
float r_loc[3],
float r_nor[3],
int r_elem_index[3],
- int *r_snap_elem)
+ eSnapMode *r_snap_elem)
{
if (C) {
/* Snap values are updated too late at the cursor. Be sure to update ahead of time. */
@@ -283,7 +283,7 @@ static int snap_gizmo_test_select(bContext *C, wmGizmo *gz, const int mval[2])
ED_view3d_cursor_snap_data_update(snap_gizmo->snap_state, C, x, y);
V3DSnapCursorData *snap_data = ED_view3d_cursor_snap_data_get();
- if (snap_data->snap_elem) {
+ if (snap_data->snap_elem != SCE_SNAP_MODE_NONE) {
return 0;
}
return -1;
@@ -345,7 +345,7 @@ static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
prop = RNA_def_enum_flag(gzt->srna,
"snap_elements_force",
rna_enum_snap_element_items,
- SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST,
"Snap Elements",
"");
RNA_def_property_enum_funcs_runtime(prop,
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index f720f261ad5..ae09aea28d3 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -841,7 +841,8 @@ void ED_annotation_draw_2dimage(const bContext *C)
}
/* draw it! */
- annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, area->spacetype);
+ annotation_draw_data_all(
+ scene, gpd, offsx, offsy, sizex, sizey, scene->r.cfra, dflag, area->spacetype);
}
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
@@ -877,7 +878,7 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
}
annotation_draw_data_all(
- scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype);
+ scene, gpd, 0, 0, region->winx, region->winy, scene->r.cfra, dflag, area->spacetype);
}
void ED_annotation_draw_view3d(
@@ -928,7 +929,8 @@ void ED_annotation_draw_view3d(
}
/* draw it! */
- annotation_draw_data_all(scene, gpd, offsx, offsy, winx, winy, CFRA, dflag, v3d->spacetype);
+ annotation_draw_data_all(
+ scene, gpd, offsx, offsy, winx, winy, scene->r.cfra, dflag, v3d->spacetype);
}
void ED_annotation_draw_ex(
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 8c393cc4f3f..2d613e2f433 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1568,7 +1568,7 @@ static void annotation_paint_initstroke(tGPsdata *p,
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_frame_get(p->gpl, scene->r.cfra, add_frame_mode);
if (p->gpf == NULL) {
p->status = GP_STATUS_ERROR;
@@ -2062,11 +2062,18 @@ static void annotation_draw_apply_event(
PointerRNA itemptr;
float mousef[2];
- /* convert from window-space to area-space mouse coordinates
- * add any x,y override position for fake events
- */
- p->mval[0] = (float)event->mval[0] - x;
- p->mval[1] = (float)event->mval[1] - y;
+ /* Convert from window-space to area-space mouse coordinates
+ * add any x,y override position for fake events. */
+ if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
+ /* The first run may be a drag event, see: T99368. */
+ WM_event_drag_start_mval_fl(event, p->region, p->mval);
+ p->mval[0] -= x;
+ p->mval[1] -= y;
+ }
+ else {
+ p->mval[0] = (float)event->mval[0] - x;
+ p->mval[1] = (float)event->mval[1] - y;
+ }
/* Key to toggle stabilization. */
if ((event->modifier & KM_SHIFT) && (p->paintmode == GP_PAINTMODE_DRAW)) {
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 011a5a66695..24de50db397 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -80,9 +80,9 @@ typedef enum eDrawStrokeFlags {
GP_DRAWDATA_ONLYI2D = (1 << 3),
/** special hack for drawing strokes in Image Editor (weird coordinates) */
GP_DRAWDATA_IEDITHACK = (1 << 4),
- /** don't draw xray in 3D view (which is default) */
+ /** Don't draw XRAY in 3D view (which is default). */
GP_DRAWDATA_NO_XRAY = (1 << 5),
- /** no onionskins should be drawn (for animation playback) */
+ /** No onion-skins should be drawn (for animation playback). */
GP_DRAWDATA_NO_ONIONS = (1 << 6),
/** draw strokes as "volumetric" circular billboards */
GP_DRAWDATA_VOLUMETRIC = (1 << 7),
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 949043e4be1..8a98dcb57fc 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -214,6 +214,18 @@ void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked,
}
}
+void ED_gpencil_set_active_channel(bGPdata *gpd, bGPDlayer *gpl)
+{
+ gpl->flag |= GP_LAYER_SELECT;
+
+ /* Update other layer status. */
+ if (BKE_gpencil_layer_active_get(gpd) != gpl) {
+ BKE_gpencil_layer_active_set(gpd, gpl);
+ BKE_gpencil_layer_autolock_set(gpd, false);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+}
+
/* ***************************************** */
/* Frame Editing Tools */
@@ -316,8 +328,13 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* assume that each of these is a GP layer */
for (ale = anim_data.first; ale; ale = ale->next) {
+ /* This function only deals with grease pencil layer frames.
+ * This check is needed in the case of a call from the main dopesheet. */
+ if (ale->type != ANIMTYPE_GPLAYER) {
+ continue;
+ }
+
ListBase copied_frames = {NULL, NULL};
bGPDlayer *gpl = (bGPDlayer *)ale->data;
@@ -354,19 +371,13 @@ bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
}
/* in case 'relative' paste method is used */
- gpencil_anim_copy_cfra = CFRA;
+ gpencil_anim_copy_cfra = scene->r.cfra;
/* clean up */
ANIM_animdata_freelist(&anim_data);
- /* check if anything ended up in the buffer */
- if (ELEM(NULL, gpencil_anim_copybuf.first, gpencil_anim_copybuf.last)) {
- BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
- return false;
- }
-
/* report success */
- return true;
+ return !BLI_listbase_is_empty(&gpencil_anim_copybuf);
}
bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
@@ -381,7 +392,6 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* check if buffer is empty */
if (BLI_listbase_is_empty(&gpencil_anim_copybuf)) {
- BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste");
return false;
}
@@ -393,13 +403,13 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* methods of offset (eKeyPasteOffset) */
switch (offset_mode) {
case KEYFRAME_PASTE_OFFSET_CFRA_START:
- offset = (CFRA - gpencil_anim_copy_firstframe);
+ offset = (scene->r.cfra - gpencil_anim_copy_firstframe);
break;
case KEYFRAME_PASTE_OFFSET_CFRA_END:
- offset = (CFRA - gpencil_anim_copy_lastframe);
+ offset = (scene->r.cfra - gpencil_anim_copy_lastframe);
break;
case KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE:
- offset = (CFRA - gpencil_anim_copy_cfra);
+ offset = (scene->r.cfra - gpencil_anim_copy_cfra);
break;
case KEYFRAME_PASTE_OFFSET_NONE:
offset = 0;
@@ -414,6 +424,11 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
/* from selected channels */
for (ale = anim_data.first; ale; ale = ale->next) {
+ /* only deal with GPlayers (case of calls from general dopesheet) */
+ if (ale->type != ANIMTYPE_GPLAYER) {
+ continue;
+ }
+
bGPDlayer *gpld = (bGPDlayer *)ale->data;
bGPDlayer *gpls = NULL;
bGPDframe *gpfs, *gpf;
@@ -503,7 +518,7 @@ static bool gpencil_frame_snap_nearestsec(bGPDframe *gpf, Scene *scene)
static bool gpencil_frame_snap_cframe(bGPDframe *gpf, Scene *scene)
{
if (gpf->flag & GP_FRAME_SELECT) {
- gpf->framenum = (int)CFRA;
+ gpf->framenum = (int)scene->r.cfra;
}
return false;
}
@@ -545,8 +560,8 @@ static bool gpencil_frame_mirror_cframe(bGPDframe *gpf, Scene *scene)
int diff;
if (gpf->flag & GP_FRAME_SELECT) {
- diff = CFRA - gpf->framenum;
- gpf->framenum = CFRA + diff;
+ diff = scene->r.cfra - gpf->framenum;
+ gpf->framenum = scene->r.cfra + diff;
}
return false;
diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c
index 2f22fad53e7..e8e6d328804 100644
--- a/source/blender/editors/gpencil/gpencil_add_blank.c
+++ b/source/blender/editors/gpencil/gpencil_add_blank.c
@@ -76,7 +76,7 @@ void ED_gpencil_create_blank(bContext *C, Object *ob, float UNUSED(mat[4][4]))
bGPDlayer *layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false);
/* frames */
- BKE_gpencil_frame_addnew(layer, CFRA);
+ BKE_gpencil_frame_addnew(layer, scene->r.cfra);
/* update depsgraph */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c
index 65ee732f6a9..bc046e89d21 100644
--- a/source/blender/editors/gpencil/gpencil_add_monkey.c
+++ b/source/blender/editors/gpencil/gpencil_add_monkey.c
@@ -844,8 +844,8 @@ void ED_gpencil_create_monkey(bContext *C, Object *ob, float mat[4][4])
/* frames */
/* NOTE: No need to check for existing, as this will take care of it for us */
- bGPDframe *frameFills = BKE_gpencil_frame_addnew(Fills, CFRA);
- bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, CFRA);
+ bGPDframe *frameFills = BKE_gpencil_frame_addnew(Fills, scene->r.cfra);
+ bGPDframe *frameLines = BKE_gpencil_frame_addnew(Lines, scene->r.cfra);
/* generate strokes */
gps = BKE_gpencil_stroke_add(frameFills, color_Skin, 270, 75, false);
diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c
index bc5fe9b5cfb..e24964c4832 100644
--- a/source/blender/editors/gpencil/gpencil_add_stroke.c
+++ b/source/blender/editors/gpencil/gpencil_add_stroke.c
@@ -211,8 +211,8 @@ void ED_gpencil_create_stroke(bContext *C, Object *ob, float mat[4][4])
bGPDlayer *lines = BKE_gpencil_layer_addnew(gpd, "Lines", true, false);
/* frames */
- bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, CFRA);
- bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, CFRA);
+ bGPDframe *frame_color = BKE_gpencil_frame_addnew(colors, scene->r.cfra);
+ bGPDframe *frame_lines = BKE_gpencil_frame_addnew(lines, scene->r.cfra);
UNUSED_VARS(frame_color);
/* generate stroke */
diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.cc b/source/blender/editors/gpencil/gpencil_bake_animation.cc
index dfc74f6d225..e480852a9bb 100644
--- a/source/blender/editors/gpencil/gpencil_bake_animation.cc
+++ b/source/blender/editors/gpencil/gpencil_bake_animation.cc
@@ -265,7 +265,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
}
/* Move scene to new frame. */
- CFRA = i;
+ scene->r.cfra = i;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Loop all objects in the list. */
@@ -285,7 +285,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
/* Apply time modifier. */
int remap_cfra = BKE_gpencil_time_modifier_cfra(
- depsgraph, scene, elem->ob, gpl_src, CFRA, false);
+ depsgraph, scene, elem->ob, gpl_src, scene->r.cfra, false);
/* Duplicate frame. */
bGPDframe *gpf_src = BKE_gpencil_layer_frame_get(
gpl_src, remap_cfra, GP_GETFRAME_USE_PREV);
@@ -293,7 +293,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
continue;
}
bGPDframe *gpf_dst = BKE_gpencil_frame_duplicate(gpf_src, true);
- gpf_dst->framenum = CFRA + frame_offset;
+ gpf_dst->framenum = scene->r.cfra + frame_offset;
gpf_dst->flag &= ~GP_FRAME_SELECT;
BLI_addtail(&gpl_dst->frames, gpf_dst);
@@ -320,6 +320,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
/* Update point location to new object space. */
for (int j = 0; j < gps->totpoints; j++) {
bGPDspoint *pt = &gps->points[j];
+ mul_m4_v3(ob_eval->obmat, &pt->x);
mul_m4_v3(invmat, &pt->x);
}
@@ -336,7 +337,7 @@ static int gpencil_bake_grease_pencil_animation_exec(bContext *C, wmOperator *op
}
}
/* Return scene frame state and DB to original state. */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Free memory. */
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 4f9468cc9c4..e02a82f4555 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -588,7 +588,7 @@ static void gpencil_stroke_path_animation(bContext *C,
}
/* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1104,7 +1104,7 @@ static void gpencil_stroke_to_bezier(bContext *C,
rad_fac,
minmax_weights);
- /* shift coord vects */
+ /* Shift coord vectors. */
copy_v3_v3(p3d_prev, p3d_cur);
copy_v3_v3(p3d_cur, p3d_next);
@@ -1271,7 +1271,7 @@ static void gpencil_layer_to_curve(bContext *C,
Collection *collection = CTX_data_collection(C);
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
bGPDstroke *prev_gps = NULL;
Object *ob;
Curve *cu;
@@ -1414,7 +1414,7 @@ static bool gpencil_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl,
int i;
bool valid = true;
- if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) ||
+ if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV)) ||
!(gps = gpf->strokes.first)) {
return false;
}
@@ -1481,7 +1481,7 @@ static bool gpencil_convert_poll(bContext *C)
* and if we are not in edit mode!
*/
return ((area && area->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) &&
- (gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV)) &&
+ (gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV)) &&
(gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd)));
}
@@ -1811,7 +1811,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op)
/* Add layer and frame. */
bGPdata *gpd = (bGPdata *)ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, "Image Layer", true, false);
- bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, CFRA);
+ bGPDframe *gpf = BKE_gpencil_frame_addnew(gpl, scene->r.cfra);
done = BKE_gpencil_from_image(sima, gpd, gpf, size, is_mask);
if (done) {
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 6843c42d2d0..b7ac73b9692 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -226,7 +226,7 @@ static int gpencil_layer_add_exec(bContext *C, wmOperator *op)
bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true, false);
/* Add a new frame to make it visible in Dopesheet. */
if (gpl != NULL) {
- gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW);
}
}
}
@@ -646,12 +646,12 @@ static int gpencil_frame_duplicate_exec(bContext *C, wmOperator *op)
}
if (mode == 0) {
- BKE_gpencil_frame_addcopy(gpl_active, CFRA);
+ BKE_gpencil_frame_addcopy(gpl_active, scene->r.cfra);
}
else {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
- BKE_gpencil_frame_addcopy(gpl, CFRA);
+ BKE_gpencil_frame_addcopy(gpl, scene->r.cfra);
}
}
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 3c8e6d6e5f5..71cf9b1fafd 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1718,7 +1718,7 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op)
* we are obliged to add a new frame if one
* doesn't exist already
*/
- gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW);
if (gpf) {
/* Create new stroke */
bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true);
@@ -1811,7 +1811,16 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op)
}
else {
/* Create a new layer. */
- target_layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true, false);
+ PropertyRNA *prop;
+ char name[128];
+ prop = RNA_struct_find_property(op->ptr, "new_layer_name");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_string_get(op->ptr, prop, name);
+ }
+ else {
+ strcpy(name, "GP_Layer");
+ }
+ target_layer = BKE_gpencil_layer_addnew(gpd, name, true, false);
}
if (target_layer == NULL) {
@@ -1888,8 +1897,46 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static void layer_new_name_get(bGPdata *gpd, char *rname)
+{
+ int index = 0;
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ if (strstr(gpl->info, "GP_Layer")) {
+ index++;
+ }
+ }
+
+ if (index == 0) {
+ BLI_strncpy(rname, "GP_Layer", 128);
+ return;
+ }
+ char *name = BLI_sprintfN("%.*s.%03d", 128, "GP_Layer", index);
+ BLI_strncpy(rname, name, 128);
+ MEM_freeN(name);
+}
+
+static int gpencil_move_to_layer_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ PropertyRNA *prop;
+ if (RNA_int_get(op->ptr, "layer") == -1) {
+ prop = RNA_struct_find_property(op->ptr, "new_layer_name");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ char name[MAX_NAME];
+ bGPdata *gpd = ob->data;
+ layer_new_name_get(gpd, name);
+ RNA_property_string_set(op->ptr, prop, name);
+ return WM_operator_props_dialog_popup(C, op, 200);
+ }
+ }
+
+ return gpencil_move_to_layer_exec(C, op);
+}
+
void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Move Strokes to Layer";
ot->idname = "GPENCIL_OT_move_to_layer";
@@ -1898,15 +1945,20 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
/* callbacks */
ot->exec = gpencil_move_to_layer_exec;
- ot->poll = gpencil_stroke_edit_poll; /* XXX? */
+ ot->invoke = gpencil_move_to_layer_invoke;
+ ot->poll = gpencil_stroke_edit_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* GPencil layer to use. */
- ot->prop = RNA_def_int(
- ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX);
- RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_int(ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_string(
+ ot->srna, "new_layer_name", NULL, MAX_NAME, "Name", "Name of the newly added layer");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ ot->prop = prop;
}
/** \} */
@@ -1919,7 +1971,7 @@ static int gpencil_blank_frame_add_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Scene *scene = CTX_data_scene(C);
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
bGPDlayer *active_gpl = BKE_gpencil_layer_active_get(gpd);
@@ -2023,7 +2075,7 @@ static int gpencil_actframe_delete_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
/* if there's no existing Grease-Pencil data there, add some */
if (gpd == NULL) {
@@ -2098,7 +2150,7 @@ static int gpencil_actframe_delete_all_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
/* try to get the "active" frame - but only if it actually occurs on this frame */
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
if (gpf == NULL) {
continue;
@@ -3657,35 +3709,44 @@ static int gpencil_stroke_flip_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+
bool changed = false;
- /* read all selected strokes */
+ /* Read all selected strokes. */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
- LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL) {
continue;
}
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
+ continue;
+ }
- if (is_curve_edit) {
- BKE_report(op->reports, RPT_ERROR, "Not implemented!");
- }
- else {
- /* Flip stroke. */
- BKE_gpencil_stroke_flip(gps);
+ if (is_curve_edit) {
+ BKE_report(op->reports, RPT_ERROR, "Not implemented!");
+ }
+ else {
+ /* Flip stroke. */
+ BKE_gpencil_stroke_flip(gps);
+ changed = true;
+ }
+ }
}
-
- changed = true;
+ }
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
}
}
}
@@ -3766,7 +3827,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
/* update frame to get the new location of objects */
if ((mode == GP_REPROJECT_SURFACE) && (cfra_prv != gpf->framenum)) {
cfra_prv = gpf->framenum;
- CFRA = gpf->framenum;
+ scene->r.cfra = gpf->framenum;
BKE_scene_graph_update_for_newframe(depsgraph);
}
@@ -3794,7 +3855,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* return frame state and DB to original state */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
if (sctx != NULL) {
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 3f06dbfdbb3..5305c764b3a 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1748,7 +1748,7 @@ static tGPDfill *gpencil_session_init_fill(bContext *C, wmOperator *op)
tgpf->v3d = tgpf->area->spacedata.first;
tgpf->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpf->win = CTX_wm_window(C);
- tgpf->active_cfra = CFRA;
+ tgpf->active_cfra = scene->r.cfra;
tgpf->reports = op->reports;
/* Setup space conversions. */
@@ -2222,8 +2222,8 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Hash of selected frames. */
GHash *frame_list = BLI_ghash_int_new_ex(__func__, 64);
- /* If not multi-frame and there is no frame in CFRA for the active layer, create
- * a new frame. */
+ /* If not multi-frame and there is no frame in scene->r.cfra for the active layer,
+ * create a new frame. */
if (!is_multiedit) {
tgpf->gpf = BKE_gpencil_layer_frame_get(
tgpf->gpl,
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 56c94e4494d..d656241c463 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -726,16 +726,16 @@ struct GP_EditableStrokes_Iter {
(void)0
/**
- * Iterate over all editable editcurves in the current context,
- * stopping on each usable layer + stroke + curve pair (i.e. gpl, gps and gpc)
+ * Iterate over all editable edit-curves in the current context,
+ * stopping on each usable layer + stroke + curve pair (i.e. `gpl`, `gps` and `gpc`)
* to perform some operations on the curve.
*
* \param gpl: The identifier to use for the layer of the stroke being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
* \param gps: The identifier to use for current stroke being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
* \param gpc: The identifier to use for current editcurve being processed.
- * Choose a suitable value to avoid name clashes.
+ * Choose a suitable value to avoid name clashes.
*/
#define GP_EDITABLE_CURVES_BEGIN(gpstroke_iter, C, gpl, gps, gpc) \
{ \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 8630b7f23d4..e7a4f2fe2dc 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -483,10 +483,10 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
tgpil->gpl = gpl;
- bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, CFRA);
+ bGPDframe *gpf = gpencil_get_previous_keyframe(gpl, scene->r.cfra);
tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpf, true);
- gpf = gpencil_get_next_keyframe(gpl, CFRA);
+ gpf = gpencil_get_next_keyframe(gpl, scene->r.cfra);
tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpf, true);
BLI_addtail(&tgpi->ilayers, tgpil);
@@ -750,7 +750,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
tGPDinterpolate *tgpi = NULL;
/* Cannot interpolate if not between 2 frames. */
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, cfra);
bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, cfra);
if (ELEM(NULL, gpf_prv, gpf_next)) {
@@ -1221,7 +1221,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
GP_SpaceConversion gsc;
gpencil_point_conversion_init(C, &gsc);
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
const int step = RNA_int_get(op->ptr, "step");
@@ -1482,8 +1482,8 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
* Changes here will likely apply there too.
*/
static const EnumPropertyItem gpencil_interpolation_type_items[] = {
- /* interpolation */
- {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
+ /* Interpolation. */
+ RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"),
{GP_IPO_LINEAR,
"LINEAR",
ICON_IPO_LINEAR,
@@ -1495,13 +1495,10 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
"Custom",
"Custom interpolation defined using a curve map"},
- /* easing */
- {0,
- "",
- 0,
- N_("Easing (by strength)"),
- "Predefined inertial transitions, useful for motion graphics (from least to most "
- "''dramatic'')"},
+ /* Easing. */
+ RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"),
+ "Predefined inertial transitions, useful for motion graphics "
+ "(from least to most \"dramatic\")"),
{GP_IPO_SINE,
"SINE",
ICON_IPO_SINE,
@@ -1518,7 +1515,7 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
"Circular",
"Circular easing (strongest and most dynamic)"},
- {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
+ RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"),
{GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
{GP_IPO_BOUNCE,
"BOUNCE",
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index 06343dcad43..8ff3f20cef3 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -113,7 +113,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
else {
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, add_frame_mode);
/* stroke */
bGPDstroke *gps = BKE_gpencil_stroke_new(MAX2(ob->actcol - 1, 0), totpoints, brush->size);
diff --git a/source/blender/editors/gpencil/gpencil_mesh.cc b/source/blender/editors/gpencil/gpencil_mesh.cc
index aee00d4ede3..b27e1c75746 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.cc
+++ b/source/blender/editors/gpencil/gpencil_mesh.cc
@@ -283,7 +283,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
}
/* Move scene to new frame. */
- CFRA = i;
+ scene->r.cfra = i;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Loop all objects in the list. */
@@ -325,7 +325,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op)
}
/* Return scene frame state and DB to original state. */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Remove unused materials. */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 7c7f532f087..70486138556 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -2166,7 +2166,7 @@ static void gpencil_paint_initstroke(tGPsdata *p,
if (gpl->actframe && gpl->actframe->strokes.first) {
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
short frame_mode = IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_COPY : GP_GETFRAME_USE_PREV;
- gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, frame_mode);
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, frame_mode);
}
has_layer_to_erase = true;
break;
@@ -2204,7 +2204,7 @@ static void gpencil_paint_initstroke(tGPsdata *p,
bool need_tag = p->gpl->actframe == NULL;
bGPDframe *actframe = p->gpl->actframe;
- p->gpf = BKE_gpencil_layer_frame_get(p->gpl, CFRA, add_frame_mode);
+ p->gpf = BKE_gpencil_layer_frame_get(p->gpl, scene->r.cfra, add_frame_mode);
/* Only if there wasn't an active frame, need update. */
if (need_tag) {
DEG_id_tag_update(&p->gpd->id, ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index b57b8145749..befff611d58 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -292,7 +292,7 @@ static void gpencil_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
Brush *brush = tgpi->brush;
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
@@ -1195,7 +1195,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->orign_type = RNA_enum_get(op->ptr, "type");
/* set current frame number */
- tgpi->cframe = CFRA;
+ tgpi->cframe = scene->r.cfra;
/* set GP datablock */
tgpi->gpd = gpd;
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 01ac02a9a1d..e27cd255217 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -829,7 +829,7 @@ static bool gpencil_brush_randomize_apply(tGP_BrushEditData *gso,
mul_v2_fl(svec, fac);
}
- /* convert to dataspace */
+ /* Convert to data-space. */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D: Project to 3D space */
bool flip;
@@ -1013,7 +1013,7 @@ static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
gpl = CTX_data_active_gpencil_layer(C);
}
bGPDframe *gpf = BKE_gpencil_layer_frame_get(
- gpl, CFRA, IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV);
+ gpl, scene->r.cfra, IS_AUTOKEY_ON(scene) ? GP_GETFRAME_ADD_NEW : GP_GETFRAME_USE_PREV);
if (gpf == NULL) {
continue;
}
@@ -1161,6 +1161,7 @@ static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op)
gso->is_painting = false;
gso->first = true;
+ gso->mval_prev[0] = -1.0f;
gso->gpd = ED_gpencil_data_get_active(C);
gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
@@ -1335,7 +1336,7 @@ static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso
bGPdata *gpd = gso->gpd;
Scene *scene = gso->scene;
- int cfra = CFRA;
+ int cfra = scene->r.cfra;
/* only try to add a new frame if this is the first stroke, or the frame has changed */
if ((gpd == NULL) || (cfra == gso->cfra)) {
@@ -1442,6 +1443,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
char tool = gso->brush->gpencil_sculpt_tool;
const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
gso->brush->size;
+ const bool is_masking = GPENCIL_ANY_SCULPT_MASK(gso->mask);
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt_active = NULL;
@@ -1459,7 +1461,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
pt = &gps->points[0];
- if (GPENCIL_ANY_SCULPT_MASK(gso->mask) && (pt->flag & GP_SPOINT_SELECT) != 0) {
+ if ((is_masking && (pt->flag & GP_SPOINT_SELECT) != 0) || (!is_masking)) {
gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp);
gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
@@ -1516,7 +1518,8 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* To each point individually... */
pt = &gps->points[i];
- if ((pt->runtime.pt_orig == NULL) && (tool != GPSCULPT_TOOL_GRAB)) {
+ if ((i != gps->totpoints - 2) && (pt->runtime.pt_orig == NULL) &&
+ (tool != GPSCULPT_TOOL_GRAB)) {
continue;
}
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
@@ -1618,7 +1621,8 @@ static bool gpencil_sculpt_brush_do_frame(bContext *C,
}
/* Check if the stroke collide with brush. */
- if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
+ if ((gps->totpoints > 1) &&
+ (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat))) {
continue;
}
@@ -1982,7 +1986,7 @@ static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *
}
/* Store coordinates as reference, if operator just started running */
- if (gso->first) {
+ if (gso->mval_prev[0] == -1.0f) {
gso->mval_prev[0] = gso->mval[0];
gso->mval_prev[1] = gso->mval[1];
gso->pressure_prev = gso->pressure;
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index a37dc99229c..a19265720e8 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -759,7 +759,7 @@ static bool gpencil_select_same_layer(bContext *C)
bool changed = false;
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
bGPDstroke *gps;
bool found = false;
@@ -1701,7 +1701,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
const bool select = (sel_op != SEL_OP_SUB);
bool changed = false;
- /* for bounding rect around circle (for quicky intersection testing) */
+ /* For bounding `rect` around circle (for quickly intersection testing). */
rcti rect = {0};
rect.xmin = mx - radius;
rect.ymin = my - radius;
diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c
index 24a0dab24c9..f6e88e05d46 100644
--- a/source/blender/editors/gpencil/gpencil_trace_ops.c
+++ b/source/blender/editors/gpencil/gpencil_trace_ops.c
@@ -295,7 +295,7 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op)
job->base_active = CTX_data_active_base(C);
job->ob_active = job->base_active->object;
job->image = (Image *)job->ob_active->data;
- job->frame_target = CFRA;
+ job->frame_target = scene->r.cfra;
job->use_current_frame = RNA_boolean_get(op->ptr, "use_current_frame");
/* Create a new grease pencil object or reuse selected. */
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 23c385c1213..7b659511aaa 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -388,6 +388,17 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
/* Create new layer */
/* TODO: have some way of specifying that we don't want this? */
+ {
+ /* "New Layer" entry */
+ item_tmp.identifier = "__CREATE__";
+ item_tmp.name = "New Layer";
+ item_tmp.value = -1;
+ item_tmp.icon = ICON_ADD;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
const int tot = BLI_listbase_count(&gpd->layers);
/* Existing layers */
@@ -405,17 +416,6 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &item_tmp);
}
- {
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
-
- /* "New Layer" entry */
- item_tmp.identifier = "__CREATE__";
- item_tmp.name = "New Layer";
- item_tmp.value = -1;
- item_tmp.icon = ICON_ADD;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -525,7 +525,7 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps
return (area->spacetype == SPACE_IMAGE);
}
if (gps->flag & GP_STROKE_2DSPACE) {
- /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
+ /* 2D strokes (data-space) - for any 2D view (i.e. everything other than 3D view). */
return (area->spacetype != SPACE_VIEW3D);
}
/* view aligned - anything goes */
@@ -1149,7 +1149,7 @@ void ED_gpencil_stroke_reproject(Depsgraph *depsgraph,
depsgraph,
v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
&ray_start[0],
&ray_normal[0],
@@ -1747,7 +1747,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
float darkcolor[3];
float radius = 3.0f;
- int mval_i[2] = {x, y};
+ const int mval_i[2] = {x, y};
/* Check if cursor is in drawing region and has valid data-block. */
if ((!gpencil_check_cursor_region(C, mval_i)) || (gpd == NULL)) {
return;
@@ -2962,7 +2962,7 @@ void ED_gpencil_projected_2d_bound_box(const GP_SpaceConversion *gsc,
bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bGPDstroke *gps,
- const float mouse[2],
+ const float mval[2],
const int radius,
const float diff_mat[4][4])
{
@@ -2980,7 +2980,7 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
rcti rect_stroke = {boundbox_min[0], boundbox_max[0], boundbox_min[1], boundbox_max[1]};
/* For mouse, add a small offset to avoid false negative in corners. */
- rcti rect_mouse = {mouse[0] - offset, mouse[0] + offset, mouse[1] - offset, mouse[1] + offset};
+ rcti rect_mouse = {mval[0] - offset, mval[0] + offset, mval[1] - offset, mval[1] + offset};
/* Check collision between both rectangles. */
return BLI_rcti_isect(&rect_stroke, &rect_mouse, NULL);
@@ -2988,7 +2988,7 @@ bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc,
bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
const GP_SpaceConversion *gsc,
- const int mouse[2],
+ const int mval[2],
const float diff_mat[4][4])
{
bool hit = false;
@@ -3014,9 +3014,8 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
BLI_lasso_boundbox(&rect, mcoords, len);
/* Test if point inside stroke. */
- hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) &&
- BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) &&
- BLI_lasso_is_point_inside(mcoords, len, mouse[0], mouse[1], INT_MAX));
+ hit = ((!ELEM(V2D_IS_CLIPPED, mval[0], mval[1])) && BLI_rcti_isect_pt(&rect, mval[0], mval[1]) &&
+ BLI_lasso_is_point_inside(mcoords, len, mval[0], mval[1], INT_MAX));
/* Free memory. */
MEM_SAFE_FREE(mcoords);
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index c0888968a2d..865c4e360b5 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -587,7 +587,7 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op)
srgb_to_linearrgb_v4(color, color);
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) {
- copy_v3_v3(pt->vert_color, color);
+ copy_v4_v4(pt->vert_color, color);
}
}
}
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 3f1b8d6ecda..84512653a24 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -55,17 +55,17 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
* 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,
+ float x,
+ float y,
+ int img_w,
+ int img_h,
+ eGPUTextureFormat gpu_format,
+ bool use_filter,
const void *rect,
- const float scaleX,
- const float scaleY,
- const float xzoom,
- const float yzoom,
+ float scaleX,
+ float scaleY,
+ float xzoom,
+ float yzoom,
const float color[4]);
/**
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index da40eef87fd..cc3c68abc55 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -324,11 +324,15 @@ typedef enum eAnimFilter_Flags {
/** duplicate entries for animation data attached to multi-user blocks must not occur */
ANIMFILTER_NODUPLIS = (1 << 11),
+ /** avoid channel that does not have any F-curve data */
+ ANIMFILTER_FCURVESONLY = (1 << 12),
+
/** for checking if we should keep some collapsed channel around (internal use only!) */
ANIMFILTER_TMP_PEEK = (1 << 30),
/** Ignore ONLYSEL flag from #bDopeSheet.filterflag (internal use only!) */
ANIMFILTER_TMP_IGNORE_ONLYSEL = (1u << 31),
+
} eAnimFilter_Flags;
/** \} */
@@ -1042,6 +1046,8 @@ void ED_keymap_anim(struct wmKeyConfig *keyconf);
void ED_operatormacros_graph(void);
/* space_action */
void ED_operatormacros_action(void);
+/* space_nla*/
+void ED_operatormacros_nla(void);
/** \} */
diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h
index 2c67b02611b..0f981e270a0 100644
--- a/source/blender/editors/include/ED_clip.h
+++ b/source/blender/editors/include/ED_clip.h
@@ -22,15 +22,53 @@ struct bScreen;
/* ** clip_editor.c ** */
-/* common poll functions */
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - There is a movie clip opened in it. */
bool ED_space_clip_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Clip view.
+ *
+ * It is not required to have movie clip opened for editing. */
bool ED_space_clip_view_clip_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Tracking mode.
+ *
+ * It is not required to have movie clip opened for editing. */
bool ED_space_clip_tracking_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ *
+ * It is not required to have mask opened for editing. */
bool ED_space_clip_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_space_clip_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - The space has mask opened. */
bool ED_space_clip_maskedit_mask_poll(struct bContext *C);
+/* Returns true when the following conditions are met:
+ * - Current space is Space Clip.
+ * - It is set to Mask mode.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_space_clip_maskedit_mask_visible_splines_poll(struct bContext *C);
+
void ED_space_clip_get_size(struct SpaceClip *sc, int *width, int *height);
void ED_space_clip_get_size_fl(struct SpaceClip *sc, float size[2]);
void ED_space_clip_get_zoom(struct SpaceClip *sc,
@@ -60,7 +98,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
*/
bool ED_space_clip_color_sample(struct SpaceClip *sc,
struct ARegion *region,
- int mval[2],
+ const int mval[2],
float r_col[3]);
void ED_clip_update_frame(const struct Main *mainp, int cfra);
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 9f4833bf1d7..061b783797d 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -49,10 +49,12 @@ void ED_curve_editnurb_free(struct Object *obedit);
/**
* \param dist_px: Maximum distance to pick (in pixels).
+ * \param vert_without_handles: When true, selecting the knot doesn't select the handles.
*/
bool ED_curve_editnurb_select_pick(struct bContext *C,
const int mval[2],
int dist_px,
+ bool vert_without_handles,
const struct SelectPick_Params *params);
struct Nurb *ED_curve_add_nurbs_primitive(
diff --git a/source/blender/editors/include/ED_curves.h b/source/blender/editors/include/ED_curves.h
index 9233b65b2ce..0817241a5c2 100644
--- a/source/blender/editors/include/ED_curves.h
+++ b/source/blender/editors/include/ED_curves.h
@@ -6,6 +6,8 @@
#pragma once
+struct bContext;
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -19,10 +21,15 @@ void ED_operatortypes_curves(void);
#ifdef __cplusplus
# include "BKE_curves.hh"
+# include "BLI_vector_set.hh"
namespace blender::ed::curves {
bke::CurvesGeometry primitive_random_sphere(int curves_size, int points_per_curve);
+bool selection_operator_poll(bContext *C);
+bool has_anything_selected(const Curves &curves_id);
+VectorSet<Curves *> get_unique_editable_curves(const bContext &C);
+void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob);
-}
+} // namespace blender::ed::curves
#endif
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index c3a66e4a7dd..e3b091430e8 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -103,6 +103,9 @@ extern const char datatoc_multiply_png[];
extern int datatoc_nudge_png_size;
extern const char datatoc_nudge_png[];
+extern int datatoc_paint_select_png_size;
+extern const char datatoc_paint_select_png[];
+
extern int datatoc_pinch_png_size;
extern const char datatoc_pinch_png[];
@@ -284,6 +287,41 @@ extern const char datatoc_gp_brush_erase_hard_png[];
extern int datatoc_gp_brush_erase_stroke_png_size;
extern const char datatoc_gp_brush_erase_stroke_png[];
+/* curves sculpt brushes files */
+
+extern int datatoc_curves_sculpt_add_png_size;
+extern const char datatoc_curves_sculpt_add_png[];
+
+extern int datatoc_curves_sculpt_comb_png_size;
+extern const char datatoc_curves_sculpt_comb_png[];
+
+extern int datatoc_curves_sculpt_cut_png_size;
+extern const char datatoc_curves_sculpt_cut_png[];
+
+extern int datatoc_curves_sculpt_delete_png_size;
+extern const char datatoc_curves_sculpt_delete_png[];
+
+extern int datatoc_curves_sculpt_density_png_size;
+extern const char datatoc_curves_sculpt_density_png[];
+
+extern int datatoc_curves_sculpt_grow_shrink_png_size;
+extern const char datatoc_curves_sculpt_grow_shrink_png[];
+
+extern int datatoc_curves_sculpt_pinch_png_size;
+extern const char datatoc_curves_sculpt_pinch_png[];
+
+extern int datatoc_curves_sculpt_puff_png_size;
+extern const char datatoc_curves_sculpt_puff_png[];
+
+extern int datatoc_curves_sculpt_slide_png_size;
+extern const char datatoc_curves_sculpt_slide_png[];
+
+extern int datatoc_curves_sculpt_smooth_png_size;
+extern const char datatoc_curves_sculpt_smooth_png[];
+
+extern int datatoc_curves_sculpt_snake_hook_png_size;
+extern const char datatoc_curves_sculpt_snake_hook_png[];
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_geometry.h b/source/blender/editors/include/ED_geometry.h
index 74ff968828c..4620181894a 100644
--- a/source/blender/editors/include/ED_geometry.h
+++ b/source/blender/editors/include/ED_geometry.h
@@ -7,12 +7,22 @@
#pragma once
+#include "BKE_attribute.h"
+#include "DNA_customdata_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-void ED_operatortypes_geometry(void);
+struct Mesh;
+void ED_operatortypes_geometry(void);
+bool ED_geometry_attribute_convert(struct Mesh *mesh,
+ const char *layer_name,
+ eCustomDataType old_type,
+ eAttrDomain old_domain,
+ eCustomDataType new_type,
+ eAttrDomain new_domain);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 067e5ba4d7f..31c1f93f5bc 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -14,6 +14,8 @@
extern "C" {
#endif
+#include "DNA_scene_types.h"
+
/* initialize gizmos */
void ED_gizmotypes_arrow_3d(void);
void ED_gizmotypes_button_2d(void);
@@ -223,24 +225,6 @@ enum {
/* -------------------------------------------------------------------- */
/* Specific gizmos utils */
-/* dial3d_gizmo.c */
-
-struct Dial3dParams {
- int draw_options;
- float angle_ofs;
- float angle_delta;
- float angle_increment;
- float arc_partial_angle;
- float arc_inner_factor;
- float *clip_plane;
-};
-void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
- const float matrix_final[4][4],
- float line_width,
- const float color[4],
- bool select,
- struct Dial3dParams *params);
-
/* snap3d_gizmo.c */
struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene,
@@ -258,7 +242,7 @@ void ED_gizmotypes_snap_3d_data_get(const struct bContext *C,
float r_loc[3],
float r_nor[3],
int r_elem_index[3],
- int *r_snap_elem);
+ eSnapMode *r_snap_elem);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 01f60a81288..b6488d6da56 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -239,7 +239,7 @@ void ED_annotation_draw_ex(
/* ----------- Grease-Pencil AnimEdit API ------------------ */
/**
- * Loops over the gp-frames for a gp-layer, and applies the given callback.
+ * 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,
@@ -281,6 +281,11 @@ void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode);
/**
+ * Set the layer's channel as active
+ */
+void ED_gpencil_set_active_channel(struct bGPdata *gpd, struct bGPDlayer *gpl);
+
+/**
* Delete selected frames.
*/
bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl);
@@ -579,7 +584,7 @@ void ED_gpencil_init_random_settings(struct Brush *brush,
*/
bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
- const float mouse[2],
+ const float mval[2],
int radius,
const float diff_mat[4][4]);
/**
@@ -587,13 +592,13 @@ bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc,
*
* \param gps: Stroke to check.
* \param gsc: Space conversion data.
- * \param mouse: Mouse position.
+ * \param mval: Region relative cursor 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 int mval[2],
const float diff_mat[4][4]);
/**
* Get the bigger 2D bound box points.
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index f79d3ce205d..91ae8286531 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -24,6 +24,7 @@ struct Scene;
struct SpaceImage;
struct View2D;
struct bContext;
+struct Paint;
struct wmOperator;
struct wmWindowManager;
@@ -63,8 +64,11 @@ bool ED_space_image_get_position(struct SpaceImage *sima,
/**
* 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);
+bool ED_space_image_color_sample(struct SpaceImage *sima,
+ struct ARegion *region,
+ const 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.
@@ -133,8 +137,39 @@ 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);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not a UV Editor.
+ * - It is set to Mask mode.
+ *
+ * It is not required to have mask opened for editing. */
bool ED_space_image_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not a UV Editor.
+ * - It is set to Mask mode.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_space_image_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not an UV Editor.
+ * - It is set to Mask mode.
+ * - The space has mask opened. */
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space is Image Editor.
+ * - The image editor is not an UV Editor.
+ * - It is set to Mask mode.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_space_image_maskedit_mask_visible_splines_poll(struct bContext *C);
+
bool ED_space_image_cursor_poll(struct bContext *C);
/**
@@ -173,6 +208,7 @@ typedef struct ImageFrameRange {
int length;
int offset;
/* UDIM tiles. */
+ bool udims_detected;
ListBase udim_tiles;
/* Temporary data. */
@@ -186,6 +222,9 @@ ListBase ED_image_filesel_detect_sequences(struct Main *bmain,
struct wmOperator *op,
bool detect_udim);
+bool ED_image_tools_paint_poll(struct bContext *C);
+void ED_paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 163797d395d..1d63e01c84b 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -229,6 +229,16 @@ typedef enum eKeyMergeMode {
KEYFRAME_PASTE_MERGE_OVER_RANGE_ALL,
} eKeyMergeMode;
+/* Possible errors occurring while pasting keys. */
+typedef enum eKeyPasteError {
+ /* No errors occurred */
+ KEYFRAME_PASTE_OK,
+ /* Nothing was copied */
+ KEYFRAME_PASTE_NOTHING_TO_PASTE,
+ /* No F-curves was selected to paste into*/
+ KEYFRAME_PASTE_NOWHERE_TO_PASTE
+} eKeyPasteError;
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -378,9 +388,6 @@ bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, con
/* ************************************************ */
/* Destructive Editing API (keyframes_general.c) */
-void delete_fcurve_key(struct FCurve *fcu, int index, bool do_recalc);
-bool delete_fcurve_keys(struct FCurve *fcu);
-void clear_fcurve_keys(struct FCurve *fcu);
bool duplicate_fcurve_keys(struct FCurve *fcu);
float get_default_rna_value(struct FCurve *fcu, struct PropertyRNA *prop, struct PointerRNA *ptr);
@@ -416,11 +423,11 @@ void sample_fcurve(struct FCurve *fcu);
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,
- eKeyPasteOffset offset_mode,
- eKeyMergeMode merge_mode,
- bool flip);
+eKeyPasteError paste_animedit_keys(struct bAnimContext *ac,
+ ListBase *anim_data,
+ eKeyPasteOffset offset_mode,
+ eKeyMergeMode merge_mode,
+ bool flip);
/* ************************************************ */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 8c0147612fb..a53042b70d6 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -658,15 +658,20 @@ bool ED_autokeyframe_pchan(struct bContext *C,
struct Object *ob,
struct bPoseChannel *pchan,
struct KeyingSet *ks);
+
/**
- * Use for auto-key-framing from the UI.
+ * Use for auto-key-framing
+ * \param only_if_property_keyed: if true, auto-key-framing only creates keyframes on already keyed
+ * properties. This is by design when using buttons. For other callers such as gizmos or VSE
+ * preview transform, creating new animation/keyframes also on non-keyed properties is desired.
*/
bool ED_autokeyframe_property(struct bContext *C,
struct Scene *scene,
PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
- float cfra);
+ float cfra,
+ bool only_if_property_keyed);
/* Names for builtin keying sets so we don't confuse these with labels/text,
* defined in python script: `keyingsets_builtins.py`. */
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 7039d6d9fc7..8cadbfde185 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -22,6 +22,34 @@ struct wmKeyConfig;
/* mask_edit.c */
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_maskedit_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - Mask has visible and editable splines.
+ *
+ * It is not required to have mask opened for editing. */
+bool ED_maskedit_visible_splines_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - The space has mask open for editing. */
+bool ED_maskedit_mask_poll(struct bContext *C);
+
+/* Returns true when the following conditions are met:
+ * - Current space supports mask editing.
+ * - The space is configured to interact with mask.
+ * - The space has mask opened.
+ * - Mask has visible and editable splines. */
+bool ED_maskedit_mask_visible_splines_poll(struct bContext *C);
+
void ED_mask_deselect_all(const struct bContext *C);
void ED_operatortypes_mask(void);
@@ -73,6 +101,7 @@ void ED_mask_draw_region(struct Depsgraph *depsgraph,
char draw_flag,
char draw_type,
eMaskOverlayMode overlay_mode,
+ float blend_factor,
int width_i,
int height_i,
float aspx,
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 30a98129ee6..b73b62d5a9d 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -137,7 +137,6 @@ void EDBM_update_extern(struct Mesh *me, bool do_tessellation, bool is_destructi
*/
struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm,
const struct Scene *scene,
- bool face_selected,
bool uv_selected,
bool use_winding,
bool do_islands);
@@ -425,6 +424,9 @@ void paintvert_select_ungrouped(struct Object *ob, bool extend, bool flush_flags
void paintvert_flush_flags(struct Object *ob);
void paintvert_tag_select_update(struct bContext *C, struct Object *ob);
+void paintvert_hide(struct bContext *C, struct Object *ob, bool unselected);
+void paintvert_reveal(struct bContext *C, struct Object *ob, bool select);
+
/* mirrtopo */
typedef struct MirrTopoStore_t {
intptr_t *index_lookup;
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 0078c1087a0..39c7ad3556c 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -536,12 +536,12 @@ bool ED_object_modifier_move_to_index(struct ReportList *reports,
struct ModifierData *md,
int index);
-bool ED_object_modifier_convert(struct ReportList *reports,
- struct Main *bmain,
- struct Depsgraph *depsgraph,
- struct ViewLayer *view_layer,
- struct Object *ob,
- struct ModifierData *md);
+bool ED_object_modifier_convert_psys_to_mesh(struct ReportList *reports,
+ struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ struct ViewLayer *view_layer,
+ struct Object *ob,
+ struct ModifierData *md);
bool ED_object_modifier_apply(struct Main *bmain,
struct ReportList *reports,
struct Depsgraph *depsgraph,
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index f909a13c2cb..a24c8625a63 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -595,8 +595,7 @@ bool ED_operator_object_active_local_editable_posemode_exclusive(struct bContext
bool ED_operator_posemode_context(struct bContext *C);
bool ED_operator_posemode(struct bContext *C);
bool ED_operator_posemode_local(struct bContext *C);
-bool ED_operator_mask(struct bContext *C);
-bool ED_operator_camera(struct bContext *C);
+bool ED_operator_camera_poll(struct bContext *C);
/* screen_user_menu.c */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 54d67c50d5c..550040d2bc6 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -51,7 +51,7 @@ 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]);
+ const float mval_fl[2]);
/* Undo for changes happening on a base mesh for multires sculpting.
* if there is no multi-res sculpt active regular undo is used. */
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index fa02ebe18f6..8c856794ec8 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -40,11 +40,11 @@ typedef enum {
} eSelectOp;
/* Select Similar */
-enum {
+typedef enum {
SIM_CMP_EQ = 0,
SIM_CMP_GT,
SIM_CMP_LT,
-};
+} eSimilarCmp;
#define SEL_OP_USE_OUTSIDE(sel_op) (ELEM(sel_op, SEL_OP_AND))
#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET))
@@ -63,11 +63,11 @@ int ED_select_op_action(eSelectOp sel_op, bool is_select, bool is_inside);
*/
int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside);
-int ED_select_similar_compare_float(float delta, float thresh, int compare);
+bool ED_select_similar_compare_float(float delta, float thresh, eSimilarCmp compare);
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
float length,
float thresh,
- int compare);
+ eSimilarCmp compare);
/**
* Utility to use for selection operations that run multiple times (circle select).
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 2919001c5ce..db44d9af706 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -6,6 +6,8 @@
#pragma once
+#include "DNA_scene_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -25,14 +27,6 @@ struct View3D;
/* ED_transform_snap_object_*** API */
-typedef enum eSnapSelect {
- SNAP_ALL = 0,
- SNAP_NOT_SELECTED = 1,
- SNAP_NOT_ACTIVE = 2,
- SNAP_NOT_EDITED = 3,
- SNAP_SELECTABLE = 4,
-} eSnapSelect;
-
typedef enum eSnapEditType {
SNAP_GEOM_FINAL = 0,
SNAP_GEOM_CAGE = 1,
@@ -59,13 +53,17 @@ struct SnapObjectHitDepth {
/** parameters that define which objects will be used to snap. */
struct SnapObjectParams {
/* Special context sensitive handling for the active or selected object. */
- eSnapSelect snap_select;
+ eSnapTargetSelect snap_target_select;
/* Geometry for snapping in edit mode. */
eSnapEditType edit_mode_type;
/* snap to the closest element, use when using more than one snap type */
bool use_occlusion_test : true;
/* exclude back facing geometry from snapping */
bool use_backface_culling : true;
+ /* Break nearest face snapping into steps to improve transformations across U-shaped targets. */
+ short face_nearest_steps;
+ /* Enable to force nearest face snapping to snap to target the source was initially near. */
+ bool keep_on_same_target;
};
typedef struct SnapObjectContext SnapObjectContext;
@@ -120,46 +118,71 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
bool sort,
struct ListBase *r_hit_list);
-short ED_transform_snap_object_project_view3d_ex(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,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- struct Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3]);
+/**
+ * Perform snapping.
+ *
+ * Given a 2D region value, snap to vert/edge/face/grid.
+ *
+ * \param sctx: Snap context.
+ * \param snap_to: Target elements to snap source to.
+ * \param params: Addition snapping options.
+ * \param init_co: Initial world-space coordinate of source (optional).
+ * \param mval: Current transformed screen-space coordinate or mouse position (optional).
+ * \param prev_co: Current transformed world-space coordinate of source (optional).
+ * \param dist_px: Maximum distance to snap (in pixels).
+ * \param r_loc: Snapped world-space coordinate.
+ * \param r_no: Snapped world-space normal (optional).
+ * \param r_index: Index of snapped-to target element (optional).
+ * \param r_ob: Snapped-to target object (optional).
+ * \param r_obmat: Matrix of snapped-to target object (optional).
+ * \param r_face_nor: World-space normal of snapped-to target face (optional).
+ * \return Snapped-to element, #eSnapMode.
+ */
+eSnapMode ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const struct SnapObjectParams *params,
+ const float init_co[3],
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ struct Object **r_ob,
+ 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 snap_to: Target elements to snap source to.
+ * \param params: Addition snapping options.
+ * \param init_co: Initial world-space coordinate of source (optional).
+ * \param mval: Current transformed screen-space coordinate or mouse position (optional).
+ * \param prev_co: Current transformed world-space coordinate of source (optional).
* \param dist_px: Maximum distance to snap (in pixels).
- * \param r_loc: hit location.
- * \param r_no: hit normal (optional).
- * \return Snap success.
+ * \param r_loc: Snapped world-space coordinate.
+ * \param r_no: Snapped world-space normal (optional).
+ * \return Snapped-to element, #eSnapMode.
*/
-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]);
+eSnapMode ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const struct SnapObjectParams *params,
+ const float init_co[3],
+ 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
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 8695e03a57f..0298983ed26 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -8,6 +8,7 @@
#pragma once
#include "BLI_utildefines.h"
+#include "DNA_scene_types.h"
#ifdef __cplusplus
extern "C" {
@@ -299,7 +300,7 @@ typedef enum {
} eV3DPlaceOrient;
typedef struct V3DSnapCursorData {
- short snap_elem;
+ eSnapMode snap_elem;
float loc[3];
float nor[3];
float obmat[4][4];
@@ -322,7 +323,7 @@ typedef struct V3DSnapCursorState {
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. */
+ eSnapMode snap_elem_force; /* If SCE_SNAP_MODE_NONE, use scene settings. */
short plane_axis;
bool use_plane_axis_auto;
bool draw_point;
@@ -347,7 +348,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d,
const float normal[3],
const uchar color_line[4],
const uchar color_point[4],
- short snap_elem_type);
+ eSnapMode snap_elem_type);
/* view3d_iterators.c */
diff --git a/source/blender/editors/include/UI_abstract_view.hh b/source/blender/editors/include/UI_abstract_view.hh
new file mode 100644
index 00000000000..dfddace8899
--- /dev/null
+++ b/source/blender/editors/include/UI_abstract_view.hh
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editorui
+ *
+ * Base class for all views (UIs to display data sets) and view items, supporting common features.
+ * https://wiki.blender.org/wiki/Source/Interface/Views
+ *
+ * One of the most important responsibilities of the base class is managing reconstruction,
+ * enabling state that is persistent over reconstructions/redraws. Other features:
+ * - Renaming
+ * - Custom context menus
+ * - Notifier listening
+ * - Drag controllers (dragging view items)
+ * - Drop controllers (dropping onto/into view items)
+ */
+
+#pragma once
+
+#include <array>
+#include <memory>
+
+#include "DNA_defs.h"
+
+#include "BLI_span.hh"
+#include "BLI_string_ref.hh"
+
+struct bContext;
+struct uiBlock;
+struct uiBut;
+struct uiLayout;
+struct uiViewItemHandle;
+struct wmDrag;
+struct wmNotifier;
+
+namespace blender::ui {
+
+class AbstractViewItem;
+class AbstractViewItemDropController;
+class AbstractViewItemDragController;
+
+class AbstractView {
+ friend class AbstractViewItem;
+
+ bool is_reconstructed_ = false;
+ /**
+ * Only one item can be renamed at a time. So rather than giving each item an own rename buffer
+ * (which just adds unused memory in most cases), have one here that is managed by the view.
+ *
+ * This fixed-size buffer is needed because that's what the rename button requires. In future we
+ * may be able to bind the button to a `std::string` or similar.
+ */
+ std::unique_ptr<std::array<char, MAX_NAME>> rename_buffer_;
+
+ public:
+ virtual ~AbstractView() = default;
+
+ /** Listen to a notifier, returning true if a redraw is needed. */
+ virtual bool listen(const wmNotifier &) const;
+
+ /**
+ * Makes \a item valid for display in this view. Behavior is undefined for items not registered
+ * with this.
+ */
+ void register_item(AbstractViewItem &item);
+
+ /** Only one item can be renamed at a time. */
+ bool is_renaming() const;
+ /** \return If renaming was started successfully. */
+ bool begin_renaming();
+ void end_renaming();
+ Span<char> get_rename_buffer() const;
+ MutableSpan<char> get_rename_buffer();
+
+ protected:
+ AbstractView() = default;
+
+ virtual void update_children_from_old(const AbstractView &old_view) = 0;
+
+ /**
+ * Match the view and its items 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
+ * #AbstractViewItem.update_from_old().
+ * After this, reconstruction is complete (see #is_reconstructed()).
+ */
+ void update_from_old(uiBlock &new_block);
+ /**
+ * Check if the view is fully (re-)constructed. That means, both the build function and
+ * #update_from_old() have finished.
+ */
+ bool is_reconstructed() const;
+};
+
+class AbstractViewItem {
+ friend class AbstractView;
+ friend class ViewItemAPIWrapper;
+
+ protected:
+ /**
+ * The view this item is a part of, and was registered for using #AbstractView::register_item().
+ * If this wasn't done, the behavior of items is undefined.
+ */
+ AbstractView *view_ = nullptr;
+ bool is_active_ = false;
+ bool is_renaming_ = false;
+
+ public:
+ virtual ~AbstractViewItem() = default;
+
+ virtual void build_context_menu(bContext &C, uiLayout &column) const;
+
+ /**
+ * Queries if the 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
+ * #AbstractViewItem::supports_renaming() returned true. Sub-classes that override this should
+ * usually call this, unless they have a custom #AbstractViewItem.matches() implementation.
+ *
+ * \return True if the renaming was successful.
+ */
+ virtual bool rename(StringRefNull new_name);
+ /**
+ * Get the string that should be used for renaming, typically the item's label. This string will
+ * not be modified, but if the renaming is canceled, the value will be reset to this.
+ */
+ virtual StringRef get_rename_string() const;
+
+ /**
+ * If an item wants to support being dragged, it has to return a drag controller here.
+ * That is an object implementing #AbstractViewItemDragController.
+ */
+ virtual std::unique_ptr<AbstractViewItemDragController> 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 #AbstractViewItemDropController.
+ *
+ * \note This drop controller may be requested for each event. The view doesn't keep a drop
+ * controller around currently. So it can not contain persistent state.
+ */
+ virtual std::unique_ptr<AbstractViewItemDropController> create_drop_controller() const;
+
+ /** Get the view this item is registered for using #AbstractView::register_item(). */
+ AbstractView &get_view() const;
+
+ /**
+ * Requires the view to have completed reconstruction, see #is_reconstructed(). Otherwise we
+ * can't be sure about the item state.
+ */
+ bool is_active() const;
+
+ bool is_renaming() const;
+ void begin_renaming();
+ void end_renaming();
+ void rename_apply();
+
+ template<typename ToType = AbstractViewItem>
+ static ToType *from_item_handle(uiViewItemHandle *handle);
+
+ protected:
+ AbstractViewItem() = default;
+
+ /**
+ * Compare this item's identity to \a other to check if they represent the same data.
+ * Implementations can assume that the types match already (caller must check).
+ *
+ * Used to recognize an item from a previous redraw, to be able to keep its state (e.g. active,
+ * renaming, etc.).
+ */
+ virtual bool matches(const AbstractViewItem &other) const = 0;
+
+ /**
+ * Copy persistent state (e.g. active, 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.
+ *
+ * \note Always call the base class implementation when overriding this!
+ */
+ virtual void update_from_old(const AbstractViewItem &old);
+
+ /**
+ * Add a text button for renaming the item to \a block. This must be used for the built-in
+ * renaming to work. This button is meant to appear temporarily. It is removed when renaming is
+ * done.
+ */
+ void add_rename_button(uiBlock &block);
+};
+
+template<typename ToType> ToType *AbstractViewItem::from_item_handle(uiViewItemHandle *handle)
+{
+ static_assert(std::is_base_of<AbstractViewItem, ToType>::value,
+ "Type must derive from and implement the AbstractViewItem interface");
+
+ return dynamic_cast<ToType *>(reinterpret_cast<AbstractViewItem *>(handle));
+}
+
+/* ---------------------------------------------------------------------- */
+/** \name Drag 'n Drop
+ * \{ */
+
+/**
+ * Class to enable dragging a view item. An item can return a drop controller for itself by
+ * implementing #AbstractViewItem::create_drag_controller().
+ */
+class AbstractViewItemDragController {
+ protected:
+ AbstractView &view_;
+
+ public:
+ AbstractViewItemDragController(AbstractView &view);
+ virtual ~AbstractViewItemDragController() = default;
+
+ virtual int get_drag_type() const = 0;
+ virtual void *create_drag_data() const = 0;
+ virtual void on_drag_start();
+
+ /** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast`
+ * exception if the view is not of the requested type. */
+ template<class ViewType> inline ViewType &get_view() const;
+};
+
+/**
+ * Class to define the behavior when dropping something onto/into a view item, plus the behavior
+ * when dragging over this item. An item can return a drop controller for itself via a custom
+ * implementation of #AbstractViewItem::create_drop_controller().
+ */
+class AbstractViewItemDropController {
+ protected:
+ AbstractView &view_;
+
+ public:
+ AbstractViewItemDropController(AbstractView &view);
+ virtual ~AbstractViewItemDropController() = 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 view item. Should explain what happens when
+ * dropping the data onto this item. Will only be used if #AbstractViewItem::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;
+
+ /** Request the view the item is registered for as type #ViewType. Throws a `std::bad_cast`
+ * exception if the view is not of the requested type. */
+ template<class ViewType> inline ViewType &get_view() const;
+};
+
+template<class ViewType> ViewType &AbstractViewItemDragController::get_view() const
+{
+ static_assert(std::is_base_of<AbstractView, ViewType>::value,
+ "Type must derive from and implement the ui::AbstractView interface");
+ return dynamic_cast<ViewType &>(view_);
+}
+
+template<class ViewType> ViewType &AbstractViewItemDropController::get_view() const
+{
+ static_assert(std::is_base_of<AbstractView, ViewType>::value,
+ "Type must derive from and implement the ui::AbstractView interface");
+ return dynamic_cast<ViewType &>(view_);
+}
+
+/** \} */
+
+} // namespace blender::ui
diff --git a/source/blender/editors/include/UI_grid_view.hh b/source/blender/editors/include/UI_grid_view.hh
index 6f553f4fad1..402c0c8512f 100644
--- a/source/blender/editors/include/UI_grid_view.hh
+++ b/source/blender/editors/include/UI_grid_view.hh
@@ -13,12 +13,13 @@
#include "BLI_map.hh"
#include "BLI_vector.hh"
+#include "UI_abstract_view.hh"
#include "UI_resources.h"
struct bContext;
struct PreviewImage;
struct uiBlock;
-struct uiButGridTile;
+struct uiButViewItem;
struct uiLayout;
struct View2D;
struct wmNotifier;
@@ -31,43 +32,29 @@ class AbstractGridView;
/** \name Grid-View Item Type
* \{ */
-class AbstractGridViewItem {
+class AbstractGridViewItem : public AbstractViewItem {
friend class AbstractGridView;
friend class GridViewLayoutBuilder;
- const AbstractGridView *view_;
-
- bool is_active_ = false;
-
protected:
/** Reference to a string that uniquely identifies this item in the view. */
StringRef identifier_{};
- /** Every visible item gets a button of type #UI_BTYPE_GRID_TILE during the layout building. */
- uiButGridTile *grid_tile_but_ = nullptr;
+ /** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
+ uiButViewItem *view_item_but_ = nullptr;
public:
virtual ~AbstractGridViewItem() = default;
virtual void build_grid_tile(uiLayout &layout) const = 0;
- /**
- * Compare this item's identifier 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. active,
- * renaming, etc.).
- */
- bool matches(const AbstractGridViewItem &other) const;
-
const AbstractGridView &get_view() 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:
AbstractGridViewItem(StringRef identifier);
+ /** See AbstractViewItem::matches(). */
+ virtual bool matches(const AbstractViewItem &other) const override;
+
/** Called when the item's state changes from inactive to active. */
virtual void on_activate();
/**
@@ -77,13 +64,6 @@ class AbstractGridViewItem {
virtual std::optional<bool> should_be_active() const;
/**
- * Copy persistent state (e.g. active, 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 AbstractGridViewItem &old);
-
- /**
* Activates this item, deactivates other items, and calls the
* #AbstractGridViewItem::on_activate() function.
* Requires the tree to have completed reconstruction, see #is_reconstructed(). Otherwise the
@@ -111,7 +91,7 @@ struct GridViewStyle {
int tile_height = 0;
};
-class AbstractGridView {
+class AbstractGridView : public AbstractView {
friend class AbstractGridViewItem;
friend class GridViewBuilder;
friend class GridViewLayoutBuilder;
@@ -122,7 +102,6 @@ class AbstractGridView {
* #update_from_old(). */
Map<StringRef, AbstractGridViewItem *> item_map_;
GridViewStyle style_;
- bool is_reconstructed_ = false;
public:
AbstractGridView();
@@ -131,9 +110,6 @@ class AbstractGridView {
using ItemIterFn = FunctionRef<void(AbstractGridViewItem &)>;
void foreach_item(ItemIterFn iter_fn) const;
- /** Listen to a notifier, returning true if a redraw is needed. */
- virtual bool listen(const wmNotifier &) const;
-
/**
* Convenience wrapper constructing the item by forwarding given arguments to the constructor of
* the type (\a ItemT).
@@ -154,19 +130,8 @@ class AbstractGridView {
protected:
virtual void build_items() = 0;
- /**
- * Check if the view is fully (re-)constructed. That means, both #build_items() and
- * #update_from_old() have finished.
- */
- bool is_reconstructed() const;
-
private:
- /**
- * Match the grid-view against an earlier version of itself (if any) and copy the old UI state
- * (e.g. active, selected, renaming, etc.) to the new one. See
- * #AbstractGridViewItem.update_from_old().
- */
- void update_from_old(uiBlock &new_block);
+ void update_children_from_old(const AbstractView &old_view) override;
AbstractGridViewItem *find_matching_item(const AbstractGridViewItem &item_to_match,
const AbstractGridView &view_to_search_in) const;
/**
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index ea1095b26ff..09057fd846e 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -652,7 +652,7 @@ DEF_ICON(PARTICLE_TIP)
DEF_ICON(PARTICLE_PATH)
/* EDITING */
-DEF_ICON_BLANK(669)
+DEF_ICON(SNAP_FACE_NEAREST)
DEF_ICON(SNAP_FACE_CENTER)
DEF_ICON(SNAP_PERPENDICULAR)
DEF_ICON(SNAP_MIDPOINT)
@@ -891,6 +891,7 @@ DEF_ICON_COLOR(BRUSH_LAYER)
DEF_ICON_COLOR(BRUSH_MASK)
DEF_ICON_COLOR(BRUSH_MIX)
DEF_ICON_COLOR(BRUSH_NUDGE)
+DEF_ICON_COLOR(BRUSH_PAINT_SELECT)
DEF_ICON_COLOR(BRUSH_PINCH)
DEF_ICON_COLOR(BRUSH_SCRAPE)
DEF_ICON_COLOR(BRUSH_SCULPT_DRAW)
@@ -903,7 +904,6 @@ DEF_ICON_COLOR(BRUSH_TEXFILL)
DEF_ICON_COLOR(BRUSH_TEXMASK)
DEF_ICON_COLOR(BRUSH_THUMB)
DEF_ICON_COLOR(BRUSH_ROTATE)
-DEF_ICON_COLOR(BRUSH_PAINT)
/* grease pencil sculpt */
DEF_ICON_COLOR(GPBRUSH_SMOOTH)
@@ -929,6 +929,19 @@ DEF_ICON_COLOR(GPBRUSH_ERASE_SOFT)
DEF_ICON_COLOR(GPBRUSH_ERASE_HARD)
DEF_ICON_COLOR(GPBRUSH_ERASE_STROKE)
+/* Curves sculpt. */
+DEF_ICON_COLOR(BRUSH_CURVES_ADD)
+DEF_ICON_COLOR(BRUSH_CURVES_COMB)
+DEF_ICON_COLOR(BRUSH_CURVES_CUT)
+DEF_ICON_COLOR(BRUSH_CURVES_DELETE)
+DEF_ICON_COLOR(BRUSH_CURVES_DENSITY)
+DEF_ICON_COLOR(BRUSH_CURVES_GROW_SHRINK)
+DEF_ICON_COLOR(BRUSH_CURVES_PINCH)
+DEF_ICON_COLOR(BRUSH_CURVES_PUFF)
+DEF_ICON_COLOR(BRUSH_CURVES_SLIDE)
+DEF_ICON_COLOR(BRUSH_CURVES_SMOOTH)
+DEF_ICON_COLOR(BRUSH_CURVES_SNAKE_HOOK)
+
/* Vector icons. */
DEF_ICON_VECTOR(KEYTYPE_KEYFRAME_VEC)
DEF_ICON_VECTOR(KEYTYPE_BREAKDOWN_VEC)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 8503779f629..a8d25b75036 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -72,14 +72,10 @@ typedef struct uiBut uiBut;
typedef struct uiButExtraOpIcon uiButExtraOpIcon;
typedef struct uiLayout uiLayout;
typedef struct uiPopupBlockHandle uiPopupBlockHandle;
-/* C handle for C++ #ui::AbstractTreeView type. */
-typedef struct uiTreeViewHandle uiTreeViewHandle;
-/* C handle for C++ #ui::AbstractTreeViewItem type. */
-typedef struct uiTreeViewItemHandle uiTreeViewItemHandle;
-/* C handle for C++ #ui::AbstractGridView type. */
-typedef struct uiGridViewHandle uiGridViewHandle;
-/* C handle for C++ #ui::AbstractGridViewItem type. */
-typedef struct uiGridViewItemHandle uiGridViewItemHandle;
+/* C handle for C++ #ui::AbstractView type. */
+typedef struct uiViewHandle uiViewHandle;
+/* C handle for C++ #ui::AbstractViewItem type. */
+typedef struct uiViewItemHandle uiViewItemHandle;
/* Defines */
@@ -393,10 +389,8 @@ typedef enum {
/** Resize handle (resize uilist). */
UI_BTYPE_GRIP = 57 << 9,
UI_BTYPE_DECORATOR = 58 << 9,
- /* An item in a tree view. Parent items may be collapsible. */
- UI_BTYPE_TREEROW = 59 << 9,
- /* An item in a grid view. */
- UI_BTYPE_GRID_TILE = 60 << 9,
+ /* An item a view (see #ui::AbstractViewItem). */
+ UI_BTYPE_VIEW_ITEM = 59 << 9,
} eButType;
#define BUTTYPE (63 << 9)
@@ -858,33 +852,6 @@ 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, 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, bool use_free);
-
uiBut *UI_but_active_drop_name_button(const struct bContext *C);
/**
* Returns true if highlighted button allows drop of names.
@@ -1714,8 +1681,6 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name);
*/
void UI_but_hint_drawstr_set(uiBut *but, const char *string);
-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]);
void UI_but_number_step_size_set(uiBut *but, float step_size);
@@ -1774,6 +1739,14 @@ struct PointerRNA *UI_but_extra_operator_icon_add(uiBut *but,
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);
+/**
+ * A decent size for a button (typically #UI_BTYPE_PREVIEW_TILE) to display a nicely readable
+ * preview with label in.
+ */
+int UI_preview_tile_size_x(void);
+int UI_preview_tile_size_y(void);
+int UI_preview_tile_size_y_no_label(void);
+
/* Autocomplete
*
* Tab complete helper functions, for use in uiButCompleteFunc callbacks.
@@ -1790,13 +1763,37 @@ AutoComplete *UI_autocomplete_begin(const char *startname, size_t maxlen);
void UI_autocomplete_update_name(AutoComplete *autocpl, const char *name);
int UI_autocomplete_end(AutoComplete *autocpl, char *autoname);
+/* Button drag-data (interface_drag.cc).
+ *
+ * Functions to set drag data for buttons. This enables dragging support, whereby the drag data is
+ * "dragged", not the button itself. */
+
+void UI_but_drag_set_id(uiBut *but, struct ID *id);
/**
- * A decent size for a button (typically #UI_BTYPE_PREVIEW_TILE) to display a nicely readable
- * preview with label in.
+ * 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.
*/
-int UI_preview_tile_size_x(void);
-int UI_preview_tile_size_y(void);
-int UI_preview_tile_size_y_no_label(void);
+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, 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, bool use_free);
/* Panels
*
@@ -1881,7 +1878,7 @@ struct PointerRNA *UI_region_panel_custom_data_under_cursor(const struct bContex
const struct wmEvent *event);
void UI_panel_custom_data_set(struct Panel *panel, struct PointerRNA *custom_data);
-/* Polyinstantiated panels for representing a list of data. */
+/* Poly-instantiated 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.
@@ -3198,54 +3195,44 @@ void UI_interface_tag_script_reload(void);
void UI_block_views_listen(const uiBlock *block,
const struct wmRegionListenerParams *listener_params);
-bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle);
-bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item);
-bool UI_grid_view_item_matches(const uiGridViewItemHandle *a, const uiGridViewItemHandle *b);
-bool UI_tree_view_item_matches(const uiTreeViewItemHandle *a, const uiTreeViewItemHandle *b);
+bool UI_view_item_is_active(const uiViewItemHandle *item_handle);
+bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle);
/**
- * 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,
+ * Can \a item_handle be renamed right now? Note that this isn't just a mere wrapper around
+ * #AbstractViewItem::supports_renaming(). 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);
+bool UI_view_item_can_rename(const uiViewItemHandle *item_handle);
+void UI_view_item_begin_rename(uiViewItemHandle *item_handle);
-void UI_tree_view_item_context_menu_build(struct bContext *C,
- const uiTreeViewItemHandle *item,
- uiLayout *column);
+void UI_view_item_context_menu_build(struct bContext *C,
+ const uiViewItemHandle *item_handle,
+ uiLayout *column);
/**
- * \param xy: Coordinate to find a tree-row item at, in window space.
+ * Attempt to start dragging \a item_. This will not work if the view item doesn't
+ * support dragging, i.e. if it won't create a drag-controller upon request.
+ * \return True if dragging started successfully, otherwise false.
*/
-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);
-
+bool UI_view_item_drag_start(struct bContext *C, const uiViewItemHandle *item_);
+bool UI_view_item_can_drop(const uiViewItemHandle *item_,
+ const struct wmDrag *drag,
+ const char **r_disabled_hint);
+char *UI_view_item_drop_tooltip(const uiViewItemHandle *item, const struct wmDrag *drag);
/**
- * Listen to \a notifier, returning true if the region should redraw.
+ * Let a view item handle a drop event.
+ * \return True if the drop was handled by the view item.
*/
-bool UI_tree_view_listen_should_redraw(const uiTreeViewHandle *view, const wmNotifier *notifier);
+bool UI_view_item_drop_handle(struct bContext *C,
+ const uiViewItemHandle *item_,
+ const struct ListBase *drags);
+
/**
- * Listen to \a notifier, returning true if the region should redraw.
+ * \param xy: Coordinate to find a view item at, in window space.
*/
-bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view, const wmNotifier *notifier);
+uiViewItemHandle *UI_region_views_find_item_at(const struct ARegion *region, const int xy[2])
+ ATTR_NONNULL();
+uiViewItemHandle *UI_region_views_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 3dc56b01993..82bfdd7e212 100644
--- a/source/blender/editors/include/UI_interface.hh
+++ b/source/blender/editors/include/UI_interface.hh
@@ -46,7 +46,7 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path);
void attribute_search_add_items(
StringRefNull str,
- bool is_output,
+ bool can_create_attribute,
Span<const nodes::geometry_nodes_eval_log::GeometryAttributeInfo *> infos,
uiSearchItems *items,
bool is_first);
@@ -54,12 +54,12 @@ void attribute_search_add_items(
} // namespace blender::ui
/**
- * Override this for all available tree types.
+ * Override this for all available view types.
*/
blender::ui::AbstractGridView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
- std::unique_ptr<blender::ui::AbstractGridView> tree_view);
+ std::unique_ptr<blender::ui::AbstractGridView> grid_view);
blender::ui::AbstractTreeView *UI_block_add_view(
uiBlock &block,
blender::StringRef idname,
diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh
index 1aeb13ca5cc..872a6085060 100644
--- a/source/blender/editors/include/UI_tree_view.hh
+++ b/source/blender/editors/include/UI_tree_view.hh
@@ -9,7 +9,6 @@
#pragma once
-#include <array>
#include <functional>
#include <memory>
#include <string>
@@ -19,23 +18,19 @@
#include "BLI_function_ref.hh"
#include "BLI_vector.hh"
+#include "UI_abstract_view.hh"
#include "UI_resources.h"
struct bContext;
struct uiBlock;
struct uiBut;
-struct uiButTreeRow;
+struct uiButViewItem;
struct uiLayout;
-struct wmDrag;
-struct wmEvent;
-struct wmNotifier;
namespace blender::ui {
class AbstractTreeView;
class AbstractTreeViewItem;
-class AbstractTreeViewItemDropController;
-class AbstractTreeViewItemDragController;
/* ---------------------------------------------------------------------- */
/** \name Tree-View Item Container
@@ -112,45 +107,20 @@ using TreeViewOrItem = TreeViewItemContainer;
/** \name Tree-View Base Class
* \{ */
-class AbstractTreeView : public TreeViewItemContainer {
+class AbstractTreeView : public AbstractView, public TreeViewItemContainer {
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;
- /** Listen to a notifier, returning true if a redraw is needed. */
- virtual bool listen(const wmNotifier &) 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, renaming, etc.) to the new one. See
- * #AbstractTreeViewItem.update_from_old().
- */
- void update_from_old(uiBlock &new_block);
+ void update_children_from_old(const AbstractView &old_view) override;
static void update_children_from_old_recursive(const TreeViewOrItem &new_items,
const TreeViewOrItem &old_items);
static AbstractTreeViewItem *find_matching_child(const AbstractTreeViewItem &lookup_item,
@@ -177,7 +147,7 @@ class AbstractTreeView : public TreeViewItemContainer {
* It also stores state information that needs to be persistent over redraws, like the collapsed
* state.
*/
-class AbstractTreeViewItem : public TreeViewItemContainer {
+class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContainer {
friend class AbstractTreeView;
friend class TreeViewLayoutBuilder;
/* Higher-level API. */
@@ -185,20 +155,17 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
private:
bool is_open_ = false;
- bool is_active_ = false;
- bool is_renaming_ = false;
protected:
/** This label is used as the default way to 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;
+ /** Every visible item gets a button of type #UI_BTYPE_VIEW_ITEM during the layout building. */
+ uiButViewItem *view_item_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;
@@ -210,11 +177,6 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* 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:
/**
@@ -227,31 +189,21 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
*/
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);
+ /** See AbstractViewItem::get_rename_string(). */
+ virtual StringRef get_rename_string() const override;
+ /** See AbstractViewItem::rename(). */
+ virtual bool rename(StringRefNull new_name) override;
/**
* 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.
- */
- virtual void update_from_old(const AbstractTreeViewItem &old);
+ /** See #AbstractViewItem::matches(). */
+ virtual bool matches(const AbstractViewItem &other) const override;
+
+ /** See #AbstractViewItem::update_from_old(). */
+ virtual void update_from_old(const AbstractViewItem &old) override;
/**
* Compare this item to \a other to check if they represent the same data.
@@ -259,22 +211,11 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
* 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.
+ * TODO #matches_single() is a rather temporary name, used to indicate that this only compares
+ * the item itself, not the parents. Item matching is expected to change quite a bit anyway.
*/
- virtual std::unique_ptr<AbstractTreeViewItemDropController> create_drop_controller() const;
+ virtual bool matches_single(const AbstractTreeViewItem &other) const;
/**
* Activates this item, deactivates other items, calls the #AbstractTreeViewItem::on_activate()
@@ -292,29 +233,24 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
*/
bool is_hovered() const;
bool is_collapsible() const;
- bool is_renaming() const;
void ensure_parents_uncollapsed();
- uiButTreeRow *tree_row_button();
+ uiButViewItem *view_item_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;
};
@@ -322,69 +258,6 @@ class AbstractTreeViewItem : public TreeViewItemContainer {
/** \} */
/* ---------------------------------------------------------------------- */
-/** \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;
-};
-
-/** \} */
-
-/* ---------------------------------------------------------------------- */
/** \name Predefined Tree-View Item Types
*
* Common, Basic Tree-View Item Types.
@@ -455,18 +328,4 @@ inline ItemT &TreeViewItemContainer::add_tree_item(Args &&...args)
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 23dbd3ed36f..e508c96b4f1 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -49,8 +49,21 @@ enum eView2D_CommonViewTypes {
/* ------ Defines for Scrollers ----- */
/** Scroll bar area. */
-#define V2D_SCROLL_HEIGHT (0.45f * U.widget_unit)
-#define V2D_SCROLL_WIDTH (0.45f * U.widget_unit)
+
+/* Maximum has to include outline which varies with line width. */
+#define V2D_SCROLL_HEIGHT ((0.45f * U.widget_unit) + (2.0f * U.pixelsize))
+#define V2D_SCROLL_WIDTH ((0.45f * U.widget_unit) + (2.0f * U.pixelsize))
+
+/* Alpha of scrollbar when at minimum size. */
+#define V2D_SCROLL_MIN_ALPHA (0.4f)
+
+/* Minimum size needs to include outline which varies with line width. */
+#define V2D_SCROLL_MIN_WIDTH ((5.0f * U.dpi_fac) + (2.0f * U.pixelsize))
+
+/* When to start showing the full-width scroller. */
+#define V2D_SCROLL_HIDE_WIDTH (AREAMINX * U.dpi_fac)
+#define V2D_SCROLL_HIDE_HEIGHT (HEADERY * U.dpi_fac)
+
/** Scroll bars with 'handles' used for scale (zoom). */
#define V2D_SCROLL_HANDLE_HEIGHT (0.6f * U.widget_unit)
#define V2D_SCROLL_HANDLE_WIDTH (0.6f * U.widget_unit)
@@ -236,9 +249,13 @@ void UI_view2d_draw_scale_x__frames_or_seconds(const struct ARegion *region,
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_ex(struct View2D *v2d,
+ const struct rcti *mask_custom,
+ bool use_full_hide);
void UI_view2d_scrollers_draw(struct View2D *v2d, const struct rcti *mask_custom);
/* List view tools. */
@@ -292,6 +309,12 @@ float UI_view2d_view_to_region_y(const struct View2D *v2d, float y);
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();
+bool UI_view2d_view_to_region_segment_clip(const View2D *v2d,
+ const float xy_a[2],
+ const float xy_b[2],
+ int r_region_a[2],
+ int r_region_b[2]) ATTR_NONNULL();
+
/**
* Convert from 2d-view space to screen/region space
*
@@ -329,8 +352,10 @@ 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.
+ *
+ * \param mapped: whether to use view2d_scroll_mapped which changes flags
*/
-void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_scroller_size_get(const struct View2D *v2d, bool mapped, float *r_x, float *r_y);
/**
* Calculate the scale per-axis of the drawing-area
*
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index a514cd6ecd1..07c3bfdafbf 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
set(INC
+ .
../include
../../blenfont
../../blenkernel
@@ -25,22 +26,22 @@ set(INC
)
set(SRC
- grid_view.cc
+ eyedroppers/interface_eyedropper.c
+ eyedroppers/eyedropper_color.c
+ eyedroppers/eyedropper_colorband.c
+ eyedroppers/eyedropper_datablock.c
+ eyedroppers/eyedropper_depth.c
+ eyedroppers/eyedropper_driver.c
+ eyedroppers/eyedropper_gpencil_color.c
interface.cc
interface_align.c
interface_anim.c
interface_button_group.c
interface_context_menu.c
interface_context_path.cc
+ interface_drag.cc
interface_draw.c
interface_dropboxes.cc
- interface_eyedropper.c
- interface_eyedropper_color.c
- interface_eyedropper_colorband.c
- interface_eyedropper_datablock.c
- interface_eyedropper_depth.c
- interface_eyedropper_driver.c
- interface_eyedropper_gpencil_color.c
interface_handlers.c
interface_icons.c
interface_icons_event.c
@@ -66,17 +67,20 @@ set(SRC
interface_templates.c
interface_undo.c
interface_utils.cc
- interface_view.cc
interface_widgets.c
resources.c
- tree_view.cc
view2d.cc
view2d_draw.cc
view2d_edge_pan.cc
view2d_gizmo_navigate.cc
view2d_ops.cc
+ views/abstract_view.cc
+ views/abstract_view_item.cc
+ views/grid_view.cc
+ views/interface_view.cc
+ views/tree_view.cc
- interface_eyedropper_intern.h
+ eyedroppers/eyedropper_intern.h
interface_intern.h
interface_regions_intern.h
)
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/eyedroppers/eyedropper_color.c
index 895f8d0d840..a2161008ec4 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_color.c
@@ -50,9 +50,7 @@
#include "RE_pipeline.h"
-#include "RE_pipeline.h"
-
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
typedef struct Eyedropper {
struct ColorManagedDisplay *display;
@@ -329,7 +327,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
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};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_image_color_sample(sima, region, region_mval, r_col, NULL)) {
return;
@@ -340,7 +338,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
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};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_node_color_sample(bmain, snode, region, region_mval, r_col)) {
return;
@@ -351,7 +349,7 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
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};
+ const int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
if (ED_space_clip_color_sample(sc, region, region_mval, r_col)) {
return;
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/eyedroppers/eyedropper_colorband.c
index a69c36fefbd..3f63a8020ed 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_colorband.c
@@ -35,7 +35,7 @@
#include "interface_intern.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
typedef struct Colorband_RNAUpdateCb {
PointerRNA ptr;
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/eyedroppers/eyedropper_datablock.c
index aec8f56678a..1710d0faa4d 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_datablock.c
@@ -38,7 +38,7 @@
#include "ED_space_api.h"
#include "ED_view3d.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
#include "interface_intern.h"
/**
@@ -156,7 +156,7 @@ static void datadropper_id_sample_pt(
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
- /* grr, always draw else we leave stale text */
+ /* Unfortunately it's necessary to always draw else we leave stale text. */
ED_region_tag_redraw(region);
if (area->spacetype == SPACE_VIEW3D) {
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c
index 56bc1a6d956..3fb5a74944b 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_depth.c
@@ -38,7 +38,7 @@
#include "ED_space_api.h"
#include "ED_view3d.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
#include "interface_intern.h"
/**
@@ -171,7 +171,7 @@ static void depthdropper_depth_sample_pt(bContext *C,
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
- /* grr, always draw else we leave stale text */
+ /* Unfortunately it's necessary to always draw otherwise we leave stale text. */
ED_region_tag_redraw(region);
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c
index 0cacb55c60c..14c00c21a5c 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c
@@ -32,7 +32,7 @@
#include "ED_keyframing.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
#include "interface_intern.h"
typedef struct DriverDropper {
diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.c
index f3c70e6a96a..c3879fe8bbd 100644
--- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.c
@@ -46,7 +46,7 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "interface_eyedropper_intern.h"
+#include "eyedropper_intern.h"
#include "interface_intern.h"
typedef struct EyedropperGPencil {
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/eyedroppers/eyedropper_intern.h
index 76316a85807..946f2145d1d 100644
--- a/source/blender/editors/interface/interface_eyedropper_intern.h
+++ b/source/blender/editors/interface/eyedroppers/eyedropper_intern.h
@@ -3,7 +3,7 @@
/** \file
* \ingroup edinterface
*
- * Share between interface_eyedropper_*.c files.
+ * Share between `interface/eyedropper/` files.
*/
#pragma once
@@ -35,7 +35,7 @@ void datadropper_win_area_find(const struct bContext *C,
*
* 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.
+ * \note Exposed by 'eyedropper_intern.h' for use with color band picking.
*/
void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/eyedroppers/interface_eyedropper.c
index eaec1e249b7..c6fb8f0ab68 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/eyedroppers/interface_eyedropper.c
@@ -21,7 +21,7 @@
#include "interface_intern.h"
-#include "interface_eyedropper_intern.h" /* own include */
+#include "eyedropper_intern.h" /* own include */
/* -------------------------------------------------------------------- */
/* Keymap
diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc
index ec2ae43acda..2f9e69137ed 100644
--- a/source/blender/editors/interface/interface.cc
+++ b/source/blender/editors/interface/interface.cc
@@ -769,20 +769,11 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
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;
- }
- }
-
- if ((but->type == UI_BTYPE_GRID_TILE) && (oldbut->type == UI_BTYPE_GRID_TILE)) {
- uiButGridTile *but_gridtile = (uiButGridTile *)but;
- uiButGridTile *oldbut_gridtile = (uiButGridTile *)oldbut;
- if (!but_gridtile->view_item || !oldbut_gridtile->view_item ||
- !UI_grid_view_item_matches(but_gridtile->view_item, oldbut_gridtile->view_item)) {
+ if ((but->type == UI_BTYPE_VIEW_ITEM) && (oldbut->type == UI_BTYPE_VIEW_ITEM)) {
+ uiButViewItem *but_item = (uiButViewItem *)but;
+ uiButViewItem *oldbut_item = (uiButViewItem *)oldbut;
+ if (!but_item->view_item || !oldbut_item->view_item ||
+ !UI_view_item_matches(but_item->view_item, oldbut_item->view_item)) {
return false;
}
}
@@ -907,16 +898,10 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
progress_oldbut->progress = progress_but->progress;
break;
}
- case UI_BTYPE_TREEROW: {
- uiButTreeRow *treerow_oldbut = (uiButTreeRow *)oldbut;
- uiButTreeRow *treerow_newbut = (uiButTreeRow *)but;
- SWAP(uiTreeViewItemHandle *, treerow_newbut->tree_item, treerow_oldbut->tree_item);
- break;
- }
- case UI_BTYPE_GRID_TILE: {
- uiButGridTile *gridtile_oldbut = (uiButGridTile *)oldbut;
- uiButGridTile *gridtile_newbut = (uiButGridTile *)but;
- SWAP(uiGridViewItemHandle *, gridtile_newbut->view_item, gridtile_oldbut->view_item);
+ case UI_BTYPE_VIEW_ITEM: {
+ uiButViewItem *view_item_oldbut = (uiButViewItem *)oldbut;
+ uiButViewItem *view_item_newbut = (uiButViewItem *)but;
+ SWAP(uiViewItemHandle *, view_item_newbut->view_item, view_item_oldbut->view_item);
break;
}
default:
@@ -942,9 +927,12 @@ static void ui_but_update_old_active_from_new(uiBut *oldbut, uiBut *but)
BLI_strncpy(oldbut->strdata, but->strdata, sizeof(oldbut->strdata));
}
- if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ if (but->dragpoin) {
SWAP(void *, but->dragpoin, oldbut->dragpoin);
}
+ if (but->imb) {
+ SWAP(ImBuf *, but->imb, oldbut->imb);
+ }
/* NOTE: if layout hasn't been applied yet, it uses old button pointers... */
}
@@ -1010,7 +998,7 @@ static bool ui_but_update_from_old_block(const bContext *C,
/* Stupid special case: The active button may be inside (as in, overlapped on top) a view-item
* button which we also want to keep highlighted then. */
- if (ui_but_is_view_item(but)) {
+ if (but->type == UI_BTYPE_VIEW_ITEM) {
flag_copy |= UI_ACTIVE;
}
@@ -2242,21 +2230,12 @@ int ui_but_is_pushed_ex(uiBut *but, double *value)
}
}
break;
- case UI_BTYPE_TREEROW: {
- uiButTreeRow *tree_row_but = (uiButTreeRow *)but;
+ case UI_BTYPE_VIEW_ITEM: {
+ const uiButViewItem *view_item_but = (const uiButViewItem *)but;
is_push = -1;
- if (tree_row_but->tree_item) {
- is_push = UI_tree_view_item_is_active(tree_row_but->tree_item);
- }
- break;
- }
- case UI_BTYPE_GRID_TILE: {
- uiButGridTile *grid_tile_but = (uiButGridTile *)but;
-
- is_push = -1;
- if (grid_tile_but->view_item) {
- is_push = UI_grid_view_item_is_active(grid_tile_but->view_item);
+ if (view_item_but->view_item) {
+ is_push = UI_view_item_is_active(view_item_but->view_item);
}
break;
}
@@ -3466,9 +3445,7 @@ static void ui_but_free(const bContext *C, uiBut *but)
IMB_freeImBuf((struct ImBuf *)but->poin);
}
- if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- }
+ ui_but_drag_free(but);
ui_but_extra_operator_icons_free(but);
BLI_assert(UI_butstore_is_registered(but->block, but) == false);
@@ -4010,17 +3987,13 @@ static void ui_but_alloc_info(const eButType type,
alloc_size = sizeof(uiButCurveProfile);
alloc_str = "uiButCurveProfile";
break;
- case UI_BTYPE_TREEROW:
- alloc_size = sizeof(uiButTreeRow);
- alloc_str = "uiButTreeRow";
- break;
case UI_BTYPE_HOTKEY_EVENT:
alloc_size = sizeof(uiButHotkeyEvent);
alloc_str = "uiButHotkeyEvent";
break;
- case UI_BTYPE_GRID_TILE:
- alloc_size = sizeof(uiButGridTile);
- alloc_str = "uiButGridTile";
+ case UI_BTYPE_VIEW_ITEM:
+ alloc_size = sizeof(uiButViewItem);
+ alloc_str = "uiButViewItem";
break;
default:
alloc_size = sizeof(uiBut);
@@ -4213,7 +4186,6 @@ static uiBut *ui_def_but(uiBlock *block,
UI_BTYPE_BLOCK,
UI_BTYPE_BUT_MENU,
UI_BTYPE_SEARCH_MENU,
- UI_BTYPE_TREEROW,
UI_BTYPE_POPOVER)) {
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@@ -5933,104 +5905,6 @@ int UI_but_return_value_get(uiBut *but)
return but->retval;
}
-void UI_but_drag_set_id(uiBut *but, ID *id)
-{
- but->dragtype = WM_DRAG_ID;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)id;
-}
-
-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 = WM_drag_create_asset_data(asset, metadata, path, 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 = static_cast<bContext *>(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 */
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- }
- but->dragpoin = asset_drag;
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- UI_but_drag_attach_image(but, imb, scale);
-}
-
-void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
-{
- but->dragtype = WM_DRAG_RNA;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)ptr;
-}
-
-void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free)
-{
- but->dragtype = WM_DRAG_PATH;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)path;
- if (use_free) {
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- }
-}
-
-void UI_but_drag_set_name(uiBut *but, const char *name)
-{
- but->dragtype = WM_DRAG_NAME;
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)name;
-}
-
-void UI_but_drag_set_value(uiBut *but)
-{
- but->dragtype = WM_DRAG_VALUE;
-}
-
-void UI_but_drag_set_image(
- uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free)
-{
- but->dragtype = WM_DRAG_PATH;
- ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
- if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
- WM_drag_data_free(but->dragtype, but->dragpoin);
- but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
- }
- but->dragpoin = (void *)path;
- if (use_free) {
- but->dragflag |= UI_BUT_DRAGPOIN_FREE;
- }
- UI_but_drag_attach_image(but, imb, scale);
-}
-
PointerRNA *UI_but_operator_ptr_get(uiBut *but)
{
if (but->optype && !but->opptr) {
@@ -6566,15 +6440,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
-void UI_but_treerow_indentation_set(uiBut *but, int indentation)
-{
- uiButTreeRow *but_row = (uiButTreeRow *)but;
- BLI_assert(but->type == UI_BTYPE_TREEROW);
-
- but_row->indentation = indentation;
- BLI_assert(indentation >= 0);
-}
-
void UI_but_hint_drawstr_set(uiBut *but, const char *string)
{
ui_but_add_shortcut(but, string, false);
@@ -6720,7 +6585,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
MenuType *mt = UI_but_menutype_get(but);
if (mt) {
if (type == BUT_GET_RNA_LABEL) {
- tmp = BLI_strdup(mt->label);
+ tmp = BLI_strdup(CTX_TIP_(mt->translation_context, mt->label));
}
else {
/* Not all menus are from Python. */
@@ -6750,7 +6615,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
PanelType *pt = UI_but_paneltype_get(but);
if (pt) {
if (type == BUT_GET_RNA_LABEL) {
- tmp = BLI_strdup(pt->label);
+ tmp = BLI_strdup(CTX_TIP_(pt->translation_context, pt->label));
}
else {
/* Not all panels are from Python. */
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index e838ce37d8e..0e69b4bb358 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -293,7 +293,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
void ui_but_anim_autokey(bContext *C, uiBut *but, Scene *scene, float cfra)
{
- ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra);
+ ED_autokeyframe_property(C, scene, &but->rnapoin, but->rnaprop, but->rnaindex, cfra, true);
}
void ui_but_anim_copy_driver(bContext *C)
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index e58298cdaee..518fe65ee09 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -927,11 +927,11 @@ 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));
+ uiButViewItem *view_item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region,
+ event->xy);
+ if (view_item_but) {
+ BLI_assert(view_item_but->but.type == UI_BTYPE_VIEW_ITEM);
+ UI_view_item_context_menu_build(C, view_item_but->view_item, uiLayoutColumn(layout, false));
uiItemS(layout);
}
}
diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc
new file mode 100644
index 00000000000..1db3db32411
--- /dev/null
+++ b/source/blender/editors/interface/interface_drag.cc
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+
+#include "interface_intern.h"
+
+void UI_but_drag_set_id(uiBut *but, ID *id)
+{
+ but->dragtype = WM_DRAG_ID;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)id;
+}
+
+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 = WM_drag_create_asset_data(asset, metadata, path, 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 = static_cast<bContext *>(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 */
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ }
+ but->dragpoin = asset_drag;
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ UI_but_drag_attach_image(but, imb, scale);
+}
+
+void UI_but_drag_set_rna(uiBut *but, PointerRNA *ptr)
+{
+ but->dragtype = WM_DRAG_RNA;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)ptr;
+}
+
+void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free)
+{
+ but->dragtype = WM_DRAG_PATH;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)path;
+ if (use_free) {
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ }
+}
+
+void UI_but_drag_set_name(uiBut *but, const char *name)
+{
+ but->dragtype = WM_DRAG_NAME;
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)name;
+}
+
+void UI_but_drag_set_value(uiBut *but)
+{
+ but->dragtype = WM_DRAG_VALUE;
+}
+
+void UI_but_drag_set_image(
+ uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free)
+{
+ but->dragtype = WM_DRAG_PATH;
+ ui_def_but_icon(but, icon, 0); /* no flag UI_HAS_ICON, so icon doesn't draw in button */
+ if (but->dragflag & UI_BUT_DRAGPOIN_FREE) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ but->dragflag &= ~UI_BUT_DRAGPOIN_FREE;
+ }
+ but->dragpoin = (void *)path;
+ if (use_free) {
+ but->dragflag |= UI_BUT_DRAGPOIN_FREE;
+ }
+ UI_but_drag_attach_image(but, imb, scale);
+}
+
+void ui_but_drag_free(uiBut *but)
+{
+ if (but->dragpoin && (but->dragflag & UI_BUT_DRAGPOIN_FREE)) {
+ WM_drag_data_free(but->dragtype, but->dragpoin);
+ }
+}
+
+bool ui_but_drag_is_draggable(const uiBut *but)
+{
+ return but->dragpoin != nullptr;
+}
+
+void ui_but_drag_start(bContext *C, uiBut *but)
+{
+ wmDrag *drag = WM_drag_data_create(C,
+ but->icon,
+ but->dragtype,
+ but->dragpoin,
+ ui_but_value_get(but),
+ (but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA :
+ WM_DRAG_NOP);
+ /* wmDrag has ownership over dragpoin now, stop messing with it. */
+ but->dragpoin = NULL;
+
+ if (but->imb) {
+ WM_event_drag_image(drag, but->imb, but->imb_scale);
+ }
+
+ WM_event_start_prepared_drag(C, drag);
+
+ /* 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);
+ }
+}
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 18bad7949ee..d201820fbb6 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -130,7 +130,7 @@ void UI_draw_roundbox_4fv_ex(const rctf *rect,
void UI_draw_roundbox_3ub_alpha(
const rctf *rect, bool filled, float rad, const uchar col[3], uchar alpha)
{
- float colv[4] = {
+ const float colv[4] = {
((float)col[0]) / 255,
((float)col[1]) / 255,
((float)col[2]) / 255,
@@ -142,7 +142,7 @@ void UI_draw_roundbox_3ub_alpha(
void UI_draw_roundbox_3fv_alpha(
const rctf *rect, bool filled, float rad, const float col[3], float alpha)
{
- float colv[4] = {col[0], col[1], col[2], alpha};
+ const float colv[4] = {col[0], col[1], col[2], alpha};
UI_draw_roundbox_4fv_ex(rect, (filled) ? colv : NULL, NULL, 1.0f, colv, U.pixelsize, rad);
}
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
index 9d3c1372b15..b72d8d2c238 100644
--- a/source/blender/editors/interface/interface_dropboxes.cc
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -22,15 +22,14 @@
#include "UI_interface.h"
/* -------------------------------------------------------------------- */
-/** \name Tree View Drag/Drop Callbacks
+/** \name View Drag/Drop Callbacks
* \{ */
-static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+static bool ui_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) {
+ const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, event->xy);
+ if (!hovered_item) {
return false;
}
@@ -39,21 +38,21 @@ static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve
}
drag->drop_state.free_disabled_info = false;
- return UI_tree_view_item_can_drop(hovered_tree_item, drag, &drag->drop_state.disabled_info);
+ return UI_view_item_can_drop(hovered_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))
+static char *ui_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) {
+ const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, xy);
+ if (!hovered_item) {
return nullptr;
}
- return UI_tree_view_item_drop_tooltip(hovered_tree_item, drag);
+ return UI_view_item_drop_tooltip(hovered_item, drag);
}
/** \} */
@@ -140,12 +139,7 @@ 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_view_drop", ui_view_drop_poll, nullptr, nullptr, ui_view_drop_tooltip);
WM_dropbox_add(lb,
"UI_OT_drop_name",
ui_drop_name_poll,
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index d1a92da3853..0a50522a141 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1151,7 +1151,10 @@ static void ui_apply_but_ROW(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
data->applied = true;
}
-static void ui_apply_but_TREEROW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data)
+static void ui_apply_but_VIEW_ITEM(bContext *C,
+ uiBlock *block,
+ uiBut *but,
+ uiHandleButtonData *data)
{
if (data->apply_through_extra_icon) {
/* Don't apply this, it would cause unintended tree-row toggling when clicking on extra icons.
@@ -1480,9 +1483,9 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
}
}
- /* edit buttons proportionally to eachother
+ /* Edit buttons proportionally to each other.
* NOTE: if we mix buttons which are proportional and others which are not,
- * this may work a bit strangely */
+ * this may work a bit strangely. */
if ((but_active->rnaprop && (RNA_property_flag(but_active->rnaprop) & PROP_PROPORTIONAL)) ||
ELEM(but_active->unit_type, RNA_SUBTYPE_UNIT_VALUE(PROP_UNIT_LENGTH))) {
if (data->origvalue != 0.0) {
@@ -2128,32 +2131,14 @@ 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 if (but->type == UI_BTYPE_VIEW_ITEM) {
+ const uiButViewItem *view_item_but = (uiButViewItem *)but;
+ if (view_item_but->view_item) {
+ UI_view_item_drag_start(C, view_item_but->view_item);
}
}
else {
- wmDrag *drag = WM_event_start_drag(
- C,
- but->icon,
- but->dragtype,
- but->dragpoin,
- ui_but_value_get(but),
- (but->dragflag & UI_BUT_DRAGPOIN_FREE) ? WM_DRAG_FREE_DATA : WM_DRAG_NOP);
- /* wmDrag has ownership over dragpoin now, stop messing with it. */
- but->dragpoin = NULL;
-
- if (but->imb) {
- WM_event_drag_image(drag, but->imb, but->imb_scale);
- }
-
- /* 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);
- }
+ ui_but_drag_start(C, but);
}
return true;
}
@@ -2307,11 +2292,8 @@ static void ui_apply_but(
case UI_BTYPE_ROW:
ui_apply_but_ROW(C, block, but, data);
break;
- case UI_BTYPE_GRID_TILE:
- ui_apply_but_ROW(C, block, but, data);
- break;
- case UI_BTYPE_TREEROW:
- ui_apply_but_TREEROW(C, block, but, data);
+ case UI_BTYPE_VIEW_ITEM:
+ ui_apply_but_VIEW_ITEM(C, block, but, data);
break;
case UI_BTYPE_LISTROW:
ui_apply_but_LISTROW(C, block, but, data);
@@ -2966,6 +2948,9 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR],
void ui_but_set_string_interactive(bContext *C, uiBut *but, const char *value)
{
+ /* Caller should check. */
+ BLI_assert((but->flag & UI_BUT_DISABLED) == 0);
+
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
ui_textedit_string_set(but, but->active, value);
@@ -3187,19 +3172,11 @@ static bool ui_textedit_insert_buf(uiBut *but,
return changed;
}
-static bool ui_textedit_insert_ascii(uiBut *but, uiHandleButtonData *data, char ascii)
+static bool ui_textedit_insert_ascii(uiBut *but, uiHandleButtonData *data, const char ascii)
{
+ BLI_assert(isascii(ascii));
const char buf[2] = {ascii, '\0'};
-
- if (UI_but_is_utf8(but) && (BLI_str_utf8_size(buf) == -1)) {
- printf(
- "%s: entering invalid ascii char into an ascii key (%d)\n", __func__, (int)(uchar)ascii);
-
- return false;
- }
-
- /* in some cases we want to allow invalid utf8 chars */
- return ui_textedit_insert_buf(but, data, buf, 1);
+ return ui_textedit_insert_buf(but, data, buf, sizeof(buf) - 1);
}
static void ui_textedit_move(uiBut *but,
@@ -3510,7 +3487,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT);
#ifdef WITH_INPUT_IME
- if (is_num_but == false && BLT_lang_is_ime_supported()) {
+ if (!is_num_but) {
ui_textedit_ime_begin(win, but);
}
#endif
@@ -3912,30 +3889,27 @@ static void ui_do_but_textedit(
}
}
- if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
+ if ((event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
#ifdef WITH_INPUT_IME
- && !is_ime_composing && (!WM_event_is_ime_switch(event) || !BLT_lang_is_ime_supported())
+ && !is_ime_composing && !WM_event_is_ime_switch(event)
#endif
) {
- char ascii = event->ascii;
+ char utf8_buf_override[2] = {'\0', '\0'};
const char *utf8_buf = event->utf8_buf;
/* Exception that's useful for number buttons, some keyboard
* numpads have a comma instead of a period. */
if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) { /* Could use `data->min`. */
- if (event->type == EVT_PADPERIOD && ascii == ',') {
- ascii = '.';
- utf8_buf = NULL; /* force ascii fallback */
+ if ((event->type == EVT_PADPERIOD) && (utf8_buf[0] == ',')) {
+ utf8_buf_override[0] = '.';
+ utf8_buf = utf8_buf_override;
}
}
- if (utf8_buf && utf8_buf[0]) {
+ if (utf8_buf[0]) {
const int utf8_buf_len = BLI_str_utf8_size(utf8_buf);
BLI_assert(utf8_buf_len != -1);
- changed = ui_textedit_insert_buf(but, data, event->utf8_buf, utf8_buf_len);
- }
- else {
- changed = ui_textedit_insert_ascii(but, data, ascii);
+ changed = ui_textedit_insert_buf(but, data, utf8_buf, utf8_buf_len);
}
retval = WM_UI_HANDLER_BREAK;
@@ -3967,6 +3941,9 @@ static void ui_do_but_textedit(
else if (event->type == WM_IME_COMPOSITE_END) {
changed = true;
}
+#else
+ /* Prevent the function from being unused. */
+ (void)ui_textedit_insert_ascii;
#endif
if (changed) {
@@ -4787,54 +4764,13 @@ 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->region, 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_GRIDTILE(bContext *C,
- uiBut *but,
- uiHandleButtonData *data,
- const wmEvent *event)
+static int ui_do_but_VIEW_ITEM(bContext *C,
+ uiBut *but,
+ uiHandleButtonData *data,
+ const wmEvent *event)
{
- uiButGridTile *grid_tile_but = (uiButGridTile *)but;
- BLI_assert(grid_tile_but->but.type == UI_BTYPE_GRID_TILE);
+ uiButViewItem *view_item_but = (uiButViewItem *)but;
+ BLI_assert(view_item_but->but.type == UI_BTYPE_VIEW_ITEM);
if (data->state == BUTTON_STATE_HIGHLIGHT) {
if (event->type == LEFTMOUSE) {
@@ -4855,7 +4791,7 @@ static int ui_do_but_GRIDTILE(bContext *C,
case KM_DBL_CLICK:
data->cancel = true;
- // UI_tree_view_item_begin_rename(grid_tile_but->tree_item);
+ UI_view_item_begin_rename(view_item_but->view_item);
ED_region_tag_redraw(CTX_wm_region(C));
return WM_UI_HANDLER_BREAK;
}
@@ -4874,7 +4810,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && but->dragpoin) {
+ if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) && ui_but_drag_is_draggable(but)) {
if (ui_but_contains_point_px_icon(but, data->region, event)) {
/* tell the button to wait and keep checking further events to
@@ -4897,7 +4833,8 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
if (ELEM(event->type, LEFTMOUSE, EVT_PADENTER, EVT_RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX: (a bit ugly) Special case handling for file-browser drag button. */
- if (but->dragpoin && but->imb && ui_but_contains_point_px_icon(but, data->region, event)) {
+ if (ui_but_drag_is_draggable(but) && but->imb &&
+ ui_but_contains_point_px_icon(but, data->region, event)) {
ret = WM_UI_HANDLER_CONTINUE;
}
/* Same special case handling for UI lists. Return CONTINUE so that a tweak or CLICK event
@@ -6055,7 +5992,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ if (event->type == LEFTMOUSE && ui_but_drag_is_draggable(but) && 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->xy[0];
@@ -6241,7 +6178,7 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
if (data->state == BUTTON_STATE_HIGHLIGHT) {
/* First handle click on icon-drag type button. */
- if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ if (event->type == LEFTMOUSE && ui_but_drag_is_draggable(but) && event->val == KM_PRESS) {
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);
@@ -7456,8 +7393,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block,
const float zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&profile->view_rect);
if (snap) {
- float d[2] = {mx - data->dragstartx, data->dragstarty};
-
+ const float d[2] = {mx - data->dragstartx, data->dragstarty};
if (len_squared_v2(d) < (9.0f * U.dpi_fac)) {
snap = false;
}
@@ -8003,7 +7939,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
* 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)) {
+ if (ELEM(but->type, UI_BTYPE_VIEW_ITEM)) {
ui_apply_but(C, but->block, but, but->active, true);
}
@@ -8068,11 +8004,8 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
case UI_BTYPE_ROW:
retval = ui_do_but_TOG(C, but, data, event);
break;
- case UI_BTYPE_GRID_TILE:
- retval = ui_do_but_GRIDTILE(C, but, data, event);
- break;
- case UI_BTYPE_TREEROW:
- retval = ui_do_but_TREEROW(C, but, data, event);
+ case UI_BTYPE_VIEW_ITEM:
+ retval = ui_do_but_VIEW_ITEM(C, but, data, event);
break;
case UI_BTYPE_SCROLL:
retval = ui_do_but_SCROLL(C, block, but, data, event);
@@ -9502,7 +9435,7 @@ static int ui_list_activate_hovered_row(bContext *C,
}
/* Simulate click on listrow button itself (which may be overlapped by another button). Also
- * calls the custom activate operator (ui_list->custom_activate_opname). */
+ * calls the custom activate operator (#uiListDyn::custom_activate_optype). */
UI_but_execute(C, region, listrow);
((uiList *)ui_list)->dyn_data->custom_activate_optype = custom_activate_optype;
@@ -9528,7 +9461,7 @@ static bool ui_list_is_hovering_draggable_but(bContext *C,
}
}
- return (hovered_but && hovered_but->dragpoin);
+ return (hovered_but && ui_but_drag_is_draggable(hovered_but));
}
static int ui_list_handle_click_drag(bContext *C,
@@ -9573,13 +9506,13 @@ static void ui_list_activate_row_from_index(
uiBut *new_active_row = ui_list_row_find_from_index(region, index, listbox);
if (new_active_row) {
/* Preferred way to update the active item, also calls the custom activate operator
- * (#uiList.custom_activate_opname). */
+ * (#uiListDyn::custom_activate_optype). */
UI_but_execute(C, region, new_active_row);
}
else {
/* A bit ugly, set the active index in RNA directly. That's because a button that's
* scrolled away in the list box isn't created at all.
- * The custom activate operator (#uiList.custom_activate_opname) is not called in this case
+ * The custom activate operator (#uiListDyn::custom_activate_optype) is not called in this case
* (which may need the row button context). */
RNA_property_int_set(&listbox->rnapoin, listbox->rnaprop, index);
RNA_property_update(C, &listbox->rnapoin, listbox->rnaprop);
@@ -9748,7 +9681,7 @@ static int ui_handle_view_items_hover(const wmEvent *event, const ARegion *regio
}
LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- if (ui_but_is_view_item(but)) {
+ if (but->type == UI_BTYPE_VIEW_ITEM) {
but->flag &= ~UI_ACTIVE;
has_view_item = true;
}
@@ -9775,7 +9708,7 @@ static int ui_handle_view_item_event(bContext *C,
ARegion *region,
uiBut *view_but)
{
- BLI_assert(ui_but_is_view_item(view_but));
+ BLI_assert(view_but->type == UI_BTYPE_VIEW_ITEM);
if (event->type == LEFTMOUSE) {
/* Will free active button if there already is one. */
ui_handle_button_activate(C, region, view_but, BUTTON_ACTIVATE_OVER);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 332b9b44b0a..c19e842aad8 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -546,6 +546,7 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_MASK, mask);
INIT_BRUSH_ICON(ICON_BRUSH_MIX, mix);
INIT_BRUSH_ICON(ICON_BRUSH_NUDGE, nudge);
+ INIT_BRUSH_ICON(ICON_BRUSH_PAINT_SELECT, paint_select);
INIT_BRUSH_ICON(ICON_BRUSH_PINCH, pinch);
INIT_BRUSH_ICON(ICON_BRUSH_SCRAPE, scrape);
INIT_BRUSH_ICON(ICON_BRUSH_SMEAR, smear);
@@ -584,6 +585,19 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard);
INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke);
+ /* Curves sculpt. */
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_ADD, curves_sculpt_add);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_COMB, curves_sculpt_comb);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_CUT, curves_sculpt_cut);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DELETE, curves_sculpt_delete);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_DENSITY, curves_sculpt_density);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_GROW_SHRINK, curves_sculpt_grow_shrink);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PINCH, curves_sculpt_pinch);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_PUFF, curves_sculpt_puff);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SLIDE, curves_sculpt_slide);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SMOOTH, curves_sculpt_smooth);
+ INIT_BRUSH_ICON(ICON_BRUSH_CURVES_SNAKE_HOOK, curves_sculpt_snake_hook);
+
# undef INIT_BRUSH_ICON
}
@@ -2034,6 +2048,9 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
paint_mode = PAINT_MODE_TEXTURE_3D;
}
+ else if (ob->mode & OB_MODE_SCULPT_CURVES) {
+ paint_mode = PAINT_MODE_SCULPT_CURVES;
+ }
}
else if (space_type == SPACE_IMAGE) {
if (area->spacetype == space_type) {
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index 00c1bcb5f6e..6ad5fe805ab 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -145,10 +145,10 @@ void icon_draw_rect_input(float x,
SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY));
icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f);
}
- else if (event_type == EVT_LEFTSHIFTKEY) {
+ else if (event_type == EVT_LEFTSHIFTKEY) { /* Right Shift has already been converted to left. */
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0});
}
- else if (event_type == EVT_LEFTCTRLKEY) {
+ else if (event_type == EVT_LEFTCTRLKEY) { /* Right Shift has already been converted to left. */
if (platform == MACOS) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0});
}
@@ -156,7 +156,7 @@ void icon_draw_rect_input(float x,
icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f);
}
}
- else if (event_type == EVT_LEFTALTKEY) {
+ else if (event_type == EVT_LEFTALTKEY) { /* Right Alt has already been converted to left. */
if (platform == MACOS) {
icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0});
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 4221959a430..03b9d03a6e3 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -343,20 +343,12 @@ typedef struct uiButProgressbar {
float progress;
} uiButProgressbar;
-/** Derived struct for #UI_BTYPE_TREEROW. */
-typedef struct uiButTreeRow {
+typedef struct uiButViewItem {
uiBut but;
- uiTreeViewItemHandle *tree_item;
- int indentation;
-} uiButTreeRow;
-
-/** Derived struct for #UI_BTYPE_GRID_TILE. */
-typedef struct uiButGridTile {
- uiBut but;
-
- uiGridViewItemHandle *view_item;
-} uiButGridTile;
+ /* C-Handle to the view item this button was created for. */
+ uiViewItemHandle *view_item;
+} uiButViewItem;
/** Derived struct for #UI_BTYPE_HSVCUBE. */
typedef struct uiButHSVCube {
@@ -1328,6 +1320,12 @@ 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_drag.cc */
+
+void ui_but_drag_free(uiBut *but);
+bool ui_but_drag_is_draggable(const uiBut *but);
+void ui_but_drag_start(struct bContext *C, uiBut *but);
+
/* interface_align.c */
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -1366,7 +1364,6 @@ void ui_but_anim_decorate_update_from_flag(uiButDecorator *but);
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_view_item(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
/**
* Can we mouse over the button or is it hidden/disabled/layout.
* \note ctrl is kind of a hack currently,
@@ -1400,9 +1397,7 @@ uiBut *ui_list_row_find_from_index(const struct ARegion *region,
uiBut *listbox) ATTR_WARN_UNUSED_RESULT;
uiBut *ui_view_item_find_mouse_over(const struct ARegion *region, const int xy[2])
ATTR_NONNULL(1, 2);
-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);
+uiBut *ui_view_item_find_active(const struct ARegion *region);
typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata);
/**
@@ -1537,12 +1532,11 @@ void ui_interface_tag_script_reload_queries(void);
/* interface_view.cc */
void ui_block_free_views(struct uiBlock *block);
-uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(const uiBlock *new_block,
- const uiTreeViewHandle *new_view);
-uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block(
- const uiBlock *new_block, const uiGridViewHandle *new_view_handle);
-uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block,
- const uiTreeViewItemHandle *new_item_handle);
+uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
+ const uiViewHandle *new_view);
+
+uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block(
+ const uiBlock *new_block, const uiViewItemHandle *new_item_handle);
/* interface_templates.c */
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index c066ced21cb..ddd805f6010 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1167,7 +1167,9 @@ static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
/* identifiers */
ot->name = "Copy to Selected";
ot->idname = "UI_OT_copy_to_selected_button";
- ot->description = "Copy property from this object to selected objects or bones";
+ ot->description =
+ "Copy the property's value from the active item to the same property of all selected items "
+ "if the same property exists";
/* callbacks */
ot->poll = copy_to_selected_button_poll;
@@ -1940,6 +1942,24 @@ static void UI_OT_drop_color(wmOperatorType *ot)
/** \name Drop Name Operator
* \{ */
+static bool drop_name_poll(bContext *C)
+{
+ if (!ED_operator_regionactive(C)) {
+ return false;
+ }
+
+ const uiBut *but = UI_but_active_drop_name_button(C);
+ if (!but) {
+ return false;
+ }
+
+ if (but->flag & UI_BUT_DISABLED) {
+ return false;
+ }
+
+ return true;
+}
+
static int drop_name_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
uiBut *but = UI_but_active_drop_name_button(C);
@@ -1959,7 +1979,7 @@ static void UI_OT_drop_name(wmOperatorType *ot)
ot->idname = "UI_OT_drop_name";
ot->description = "Drop name to button";
- ot->poll = ED_operator_regionactive;
+ ot->poll = drop_name_poll;
ot->invoke = drop_name_invoke;
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
@@ -2034,40 +2054,39 @@ static void UI_OT_list_start_filter(wmOperatorType *ot)
/** \name UI Tree-View Drop Operator
* \{ */
-static bool ui_tree_view_drop_poll(bContext *C)
+static bool ui_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);
+ const uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, win->eventstate->xy);
- return hovered_tree_item != NULL;
+ return hovered_item != NULL;
}
-static int ui_tree_view_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+static int ui_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);
+ uiViewItemHandle *hovered_item = UI_region_views_find_item_at(region, event->xy);
- if (!UI_tree_view_item_drop_handle(C, hovered_tree_item, event->customdata)) {
+ if (!UI_view_item_drop_handle(C, hovered_item, event->customdata)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
return OPERATOR_FINISHED;
}
-static void UI_OT_tree_view_drop(wmOperatorType *ot)
+static void UI_OT_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->name = "View drop";
+ ot->idname = "UI_OT_view_drop";
+ ot->description = "Drag and drop items onto a data-set item";
- ot->invoke = ui_tree_view_drop_invoke;
- ot->poll = ui_tree_view_drop_poll;
+ ot->invoke = ui_view_drop_invoke;
+ ot->poll = ui_view_drop_poll;
ot->flag = OPTYPE_INTERNAL;
}
@@ -2075,43 +2094,42 @@ static void UI_OT_tree_view_drop(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name UI Tree-View Item Rename Operator
+/** \name UI 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 their own renaming
- * operators with the same logic as they already have for their #ui::AbstractTreeViewItem::rename()
- * override.
+ * General purpose renaming operator for views. Thanks to this, to add a rename button to context
+ * menus for example, view API users don't have to implement their own renaming operators with the
+ * same logic as they already have for their #ui::AbstractViewItem::rename() override.
*
* \{ */
-static bool ui_tree_view_item_rename_poll(bContext *C)
+static bool ui_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);
+ const uiViewItemHandle *active_item = UI_region_views_find_active_item(region);
+ return active_item != NULL && UI_view_item_can_rename(active_item);
}
-static int ui_tree_view_item_rename_exec(bContext *C, wmOperator *UNUSED(op))
+static int ui_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);
+ uiViewItemHandle *active_item = UI_region_views_find_active_item(region);
- UI_tree_view_item_begin_rename(active_item);
+ UI_view_item_begin_rename(active_item);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
}
-static void UI_OT_tree_view_item_rename(wmOperatorType *ot)
+static void UI_OT_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->name = "Rename View Item";
+ ot->idname = "UI_OT_view_item_rename";
+ ot->description = "Rename the active item in the data-set view";
- ot->exec = ui_tree_view_item_rename_exec;
- ot->poll = ui_tree_view_item_rename_poll;
+ ot->exec = ui_view_item_rename_exec;
+ ot->poll = ui_view_item_rename_poll;
/* Could get a custom tooltip via the `get_description()` callback and another overridable
- * function of the tree-view. */
+ * function of the view. */
ot->flag = OPTYPE_INTERNAL;
}
@@ -2215,8 +2233,8 @@ 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);
+ WM_operatortype_append(UI_OT_view_drop);
+ WM_operatortype_append(UI_OT_view_item_rename);
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
diff --git a/source/blender/editors/interface/interface_query.cc b/source/blender/editors/interface/interface_query.cc
index 2bcb419cfba..f084f3e06cb 100644
--- a/source/blender/editors/interface/interface_query.cc
+++ b/source/blender/editors/interface/interface_query.cc
@@ -54,13 +54,7 @@ bool ui_but_is_toggle(const uiBut *but)
UI_BTYPE_TOGGLE_N,
UI_BTYPE_CHECKBOX,
UI_BTYPE_CHECKBOX_N,
- UI_BTYPE_ROW,
- UI_BTYPE_TREEROW);
-}
-
-bool ui_but_is_view_item(const uiBut *but)
-{
- return ELEM(but->type, UI_BTYPE_TREEROW, UI_BTYPE_GRID_TILE);
+ UI_BTYPE_ROW);
}
bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool for_tooltip)
@@ -69,12 +63,12 @@ bool ui_but_is_interactive_ex(const uiBut *but, const bool labeledit, const bool
if (but->type == UI_BTYPE_LABEL) {
if (for_tooltip) {
/* It's important labels are considered interactive for the purpose of showing tooltip. */
- if (but->dragpoin == nullptr && but->tip_func == nullptr) {
+ if (!ui_but_drag_is_draggable(but) && but->tip_func == nullptr) {
return false;
}
}
else {
- if (but->dragpoin == nullptr) {
+ if (!ui_but_drag_is_draggable(but)) {
return false;
}
}
@@ -462,14 +456,9 @@ 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;
-}
-
static bool ui_but_is_view_item_fn(const uiBut *but, const void *UNUSED(customdata))
{
- return ui_but_is_view_item(but);
+ return but->type == UI_BTYPE_VIEW_ITEM;
}
uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2])
@@ -477,24 +466,19 @@ uiBut *ui_view_item_find_mouse_over(const ARegion *region, const int xy[2])
return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_view_item_fn, nullptr);
}
-uiBut *ui_tree_row_find_mouse_over(const ARegion *region, const int xy[2])
-{
- return ui_but_find_mouse_over_ex(region, xy, false, false, ui_but_is_treerow, nullptr);
-}
-
-static bool ui_but_is_active_treerow(const uiBut *but, const void *customdata)
+static bool ui_but_is_active_view_item(const uiBut *but, const void *UNUSED(customdata))
{
- if (!ui_but_is_treerow(but, customdata)) {
+ if (but->type != UI_BTYPE_VIEW_ITEM) {
return false;
}
- const uiButTreeRow *treerow_but = (const uiButTreeRow *)but;
- return UI_tree_view_item_is_active(treerow_but->tree_item);
+ const uiButViewItem *view_item_but = (const uiButViewItem *)but;
+ return UI_view_item_is_active(view_item_but->view_item);
}
-uiBut *ui_tree_row_find_active(const ARegion *region)
+uiBut *ui_view_item_find_active(const ARegion *region)
{
- return ui_but_find(region, ui_but_is_active_treerow, nullptr);
+ return ui_but_find(region, ui_but_is_active_view_item, nullptr);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_region_hud.cc b/source/blender/editors/interface/interface_region_hud.cc
index d6166694a4a..aca36686dea 100644
--- a/source/blender/editors/interface/interface_region_hud.cc
+++ b/source/blender/editors/interface/interface_region_hud.cc
@@ -143,6 +143,11 @@ static void hud_panels_register(ARegionType *art, int space_type, int region_typ
static void hud_region_init(wmWindowManager *wm, ARegion *region)
{
ED_region_panels_init(wm, region);
+
+ /* Reset zoom from panels init because we don't want zoom allowed for redo panel. */
+ region->v2d.maxzoom = 1.0f;
+ region->v2d.minzoom = 1.0f;
+
UI_region_handlers_add(&region->handlers);
region->flag |= RGN_FLAG_TEMP_REGIONDATA;
}
@@ -251,7 +256,7 @@ static ARegion *hud_region_add(ScrArea *area)
if (region_win) {
float x, y;
- UI_view2d_scroller_size_get(&region_win->v2d, &x, &y);
+ UI_view2d_scroller_size_get(&region_win->v2d, true, &x, &y);
region->runtime.offset_x = x;
region->runtime.offset_y = y;
}
diff --git a/source/blender/editors/interface/interface_region_menu_pie.cc b/source/blender/editors/interface/interface_region_menu_pie.cc
index b11564f09c5..09902dd6c35 100644
--- a/source/blender/editors/interface/interface_region_menu_pie.cc
+++ b/source/blender/editors/interface/interface_region_menu_pie.cc
@@ -371,7 +371,7 @@ void ui_pie_menu_level_create(uiBlock *block,
EnumPropertyItem *remaining = static_cast<EnumPropertyItem *>(
MEM_mallocN(array_size + sizeof(EnumPropertyItem), "pie_level_item_array"));
memcpy(remaining, items + totitem_parent, array_size);
- /* A nullptr terminating sentinel element is required. */
+ /* A null terminating sentinel element is required. */
memset(&remaining[totitem_remain], 0, sizeof(EnumPropertyItem));
/* yuk, static... issue is we can't reliably free this without doing dangerous changes */
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index 64de31dfe6a..81c0c29d09a 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -451,15 +451,16 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
/* reset vars */
data->items.totitem = 0;
data->items.more = 0;
- if (reset == false) {
+ if (!reset) {
data->items.offset_i = data->items.offset;
}
else {
data->items.offset_i = data->items.offset = 0;
data->active = -1;
- /* handle active */
- if (search_but->items_update_fn && search_but->item_active) {
+ /* On init, find and center active item. */
+ const bool is_first_search = !search_but->but.changed;
+ if (is_first_search && 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 = nullptr;
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index c7ebecb178b..88fe866f717 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -800,7 +800,7 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
.style = UI_TIP_STYLE_HEADER,
.color_id = UI_TIP_LC_NORMAL,
});
- field->text = BLI_sprintfN("%s", but_label.strinfo);
+ field->text = BLI_strdup(but_label.strinfo);
}
/* Tip */
@@ -1005,7 +1005,7 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C,
/* this could get its own 'BUT_GET_...' type */
/* never fails */
- /* move ownership (no need for re-alloc) */
+ /* Move ownership (no need for re-allocation). */
if (rnaprop) {
field->text = RNA_path_full_property_py_ex(
CTX_data_main(C), &but->rnapoin, rnaprop, but->rnaindex, true);
diff --git a/source/blender/editors/interface/interface_style.cc b/source/blender/editors/interface/interface_style.cc
index 291ede05730..904765f6dc4 100644
--- a/source/blender/editors/interface/interface_style.cc
+++ b/source/blender/editors/interface/interface_style.cc
@@ -382,19 +382,8 @@ void uiStyleInit(void)
}
CLAMP(U.dpi, 48, 144);
- LISTBASE_FOREACH (uiFont *, font, &U.uifonts) {
- BLF_unload_id(font->blf_id);
- }
-
- if (blf_mono_font != -1) {
- BLF_unload_id(blf_mono_font);
- blf_mono_font = -1;
- }
-
- if (blf_mono_font_render != -1) {
- BLF_unload_id(blf_mono_font_render);
- blf_mono_font_render = -1;
- }
+ /* Needed so that custom fonts are always first. */
+ BLF_unload_all();
uiFont *font_first = static_cast<uiFont *>(U.uifonts.first);
@@ -498,6 +487,9 @@ void uiStyleInit(void)
const bool unique = true;
blf_mono_font_render = BLF_load_mono_default(unique);
}
+
+ /* Load the fallback fonts last. */
+ BLF_load_font_stack();
}
void UI_fontstyle_set(const uiFontStyle *fs)
diff --git a/source/blender/editors/interface/interface_template_attribute_search.cc b/source/blender/editors/interface/interface_template_attribute_search.cc
index dc8f568d025..0a684903f0f 100644
--- a/source/blender/editors/interface/interface_template_attribute_search.cc
+++ b/source/blender/editors/interface/interface_template_attribute_search.cc
@@ -24,14 +24,14 @@ using blender::nodes::geometry_nodes_eval_log::GeometryAttributeInfo;
namespace blender::ui {
-static StringRef attribute_data_type_string(const CustomDataType type)
+static StringRef attribute_data_type_string(const eCustomDataType 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)
+static StringRef attribute_domain_string(const eAttrDomain domain)
{
const char *name = nullptr;
RNA_enum_name_from_value(rna_enum_attribute_domain_items, domain, &name);
@@ -50,7 +50,7 @@ static bool attribute_search_item_add(uiSearchItems *items, const GeometryAttrib
}
void attribute_search_add_items(StringRefNull str,
- const bool is_output,
+ const bool can_create_attribute,
Span<const GeometryAttributeInfo *> infos,
uiSearchItems *seach_items,
const bool is_first)
@@ -68,8 +68,12 @@ void attribute_search_add_items(StringRefNull str,
}
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);
+ UI_search_item_add(seach_items,
+ str.c_str(),
+ &dummy_info,
+ can_create_attribute ? ICON_ADD : ICON_NONE,
+ 0,
+ 0);
}
}
@@ -91,6 +95,9 @@ void attribute_search_add_items(StringRefNull str,
if (item->name == "normal" && item->domain == ATTR_DOMAIN_FACE) {
continue;
}
+ if (!bke::allow_procedural_attribute_access(item->name)) {
+ continue;
+ }
BLI_string_search_add(search, item->name.c_str(), (void *)item, 0);
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index a02e8a3ac49..14da5a7cd62 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -741,8 +741,15 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
if (object_active != NULL) {
object_active->id.tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false);
+ BKE_lib_override_library_create(bmain,
+ scene,
+ view_layer,
+ NULL,
+ id,
+ &collection_active->id,
+ NULL,
+ &id_override,
+ U.experimental.use_override_new_fully_editable);
}
else if (object_active != NULL && !ID_IS_LINKED(object_active) &&
&object_active->instance_collection->id == id) {
@@ -755,7 +762,7 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
&object_active->id,
&object_active->id,
&id_override,
- false);
+ U.experimental.use_override_new_fully_editable);
}
break;
case ID_OB:
@@ -765,8 +772,15 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
if (object_active != NULL) {
object_active->id.tag |= LIB_TAG_DOIT;
}
- BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &collection_active->id, NULL, &id_override, false);
+ BKE_lib_override_library_create(bmain,
+ scene,
+ view_layer,
+ NULL,
+ id,
+ &collection_active->id,
+ NULL,
+ &id_override,
+ U.experimental.use_override_new_fully_editable);
}
break;
case ID_ME:
@@ -796,12 +810,19 @@ static void template_id_liboverride_hierarchy_create(bContext *C,
&collection_active->id,
NULL,
&id_override,
- false);
+ U.experimental.use_override_new_fully_editable);
}
else {
object_active->id.tag |= LIB_TAG_DOIT;
- BKE_lib_override_library_create(
- bmain, scene, view_layer, NULL, id, &object_active->id, NULL, &id_override, false);
+ BKE_lib_override_library_create(bmain,
+ scene,
+ view_layer,
+ NULL,
+ id,
+ &object_active->id,
+ NULL,
+ &id_override,
+ U.experimental.use_override_new_fully_editable);
}
}
break;
@@ -1024,6 +1045,26 @@ static const char *template_id_browse_tip(const StructRNA *type)
}
/**
+ * Add a superimposed extra icon to \a but, for workspace pinning.
+ * Rather ugly special handling, but this is really a special case at this point, nothing worth
+ * generalizing.
+ */
+static void template_id_workspace_pin_extra_icon(const TemplateID *template_ui, uiBut *but)
+{
+ if ((template_ui->idcode != ID_SCE) || (template_ui->ptr.type != &RNA_Window)) {
+ return;
+ }
+
+ const wmWindow *win = template_ui->ptr.data;
+ const WorkSpace *workspace = WM_window_get_active_workspace(win);
+ UI_but_extra_operator_icon_add(but,
+ "WORKSPACE_OT_scene_pin_toggle",
+ WM_OP_INVOKE_DEFAULT,
+ (workspace->flags & WORKSPACE_USE_PIN_SCENE) ? ICON_PINNED :
+ ICON_UNPINNED);
+}
+
+/**
* \return a type-based i18n context, needed e.g. by "New" button.
* In most languages, this adjective takes different form based on gender of type name...
*/
@@ -1220,6 +1261,8 @@ static void template_ID(const bContext *C,
UI_but_flag_enable(but, UI_BUT_REDALERT);
}
+ template_id_workspace_pin_extra_icon(template_ui, but);
+
if (ID_IS_LINKED(id)) {
const bool disabled = !BKE_idtype_idcode_is_localizable(GS(id->name));
if (id->tag & LIB_TAG_INDIRECT) {
@@ -1536,8 +1579,8 @@ static void template_ID_tabs(const bContext *C,
0.0f,
"");
UI_but_funcN_set(&tab->but, template_ID_set_property_exec_fn, MEM_dupallocN(template), id);
+ UI_but_drag_set_id(&tab->but, id);
tab->but.custom_data = (void *)id;
- tab->but.dragpoin = id;
tab->menu = mt;
UI_but_drawflag_enable(&tab->but, but_align);
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
deleted file mode 100644
index 699ac0c2b53..00000000000
--- a/source/blender/editors/interface/interface_view.cc
+++ /dev/null
@@ -1,229 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup edinterface
- *
- * This part of the UI-View API is mostly needed to support persistent state of items within the
- * view. Views are stored in #uiBlock's, and kept alive with it until after the next redraw. So we
- * can compare the old view items with the new view items and keep state persistent for matching
- * ones.
- */
-
-#include <memory>
-#include <type_traits>
-#include <variant>
-
-#include "DNA_screen_types.h"
-
-#include "BKE_screen.h"
-
-#include "BLI_listbase.h"
-
-#include "ED_screen.h"
-
-#include "interface_intern.h"
-
-#include "UI_interface.hh"
-
-#include "UI_grid_view.hh"
-#include "UI_tree_view.hh"
-
-using namespace blender;
-using namespace blender::ui;
-
-/**
- * Wrapper to store views in a #ListBase. There's no `uiView` base class, we just store views as a
- * #std::variant.
- */
-struct ViewLink : public Link {
- using TreeViewPtr = std::unique_ptr<AbstractTreeView>;
- using GridViewPtr = std::unique_ptr<AbstractGridView>;
-
- std::string idname;
- /* NOTE: Can't use std::get() on this until minimum macOS deployment target is 10.14. */
- std::variant<TreeViewPtr, GridViewPtr> view;
-};
-
-template<class T> constexpr void check_if_valid_view_type()
-{
- static_assert(std::is_same_v<T, AbstractTreeView> || std::is_same_v<T, AbstractGridView>,
- "Unsupported view type");
-}
-
-template<class T> T *get_view_from_link(ViewLink &link)
-{
- auto *t_uptr = std::get_if<std::unique_ptr<T>>(&link.view);
- return t_uptr ? t_uptr->get() : nullptr;
-}
-
-template<class T>
-static T *ui_block_add_view_impl(uiBlock &block, StringRef idname, std::unique_ptr<T> view)
-{
- check_if_valid_view_type<T>();
-
- ViewLink *view_link = MEM_new<ViewLink>(__func__);
- BLI_addtail(&block.views, view_link);
-
- view_link->view = std::move(view);
- view_link->idname = idname;
-
- return get_view_from_link<T>(*view_link);
-}
-
-AbstractGridView *UI_block_add_view(uiBlock &block,
- StringRef idname,
- std::unique_ptr<AbstractGridView> tree_view)
-{
- return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(tree_view));
-}
-
-AbstractTreeView *UI_block_add_view(uiBlock &block,
- StringRef idname,
- std::unique_ptr<AbstractTreeView> tree_view)
-{
- return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view));
-}
-
-void ui_block_free_views(uiBlock *block)
-{
- LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
- MEM_delete(link);
- }
-}
-
-void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
-{
- ARegion *region = listener_params->region;
-
- LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
- if (AbstractGridView *grid_view = get_view_from_link<AbstractGridView>(*view_link)) {
- if (UI_grid_view_listen_should_redraw(reinterpret_cast<uiGridViewHandle *>(grid_view),
- listener_params->notifier)) {
- ED_region_tag_redraw(region);
- }
- }
- else if (AbstractTreeView *tree_view = get_view_from_link<AbstractTreeView>(*view_link)) {
- if (UI_tree_view_listen_should_redraw(reinterpret_cast<uiTreeViewHandle *>(tree_view),
- listener_params->notifier)) {
- ED_region_tag_redraw(region);
- }
- }
- }
-}
-
-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;
-}
-
-template<class T> static StringRef ui_block_view_find_idname(const uiBlock &block, const T &view)
-{
- check_if_valid_view_type<T>();
-
- /* First get the idname the of the view we're looking for. */
- LISTBASE_FOREACH (ViewLink *, view_link, &block.views) {
- if (get_view_from_link<T>(*view_link) == &view) {
- return view_link->idname;
- }
- }
-
- return {};
-}
-
-template<class T>
-static T *ui_block_view_find_matching_in_old_block(const uiBlock &new_block, const T &new_view)
-{
- check_if_valid_view_type<T>();
-
- 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<T>(*old_view_link);
- }
- }
-
- return nullptr;
-}
-
-uiTreeViewHandle *ui_block_tree_view_find_matching_in_old_block(
- const uiBlock *new_block, const uiTreeViewHandle *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);
-}
-
-uiGridViewHandle *ui_block_grid_view_find_matching_in_old_block(
- const uiBlock *new_block, const uiGridViewHandle *new_view_handle)
-{
- BLI_assert(new_block && new_view_handle);
- const AbstractGridView &new_view = reinterpret_cast<const AbstractGridView &>(*new_view_handle);
-
- AbstractGridView *old_view = ui_block_view_find_matching_in_old_block(*new_block, new_view);
- return reinterpret_cast<uiGridViewHandle *>(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;
- }
-
- 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 (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;
- }
- }
-
- return nullptr;
-}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 110f8146c7f..c939ba461c9 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -104,8 +104,7 @@ typedef enum {
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
- UI_WTYPE_TREEROW,
- UI_WTYPE_GRID_TILE,
+ UI_WTYPE_VIEW_ITEM,
} uiWidgetTypeEnum;
/**
@@ -1420,7 +1419,7 @@ static void widget_draw_icon(
const bool has_theme = UI_icon_get_theme_color(icon, color);
/* to indicate draggable */
- if (but->dragpoin && (but->flag & UI_ACTIVE)) {
+ if (ui_but_drag_is_draggable(but) && (but->flag & UI_ACTIVE)) {
UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme);
}
else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW))) {
@@ -3672,12 +3671,11 @@ static void widget_progressbar(uiBut *but,
widgetbase_draw(&wtb_bar, wcol);
}
-static void widget_treerow_exec(uiWidgetColors *wcol,
- rcti *rect,
- const uiWidgetStateInfo *state,
- int UNUSED(roundboxalign),
- int indentation,
- const float zoom)
+static void widget_view_item(uiWidgetColors *wcol,
+ rcti *rect,
+ const uiWidgetStateInfo *state,
+ int UNUSED(roundboxalign),
+ const float zoom)
{
uiWidgetBase wtb;
widget_init(&wtb);
@@ -3690,28 +3688,6 @@ static void widget_treerow_exec(uiWidgetColors *wcol,
if ((state->but_flag & UI_ACTIVE) || (state->but_flag & UI_SELECT)) {
widgetbase_draw(&wtb, wcol);
}
-
- BLI_rcti_resize(rect, BLI_rcti_size_x(rect) - UI_UNIT_X * indentation, BLI_rcti_size_y(rect));
- BLI_rcti_translate(rect, 0.5f * UI_UNIT_X * indentation, 0);
-}
-
-static void widget_treerow(uiBut *but,
- uiWidgetColors *wcol,
- rcti *rect,
- const uiWidgetStateInfo *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, zoom);
-}
-
-static void widget_gridtile(
- uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, const float zoom)
-{
- /* TODO Reuse tree-row drawing. */
- widget_treerow_exec(wcol, rect, state, roundboxalign, 0, zoom);
}
static void widget_nodesocket(uiBut *but,
@@ -4605,14 +4581,9 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.custom = widget_progressbar;
break;
- case UI_WTYPE_TREEROW:
+ case UI_WTYPE_VIEW_ITEM:
wt.wcol_theme = &btheme->tui.wcol_view_item;
- wt.custom = widget_treerow;
- break;
-
- case UI_WTYPE_GRID_TILE:
- wt.wcol_theme = &btheme->tui.wcol_view_item;
- wt.draw = widget_gridtile;
+ wt.draw = widget_view_item;
break;
case UI_WTYPE_NODESOCKET:
@@ -4946,13 +4917,8 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
fstyle = &style->widgetlabel;
break;
- case UI_BTYPE_TREEROW:
- wt = widget_type(UI_WTYPE_TREEROW);
- fstyle = &style->widgetlabel;
- break;
-
- case UI_BTYPE_GRID_TILE:
- wt = widget_type(UI_WTYPE_GRID_TILE);
+ case UI_BTYPE_VIEW_ITEM:
+ wt = widget_type(UI_WTYPE_VIEW_ITEM);
fstyle = &style->widgetlabel;
break;
diff --git a/source/blender/editors/interface/view2d.cc b/source/blender/editors/interface/view2d.cc
index 6ece7eb4ffa..1bf7e25b154 100644
--- a/source/blender/editors/interface/view2d.cc
+++ b/source/blender/editors/interface/view2d.cc
@@ -149,7 +149,9 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
}
}
- scroll = view2d_scroll_mapped(v2d->scroll);
+ /* Do not use mapped scroll here because we want to update scroller rects
+ * even if they are not displayed. For init purposes. See T75003.*/
+ scroll = v2d->scroll;
/* Scrollers are based off region-size:
* - they can only be on one to two edges of the region they define
@@ -158,7 +160,7 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
if (scroll) {
float scroll_width, scroll_height;
- UI_view2d_scroller_size_get(v2d, &scroll_width, &scroll_height);
+ UI_view2d_scroller_size_get(v2d, false, &scroll_width, &scroll_height);
/* vertical scroller */
if (scroll & V2D_SCROLL_LEFT) {
@@ -191,18 +193,6 @@ static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
v2d->hor = *mask_scroll;
v2d->hor.ymin = v2d->hor.ymax - scroll_height;
}
-
- /* adjust vertical scroller if there's a horizontal scroller, to leave corner free */
- if (scroll & V2D_SCROLL_VERTICAL) {
- if (scroll & V2D_SCROLL_BOTTOM) {
- /* on bottom edge of region */
- v2d->vert.ymin = v2d->hor.ymax;
- }
- else if (scroll & V2D_SCROLL_TOP) {
- /* on upper edge of region */
- v2d->vert.ymax = v2d->hor.ymin;
- }
- }
}
}
@@ -260,6 +250,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
/* tot rect has strictly regulated placement, and must only occur in +/- quadrant */
v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y);
v2d->keeptot = V2D_KEEPTOT_STRICT;
+ v2d->keepofs = (V2D_KEEPOFS_X | V2D_KEEPOFS_Y);
tot_changed = do_init;
/* scroller settings are currently not set here... that is left for regions... */
@@ -276,6 +267,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
/* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */
v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
v2d->keeptot = V2D_KEEPTOT_STRICT;
+ v2d->keepofs = (V2D_KEEPOFS_X | V2D_KEEPOFS_Y);
tot_changed = do_init;
/* scroller settings are currently not set here... that is left for regions... */
@@ -493,8 +485,8 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize)
}
/* check if we should restore aspect ratio (if view size changed) */
- if (v2d->keepzoom & V2D_KEEPASPECT) {
- bool do_x = false, do_y = false, do_cur /* , do_win */ /* UNUSED */;
+ if (v2d->keepzoom & V2D_KEEPASPECT && !(v2d->keeptot == V2D_KEEPTOT_STRICT)) {
+ bool do_x = false, do_y = false, do_cur;
float curRatio, winRatio;
/* when a window edge changes, the aspect ratio can't be used to
@@ -532,53 +524,12 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize)
/* do_win = do_y; */ /* UNUSED */
if (do_cur) {
- if ((v2d->keeptot == V2D_KEEPTOT_STRICT) && (winx != v2d->oldwinx)) {
- /* Special exception for Outliner (and later channel-lists):
- * - The view may be moved left to avoid contents
- * being pushed out of view when view shrinks.
- * - The keeptot code will make sure cur->xmin will not be less than tot->xmin
- * (which cannot be allowed).
- * - width is not adjusted for changed ratios here.
- */
- if (winx < v2d->oldwinx) {
- const float temp = v2d->oldwinx - winx;
-
- cur->xmin -= temp;
- cur->xmax -= temp;
-
- /* width does not get modified, as keepaspect here is just set to make
- * sure visible area adjusts to changing view shape!
- */
- }
- }
- else {
- /* portrait window: correct for x */
- width = height / winRatio;
- }
+ /* portrait window: correct for x */
+ width = height / winRatio;
}
else {
- if ((v2d->keeptot == V2D_KEEPTOT_STRICT) && (winy != v2d->oldwiny)) {
- /* special exception for Outliner (and later channel-lists):
- * - Currently, no actions need to be taken here...
- */
-
- if (winy < v2d->oldwiny) {
- const float temp = v2d->oldwiny - winy;
-
- if (v2d->align & V2D_ALIGN_NO_NEG_Y) {
- cur->ymin -= temp;
- cur->ymax -= temp;
- }
- else { /* Assume V2D_ALIGN_NO_POS_Y or combination */
- cur->ymin += temp;
- cur->ymax += temp;
- }
- }
- }
- else {
- /* landscape window: correct for y */
- height = width * winRatio;
- }
+ /* landscape window: correct for y */
+ height = width * winRatio;
}
/* store region size for next time */
@@ -1510,7 +1461,7 @@ void UI_view2d_scrollers_calc(View2D *v2d,
}
}
-void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
+void UI_view2d_scrollers_draw_ex(View2D *v2d, const rcti *mask_custom, bool use_full_hide)
{
View2DScrollers scrollers;
UI_view2d_scrollers_calc(v2d, mask_custom, &scrollers);
@@ -1518,6 +1469,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
rcti vert, hor;
const int scroll = view2d_scroll_mapped(v2d->scroll);
const char emboss_alpha = btheme->tui.widget_emboss[3];
+ const float alpha_min = use_full_hide ? 0.0f : V2D_SCROLL_MIN_ALPHA;
+
uchar scrollers_back_color[4];
/* Color for scrollbar backs */
@@ -1530,7 +1483,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
/* horizontal scrollbar */
if (scroll & V2D_SCROLL_HORIZONTAL) {
uiWidgetColors wcol = btheme->tui.wcol_scroll;
- const float alpha_fac = v2d->alpha_hor / 255.0f;
+ /* 0..255 -> min...1 */
+ const float alpha_fac = ((v2d->alpha_hor / 255.0f) * (1.0f - alpha_min)) + alpha_min;
rcti slider;
int state;
@@ -1543,8 +1497,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
wcol.inner[3] *= alpha_fac;
wcol.item[3] *= alpha_fac;
- wcol.outline[3] *= alpha_fac;
- btheme->tui.widget_emboss[3] *= alpha_fac; /* will be reset later */
+ wcol.outline[3] = 0;
+ btheme->tui.widget_emboss[3] = 0; /* will be reset later */
/* show zoom handles if:
* - zooming on x-axis is allowed (no scroll otherwise)
@@ -1565,7 +1519,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
if (scroll & V2D_SCROLL_VERTICAL) {
uiWidgetColors wcol = btheme->tui.wcol_scroll;
rcti slider;
- const float alpha_fac = v2d->alpha_vert / 255.0f;
+ /* 0..255 -> min...1 */
+ const float alpha_fac = ((v2d->alpha_vert / 255.0f) * (1.0f - alpha_min)) + alpha_min;
int state;
slider.xmin = vert.xmin;
@@ -1577,8 +1532,8 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
wcol.inner[3] *= alpha_fac;
wcol.item[3] *= alpha_fac;
- wcol.outline[3] *= alpha_fac;
- btheme->tui.widget_emboss[3] *= alpha_fac; /* will be reset later */
+ wcol.outline[3] = 0;
+ btheme->tui.widget_emboss[3] = 0; /* will be reset later */
/* show zoom handles if:
* - zooming on y-axis is allowed (no scroll otherwise)
@@ -1599,6 +1554,11 @@ void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
btheme->tui.widget_emboss[3] = emboss_alpha;
}
+void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
+{
+ UI_view2d_scrollers_draw_ex(v2d, mask_custom, false);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1735,6 +1695,41 @@ void UI_view2d_view_to_region_fl(
*r_region_y = v2d->mask.ymin + (y * BLI_rcti_size_y(&v2d->mask));
}
+bool UI_view2d_view_to_region_segment_clip(const View2D *v2d,
+ const float xy_a[2],
+ const float xy_b[2],
+ int r_region_a[2],
+ int r_region_b[2])
+{
+ rctf rect_unit;
+ rect_unit.xmin = rect_unit.ymin = 0.0f;
+ rect_unit.xmax = rect_unit.ymax = 1.0f;
+
+ /* Express given coordinates as proportional values. */
+ const float s_a[2] = {
+ (xy_a[0] - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur),
+ (xy_a[1] - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur),
+ };
+ const float s_b[2] = {
+ (xy_b[0] - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur),
+ (xy_b[1] - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur),
+ };
+
+ /* Set initial value in case coordinates lie outside bounds. */
+ r_region_a[0] = r_region_b[0] = r_region_a[1] = r_region_b[1] = V2D_IS_CLIPPED;
+
+ if (BLI_rctf_isect_segment(&rect_unit, s_a, s_b)) {
+ r_region_a[0] = (int)(v2d->mask.xmin + (s_a[0] * BLI_rcti_size_x(&v2d->mask)));
+ r_region_a[1] = (int)(v2d->mask.ymin + (s_a[1] * BLI_rcti_size_y(&v2d->mask)));
+ r_region_b[0] = (int)(v2d->mask.xmin + (s_b[0] * BLI_rcti_size_x(&v2d->mask)));
+ r_region_b[1] = (int)(v2d->mask.ymin + (s_b[1] * BLI_rcti_size_y(&v2d->mask)));
+
+ return true;
+ }
+
+ return false;
+}
+
void UI_view2d_view_to_region_rcti(const View2D *v2d, const rctf *rect_src, rcti *rect_dst)
{
const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)};
@@ -1835,13 +1830,14 @@ View2D *UI_view2d_fromcontext_rwin(const bContext *C)
return &(region->v2d);
}
-void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_scroller_size_get(const View2D *v2d, bool mapped, float *r_x, float *r_y)
{
- const int scroll = view2d_scroll_mapped(v2d->scroll);
+ const int scroll = (mapped) ? view2d_scroll_mapped(v2d->scroll) : v2d->scroll;
if (r_x) {
if (scroll & V2D_SCROLL_VERTICAL) {
*r_x = (scroll & V2D_SCROLL_VERTICAL_HANDLES) ? V2D_SCROLL_HANDLE_WIDTH : V2D_SCROLL_WIDTH;
+ *r_x = ((*r_x - V2D_SCROLL_MIN_WIDTH) * (v2d->alpha_vert / 255.0f)) + V2D_SCROLL_MIN_WIDTH;
}
else {
*r_x = 0;
@@ -1851,6 +1847,7 @@ void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
if (scroll & V2D_SCROLL_HORIZONTAL) {
*r_y = (scroll & V2D_SCROLL_HORIZONTAL_HANDLES) ? V2D_SCROLL_HANDLE_HEIGHT :
V2D_SCROLL_HEIGHT;
+ *r_y = ((*r_y - V2D_SCROLL_MIN_WIDTH) * (v2d->alpha_hor / 255.0f)) + V2D_SCROLL_MIN_WIDTH;
}
else {
*r_y = 0;
diff --git a/source/blender/editors/interface/view2d_ops.cc b/source/blender/editors/interface/view2d_ops.cc
index a4477c5271c..ec15c4ffc9f 100644
--- a/source/blender/editors/interface/view2d_ops.cc
+++ b/source/blender/editors/interface/view2d_ops.cc
@@ -960,8 +960,8 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op)
const double time = PIL_check_seconds_timer();
const float time_step = (float)(time - vzd->timer_lastdraw);
- dx *= time_step * 0.5f;
- dy *= time_step * 0.5f;
+ dx *= time_step * 5.0f;
+ dy *= time_step * 5.0f;
vzd->timer_lastdraw = time;
}
diff --git a/source/blender/editors/interface/views/abstract_view.cc b/source/blender/editors/interface/views/abstract_view.cc
new file mode 100644
index 00000000000..077c76a08f1
--- /dev/null
+++ b/source/blender/editors/interface/views/abstract_view.cc
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "interface_intern.h"
+
+#include "UI_abstract_view.hh"
+
+namespace blender::ui {
+
+void AbstractView::register_item(AbstractViewItem &item)
+{
+ /* Actually modifies the item, not the view. But for the public API it "feels" a bit nicer to
+ * have the view base class register the items, rather than setting the view on the item. */
+ item.view_ = this;
+}
+
+/* ---------------------------------------------------------------------- */
+/** \name View Reconstruction
+ * \{ */
+
+bool AbstractView::is_reconstructed() const
+{
+ return is_reconstructed_;
+}
+
+void AbstractView::update_from_old(uiBlock &new_block)
+{
+ uiBlock *old_block = new_block.oldblock;
+ if (!old_block) {
+ is_reconstructed_ = true;
+ return;
+ }
+
+ uiViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block(
+ &new_block, reinterpret_cast<uiViewHandle *>(this));
+ if (old_view_handle == nullptr) {
+ /* Initial construction, nothing to update. */
+ is_reconstructed_ = true;
+ return;
+ }
+
+ AbstractView &old_view = reinterpret_cast<AbstractView &>(*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(old_view);
+
+ /* Finished (re-)constructing the tree. */
+ is_reconstructed_ = true;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Default implementations of virtual functions
+ * \{ */
+
+bool AbstractView::listen(const wmNotifier & /*notifier*/) const
+{
+ /* Nothing by default. */
+ return false;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Renaming
+ * \{ */
+
+bool AbstractView::is_renaming() const
+{
+ return rename_buffer_ != nullptr;
+}
+
+bool AbstractView::begin_renaming()
+{
+ if (is_renaming()) {
+ return false;
+ }
+
+ rename_buffer_ = std::make_unique<decltype(rename_buffer_)::element_type>();
+ return true;
+}
+
+void AbstractView::end_renaming()
+{
+ BLI_assert(is_renaming());
+ rename_buffer_ = nullptr;
+}
+
+Span<char> AbstractView::get_rename_buffer() const
+{
+ return *rename_buffer_;
+}
+MutableSpan<char> AbstractView::get_rename_buffer()
+{
+ return *rename_buffer_;
+}
+
+/** \} */
+
+} // namespace blender::ui
diff --git a/source/blender/editors/interface/views/abstract_view_item.cc b/source/blender/editors/interface/views/abstract_view_item.cc
new file mode 100644
index 00000000000..f73183d07e9
--- /dev/null
+++ b/source/blender/editors/interface/views/abstract_view_item.cc
@@ -0,0 +1,373 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ */
+
+#include "BKE_context.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "WM_api.h"
+
+#include "UI_interface.h"
+#include "interface_intern.h"
+
+#include "UI_abstract_view.hh"
+
+namespace blender::ui {
+
+/* ---------------------------------------------------------------------- */
+/** \name View Reconstruction
+ * \{ */
+
+void AbstractViewItem::update_from_old(const AbstractViewItem &old)
+{
+ is_active_ = old.is_active_;
+ is_renaming_ = old.is_renaming_;
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Renaming
+ * \{ */
+
+bool AbstractViewItem::supports_renaming() const
+{
+ /* No renaming by default. */
+ return false;
+}
+bool AbstractViewItem::rename(StringRefNull /*new_name*/)
+{
+ /* No renaming by default. */
+ return false;
+}
+
+StringRef AbstractViewItem::get_rename_string() const
+{
+ /* No rename string by default. */
+ return {};
+}
+
+bool AbstractViewItem::is_renaming() const
+{
+ return is_renaming_;
+}
+
+void AbstractViewItem::begin_renaming()
+{
+ AbstractView &view = get_view();
+ if (view.is_renaming() || !supports_renaming()) {
+ return;
+ }
+
+ if (view.begin_renaming()) {
+ is_renaming_ = true;
+ }
+
+ StringRef initial_str = get_rename_string();
+ std::copy(std::begin(initial_str), std::end(initial_str), std::begin(view.get_rename_buffer()));
+}
+
+void AbstractViewItem::rename_apply()
+{
+ const AbstractView &view = get_view();
+ rename(view.get_rename_buffer().data());
+ end_renaming();
+}
+
+void AbstractViewItem::end_renaming()
+{
+ if (!is_renaming()) {
+ return;
+ }
+
+ is_renaming_ = false;
+
+ AbstractView &view = get_view();
+ view.end_renaming();
+}
+
+static AbstractViewItem *find_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_VIEW_ITEM) {
+ continue;
+ }
+
+ uiButViewItem *view_item_but = (uiButViewItem *)but;
+ AbstractViewItem *item = reinterpret_cast<AbstractViewItem *>(view_item_but->view_item);
+ const AbstractView &view = item->get_view();
+
+ if (item->is_renaming() && (view.get_rename_buffer().data() == rename_but.poin)) {
+ return item;
+ }
+ }
+
+ return nullptr;
+}
+
+static void rename_button_fn(bContext *UNUSED(C), void *arg, char *UNUSED(origstr))
+{
+ const uiBut *rename_but = static_cast<uiBut *>(arg);
+ AbstractViewItem *item = find_item_from_rename_button(*rename_but);
+ BLI_assert(item);
+ item->rename_apply();
+}
+
+void AbstractViewItem::add_rename_button(uiBlock &block)
+{
+ AbstractView &view = get_view();
+ uiBut *rename_but = uiDefBut(&block,
+ UI_BTYPE_TEXT,
+ 1,
+ "",
+ 0,
+ 0,
+ UI_UNIT_X * 10,
+ UI_UNIT_Y,
+ view.get_rename_buffer().data(),
+ 1.0f,
+ view.get_rename_buffer().size(),
+ 0,
+ 0,
+ "");
+
+ /* Gotta be careful with what's passed to the `arg1` here. Any view data will be freed once the
+ * callback is executed. */
+ UI_but_func_rename_set(rename_but, rename_button_fn, rename_but);
+ UI_but_flag_disable(rename_but, UI_BUT_UNDO);
+
+ const bContext *evil_C = reinterpret_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();
+ }
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Context Menu
+ * \{ */
+
+void AbstractViewItem::build_context_menu(bContext & /*C*/, uiLayout & /*column*/) const
+{
+ /* No context menu by default. */
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name Drag 'n Drop
+ * \{ */
+
+std::unique_ptr<AbstractViewItemDragController> AbstractViewItem::create_drag_controller() const
+{
+ /* There's no drag controller (and hence no drag support) by default. */
+ return nullptr;
+}
+
+std::unique_ptr<AbstractViewItemDropController> AbstractViewItem::create_drop_controller() const
+{
+ /* There's no drop controller (and hence no drop support) by default. */
+ return nullptr;
+}
+
+AbstractViewItemDragController::AbstractViewItemDragController(AbstractView &view) : view_(view)
+{
+}
+
+void AbstractViewItemDragController::on_drag_start()
+{
+ /* Do nothing by default. */
+}
+
+AbstractViewItemDropController::AbstractViewItemDropController(AbstractView &view) : view_(view)
+{
+}
+
+/** \} */
+
+/* ---------------------------------------------------------------------- */
+/** \name General Getters & Setters
+ * \{ */
+
+AbstractView &AbstractViewItem::get_view() const
+{
+ if (UNLIKELY(!view_)) {
+ throw std::runtime_error(
+ "Invalid state, item must be registered through AbstractView::register_item()");
+ }
+ return *view_;
+}
+
+bool AbstractViewItem::is_active() const
+{
+ BLI_assert_msg(get_view().is_reconstructed(),
+ "State can't be queried until reconstruction is completed");
+ return is_active_;
+}
+
+/** \} */
+
+} // namespace blender::ui
+
+/* ---------------------------------------------------------------------- */
+/** \name C-API
+ * \{ */
+
+namespace blender::ui {
+
+/**
+ * Helper class to provide a higher level public (C-)API. Has access to private/protected view item
+ * members and ensures some invariants that way.
+ */
+class ViewItemAPIWrapper {
+ public:
+ static bool matches(const AbstractViewItem &a, const AbstractViewItem &b)
+ {
+ if (typeid(a) != typeid(b)) {
+ return false;
+ }
+ /* TODO should match the view as well. */
+ return a.matches(b);
+ }
+
+ static bool can_rename(const AbstractViewItem &item)
+ {
+ const AbstractView &view = item.get_view();
+ return !view.is_renaming() && item.supports_renaming();
+ }
+
+ static bool drag_start(bContext &C, const AbstractViewItem &item)
+ {
+ const std::unique_ptr<AbstractViewItemDragController> 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 AbstractViewItem &item,
+ const wmDrag &drag,
+ const char **r_disabled_hint)
+ {
+ const std::unique_ptr<AbstractViewItemDropController> 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 AbstractViewItem &item, const wmDrag &drag)
+ {
+ const std::unique_ptr<AbstractViewItemDropController> drop_controller =
+ item.create_drop_controller();
+ if (!drop_controller) {
+ return {};
+ }
+
+ return drop_controller->drop_tooltip(drag);
+ }
+
+ static bool drop_handle(bContext &C, const AbstractViewItem &item, const ListBase &drags)
+ {
+ std::unique_ptr<AbstractViewItemDropController> 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;
+ }
+};
+
+} // namespace blender::ui
+
+using namespace blender::ui;
+
+bool UI_view_item_is_active(const uiViewItemHandle *item_handle)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
+ return item.is_active();
+}
+
+bool UI_view_item_matches(const uiViewItemHandle *a_handle, const uiViewItemHandle *b_handle)
+{
+ const AbstractViewItem &a = reinterpret_cast<const AbstractViewItem &>(*a_handle);
+ const AbstractViewItem &b = reinterpret_cast<const AbstractViewItem &>(*b_handle);
+ return ViewItemAPIWrapper::matches(a, b);
+}
+
+bool UI_view_item_can_rename(const uiViewItemHandle *item_handle)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
+ return ViewItemAPIWrapper::can_rename(item);
+}
+
+void UI_view_item_begin_rename(uiViewItemHandle *item_handle)
+{
+ AbstractViewItem &item = reinterpret_cast<AbstractViewItem &>(*item_handle);
+ item.begin_renaming();
+}
+
+void UI_view_item_context_menu_build(bContext *C,
+ const uiViewItemHandle *item_handle,
+ uiLayout *column)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_handle);
+ item.build_context_menu(*C, *column);
+}
+
+bool UI_view_item_drag_start(bContext *C, const uiViewItemHandle *item_)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
+ return ViewItemAPIWrapper::drag_start(*C, item);
+}
+
+bool UI_view_item_can_drop(const uiViewItemHandle *item_,
+ const wmDrag *drag,
+ const char **r_disabled_hint)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
+ return ViewItemAPIWrapper::can_drop(item, *drag, r_disabled_hint);
+}
+
+char *UI_view_item_drop_tooltip(const uiViewItemHandle *item_, const wmDrag *drag)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
+
+ const std::string tooltip = ViewItemAPIWrapper::drop_tooltip(item, *drag);
+ return tooltip.empty() ? nullptr : BLI_strdup(tooltip.c_str());
+}
+
+bool UI_view_item_drop_handle(bContext *C, const uiViewItemHandle *item_, const ListBase *drags)
+{
+ const AbstractViewItem &item = reinterpret_cast<const AbstractViewItem &>(*item_);
+ return ViewItemAPIWrapper::drop_handle(*C, item, *drags);
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/grid_view.cc b/source/blender/editors/interface/views/grid_view.cc
index a82cb7798fe..52ff1460cbd 100644
--- a/source/blender/editors/interface/grid_view.cc
+++ b/source/blender/editors/interface/views/grid_view.cc
@@ -29,26 +29,19 @@ AbstractGridViewItem &AbstractGridView::add_item(std::unique_ptr<AbstractGridVie
items_.append(std::move(item));
AbstractGridViewItem &added_item = *items_.last();
- added_item.view_ = this;
-
item_map_.add(added_item.identifier_, &added_item);
+ register_item(added_item);
return added_item;
}
void AbstractGridView::foreach_item(ItemIterFn iter_fn) const
{
- for (auto &item_ptr : items_) {
+ for (const auto &item_ptr : items_) {
iter_fn(*item_ptr);
}
}
-bool AbstractGridView::listen(const wmNotifier &) const
-{
- /* Nothing by default. */
- return false;
-}
-
AbstractGridViewItem *AbstractGridView::find_matching_item(
const AbstractGridViewItem &item_to_match, const AbstractGridView &view_to_search_in) const
{
@@ -67,34 +60,18 @@ void AbstractGridView::change_state_delayed()
foreach_item([](AbstractGridViewItem &item) { item.change_state_delayed(); });
}
-void AbstractGridView::update_from_old(uiBlock &new_block)
+void AbstractGridView::update_children_from_old(const AbstractView &old_view)
{
- uiGridViewHandle *old_view_handle = ui_block_grid_view_find_matching_in_old_block(
- &new_block, reinterpret_cast<uiGridViewHandle *>(this));
- if (!old_view_handle) {
- /* Initial construction, nothing to update. */
- is_reconstructed_ = true;
- return;
- }
+ const AbstractGridView &old_grid_view = dynamic_cast<const AbstractGridView &>(old_view);
- AbstractGridView &old_view = reinterpret_cast<AbstractGridView &>(*old_view_handle);
-
- foreach_item([this, &old_view](AbstractGridViewItem &new_item) {
- const AbstractGridViewItem *matching_old_item = find_matching_item(new_item, old_view);
+ foreach_item([this, &old_grid_view](AbstractGridViewItem &new_item) {
+ const AbstractGridViewItem *matching_old_item = find_matching_item(new_item, old_grid_view);
if (!matching_old_item) {
return;
}
new_item.update_from_old(*matching_old_item);
});
-
- /* Finished (re-)constructing the tree. */
- is_reconstructed_ = true;
-}
-
-bool AbstractGridView::is_reconstructed() const
-{
- return is_reconstructed_;
}
const GridViewStyle &AbstractGridView::get_style() const
@@ -117,18 +94,19 @@ AbstractGridViewItem::AbstractGridViewItem(StringRef identifier) : identifier_(i
{
}
-bool AbstractGridViewItem::matches(const AbstractGridViewItem &other) const
+bool AbstractGridViewItem::matches(const AbstractViewItem &other) const
{
- return identifier_ == other.identifier_;
+ const AbstractGridViewItem &other_grid_item = dynamic_cast<const AbstractGridViewItem &>(other);
+ return identifier_ == other_grid_item.identifier_;
}
void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/,
void *but_arg1,
void * /*arg2*/)
{
- uiButGridTile *grid_tile_but = (uiButGridTile *)but_arg1;
+ uiButViewItem *view_item_but = (uiButViewItem *)but_arg1;
AbstractGridViewItem &grid_item = reinterpret_cast<AbstractGridViewItem &>(
- *grid_tile_but->view_item);
+ *view_item_but->view_item);
grid_item.activate();
}
@@ -136,8 +114,8 @@ void AbstractGridViewItem::grid_tile_click_fn(struct bContext * /*C*/,
void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
{
const GridViewStyle &style = get_view().get_style();
- grid_tile_but_ = (uiButGridTile *)uiDefBut(&block,
- UI_BTYPE_GRID_TILE,
+ view_item_but_ = (uiButViewItem *)uiDefBut(&block,
+ UI_BTYPE_VIEW_ITEM,
0,
"",
0,
@@ -151,15 +129,8 @@ void AbstractGridViewItem::add_grid_tile_button(uiBlock &block)
0,
"");
- grid_tile_but_->view_item = reinterpret_cast<uiGridViewItemHandle *>(this);
- UI_but_func_set(&grid_tile_but_->but, grid_tile_click_fn, grid_tile_but_, nullptr);
-}
-
-bool AbstractGridViewItem::is_active() const
-{
- BLI_assert_msg(get_view().is_reconstructed(),
- "State can't be queried until reconstruction is completed");
- return is_active_;
+ view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this);
+ UI_but_func_set(&view_item_but_->but, grid_tile_click_fn, view_item_but_, nullptr);
}
void AbstractGridViewItem::on_activate()
@@ -180,11 +151,6 @@ void AbstractGridViewItem::change_state_delayed()
}
}
-void AbstractGridViewItem::update_from_old(const AbstractGridViewItem &old)
-{
- is_active_ = old.is_active_;
-}
-
void AbstractGridViewItem::activate()
{
BLI_assert_msg(get_view().is_reconstructed(),
@@ -213,7 +179,7 @@ const AbstractGridView &AbstractGridViewItem::get_view() const
throw std::runtime_error(
"Invalid state, item must be added through AbstractGridView::add_item()");
}
- return *view_;
+ return dynamic_cast<AbstractGridView &>(*view_);
}
/* ---------------------------------------------------------------------- */
@@ -243,17 +209,17 @@ class BuildOnlyVisibleButtonsHelper {
IndexRange visible_items_range_{};
public:
- BuildOnlyVisibleButtonsHelper(const View2D &,
+ BuildOnlyVisibleButtonsHelper(const View2D &v2d,
const AbstractGridView &grid_view,
int cols_per_row);
bool is_item_visible(int item_idx) const;
- void fill_layout_before_visible(uiBlock &) const;
- void fill_layout_after_visible(uiBlock &) const;
+ void fill_layout_before_visible(uiBlock &block) const;
+ void fill_layout_after_visible(uiBlock &block) const;
private:
IndexRange get_visible_range() const;
- void add_spacer_button(uiBlock &, int row_count) const;
+ void add_spacer_button(uiBlock &block, int row_count) const;
};
BuildOnlyVisibleButtonsHelper::BuildOnlyVisibleButtonsHelper(const View2D &v2d,
@@ -495,31 +461,3 @@ std::optional<bool> PreviewGridItem::should_be_active() const
}
} // namespace blender::ui
-
-using namespace blender::ui;
-
-/* ---------------------------------------------------------------------- */
-/* C-API */
-
-using namespace blender::ui;
-
-bool UI_grid_view_item_is_active(const uiGridViewItemHandle *item_handle)
-{
- const AbstractGridViewItem &item = reinterpret_cast<const AbstractGridViewItem &>(*item_handle);
- return item.is_active();
-}
-
-bool UI_grid_view_listen_should_redraw(const uiGridViewHandle *view_handle,
- const wmNotifier *notifier)
-{
- const AbstractGridView &view = *reinterpret_cast<const AbstractGridView *>(view_handle);
- return view.listen(*notifier);
-}
-
-bool UI_grid_view_item_matches(const uiGridViewItemHandle *a_handle,
- const uiGridViewItemHandle *b_handle)
-{
- const AbstractGridViewItem &a = reinterpret_cast<const AbstractGridViewItem &>(*a_handle);
- const AbstractGridViewItem &b = reinterpret_cast<const AbstractGridViewItem &>(*b_handle);
- return a.matches(b);
-}
diff --git a/source/blender/editors/interface/views/interface_view.cc b/source/blender/editors/interface/views/interface_view.cc
new file mode 100644
index 00000000000..c568a8cab74
--- /dev/null
+++ b/source/blender/editors/interface/views/interface_view.cc
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Code to manage views as part of the regular screen hierarchy. E.g. managing ownership of views
+ * inside blocks (#uiBlock.views), looking up items in the region, passing WM notifiers to views,
+ * etc.
+ *
+ * Blocks and their contained views are reconstructed on every redraw. This file also contains
+ * functions related to this recreation of views inside blocks. For example to query state
+ * information before the view is done reconstructing (#AbstractView.is_reconstructed() returns
+ * false), it may be enough to query the previous version of the block/view/view-item. Since such
+ * queries rely on the details of the UI reconstruction process, they should remain internal to
+ * `interface/` code.
+ */
+
+#include <memory>
+#include <type_traits>
+#include <variant>
+
+#include "DNA_screen_types.h"
+
+#include "BKE_screen.h"
+
+#include "BLI_listbase.h"
+
+#include "ED_screen.h"
+
+#include "interface_intern.h"
+
+#include "UI_interface.hh"
+
+#include "UI_abstract_view.hh"
+#include "UI_grid_view.hh"
+#include "UI_tree_view.hh"
+
+using namespace blender;
+using namespace blender::ui;
+
+/**
+ * Wrapper to store views in a #ListBase, addressable via an identifier.
+ */
+struct ViewLink : public Link {
+ std::string idname;
+ std::unique_ptr<AbstractView> view;
+};
+
+template<class T>
+static T *ui_block_add_view_impl(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractView> view)
+{
+ ViewLink *view_link = MEM_new<ViewLink>(__func__);
+ BLI_addtail(&block.views, view_link);
+
+ view_link->view = std::move(view);
+ view_link->idname = idname;
+
+ return dynamic_cast<T *>(view_link->view.get());
+}
+
+AbstractGridView *UI_block_add_view(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractGridView> grid_view)
+{
+ return ui_block_add_view_impl<AbstractGridView>(block, idname, std::move(grid_view));
+}
+
+AbstractTreeView *UI_block_add_view(uiBlock &block,
+ StringRef idname,
+ std::unique_ptr<AbstractTreeView> tree_view)
+{
+ return ui_block_add_view_impl<AbstractTreeView>(block, idname, std::move(tree_view));
+}
+
+void ui_block_free_views(uiBlock *block)
+{
+ LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
+ MEM_delete(link);
+ }
+}
+
+void UI_block_views_listen(const uiBlock *block, const wmRegionListenerParams *listener_params)
+{
+ ARegion *region = listener_params->region;
+
+ LISTBASE_FOREACH (ViewLink *, view_link, &block->views) {
+ if (view_link->view->listen(*listener_params->notifier)) {
+ ED_region_tag_redraw(region);
+ }
+ }
+}
+
+uiViewItemHandle *UI_region_views_find_item_at(const ARegion *region, const int xy[2])
+{
+ uiButViewItem *item_but = (uiButViewItem *)ui_view_item_find_mouse_over(region, xy);
+ if (!item_but) {
+ return nullptr;
+ }
+
+ return item_but->view_item;
+}
+
+uiViewItemHandle *UI_region_views_find_active_item(const ARegion *region)
+{
+ uiButViewItem *item_but = (uiButViewItem *)ui_view_item_find_active(region);
+ if (!item_but) {
+ return nullptr;
+ }
+
+ return item_but->view_item;
+}
+
+static StringRef ui_block_view_find_idname(const uiBlock &block, const AbstractView &view)
+{
+ /* First get the idname the of the view we're looking for. */
+ LISTBASE_FOREACH (ViewLink *, view_link, &block.views) {
+ if (view_link->view.get() == &view) {
+ return view_link->idname;
+ }
+ }
+
+ return {};
+}
+
+template<class T>
+static T *ui_block_view_find_matching_in_old_block_impl(const uiBlock &new_block,
+ const T &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 dynamic_cast<T *>(old_view_link->view.get());
+ }
+ }
+
+ return nullptr;
+}
+
+uiViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_block,
+ const uiViewHandle *new_view_handle)
+{
+ BLI_assert(new_block && new_view_handle);
+ const AbstractView &new_view = reinterpret_cast<const AbstractView &>(*new_view_handle);
+
+ AbstractView *old_view = ui_block_view_find_matching_in_old_block_impl(*new_block, new_view);
+ return reinterpret_cast<uiViewHandle *>(old_view);
+}
+
+uiButViewItem *ui_block_view_find_matching_view_item_but_in_old_block(
+ const uiBlock *new_block, const uiViewItemHandle *new_item_handle)
+{
+ uiBlock *old_block = new_block->oldblock;
+ if (!old_block) {
+ return nullptr;
+ }
+
+ const AbstractViewItem &new_item = *reinterpret_cast<const AbstractViewItem *>(new_item_handle);
+ const AbstractView *old_view = ui_block_view_find_matching_in_old_block_impl(
+ *new_block, new_item.get_view());
+ if (!old_view) {
+ return nullptr;
+ }
+
+ LISTBASE_FOREACH (uiBut *, old_but, &old_block->buttons) {
+ if (old_but->type != UI_BTYPE_VIEW_ITEM) {
+ continue;
+ }
+ uiButViewItem *old_item_but = (uiButViewItem *)old_but;
+ if (!old_item_but->view_item) {
+ continue;
+ }
+ AbstractViewItem &old_item = *reinterpret_cast<AbstractViewItem *>(old_item_but->view_item);
+ /* Check if the item is from the expected view. */
+ if (&old_item.get_view() != old_view) {
+ continue;
+ }
+
+ if (UI_view_item_matches(reinterpret_cast<const uiViewItemHandle *>(&new_item),
+ reinterpret_cast<const uiViewItemHandle *>(&old_item))) {
+ return old_item_but;
+ }
+ }
+
+ return nullptr;
+}
diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/views/tree_view.cc
index f86d1c4d8bc..21078b711c7 100644
--- a/source/blender/editors/interface/tree_view.cc
+++ b/source/blender/editors/interface/views/tree_view.cc
@@ -37,9 +37,11 @@ AbstractTreeViewItem &TreeViewItemContainer::add_tree_item(
if (root_ == nullptr) {
root_ = this;
}
-
+ AbstractTreeView &tree_view = static_cast<AbstractTreeView &>(*root_);
AbstractTreeViewItem &added_item = *children_.last();
added_item.root_ = root_;
+ tree_view.register_item(added_item);
+
if (root_ != this) {
/* Any item that isn't the root can be assumed to the a #AbstractTreeViewItem. Not entirely
* nice to static_cast this, but well... */
@@ -68,45 +70,11 @@ void AbstractTreeView::foreach_item(ItemIterFn iter_fn, IterOptions options) con
foreach_item_recursive(iter_fn, options);
}
-bool AbstractTreeView::listen(const wmNotifier &) const
+void AbstractTreeView::update_children_from_old(const AbstractView &old_view)
{
- /* Nothing by default. */
- return false;
-}
+ const AbstractTreeView &old_tree_view = dynamic_cast<const AbstractTreeView &>(old_view);
-bool AbstractTreeView::is_renaming() const
-{
- 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_tree_view_find_matching_in_old_block(
- &new_block, reinterpret_cast<uiTreeViewHandle *>(this));
- 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;
+ update_children_from_old_recursive(*this, old_tree_view);
}
void AbstractTreeView::update_children_from_old_recursive(const TreeViewOrItem &new_items,
@@ -129,7 +97,7 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
const AbstractTreeViewItem &lookup_item, const TreeViewOrItem &items)
{
for (const auto &iter_item : items.children_) {
- if (lookup_item.matches(*iter_item)) {
+ if (lookup_item.matches_single(*iter_item)) {
/* We have a matching item! */
return iter_item.get();
}
@@ -138,11 +106,6 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
return nullptr;
}
-bool AbstractTreeView::is_reconstructed() const
-{
- return is_reconstructed_;
-}
-
void AbstractTreeView::change_state_delayed()
{
BLI_assert_msg(
@@ -157,9 +120,8 @@ 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);
+ uiButViewItem *item_but = (uiButViewItem *)but_arg1;
+ AbstractTreeViewItem &tree_item = reinterpret_cast<AbstractTreeViewItem &>(*item_but->view_item);
tree_item.activate();
/* Not only activate the item, also show its children. Maybe this should be optional, or
@@ -170,11 +132,11 @@ void AbstractTreeViewItem::tree_row_click_fn(struct bContext * /*C*/,
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, "");
+ view_item_but_ = (uiButViewItem *)uiDefBut(
+ &block, UI_BTYPE_VIEW_ITEM, 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);
+ view_item_but_->view_item = reinterpret_cast<uiViewItemHandle *>(this);
+ UI_but_func_set(&view_item_but_->but, tree_row_click_fn, view_item_but_, nullptr);
}
void AbstractTreeViewItem::add_indent(uiLayout &row) const
@@ -206,10 +168,9 @@ void AbstractTreeViewItem::collapse_chevron_click_fn(struct bContext *C,
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);
+ uiViewItemHandle *hovered_item_handle = UI_region_views_find_item_at(region, win->eventstate->xy);
+
+ AbstractTreeViewItem *hovered_item = from_item_handle<AbstractTreeViewItem>(hovered_item_handle);
BLI_assert(hovered_item != nullptr);
hovered_item->toggle_collapsed();
@@ -243,40 +204,6 @@ void AbstractTreeViewItem::add_collapse_chevron(uiBlock &block) const
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);
@@ -286,33 +213,7 @@ void AbstractTreeViewItem::add_rename_button(uiLayout &row)
/* 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();
- }
+ AbstractViewItem::add_rename_button(*block);
UI_block_emboss_set(block, previous_emboss);
UI_block_layout_set_current(block, &row);
@@ -345,79 +246,35 @@ bool AbstractTreeViewItem::supports_collapsing() const
return true;
}
-std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller()
- const
+StringRef AbstractTreeViewItem::get_rename_string() 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;
+ return label_;
}
bool AbstractTreeViewItem::rename(StringRefNull new_name)
{
- /* It is important to update the label after renaming, so #AbstractTreeViewItem::matches()
+ /* It is important to update the label after renaming, so #AbstractTreeViewItem::matches_single()
* recognizes the item. (It only compares labels by default.) */
label_ = new_name;
return true;
}
-void AbstractTreeViewItem::build_context_menu(bContext & /*C*/, uiLayout & /*column*/) const
+void AbstractTreeViewItem::update_from_old(const AbstractViewItem &old)
{
- /* No context menu by default. */
-}
+ AbstractViewItem::update_from_old(old);
-void AbstractTreeViewItem::update_from_old(const AbstractTreeViewItem &old)
-{
- is_open_ = old.is_open_;
- is_active_ = old.is_active_;
- is_renaming_ = old.is_renaming_;
+ const AbstractTreeViewItem &old_tree_item = dynamic_cast<const AbstractTreeViewItem &>(old);
+ is_open_ = old_tree_item.is_open_;
}
-bool AbstractTreeViewItem::matches(const AbstractTreeViewItem &other) const
+bool AbstractTreeViewItem::matches_single(const AbstractTreeViewItem &other) const
{
return label_ == other.label_;
}
-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_);
+ return dynamic_cast<AbstractTreeView &>(get_view());
}
int AbstractTreeViewItem::count_parents() const
@@ -453,26 +310,19 @@ 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,
+ BLI_assert_msg(view_item_but_ != nullptr,
"Hovered state can't be queried before the tree row is being built");
- const uiTreeViewItemHandle *this_handle = reinterpret_cast<const uiTreeViewItemHandle *>(this);
+ const uiViewItemHandle *this_item_handle = reinterpret_cast<const uiViewItemHandle *>(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);
+ uiButViewItem *old_item_but = ui_block_view_find_matching_view_item_but_in_old_block(
+ view_item_but_->but.block, this_item_handle);
+ return old_item_but && (old_item_but->but.flag & UI_ACTIVE);
}
bool AbstractTreeViewItem::is_collapsed() const
@@ -500,11 +350,6 @@ bool AbstractTreeViewItem::is_collapsible() const
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_) {
@@ -512,19 +357,21 @@ void AbstractTreeViewItem::ensure_parents_uncollapsed()
}
}
-bool AbstractTreeViewItem::matches_including_parents(const AbstractTreeViewItem &other) const
+bool AbstractTreeViewItem::matches(const AbstractViewItem &other) const
{
- if (!matches(other)) {
+ const AbstractTreeViewItem &other_tree_item = dynamic_cast<const AbstractTreeViewItem &>(other);
+
+ if (!matches_single(other_tree_item)) {
return false;
}
- if (count_parents() != other.count_parents()) {
+ if (count_parents() != other_tree_item.count_parents()) {
return false;
}
- for (AbstractTreeViewItem *parent = parent_, *other_parent = other.parent_;
+ for (AbstractTreeViewItem *parent = parent_, *other_parent = other_tree_item.parent_;
parent && other_parent;
parent = parent->parent_, other_parent = other_parent->parent_) {
- if (!parent->matches(*other_parent)) {
+ if (!parent->matches_single(*other_parent)) {
return false;
}
}
@@ -532,9 +379,9 @@ bool AbstractTreeViewItem::matches_including_parents(const AbstractTreeViewItem
return true;
}
-uiButTreeRow *AbstractTreeViewItem::tree_row_button()
+uiButViewItem *AbstractTreeViewItem::view_item_button()
{
- return tree_row_but_;
+ return view_item_but_;
}
void AbstractTreeViewItem::change_state_delayed()
@@ -547,25 +394,6 @@ void AbstractTreeViewItem::change_state_delayed()
/* ---------------------------------------------------------------------- */
-AbstractTreeViewItemDragController::AbstractTreeViewItemDragController(AbstractTreeView &tree_view)
- : tree_view_(tree_view)
-{
-}
-
-void AbstractTreeViewItemDragController::on_drag_start()
-{
- /* Do nothing by default. */
-}
-
-/* ---------------------------------------------------------------------- */
-
-AbstractTreeViewItemDropController::AbstractTreeViewItemDropController(AbstractTreeView &tree_view)
- : tree_view_(tree_view)
-{
-}
-
-/* ---------------------------------------------------------------------- */
-
class TreeViewLayoutBuilder {
uiBlock &block_;
@@ -611,7 +439,7 @@ void TreeViewLayoutBuilder::polish_layout(const uiBlock &block)
UI_but_drawflag_enable(static_cast<uiBut *>(but->next), UI_BUT_NO_TEXT_PADDING);
}
- if (but->type == UI_BTYPE_TREEROW) {
+ if (but->type == UI_BTYPE_VIEW_ITEM) {
break;
}
}
@@ -723,161 +551,4 @@ std::optional<bool> BasicTreeViewItem::should_be_active() const
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_listen_should_redraw(const uiTreeViewHandle *view_handle,
- const wmNotifier *notifier)
-{
- const AbstractTreeView &view = *reinterpret_cast<const AbstractTreeView *>(view_handle);
- return view.listen(*notifier);
-}
-
-bool UI_tree_view_item_is_active(const uiTreeViewItemHandle *item_handle)
-{
- 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/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index ef093a01ff8..a716c00d5d9 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -13,6 +13,7 @@ set(INC
../../io/gpencil
../../io/usd
../../io/wavefront_obj
+ ../../io/stl
../../makesdna
../../makesrna
../../windowmanager
@@ -33,6 +34,7 @@ set(SRC
io_obj.c
io_ops.c
io_usd.c
+ io_stl_ops.c
io_alembic.h
io_cache.h
@@ -41,12 +43,12 @@ set(SRC
io_obj.h
io_ops.h
io_usd.h
+ io_stl_ops.h
)
set(LIB
bf_blenkernel
bf_blenlib
- bf_wavefront_obj
)
if(WITH_OPENCOLLADA)
@@ -56,6 +58,27 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_IO_WAVEFRONT_OBJ)
+ list(APPEND LIB
+ bf_wavefront_obj
+ )
+ add_definitions(-DWITH_IO_WAVEFRONT_OBJ)
+endif()
+
+if(WITH_IO_STL)
+ list(APPEND LIB
+ bf_stl
+ )
+ add_definitions(-DWITH_IO_STL)
+endif()
+
+if(WITH_IO_GPENCIL)
+ list(APPEND LIB
+ bf_gpencil
+ )
+ add_definitions(-DWITH_IO_GPENCIL)
+endif()
+
if(WITH_ALEMBIC)
list(APPEND LIB
bf_alembic
@@ -78,6 +101,4 @@ if(WITH_HARU)
add_definitions(-DWITH_HARU)
endif()
-list(APPEND LIB bf_gpencil)
-
blender_add_lib(bf_editor_io "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 87923d9fdf8..0068586730f 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -144,10 +144,10 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op)
/* Take some defaults from the scene, if not specified explicitly. */
Scene *scene = CTX_data_scene(C);
if (params.frame_start == INT_MIN) {
- params.frame_start = SFRA;
+ params.frame_start = scene->r.sfra;
}
if (params.frame_end == INT_MIN) {
- params.frame_end = EFRA;
+ params.frame_end = scene->r.efra;
}
const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job");
@@ -248,8 +248,8 @@ static void wm_alembic_export_draw(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
if (scene != NULL && RNA_boolean_get(op->ptr, "init_scene_frame_range")) {
- RNA_int_set(op->ptr, "start", SFRA);
- RNA_int_set(op->ptr, "end", EFRA);
+ RNA_int_set(op->ptr, "start", scene->r.sfra);
+ RNA_int_set(op->ptr, "end", scene->r.efra);
RNA_boolean_set(op->ptr, "init_scene_frame_range", false);
}
@@ -282,7 +282,7 @@ void WM_OT_alembic_export(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->ui = wm_alembic_export_draw;
ot->check = wm_alembic_export_check;
- ot->flag |= OPTYPE_PRESET;
+ ot->flag = OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index dc62212bf53..c491e7a5815 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -468,7 +468,7 @@ void WM_OT_collada_export(wmOperatorType *ot)
ot->poll = WM_operator_winactive;
ot->check = wm_collada_export_check;
- ot->flag |= OPTYPE_PRESET;
+ ot->flag = OPTYPE_PRESET;
ot->ui = wm_collada_export_draw;
@@ -786,7 +786,7 @@ void WM_OT_collada_import(wmOperatorType *ot)
ot->exec = wm_collada_import_exec;
ot->poll = WM_operator_winactive;
- // ot->flag |= OPTYPE_PRESET;
+ // ot->flag = OPTYPE_PRESET;
ot->ui = wm_collada_import_draw;
diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c
index 7ac05fcca3e..3f905dd7de0 100644
--- a/source/blender/editors/io/io_gpencil_export.c
+++ b/source/blender/editors/io/io_gpencil_export.c
@@ -5,36 +5,38 @@
* \ingroup editor/io
*/
-#include "BLI_path_util.h"
-#include "BLI_string.h"
+#ifdef WITH_IO_GPENCIL
-#include "DNA_gpencil_types.h"
-#include "DNA_space_types.h"
+# include "BLI_path_util.h"
+# include "BLI_string.h"
-#include "BKE_gpencil.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_screen.h"
+# include "DNA_gpencil_types.h"
+# include "DNA_space_types.h"
-#include "BLT_translation.h"
+# include "BKE_gpencil.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
+# include "BKE_screen.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "BLT_translation.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
+# include "WM_api.h"
+# include "WM_types.h"
-#include "io_gpencil.h"
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_query.h"
-#include "gpencil_io.h"
+# include "io_gpencil.h"
-#if defined(WITH_PUGIXML) || defined(WITH_HARU)
+# include "gpencil_io.h"
+
+# if defined(WITH_PUGIXML) || defined(WITH_HARU)
/* Definition of enum elements to export. */
/* Common props for exporting. */
static void gpencil_export_common_props_definition(wmOperatorType *ot)
@@ -87,10 +89,10 @@ static void set_export_filepath(bContext *C, wmOperator *op, const char *extensi
RNA_string_set(op->ptr, "filepath", filepath);
}
}
-#endif
+# endif
/* <-------- SVG single frame export. --------> */
-#ifdef WITH_PUGIXML
+# ifdef WITH_PUGIXML
static bool wm_gpencil_export_svg_common_check(bContext *UNUSED(C), wmOperator *op)
{
char filepath[FILE_MAX];
@@ -151,9 +153,9 @@ static int wm_gpencil_export_svg_exec(bContext *C, wmOperator *op)
.v3d = v3d,
.ob = ob,
.mode = GP_EXPORT_TO_SVG,
- .frame_start = CFRA,
- .frame_end = CFRA,
- .frame_cur = CFRA,
+ .frame_start = scene->r.cfra,
+ .frame_end = scene->r.cfra,
+ .frame_cur = scene->r.cfra,
.flag = flag,
.scale = 1.0f,
.select_mode = select_mode,
@@ -241,10 +243,10 @@ void WM_OT_gpencil_export_svg(wmOperatorType *ot)
"Clip Camera",
"Clip drawings to camera size when export in camera view");
}
-#endif
+# endif
/* <-------- PDF single frame export. --------> */
-#ifdef WITH_HARU
+# ifdef WITH_HARU
static bool wm_gpencil_export_pdf_common_check(bContext *UNUSED(C), wmOperator *op)
{
@@ -304,9 +306,9 @@ static int wm_gpencil_export_pdf_exec(bContext *C, wmOperator *op)
.v3d = v3d,
.ob = ob,
.mode = GP_EXPORT_TO_PDF,
- .frame_start = SFRA,
- .frame_end = EFRA,
- .frame_cur = CFRA,
+ .frame_start = scene->r.sfra,
+ .frame_end = scene->r.efra,
+ .frame_cur = scene->r.cfra,
.flag = flag,
.scale = 1.0f,
.select_mode = select_mode,
@@ -406,4 +408,6 @@ void WM_OT_gpencil_export_pdf(wmOperatorType *ot)
"Frames",
"Which frames to include in the export");
}
-#endif
+# endif /* WITH_HARU */
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c
index 8bed32ad6c3..9ac64407dcf 100644
--- a/source/blender/editors/io/io_gpencil_import.c
+++ b/source/blender/editors/io/io_gpencil_import.c
@@ -5,34 +5,36 @@
* \ingroup editor/io
*/
-#include "BLI_path_util.h"
+#ifdef WITH_IO_GPENCIL
-#include "DNA_gpencil_types.h"
-#include "DNA_space_types.h"
+# include "BLI_path_util.h"
-#include "BKE_context.h"
-#include "BKE_gpencil.h"
-#include "BKE_report.h"
+# include "DNA_gpencil_types.h"
+# include "DNA_space_types.h"
-#include "BLT_translation.h"
+# include "BKE_context.h"
+# include "BKE_gpencil.h"
+# include "BKE_report.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "BLT_translation.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
+# include "WM_api.h"
+# include "WM_types.h"
-#include "ED_gpencil.h"
+# include "DEG_depsgraph.h"
+# include "DEG_depsgraph_query.h"
-#include "io_gpencil.h"
+# include "ED_gpencil.h"
-#include "gpencil_io.h"
+# include "io_gpencil.h"
+
+# include "gpencil_io.h"
/* <-------- SVG single frame import. --------> */
static bool wm_gpencil_import_svg_common_check(bContext *UNUSED(C), wmOperator *op)
@@ -88,9 +90,9 @@ static int wm_gpencil_import_svg_exec(bContext *C, wmOperator *op)
.v3d = v3d,
.ob = NULL,
.mode = GP_IMPORT_FROM_SVG,
- .frame_start = CFRA,
- .frame_end = CFRA,
- .frame_cur = CFRA,
+ .frame_start = scene->r.cfra,
+ .frame_end = scene->r.cfra,
+ .frame_cur = scene->r.cfra,
.flag = flag,
.scale = scale,
.select_mode = 0,
@@ -174,3 +176,5 @@ void WM_OT_gpencil_import_svg(wmOperatorType *ot)
0.001f,
100.0f);
}
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_gpencil_utils.c b/source/blender/editors/io/io_gpencil_utils.c
index fa5fcd79b96..9a88daef1a1 100644
--- a/source/blender/editors/io/io_gpencil_utils.c
+++ b/source/blender/editors/io/io_gpencil_utils.c
@@ -5,14 +5,16 @@
* \ingroup editor/io
*/
-#include "DNA_space_types.h"
+#ifdef WITH_IO_GPENCIL
-#include "BKE_context.h"
-#include "BKE_screen.h"
+# include "DNA_space_types.h"
-#include "WM_api.h"
+# include "BKE_context.h"
+# include "BKE_screen.h"
-#include "io_gpencil.h"
+# include "WM_api.h"
+
+# include "io_gpencil.h"
ARegion *get_invoke_region(bContext *C)
{
@@ -46,3 +48,5 @@ View3D *get_invoke_view3d(bContext *C)
return NULL;
}
+
+#endif /* WITH_IO_GPENCIL */
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index f1cd7607771..79ec7ebf2a5 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -4,54 +4,39 @@
* \ingroup editor/io
*/
-#include "DNA_space_types.h"
+#ifdef WITH_IO_WAVEFRONT_OBJ
-#include "BKE_context.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
+# include "DNA_space_types.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
+# include "BKE_context.h"
+# include "BKE_main.h"
+# include "BKE_report.h"
-#include "BLT_translation.h"
+# include "BLI_path_util.h"
+# include "BLI_string.h"
+# include "BLI_utildefines.h"
-#include "ED_outliner.h"
+# include "BLT_translation.h"
-#include "MEM_guardedalloc.h"
+# include "ED_outliner.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
+# include "MEM_guardedalloc.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
+# include "RNA_access.h"
+# include "RNA_define.h"
-#include "WM_api.h"
-#include "WM_types.h"
+# include "UI_interface.h"
+# include "UI_resources.h"
-#include "DEG_depsgraph.h"
+# include "WM_api.h"
+# include "WM_types.h"
-#include "IO_path_util_types.h"
-#include "IO_wavefront_obj.h"
-#include "io_obj.h"
+# include "DEG_depsgraph.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", "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", "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}};
+# include "IO_orientation.h"
+# include "IO_path_util_types.h"
+# include "IO_wavefront_obj.h"
+# include "io_obj.h"
static const EnumPropertyItem io_obj_export_evaluation_mode[] = {
{DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
@@ -115,6 +100,7 @@ static int wm_obj_export_exec(bContext *C, wmOperator *op)
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_colors = RNA_boolean_get(op->ptr, "export_colors");
export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
export_params.path_mode = RNA_enum_get(op->ptr, "path_mode");
export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
@@ -175,6 +161,7 @@ static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
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_colors", 0, IFACE_("Colors"), 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);
@@ -221,11 +208,11 @@ static bool wm_obj_export_check(bContext *C, wmOperator *op)
int end = RNA_int_get(op->ptr, "end_frame");
/* Set the defaults. */
if (start == INT_MIN) {
- start = SFRA;
+ start = scene->r.sfra;
changed = true;
}
if (end == INT_MAX) {
- end = EFRA;
+ end = scene->r.efra;
changed = true;
}
/* Fix user errors. */
@@ -261,7 +248,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
ot->ui = wm_obj_export_draw;
ot->check = wm_obj_export_check;
- ot->flag |= OPTYPE_PRESET;
+ ot->flag = OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
@@ -279,7 +266,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"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, /* wm_obj_export_check uses this to set scene->r.sfra. */
INT_MIN,
INT_MAX,
"Start Frame",
@@ -288,7 +275,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
INT_MAX);
RNA_def_int(ot->srna,
"end_frame",
- INT_MAX, /* wm_obj_export_check uses this to set EFRA. */
+ INT_MAX, /* wm_obj_export_check uses this to set scene->r.efra. */
INT_MIN,
INT_MAX,
"End Frame",
@@ -296,13 +283,9 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
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_enum(
+ ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
RNA_def_float(ot->srna,
"scaling_factor",
1.0f,
@@ -334,6 +317,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"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_colors", false, "Export Colors", "Export per-vertex colors");
RNA_def_boolean(ot->srna,
"export_materials",
true,
@@ -408,6 +392,7 @@ static int wm_obj_import_exec(bContext *C, wmOperator *op)
import_params.clamp_size = RNA_float_get(op->ptr, "clamp_size");
import_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
import_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ import_params.import_vertex_groups = RNA_boolean_get(op->ptr, "import_vertex_groups");
import_params.validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes");
OBJ_import(C, &import_params);
@@ -438,6 +423,7 @@ static void ui_obj_import_settings(uiLayout *layout, PointerRNA *imfptr)
box = uiLayoutBox(layout);
uiItemL(box, IFACE_("Options"), ICON_EXPORT);
col = uiLayoutColumn(box, false);
+ uiItemR(col, imfptr, "import_vertex_groups", 0, NULL, ICON_NONE);
uiItemR(col, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
}
@@ -456,6 +442,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
ot->name = "Import Wavefront OBJ";
ot->description = "Load a Wavefront OBJ scene";
ot->idname = "WM_OT_obj_import";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->invoke = wm_obj_import_invoke;
ot->exec = wm_obj_import_exec;
@@ -479,13 +466,14 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
"Resize the objects to keep bounding box under this value. Value 0 disables clamping",
0.0f,
1000.0f);
- 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_enum(
+ ot->srna, "forward_axis", io_transform_axis, IO_AXIS_NEGATIVE_Z, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Y, "Up Axis", "");
+ RNA_def_boolean(ot->srna,
+ "import_vertex_groups",
+ false,
+ "Vertex Groups",
+ "Import OBJ groups as vertex groups");
RNA_def_boolean(ot->srna,
"validate_meshes",
false,
@@ -496,3 +484,5 @@ void WM_OT_obj_import(struct wmOperatorType *ot)
prop = RNA_def_string(ot->srna, "filter_glob", "*.obj;*.mtl", 0, "Extension Filter", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+
+#endif /* WITH_IO_WAVEFRONT_OBJ */
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index 094f89d1540..0340d0598d5 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -24,6 +24,7 @@
#include "io_cache.h"
#include "io_gpencil.h"
#include "io_obj.h"
+#include "io_stl_ops.h"
void ED_operatortypes_io(void)
{
@@ -41,14 +42,14 @@ void ED_operatortypes_io(void)
WM_operatortype_append(WM_OT_usd_export);
#endif
+#ifdef WITH_IO_GPENCIL
WM_operatortype_append(WM_OT_gpencil_import_svg);
-
-#ifdef WITH_PUGIXML
+# ifdef WITH_PUGIXML
WM_operatortype_append(WM_OT_gpencil_export_svg);
-#endif
-
-#ifdef WITH_HARU
+# endif
+# ifdef WITH_HARU
WM_operatortype_append(WM_OT_gpencil_export_pdf);
+# endif
#endif
WM_operatortype_append(CACHEFILE_OT_open);
@@ -58,6 +59,12 @@ void ED_operatortypes_io(void)
WM_operatortype_append(CACHEFILE_OT_layer_remove);
WM_operatortype_append(CACHEFILE_OT_layer_move);
+#ifdef WITH_IO_WAVEFRONT_OBJ
WM_operatortype_append(WM_OT_obj_export);
WM_operatortype_append(WM_OT_obj_import);
+#endif
+
+#ifdef WITH_IO_STL
+ WM_operatortype_append(WM_OT_stl_import);
+#endif
}
diff --git a/source/blender/editors/io/io_stl_ops.c b/source/blender/editors/io/io_stl_ops.c
new file mode 100644
index 00000000000..7db32cd6f18
--- /dev/null
+++ b/source/blender/editors/io/io_stl_ops.c
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#ifdef WITH_IO_STL
+
+# include "BKE_context.h"
+# include "BKE_report.h"
+
+# include "WM_api.h"
+# include "WM_types.h"
+
+# include "DNA_space_types.h"
+
+# include "ED_outliner.h"
+
+# include "RNA_access.h"
+# include "RNA_define.h"
+
+# include "IO_stl.h"
+# include "io_stl_ops.h"
+
+static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ return WM_operator_filesel(C, op, event);
+}
+
+static int wm_stl_import_execute(bContext *C, wmOperator *op)
+{
+ struct STLImportParams params;
+ params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
+ params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ params.use_facet_normal = RNA_boolean_get(op->ptr, "use_facet_normal");
+ params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit");
+ params.global_scale = RNA_float_get(op->ptr, "global_scale");
+ params.use_mesh_validate = RNA_boolean_get(op->ptr, "use_mesh_validate");
+
+ int files_len = RNA_collection_length(op->ptr, "files");
+
+ if (files_len) {
+ PointerRNA fileptr;
+ PropertyRNA *prop;
+ char dir_only[FILE_MAX], file_only[FILE_MAX];
+
+ RNA_string_get(op->ptr, "directory", dir_only);
+ prop = RNA_struct_find_property(op->ptr, "files");
+ for (int i = 0; i < files_len; i++) {
+ RNA_property_collection_lookup_int(op->ptr, prop, i, &fileptr);
+ RNA_string_get(&fileptr, "name", file_only);
+ BLI_join_dirfile(params.filepath, sizeof(params.filepath), dir_only, file_only);
+ STL_import(C, &params);
+ }
+ }
+ else if (RNA_struct_property_is_set(op->ptr, "filepath")) {
+ RNA_string_get(op->ptr, "filepath", params.filepath);
+ STL_import(C, &params);
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static bool wm_stl_import_check(bContext *UNUSED(C), wmOperator *op)
+{
+ const int num_axes = 3;
+ /* Both forward and up axes cannot be the same (or same except opposite sign). */
+ if (RNA_enum_get(op->ptr, "forward_axis") % num_axes ==
+ (RNA_enum_get(op->ptr, "up_axis") % num_axes)) {
+ RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % num_axes + 1);
+ return true;
+ }
+ return false;
+}
+
+void WM_OT_stl_import(struct wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name = "Import STL";
+ ot->description = "Import an STL file as an object";
+ ot->idname = "WM_OT_stl_import";
+
+ ot->invoke = wm_stl_import_invoke;
+ ot->exec = wm_stl_import_execute;
+ ot->poll = WM_operator_winactive;
+ ot->check = wm_stl_import_check;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER,
+ FILE_BLENDER,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_FILES | WM_FILESEL_DIRECTORY |
+ WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f);
+ RNA_def_boolean(ot->srna,
+ "use_scene_unit",
+ false,
+ "Scene Unit",
+ "Apply current scene's unit (as defined by unit scale) to imported data");
+ RNA_def_boolean(ot->srna,
+ "use_facet_normal",
+ false,
+ "Facet Normals",
+ "Use (import) facet normals (note that this will still give flat shading)");
+ RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
+ RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
+ RNA_def_boolean(ot->srna,
+ "use_mesh_validate",
+ false,
+ "Validate Mesh",
+ "Validate and correct imported mesh (slow)");
+
+ /* Only show .stl files by default. */
+ prop = RNA_def_string(ot->srna, "filter_glob", "*.stl", 0, "Extension Filter", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+#endif /* WITH_IO_STL */
diff --git a/source/blender/editors/io/io_stl_ops.h b/source/blender/editors/io/io_stl_ops.h
new file mode 100644
index 00000000000..8f548f75985
--- /dev/null
+++ b/source/blender/editors/io/io_stl_ops.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#pragma once
+
+struct wmOperatorType;
+
+void WM_OT_stl_export(struct wmOperatorType *ot);
+void WM_OT_stl_import(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index 609230eefea..a59cdf60243 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -57,6 +57,20 @@ const EnumPropertyItem rna_enum_usd_export_evaluation_mode_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_usd_mtl_name_collision_mode_items[] = {
+ {USD_MTL_NAME_COLLISION_MAKE_UNIQUE,
+ "MAKE_UNIQUE",
+ 0,
+ "Make Unique",
+ "Import each USD material as a unique Blender material"},
+ {USD_MTL_NAME_COLLISION_REFERENCE_EXISTING,
+ "REFERENCE_EXISTING",
+ 0,
+ "Reference Existing",
+ "If a material with the same name already exists, reference that instead of importing"},
+ {0, NULL, 0, NULL, NULL},
+};
+
/* Stored in the wmOperator's customdata field to indicate it should run as a background job.
* This is set when the operator is invoked, and not set when it is only executed. */
enum { AS_BACKGROUND_JOB = 1 };
@@ -216,7 +230,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
ot->ui = wm_usd_export_draw;
ot->check = wm_usd_export_check;
- ot->flag = OPTYPE_REGISTER; /* No UNDO possible. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_PRESET; /* No UNDO possible. */
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_USD,
@@ -371,6 +385,9 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
const float light_intensity_scale = RNA_float_get(op->ptr, "light_intensity_scale");
+ const eUSDMtlNameCollisionMode mtl_name_collision_mode = RNA_enum_get(op->ptr,
+ "mtl_name_collision_mode");
+
/* TODO(makowalski): Add support for sequences. */
const bool is_sequence = false;
int offset = 0;
@@ -409,7 +426,8 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
.use_instancing = use_instancing,
.import_usd_preview = import_usd_preview,
.set_material_blend = set_material_blend,
- .light_intensity_scale = light_intensity_scale};
+ .light_intensity_scale = light_intensity_scale,
+ .mtl_name_collision_mode = mtl_name_collision_mode};
const bool ok = USD_import(C, filename, &params, as_background_job);
@@ -452,6 +470,7 @@ static void wm_usd_import_draw(bContext *UNUSED(C), wmOperator *op)
uiItemR(col, ptr, "relative_path", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "create_collection", 0, NULL, ICON_NONE);
uiItemR(box, ptr, "light_intensity_scale", 0, NULL, ICON_NONE);
+ uiItemR(box, ptr, "mtl_name_collision_mode", 0, NULL, ICON_NONE);
box = uiLayoutBox(layout);
col = uiLayoutColumnWithHeading(box, true, IFACE_("Experimental"));
@@ -575,6 +594,14 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
"Scale for the intensity of imported lights",
0.0001f,
1000.0f);
+
+ RNA_def_enum(
+ ot->srna,
+ "mtl_name_collision_mode",
+ rna_enum_usd_mtl_name_collision_mode_items,
+ USD_MTL_NAME_COLLISION_MAKE_UNIQUE,
+ "Material Name Collision",
+ "Behavior when the name of an imported material conflicts with an existing material");
}
#endif /* WITH_USD */
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index d10c420e28c..df30870007f 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -31,7 +31,9 @@
#include "mask_intern.h" /* own include */
-/******************** add vertex *********************/
+/* -------------------------------------------------------------------- */
+/** \name Add Vertex
+ * \{ */
static void setup_vertex_point(Mask *mask,
MaskSpline *spline,
@@ -160,7 +162,11 @@ static void setup_vertex_point(Mask *mask,
ED_mask_select_flush_all(mask);
}
-/* **** add extrude vertex **** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Extrude Vertex
+ * \{ */
static void finSelectedSplinePoint(MaskLayer *mask_layer,
MaskSpline **spline,
@@ -206,7 +212,11 @@ static void finSelectedSplinePoint(MaskLayer *mask_layer,
}
}
-/* **** add subdivide vertex **** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Subdivide Vertex
+ * \{ */
static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
{
@@ -248,7 +258,7 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
&u,
NULL)) {
Scene *scene = CTX_data_scene(C);
- const float ctime = CFRA;
+ const float ctime = scene->r.cfra;
MaskSplinePoint *new_point;
int point_index = point - spline->points;
@@ -285,7 +295,7 @@ static bool add_vertex_extrude(const bContext *C,
const float co[2])
{
Scene *scene = CTX_data_scene(C);
- const float ctime = CFRA;
+ const float ctime = scene->r.cfra;
MaskSpline *spline;
MaskSplinePoint *point;
@@ -384,13 +394,13 @@ static bool add_vertex_extrude(const bContext *C,
static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *mask_layer, const float co[2])
{
Scene *scene = CTX_data_scene(C);
- const float ctime = CFRA;
+ const float ctime = scene->r.cfra;
MaskSpline *spline;
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
if (!mask_layer) {
- /* if there's no mask layer currently operationg on, create new one */
+ /* If there's no mask layer currently operating on, create new one. */
mask_layer = BKE_mask_layer_new(mask, "");
mask->masklay_act = mask->masklay_tot - 1;
}
@@ -492,6 +502,12 @@ static int add_vertex_handle_cyclic(
return OPERATOR_PASS_THROUGH;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Vertex Operator
+ * \{ */
+
static int add_vertex_exec(bContext *C, wmOperator *op)
{
MaskViewLockState lock_state;
@@ -567,7 +583,7 @@ void MASK_OT_add_vertex(wmOperatorType *ot)
/* api callbacks */
ot->exec = add_vertex_exec;
ot->invoke = add_vertex_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -585,7 +601,11 @@ void MASK_OT_add_vertex(wmOperatorType *ot)
1.0f);
}
-/******************** add feather vertex *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Feather Vertex Operator
+ * \{ */
static int add_feather_vertex_exec(bContext *C, wmOperator *op)
{
@@ -677,7 +697,11 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot)
1.0f);
}
-/******************** common primitive functions *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Common Primitive Functions
+ * \{ */
static BezTriple *points_to_bezier(const float (*points)[2],
const int num_points,
@@ -812,7 +836,11 @@ static void define_primitive_add_properties(wmOperatorType *ot)
FLT_MAX);
}
-/******************** primitive add circle *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Add Circle Operator
+ * \{ */
static int primitive_circle_add_exec(bContext *C, wmOperator *op)
{
@@ -834,7 +862,7 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = primitive_circle_add_exec;
ot->invoke = primitive_add_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -843,7 +871,11 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot)
define_primitive_add_properties(ot);
}
-/******************** primitive add suqare *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Add Square Operator
+ * \{ */
static int primitive_square_add_exec(bContext *C, wmOperator *op)
{
@@ -865,7 +897,7 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = primitive_square_add_exec;
ot->invoke = primitive_add_invoke;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -873,3 +905,5 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot)
/* properties */
define_primitive_add_properties(ot);
}
+
+/** \} */
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index aab4007854f..4c01154ba49 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -171,12 +171,10 @@ static void draw_single_handle(const MaskLayer *mask_layer,
static void draw_spline_points(const bContext *C,
MaskLayer *mask_layer,
MaskSpline *spline,
- const char draw_flag,
const char draw_type)
{
const bool is_spline_sel = (spline->flag & SELECT) &&
(mask_layer->visibility_flag & MASK_HIDE_SELECT) == 0;
- const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
uchar rgb_spline[4];
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
@@ -253,9 +251,7 @@ static void draw_spline_points(const bContext *C,
immUnbindProgram();
- if (is_smooth) {
- GPU_line_smooth(true);
- }
+ GPU_line_smooth(true);
/* control points */
INIT_MINMAX2(min, max);
@@ -323,9 +319,7 @@ static void draw_spline_points(const bContext *C,
minmax_v2v2_v2(min, max, vert);
}
- if (is_smooth) {
- GPU_line_smooth(false);
- }
+ GPU_line_smooth(false);
if (is_spline_sel) {
float x = (min[0] + max[0]) * 0.5f;
@@ -502,7 +496,6 @@ static void mask_draw_curve_type(const bContext *C,
static void draw_spline_curve(const bContext *C,
MaskLayer *mask_layer,
MaskSpline *spline,
- const char draw_flag,
const char draw_type,
const bool is_active,
const int width,
@@ -515,7 +508,6 @@ static void draw_spline_curve(const bContext *C,
const bool is_spline_sel = (spline->flag & SELECT) &&
(mask_layer->visibility_flag & MASK_HIDE_SELECT) == 0;
- const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
uint tot_diff_point;
@@ -530,9 +522,7 @@ static void draw_spline_curve(const bContext *C,
return;
}
- if (is_smooth) {
- GPU_line_smooth(true);
- }
+ GPU_line_smooth(true);
feather_points = BKE_mask_spline_feather_differentiated_points_with_resolution(
spline, resol, (is_fill != false), &tot_feather_point);
@@ -567,14 +557,11 @@ static void draw_spline_curve(const bContext *C,
C, spline, diff_points, tot_diff_point, false, is_active, rgb_tmp, draw_type);
MEM_freeN(diff_points);
- if (is_smooth) {
- GPU_line_smooth(false);
- }
+ GPU_line_smooth(false);
}
static void draw_layer_splines(const bContext *C,
MaskLayer *layer,
- const char draw_flag,
const char draw_type,
const int width,
const int height,
@@ -582,11 +569,11 @@ static void draw_layer_splines(const bContext *C,
{
LISTBASE_FOREACH (MaskSpline *, spline, &layer->splines) {
/* draw curve itself first... */
- draw_spline_curve(C, layer, spline, draw_flag, draw_type, is_active, width, height);
+ draw_spline_curve(C, layer, spline, 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);
+ draw_spline_points(C, layer, spline, draw_type);
}
/* show undeform for testing */
@@ -594,19 +581,15 @@ static void draw_layer_splines(const bContext *C,
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);
+ draw_spline_curve(C, layer, spline, draw_type, is_active, width, height);
+ draw_spline_points(C, layer, spline, draw_type);
spline->points_deform = back;
}
}
}
-static void draw_mask_layers(const bContext *C,
- Mask *mask,
- const char draw_flag,
- const char draw_type,
- const int width,
- const int height)
+static void draw_mask_layers(
+ const bContext *C, Mask *mask, const char draw_type, const int width, const int height)
{
GPU_blend(GPU_BLEND_ALPHA);
GPU_program_point_size(true);
@@ -628,11 +611,11 @@ static void draw_mask_layers(const bContext *C,
continue;
}
- draw_layer_splines(C, mask_layer, draw_flag, draw_type, width, height, is_active);
+ draw_layer_splines(C, mask_layer, draw_type, width, height, is_active);
}
if (active != NULL) {
- draw_layer_splines(C, active, draw_flag, draw_type, width, height, true);
+ draw_layer_splines(C, active, draw_type, width, height, true);
}
GPU_program_point_size(false);
@@ -663,6 +646,7 @@ void ED_mask_draw_region(
const char draw_flag,
const char draw_type,
const eMaskOverlayMode overlay_mode,
+ const float blend_factor,
/* convert directly into aspect corrected vars */
const int width_i,
const int height_i,
@@ -721,12 +705,14 @@ void ED_mask_draw_region(
}
if (draw_flag & MASK_DRAWFLAG_OVERLAY) {
- const float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
+ float buf_col[4] = {1.0f, 0.0f, 0.0f, 0.0f};
float *buffer = mask_rasterize(mask_eval, width, height);
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
/* More blending types could be supported in the future. */
- GPU_blend(GPU_BLEND_MULTIPLY);
+ GPU_blend(GPU_BLEND_ALPHA);
+ buf_col[0] = -1.0f;
+ buf_col[3] = 1.0f;
}
GPU_matrix_push();
@@ -737,10 +723,18 @@ 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);
- immDrawPixelsTexTiled(
- &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, buf_col);
+
+ if (overlay_mode == MASK_OVERLAY_COMBINED) {
+ const float blend_col[4] = {0.0f, 0.0f, 0.0f, blend_factor};
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, blend_col);
+ }
+ else {
+ immDrawPixelsTexTiled(
+ &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL);
+ }
GPU_matrix_pop();
if (overlay_mode != MASK_OVERLAY_ALPHACHANNEL) {
@@ -765,7 +759,9 @@ void ED_mask_draw_region(
}
/* draw! */
- draw_mask_layers(C, mask_eval, draw_flag, draw_type, width, height);
+ if (draw_flag & MASK_DRAWFLAG_SPLINE) {
+ draw_mask_layers(C, mask_eval, draw_type, width, height);
+ }
if (do_draw_cb) {
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
@@ -806,7 +802,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, scene->r.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_edit.c b/source/blender/editors/mask/mask_edit.c
index b2d49bcc642..915f90a1537 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -42,6 +42,22 @@ bool ED_maskedit_poll(bContext *C)
return false;
}
+bool ED_maskedit_visible_splines_poll(bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
+ case SPACE_CLIP:
+ return ED_space_clip_maskedit_visible_splines_poll(C);
+ case SPACE_SEQ:
+ return ED_space_sequencer_maskedit_poll(C);
+ case SPACE_IMAGE:
+ return ED_space_image_maskedit_visible_splines_poll(C);
+ }
+ }
+ return false;
+}
+
bool ED_maskedit_mask_poll(bContext *C)
{
ScrArea *area = CTX_wm_area(C);
@@ -58,6 +74,22 @@ bool ED_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ const ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
+ case SPACE_CLIP:
+ return ED_space_clip_maskedit_mask_visible_splines_poll(C);
+ case SPACE_SEQ:
+ return ED_space_sequencer_maskedit_mask_poll(C);
+ case SPACE_IMAGE:
+ return ED_space_image_maskedit_mask_visible_splines_poll(C);
+ }
+ }
+ return false;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index 8a23a53a5d2..9819532224e 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -304,7 +304,7 @@ static bool snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *
static bool snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
{
if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
- mask_layer_shape->frame = (int)CFRA;
+ mask_layer_shape->frame = (int)scene->r.cfra;
}
return false;
}
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index c620d781c7f..2e99b45f215 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -86,9 +86,6 @@ 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);
-
/* Generalized solution for preserving editor viewport when making changes while lock-to-selection
* is enabled.
* Any mask operator can use this API, without worrying that some editors do not have an idea of
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 3c0e7ee399c..d34b274c111 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -113,7 +113,7 @@ void MASK_OT_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_new_exec;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_poll;
/* properties */
RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask");
@@ -146,7 +146,7 @@ void MASK_OT_layer_new(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_layer_new_exec;
- ot->poll = ED_maskedit_poll;
+ ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -181,7 +181,7 @@ void MASK_OT_layer_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_layer_remove_exec;
- ot->poll = ED_maskedit_poll;
+ ot->poll = ED_maskedit_mask_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -856,7 +856,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Don't key sliding feather UW's. */
if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == false) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(data->mask_layer, CFRA);
+ ED_mask_layer_shape_auto_key(data->mask_layer, scene->r.cfra);
}
}
@@ -907,7 +907,7 @@ void MASK_OT_slide_point(wmOperatorType *ot)
/* api callbacks */
ot->invoke = slide_point_invoke;
ot->modal = slide_point_modal;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1262,7 +1262,7 @@ static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEve
if (event->type == slide_data->event_invoke_type && event->val == KM_RELEASE) {
/* Don't key sliding feather UW's. */
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(slide_data->mask_layer, CFRA);
+ ED_mask_layer_shape_auto_key(slide_data->mask_layer, scene->r.cfra);
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
@@ -1297,7 +1297,7 @@ void MASK_OT_slide_spline_curvature(wmOperatorType *ot)
/* api callbacks */
ot->invoke = slide_spline_curvature_invoke;
ot->modal = slide_spline_curvature_modal;
- ot->poll = ED_operator_mask;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1336,7 +1336,7 @@ void MASK_OT_cyclic_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = cyclic_toggle_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1493,7 +1493,7 @@ void MASK_OT_delete(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = delete_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1525,7 +1525,7 @@ static int mask_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
if (changed_layer) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(mask_layer, CFRA);
+ ED_mask_layer_shape_auto_key(mask_layer, scene->r.cfra);
}
}
}
@@ -1551,7 +1551,7 @@ void MASK_OT_switch_direction(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_switch_direction_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1587,7 +1587,7 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
if (changed_layer) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(mask_layer, CFRA);
+ ED_mask_layer_shape_auto_key(mask_layer, scene->r.cfra);
}
}
}
@@ -1613,7 +1613,7 @@ void MASK_OT_normals_make_consistent(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_normals_make_consistent_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1693,7 +1693,7 @@ void MASK_OT_handle_type_set(wmOperatorType *ot)
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = set_handle_type_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1849,7 +1849,7 @@ void MASK_OT_feather_weight_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_feather_weight_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2043,7 +2043,7 @@ void MASK_OT_duplicate(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_duplicate_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2084,7 +2084,7 @@ void MASK_OT_copy_splines(wmOperatorType *ot)
static bool paste_splines_poll(bContext *C)
{
- if (ED_maskedit_mask_poll(C)) {
+ if (ED_maskedit_mask_visible_splines_poll(C)) {
return BKE_mask_clipboard_is_empty() == false;
}
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index 89524a7b9e2..bb865e925d7 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -615,7 +615,7 @@ bool ED_mask_selected_minmax(const bContext *C,
/* Use evaluated mask to take animation into account.
* The animation of splies is not "flushed" back to original, so need to explicitly
- * sue evaluated datablock here. */
+ * use evaluated datablock here. */
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask->id);
INIT_MINMAX2(min, max);
@@ -682,8 +682,7 @@ void ED_mask_get_size(ScrArea *area, int *width, int *height)
}
case SPACE_SEQ: {
// Scene *scene = CTX_data_scene(C);
- // *width = (scene->r.size * scene->r.xsch) / 100;
- // *height = (scene->r.size * scene->r.ysch) / 100;
+ // BKE_render_resolution(&scene->r, false, width, height);
break;
}
case SPACE_IMAGE: {
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 9d8b84de66b..1f175ce51fc 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -21,6 +21,7 @@
#include "WM_types.h"
#include "ED_clip.h" /* frame remapping functions */
+#include "ED_mask.h"
#include "ED_screen.h"
#include "mask_intern.h" /* own include */
@@ -61,7 +62,7 @@ void MASK_OT_parent_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_parent_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 7c0b6fb0a93..95cad3f54ca 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -31,8 +31,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "DEG_depsgraph.h"
-
#include "mask_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -222,7 +220,7 @@ void MASK_OT_select_all(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_all_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -364,12 +362,9 @@ static int select_exec(bContext *C, wmOperator *op)
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
if (deselect_all) {
- /* For clip editor tracks, leave deselect all to clip editor. */
- if (!ED_clip_can_select(C)) {
- ED_mask_deselect_all(C);
- ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
- }
+ ED_mask_deselect_all(C);
+ ED_mask_view_lock_state_restore_no_jump(C, &lock_state);
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
return OPERATOR_PASS_THROUGH;
@@ -401,7 +396,7 @@ void MASK_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->exec = select_exec;
ot->invoke = select_invoke;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
ot->get_name = ED_select_pick_get_name;
/* flags */
@@ -507,7 +502,7 @@ void MASK_OT_select_box(wmOperatorType *ot)
ot->invoke = WM_gesture_box_invoke;
ot->exec = box_select_exec;
ot->modal = WM_gesture_box_modal;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_UNDO;
@@ -630,7 +625,7 @@ void MASK_OT_select_lasso(wmOperatorType *ot)
ot->invoke = WM_gesture_lasso_invoke;
ot->modal = WM_gesture_lasso_modal;
ot->exec = clip_lasso_select_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
ot->cancel = WM_gesture_lasso_cancel;
/* flags */
@@ -748,7 +743,7 @@ void MASK_OT_select_circle(wmOperatorType *ot)
ot->invoke = WM_gesture_circle_invoke;
ot->modal = WM_gesture_circle_modal;
ot->exec = circle_select_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
ot->get_name = ED_select_circle_get_name;
/* flags */
@@ -812,7 +807,7 @@ void MASK_OT_select_linked_pick(wmOperatorType *ot)
/* api callbacks */
ot->invoke = mask_select_linked_pick_invoke;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -867,7 +862,7 @@ void MASK_OT_select_linked(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_linked_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -966,7 +961,7 @@ void MASK_OT_select_more(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_more_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -986,7 +981,7 @@ void MASK_OT_select_less(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_select_less_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index dd54d84a90b..48944c081a8 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -33,7 +33,7 @@
static int mask_shape_key_insert_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- const int frame = CFRA;
+ const int frame = scene->r.cfra;
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
@@ -67,7 +67,7 @@ void MASK_OT_shape_key_insert(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_insert_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -76,7 +76,7 @@ void MASK_OT_shape_key_insert(wmOperatorType *ot)
static int mask_shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- const int frame = CFRA;
+ const int frame = scene->r.cfra;
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
@@ -113,7 +113,7 @@ void MASK_OT_shape_key_clear(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_clear_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -122,7 +122,7 @@ void MASK_OT_shape_key_clear(wmOperatorType *ot)
static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- const int frame = CFRA;
+ const int frame = scene->r.cfra;
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
@@ -197,7 +197,7 @@ void MASK_OT_shape_key_feather_reset(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_feather_reset_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -214,7 +214,7 @@ void MASK_OT_shape_key_feather_reset(wmOperatorType *ot)
static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- const int frame = CFRA;
+ const int frame = scene->r.cfra;
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
@@ -356,7 +356,7 @@ void MASK_OT_shape_key_rekey(wmOperatorType *ot)
/* api callbacks */
ot->exec = mask_shape_key_rekey_exec;
- ot->poll = ED_maskedit_mask_poll;
+ ot->poll = ED_maskedit_mask_visible_splines_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc
index cb5d48d1023..b69cd8b8606 100644
--- a/source/blender/editors/mesh/editface.cc
+++ b/source/blender/editors/mesh/editface.cc
@@ -158,7 +158,7 @@ void paintface_reveal(bContext *C, Object *ob, const bool select)
paintface_flush_flags(C, ob, SELECT | ME_HIDE);
}
-/* Set tface seams based on edge data, uses hash table to find seam edges. */
+/* Set object-mode face selection seams based on edge data, uses hash table to find seam edges. */
static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bool select)
{
@@ -551,3 +551,54 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags)
paintvert_flush_flags(ob);
}
}
+
+void paintvert_hide(bContext *C, Object *ob, const bool unselected)
+{
+ Mesh *const me = BKE_mesh_from_object(ob);
+
+ if (me == NULL || me->totvert == 0) {
+ return;
+ }
+
+ for (int i = 0; i < me->totvert; i++) {
+ MVert *const mvert = &me->mvert[i];
+
+ if ((mvert->flag & ME_HIDE) == 0) {
+ if (((mvert->flag & SELECT) == 0) == unselected) {
+ mvert->flag |= ME_HIDE;
+ }
+ }
+
+ if (mvert->flag & ME_HIDE) {
+ mvert->flag &= ~SELECT;
+ }
+ }
+
+ BKE_mesh_flush_hidden_from_verts(me);
+
+ paintvert_flush_flags(ob);
+ paintvert_tag_select_update(C, ob);
+}
+
+void paintvert_reveal(bContext *C, Object *ob, const bool select)
+{
+ Mesh *const me = BKE_mesh_from_object(ob);
+
+ if (me == NULL || me->totvert == 0) {
+ return;
+ }
+
+ for (int i = 0; i < me->totvert; i++) {
+ MVert *const mvert = &me->mvert[i];
+
+ if (mvert->flag & ME_HIDE) {
+ SET_FLAG_FROM_TEST(mvert->flag, select, SELECT);
+ mvert->flag &= ~ME_HIDE;
+ }
+ }
+
+ BKE_mesh_flush_hidden_from_verts(me);
+
+ paintvert_flush_flags(ob);
+ paintvert_tag_select_update(C, ob);
+}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 969d5b5912c..e7891450bd6 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -669,7 +669,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
short etype = event->type;
short eval = event->val;
- /* When activated from toolbar, need to convert leftmouse release to confirm */
+ /* When activated from toolbar, need to convert left-mouse release to confirm. */
if (ELEM(etype, LEFTMOUSE, opdata->launch_event) && (eval == KM_RELEASE) &&
RNA_boolean_get(op->ptr, "release_confirm")) {
etype = EVT_MODAL_MAP;
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 8d63b1ea020..330008d92d1 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -702,7 +702,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
const bool rot_src = RNA_boolean_get(op->ptr, "rotate_source");
const bool use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
- (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
+ (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE_RAYCAST));
/* First calculate the center of transformation. */
zero_v3(center);
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 7972459e457..5680865ae67 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1310,7 +1310,7 @@ static void knife_bvh_raycast_cb(void *userdata,
const BVHTreeRay *ray,
BVHTreeRayHit *hit)
{
- if (index != -1) {
+ if (index == -1) {
return;
}
@@ -1355,13 +1355,19 @@ static void knife_bvh_raycast_cb(void *userdata,
#endif
if (isect && dist < hit->dist) {
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+
+ /* Discard clipped points. */
+ if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) &&
+ ED_view3d_clipping_test(kcd->vc.rv3d, hit->co, false)) {
+ return;
+ }
+
hit->dist = dist;
hit->index = index;
copy_v3_v3(hit->no, ltri[0]->f->no);
- madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
-
kcd->bvh.looptris = em->looptris;
copy_v2_v2(kcd->bvh.uv, uv);
kcd->bvh.base_index = b;
@@ -4672,6 +4678,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE: /* Mouse moved somewhere to select another loop. */
if (kcd->mode != MODE_PANNING) {
knifetool_update_mval_i(kcd, event->mval);
+ knife_update_header(C, op, kcd);
if (kcd->is_drag_hold) {
if (kcd->totlinehit >= 2) {
@@ -4754,6 +4761,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* We don't really need to update mval,
* but this happens to be the best way to refresh at the moment. */
knifetool_update_mval_i(kcd, event->mval);
+ knife_update_header(C, op, kcd);
}
/* Keep going until the user confirms. */
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index 3f05c27e8fa..c931cb4948b 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -1370,8 +1370,14 @@ static bool edbm_select_similar_poll_property(const bContext *UNUSED(C),
const char *prop_id = RNA_property_identifier(prop);
const int type = RNA_enum_get(op->ptr, "type");
+ /* Only show compare when it is used. */
+ if (STREQ(prop_id, "compare")) {
+ if (type == SIMVERT_VGROUP) {
+ return false;
+ }
+ }
/* Only show threshold when it is used. */
- if (STREQ(prop_id, "threshold")) {
+ else if (STREQ(prop_id, "threshold")) {
if (!ELEM(type,
SIMVERT_NORMAL,
SIMEDGE_BEVEL,
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index feecefdb7ea..1febc429edc 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3092,8 +3092,8 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
BMOperator bmop;
- Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const Mesh *me = BKE_object_get_original_mesh(ob);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
continue;
@@ -3144,8 +3144,8 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
continue;
}
- Mesh *me = BKE_object_get_original_mesh(obedit);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const Mesh *me = BKE_object_get_original_mesh(obedit);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) {
continue;
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index ecc5f8f8ef5..d75c92f963f 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -72,7 +72,7 @@ static CLG_LogRef LOG = {"ed.undo.mesh"};
/* Single linked list of layers stored per type */
typedef struct BArrayCustomData {
struct BArrayCustomData *next;
- CustomDataType type;
+ eCustomDataType type;
int states_len; /* number of layers for each type */
BArrayState *states[0];
} BArrayCustomData;
@@ -149,7 +149,7 @@ static void um_arraystore_cd_compact(struct CustomData *cdata,
const BArrayCustomData *bcd_reference_current = bcd_reference;
BArrayCustomData *bcd = NULL, *bcd_first = NULL, *bcd_prev = NULL;
for (int layer_start = 0, layer_end; layer_start < cdata->totlayer; layer_start = layer_end) {
- const CustomDataType type = cdata->layers[layer_start].type;
+ const eCustomDataType type = cdata->layers[layer_start].type;
/* Perform a full copy on dynamic layers.
*
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index c7c7e5cf2f8..ac5530c8ea9 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -593,13 +593,143 @@ UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
return vmap->vert[v];
}
+#define INVALID_ISLAND ((unsigned int)-1)
+
+static void bm_uv_assign_island(UvElementMap *element_map,
+ UvElement *element,
+ int nisland,
+ uint *map,
+ UvElement *islandbuf,
+ int islandbufsize)
+{
+ element->island = nisland;
+ map[element - element_map->buf] = islandbufsize;
+
+ /* Copy *element to islandbuf[islandbufsize]. */
+ islandbuf[islandbufsize].l = element->l;
+ islandbuf[islandbufsize].separate = element->separate;
+ islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index;
+ islandbuf[islandbufsize].island = element->island;
+ islandbuf[islandbufsize].flag = element->flag;
+}
+
+static int bm_uv_edge_select_build_islands(UvElementMap *element_map,
+ const Scene *scene,
+ UvElement *islandbuf,
+ uint *map,
+ bool uv_selected,
+ int cd_loop_uv_offset)
+{
+ int totuv = element_map->totalUVs;
+
+ /* For each UvElement, locate the "separate" UvElement that precedes it in the linked list. */
+ UvElement **head_table = MEM_mallocN(sizeof(*head_table) * totuv, "uv_island_head_table");
+ for (int i = 0; i < totuv; i++) {
+ UvElement *head = element_map->buf + i;
+ if (head->separate) {
+ UvElement *element = head;
+ while (element) {
+ head_table[element - element_map->buf] = head;
+ element = element->next;
+ if (element && element->separate) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Depth first search the graph, building islands as we go. */
+ int nislands = 0;
+ int islandbufsize = 0;
+ int stack_upper_bound = totuv;
+ UvElement **stack_uv = MEM_mallocN(sizeof(*stack_uv) * stack_upper_bound,
+ "uv_island_element_stack");
+ int stacksize_uv = 0;
+ for (int i = 0; i < totuv; i++) {
+ UvElement *element = element_map->buf + i;
+ if (element->island != INVALID_ISLAND) {
+ /* Unique UV (element and all it's children) are already part of an island. */
+ continue;
+ }
+
+ /* Create a new island, i.e. nislands++. */
+
+ BLI_assert(element->separate); /* Ensure we're the head of this unique UV. */
+
+ /* Seed the graph search. */
+ stack_uv[stacksize_uv++] = element;
+ while (element) {
+ bm_uv_assign_island(element_map, element, nislands, map, islandbuf, islandbufsize++);
+ element = element->next;
+ if (element && element->separate) {
+ break;
+ }
+ }
+
+ /* Traverse the graph. */
+ while (stacksize_uv) {
+ BLI_assert(stacksize_uv < stack_upper_bound);
+ element = stack_uv[--stacksize_uv];
+ while (element) {
+
+ /* Scan forwards around the BMFace that contains element->l. */
+ if (!uv_selected || uvedit_edge_select_test(scene, element->l, cd_loop_uv_offset)) {
+ UvElement *next = BM_uv_element_get(element_map, element->l->next->f, element->l->next);
+ if (next->island == INVALID_ISLAND) {
+ UvElement *tail = head_table[next - element_map->buf];
+ stack_uv[stacksize_uv++] = tail;
+ while (tail) {
+ bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++);
+ tail = tail->next;
+ if (tail && tail->separate) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Scan backwards around the BMFace that contains element->l. */
+ if (!uv_selected || uvedit_edge_select_test(scene, element->l->prev, cd_loop_uv_offset)) {
+ UvElement *prev = BM_uv_element_get(element_map, element->l->prev->f, element->l->prev);
+ if (prev->island == INVALID_ISLAND) {
+ UvElement *tail = head_table[prev - element_map->buf];
+ stack_uv[stacksize_uv++] = tail;
+ while (tail) {
+ bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++);
+ tail = tail->next;
+ if (tail && tail->separate) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* The same for all the UvElements in this unique UV. */
+ element = element->next;
+ if (element && element->separate) {
+ break;
+ }
+ }
+ }
+ nislands++;
+ }
+ BLI_assert(islandbufsize == totuv);
+
+ MEM_SAFE_FREE(stack_uv);
+ MEM_SAFE_FREE(head_table);
+
+ return nislands;
+}
+
UvElementMap *BM_uv_element_map_create(BMesh *bm,
const Scene *scene,
- const bool face_selected,
const bool uv_selected,
const bool use_winding,
const bool do_islands)
{
+ /* In uv sync selection, all UVs are visible. */
+ const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
+
BMVert *ev;
BMFace *efa;
BMLoop *l;
@@ -623,15 +753,21 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
/* generate UvElement array */
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- if (!uv_selected) {
- totuv += efa->len;
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- totuv++;
- }
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+
+ if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ continue;
+ }
+
+ if (!uv_selected) {
+ totuv += efa->len;
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ totuv++;
}
}
}
@@ -649,46 +785,48 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
"UvElement");
if (use_winding) {
- winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding");
+ winding = MEM_callocN(sizeof(*winding) * totfaces, "winding");
}
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
- if (use_winding) {
- winding[j] = false;
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ continue;
}
- if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- float(*tf_uv)[2] = NULL;
-
- if (use_winding) {
- tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
- }
+ if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ continue;
+ }
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- continue;
- }
+ float(*tf_uv)[2] = NULL;
- buf->l = l;
- buf->separate = 0;
- buf->island = INVALID_ISLAND;
- buf->loop_of_poly_index = i;
+ if (use_winding) {
+ tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
+ }
- buf->next = element_map->vert[BM_elem_index_get(l->v)];
- element_map->vert[BM_elem_index_get(l->v)] = buf;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
- if (use_winding) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(tf_uv[i], luv->uv);
- }
+ buf->l = l;
+ buf->separate = 0;
+ buf->island = INVALID_ISLAND;
+ buf->loop_of_poly_index = i;
- buf++;
- }
+ buf->next = element_map->vert[BM_elem_index_get(l->v)];
+ element_map->vert[BM_elem_index_get(l->v)] = buf;
if (use_winding) {
- winding[j] = cross_poly_v2(tf_uv, efa->len) > 0;
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(tf_uv[i], luv->uv);
}
+
+ buf++;
+ }
+
+ if (winding) {
+ winding[j] = cross_poly_v2(tf_uv, efa->len) > 0;
}
}
@@ -771,6 +909,15 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face");
copy_vn_i(island_number, totfaces, INVALID_ISLAND);
+ const bool use_uv_edge_connectivity = scene->toolsettings->uv_flag & UV_SYNC_SELECTION ?
+ scene->toolsettings->selectmode & SCE_SELECT_EDGE :
+ scene->toolsettings->uv_selectmode & UV_SELECT_EDGE;
+ if (use_uv_edge_connectivity) {
+ nislands = bm_uv_edge_select_build_islands(
+ element_map, scene, islandbuf, map, uv_selected, cd_loop_uv_offset);
+ islandbufsize = totuv;
+ }
+
/* at this point, every UvElement in vert points to a UvElement sharing the same vertex.
* Now we should sort uv's in islands. */
for (i = 0; i < totuv; i++) {
@@ -798,13 +945,8 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
if (element->l->f == efa) {
/* found the uv corresponding to our face and vertex.
* Now fill it to the buffer */
- element->island = nislands;
- map[element - element_map->buf] = islandbufsize;
- islandbuf[islandbufsize].l = element->l;
- islandbuf[islandbufsize].separate = element->separate;
- islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index;
- islandbuf[islandbufsize].island = nislands;
- islandbufsize++;
+ bm_uv_assign_island(
+ element_map, element, nislands, map, islandbuf, islandbufsize++);
for (element = initelement; element; element = element->next) {
if (element->separate && element != initelement) {
@@ -1641,21 +1783,23 @@ void EDBM_project_snap_verts(
float mval[2], co_proj[3];
if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) ==
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,
- .edit_mode_type = SNAP_GEOM_FINAL,
- .use_occlusion_test = true,
- },
- mval,
- NULL,
- NULL,
- co_proj,
- NULL)) {
+ if (ED_transform_snap_object_project_view3d(
+ snap_context,
+ depsgraph,
+ region,
+ CTX_wm_view3d(C),
+ SCE_SNAP_MODE_FACE_RAYCAST,
+ &(const struct SnapObjectParams){
+ .snap_target_select = SCE_SNAP_TARGET_NOT_ACTIVE,
+ .edit_mode_type = SNAP_GEOM_FINAL,
+ .use_occlusion_test = true,
+ },
+ NULL,
+ mval,
+ NULL,
+ NULL,
+ co_proj,
+ NULL)) {
mul_v3_m4v3(eve->co, obedit->imat, co_proj);
}
}
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 97376a495c1..a2f993c92b9 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -76,7 +76,6 @@ endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
add_definitions(-DWITH_POINT_CLOUD)
- add_definitions(-DWITH_NEW_CURVES_TYPE)
endif()
blender_add_lib(bf_editor_object "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc
index 422aaa03120..a8e11afba65 100644
--- a/source/blender/editors/object/object_add.cc
+++ b/source/blender/editors/object/object_add.cc
@@ -24,6 +24,7 @@
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_fluidsim_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
@@ -36,6 +37,7 @@
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -71,6 +73,7 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_nla.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcloud.h"
@@ -113,6 +116,10 @@
#include "object_intern.h"
+using blender::float3;
+using blender::float4x4;
+using blender::Vector;
+
/* -------------------------------------------------------------------- */
/** \name Local Enum Declarations
* \{ */
@@ -621,9 +628,16 @@ Object *ED_object_add_type_with_obdata(bContext *C,
else {
ob = BKE_object_add(bmain, view_layer, type, name);
}
- BASACT(view_layer)->local_view_bits = local_view_bits;
- /* editor level activate, notifiers */
- ED_object_base_activate(C, view_layer->basact);
+
+ Base *ob_base_act = BASACT(view_layer);
+ /* While not getting a valid base is not a good thing, it can happen in convoluted corner cases,
+ * better not crash on it in releases. */
+ BLI_assert(ob_base_act != nullptr);
+ if (ob_base_act != nullptr) {
+ ob_base_act->local_view_bits = local_view_bits;
+ /* editor level activate, notifiers */
+ ED_object_base_activate(C, ob_base_act);
+ }
/* more editor stuff */
ED_object_base_init_transform_on_add(ob, loc, rot);
@@ -1321,21 +1335,21 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
const char *ob_name = nullptr;
switch (type) {
case GP_EMPTY: {
- ob_name = "GPencil";
+ ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "GPencil");
break;
}
case GP_MONKEY: {
- ob_name = "Suzanne";
+ ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "Suzanne");
break;
}
case GP_STROKE: {
- ob_name = "Stroke";
+ ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "Stroke");
break;
}
case GP_LRT_OBJECT:
case GP_LRT_SCENE:
case GP_LRT_COLLECTION: {
- ob_name = "Line Art";
+ ob_name = CTX_DATA_(BLT_I18NCONTEXT_ID_GPENCIL, "LineArt");
break;
}
default: {
@@ -1977,7 +1991,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
AnimData *adt = BKE_animdata_ensure_id(&ob->id);
NlaTrack *nlt = BKE_nlatrack_add(adt, nullptr, is_liboverride);
NlaStrip *strip = BKE_nla_add_soundstrip(bmain, scene, static_cast<Speaker *>(ob->data));
- strip->start = CFRA;
+ strip->start = scene->r.cfra;
strip->end += strip->start;
/* hook them up */
@@ -2016,14 +2030,6 @@ void OBJECT_OT_speaker_add(wmOperatorType *ot)
/** \name Add Curves Operator
* \{ */
-static bool object_curves_add_poll(bContext *C)
-{
- if (!U.experimental.use_new_curves_type) {
- return false;
- }
- return ED_operator_objectmode(C);
-}
-
static int object_curves_random_add_exec(bContext *C, wmOperator *op)
{
using namespace blender;
@@ -2036,7 +2042,6 @@ static int object_curves_random_add_exec(bContext *C, wmOperator *op)
}
Object *object = ED_object_add_type(C, OB_CURVES, nullptr, loc, rot, false, local_view_bits);
- object->dtx |= OB_DRAWBOUNDOX; /* TODO: remove once there is actual drawing. */
Curves *curves_id = static_cast<Curves *>(object->data);
bke::CurvesGeometry::wrap(curves_id->geometry) = ed::curves::primitive_random_sphere(500, 8);
@@ -2053,7 +2058,7 @@ void OBJECT_OT_curves_random_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_curves_random_add_exec;
- ot->poll = object_curves_add_poll;
+ ot->poll = ED_operator_objectmode;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2063,32 +2068,47 @@ void OBJECT_OT_curves_random_add(wmOperatorType *ot)
static int object_curves_empty_hair_add_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
+
ushort local_view_bits;
- float loc[3], rot[3];
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, nullptr, nullptr, &local_view_bits, nullptr)) {
+ C, op, 'Z', nullptr, nullptr, nullptr, nullptr, &local_view_bits, nullptr)) {
return OPERATOR_CANCELLED;
}
Object *surface_ob = CTX_data_active_object(C);
+ BLI_assert(surface_ob != nullptr);
- Object *object = ED_object_add_type(C, OB_CURVES, nullptr, loc, rot, false, local_view_bits);
- object->dtx |= OB_DRAWBOUNDOX; /* TODO: remove once there is actual drawing. */
+ Object *curves_ob = ED_object_add_type(C, OB_CURVES, nullptr, nullptr, nullptr, false, local_view_bits);
+ BKE_object_apply_mat4(curves_ob, surface_ob->obmat, false, false);
+
+ /* Set surface object. */
+ Curves *curves_id = static_cast<Curves *>(curves_ob->data);
+ curves_id->surface = surface_ob;
- if (surface_ob != nullptr && surface_ob->type == OB_MESH) {
- Curves *curves_id = static_cast<Curves *>(object->data);
- curves_id->surface = surface_ob;
- id_us_plus(&surface_ob->id);
+ /* Parent to surface object. */
+ ED_object_parent_set(
+ op->reports, C, scene, curves_ob, surface_ob, PAR_OBJECT, false, true, nullptr);
+
+ /* Decide which UV map to use for attachment. */
+ Mesh *surface_mesh = static_cast<Mesh *>(surface_ob->data);
+ const char *uv_name = CustomData_get_active_layer_name(&surface_mesh->ldata, CD_MLOOPUV);
+ if (uv_name != nullptr) {
+ curves_id->surface_uv_map = BLI_strdup(uv_name);
}
+ /* Add deformation modifier. */
+ blender::ed::curves::ensure_surface_deformation_node_exists(*C, *curves_ob);
+
+ /* Make sure the surface object has a rest position attribute which is necessary for
+ * deformations. */
+ surface_ob->modifier_flag |= OB_MODIFIER_FLAG_ADD_REST_POSITION;
+
return OPERATOR_FINISHED;
}
static bool object_curves_empty_hair_add_poll(bContext *C)
{
- if (!U.experimental.use_new_curves_type) {
- return false;
- }
if (!ED_operator_objectmode(C)) {
return false;
}
@@ -2750,28 +2770,6 @@ static const EnumPropertyItem convert_target_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
-static const EnumPropertyItem *convert_target_items_fn(bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
-{
- EnumPropertyItem *items = nullptr;
- int items_num = 0;
- for (const EnumPropertyItem *item = convert_target_items; item->identifier != nullptr; item++) {
- if (item->value == OB_CURVES) {
- if (U.experimental.use_new_curves_type) {
- RNA_enum_item_add(&items, &items_num, item);
- }
- }
- else {
- RNA_enum_item_add(&items, &items_num, item);
- }
- }
- RNA_enum_item_end(&items, &items_num);
- *r_free = true;
- return items;
-}
-
static void object_data_convert_ensure_curve_cache(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
if (ob->runtime.curve_cache == nullptr) {
@@ -3179,9 +3177,7 @@ static int object_convert_exec(bContext *C, wmOperator *op)
}
/* Anonymous attributes shouldn't be available on the applied geometry. */
- MeshComponent component;
- component.replace(new_mesh, GeometryOwnershipType::Editable);
- component.attributes_remove_anonymous();
+ blender::bke::mesh_attributes_for_write(*new_mesh).remove_anonymous();
BKE_object_free_modifiers(newob, 0); /* after derivedmesh calls! */
}
@@ -3531,7 +3527,6 @@ void OBJECT_OT_convert(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(
ot->srna, "target", convert_target_items, OB_MESH, "Target", "Type of object to convert to");
- RNA_def_enum_funcs(ot->prop, convert_target_items_fn);
RNA_def_boolean(ot->srna,
"keep_original",
false,
@@ -3587,7 +3582,8 @@ static Base *object_add_duplicate_internal(Main *bmain,
ViewLayer *view_layer,
Object *ob,
const eDupli_ID_Flags dupflag,
- const eLibIDDuplicateFlags duplicate_options)
+ const eLibIDDuplicateFlags duplicate_options,
+ Object **r_ob_new)
{
Base *base, *basen = nullptr;
Object *obn;
@@ -3598,6 +3594,9 @@ static Base *object_add_duplicate_internal(Main *bmain,
else {
obn = static_cast<Object *>(
ID_NEW_SET(ob, BKE_object_duplicate(bmain, ob, dupflag, duplicate_options)));
+ if (r_ob_new) {
+ *r_ob_new = obn;
+ }
DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
base = BKE_view_layer_base_find(view_layer, ob);
@@ -3610,7 +3609,7 @@ static Base *object_add_duplicate_internal(Main *bmain,
}
basen = BKE_view_layer_base_find(view_layer, obn);
- if (base != nullptr) {
+ if (base != nullptr && basen != nullptr) {
basen->local_view_bits = base->local_view_bits;
}
@@ -3641,7 +3640,8 @@ Base *ED_object_add_duplicate(
base->object,
dupflag,
LIB_ID_DUPLICATE_IS_SUBPROCESS |
- LIB_ID_DUPLICATE_IS_ROOT_ID);
+ LIB_ID_DUPLICATE_IS_ROOT_ID,
+ nullptr);
if (basen == nullptr) {
return nullptr;
}
@@ -3674,45 +3674,73 @@ static int duplicate_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
const bool linked = RNA_boolean_get(op->ptr, "linked");
const eDupli_ID_Flags dupflag = (linked) ? (eDupli_ID_Flags)0 : (eDupli_ID_Flags)U.dupflag;
- bool changed = false;
/* We need to handle that here ourselves, because we may duplicate several objects, in which case
* we also want to remap pointers between those... */
BKE_main_id_newptr_and_tag_clear(bmain);
+ /* Do not do collection re-syncs for each object; will do it once afterwards.
+ * However this means we can't get to new duplicated Base's immediately, will
+ * have to process them after the sync. */
+ BKE_layer_collection_resync_forbid();
+
+ /* Duplicate the selected objects, remember data needed to process
+ * after the sync (the base of the original object, and the copy of the
+ * original object). */
+ blender::Vector<std::pair<Base *, Object *>> source_bases_new_objects;
+ Object *ob_new_active = nullptr;
+
CTX_DATA_BEGIN (C, Base *, base, selected_bases) {
- Base *basen = object_add_duplicate_internal(bmain,
- scene,
- view_layer,
- base->object,
- dupflag,
- LIB_ID_DUPLICATE_IS_SUBPROCESS |
- LIB_ID_DUPLICATE_IS_ROOT_ID);
+ Object *ob_new = NULL;
+ object_add_duplicate_internal(bmain,
+ scene,
+ view_layer,
+ base->object,
+ dupflag,
+ LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID,
+ &ob_new);
+ if (ob_new == nullptr) {
+ continue;
+ }
+ source_bases_new_objects.append({base, ob_new});
/* note that this is safe to do with this context iterator,
* the list is made in advance */
ED_object_base_select(base, BA_DESELECT);
- ED_object_base_select(basen, BA_SELECT);
- changed = true;
- if (basen == nullptr) {
- continue;
- }
-
- /* new object becomes active */
+ /* new object will become active */
if (BASACT(view_layer) == base) {
- ED_object_base_activate(C, basen);
- }
-
- if (basen->object->data) {
- DEG_id_tag_update(static_cast<ID *>(basen->object->data), 0);
+ ob_new_active = ob_new;
}
}
CTX_DATA_END;
- if (!changed) {
+ if (source_bases_new_objects.is_empty()) {
return OPERATOR_CANCELLED;
}
+ /* Sync the collection now, after everything is duplicated. */
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync(bmain);
+
+ /* After sync we can get to the new Base data, process it here. */
+ for (const auto &item : source_bases_new_objects) {
+ Object *ob_new = item.second;
+ Base *base_source = item.first;
+ Base *base_new = BKE_view_layer_base_find(view_layer, ob_new);
+ if (base_new == nullptr) {
+ continue;
+ }
+ ED_object_base_select(base_new, BA_SELECT);
+ if (ob_new == ob_new_active) {
+ ED_object_base_activate(C, base_new);
+ }
+ if (base_new->object->data) {
+ DEG_id_tag_update(static_cast<ID *>(base_new->object->data), 0);
+ }
+ /* #object_add_duplicate_internal will not have done this, since
+ * before the collection sync it would not have found the new base yet. */
+ base_new->local_view_bits = base_source->local_view_bits;
+ }
/* Note that this will also clear newid pointers and tags. */
copy_object_set_idnew(C);
@@ -3795,7 +3823,8 @@ static int object_add_named_exec(bContext *C, wmOperator *op)
* 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);
+ LIB_ID_DUPLICATE_IS_SUBPROCESS | LIB_ID_DUPLICATE_IS_ROOT_ID,
+ nullptr);
if (basen == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Object could not be duplicated");
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 1483c24ac70..effbde41c38 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -220,22 +220,22 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
Mesh *me = (Mesh *)ob->data;
MultiresModifierData tmp_mmd = *mmd;
- DerivedMesh *cddm = CDDM_from_mesh(me);
- DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ *lvl = mmd->lvl;
if (mmd->lvl == 0) {
- dm = CDDM_copy(cddm);
- }
- else {
- tmp_mmd.lvl = mmd->lvl;
- tmp_mmd.sculptlvl = mmd->lvl;
- dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0);
+ DerivedMesh *cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ return cddm;
}
- cddm->release(cddm);
+ DerivedMesh *cddm = CDDM_from_mesh(me);
+ DM_set_only_copy(cddm, &CD_MASK_BAREMESH);
+ tmp_mmd.lvl = mmd->lvl;
+ tmp_mmd.sculptlvl = mmd->lvl;
+ dm = multires_make_derived_from_derived(cddm, &tmp_mmd, scene, ob, 0);
- *lvl = mmd->lvl;
+ cddm->release(cddm);
return dm;
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 114b2ce8102..a664d93bb2e 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -21,6 +21,8 @@
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BKE_attribute.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -322,7 +324,7 @@ static bool write_external_bake_pixels(const char *filepath,
const int height,
const int margin,
const int margin_type,
- ImageFormatData *im_format,
+ ImageFormatData const *im_format,
const bool is_noncolor,
Mesh const *mesh_eval,
char const *uv_layer,
@@ -446,14 +448,11 @@ static bool bake_object_check(ViewLayer *view_layer,
}
if (target == R_BAKE_TARGET_VERTEX_COLORS) {
- const MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- const MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
- if (mloopcol == NULL && !mcol_valid) {
+ if (BKE_id_attributes_active_color_get(&me->id) == NULL) {
BKE_reportf(reports,
RPT_ERROR,
- "No vertex colors layer found in the object \"%s\"",
- ob->id.name + 2);
+ "Mesh does not have an active color attribute \"%s\"",
+ me->id.name + 2);
return false;
}
}
@@ -937,17 +936,13 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr,
static bool bake_targets_init_vertex_colors(BakeTargets *targets, Object *ob, ReportList *reports)
{
if (ob->type != OB_MESH) {
- BKE_report(
- reports, RPT_ERROR, "Vertex color baking not support with object types other than mesh");
+ BKE_report(reports, RPT_ERROR, "Color attribute baking is only supported for mesh objects");
return false;
}
Mesh *me = ob->data;
- const MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- const MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
- if (mloopcol == NULL && !mcol_valid) {
- BKE_report(reports, RPT_ERROR, "No vertex colors layer found to bake to");
+ if (BKE_id_attributes_active_color_get(&me->id) == NULL) {
+ BKE_report(reports, RPT_ERROR, "No active color attribute to bake to");
return false;
}
@@ -996,10 +991,10 @@ static int find_original_loop(const Mesh *me_orig,
return ORIGINDEX_NONE;
}
-static void bake_targets_populate_pixels_vertex_colors(BakeTargets *targets,
- Object *ob,
- Mesh *me_eval,
- BakePixel *pixel_array)
+static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets,
+ Object *ob,
+ Mesh *me_eval,
+ BakePixel *pixel_array)
{
Mesh *me = ob->data;
const int pixels_num = targets->pixels_num;
@@ -1094,19 +1089,42 @@ static void bake_result_add_to_rgba(float rgba[4], const float *result, const in
}
}
+static void convert_float_color_to_byte_color(const MPropCol *float_colors,
+ const int num,
+ const bool is_noncolor,
+ MLoopCol *byte_colors)
+{
+ if (is_noncolor) {
+ for (int i = 0; i < num; i++) {
+ unit_float_to_uchar_clamp_v4(&byte_colors->r, float_colors[i].color);
+ }
+ }
+ else {
+ for (int i = 0; i < num; i++) {
+ linearrgb_to_srgb_uchar4(&byte_colors[i].r, float_colors[i].color);
+ }
+ }
+}
+
static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
{
Mesh *me = ob->data;
- MPropCol *mcol = CustomData_get_layer(&me->vdata, CD_PROP_COLOR);
- const bool mcol_valid = (mcol != NULL);
- MLoopCol *mloopcol = CustomData_get_layer(&me->ldata, CD_PROP_BYTE_COLOR);
+ CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
+ BLI_assert(active_color_layer != NULL);
+ const eAttrDomain domain = BKE_id_attribute_domain(&me->id, active_color_layer);
+
const int channels_num = targets->channels_num;
+ const bool is_noncolor = targets->is_noncolor;
const float *result = targets->result;
- if (mcol_valid) {
+ if (domain == ATTR_DOMAIN_POINT) {
const int totvert = me->totvert;
const int totloop = me->totloop;
+ MPropCol *mcol = active_color_layer->type == CD_PROP_COLOR ?
+ active_color_layer->data :
+ MEM_malloc_arrayN(totvert, sizeof(MPropCol), __func__);
+
/* Accumulate float vertex colors in scene linear color space. */
int *num_loops_for_vertex = MEM_callocN(sizeof(int) * me->totvert, "num_loops_for_vertex");
memset(mcol, 0, sizeof(MPropCol) * me->totvert);
@@ -1125,25 +1143,35 @@ static bool bake_targets_output_vertex_colors(BakeTargets *targets, Object *ob)
}
}
+ if (mcol != active_color_layer->data) {
+ convert_float_color_to_byte_color(mcol, totvert, is_noncolor, active_color_layer->data);
+ MEM_freeN(mcol);
+ }
+
MEM_SAFE_FREE(num_loops_for_vertex);
}
- else {
- /* Byte loop colors in sRGB colors space. */
- MLoop *mloop = me->mloop;
- const int totloop = me->totloop;
- const bool is_noncolor = targets->is_noncolor;
-
- for (int i = 0; i < totloop; i++, mloop++, mloopcol++) {
- float rgba[4];
- zero_v4(rgba);
- bake_result_add_to_rgba(rgba, &result[i * channels_num], channels_num);
-
- if (is_noncolor) {
- unit_float_to_uchar_clamp_v4(&mloopcol->r, rgba);
+ else if (domain == ATTR_DOMAIN_CORNER) {
+ switch (active_color_layer->type) {
+ case CD_PROP_COLOR: {
+ MPropCol *colors = active_color_layer->data;
+ for (int i = 0; i < me->totloop; i++) {
+ zero_v4(colors[i].color);
+ bake_result_add_to_rgba(colors[i].color, &result[i * channels_num], channels_num);
+ }
+ break;
}
- else {
- linearrgb_to_srgb_uchar4(&mloopcol->r, rgba);
+ case CD_PROP_BYTE_COLOR: {
+ MLoopCol *colors = active_color_layer->data;
+ for (int i = 0; i < me->totloop; i++) {
+ MPropCol color;
+ zero_v4(color.color);
+ bake_result_add_to_rgba(color.color, &result[i * channels_num], channels_num);
+ convert_float_color_to_byte_color(&color, 1, is_noncolor, &colors[i]);
+ }
+ break;
}
+ default:
+ BLI_assert_unreachable();
}
}
@@ -1197,7 +1225,7 @@ static void bake_targets_populate_pixels(const BakeAPIRender *bkr,
BakePixel *pixel_array)
{
if (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) {
- bake_targets_populate_pixels_vertex_colors(targets, ob, me_eval, pixel_array);
+ bake_targets_populate_pixels_color_attributes(targets, ob, me_eval, pixel_array);
}
else {
RE_bake_pixels_populate(me_eval, pixel_array, targets->pixels_num, targets, bkr->uv_layer);
@@ -1535,7 +1563,7 @@ static int bake(const BakeAPIRender *bkr,
ob_low_eval->obmat);
}
else {
- /* from multiresolution */
+ /* From multi-resolution. */
Mesh *me_nores = NULL;
ModifierData *md = NULL;
int mode;
@@ -1806,6 +1834,17 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
RE_SetReports(bkr->render, NULL);
}
+static void bake_job_complete(void *bkv)
+{
+ BakeAPIRender *bkr = (BakeAPIRender *)bkv;
+ BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_COMPLETE);
+}
+static void bake_job_canceled(void *bkv)
+{
+ BakeAPIRender *bkr = (BakeAPIRender *)bkv;
+ BKE_callback_exec_id(bkr->main, &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_CANCEL);
+}
+
static void bake_freejob(void *bkv)
{
BakeAPIRender *bkr = (BakeAPIRender *)bkv;
@@ -1941,6 +1980,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
/* init bake render */
bake_init_api_data(op, C, bkr);
+ BKE_callback_exec_id(CTX_data_main(C), &bkr->ob->id, BKE_CB_EVT_OBJECT_BAKE_PRE);
re = bkr->render;
/* setup new render */
@@ -1958,7 +1998,8 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
/* TODO: only draw bake image, can we enforce this. */
WM_jobs_timer(
wm_job, 0.5, (bkr->target == R_BAKE_TARGET_VERTEX_COLORS) ? NC_GEOM | ND_DATA : NC_IMAGE, 0);
- WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL);
+ WM_jobs_callbacks_ex(
+ wm_job, bake_startjob, NULL, NULL, NULL, bake_job_complete, bake_job_canceled);
G.is_break = false;
G.is_rendering = true;
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index d982d86fe77..bf3b71178e8 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -245,13 +245,11 @@ static void set_constraint_nth_target(bConstraint *con,
const char subtarget[],
int index)
{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
int num_targets, i;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
+ if (BKE_constraint_targets_get(con, &targets)) {
num_targets = BLI_listbase_count(&targets);
if (index < 0) {
@@ -274,9 +272,7 @@ static void set_constraint_nth_target(bConstraint *con,
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
- }
+ BKE_constraint_targets_flush(con, &targets, 0);
}
}
@@ -289,7 +285,6 @@ static void set_constraint_nth_target(bConstraint *con,
static void test_constraint(
Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type)
{
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
bool check_targets = true;
@@ -465,14 +460,7 @@ static void test_constraint(
}
/* Check targets for constraints */
- if (check_targets && cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
- /* constraints with empty target list that actually require targets */
- if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
- con->flag |= CONSTRAINT_DISABLE;
- }
-
+ if (check_targets && BKE_constraint_targets_get(con, &targets)) {
/* disable and clear constraints targets that are incorrect */
for (ct = targets.first; ct; ct = ct->next) {
/* general validity checks (for those constraints that need this) */
@@ -543,8 +531,12 @@ static void test_constraint(
}
/* free any temporary targets */
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 0);
+ BKE_constraint_targets_flush(con, &targets, 0);
+ }
+ else if (check_targets) {
+ /* constraints with empty target list that actually require targets */
+ if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
+ con->flag |= CONSTRAINT_DISABLE;
}
}
}
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index dfe858e5bd9..4837b538bf6 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -45,7 +45,7 @@
* Note some are 'fake' ones, i.e. they are not hold by real CDLayers. */
/* Not shared with modifier, since we use a usual enum here, not a multi-choice one. */
static const EnumPropertyItem DT_layer_items[] = {
- {0, "", 0, "Vertex Data", ""},
+ RNA_ENUM_ITEM_HEADING("Vertex Data", NULL),
{DT_TYPE_MDEFORMVERT,
"VGROUP_WEIGHTS",
0,
@@ -60,7 +60,8 @@ static const EnumPropertyItem DT_layer_items[] = {
{DT_TYPE_SKIN, "SKIN", 0, "Skin Weight", "Transfer skin weights"},
#endif
{DT_TYPE_BWEIGHT_VERT, "BEVEL_WEIGHT_VERT", 0, "Bevel Weight", "Transfer bevel weights"},
- {0, "", 0, "Edge Data", ""},
+
+ RNA_ENUM_ITEM_HEADING("Edge Data", NULL),
{DT_TYPE_SHARP_EDGE, "SHARP_EDGE", 0, "Sharp", "Transfer sharp mark"},
{DT_TYPE_SEAM, "SEAM", 0, "UV Seam", "Transfer UV seam mark"},
{DT_TYPE_CREASE, "CREASE", 0, "Subdivision Crease", "Transfer crease values"},
@@ -70,11 +71,13 @@ static const EnumPropertyItem DT_layer_items[] = {
0,
"Freestyle Mark",
"Transfer Freestyle edge mark"},
- {0, "", 0, "Face Corner Data", ""},
+
+ RNA_ENUM_ITEM_HEADING("Face Corner Data", NULL),
{DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
{DT_TYPE_MPROPCOL_LOOP | DT_TYPE_MLOOPCOL_LOOP, "VCOL", 0, "Colors", "Color Attributes"},
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
- {0, "", 0, "Face Data", ""},
+
+ RNA_ENUM_ITEM_HEADING("Face Data", NULL),
{DT_TYPE_SHARP_FACE, "SMOOTH", 0, "Smooth", "Transfer flat/smooth mark"},
{DT_TYPE_FREESTYLE_FACE,
"FREESTYLE_FACE",
@@ -85,14 +88,14 @@ static const EnumPropertyItem DT_layer_items[] = {
};
static void dt_add_vcol_layers(CustomData *cdata,
- CustomDataMask mask,
+ eCustomDataMask mask,
EnumPropertyItem **r_item,
int *r_totitem)
{
int types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
for (int i = 0; i < 2; i++) {
- CustomDataType type = types[i];
+ eCustomDataType type = types[i];
if (!(mask & CD_TYPE_AS_MASK(type))) {
continue;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index e5dd9fb2c8b..4896ddb5258 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1244,7 +1244,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
- /* Note: the notifier below isn't actually correct, but kept around just to be on the safe side.
+ /* NOTE: the notifier below isn't actually correct, but kept around just to be on the safe side.
* If further testing shows it's not necessary (for both bones and objects) removal is fine. */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
@@ -1316,7 +1316,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *op)
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW_ANIMVIZ, NULL);
- /* Note: the notifier below isn't actually correct, but kept around just to be on the safe side.
+ /* NOTE: the notifier below isn't actually correct, but kept around just to be on the safe side.
* If further testing shows it's not necessary (for both bones and objects) removal is fine. */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM | ND_POSE, NULL);
@@ -1469,8 +1469,6 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
- const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth");
- const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle");
bool changed_multi = false;
bool has_linked_data = false;
@@ -1518,7 +1516,11 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
bool changed = false;
if (ob->type == OB_MESH) {
BKE_mesh_smooth_flag_set(ob->data, use_smooth);
- BKE_mesh_auto_smooth_flag_set(ob->data, use_auto_smooth, auto_smooth_angle);
+ if (use_smooth) {
+ const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth");
+ const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle");
+ BKE_mesh_auto_smooth_flag_set(ob->data, use_auto_smooth, auto_smooth_angle);
+ }
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
changed = true;
}
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index fdf2cae026d..0055cdf9ea1 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -458,7 +458,7 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
return false;
}
- bool mode_transfered = false;
+ bool mode_transferred = false;
ED_undo_group_begin(C);
@@ -480,11 +480,11 @@ static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_toolsystem_update_from_context_view3d(C);
- mode_transfered = true;
+ mode_transferred = true;
}
ED_undo_group_end(C);
- return mode_transfered;
+ return mode_transferred;
}
static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -493,8 +493,8 @@ static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEven
const eObjectMode src_mode = (eObjectMode)ob_src->mode;
Base *base_dst = ED_view3d_give_base_under_cursor(C, event->mval);
- const bool mode_transfered = object_transfer_mode_to_base(C, op, base_dst);
- if (!mode_transfered) {
+ const bool mode_transferred = object_transfer_mode_to_base(C, op, base_dst);
+ if (!mode_transferred) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc
index 963e92942bb..69edd00ae24 100644
--- a/source/blender/editors/object/object_modifier.cc
+++ b/source/blender/editors/object/object_modifier.cc
@@ -515,12 +515,12 @@ void ED_object_modifier_copy_to_object(bContext *C,
DEG_relations_tag_update(bmain);
}
-bool ED_object_modifier_convert(ReportList *UNUSED(reports),
- Main *bmain,
- Depsgraph *depsgraph,
- ViewLayer *view_layer,
- Object *ob,
- ModifierData *md)
+bool ED_object_modifier_convert_psys_to_mesh(ReportList *UNUSED(reports),
+ Main *bmain,
+ Depsgraph *depsgraph,
+ ViewLayer *view_layer,
+ Object *ob,
+ ModifierData *md)
{
int cvert = 0;
@@ -757,9 +757,7 @@ static bool modifier_apply_obdata(
BKE_mesh_nomain_to_mesh(mesh_applied, me, ob, &CD_MASK_MESH, true);
/* Anonymous attributes shouldn't be available on the applied geometry. */
- MeshComponent component;
- component.replace(me, GeometryOwnershipType::Editable);
- component.attributes_remove_anonymous();
+ blender::bke::mesh_attributes_for_write(*me).remove_anonymous();
if (md_eval->type == eModifierType_Multires) {
multires_customdata_delete(me);
@@ -828,11 +826,12 @@ static bool modifier_apply_obdata(
BKE_report(reports, RPT_ERROR, "Evaluated geometry from modifier does not contain curves");
return false;
}
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
Curves &curves_eval = *geometry_set.get_curves_for_write();
/* Anonymous attributes shouldn't be available on the applied geometry. */
- component.attributes_remove_anonymous();
+ blender::bke::CurvesGeometry::wrap(curves_eval.geometry)
+ .attributes_for_write()
+ .remove_anonymous();
/* If the modifier's output is a different curves data-block, copy the relevant information to
* the original. */
@@ -1468,7 +1467,7 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo
return OPERATOR_CANCELLED;
}
- if (do_merge_customdata &&
+ if (ob->type == OB_MESH && do_merge_customdata &&
(mti->type & (eModifierTypeType_Constructive | eModifierTypeType_Nonconstructive))) {
BKE_mesh_merge_customdata_for_apply_modifier((Mesh *)ob->data);
}
@@ -1531,12 +1530,12 @@ void OBJECT_OT_modifier_apply(wmOperatorType *ot)
edit_modifier_properties(ot);
edit_modifier_report_property(ot);
- RNA_def_boolean(
- ot->srna,
- "merge_customdata",
- true,
- "Merge UV's",
- "Merge UV coordinates that share a vertex to account for imprecision in some modifiers");
+ RNA_def_boolean(ot->srna,
+ "merge_customdata",
+ true,
+ "Merge UV's",
+ "For mesh objects, merge UV coordinates that share a vertex to account for "
+ "imprecision in some modifiers");
PropertyRNA *prop = RNA_def_boolean(ot->srna,
"single_user",
false,
@@ -1608,7 +1607,7 @@ void OBJECT_OT_modifier_apply_as_shapekey(wmOperatorType *ot)
/** \} */
/* ------------------------------------------------------------------- */
-/** \name Convert Modifier Operator
+/** \name Convert Particle System Modifier to Mesh Operator
* \{ */
static int modifier_convert_exec(bContext *C, wmOperator *op)
@@ -1618,18 +1617,12 @@ static int modifier_convert_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = ED_object_active_context(C);
ModifierData *md = edit_modifier_property_get(op, ob, 0);
- const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
- const bool do_merge_customdata = RNA_boolean_get(op->ptr, "merge_customdata");
- if (!md || !ED_object_modifier_convert(op->reports, bmain, depsgraph, view_layer, ob, md)) {
+ if (!md || !ED_object_modifier_convert_psys_to_mesh(
+ op->reports, bmain, depsgraph, view_layer, ob, md)) {
return OPERATOR_CANCELLED;
}
- if (do_merge_customdata &&
- (mti->type & (eModifierTypeType_Constructive | eModifierTypeType_Nonconstructive))) {
- BKE_mesh_merge_customdata_for_apply_modifier((Mesh *)ob->data);
- }
-
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
@@ -1646,7 +1639,7 @@ static int modifier_convert_invoke(bContext *C, wmOperator *op, const wmEvent *U
void OBJECT_OT_modifier_convert(wmOperatorType *ot)
{
- ot->name = "Convert Modifier";
+ ot->name = "Convert Particles to Mesh";
ot->description = "Convert particles to a mesh object";
ot->idname = "OBJECT_OT_modifier_convert";
@@ -1657,13 +1650,6 @@ void OBJECT_OT_modifier_convert(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
-
- RNA_def_boolean(
- ot->srna,
- "merge_customdata",
- true,
- "Merge UV's",
- "Merge UV coordinates that share a vertex to account for imprecision in some modifiers");
}
/** \} */
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index 1067c2d6a95..8a0d380ff2f 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -281,7 +281,7 @@ void ED_operatormacros_object(void)
ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move",
"Duplicate Objects",
- "Duplicate selected objects and move them",
+ "Duplicate the selected objects and move them",
OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
@@ -289,11 +289,11 @@ void ED_operatormacros_object(void)
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
}
- /* grr, should be able to pass options on... */
- ot = WM_operatortype_append_macro("OBJECT_OT_duplicate_move_linked",
- "Duplicate Linked",
- "Duplicate selected objects and move them",
- OPTYPE_UNDO | OPTYPE_REGISTER);
+ ot = WM_operatortype_append_macro(
+ "OBJECT_OT_duplicate_move_linked",
+ "Duplicate Linked",
+ "Duplicate the selected objects, but not their object data, and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
if (ot) {
otmacro = WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
RNA_boolean_set(otmacro->ptr, "linked", true);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index abbde3b5b3a..01042824aac 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -951,7 +951,7 @@ static int parent_set_invoke_menu(bContext *C, wmOperatorType *ot)
1);
struct {
- bool mesh, gpencil;
+ bool mesh, gpencil, curves;
} has_children_of_type = {0};
CTX_DATA_BEGIN (C, Object *, child, selected_editable_objects) {
@@ -964,6 +964,9 @@ static int parent_set_invoke_menu(bContext *C, wmOperatorType *ot)
if (child->type == OB_GPENCIL) {
has_children_of_type.gpencil = true;
}
+ if (child->type == OB_CURVES) {
+ has_children_of_type.curves = true;
+ }
}
CTX_DATA_END;
@@ -987,6 +990,11 @@ static int parent_set_invoke_menu(bContext *C, wmOperatorType *ot)
else if (parent->type == OB_LATTICE) {
uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE);
}
+ else if (parent->type == OB_MESH) {
+ if (has_children_of_type.curves) {
+ uiItemO(layout, "Object (Attach Curves to Surface)", ICON_NONE, "CURVES_OT_surface_set");
+ }
+ }
/* vertex parenting */
if (OB_TYPE_SUPPORT_PARVERT(parent->type)) {
@@ -1653,7 +1661,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
"Link Instance Collection",
"Replace assigned Collection Instance"},
{MAKE_LINKS_FONTS, "FONTS", 0, "Link Fonts to Text", "Replace Text object Fonts"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MAKE_LINKS_MODIFIERS, "MODIFIERS", 0, "Copy Modifiers", "Replace Modifiers"},
{MAKE_LINKS_SHADERFX,
"EFFECTS",
@@ -2267,7 +2275,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
ID *id_root = NULL;
bool is_override_instancing_object = false;
- const bool do_fully_editable = RNA_boolean_get(op->ptr, "do_fully_editable");
+ const bool do_fully_editable = U.experimental.use_override_new_fully_editable;
GSet *user_overrides_objects_uids = do_fully_editable ? NULL :
BLI_gset_new(BLI_ghashutil_inthash_p,
@@ -2290,27 +2298,19 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
user_overrides_from_selected_objects = false;
}
else if (!make_override_library_object_overridable_check(bmain, obact)) {
- const int i = RNA_property_enum_get(op->ptr, op->type->prop);
- const uint collection_session_uuid = *((uint *)&i);
+ const int i = RNA_property_int_get(op->ptr, op->type->prop);
+ const uint collection_session_uuid = *((const uint *)&i);
if (collection_session_uuid == MAIN_ID_SESSION_UUID_UNSET) {
BKE_reportf(op->reports,
RPT_ERROR_INVALID_INPUT,
- "Active object '%s' is not overridable",
+ "Could not find an overridable root hierarchy for object '%s'",
obact->id.name + 2);
return OPERATOR_CANCELLED;
}
-
Collection *collection = BLI_listbase_bytes_find(&bmain->collections,
&collection_session_uuid,
sizeof(collection_session_uuid),
offsetof(ID, session_uuid));
- if (!ID_IS_OVERRIDABLE_LIBRARY(collection)) {
- BKE_reportf(op->reports,
- RPT_ERROR_INVALID_INPUT,
- "Could not find an overridable collection containing object '%s'",
- obact->id.name + 2);
- return OPERATOR_CANCELLED;
- }
id_root = &collection->id;
user_overrides_from_selected_objects = true;
}
@@ -2372,10 +2372,36 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
BLI_gset_free(user_overrides_objects_uids, NULL);
}
- /* Remove the instance empty from this scene, the items now have an overridden collection
- * instead. */
- if (success && is_override_instancing_object) {
- ED_object_base_free_and_unlink(bmain, scene, obact);
+ if (success) {
+ if (is_override_instancing_object) {
+ /* Remove the instance empty from this scene, the items now have an overridden collection
+ * instead. */
+ ED_object_base_free_and_unlink(bmain, scene, obact);
+ }
+ else {
+ /* Remove the found root ID from the view layer. */
+ switch (GS(id_root->name)) {
+ case ID_GR: {
+ Collection *collection_root = (Collection *)id_root;
+ LISTBASE_FOREACH_MUTABLE (
+ CollectionParent *, collection_parent, &collection_root->parents) {
+ if (ID_IS_LINKED(collection_parent->collection) ||
+ !BKE_view_layer_has_collection(view_layer, collection_parent->collection)) {
+ continue;
+ }
+ BKE_collection_child_remove(bmain, collection_parent->collection, collection_root);
+ }
+ break;
+ }
+ case ID_OB: {
+ /* TODO: Not sure how well we can handle this case, when we don't have the collections as
+ * reference containers... */
+ break;
+ }
+ default:
+ break;
+ }
+ }
}
DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE);
@@ -2385,10 +2411,11 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
}
/* Set the object to override. */
-static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obact = ED_object_active_context(C);
/* Sanity checks. */
@@ -2402,16 +2429,37 @@ static int make_override_library_invoke(bContext *C, wmOperator *op, const wmEve
return make_override_library_exec(C, op);
}
- if (ID_IS_LINKED(obact)) {
- /* Show menu with list of directly linked collections containing the active object. */
- WM_enum_search_invoke(C, op, event);
+ if (!ID_IS_LINKED(obact)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot make library override from a local object");
return OPERATOR_CANCELLED;
}
- /* Error.. cannot continue. */
- BKE_report(op->reports,
- RPT_ERROR,
- "Can only make library override for a referenced object or collection");
+ int potential_root_collections_num = 0;
+ uint collection_session_uuid = MAIN_ID_SESSION_UUID_UNSET;
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ /* Only check for directly linked collections. */
+ if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0 ||
+ !BKE_view_layer_has_collection(view_layer, collection)) {
+ continue;
+ }
+ if (BKE_collection_has_object_recursive(collection, obact)) {
+ if (potential_root_collections_num == 0) {
+ collection_session_uuid = collection->id.session_uuid;
+ }
+ potential_root_collections_num++;
+ }
+ }
+
+ if (potential_root_collections_num <= 1) {
+ RNA_property_int_set(op->ptr, op->type->prop, *((int *)&collection_session_uuid));
+ return make_override_library_exec(C, op);
+ }
+
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "Too many potential root collections (%d) for the override hierarchy, "
+ "please use the Outliner instead",
+ potential_root_collections_num);
return OPERATOR_CANCELLED;
}
@@ -2426,37 +2474,6 @@ static bool make_override_library_poll(bContext *C)
!ID_IS_OVERRIDE_LIBRARY(obact))));
}
-static const EnumPropertyItem *make_override_collections_of_linked_object_itemf(
- bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- EnumPropertyItem item_tmp = {0}, *item = NULL;
- int totitem = 0;
-
- Object *object = ED_object_active_context(C);
- Main *bmain = CTX_data_main(C);
-
- if (!object || !ID_IS_LINKED(object)) {
- return DummyRNA_DEFAULT_items;
- }
-
- LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
- /* Only check for directly linked collections. */
- if (!ID_IS_LINKED(&collection->id) || (collection->id.tag & LIB_TAG_INDIRECT) != 0) {
- continue;
- }
- if (BKE_collection_has_object_recursive(collection, object)) {
- item_tmp.identifier = item_tmp.name = collection->id.name + 2;
- item_tmp.value = *((int *)&collection->id.session_uuid);
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
void OBJECT_OT_make_override_library(wmOperatorType *ot)
{
/* identifiers */
@@ -2474,23 +2491,18 @@ void OBJECT_OT_make_override_library(wmOperatorType *ot)
/* properties */
PropertyRNA *prop;
- prop = RNA_def_enum(ot->srna,
- "collection",
- DummyRNA_DEFAULT_items,
- MAIN_ID_SESSION_UUID_UNSET,
- "Override Collection",
- "Name of directly linked collection containing the selected object, to make "
- "an override from");
- RNA_def_enum_funcs(prop, make_override_collections_of_linked_object_itemf);
- RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
- ot->prop = prop;
-
- prop = RNA_def_boolean(ot->srna,
- "do_fully_editable",
- false,
- "Create Fully Editable",
- "Make all created override data-blocks fully editable");
+ prop = RNA_def_int(ot->srna,
+ "collection",
+ MAIN_ID_SESSION_UUID_UNSET,
+ INT_MIN,
+ INT_MAX,
+ "Override Collection",
+ "Session UUID of the directly linked collection containing the selected "
+ "object, to make an override from",
+ INT_MIN,
+ INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ ot->prop = prop;
}
/** \} */
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index ba2efa6e517..8a7138b25ac 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -344,7 +344,7 @@ static void voxel_size_edit_draw(const bContext *C, ARegion *UNUSED(ar), void *a
BKE_unit_value_as_string(str,
VOXEL_SIZE_EDIT_MAX_STR_LEN,
(double)(cd->voxel_size * unit->scale_length),
- 4,
+ -3,
B_UNIT_LENGTH,
unit,
true);
@@ -415,15 +415,15 @@ static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *eve
}
if (event->modifier & KM_CTRL) {
- /* Linear mode, enables jumping to any voxel size. */
- d = d * 0.0005f;
- }
- else {
/* Multiply d by the initial voxel size to prevent uncontrollable speeds when using low voxel
* sizes. */
/* When the voxel size is slower, it needs more precision. */
d = d * min_ff(pow2f(cd->init_voxel_size), 0.1f) * 0.05f;
}
+ else {
+ /* Linear mode, enables jumping to any voxel size. */
+ d = d * 0.0005f;
+ }
if (cd->slow_mode) {
cd->voxel_size = cd->slow_voxel_size + d * 0.05f;
}
@@ -592,7 +592,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
ED_region_tag_redraw(region);
const char *status_str = TIP_(
- "Move the mouse to change the voxel size. LMB: confirm size, ESC/RMB: cancel");
+ "Move the mouse to change the voxel size. CTRL: Relative Scale, SHIFT: Precision Mode, "
+ "ENTER/LMB: Confirm Size, ESC/RMB: Cancel");
ED_workspace_status_text(C, status_str);
return OPERATOR_RUNNING_MODAL;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index ebcf8573ccd..0e3945bff15 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -20,6 +20,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
@@ -299,6 +301,10 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op)
bool changed = false;
if (RNA_boolean_get(op->ptr, "all")) {
+ if (RNA_boolean_get(op->ptr, "apply_mix")) {
+ float *arr = BKE_key_evaluate_object_ex(ob, NULL, NULL, 0, ob->data);
+ MEM_freeN(arr);
+ }
changed = BKE_object_shapekey_free(bmain, ob);
}
else {
@@ -315,6 +321,34 @@ static int shape_key_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+static bool shape_key_remove_poll_property(const bContext *UNUSED(C),
+ wmOperator *op,
+ const PropertyRNA *prop)
+{
+ const char *prop_id = RNA_property_identifier(prop);
+ const bool do_all = RNA_enum_get(op->ptr, "all");
+
+ /* Only show seed for randomize action! */
+ if (STREQ(prop_id, "apply_mix") && !do_all) {
+ return false;
+ }
+ return true;
+}
+
+static char *shape_key_remove_get_description(bContext *UNUSED(C),
+ wmOperatorType *UNUSED(ot),
+ PointerRNA *ptr)
+{
+ const bool do_apply_mix = RNA_boolean_get(ptr, "apply_mix");
+
+ if (do_apply_mix) {
+ return BLI_strdup(
+ TIP_("Apply current visible shape to the object data, and delete all shape keys"));
+ }
+
+ return NULL;
+}
+
void OBJECT_OT_shape_key_remove(wmOperatorType *ot)
{
/* identifiers */
@@ -325,12 +359,19 @@ void OBJECT_OT_shape_key_remove(wmOperatorType *ot)
/* api callbacks */
ot->poll = shape_key_mode_exists_poll;
ot->exec = shape_key_remove_exec;
+ ot->poll_property = shape_key_remove_poll_property;
+ ot->get_description = shape_key_remove_get_description;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all shape keys");
+ RNA_def_boolean(ot->srna, "all", false, "All", "Remove all shape keys");
+ RNA_def_boolean(ot->srna,
+ "apply_mix",
+ false,
+ "Apply Mix",
+ "Apply current mix of shape keys to the geometry before removing them");
}
/** \} */
diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc
index 82e67231ec1..70c3eed3768 100644
--- a/source/blender/editors/object/object_transform.cc
+++ b/source/blender/editors/object/object_transform.cc
@@ -855,7 +855,7 @@ static int apply_objects_internal(bContext *C,
/* calculate translation */
if (apply_loc) {
- copy_v3_v3(mat[3], ob->loc);
+ add_v3_v3v3(mat[3], ob->loc, ob->dloc);
if (!(apply_scale && apply_rot)) {
float tmat[3][3];
@@ -1023,12 +1023,15 @@ static int apply_objects_internal(bContext *C,
else {
if (apply_loc) {
zero_v3(ob->loc);
+ zero_v3(ob->dloc);
}
if (apply_scale) {
- ob->scale[0] = ob->scale[1] = ob->scale[2] = 1.0f;
+ copy_v3_fl(ob->scale, 1.0f);
+ copy_v3_fl(ob->dscale, 1.0f);
}
if (apply_rot) {
zero_v3(ob->rot);
+ zero_v3(ob->drot);
unit_qt(ob->quat);
unit_axis_angle(ob->rotAxis, &ob->rotAngle);
}
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 492ece0b40e..17b7fe7fe5e 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -693,7 +693,7 @@ static const EnumPropertyItem WT_vertex_group_select_item[] = {
const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *C,
PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
+ PropertyRNA *prop,
bool *r_free,
const uint selection_mask)
{
@@ -731,6 +731,12 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext *
RNA_enum_items_add_value(&item, &totitem, WT_vertex_group_select_item, WT_VGROUP_ALL);
}
+ /* Set `Deform Bone` as default selection if armature is present. */
+ if (ob) {
+ RNA_def_property_enum_default(
+ prop, BKE_modifiers_is_deformed_by_armature(ob) ? WT_VGROUP_BONE_DEFORM : WT_VGROUP_ALL);
+ }
+
RNA_enum_item_end(&item, &totitem);
*r_free = true;
@@ -4266,7 +4272,6 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
Mesh *me = ob->data;
BMEditMesh *em = me->edit_mesh;
- float weight_act;
int i;
if (em) {
@@ -4278,18 +4283,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
if (dvert_act == NULL) {
return;
}
- weight_act = BKE_defvert_find_weight(dvert_act, def_nr);
BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && (eve != eve_act)) {
- MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
- if (dw) {
- dw->weight = weight_act;
+ MDeformVert *dvert_dst = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset);
- if (me->symmetry & ME_SYMMETRY_X) {
- ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
- }
+ BKE_defvert_copy_index(dvert_dst, def_nr, dvert_act, def_nr);
+
+ if (me->symmetry & ME_SYMMETRY_X) {
+ ED_mesh_defvert_mirror_update_em(ob, eve, -1, i, cd_dvert_offset);
}
}
}
@@ -4306,17 +4308,15 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr)
if (dvert_act == NULL) {
return;
}
- weight_act = BKE_defvert_find_weight(dvert_act, def_nr);
dv = me->dvert;
for (i = 0; i < me->totvert; i++, dv++) {
if ((me->mvert[i].flag & SELECT) && (dv != dvert_act)) {
- MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
- if (dw) {
- dw->weight = weight_act;
- if (me->symmetry & ME_SYMMETRY_X) {
- ED_mesh_defvert_mirror_update_ob(ob, -1, i);
- }
+
+ BKE_defvert_copy_index(dv, def_nr, dvert_act, def_nr);
+
+ if (me->symmetry & ME_SYMMETRY_X) {
+ ED_mesh_defvert_mirror_update_ob(ob, -1, i);
}
}
}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 0e03feba340..03f9b4eb867 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -32,6 +32,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -1512,7 +1513,7 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
}
}
- psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
+ psys_cache_edit_paths(depsgraph, scene, ob, edit, scene->r.cfra, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
@@ -1647,11 +1648,11 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
* and flagging with PEK_HIDE will prevent selection. This might get restored once this is
* supported in drawing (but doesn't make much sense for hair anyways). */
if (edit->psys && edit->psys->part->type == PART_EMITTER) {
- PE_hide_keys_time(scene, edit, CFRA);
+ PE_hide_keys_time(scene, edit, scene->r.cfra);
}
/* regenerate path caches */
- psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
+ psys_cache_edit_paths(depsgraph, scene, ob, edit, scene->r.cfra, G.is_rendering);
/* disable update flag */
LOOP_POINTS {
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 6bea6e2c19e..96aea0ededf 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -26,6 +26,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 96195bdcc2e..80de8fae072 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -256,8 +256,8 @@ static void fluid_bake_sequence(FluidJob *job)
frame = is_first_frame ? fds->cache_frame_start : (*pause_frame);
/* Save orig frame and update scene frame. */
- orig_frame = CFRA;
- CFRA = frame;
+ orig_frame = scene->r.cfra;
+ scene->r.cfra = frame;
/* Loop through selected frames. */
for (; frame <= fds->cache_frame_end; frame++) {
@@ -280,7 +280,7 @@ static void fluid_bake_sequence(FluidJob *job)
*(job->progress) = progress;
}
- CFRA = frame;
+ scene->r.cfra = frame;
/* Update animation system. */
ED_update_for_newframe(job->bmain, job->depsgraph);
@@ -293,7 +293,7 @@ static void fluid_bake_sequence(FluidJob *job)
}
/* Restore frame position that we were on before bake. */
- CFRA = orig_frame;
+ scene->r.cfra = orig_frame;
}
static void fluid_bake_endjob(void *customdata)
diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc
index d907a52543c..77ad23f1e3f 100644
--- a/source/blender/editors/render/render_opengl.cc
+++ b/source/blender/editors/render/render_opengl.cc
@@ -494,7 +494,8 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
for (view_id = 0; view_id < oglrender->views_len; view_id++) {
context.view_id = view_id;
context.gpu_offscreen = oglrender->ofs;
- oglrender->seq_data.ibufs_arr[view_id] = SEQ_render_give_ibuf(&context, CFRA, chanshown);
+ oglrender->seq_data.ibufs_arr[view_id] = SEQ_render_give_ibuf(
+ &context, scene->r.cfra, chanshown);
}
}
@@ -757,8 +758,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
WM_jobs_kill_all_except(wm, CTX_wm_screen(C));
/* create offscreen buffer */
- sizex = (scene->r.size * scene->r.xsch) / 100;
- sizey = (scene->r.size * scene->r.ysch) / 100;
+ BKE_render_resolution(&scene->r, false, &sizex, &sizey);
/* corrects render size with actual size, not every card supports non-power-of-two dimensions */
DRW_opengl_context_enable(); /* Off-screen creation needs to be done in DRW context. */
@@ -1136,12 +1136,12 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
RenderResult *rr;
/* go to next frame */
- if (CFRA < oglrender->nfra) {
- CFRA++;
+ if (scene->r.cfra < oglrender->nfra) {
+ scene->r.cfra++;
}
- while (CFRA < oglrender->nfra) {
+ while (scene->r.cfra < oglrender->nfra) {
BKE_scene_graph_update_for_newframe(depsgraph);
- CFRA++;
+ scene->r.cfra++;
}
is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
@@ -1184,7 +1184,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
}
if (oglrender->render_frames == nullptr ||
- BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
+ BLI_BITMAP_TEST_BOOL(oglrender->render_frames, scene->r.cfra - PSFRA)) {
/* render into offscreen buffer */
screen_opengl_render_apply(C, oglrender);
}
@@ -1204,7 +1204,7 @@ finally: /* Step the frame and bail early if needed */
oglrender->nfra += scene->r.frame_step;
/* stop at the end or on error */
- if (CFRA >= PEFRA || !ok) {
+ if (scene->r.cfra >= PEFRA || !ok) {
screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return false;
}
diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc
index addcedc4481..97bbcaa102f 100644
--- a/source/blender/editors/render/render_preview.cc
+++ b/source/blender/editors/render/render_preview.cc
@@ -805,7 +805,7 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
Scene *scene = BKE_scene_add(preview_data->pr_main, "Object preview scene");
/* Preview need to be in the current frame to get a thumbnail similar of what
* viewport displays. */
- CFRA = preview_data->cfra;
+ scene->r.cfra = preview_data->cfra;
ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
Depsgraph *depsgraph = DEG_graph_new(
diff --git a/source/blender/editors/render/render_view.cc b/source/blender/editors/render/render_view.cc
index a7ff2aad05a..9a16c910205 100644
--- a/source/blender/editors/render/render_view.cc
+++ b/source/blender/editors/render/render_view.cc
@@ -19,6 +19,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BLT_translation.h"
@@ -130,8 +131,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
- int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
- int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
+ int sizex, sizey;
+ BKE_render_resolution(&scene->r, false, &sizex, &sizey);
+
+ sizex += 30 * UI_DPI_FAC;
+ sizey += 60 * UI_DPI_FAC;
/* arbitrary... miniature image window views don't make much sense */
if (sizex < 320) {
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 369ca553a8c..def6c38f5ca 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1075,6 +1075,7 @@ static void region_azone_scrollbar_init(ScrArea *area,
{
rcti scroller_vert = (direction == AZ_SCROLL_VERT) ? region->v2d.vert : region->v2d.hor;
AZone *az = MEM_callocN(sizeof(*az), __func__);
+ float hide_width;
BLI_addtail(&area->actionzones, az);
az->type = AZONE_REGION_SCROLL;
@@ -1083,16 +1084,18 @@ static void region_azone_scrollbar_init(ScrArea *area,
if (direction == AZ_SCROLL_VERT) {
az->region->v2d.alpha_vert = 0;
+ hide_width = V2D_SCROLL_HIDE_HEIGHT;
}
else if (direction == AZ_SCROLL_HOR) {
az->region->v2d.alpha_hor = 0;
+ hide_width = V2D_SCROLL_HIDE_WIDTH;
}
BLI_rcti_translate(&scroller_vert, region->winrct.xmin, region->winrct.ymin);
- az->x1 = scroller_vert.xmin - AZONEFADEIN;
- az->y1 = scroller_vert.ymin - AZONEFADEIN;
- az->x2 = scroller_vert.xmax + AZONEFADEIN;
- az->y2 = scroller_vert.ymax + AZONEFADEIN;
+ az->x1 = scroller_vert.xmin - ((direction == AZ_SCROLL_VERT) ? hide_width : 0);
+ az->y1 = scroller_vert.ymin - ((direction == AZ_SCROLL_HOR) ? hide_width : 0);
+ az->x2 = scroller_vert.xmax + ((direction == AZ_SCROLL_VERT) ? hide_width : 0);
+ az->y2 = scroller_vert.ymax + ((direction == AZ_SCROLL_HOR) ? hide_width : 0);
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
@@ -3125,7 +3128,12 @@ void ED_region_panels_draw(const bContext *C, ARegion *region)
UI_view2d_mask_from_win(v2d, &mask);
mask.xmax -= UI_PANEL_CATEGORY_MARGIN_WIDTH;
}
- UI_view2d_scrollers_draw(v2d, use_mask ? &mask : NULL);
+ bool use_full_hide = false;
+ if (region->overlap) {
+ /* Don't always show scrollbars for transparent regions as it's distracting. */
+ use_full_hide = true;
+ }
+ UI_view2d_scrollers_draw_ex(v2d, use_mask ? &mask : NULL, use_full_hide);
}
void ED_region_panels_ex(const bContext *C, ARegion *region, const char *contexts[])
@@ -3458,9 +3466,9 @@ ScrArea *ED_area_find_under_cursor(const bContext *C, int spacetype, const int x
if (!area) {
/* Check all windows except the active one. */
int scr_pos[2];
- wmWindow *r_win = WM_window_find_under_cursor(win, xy, scr_pos);
- if (r_win && r_win != win) {
- win = r_win;
+ wmWindow *win_other = WM_window_find_under_cursor(win, xy, scr_pos);
+ if (win_other && win_other != win) {
+ win = win_other;
screen = WM_window_get_active_screen(win);
area = BKE_screen_find_area_xy(screen, spacetype, scr_pos);
}
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 11a62123ad7..0d6b6ee1d78 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -100,6 +100,7 @@ const char *screen_context_dir[] = {
"active_gpencil_frame",
"active_annotation_layer",
"active_operator",
+ "active_action",
"selected_visible_actions",
"selected_editable_actions",
"visible_fcurves",
@@ -969,6 +970,7 @@ static eContextResult screen_ctx_active_operator(const bContext *C, bContextData
}
static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
bContextDataResult *result,
+ bool active_only,
bool editable)
{
bAnimContext ac;
@@ -978,11 +980,17 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
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);
+ if (active_only) {
+ CTX_data_id_pointer_set(result, (ID *)saction->action);
+ }
+ else {
+ 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);
}
- CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
}
@@ -995,7 +1003,8 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
switch (ac.spacetype) {
case SPACE_GRAPH:
- filter |= ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL;
+ filter |= ANIMFILTER_FCURVESONLY | ANIMFILTER_CURVE_VISIBLE |
+ (active_only ? ANIMFILTER_ACTIVE : ANIMFILTER_SEL);
break;
case SPACE_ACTION:
@@ -1006,7 +1015,7 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- GSet *seen_set = BLI_gset_ptr_new("seen actions");
+ GSet *seen_set = active_only ? NULL : BLI_gset_ptr_new("seen actions");
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
/* In dopesheet check selection status of individual items, skipping
@@ -1019,37 +1028,48 @@ static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
bAction *action = ANIM_channel_action_get(ale);
if (action) {
- if (editable && ID_IS_LINKED(action)) {
- continue;
+ if (active_only) {
+ CTX_data_id_pointer_set(result, (ID *)action);
+ break;
}
+ else {
+ 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);
+ /* Add the action to the output list if not already added. */
+ if (BLI_gset_add(seen_set, action)) {
+ CTX_data_id_list_add(result, &action->id);
+ }
}
}
}
- BLI_gset_free(seen_set, NULL);
-
ANIM_animdata_freelist(&anim_data);
- CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ if (!active_only) {
+ BLI_gset_free(seen_set, NULL);
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ }
+
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
-
+static eContextResult screen_ctx_active_action(const bContext *C, bContextDataResult *result)
+{
+ return screen_ctx_sel_actions_impl(C, result, true, false);
+}
static eContextResult screen_ctx_selected_visible_actions(const bContext *C,
bContextDataResult *result)
{
- return screen_ctx_sel_actions_impl(C, result, false);
+ return screen_ctx_sel_actions_impl(C, result, false, false);
}
static eContextResult screen_ctx_selected_editable_actions(const bContext *C,
bContextDataResult *result)
{
- return screen_ctx_sel_actions_impl(C, result, true);
+ return screen_ctx_sel_actions_impl(C, result, false, true);
}
static eContextResult screen_ctx_sel_edit_fcurves_(const bContext *C,
bContextDataResult *result,
@@ -1060,8 +1080,9 @@ static eContextResult screen_ctx_sel_edit_fcurves_(const bContext *C,
ListBase anim_data = {NULL, NULL};
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS) |
- (ac.spacetype == SPACE_GRAPH ? ANIMFILTER_CURVE_VISIBLE :
- ANIMFILTER_LIST_VISIBLE) |
+ (ac.spacetype == SPACE_GRAPH ?
+ (ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY) :
+ ANIMFILTER_LIST_VISIBLE) |
extra_filter;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1105,7 +1126,7 @@ static eContextResult screen_ctx_active_editable_fcurve(const bContext *C,
ListBase anim_data = {NULL, NULL};
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT |
- ANIMFILTER_CURVE_VISIBLE);
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_CURVE_VISIBLE);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1131,8 +1152,9 @@ static eContextResult screen_ctx_selected_editable_keyframes(const bContext *C,
/* Use keyframes from editable selected FCurves. */
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS | ANIMFILTER_FOREDIT |
ANIMFILTER_SEL) |
- (ac.spacetype == SPACE_GRAPH ? ANIMFILTER_CURVE_VISIBLE :
- ANIMFILTER_LIST_VISIBLE);
+ (ac.spacetype == SPACE_GRAPH ?
+ (ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY) :
+ ANIMFILTER_LIST_VISIBLE);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1261,6 +1283,7 @@ 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("active_action", screen_ctx_active_action);
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);
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 43c19670a41..08c8c863729 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -626,8 +626,8 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen_geom_vertices_scale(win, screen);
ED_screen_areas_iter (win, screen, area) {
- /* set spacetype and region callbacks, calls init() */
- /* sets subwindows for regions, adds handlers */
+ /* Set space-type and region callbacks, calls init() */
+ /* Sets sub-windows for regions, adds handlers. */
ED_area_init(wm, win, area);
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index d7cf09ca89a..3618b933443 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -659,36 +659,10 @@ bool ED_operator_editmball(bContext *C)
return false;
}
-bool ED_operator_mask(bContext *C)
-{
- ScrArea *area = CTX_wm_area(C);
- if (area && area->spacedata.first) {
- switch (area->spacetype) {
- case SPACE_CLIP: {
- SpaceClip *screen = area->spacedata.first;
- return ED_space_clip_check_show_maskedit(screen);
- }
- case SPACE_SEQ: {
- SpaceSeq *sseq = area->spacedata.first;
- Scene *scene = CTX_data_scene(C);
- return ED_space_sequencer_check_show_maskedit(sseq, scene);
- }
- case SPACE_IMAGE: {
- SpaceImage *sima = area->spacedata.first;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
- return ED_space_image_check_show_maskedit(sima, obedit);
- }
- }
- }
-
- return false;
-}
-
-bool ED_operator_camera(bContext *C)
+bool ED_operator_camera_poll(bContext *C)
{
struct Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
- return (cam != NULL);
+ return (cam != NULL && !ID_IS_LINKED(cam));
}
/** \} */
@@ -913,14 +887,16 @@ static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const b
float dist_fac = 0.0f, alpha = 0.0f;
if (az->direction == AZ_SCROLL_HOR) {
- dist_fac = BLI_rcti_length_y(&v2d->hor, local_xy[1]) / AZONEFADEIN;
+ float hide_width = (az->y2 - az->y1) / 2.0f;
+ dist_fac = BLI_rcti_length_y(&v2d->hor, local_xy[1]) / hide_width;
CLAMP(dist_fac, 0.0f, 1.0f);
alpha = 1.0f - dist_fac;
v2d->alpha_hor = alpha * 255;
}
else if (az->direction == AZ_SCROLL_VERT) {
- dist_fac = BLI_rcti_length_x(&v2d->vert, local_xy[0]) / AZONEFADEIN;
+ float hide_width = (az->x2 - az->x1) / 2.0f;
+ dist_fac = BLI_rcti_length_x(&v2d->vert, local_xy[0]) / hide_width;
CLAMP(dist_fac, 0.0f, 1.0f);
alpha = 1.0f - dist_fac;
@@ -1477,7 +1453,7 @@ static int area_close_exec(bContext *C, wmOperator *op)
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
- /* This operator is scriptable, so the area passed could be invalid. */
+ /* This operator is script-able, so the area passed could be invalid. */
if (BLI_findindex(&screen->areabase, area) == -1) {
BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen");
return OPERATOR_CANCELLED;
@@ -2490,6 +2466,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case EVT_LEFTCTRLKEY:
+ case EVT_RIGHTCTRLKEY:
sd->do_snap = event->val == KM_PRESS;
update_factor = true;
break;
@@ -2722,7 +2699,7 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event
rmd->region->sizey = rmd->region->winy;
}
- /* now copy to regionmovedata */
+ /* Now copy to region-move-data. */
if (ELEM(rmd->edge, AE_LEFT_TO_TOPRIGHT, AE_RIGHT_TO_TOPLEFT)) {
rmd->origval = rmd->region->sizex;
}
@@ -2974,9 +2951,9 @@ static int frame_offset_exec(bContext *C, wmOperator *op)
int delta = RNA_int_get(op->ptr, "delta");
- CFRA += delta;
- FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.0f;
+ scene->r.cfra += delta;
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
+ scene->r.subframe = 0.0f;
areas_do_frame_follow(C, false);
@@ -3015,7 +2992,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
- /* Don't change CFRA directly if animtimer is running as this can cause
+ /* Don't change scene->r.cfra directly if animtimer is running as this can cause
* first/last frame not to be actually shown (bad since for example physics
* simulations aren't reset properly).
*/
@@ -3033,10 +3010,10 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
}
else {
if (RNA_boolean_get(op->ptr, "end")) {
- CFRA = PEFRA;
+ scene->r.cfra = PEFRA;
}
else {
- CFRA = PSFRA;
+ scene->r.cfra = PSFRA;
}
areas_do_frame_follow(C, true);
@@ -3085,7 +3062,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- float cfra = (float)(CFRA);
+ float cfra = (float)(scene->r.cfra);
/* Initialize binary-tree-list for getting keyframes. */
struct AnimKeylist *keylist = ED_keylist_create();
@@ -3127,9 +3104,9 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
}
while ((ak != NULL) && (done == false)) {
- if (CFRA != (int)ak->cfra) {
+ if (scene->r.cfra != (int)ak->cfra) {
/* this changes the frame, so set the frame and we're done */
- CFRA = (int)ak->cfra;
+ scene->r.cfra = (int)ak->cfra;
done = true;
}
else {
@@ -3188,20 +3165,20 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
static int marker_jump_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- int closest = CFRA;
+ int closest = scene->r.cfra;
const bool next = RNA_boolean_get(op->ptr, "next");
bool found = false;
/* find matching marker in the right direction */
LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
if (next) {
- if ((marker->frame > CFRA) && (!found || closest > marker->frame)) {
+ if ((marker->frame > scene->r.cfra) && (!found || closest > marker->frame)) {
closest = marker->frame;
found = true;
}
}
else {
- if ((marker->frame < CFRA) && (!found || closest < marker->frame)) {
+ if ((marker->frame < scene->r.cfra) && (!found || closest < marker->frame)) {
closest = marker->frame;
found = true;
}
@@ -3215,7 +3192,7 @@ static int marker_jump_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- CFRA = closest;
+ scene->r.cfra = closest;
areas_do_frame_follow(C, true);
@@ -4737,11 +4714,11 @@ static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), con
if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
#ifdef PROFILE_AUDIO_SYNCH
- old_frame = CFRA;
+ old_frame = scene->r.cfra;
#endif
}
- /* since we follow drawflags, we can't send notifier but tag regions ourselves */
+ /* Since we follow draw-flags, we can't send notifier but tag regions ourselves. */
if (depsgraph != NULL) {
ED_update_for_newframe(bmain, depsgraph);
}
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 1156452310c..9d66debda6f 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -214,7 +214,14 @@ static void screen_user_menu_draw(const bContext *C, Menu *menu)
wmOperatorType *ot = WM_operatortype_find(umi_op->op_idname, false);
if (ot != NULL) {
IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
- uiItemFullO_ptr(menu->layout, ot, ui_name, ICON_NONE, prop, umi_op->opcontext, 0, NULL);
+ uiItemFullO_ptr(menu->layout,
+ ot,
+ CTX_IFACE_(ot->translation_context, ui_name),
+ ICON_NONE,
+ prop,
+ umi_op->opcontext,
+ 0,
+ NULL);
is_empty = false;
}
else {
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 01417650b3d..cb29f15420c 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -54,17 +54,87 @@ WorkSpace *ED_workspace_add(Main *bmain, const char *name)
return BKE_workspace_add(bmain, name);
}
+static void workspace_exit(WorkSpace *workspace, wmWindow *win)
+{
+ /* Scene pinning: Store whatever scene was active when leaving the workspace. It's reactivated
+ * when the workspace gets reactivated as well. */
+ if (workspace->flags & WORKSPACE_USE_PIN_SCENE) {
+ workspace->pin_scene = WM_window_get_active_scene(win);
+ }
+ else {
+ /* The active scene may have been changed. So also always update the unpinned scene to the
+ * latest when leaving a workspace that has no scene pinning. */
+ win->unpinned_scene = WM_window_get_active_scene(win);
+ }
+}
+
+/**
+ * State changes (old workspace to new workspace):
+ * 1) unpinned -> pinned
+ * * Store current scene as the unpinned one (done in #workspace_exit()).
+ * * Change the current scene to the pinned one.
+ * 2) pinned -> pinned
+ * * Change the current scene to the new pinned one.
+ * 3) pinned -> unpinned
+ * * Change current scene back to the unpinned one
+ * 4) unpinned -> unpinned
+ * * Make sure the unpinned scene is active.
+ *
+ * Note that the pin scene must also be updated when leaving a workspace with a pinned scene.
+ * That's done separately via workspace_exit() above.
+ */
+static void workspace_scene_pinning_update(WorkSpace *workspace_new,
+ const WorkSpace *workspace_old,
+ bContext *C)
+{
+ wmWindow *win = CTX_wm_window(C);
+ Main *bmain = CTX_data_main(C);
+ Scene *active_scene = WM_window_get_active_scene(win);
+
+ const bool is_new_pinned = (workspace_new->flags & WORKSPACE_USE_PIN_SCENE);
+ const bool is_old_pinned = (workspace_old->flags & WORKSPACE_USE_PIN_SCENE);
+
+ /* State changes 1 and 2. */
+ if (is_new_pinned) {
+ if (workspace_new->pin_scene && (workspace_new->pin_scene != active_scene)) {
+ WM_window_set_active_scene(bmain, C, win, workspace_new->pin_scene);
+ workspace_new->pin_scene = NULL;
+ }
+ }
+ /* State change 3 - Changing from workspace with pinned scene to unpinned scene. */
+ else if (is_old_pinned) {
+ if (win->unpinned_scene) {
+ WM_window_set_active_scene(bmain, C, win, win->unpinned_scene);
+ }
+ else {
+ /* When leaving a workspace where the pinning was just enabled, the unpinned scene wasn't set
+ * yet. */
+ win->unpinned_scene = active_scene;
+ }
+ }
+ else {
+ /* When leaving a workspace where the pinning was just disabled, we still want to restore the
+ * unpinned scene. */
+ if (win->unpinned_scene) {
+ WM_window_set_active_scene(bmain, C, win, win->unpinned_scene);
+ }
+ }
+
+ BLI_assert(WM_window_get_active_scene(win));
+}
+
/**
* Changes the object mode (if needed) to the one set in \a workspace_new.
* Object mode is still stored on object level. In future it should all be workspace level instead.
*/
static void workspace_change_update(WorkSpace *workspace_new,
- const WorkSpace *workspace_old,
+ WorkSpace *workspace_old,
bContext *C,
wmWindowManager *wm)
{
+ workspace_scene_pinning_update(workspace_new, workspace_old, C);
/* needs to be done before changing mode! (to ensure right context) */
- UNUSED_VARS(workspace_old, workspace_new, C, wm);
+ UNUSED_VARS(wm);
#if 0
Object *ob_act = CTX_data_active_object(C) eObjectMode mode_old = workspace_old->object_mode;
eObjectMode mode_new = workspace_new->object_mode;
@@ -113,6 +183,8 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
return false;
}
+ workspace_exit(workspace_old, win);
+
screen_change_prepare(screen_old, screen_new, bmain, C, win);
if (screen_new == NULL) {
@@ -143,6 +215,7 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo
WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2);
workspace_new->flags = workspace_old->flags;
+ workspace_new->pin_scene = workspace_old->pin_scene;
workspace_new->object_mode = workspace_old->object_mode;
workspace_new->order = workspace_old->order;
BLI_duplicatelist(&workspace_new->owner_ids, &workspace_old->owner_ids);
@@ -512,6 +585,35 @@ static void WORKSPACE_OT_reorder_to_front(wmOperatorType *ot)
ot->exec = workspace_reorder_to_front_exec;
}
+static int workspace_scene_pin_toggle(bContext *C, wmOperator *UNUSED(op))
+{
+ WorkSpace *workspace = workspace_context_get(C);
+
+ /* Trivial. The operator is only needed to display a superimposed extra icon, which
+ * requires an operator. */
+ workspace->flags ^= WORKSPACE_USE_PIN_SCENE;
+
+ WM_event_add_notifier(C, NC_WORKSPACE, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void WORKSPACE_OT_scene_pin_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Pin Scene to Workspace";
+ ot->description =
+ "Remember the last used scene for the current workspace and switch to it whenever this "
+ "workspace is activated again";
+ ot->idname = "WORKSPACE_OT_scene_pin_toggle";
+
+ /* api callbacks */
+ ot->poll = workspace_context_poll;
+ ot->exec = workspace_scene_pin_toggle;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
void ED_operatortypes_workspace(void)
{
WM_operatortype_append(WORKSPACE_OT_duplicate);
@@ -520,6 +622,7 @@ void ED_operatortypes_workspace(void)
WM_operatortype_append(WORKSPACE_OT_append_activate);
WM_operatortype_append(WORKSPACE_OT_reorder_to_back);
WM_operatortype_append(WORKSPACE_OT_reorder_to_front);
+ WM_operatortype_append(WORKSPACE_OT_scene_pin_toggle);
}
/** \} Workspace Operators */
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index d3bf28798c4..edb0f1cda4d 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -10,6 +10,7 @@ set(INC
../../depsgraph
../../draw
../../functions
+ ../../geometry
../../gpu
../../imbuf
../../makesdna
@@ -31,8 +32,15 @@ set(SRC
curves_sculpt_brush.cc
curves_sculpt_comb.cc
curves_sculpt_delete.cc
+ curves_sculpt_density.cc
curves_sculpt_grow_shrink.cc
curves_sculpt_ops.cc
+ curves_sculpt_pinch.cc
+ curves_sculpt_puff.cc
+ curves_sculpt_selection_paint.cc
+ curves_sculpt_selection.cc
+ curves_sculpt_slide.cc
+ curves_sculpt_smooth.cc
curves_sculpt_snake_hook.cc
paint_canvas.cc
paint_cursor.c
@@ -49,13 +57,12 @@ set(SRC
paint_stroke.c
paint_utils.c
paint_vertex.cc
- paint_vertex_color_ops.c
- paint_vertex_color_utils.c
+ paint_vertex_color_ops.cc
paint_vertex_proj.c
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
sculpt.c
- sculpt_automasking.c
+ sculpt_automasking.cc
sculpt_boundary.c
sculpt_brush_types.c
sculpt_cloth.c
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
index d7f4b71d2d0..26145a386f5 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -19,11 +19,12 @@
#include "BKE_context.h"
#include "BKE_curves.hh"
#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
#include "BKE_paint.h"
#include "BKE_report.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
@@ -37,10 +38,12 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "GEO_add_curves_on_mesh.hh"
+
#include "WM_api.h"
/**
- * The code below uses a prefix naming convention to indicate the coordinate space:
+ * The code below uses a suffix naming convention to indicate the coordinate space:
* cu: Local space of the curves object that is being edited.
* su: Local space of the surface object.
* wo: World space.
@@ -69,26 +72,13 @@ class AddOperation : public CurvesSculptStrokeOperation {
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
};
-static void initialize_straight_curve_positions(const float3 &p1,
- const float3 &p2,
- MutableSpan<float3> r_positions)
-{
- const float step = 1.0f / (float)(r_positions.size() - 1);
- for (const int i : r_positions.index_range()) {
- r_positions[i] = math::interpolate(p1, p2, i * step);
- }
-}
-
/**
* Utility class that actually executes the update when the stroke is updated. That's useful
* because it avoids passing a very large number of parameters between functions.
*/
struct AddOperationExecutor {
AddOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
@@ -97,60 +87,34 @@ struct AddOperationExecutor {
Object *surface_ob_ = nullptr;
Mesh *surface_ = nullptr;
Span<MLoopTri> surface_looptris_;
- Span<float3> corner_normals_su_;
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
const BrushCurvesSculptSettings *brush_settings_ = nullptr;
+ int add_amount_;
+ bool use_front_face_;
float brush_radius_re_;
float2 brush_pos_re_;
- bool use_front_face_;
- bool interpolate_length_;
- bool interpolate_shape_;
- bool interpolate_point_count_;
- bool use_interpolation_;
- float new_curve_length_;
- int add_amount_;
- int constant_points_per_curve_;
-
- /** Various matrices to convert between coordinate spaces. */
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
- float4x4 world_to_surface_mat_;
- float4x4 surface_to_world_mat_;
- float4x4 surface_to_curves_mat_;
- float4x4 surface_to_curves_normal_mat_;
+ CurvesSurfaceTransforms transforms_;
BVHTreeFromMesh surface_bvh_;
- int tot_old_curves_;
- int tot_old_points_;
-
struct AddedPoints {
Vector<float3> positions_cu;
Vector<float3> bary_coords;
Vector<int> looptri_indices;
};
- struct NeighborInfo {
- /* Curve index of the neighbor. */
- int index;
- /* The weights of all neighbors of a new curve add up to 1. */
- float weight;
- };
- static constexpr int max_neighbors = 5;
- using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
+ AddOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
void execute(AddOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -159,43 +123,21 @@ struct AddOperationExecutor {
return;
}
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
surface_ob_ = curves_id_->surface;
surface_ = static_cast<Mesh *>(surface_ob_->data);
- surface_to_world_mat_ = surface_ob_->obmat;
- world_to_surface_mat_ = surface_to_world_mat_.inverted();
- surface_to_curves_mat_ = world_to_curves_mat_ * surface_to_world_mat_;
- surface_to_curves_normal_mat_ = surface_to_curves_mat_.inverted().transposed();
- if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
- BKE_mesh_calc_normals_split(surface_);
- }
- corner_normals_su_ = {
- reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
- surface_->totloop};
-
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
brush_settings_ = brush_->curves_sculpt_settings;
- brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension);
+ brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
use_front_face_ = brush_->flag & BRUSH_FRONTFACE;
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
add_amount_ = std::max(0, brush_settings_->add_amount);
- constant_points_per_curve_ = std::max(2, brush_settings_->points_per_curve);
- interpolate_length_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
- interpolate_shape_ = brush_settings_->flag & BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
- interpolate_point_count_ = brush_settings_->flag &
- BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
- use_interpolation_ = interpolate_length_ || interpolate_shape_ || interpolate_point_count_;
- new_curve_length_ = brush_settings_->curve_length;
-
- tot_old_curves_ = curves_->curves_num();
- tot_old_points_ = curves_->points_num();
if (add_amount_ == 0) {
return;
@@ -231,42 +173,53 @@ struct AddOperationExecutor {
return;
}
- Array<NeighborsVector> neighbors_per_curve;
- if (use_interpolation_) {
- this->ensure_curve_roots_kdtree();
- neighbors_per_curve = this->find_curve_neighbors(added_points);
+ /* Find UV map. */
+ VArraySpan<float2> surface_uv_map;
+ if (curves_id_->surface_uv_map != nullptr) {
+ const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_);
+ surface_uv_map = surface_attributes.lookup<float2>(curves_id_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
}
- /* Resize to add the new curves, building the offsets in the array owned by the curves. */
- const int tot_added_curves = added_points.bary_coords.size();
- curves_->resize(curves_->points_num(), curves_->curves_num() + tot_added_curves);
- if (interpolate_point_count_) {
- this->initialize_curve_offsets_with_interpolation(neighbors_per_curve);
- }
- else {
- this->initialize_curve_offsets_without_interpolation(constant_points_per_curve_);
+ /* Find normals. */
+ if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_);
}
+ const Span<float3> corner_normals_su = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
+ surface_->totloop};
- /* Resize to add the correct point count calculated as part of building the offsets. */
- curves_->resize(curves_->offsets().last(), curves_->curves_num());
-
- this->initialize_attributes(added_points, neighbors_per_curve);
+ geometry::AddCurvesOnMeshInputs add_inputs;
+ add_inputs.root_positions_cu = added_points.positions_cu;
+ add_inputs.bary_coords = added_points.bary_coords;
+ add_inputs.looptri_indices = added_points.looptri_indices;
+ add_inputs.interpolate_length = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
+ add_inputs.interpolate_shape = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
+ add_inputs.interpolate_point_count = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+ add_inputs.fallback_curve_length = brush_settings_->curve_length;
+ add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
+ add_inputs.surface = surface_;
+ add_inputs.surface_bvh = &surface_bvh_;
+ add_inputs.surface_looptris = surface_looptris_;
+ add_inputs.surface_uv_map = surface_uv_map;
+ add_inputs.corner_normals_su = corner_normals_su;
+ add_inputs.curves_to_surface_mat = transforms_.curves_to_surface;
+ add_inputs.surface_to_curves_normal_mat = transforms_.surface_to_curves_normal;
+
+ if (add_inputs.interpolate_length || add_inputs.interpolate_shape ||
+ add_inputs.interpolate_point_count) {
+ this->ensure_curve_roots_kdtree();
+ add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_;
+ }
- curves_->update_curve_types();
+ geometry::add_curves_on_mesh(*curves_, add_inputs);
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
- }
-
- float3 get_bary_coords(const Mesh &mesh, const MLoopTri &looptri, const float3 position) const
- {
- const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
- const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
- const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
- float3 bary_coords;
- interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
- return bary_coords;
+ ED_region_tag_redraw(ctx_.region);
}
/**
@@ -276,16 +229,16 @@ struct AddOperationExecutor {
{
float3 ray_start_wo, ray_end_wo;
ED_view3d_win_to_segment_clipped(
- depsgraph_, region_, v3d_, brush_pos_re_, ray_start_wo, ray_end_wo, true);
- const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
- const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, brush_pos_re_, ray_start_wo, ray_end_wo, true);
+ const float3 ray_start_cu = transforms_.world_to_curves * ray_start_wo;
+ const float3 ray_end_cu = transforms_.world_to_curves * ray_end_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- this->sample_in_center(
- r_added_points, brush_transform * ray_start_su, brush_transform * ray_end_su);
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform;
+ this->sample_in_center(r_added_points, transform * ray_start_cu, transform * ray_end_cu);
}
}
@@ -312,10 +265,10 @@ struct AddOperationExecutor {
const int looptri_index = ray_hit.index;
const float3 brush_pos_su = ray_hit.co;
- const float3 bary_coords = this->get_bary_coords(
+ const float3 bary_coords = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
*surface_, surface_looptris_[looptri_index], brush_pos_su);
- const float3 brush_pos_cu = surface_to_curves_mat_ * brush_pos_su;
+ const float3 brush_pos_cu = transforms_.surface_to_curves * brush_pos_su;
r_added_points.positions_cu.append(brush_pos_cu);
r_added_points.bary_coords.append(bary_coords);
@@ -339,57 +292,37 @@ struct AddOperationExecutor {
const float4x4 &brush_transform)
{
const int old_amount = r_added_points.bary_coords.size();
- const int max_iterations = std::max(100'000, add_amount_ * 10);
+ const int max_iterations = 100;
int current_iteration = 0;
while (r_added_points.bary_coords.size() < old_amount + add_amount_) {
if (current_iteration++ >= max_iterations) {
break;
}
-
- const float r = brush_radius_re_ * std::sqrt(rng.get_float());
- const float angle = rng.get_float() * 2.0f * M_PI;
- const float2 pos_re = brush_pos_re_ + r * float2(std::cos(angle), std::sin(angle));
-
- float3 ray_start_wo, ray_end_wo;
- ED_view3d_win_to_segment_clipped(
- depsgraph_, region_, v3d_, pos_re, ray_start_wo, ray_end_wo, true);
- const float3 ray_start_su = brush_transform * (world_to_surface_mat_ * ray_start_wo);
- const float3 ray_end_su = brush_transform * (world_to_surface_mat_ * ray_end_wo);
- const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
-
- BVHTreeRayHit ray_hit;
- ray_hit.dist = FLT_MAX;
- ray_hit.index = -1;
- BLI_bvhtree_ray_cast(surface_bvh_.tree,
- ray_start_su,
- ray_direction_su,
- 0.0f,
- &ray_hit,
- surface_bvh_.raycast_callback,
- &surface_bvh_);
-
- if (ray_hit.index == -1) {
- continue;
- }
-
- if (use_front_face_) {
- const float3 normal_su = ray_hit.no;
- if (math::dot(ray_direction_su, normal_su) >= 0.0f) {
- continue;
- }
+ const int missing_amount = add_amount_ + old_amount - r_added_points.bary_coords.size();
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
+ rng,
+ *surface_,
+ surface_bvh_,
+ brush_pos_re_,
+ brush_radius_re_,
+ [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) {
+ float3 start_wo, end_wo;
+ ED_view3d_win_to_segment_clipped(
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true);
+ const float3 start_cu = brush_transform * (transforms_.world_to_curves * start_wo);
+ const float3 end_cu = brush_transform * (transforms_.world_to_curves * end_wo);
+ r_start_su = transforms_.curves_to_surface * start_cu;
+ r_end_su = transforms_.curves_to_surface * end_cu;
+ },
+ use_front_face_,
+ add_amount_,
+ missing_amount,
+ r_added_points.bary_coords,
+ r_added_points.looptri_indices,
+ r_added_points.positions_cu);
+ for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) {
+ pos = transforms_.surface_to_curves * pos;
}
-
- const int looptri_index = ray_hit.index;
- const float3 pos_su = ray_hit.co;
-
- const float3 bary_coords = this->get_bary_coords(
- *surface_, surface_looptris_[looptri_index], pos_su);
-
- const float3 pos_cu = surface_to_curves_mat_ * pos_su;
-
- r_added_points.positions_cu.append(pos_cu);
- r_added_points.bary_coords.append(bary_coords);
- r_added_points.looptri_indices.append(looptri_index);
}
}
@@ -398,66 +331,51 @@ struct AddOperationExecutor {
*/
void sample_spherical_with_symmetry(RandomNumberGenerator &rng, AddedPoints &r_added_points)
{
- /* Find ray that starts in the center of the brush. */
- float3 brush_ray_start_wo, brush_ray_end_wo;
- ED_view3d_win_to_segment_clipped(
- depsgraph_, region_, v3d_, brush_pos_re_, brush_ray_start_wo, brush_ray_end_wo, true);
- const float3 brush_ray_start_su = world_to_surface_mat_ * brush_ray_start_wo;
- const float3 brush_ray_end_su = world_to_surface_mat_ * brush_ray_end_wo;
-
- /* Find ray that starts on the boundary of the brush. That is used to compute the brush radius
- * in 3D. */
- float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo;
- ED_view3d_win_to_segment_clipped(depsgraph_,
- region_,
- v3d_,
- brush_pos_re_ + float2(brush_radius_re_, 0),
- brush_radius_ray_start_wo,
- brush_radius_ray_end_wo,
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ transforms_,
+ surface_bvh_,
+ brush_pos_re_,
+ brush_radius_re_);
+ if (!brush_3d.has_value()) {
+ return;
+ }
+
+ float3 view_ray_start_wo, view_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(ctx_.depsgraph,
+ ctx_.region,
+ ctx_.v3d,
+ brush_pos_re_,
+ view_ray_start_wo,
+ view_ray_end_wo,
true);
- const float3 brush_radius_ray_start_su = world_to_surface_mat_ * brush_radius_ray_start_wo;
- const float3 brush_radius_ray_end_su = world_to_surface_mat_ * brush_radius_ray_end_wo;
+
+ const float3 view_ray_start_cu = transforms_.world_to_curves * view_ray_start_wo;
+ const float3 view_ray_end_cu = transforms_.world_to_curves * view_ray_end_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
- this->sample_spherical(rng,
- r_added_points,
- brush_transform * brush_ray_start_su,
- brush_transform * brush_ray_end_su,
- brush_transform * brush_radius_ray_start_su,
- brush_transform * brush_radius_ray_end_su);
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform;
+
+ const float3 brush_pos_su = transform * brush_3d->position_cu;
+ const float3 view_direction_su = math::normalize(transform * view_ray_end_cu -
+ transform * view_ray_start_cu);
+ const float brush_radius_su = transform_brush_radius(
+ transform, brush_3d->position_cu, brush_3d->radius_cu);
+
+ this->sample_spherical(
+ rng, r_added_points, brush_pos_su, brush_radius_su, view_direction_su);
}
}
void sample_spherical(RandomNumberGenerator &rng,
AddedPoints &r_added_points,
- const float3 &brush_ray_start_su,
- const float3 &brush_ray_end_su,
- const float3 &brush_radius_ray_start_su,
- const float3 &brush_radius_ray_end_su)
+ const float3 &brush_pos_su,
+ const float brush_radius_su,
+ const float3 &view_direction_su)
{
- const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
-
- BVHTreeRayHit ray_hit;
- ray_hit.dist = FLT_MAX;
- ray_hit.index = -1;
- BLI_bvhtree_ray_cast(surface_bvh_.tree,
- brush_ray_start_su,
- brush_ray_direction_su,
- 0.0f,
- &ray_hit,
- surface_bvh_.raycast_callback,
- &surface_bvh_);
-
- if (ray_hit.index == -1) {
- return;
- }
-
- /* Compute brush radius. */
- const float3 brush_pos_su = ray_hit.co;
- const float brush_radius_su = dist_to_line_v3(
- brush_pos_su, brush_radius_ray_start_su, brush_radius_ray_end_su);
const float brush_radius_sq_su = pow2f(brush_radius_su);
/* Find surface triangles within brush radius. */
@@ -474,7 +392,7 @@ struct AddOperationExecutor {
const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
float3 normal_su;
normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
- if (math::dot(normal_su, brush_ray_direction_su) >= 0.0f) {
+ if (math::dot(normal_su, view_direction_su) >= 0.0f) {
return;
}
looptri_indices.append(index);
@@ -496,9 +414,6 @@ struct AddOperationExecutor {
const float brush_plane_area_su = M_PI * brush_radius_sq_su;
const float approximate_density_su = add_amount_ / brush_plane_area_su;
- /* Used for switching between two triangle sampling strategies. */
- const float area_threshold = brush_plane_area_su;
-
/* Usually one or two iterations should be enough. */
const int max_iterations = 5;
int current_iteration = 0;
@@ -508,78 +423,18 @@ struct AddOperationExecutor {
if (current_iteration++ >= max_iterations) {
break;
}
-
- for (const int looptri_index : looptri_indices) {
- const MLoopTri &looptri = surface_looptris_[looptri_index];
-
- const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co;
- const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co;
- const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
-
- const float looptri_area_su = area_tri_v3(v0_su, v1_su, v2_su);
-
- if (looptri_area_su < area_threshold) {
- /* The triangle is small compared to the brush radius. Sample by generating random
- * barycentric coordinates. */
- const int amount = rng.round_probabilistic(approximate_density_su * looptri_area_su);
- for ([[maybe_unused]] const int i : IndexRange(amount)) {
- const float3 bary_coord = rng.get_barycentric_coordinates();
- const float3 point_pos_su = attribute_math::mix3(bary_coord, v0_su, v1_su, v2_su);
- const float distance_to_brush_sq_su = math::distance_squared(point_pos_su,
- brush_pos_su);
- if (distance_to_brush_sq_su > brush_radius_sq_su) {
- continue;
- }
-
- r_added_points.bary_coords.append(bary_coord);
- r_added_points.looptri_indices.append(looptri_index);
- r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
- }
- }
- else {
- /* The triangle is large compared to the brush radius. Sample by generating random points
- * on the triangle plane within the brush radius. */
- float3 normal_su;
- normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
-
- float3 brush_pos_proj_su = brush_pos_su;
- project_v3_plane(brush_pos_proj_su, normal_su, v0_su);
-
- const float proj_distance_sq_su = math::distance_squared(brush_pos_proj_su,
- brush_pos_su);
- const float brush_radius_factor_sq = 1.0f -
- std::min(1.0f,
- proj_distance_sq_su / brush_radius_sq_su);
- const float radius_proj_sq_su = brush_radius_sq_su * brush_radius_factor_sq;
- const float radius_proj_su = std::sqrt(radius_proj_sq_su);
- const float circle_area_su = M_PI * radius_proj_su;
-
- const int amount = rng.round_probabilistic(approximate_density_su * circle_area_su);
-
- const float3 axis_1_su = math::normalize(v1_su - v0_su) * radius_proj_su;
- const float3 axis_2_su = math::normalize(math::cross(
- axis_1_su, math::cross(axis_1_su, v2_su - v0_su))) *
- radius_proj_su;
-
- for ([[maybe_unused]] const int i : IndexRange(amount)) {
- const float r = std::sqrt(rng.get_float());
- const float angle = rng.get_float() * 2.0f * M_PI;
- const float x = r * std::cos(angle);
- const float y = r * std::sin(angle);
- const float3 point_pos_su = brush_pos_proj_su + axis_1_su * x + axis_2_su * y;
- if (!isect_point_tri_prism_v3(point_pos_su, v0_su, v1_su, v2_su)) {
- /* Sampled point is not in the triangle. */
- continue;
- }
-
- float3 bary_coord;
- interp_weights_tri_v3(bary_coord, v0_su, v1_su, v2_su, point_pos_su);
-
- r_added_points.bary_coords.append(bary_coord);
- r_added_points.looptri_indices.append(looptri_index);
- r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
- }
- }
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
+ rng,
+ *surface_,
+ looptri_indices,
+ brush_pos_su,
+ brush_radius_su,
+ approximate_density_su,
+ r_added_points.bary_coords,
+ r_added_points.looptri_indices,
+ r_added_points.positions_cu);
+ for (float3 &pos : r_added_points.positions_cu.as_mutable_span().take_back(new_points)) {
+ pos = transforms_.surface_to_curves * pos;
}
}
@@ -604,269 +459,11 @@ struct AddOperationExecutor {
BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
}
}
-
- void initialize_curve_offsets_with_interpolation(const Span<NeighborsVector> neighbors_per_curve)
- {
- MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
-
- attribute_math::DefaultMixer<int> mixer{new_offsets};
- threading::parallel_for(neighbors_per_curve.index_range(), 1024, [&](IndexRange curves_range) {
- for (const int i : curves_range) {
- if (neighbors_per_curve[i].is_empty()) {
- mixer.mix_in(i, constant_points_per_curve_, 1.0f);
- }
- else {
- for (const NeighborInfo &neighbor : neighbors_per_curve[i]) {
- const int neighbor_points_num = curves_->points_for_curve(neighbor.index).size();
- mixer.mix_in(i, neighbor_points_num, neighbor.weight);
- }
- }
- }
- });
- mixer.finalize();
-
- bke::curves::accumulate_counts_to_offsets(new_offsets, tot_old_points_);
- }
-
- void initialize_curve_offsets_without_interpolation(const int points_per_curve)
- {
- MutableSpan<int> new_offsets = curves_->offsets_for_write().drop_front(tot_old_curves_);
- int offset = tot_old_points_;
- for (const int i : new_offsets.index_range()) {
- new_offsets[i] = offset;
- offset += points_per_curve;
- }
- }
-
- void initialize_attributes(const AddedPoints &added_points,
- const Span<NeighborsVector> neighbors_per_curve)
- {
- Array<float> new_lengths_cu(added_points.bary_coords.size());
- if (interpolate_length_) {
- this->interpolate_lengths(neighbors_per_curve, new_lengths_cu);
- }
- else {
- new_lengths_cu.fill(new_curve_length_);
- }
-
- Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points);
- this->initialize_surface_attachment(added_points);
-
- if (interpolate_shape_) {
- this->initialize_position_with_interpolation(
- added_points, neighbors_per_curve, new_normals_su, new_lengths_cu);
- }
- else {
- this->initialize_position_without_interpolation(
- added_points, new_lengths_cu, new_normals_su);
- }
- }
-
- Array<NeighborsVector> find_curve_neighbors(const AddedPoints &added_points)
- {
- const int tot_added_curves = added_points.bary_coords.size();
- Array<NeighborsVector> neighbors_per_curve(tot_added_curves);
- threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) {
- for (const int i : range) {
- const float3 root_cu = added_points.positions_cu[i];
- std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
- const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
- self_->curve_roots_kdtree_, root_cu, nearest_n.data(), max_neighbors);
- float tot_weight = 0.0f;
- for (const int neighbor_i : IndexRange(found_neighbors)) {
- KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
- const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
- tot_weight += weight;
- neighbors_per_curve[i].append({nearest.index, weight});
- }
- /* Normalize weights. */
- for (NeighborInfo &neighbor : neighbors_per_curve[i]) {
- neighbor.weight /= tot_weight;
- }
- }
- });
- return neighbors_per_curve;
- }
-
- void interpolate_lengths(const Span<NeighborsVector> neighbors_per_curve,
- MutableSpan<float> r_lengths)
- {
- const Span<float3> positions_cu = curves_->positions();
-
- threading::parallel_for(r_lengths.index_range(), 128, [&](const IndexRange range) {
- for (const int added_curve_i : range) {
- const Span<NeighborInfo> neighbors = neighbors_per_curve[added_curve_i];
- float length_sum = 0.0f;
- for (const NeighborInfo &neighbor : neighbors) {
- const IndexRange neighbor_points = curves_->points_for_curve(neighbor.index);
- float neighbor_length = 0.0f;
- for (const int segment_i : neighbor_points.drop_back(1)) {
- const float3 &p1 = positions_cu[segment_i];
- const float3 &p2 = positions_cu[segment_i + 1];
- neighbor_length += math::distance(p1, p2);
- }
- length_sum += neighbor.weight * neighbor_length;
- }
- const float length = neighbors.is_empty() ? new_curve_length_ : length_sum;
- r_lengths[added_curve_i] = length;
- }
- });
- }
-
- float3 compute_point_normal_su(const int looptri_index, const float3 &bary_coord)
- {
- const MLoopTri &looptri = surface_looptris_[looptri_index];
- const int l0 = looptri.tri[0];
- const int l1 = looptri.tri[1];
- const int l2 = looptri.tri[2];
-
- const float3 &l0_normal_su = corner_normals_su_[l0];
- const float3 &l1_normal_su = corner_normals_su_[l1];
- const float3 &l2_normal_su = corner_normals_su_[l2];
-
- const float3 normal_su = math::normalize(
- attribute_math::mix3(bary_coord, l0_normal_su, l1_normal_su, l2_normal_su));
- return normal_su;
- }
-
- Array<float3> compute_normals_for_added_curves_su(const AddedPoints &added_points)
- {
- Array<float3> normals_su(added_points.bary_coords.size());
- threading::parallel_for(normals_su.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const int looptri_index = added_points.looptri_indices[i];
- const float3 &bary_coord = added_points.bary_coords[i];
- normals_su[i] = this->compute_point_normal_su(looptri_index, bary_coord);
- }
- });
- return normals_su;
- }
-
- void initialize_surface_attachment(const AddedPoints &added_points)
- {
- MutableSpan<int> surface_triangle_indices = curves_->surface_triangle_indices_for_write();
- MutableSpan<float2> surface_triangle_coords = curves_->surface_triangle_coords_for_write();
- threading::parallel_for(
- added_points.bary_coords.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- const int curve_i = tot_old_curves_ + i;
- surface_triangle_indices[curve_i] = added_points.looptri_indices[i];
- surface_triangle_coords[curve_i] = float2(added_points.bary_coords[i]);
- }
- });
- }
-
- /**
- * Initialize new curves so that they are just a straight line in the normal direction.
- */
- void initialize_position_without_interpolation(const AddedPoints &added_points,
- const Span<float> lengths_cu,
- const MutableSpan<float3> normals_su)
- {
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
-
- threading::parallel_for(
- added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
- const float3 &root_cu = added_points.positions_cu[i];
- const float length = lengths_cu[i];
- const float3 &normal_su = normals_su[i];
- const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
- const float3 tip_cu = root_cu + length * normal_cu;
-
- initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
- }
- });
- }
-
- /**
- * Use neighboring curves to determine the shape.
- */
- void initialize_position_with_interpolation(const AddedPoints &added_points,
- const Span<NeighborsVector> neighbors_per_curve,
- const Span<float3> new_normals_su,
- const Span<float> new_lengths_cu)
- {
- MutableSpan<float3> positions_cu = curves_->positions_for_write();
- const VArray_Span<int> surface_triangle_indices{curves_->surface_triangle_indices()};
- const Span<float2> surface_triangle_coords = curves_->surface_triangle_coords();
-
- threading::parallel_for(
- added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
- for (const int i : range) {
- const Span<NeighborInfo> neighbors = neighbors_per_curve[i];
- const IndexRange points = curves_->points_for_curve(tot_old_curves_ + i);
-
- const float length_cu = new_lengths_cu[i];
- const float3 &normal_su = new_normals_su[i];
- const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
-
- const float3 &root_cu = added_points.positions_cu[i];
-
- if (neighbors.is_empty()) {
- /* If there are no neighbors, just make a straight line. */
- const float3 tip_cu = root_cu + length_cu * normal_cu;
- initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
- continue;
- }
-
- positions_cu.slice(points).fill(root_cu);
-
- for (const NeighborInfo &neighbor : neighbors) {
- const int neighbor_curve_i = neighbor.index;
- const int neighbor_looptri_index = surface_triangle_indices[neighbor_curve_i];
-
- float3 neighbor_bary_coord{surface_triangle_coords[neighbor_curve_i]};
- neighbor_bary_coord.z = 1.0f - neighbor_bary_coord.x - neighbor_bary_coord.y;
-
- const float3 neighbor_normal_su = this->compute_point_normal_su(
- neighbor_looptri_index, neighbor_bary_coord);
- const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat_ *
- neighbor_normal_su);
-
- /* The rotation matrix used to transform relative coordinates of the neighbor curve
- * to the new curve. */
- float normal_rotation_cu[3][3];
- rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
-
- const IndexRange neighbor_points = curves_->points_for_curve(neighbor_curve_i);
- const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
-
- /* Use a temporary #PolySpline, because that's the easiest way to resample an
- * existing curve right now. Resampling is necessary if the length of the new curve
- * does not match the length of the neighbors or the number of handle points is
- * different. */
- PolySpline neighbor_spline;
- neighbor_spline.resize(neighbor_points.size());
- neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points));
- neighbor_spline.mark_cache_invalid();
-
- const float neighbor_length_cu = neighbor_spline.length();
- const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
-
- const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor;
- for (const int j : IndexRange(points.size())) {
- const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor(
- j * resample_factor);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- neighbor_spline.sample_with_index_factors<float3>(
- neighbor_spline.positions(), {&index_factor, 1}, {&p, 1});
- const float3 relative_coord = p - neighbor_root_cu;
- float3 rotated_relative_coord = relative_coord;
- mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
- positions_cu[points[j]] += neighbor.weight * rotated_relative_coord;
- }
- }
- }
- });
- }
};
void AddOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
{
- AddOperationExecutor executor;
+ AddOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
index 92ce6ba3153..10564942ab9 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_brush.cc
@@ -4,6 +4,7 @@
#include "curves_sculpt_intern.hh"
+#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
@@ -12,7 +13,11 @@
#include "UI_interface.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_length_parameterize.hh"
#include "BLI_task.hh"
/**
@@ -249,6 +254,55 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
return brush_3d;
}
+std::optional<CurvesBrush3D> sample_curves_surface_3d_brush(
+ const Depsgraph &depsgraph,
+ const ARegion &region,
+ const View3D &v3d,
+ const CurvesSurfaceTransforms &transforms,
+ const BVHTreeFromMesh &surface_bvh,
+ const float2 &brush_pos_re,
+ const float brush_radius_re)
+{
+ float3 brush_ray_start_wo, brush_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ &depsgraph, &region, &v3d, brush_pos_re, brush_ray_start_wo, brush_ray_end_wo, true);
+ const float3 brush_ray_start_su = transforms.world_to_surface * brush_ray_start_wo;
+ const float3 brush_ray_end_su = transforms.world_to_surface * brush_ray_end_wo;
+
+ const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh.tree,
+ brush_ray_start_su,
+ brush_ray_direction_su,
+ 0.0f,
+ &ray_hit,
+ surface_bvh.raycast_callback,
+ const_cast<void *>(static_cast<const void *>(&surface_bvh)));
+ if (ray_hit.index == -1) {
+ return std::nullopt;
+ }
+
+ float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(&depsgraph,
+ &region,
+ &v3d,
+ brush_pos_re + float2(brush_radius_re, 0),
+ brush_radius_ray_start_wo,
+ brush_radius_ray_end_wo,
+ true);
+ const float3 brush_radius_ray_start_cu = transforms.world_to_curves * brush_radius_ray_start_wo;
+ const float3 brush_radius_ray_end_cu = transforms.world_to_curves * brush_radius_ray_end_wo;
+
+ const float3 brush_pos_su = ray_hit.co;
+ const float3 brush_pos_cu = transforms.surface_to_curves * brush_pos_su;
+ const float brush_radius_cu = dist_to_line_v3(
+ brush_pos_cu, brush_radius_ray_start_cu, brush_radius_ray_end_cu);
+ return CurvesBrush3D{brush_pos_cu, brush_radius_cu};
+}
+
Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
{
Vector<float4x4> matrices;
@@ -277,4 +331,53 @@ Vector<float4x4> get_symmetry_brush_transforms(const eCurvesSymmetryType symmetr
return matrices;
}
+float transform_brush_radius(const float4x4 &transform,
+ const float3 &brush_position,
+ const float old_radius)
+{
+ const float3 offset_position = brush_position + float3(old_radius, 0.0f, 0.0f);
+ const float3 new_position = transform * brush_position;
+ const float3 new_offset_position = transform * offset_position;
+ return math::distance(new_position, new_offset_position);
+}
+
+void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position)
+{
+ /* Find the accumulated length of each point in the original curve,
+ * treating it as a poly curve for performance reasons and simplicity. */
+ Array<float> orig_lengths(length_parameterize::segments_num(positions.size(), false));
+ length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths);
+ const float orig_total_length = orig_lengths.last();
+
+ /* Find the factor by which the new curve is shorter or longer than the original. */
+ const float new_last_segment_length = math::distance(positions.last(1), new_last_position);
+ const float new_total_length = orig_lengths.last(1) + new_last_segment_length;
+ const float length_factor = safe_divide(new_total_length, orig_total_length);
+
+ /* Calculate the lengths to sample the original curve with by scaling the original lengths. */
+ Array<float> new_lengths(positions.size() - 1);
+ new_lengths.first() = 0.0f;
+ for (const int i : new_lengths.index_range().drop_front(1)) {
+ new_lengths[i] = orig_lengths[i - 1] * length_factor;
+ }
+
+ Array<int> indices(positions.size() - 1);
+ Array<float> factors(positions.size() - 1);
+ length_parameterize::sample_at_lengths(orig_lengths, new_lengths, indices, factors);
+
+ Array<float3> new_positions(positions.size() - 1);
+ length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions);
+ positions.drop_back(1).copy_from(new_positions);
+ positions.last() = new_last_position;
+}
+
+CurvesSculptCommonContext::CurvesSculptCommonContext(const bContext &C)
+{
+ this->depsgraph = CTX_data_depsgraph_pointer(&C);
+ this->scene = CTX_data_scene(&C);
+ this->region = CTX_wm_region(&C);
+ this->v3d = CTX_wm_view3d(&C);
+ this->rv3d = CTX_wm_region_view3d(&C);
+}
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
index 1fcab2290e8..449f1786167 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -78,11 +78,7 @@ class CombOperation : public CurvesSculptStrokeOperation {
*/
struct CombOperationExecutor {
CombOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
@@ -96,21 +92,19 @@ struct CombOperationExecutor {
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
- const Object *surface_ob_ = nullptr;
- const Mesh *surface_ = nullptr;
- Span<MLoopTri> surface_looptris_;
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
float2 brush_pos_prev_re_;
float2 brush_pos_re_;
float2 brush_pos_diff_re_;
- float brush_pos_diff_length_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
- float4x4 surface_to_world_mat_;
- float4x4 world_to_surface_mat_;
+ CurvesSurfaceTransforms transforms_;
- BVHTreeFromMesh surface_bvh_;
+ CombOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
void execute(CombOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
{
@@ -118,21 +112,13 @@ struct CombOperationExecutor {
BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; });
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
- brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
-
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
@@ -142,26 +128,14 @@ struct CombOperationExecutor {
return;
}
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
brush_pos_prev_re_ = self_->brush_pos_last_re_;
brush_pos_re_ = stroke_extension.mouse_position;
brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
- brush_pos_diff_length_re_ = math::length(brush_pos_diff_re_);
-
- surface_ob_ = curves_id_->surface;
- if (surface_ob_ != nullptr) {
- surface_ = static_cast<const Mesh *>(surface_ob_->data);
- surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
- BKE_mesh_runtime_looptri_len(surface_)};
- surface_to_world_mat_ = surface_ob_->obmat;
- world_to_surface_mat_ = surface_to_world_mat_.inverted();
- BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
- }
-
- BLI_SCOPED_DEFER([&]() {
- if (surface_ob_ != nullptr) {
- free_bvhtree_from_mesh(&surface_bvh_);
- }
- });
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
@@ -189,7 +163,7 @@ struct CombOperationExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
/**
@@ -212,14 +186,14 @@ struct CombOperationExecutor {
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
- threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
Vector<int> &local_changed_curves = r_changed_curves.local();
- for (const int curve_i : curves_range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
bool curve_changed = false;
const IndexRange points = curves_->points_for_curve(curve_i);
for (const int point_i : points.drop_front(1)) {
@@ -227,7 +201,7 @@ struct CombOperationExecutor {
/* Find the position of the point in screen space. */
float2 old_pos_re;
- ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2(
old_pos_re, brush_pos_prev_re_, brush_pos_re_);
@@ -241,15 +215,19 @@ struct CombOperationExecutor {
const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_re, brush_radius_re);
/* Combine the falloff and brush strength. */
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * point_factors_[point_i];
- /* Offset the old point position in screen space and transform it back into 3D space. */
+ /* Offset the old point position in screen space and transform it back into 3D space.
+ */
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
float3 new_position_wo;
- ED_view3d_win_to_3d(
- v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * old_pos_cu,
+ new_position_re,
+ new_position_wo);
const float3 new_position_cu = brush_transform *
- (world_to_curves_mat_ * new_position_wo);
+ (transforms_.world_to_curves * new_position_wo);
positions_cu[point_i] = new_position_cu;
curve_changed = true;
@@ -267,21 +245,21 @@ struct CombOperationExecutor {
void comb_spherical_with_symmetry(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_prev_re_,
brush_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo;
+ const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
@@ -304,9 +282,9 @@ struct CombOperationExecutor {
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
- threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
Vector<int> &local_changed_curves = r_changed_curves.local();
- for (const int curve_i : curves_range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
bool curve_changed = false;
const IndexRange points = curves_->points_for_curve(curve_i);
for (const int point_i : points.drop_front(1)) {
@@ -326,7 +304,7 @@ struct CombOperationExecutor {
const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_cu, brush_radius_cu);
/* Combine the falloff and brush strength. */
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * point_factors_[point_i];
/* Update the point position. */
positions_cu[point_i] = pos_old_cu + weight * brush_diff_cu;
@@ -344,8 +322,13 @@ struct CombOperationExecutor {
*/
void initialize_spherical_brush_reference_point()
{
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -399,7 +382,7 @@ struct CombOperationExecutor {
void CombOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
{
- CombOperationExecutor executor;
+ CombOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
index 323e99df099..777ebd16110 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
@@ -60,16 +60,15 @@ class DeleteOperation : public CurvesSculptStrokeOperation {
struct DeleteOperationExecutor {
DeleteOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
float brush_radius_base_re_;
@@ -77,32 +76,31 @@ struct DeleteOperationExecutor {
float2 brush_pos_re_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSurfaceTransforms transforms_;
- void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ DeleteOperationExecutor(const bContext &C) : ctx_(C)
{
+ }
+ void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ selected_curve_indices_.clear();
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
brush_->falloff_shape);
@@ -134,7 +132,7 @@ struct DeleteOperationExecutor {
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
void delete_projected_with_symmetry(MutableSpan<bool> curves_to_delete)
@@ -151,20 +149,20 @@ struct DeleteOperationExecutor {
const float4x4 brush_transform_inv = brush_transform.inverted();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
Span<float3> positions_cu = curves_->positions();
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
- threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
- for (const int curve_i : curve_range) {
+ threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
const IndexRange points = curves_->points_for_curve(curve_i);
if (points.size() == 1) {
const float3 pos_cu = brush_transform_inv * positions_cu[points.first()];
float2 pos_re;
- ED_view3d_project_float_v2_m4(region_, pos_cu, pos_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) {
curves_to_delete[curve_i] = true;
@@ -177,8 +175,8 @@ struct DeleteOperationExecutor {
const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1];
float2 pos1_re, pos2_re;
- ED_view3d_project_float_v2_m4(region_, pos1_cu, pos1_re, projection.values);
- ED_view3d_project_float_v2_m4(region_, pos2_cu, pos2_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values);
const float dist_sq_re = dist_squared_to_line_segment_v2(
brush_pos_re_, pos1_re, pos2_re);
@@ -194,15 +192,15 @@ struct DeleteOperationExecutor {
void delete_spherical_with_symmetry(MutableSpan<bool> curves_to_delete)
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_wo);
- const float3 brush_cu = world_to_curves_mat_ * brush_wo;
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -219,8 +217,8 @@ struct DeleteOperationExecutor {
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
- threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
- for (const int curve_i : curve_range) {
+ threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
const IndexRange points = curves_->points_for_curve(curve_i);
if (points.size() == 1) {
@@ -249,8 +247,13 @@ struct DeleteOperationExecutor {
void initialize_spherical_brush_reference_point()
{
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -260,7 +263,7 @@ struct DeleteOperationExecutor {
void DeleteOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
- DeleteOperationExecutor executor;
+ DeleteOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
new file mode 100644
index 00000000000..e211a568705
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc
@@ -0,0 +1,827 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <numeric>
+
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BLI_index_mask_ops.hh"
+#include "BLI_kdtree.h"
+#include "BLI_rand.hh"
+#include "BLI_task.hh"
+
+#include "PIL_time.h"
+
+#include "GEO_add_curves_on_mesh.hh"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+
+#include "WM_api.h"
+
+#include "curves_sculpt_intern.hh"
+
+namespace blender::ed::sculpt_paint {
+
+class DensityAddOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Used when some data should be interpolated from existing curves. */
+ KDTree_3d *curve_roots_kdtree_ = nullptr;
+ int original_curve_num_ = 0;
+
+ friend struct DensityAddOperationExecutor;
+
+ public:
+ ~DensityAddOperation() override
+ {
+ if (curve_roots_kdtree_ != nullptr) {
+ BLI_kdtree_3d_free(curve_roots_kdtree_);
+ }
+ }
+
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+struct DensityAddOperationExecutor {
+ DensityAddOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ Object *surface_ob_ = nullptr;
+ Mesh *surface_ = nullptr;
+ Span<MLoopTri> surface_looptris_;
+ Span<float3> corner_normals_su_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ const BrushCurvesSculptSettings *brush_settings_ = nullptr;
+
+ float brush_strength_;
+ float brush_radius_re_;
+ float2 brush_pos_re_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ BVHTreeFromMesh surface_bvh_;
+
+ DensityAddOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(DensityAddOperation &self,
+ const bContext &C,
+ const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+ object_ = CTX_data_active_object(&C);
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+
+ if (stroke_extension.is_first) {
+ self_->original_curve_num_ = curves_->curves_num();
+ }
+
+ if (curves_id_->surface == nullptr || curves_id_->surface->type != OB_MESH) {
+ return;
+ }
+
+ surface_ob_ = curves_id_->surface;
+ surface_ = static_cast<Mesh *>(surface_ob_->data);
+
+ surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
+ BKE_mesh_runtime_looptri_len(surface_)};
+
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_);
+ }
+ corner_normals_su_ = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
+ surface_->totloop};
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_settings_ = brush_->curves_sculpt_settings;
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_radius_re_ = brush_radius_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+
+ BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
+
+ Vector<float3> new_bary_coords;
+ Vector<int> new_looptri_indices;
+ Vector<float3> new_positions_cu;
+ const double time = PIL_check_seconds_timer() * 1000000.0;
+ RandomNumberGenerator rng{*(uint32_t *)(&time)};
+
+ /* Find potential new curve root points. */
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->sample_projected_with_symmetry(
+ rng, new_bary_coords, new_looptri_indices, new_positions_cu);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->sample_spherical_with_symmetry(
+ rng, new_bary_coords, new_looptri_indices, new_positions_cu);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ for (float3 &pos : new_positions_cu) {
+ pos = transforms_.surface_to_curves * pos;
+ }
+
+ this->ensure_curve_roots_kdtree();
+
+ const int already_added_curves = curves_->curves_num() - self_->original_curve_num_;
+ KDTree_3d *new_roots_kdtree = BLI_kdtree_3d_new(already_added_curves +
+ new_positions_cu.size());
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(new_roots_kdtree); });
+
+ /* Used to tag all curves that are too close to existing curves or too close to other new
+ * curves. */
+ Array<bool> new_curve_skipped(new_positions_cu.size(), false);
+ threading::parallel_invoke(
+ /* Build kdtree from root points created by the current stroke. */
+ [&]() {
+ const Span<float3> positions_cu = curves_->positions();
+ for (const int curve_i : curves_->curves_range().take_back(already_added_curves)) {
+ const float3 &root_pos_cu = positions_cu[curves_->offsets()[curve_i]];
+ BLI_kdtree_3d_insert(new_roots_kdtree, curve_i, root_pos_cu);
+ }
+ for (const int new_i : new_positions_cu.index_range()) {
+ const int index_in_kdtree = curves_->curves_num() + new_i;
+ const float3 &root_pos_cu = new_positions_cu[new_i];
+ BLI_kdtree_3d_insert(new_roots_kdtree, index_in_kdtree, root_pos_cu);
+ }
+ BLI_kdtree_3d_balance(new_roots_kdtree);
+ },
+ /* Check which new root points are close to roots that existed before the current stroke
+ * started. */
+ [&]() {
+ threading::parallel_for(
+ new_positions_cu.index_range(), 128, [&](const IndexRange range) {
+ for (const int new_i : range) {
+ const float3 &new_root_pos_cu = new_positions_cu[new_i];
+ KDTreeNearest_3d nearest;
+ nearest.dist = FLT_MAX;
+ BLI_kdtree_3d_find_nearest(
+ self_->curve_roots_kdtree_, new_root_pos_cu, &nearest);
+ if (nearest.dist < brush_settings_->minimum_distance) {
+ new_curve_skipped[new_i] = true;
+ }
+ }
+ });
+ });
+
+ /* Find new points that are too close too other new points. */
+ for (const int new_i : new_positions_cu.index_range()) {
+ if (new_curve_skipped[new_i]) {
+ continue;
+ }
+ const float3 &root_pos_cu = new_positions_cu[new_i];
+ BLI_kdtree_3d_range_search_cb_cpp(
+ new_roots_kdtree,
+ root_pos_cu,
+ brush_settings_->minimum_distance,
+ [&](const int other_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ if (other_i < curves_->curves_num()) {
+ new_curve_skipped[new_i] = true;
+ return false;
+ }
+ const int other_new_i = other_i - curves_->curves_num();
+ if (new_i == other_new_i) {
+ return true;
+ }
+ new_curve_skipped[other_new_i] = true;
+ return true;
+ });
+ }
+
+ /* Remove points that are too close to others. */
+ for (int64_t i = new_positions_cu.size() - 1; i >= 0; i--) {
+ if (new_curve_skipped[i]) {
+ new_positions_cu.remove_and_reorder(i);
+ new_bary_coords.remove_and_reorder(i);
+ new_looptri_indices.remove_and_reorder(i);
+ }
+ }
+
+ /* Find UV map. */
+ VArraySpan<float2> surface_uv_map;
+ if (curves_id_->surface_uv_map != nullptr) {
+ bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_);
+ surface_uv_map = surface_attributes.lookup<float2>(curves_id_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
+ }
+
+ /* Find normals. */
+ if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_);
+ }
+ const Span<float3> corner_normals_su = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
+ surface_->totloop};
+
+ geometry::AddCurvesOnMeshInputs add_inputs;
+ add_inputs.root_positions_cu = new_positions_cu;
+ add_inputs.bary_coords = new_bary_coords;
+ add_inputs.looptri_indices = new_looptri_indices;
+ add_inputs.interpolate_length = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
+ add_inputs.interpolate_shape = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
+ add_inputs.interpolate_point_count = brush_settings_->flag &
+ BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT;
+ add_inputs.fallback_curve_length = brush_settings_->curve_length;
+ add_inputs.fallback_point_count = std::max(2, brush_settings_->points_per_curve);
+ add_inputs.surface = surface_;
+ add_inputs.surface_bvh = &surface_bvh_;
+ add_inputs.surface_looptris = surface_looptris_;
+ add_inputs.surface_uv_map = surface_uv_map;
+ add_inputs.corner_normals_su = corner_normals_su;
+ add_inputs.curves_to_surface_mat = transforms_.curves_to_surface;
+ add_inputs.surface_to_curves_normal_mat = transforms_.surface_to_curves_normal;
+ add_inputs.old_roots_kdtree = self_->curve_roots_kdtree_;
+
+ geometry::add_curves_on_mesh(*curves_, add_inputs);
+
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void ensure_curve_roots_kdtree()
+ {
+ if (self_->curve_roots_kdtree_ == nullptr) {
+ self_->curve_roots_kdtree_ = BLI_kdtree_3d_new(curves_->curves_num());
+ for (const int curve_i : curves_->curves_range()) {
+ const int root_point_i = curves_->offsets()[curve_i];
+ const float3 &root_pos_cu = curves_->positions()[root_point_i];
+ BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, root_pos_cu);
+ }
+ BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
+ }
+ }
+
+ void sample_projected_with_symmetry(RandomNumberGenerator &rng,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions_su)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+ const float4x4 transform = transforms_.curves_to_surface * brush_transform *
+ transforms_.world_to_curves;
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_projected(
+ rng,
+ *surface_,
+ surface_bvh_,
+ brush_pos_re_,
+ brush_radius_re_,
+ [&](const float2 &pos_re, float3 &r_start_su, float3 &r_end_su) {
+ float3 start_wo, end_wo;
+ ED_view3d_win_to_segment_clipped(
+ ctx_.depsgraph, ctx_.region, ctx_.v3d, pos_re, start_wo, end_wo, true);
+ r_start_su = transform * start_wo;
+ r_end_su = transform * end_wo;
+ },
+ true,
+ brush_settings_->density_add_attempts,
+ brush_settings_->density_add_attempts,
+ r_bary_coords,
+ r_looptri_indices,
+ r_positions_su);
+
+ /* Remove some sampled points randomly based on the brush falloff and strength. */
+ const int old_points = r_bary_coords.size() - new_points;
+ for (int i = r_bary_coords.size() - 1; i >= old_points; i--) {
+ const float3 pos_su = r_positions_su[i];
+ const float3 pos_cu = brush_transform_inv * transforms_.surface_to_curves * pos_su;
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ const float dist_to_brush_re = math::distance(brush_pos_re_, pos_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re_);
+ const float weight = brush_strength_ * radius_falloff;
+ if (rng.get_float() > weight) {
+ r_bary_coords.remove_and_reorder(i);
+ r_looptri_indices.remove_and_reorder(i);
+ r_positions_su.remove_and_reorder(i);
+ }
+ }
+ }
+ }
+
+ void sample_spherical_with_symmetry(RandomNumberGenerator &rng,
+ Vector<float3> &r_bary_coords,
+ Vector<int> &r_looptri_indices,
+ Vector<float3> &r_positions_su)
+ {
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ transforms_,
+ surface_bvh_,
+ brush_pos_re_,
+ brush_radius_re_);
+ if (!brush_3d.has_value()) {
+ return;
+ }
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ const float3 brush_pos_cu = brush_transform * brush_3d->position_cu;
+ const float3 brush_pos_su = transforms_.curves_to_surface * brush_pos_cu;
+ const float brush_radius_su = transform_brush_radius(
+ transforms_.curves_to_surface, brush_pos_cu, brush_3d->radius_cu);
+ const float brush_radius_sq_su = pow2f(brush_radius_su);
+
+ Vector<int> looptri_indices;
+ BLI_bvhtree_range_query_cpp(
+ *surface_bvh_.tree,
+ brush_pos_su,
+ brush_radius_su,
+ [&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
+ looptri_indices.append(index);
+ });
+
+ const float brush_plane_area_su = M_PI * brush_radius_sq_su;
+ const float approximate_density_su = brush_settings_->density_add_attempts /
+ brush_plane_area_su;
+
+ const int new_points = bke::mesh_surface_sample::sample_surface_points_spherical(
+ rng,
+ *surface_,
+ looptri_indices,
+ brush_pos_su,
+ brush_radius_su,
+ approximate_density_su,
+ r_bary_coords,
+ r_looptri_indices,
+ r_positions_su);
+
+ /* Remove some sampled points randomly based on the brush falloff and strength. */
+ const int old_points = r_bary_coords.size() - new_points;
+ for (int i = r_bary_coords.size() - 1; i >= old_points; i--) {
+ const float3 pos_su = r_positions_su[i];
+ const float3 pos_cu = transforms_.surface_to_curves * pos_su;
+ const float dist_to_brush_cu = math::distance(pos_cu, brush_pos_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_3d->radius_cu);
+ const float weight = brush_strength_ * radius_falloff;
+ if (rng.get_float() > weight) {
+ r_bary_coords.remove_and_reorder(i);
+ r_looptri_indices.remove_and_reorder(i);
+ r_positions_su.remove_and_reorder(i);
+ }
+ }
+ }
+ }
+};
+
+void DensityAddOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
+{
+ DensityAddOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+class DensitySubtractOperation : public CurvesSculptStrokeOperation {
+ private:
+ friend struct DensitySubtractOperationExecutor;
+
+ public:
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct DensitySubtractOperationExecutor {
+ DensitySubtractOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ Object *surface_ob_ = nullptr;
+ Mesh *surface_ = nullptr;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+ float2 brush_pos_re_;
+
+ float minimum_distance_;
+
+ CurvesSurfaceTransforms transforms_;
+ BVHTreeFromMesh surface_bvh_;
+
+ KDTree_3d *root_points_kdtree_;
+
+ DensitySubtractOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(DensitySubtractOperation &self,
+ const bContext &C,
+ const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ surface_ob_ = curves_id_->surface;
+ if (surface_ob_ == nullptr) {
+ return;
+ }
+ surface_ = static_cast<Mesh *>(surface_ob_->data);
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ minimum_distance_ = brush_->curves_sculpt_settings->minimum_distance;
+
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+ BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
+
+ const Span<float3> positions_cu = curves_->positions();
+
+ root_points_kdtree_ = BLI_kdtree_3d_new(curve_selection_.size());
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(root_points_kdtree_); });
+ for (const int curve_i : curve_selection_) {
+ const int first_point_i = curves_->offsets()[curve_i];
+ const float3 &pos_cu = positions_cu[first_point_i];
+ BLI_kdtree_3d_insert(root_points_kdtree_, curve_i, pos_cu);
+ }
+ BLI_kdtree_3d_balance(root_points_kdtree_);
+
+ /* Find all curves that should be deleted. */
+ Array<bool> curves_to_delete(curves_->curves_num(), false);
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->reduce_density_projected_with_symmetry(curves_to_delete);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->reduce_density_spherical_with_symmetry(curves_to_delete);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ Vector<int64_t> indices;
+ const IndexMask mask = index_mask_ops::find_indices_based_on_predicate(
+ curves_->curves_range(), 4096, indices, [&](const int curve_i) {
+ return curves_to_delete[curve_i];
+ });
+
+ curves_->remove_curves(mask);
+
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void reduce_density_projected_with_symmetry(MutableSpan<bool> curves_to_delete)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->reduce_density_projected(brush_transform, curves_to_delete);
+ }
+ }
+
+ void reduce_density_projected(const float4x4 &brush_transform,
+ MutableSpan<bool> curves_to_delete)
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ const Span<int> offsets = curves_->offsets();
+
+ /* Randomly select the curves that are allowed to be removed, based on the brush radius and
+ * strength. */
+ Array<bool> allow_remove_curve(curves_->curves_num(), false);
+ threading::parallel_for(curves_->curves_range(), 512, [&](const IndexRange range) {
+ RandomNumberGenerator rng((int)(PIL_check_seconds_timer() * 1000000.0));
+
+ for (const int curve_i : range) {
+ if (curves_to_delete[curve_i]) {
+ allow_remove_curve[curve_i] = true;
+ continue;
+ }
+ const int first_point_i = offsets[curve_i];
+ const float3 pos_cu = brush_transform * positions_cu[first_point_i];
+
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re);
+ const float weight = brush_strength_ * radius_falloff;
+ if (rng.get_float() < weight) {
+ allow_remove_curve[curve_i] = true;
+ }
+ }
+ });
+
+ /* Detect curves that are too close to other existing curves. */
+ for (const int curve_i : curve_selection_) {
+ if (curves_to_delete[curve_i]) {
+ continue;
+ }
+ if (!allow_remove_curve[curve_i]) {
+ continue;
+ }
+ const int first_point_i = offsets[curve_i];
+ const float3 orig_pos_cu = positions_cu[first_point_i];
+ const float3 pos_cu = brush_transform * orig_pos_cu;
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ const float dist_to_brush_sq_re = math::distance_squared(brush_pos_re_, pos_re);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+ BLI_kdtree_3d_range_search_cb_cpp(
+ root_points_kdtree_,
+ orig_pos_cu,
+ minimum_distance_,
+ [&](const int other_curve_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ if (other_curve_i == curve_i) {
+ return true;
+ }
+ if (allow_remove_curve[other_curve_i]) {
+ curves_to_delete[other_curve_i] = true;
+ }
+ return true;
+ });
+ }
+ }
+
+ void reduce_density_spherical_with_symmetry(MutableSpan<bool> curves_to_delete)
+ {
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ transforms_,
+ surface_bvh_,
+ brush_pos_re_,
+ brush_radius_re);
+ if (!brush_3d.has_value()) {
+ return;
+ }
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ const float3 brush_pos_cu = brush_transform * brush_3d->position_cu;
+ this->reduce_density_spherical(brush_pos_cu, brush_3d->radius_cu, curves_to_delete);
+ }
+ }
+
+ void reduce_density_spherical(const float3 &brush_pos_cu,
+ const float brush_radius_cu,
+ MutableSpan<bool> curves_to_delete)
+ {
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+ const Span<float3> positions_cu = curves_->positions();
+ const Span<int> offsets = curves_->offsets();
+
+ /* Randomly select the curves that are allowed to be removed, based on the brush radius and
+ * strength. */
+ Array<bool> allow_remove_curve(curves_->curves_num(), false);
+ threading::parallel_for(curves_->curves_range(), 512, [&](const IndexRange range) {
+ RandomNumberGenerator rng((int)(PIL_check_seconds_timer() * 1000000.0));
+
+ for (const int curve_i : range) {
+ if (curves_to_delete[curve_i]) {
+ allow_remove_curve[curve_i] = true;
+ continue;
+ }
+ const int first_point_i = offsets[curve_i];
+ const float3 pos_cu = positions_cu[first_point_i];
+
+ const float dist_to_brush_sq_cu = math::distance_squared(brush_pos_cu, pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_radius_cu);
+ const float weight = brush_strength_ * radius_falloff;
+ if (rng.get_float() < weight) {
+ allow_remove_curve[curve_i] = true;
+ }
+ }
+ });
+
+ /* Detect curves that are too close to other existing curves. */
+ for (const int curve_i : curve_selection_) {
+ if (curves_to_delete[curve_i]) {
+ continue;
+ }
+ if (!allow_remove_curve[curve_i]) {
+ continue;
+ }
+ const int first_point_i = offsets[curve_i];
+ const float3 &pos_cu = positions_cu[first_point_i];
+ const float dist_to_brush_sq_cu = math::distance_squared(pos_cu, brush_pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ BLI_kdtree_3d_range_search_cb_cpp(
+ root_points_kdtree_,
+ pos_cu,
+ minimum_distance_,
+ [&](const int other_curve_i, const float *UNUSED(co), float UNUSED(dist_sq)) {
+ if (other_curve_i == curve_i) {
+ return true;
+ }
+ if (allow_remove_curve[other_curve_i]) {
+ curves_to_delete[other_curve_i] = true;
+ }
+ return true;
+ });
+ }
+ }
+};
+
+void DensitySubtractOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
+{
+ DensitySubtractOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+/**
+ * Detects whether the brush should be in Add or Subtract mode.
+ */
+static bool use_add_density_mode(const BrushStrokeMode brush_mode,
+ const bContext &C,
+ const StrokeExtension &stroke_start)
+{
+ const Scene &scene = *CTX_data_scene(&C);
+ const Brush &brush = *BKE_paint_brush_for_read(&scene.toolsettings->curves_sculpt->paint);
+ const eBrushCurvesSculptDensityMode density_mode = static_cast<eBrushCurvesSculptDensityMode>(
+ brush.curves_sculpt_settings->density_mode);
+ const bool use_invert = brush_mode == BRUSH_STROKE_INVERT;
+
+ if (density_mode == BRUSH_CURVES_SCULPT_DENSITY_MODE_ADD) {
+ return !use_invert;
+ }
+ if (density_mode == BRUSH_CURVES_SCULPT_DENSITY_MODE_REMOVE) {
+ return use_invert;
+ }
+
+ const Object &curves_ob = *CTX_data_active_object(&C);
+ const Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
+ const CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ if (curves_id.surface == nullptr) {
+ /* The brush won't do anything in this case anyway. */
+ return true;
+ }
+ if (curves.curves_num() <= 1) {
+ return true;
+ }
+
+ const CurvesSurfaceTransforms transforms(curves_ob, curves_id.surface);
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(
+ &surface_bvh, static_cast<const Mesh *>(curves_id.surface->data), BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
+ const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
+ const ARegion &region = *CTX_wm_region(&C);
+ const View3D &v3d = *CTX_wm_view3d(&C);
+
+ const float2 brush_pos_re = stroke_start.mouse_position;
+ /* Reduce radius so that only an inner circle is used to determine the existing density. */
+ const float brush_radius_re = BKE_brush_size_get(&scene, &brush) * 0.5f;
+
+ /* Find the surface point under the brush. */
+ const std::optional<CurvesBrush3D> brush_3d = sample_curves_surface_3d_brush(
+ depsgraph, region, v3d, transforms, surface_bvh, brush_pos_re, brush_radius_re);
+ if (!brush_3d.has_value()) {
+ return true;
+ }
+
+ const float3 brush_pos_cu = brush_3d->position_cu;
+ const float brush_radius_cu = brush_3d->radius_cu;
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ const Span<int> offsets = curves.offsets();
+ const Span<float3> positions_cu = curves.positions();
+
+ /* Compute distance from brush to curve roots. */
+ Array<std::pair<float, int>> distances_sq_to_brush(curves.curves_num());
+ threading::EnumerableThreadSpecific<int> valid_curve_count_by_thread;
+ threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) {
+ int &valid_curve_count = valid_curve_count_by_thread.local();
+ for (const int curve_i : range) {
+ const int root_point_i = offsets[curve_i];
+ const float3 &root_pos_cu = positions_cu[root_point_i];
+ const float dist_sq_cu = math::distance_squared(root_pos_cu, brush_pos_cu);
+ if (dist_sq_cu < brush_radius_sq_cu) {
+ distances_sq_to_brush[curve_i] = {math::distance_squared(root_pos_cu, brush_pos_cu),
+ curve_i};
+ valid_curve_count++;
+ }
+ else {
+ distances_sq_to_brush[curve_i] = {FLT_MAX, -1};
+ }
+ }
+ });
+ const int valid_curve_count = std::accumulate(
+ valid_curve_count_by_thread.begin(), valid_curve_count_by_thread.end(), 0);
+
+ /* Find a couple of curves that are closest to the brush center. */
+ const int check_curve_count = std::min<int>(8, valid_curve_count);
+ std::partial_sort(distances_sq_to_brush.begin(),
+ distances_sq_to_brush.begin() + check_curve_count,
+ distances_sq_to_brush.end());
+
+ /* Compute the minimum pair-wise distance between the curve roots that are close to the brush
+ * center. */
+ float min_dist_sq_cu = FLT_MAX;
+ for (const int i : IndexRange(check_curve_count)) {
+ const float3 &pos_i = positions_cu[offsets[distances_sq_to_brush[i].second]];
+ for (int j = i + 1; j < check_curve_count; j++) {
+ const float3 &pos_j = positions_cu[offsets[distances_sq_to_brush[j].second]];
+ const float dist_sq_cu = math::distance_squared(pos_i, pos_j);
+ math::min_inplace(min_dist_sq_cu, dist_sq_cu);
+ }
+ }
+
+ const float min_dist_cu = std::sqrt(min_dist_sq_cu);
+ if (min_dist_cu > brush.curves_sculpt_settings->minimum_distance) {
+ return true;
+ }
+
+ return false;
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_density_operation(
+ const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start)
+{
+ if (use_add_density_mode(brush_mode, C, stroke_start)) {
+ return std::make_unique<DensityAddOperation>();
+ }
+ return std::make_unique<DensitySubtractOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
index b0a6d6ef29c..408139d6653 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_grow_shrink.cc
@@ -2,12 +2,9 @@
#include <algorithm>
-#include "curves_sculpt_intern.hh"
-
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_float4x4.hh"
-#include "BLI_kdtree.h"
-#include "BLI_rand.hh"
+#include "BLI_length_parameterize.hh"
#include "BLI_vector.hh"
#include "PIL_time.h"
@@ -16,19 +13,13 @@
#include "BKE_attribute_math.hh"
#include "BKE_brush.h"
-#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
-#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
#include "DNA_curves_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
@@ -72,6 +63,24 @@ class ShrinkCurvesEffect : public CurvesEffect {
private:
const Brush &brush_;
+ /** Storage of per-curve parameterization data to avoid reallocation. */
+ struct ParameterizationBuffers {
+ Array<float3> old_positions;
+ Array<float> old_lengths;
+ Array<float> sample_lengths;
+ Array<int> indices;
+ Array<float> factors;
+
+ void reinitialize(const int points_num)
+ {
+ this->old_positions.reinitialize(points_num);
+ this->old_lengths.reinitialize(length_parameterize::segments_num(points_num, false));
+ this->sample_lengths.reinitialize(points_num);
+ this->indices.reinitialize(points_num);
+ this->factors.reinitialize(points_num);
+ }
+ };
+
public:
ShrinkCurvesEffect(const Brush &brush) : brush_(brush)
{
@@ -83,46 +92,42 @@ class ShrinkCurvesEffect : public CurvesEffect {
{
MutableSpan<float3> positions_cu = curves.positions_for_write();
threading::parallel_for(curve_indices.index_range(), 256, [&](const IndexRange range) {
+ ParameterizationBuffers data;
for (const int influence_i : range) {
const int curve_i = curve_indices[influence_i];
const float move_distance_cu = move_distances_cu[influence_i];
- const IndexRange curve_points = curves.points_for_curve(curve_i);
- this->shrink_curve(positions_cu, curve_points, move_distance_cu);
+ const IndexRange points = curves.points_for_curve(curve_i);
+ this->shrink_curve(positions_cu.slice(points), move_distance_cu, data);
}
});
}
+ private:
void shrink_curve(MutableSpan<float3> positions,
- const IndexRange curve_points,
- const float shrink_length) const
+ const float shrink_length,
+ ParameterizationBuffers &data) const
{
- PolySpline spline;
- spline.resize(curve_points.size());
- MutableSpan<float3> spline_positions = spline.positions();
- spline_positions.copy_from(positions.slice(curve_points));
- spline.mark_cache_invalid();
+ namespace lp = length_parameterize;
+ data.reinitialize(positions.size());
+
+ /* Copy the old positions to facilitate mixing from neighbors for the resulting curve. */
+ data.old_positions.as_mutable_span().copy_from(positions);
+
+ lp::accumulate_lengths<float3>(data.old_positions, false, data.old_lengths);
+
const float min_length = brush_.curves_sculpt_settings->minimum_length;
- const float old_length = spline.length();
+ const float old_length = data.old_lengths.last();
const float new_length = std::max(min_length, old_length - shrink_length);
const float length_factor = std::clamp(new_length / old_length, 0.0f, 1.0f);
- Vector<float> old_point_lengths;
- old_point_lengths.append(0.0f);
- for (const int i : spline_positions.index_range().drop_back(1)) {
- const float3 &p1 = spline_positions[i];
- const float3 &p2 = spline_positions[i + 1];
- const float length = math::distance(p1, p2);
- old_point_lengths.append(old_point_lengths.last() + length);
+ data.sample_lengths.first() = 0.0f;
+ for (const int i : data.old_lengths.index_range()) {
+ data.sample_lengths[i + 1] = data.old_lengths[i] * length_factor;
}
- for (const int i : spline_positions.index_range()) {
- const float eval_length = old_point_lengths[i] * length_factor;
- const Spline::LookupResult lookup = spline.lookup_evaluated_length(eval_length);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- spline.sample_with_index_factors<float3>(spline_positions, {&index_factor, 1}, {&p, 1});
- positions[curve_points[i]] = p;
- }
+ lp::sample_at_lengths(data.old_lengths, data.sample_lengths, data.indices, data.factors);
+
+ lp::linear_interpolation<float3>(data.old_positions, data.indices, data.factors, positions);
}
};
@@ -153,50 +158,10 @@ class ExtrapolateCurvesEffect : public CurvesEffect {
const float3 direction = math::normalize(old_last_pos_cu - direction_reference_point);
const float3 new_last_pos_cu = old_last_pos_cu + direction * move_distance_cu;
- this->move_last_point_and_resample(positions_cu, curve_points, new_last_pos_cu);
+ move_last_point_and_resample(positions_cu.slice(curve_points), new_last_pos_cu);
}
});
}
-
- void move_last_point_and_resample(MutableSpan<float3> positions,
- const IndexRange curve_points,
- const float3 &new_last_point_position) const
- {
- Vector<float> old_lengths;
- old_lengths.append(0.0f);
- /* Used to (1) normalize the segment sizes over time and (2) support making zero-length
- * segments */
- const float extra_length = 0.001f;
- for (const int segment_i : IndexRange(curve_points.size() - 1)) {
- const float3 &p1 = positions[curve_points[segment_i]];
- const float3 &p2 = positions[curve_points[segment_i] + 1];
- const float length = math::distance(p1, p2);
- old_lengths.append(old_lengths.last() + length + extra_length);
- }
- Vector<float> point_factors;
- for (float &old_length : old_lengths) {
- point_factors.append(old_length / old_lengths.last());
- }
-
- PolySpline new_spline;
- new_spline.resize(curve_points.size());
- MutableSpan<float3> new_spline_positions = new_spline.positions();
- for (const int i : IndexRange(curve_points.size() - 1)) {
- new_spline_positions[i] = positions[curve_points[i]];
- }
- new_spline_positions.last() = new_last_point_position;
- new_spline.mark_cache_invalid();
-
- for (const int i : IndexRange(curve_points.size())) {
- const float factor = point_factors[i];
- const Spline::LookupResult lookup = new_spline.lookup_evaluated_factor(factor);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- new_spline.sample_with_index_factors<float3>(
- new_spline_positions, {&index_factor, 1}, {&p, 1});
- positions[curve_points[i]] = p;
- }
- }
};
/**
@@ -272,16 +237,16 @@ class CurvesEffectOperation : public CurvesSculptStrokeOperation {
*/
struct CurvesEffectOperationExecutor {
CurvesEffectOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
Object *object_ = nullptr;
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
+ VArray<float> curve_selection_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
const Brush *brush_ = nullptr;
float brush_radius_base_re_;
float brush_radius_factor_;
@@ -289,8 +254,7 @@ struct CurvesEffectOperationExecutor {
eBrushFalloffShape falloff_shape_;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ CurvesSurfaceTransforms transforms_;
float2 brush_pos_start_re_;
float2 brush_pos_end_re_;
@@ -300,6 +264,10 @@ struct CurvesEffectOperationExecutor {
Vector<float> move_distances_cu;
};
+ CurvesEffectOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
void execute(CurvesEffectOperation &self,
const bContext &C,
const StrokeExtension &stroke_extension)
@@ -307,12 +275,7 @@ struct CurvesEffectOperationExecutor {
BLI_SCOPED_DEFER([&]() { self.last_mouse_position_ = stroke_extension.mouse_position; });
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
@@ -320,18 +283,20 @@ struct CurvesEffectOperationExecutor {
return;
}
- const CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt;
+ curve_selection_factors_ = get_curves_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ const CurvesSculpt &curves_sculpt = *ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint);
- brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
- brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
brush_pos_start_re_ = self.last_mouse_position_;
brush_pos_end_re_ = stroke_extension.mouse_position;
@@ -339,10 +304,10 @@ struct CurvesEffectOperationExecutor {
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
if (std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_,
- *region_,
- *v3d_,
- *rv3d_,
+ *ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
*object_,
stroke_extension.mouse_position,
brush_radius_base_re_)) {
@@ -371,7 +336,7 @@ struct CurvesEffectOperationExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
void gather_influences_projected(
@@ -380,7 +345,7 @@ struct CurvesEffectOperationExecutor {
const Span<float3> positions_cu = curves_->positions();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@@ -398,6 +363,8 @@ struct CurvesEffectOperationExecutor {
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
+ const float curve_selection_factor = curve_selection_factors_[curve_i];
+
float max_move_distance_cu = 0.0f;
for (const float4x4 &brush_transform_inv : symmetry_brush_transforms_inv) {
for (const int segment_i : points.drop_back(1)) {
@@ -405,8 +372,8 @@ struct CurvesEffectOperationExecutor {
const float3 p2_cu = brush_transform_inv * positions_cu[segment_i + 1];
float2 p1_re, p2_re;
- ED_view3d_project_float_v2_m4(region_, p1_cu, p1_re, projection.values);
- ED_view3d_project_float_v2_m4(region_, p2_cu, p2_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, p1_cu, p1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, p2_cu, p2_re, projection.values);
float2 closest_on_brush_re;
float2 closest_on_segment_re;
@@ -428,24 +395,24 @@ struct CurvesEffectOperationExecutor {
const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
const float radius_falloff = BKE_brush_curve_strength(
brush_, dist_to_brush_re, brush_radius_re);
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
const float3 closest_on_segment_cu = math::interpolate(
p1_cu, p2_cu, lambda_on_segment);
float3 brush_start_pos_wo, brush_end_pos_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * closest_on_segment_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * closest_on_segment_cu,
brush_pos_start_re_,
brush_start_pos_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * closest_on_segment_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * closest_on_segment_cu,
brush_pos_end_re_,
brush_end_pos_wo);
- const float3 brush_start_pos_cu = world_to_curves_mat_ * brush_start_pos_wo;
- const float3 brush_end_pos_cu = world_to_curves_mat_ * brush_end_pos_wo;
+ const float3 brush_start_pos_cu = transforms_.world_to_curves * brush_start_pos_wo;
+ const float3 brush_end_pos_cu = transforms_.world_to_curves * brush_end_pos_wo;
const float move_distance_cu = weight *
math::distance(brush_start_pos_cu, brush_end_pos_cu);
@@ -466,18 +433,18 @@ struct CurvesEffectOperationExecutor {
const Span<float3> positions_cu = curves_->positions();
float3 brush_pos_start_wo, brush_pos_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_start_re_,
brush_pos_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_end_re_,
brush_pos_end_wo);
- const float3 brush_pos_start_cu = world_to_curves_mat_ * brush_pos_start_wo;
- const float3 brush_pos_end_cu = world_to_curves_mat_ * brush_pos_end_wo;
+ const float3 brush_pos_start_cu = transforms_.world_to_curves * brush_pos_start_wo;
+ const float3 brush_pos_end_cu = transforms_.world_to_curves * brush_pos_end_wo;
const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu;
const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu);
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
@@ -493,6 +460,9 @@ struct CurvesEffectOperationExecutor {
const IndexRange points = curves_->points_for_curve(curve_i);
float max_move_distance_cu = 0.0f;
+
+ const float curve_selection_factor = curve_selection_factors_[curve_i];
+
for (const float4x4 &brush_transform : symmetry_brush_transforms) {
const float3 brush_pos_start_transformed_cu = brush_transform * brush_pos_start_cu;
const float3 brush_pos_end_transformed_cu = brush_transform * brush_pos_end_cu;
@@ -519,7 +489,7 @@ struct CurvesEffectOperationExecutor {
const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
const float radius_falloff = BKE_brush_curve_strength(
brush_, dist_to_brush_cu, brush_radius_cu);
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * curve_selection_factor;
const float move_distance_cu = weight * brush_pos_diff_length_cu;
max_move_distance_cu = std::max(max_move_distance_cu, move_distance_cu);
@@ -537,7 +507,7 @@ struct CurvesEffectOperationExecutor {
void CurvesEffectOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
- CurvesEffectOperationExecutor executor;
+ CurvesEffectOperationExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
index 842de234761..c31bba2fe1e 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -8,7 +8,10 @@
#include "paint_intern.h"
#include "BLI_math_vector.hh"
+#include "BLI_vector.hh"
+#include "BLI_virtual_array.hh"
+#include "BKE_attribute.h"
#include "BKE_curves.hh"
struct ARegion;
@@ -18,10 +21,12 @@ struct View3D;
struct Object;
struct Brush;
struct Scene;
+struct BVHTreeFromMesh;
namespace blender::ed::sculpt_paint {
using bke::CurvesGeometry;
+using bke::CurvesSurfaceTransforms;
struct StrokeExtension {
bool is_first;
@@ -55,6 +60,15 @@ std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation();
std::unique_ptr<CurvesSculptStrokeOperation> new_grow_shrink_operation(
const BrushStrokeMode brush_mode, const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation(
+ const BrushStrokeMode brush_mode, const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_pinch_operation(const BrushStrokeMode brush_mode,
+ const bContext &C);
+std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_puff_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_density_operation(
+ const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start);
+std::unique_ptr<CurvesSculptStrokeOperation> new_slide_operation();
struct CurvesBrush3D {
float3 position_cu;
@@ -74,4 +88,46 @@ std::optional<CurvesBrush3D> sample_curves_3d_brush(const Depsgraph &depsgraph,
Vector<float4x4> get_symmetry_brush_transforms(eCurvesSymmetryType symmetry);
+/**
+ * Get the floating point selection on the curve domain, averaged from points if necessary.
+ */
+VArray<float> get_curves_selection(const Curves &curves_id);
+
+/**
+ * Get the floating point selection on the curve domain, copied from curves if necessary.
+ */
+VArray<float> get_point_selection(const Curves &curves_id);
+
+/**
+ * Find curves that have any point selected (a selection factor greater than zero),
+ * or curves that have their own selection factor greater than zero.
+ */
+IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices);
+
+void move_last_point_and_resample(MutableSpan<float3> positions, const float3 &new_last_position);
+
+class CurvesSculptCommonContext {
+ public:
+ const Depsgraph *depsgraph = nullptr;
+ const Scene *scene = nullptr;
+ ARegion *region = nullptr;
+ const View3D *v3d = nullptr;
+ RegionView3D *rv3d = nullptr;
+
+ CurvesSculptCommonContext(const bContext &C);
+};
+
+std::optional<CurvesBrush3D> sample_curves_surface_3d_brush(
+ const Depsgraph &depsgraph,
+ const ARegion &region,
+ const View3D &v3d,
+ const CurvesSurfaceTransforms &transforms,
+ const BVHTreeFromMesh &surface_bvh,
+ const float2 &brush_pos_re,
+ const float brush_radius_re);
+
+float transform_brush_radius(const float4x4 &transform,
+ const float3 &brush_position,
+ const float old_radius);
+
} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index 15d0f73592d..47e0fe3a61a 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -1,55 +1,57 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_kdtree.h"
+#include "BLI_rand.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector_set.hh"
-#include "BKE_attribute_math.hh"
#include "BKE_brush.h"
#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
-#include "BKE_geometry_set.hh"
-#include "BKE_lib_id.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
-#include "BKE_spline.hh"
#include "WM_api.h"
+#include "WM_message.h"
#include "WM_toolsystem.h"
+#include "ED_curves.h"
#include "ED_curves_sculpt.h"
+#include "ED_image.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_space_api.h"
#include "ED_view3d.h"
#include "DEG_depsgraph.h"
#include "DNA_brush_types.h"
#include "DNA_curves_types.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
#include "DNA_screen_types.h"
#include "RNA_access.h"
-
-#include "BLI_index_mask_ops.hh"
-#include "BLI_kdtree.h"
-#include "BLI_math_vector.hh"
-#include "BLI_rand.hh"
-
-#include "PIL_time.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "curves_sculpt_intern.h"
#include "curves_sculpt_intern.hh"
#include "paint_intern.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
/* -------------------------------------------------------------------- */
/** \name Poll Functions
* \{ */
bool CURVES_SCULPT_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
return ob && ob->mode & OB_MODE_SCULPT_CURVES;
}
@@ -104,14 +106,14 @@ float brush_strength_get(const Scene &scene,
return BKE_brush_alpha_get(&scene, &brush) * brush_strength_factor(brush, stroke_extension);
}
-static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bContext &C,
- wmOperator &op)
+static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(
+ bContext &C, wmOperator &op, const StrokeExtension &stroke_start)
{
const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode"));
- Scene &scene = *CTX_data_scene(&C);
- CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
- Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
+ const Scene &scene = *CTX_data_scene(&C);
+ const CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
+ const Brush &brush = *BKE_paint_brush_for_read(&curves_sculpt.paint);
switch (brush.curves_sculpt_tool) {
case CURVES_SCULPT_TOOL_COMB:
return new_comb_operation();
@@ -123,6 +125,18 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte
return new_add_operation(C, op.reports);
case CURVES_SCULPT_TOOL_GROW_SHRINK:
return new_grow_shrink_operation(mode, C);
+ case CURVES_SCULPT_TOOL_SELECTION_PAINT:
+ return new_selection_paint_operation(mode, C);
+ case CURVES_SCULPT_TOOL_PINCH:
+ return new_pinch_operation(mode, C);
+ case CURVES_SCULPT_TOOL_SMOOTH:
+ return new_smooth_operation();
+ case CURVES_SCULPT_TOOL_PUFF:
+ return new_puff_operation();
+ case CURVES_SCULPT_TOOL_DENSITY:
+ return new_density_operation(mode, C, stroke_start);
+ case CURVES_SCULPT_TOOL_SLIDE:
+ return new_slide_operation();
}
BLI_assert_unreachable();
return {};
@@ -133,7 +147,10 @@ struct SculptCurvesBrushStrokeData {
PaintStroke *stroke;
};
-static bool stroke_get_location(bContext *C, float out[3], const float mouse[2])
+static bool stroke_get_location(bContext *C,
+ float out[3],
+ const float mouse[2],
+ bool UNUSED(force_original))
{
out[0] = mouse[0];
out[1] = mouse[1];
@@ -162,7 +179,7 @@ static void stroke_update_step(bContext *C,
if (!op_data->operation) {
stroke_extension.is_first = true;
- op_data->operation = start_brush_operation(*C, *op);
+ op_data->operation = start_brush_operation(*C, *op, stroke_extension);
}
else {
stroke_extension.is_first = false;
@@ -180,8 +197,8 @@ static void stroke_done(const bContext *C, PaintStroke *stroke)
static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
+ const Paint *paint = BKE_paint_get_active_from_context(C);
+ const Brush *brush = BKE_paint_brush_for_read(paint);
if (brush == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -250,7 +267,7 @@ static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot)
static bool curves_sculptmode_toggle_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
if (ob == nullptr) {
return false;
}
@@ -263,16 +280,19 @@ static bool curves_sculptmode_toggle_poll(bContext *C)
static void curves_sculptmode_enter(bContext *C)
{
Scene *scene = CTX_data_scene(C);
+ wmMsgBus *mbus = CTX_wm_message_bus(C);
+
Object *ob = CTX_data_active_object(C);
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->curves_sculpt);
CurvesSculpt *curves_sculpt = scene->toolsettings->curves_sculpt;
ob->mode = OB_MODE_SCULPT_CURVES;
- paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d);
+ ED_paint_cursor_start(&curves_sculpt->paint, CURVES_SCULPT_mode_poll_view3d);
- /* Update for mode change. */
+ /* Necessary to change the object mode on the evaluated object. */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);
}
@@ -285,6 +305,8 @@ static void curves_sculptmode_exit(bContext *C)
static int curves_sculptmode_toggle_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
+ wmMsgBus *mbus = CTX_wm_message_bus(C);
+
const bool is_mode_set = ob->mode == OB_MODE_SCULPT_CURVES;
if (is_mode_set) {
@@ -301,6 +323,10 @@ static int curves_sculptmode_toggle_exec(bContext *C, wmOperator *op)
}
WM_toolsystem_update_from_context_view3d(C);
+
+ /* Necessary to change the object mode on the evaluated object. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);
return OPERATOR_FINISHED;
}
@@ -319,6 +345,934 @@ static void CURVES_OT_sculptmode_toggle(wmOperatorType *ot)
/** \} */
+namespace select_random {
+
+static int select_random_exec(bContext *C, wmOperator *op)
+{
+ VectorSet<Curves *> unique_curves = curves::get_unique_editable_curves(*C);
+
+ const int seed = RNA_int_get(op->ptr, "seed");
+ RandomNumberGenerator rng{static_cast<uint32_t>(seed)};
+
+ const bool partial = RNA_boolean_get(op->ptr, "partial");
+ const bool constant_per_curve = RNA_boolean_get(op->ptr, "constant_per_curve");
+ const float probability = RNA_float_get(op->ptr, "probability");
+ const float min_value = RNA_float_get(op->ptr, "min");
+ const auto next_partial_random_value = [&]() {
+ return rng.get_float() * (1.0f - min_value) + min_value;
+ };
+ const auto next_bool_random_value = [&]() { return rng.get_float() <= probability; };
+
+ for (Curves *curves_id : unique_curves) {
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ const bool was_anything_selected = curves::has_anything_selected(*curves_id);
+ switch (curves_id->selection_domain) {
+ case ATTR_DOMAIN_POINT: {
+ MutableSpan<float> selection = curves.selection_point_float_for_write();
+ if (!was_anything_selected) {
+ selection.fill(1.0f);
+ }
+ if (partial) {
+ if (constant_per_curve) {
+ for (const int curve_i : curves.curves_range()) {
+ const float random_value = next_partial_random_value();
+ const IndexRange points = curves.points_for_curve(curve_i);
+ for (const int point_i : points) {
+ selection[point_i] *= random_value;
+ }
+ }
+ }
+ else {
+ for (const int point_i : selection.index_range()) {
+ const float random_value = next_partial_random_value();
+ selection[point_i] *= random_value;
+ }
+ }
+ }
+ else {
+ if (constant_per_curve) {
+ for (const int curve_i : curves.curves_range()) {
+ const bool random_value = next_bool_random_value();
+ const IndexRange points = curves.points_for_curve(curve_i);
+ if (!random_value) {
+ selection.slice(points).fill(0.0f);
+ }
+ }
+ }
+ else {
+ for (const int point_i : selection.index_range()) {
+ const bool random_value = next_bool_random_value();
+ if (!random_value) {
+ selection[point_i] = 0.0f;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case ATTR_DOMAIN_CURVE: {
+ MutableSpan<float> selection = curves.selection_curve_float_for_write();
+ if (!was_anything_selected) {
+ selection.fill(1.0f);
+ }
+ if (partial) {
+ for (const int curve_i : curves.curves_range()) {
+ const float random_value = next_partial_random_value();
+ selection[curve_i] *= random_value;
+ }
+ }
+ else {
+ for (const int curve_i : curves.curves_range()) {
+ const bool random_value = next_bool_random_value();
+ if (!random_value) {
+ selection[curve_i] = 0.0f;
+ }
+ }
+ }
+ break;
+ }
+ }
+ MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
+ curves.selection_point_float_for_write() :
+ curves.selection_curve_float_for_write();
+ const bool was_any_selected = std::any_of(
+ selection.begin(), selection.end(), [](const float v) { return v > 0.0f; });
+ if (was_any_selected) {
+ for (float &v : selection) {
+ v *= rng.get_float();
+ }
+ }
+ else {
+ for (float &v : selection) {
+ v = rng.get_float();
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+ return OPERATOR_FINISHED;
+}
+
+static void select_random_ui(bContext *UNUSED(C), wmOperator *op)
+{
+ uiLayout *layout = op->layout;
+
+ uiItemR(layout, op->ptr, "seed", 0, nullptr, ICON_NONE);
+ uiItemR(layout, op->ptr, "constant_per_curve", 0, nullptr, ICON_NONE);
+ uiItemR(layout, op->ptr, "partial", 0, nullptr, ICON_NONE);
+
+ if (RNA_boolean_get(op->ptr, "partial")) {
+ uiItemR(layout, op->ptr, "min", UI_ITEM_R_SLIDER, "Min", ICON_NONE);
+ }
+ else {
+ uiItemR(layout, op->ptr, "probability", UI_ITEM_R_SLIDER, "Probability", ICON_NONE);
+ }
+}
+
+} // namespace select_random
+
+static void SCULPT_CURVES_OT_select_random(wmOperatorType *ot)
+{
+ ot->name = "Select Random";
+ ot->idname = __func__;
+ ot->description = "Randomizes existing selection or create new random selection";
+
+ ot->exec = select_random::select_random_exec;
+ ot->poll = curves::selection_operator_poll;
+ ot->ui = select_random::select_random_ui;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna,
+ "seed",
+ 0,
+ INT32_MIN,
+ INT32_MAX,
+ "Seed",
+ "Source of randomness",
+ INT32_MIN,
+ INT32_MAX);
+ RNA_def_boolean(
+ ot->srna, "partial", false, "Partial", "Allow points or curves to be selected partially");
+ RNA_def_float(ot->srna,
+ "probability",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Probability",
+ "Chance of every point or curve being included in the selection",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "min",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Min",
+ "Minimum value for the random selection",
+ 0.0f,
+ 1.0f);
+ RNA_def_boolean(ot->srna,
+ "constant_per_curve",
+ true,
+ "Constant per Curve",
+ "The generated random number is the same for every control point of a curve");
+}
+
+namespace select_end {
+static bool select_end_poll(bContext *C)
+{
+ if (!curves::selection_operator_poll(C)) {
+ return false;
+ }
+ const Curves *curves_id = static_cast<const Curves *>(CTX_data_active_object(C)->data);
+ if (curves_id->selection_domain != ATTR_DOMAIN_POINT) {
+ CTX_wm_operator_poll_msg_set(C, "Only available in point selection mode");
+ return false;
+ }
+ return true;
+}
+
+static int select_end_exec(bContext *C, wmOperator *op)
+{
+ VectorSet<Curves *> unique_curves = curves::get_unique_editable_curves(*C);
+ const bool end_points = RNA_boolean_get(op->ptr, "end_points");
+ const int amount = RNA_int_get(op->ptr, "amount");
+
+ for (Curves *curves_id : unique_curves) {
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
+ const bool was_anything_selected = curves::has_anything_selected(*curves_id);
+ MutableSpan<float> selection = curves.selection_point_float_for_write();
+ if (!was_anything_selected) {
+ selection.fill(1.0f);
+ }
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ if (end_points) {
+ selection.slice(points.drop_back(amount)).fill(0.0f);
+ }
+ else {
+ selection.slice(points.drop_front(amount)).fill(0.0f);
+ }
+ }
+ });
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
+ }
+
+ return OPERATOR_FINISHED;
+}
+} // namespace select_end
+
+static void SCULPT_CURVES_OT_select_end(wmOperatorType *ot)
+{
+ ot->name = "Select End";
+ ot->idname = __func__;
+ ot->description = "Select end points of curves";
+
+ ot->exec = select_end::select_end_exec;
+ ot->poll = select_end::select_end_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna,
+ "end_points",
+ true,
+ "End Points",
+ "Select points at the end of the curve as opposed to the beginning");
+ RNA_def_int(
+ ot->srna, "amount", 1, 0, INT32_MAX, "Amount", "Number of points to select", 0, INT32_MAX);
+}
+
+namespace select_grow {
+
+struct GrowOperatorDataPerCurve : NonCopyable, NonMovable {
+ Curves *curves_id;
+ Vector<int> selected_point_indices;
+ Vector<int> unselected_point_indices;
+ Array<float> distances_to_selected;
+ Array<float> distances_to_unselected;
+
+ Array<float> original_selection;
+ float pixel_to_distance_factor;
+};
+
+struct GrowOperatorData {
+ int initial_mouse_x;
+ Vector<std::unique_ptr<GrowOperatorDataPerCurve>> per_curve;
+};
+
+static void update_points_selection(const GrowOperatorDataPerCurve &data,
+ const float distance,
+ MutableSpan<float> points_selection)
+{
+ if (distance > 0.0f) {
+ threading::parallel_for(
+ data.unselected_point_indices.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int point_i = data.unselected_point_indices[i];
+ const float distance_to_selected = data.distances_to_selected[i];
+ const float selection = distance_to_selected <= distance ? 1.0f : 0.0f;
+ points_selection[point_i] = selection;
+ }
+ });
+ threading::parallel_for(
+ data.selected_point_indices.index_range(), 512, [&](const IndexRange range) {
+ for (const int point_i : data.selected_point_indices.as_span().slice(range)) {
+ points_selection[point_i] = 1.0f;
+ }
+ });
+ }
+ else {
+ threading::parallel_for(
+ data.selected_point_indices.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int point_i = data.selected_point_indices[i];
+ const float distance_to_unselected = data.distances_to_unselected[i];
+ const float selection = distance_to_unselected <= -distance ? 0.0f : 1.0f;
+ points_selection[point_i] = selection;
+ }
+ });
+ threading::parallel_for(
+ data.unselected_point_indices.index_range(), 512, [&](const IndexRange range) {
+ for (const int point_i : data.unselected_point_indices.as_span().slice(range)) {
+ points_selection[point_i] = 0.0f;
+ }
+ });
+ }
+}
+
+static int select_grow_update(bContext *C, wmOperator *op, const float mouse_diff_x)
+{
+ GrowOperatorData &op_data = *static_cast<GrowOperatorData *>(op->customdata);
+
+ for (std::unique_ptr<GrowOperatorDataPerCurve> &curve_op_data : op_data.per_curve) {
+ Curves &curves_id = *curve_op_data->curves_id;
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ const float distance = curve_op_data->pixel_to_distance_factor * mouse_diff_x;
+
+ /* Grow or shrink selection based on precomputed distances. */
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT: {
+ MutableSpan<float> points_selection = curves.selection_point_float_for_write();
+ update_points_selection(*curve_op_data, distance, points_selection);
+ break;
+ }
+ case ATTR_DOMAIN_CURVE: {
+ Array<float> new_points_selection(curves.points_num());
+ update_points_selection(*curve_op_data, distance, new_points_selection);
+ /* Propagate grown point selection to the curve selection. */
+ MutableSpan<float> curves_selection = curves.selection_curve_float_for_write();
+ for (const int curve_i : curves.curves_range()) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const Span<float> points_selection = new_points_selection.as_span().slice(points);
+ const float max_selection = *std::max_element(points_selection.begin(),
+ points_selection.end());
+ curves_selection[curve_i] = max_selection;
+ }
+ break;
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void select_grow_invoke_per_curve(Curves &curves_id,
+ Object &curves_ob,
+ const ARegion &region,
+ const View3D &v3d,
+ const RegionView3D &rv3d,
+ GrowOperatorDataPerCurve &curve_op_data)
+{
+ curve_op_data.curves_id = &curves_id;
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ const Span<float3> positions = curves.positions();
+
+ /* Find indices of selected and unselected points. */
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT: {
+ const VArray<float> points_selection = curves.selection_point_float();
+ curve_op_data.original_selection.reinitialize(points_selection.size());
+ points_selection.materialize(curve_op_data.original_selection);
+ for (const int point_i : points_selection.index_range()) {
+ const float point_selection = points_selection[point_i];
+ if (point_selection > 0.0f) {
+ curve_op_data.selected_point_indices.append(point_i);
+ }
+ else {
+ curve_op_data.unselected_point_indices.append(point_i);
+ }
+ }
+
+ break;
+ }
+ case ATTR_DOMAIN_CURVE: {
+ const VArray<float> curves_selection = curves.selection_curve_float();
+ curve_op_data.original_selection.reinitialize(curves_selection.size());
+ curves_selection.materialize(curve_op_data.original_selection);
+ for (const int curve_i : curves_selection.index_range()) {
+ const float curve_selection = curves_selection[curve_i];
+ const IndexRange points = curves.points_for_curve(curve_i);
+ if (curve_selection > 0.0f) {
+ for (const int point_i : points) {
+ curve_op_data.selected_point_indices.append(point_i);
+ }
+ }
+ else {
+ for (const int point_i : points) {
+ curve_op_data.unselected_point_indices.append(point_i);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ threading::parallel_invoke(
+ [&]() {
+ /* Build KD-tree for the selected points. */
+ KDTree_3d *kdtree = BLI_kdtree_3d_new(curve_op_data.selected_point_indices.size());
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
+ for (const int point_i : curve_op_data.selected_point_indices) {
+ const float3 &position = positions[point_i];
+ BLI_kdtree_3d_insert(kdtree, point_i, position);
+ }
+ BLI_kdtree_3d_balance(kdtree);
+
+ /* For each unselected point, compute the distance to the closest selected point. */
+ curve_op_data.distances_to_selected.reinitialize(
+ curve_op_data.unselected_point_indices.size());
+ threading::parallel_for(curve_op_data.unselected_point_indices.index_range(),
+ 256,
+ [&](const IndexRange range) {
+ for (const int i : range) {
+ const int point_i = curve_op_data.unselected_point_indices[i];
+ const float3 &position = positions[point_i];
+ KDTreeNearest_3d nearest;
+ BLI_kdtree_3d_find_nearest(kdtree, position, &nearest);
+ curve_op_data.distances_to_selected[i] = nearest.dist;
+ }
+ });
+ },
+ [&]() {
+ /* Build KD-tree for the unselected points. */
+ KDTree_3d *kdtree = BLI_kdtree_3d_new(curve_op_data.unselected_point_indices.size());
+ BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
+ for (const int point_i : curve_op_data.unselected_point_indices) {
+ const float3 &position = positions[point_i];
+ BLI_kdtree_3d_insert(kdtree, point_i, position);
+ }
+ BLI_kdtree_3d_balance(kdtree);
+
+ /* For each selected point, compute the distance to the closest unselected point. */
+ curve_op_data.distances_to_unselected.reinitialize(
+ curve_op_data.selected_point_indices.size());
+ threading::parallel_for(
+ curve_op_data.selected_point_indices.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int point_i = curve_op_data.selected_point_indices[i];
+ const float3 &position = positions[point_i];
+ KDTreeNearest_3d nearest;
+ BLI_kdtree_3d_find_nearest(kdtree, position, &nearest);
+ curve_op_data.distances_to_unselected[i] = nearest.dist;
+ }
+ });
+ });
+
+ float4x4 curves_to_world_mat = curves_ob.obmat;
+ float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(&rv3d, &curves_ob, projection.values);
+
+ /* Compute how mouse movements in screen space are converted into grow/shrink distances in
+ * object space. */
+ curve_op_data.pixel_to_distance_factor = threading::parallel_reduce(
+ curve_op_data.selected_point_indices.index_range(),
+ 256,
+ FLT_MAX,
+ [&](const IndexRange range, float pixel_to_distance_factor) {
+ for (const int i : range) {
+ const int point_i = curve_op_data.selected_point_indices[i];
+ const float3 &pos_cu = positions[point_i];
+
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(&region, pos_cu, pos_re, projection.values);
+ if (pos_re.x < 0 || pos_re.y < 0 || pos_re.x > region.winx || pos_re.y > region.winy) {
+ continue;
+ }
+ /* Compute how far this point moves in curve space when it moves one unit in screen
+ * space. */
+ const float2 pos_offset_re = pos_re + float2(1, 0);
+ float3 pos_offset_wo;
+ ED_view3d_win_to_3d(
+ &v3d, &region, curves_to_world_mat * pos_cu, pos_offset_re, pos_offset_wo);
+ const float3 pos_offset_cu = world_to_curves_mat * pos_offset_wo;
+ const float dist_cu = math::distance(pos_cu, pos_offset_cu);
+ const float dist_re = math::distance(pos_re, pos_offset_re);
+ const float factor = dist_cu / dist_re;
+ math::min_inplace(pixel_to_distance_factor, factor);
+ }
+ return pixel_to_distance_factor;
+ },
+ [](const float a, const float b) { return std::min(a, b); });
+}
+
+static int select_grow_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *active_ob = CTX_data_active_object(C);
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ GrowOperatorData *op_data = MEM_new<GrowOperatorData>(__func__);
+ op->customdata = op_data;
+
+ op_data->initial_mouse_x = event->xy[0];
+
+ Curves &curves_id = *static_cast<Curves *>(active_ob->data);
+ auto curve_op_data = std::make_unique<GrowOperatorDataPerCurve>();
+ select_grow_invoke_per_curve(curves_id, *active_ob, *region, *v3d, *rv3d, *curve_op_data);
+ op_data->per_curve.append(std::move(curve_op_data));
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int select_grow_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ GrowOperatorData &op_data = *static_cast<GrowOperatorData *>(op->customdata);
+ const int mouse_x = event->xy[0];
+ const int mouse_diff_x = mouse_x - op_data.initial_mouse_x;
+ switch (event->type) {
+ case MOUSEMOVE: {
+ select_grow_update(C, op, mouse_diff_x);
+ break;
+ }
+ case LEFTMOUSE: {
+ MEM_delete(&op_data);
+ return OPERATOR_FINISHED;
+ }
+ case EVT_ESCKEY:
+ case RIGHTMOUSE: {
+ /* Undo operator by resetting the selection to the original value. */
+ for (std::unique_ptr<GrowOperatorDataPerCurve> &curve_op_data : op_data.per_curve) {
+ Curves &curves_id = *curve_op_data->curves_id;
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ switch (curves_id.selection_domain) {
+ case ATTR_DOMAIN_POINT: {
+ MutableSpan<float> points_selection = curves.selection_point_float_for_write();
+ points_selection.copy_from(curve_op_data->original_selection);
+ break;
+ }
+ case ATTR_DOMAIN_CURVE: {
+ MutableSpan<float> curves_seletion = curves.selection_curve_float_for_write();
+ curves_seletion.copy_from(curve_op_data->original_selection);
+ break;
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
+ * attribute for now. */
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id);
+ }
+ MEM_delete(&op_data);
+ return OPERATOR_CANCELLED;
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+}
+
+} // namespace select_grow
+
+static void SCULPT_CURVES_OT_select_grow(wmOperatorType *ot)
+{
+ ot->name = "Select Grow";
+ ot->idname = __func__;
+ ot->description = "Select curves which are close to curves that are selected already";
+
+ ot->invoke = select_grow::select_grow_invoke;
+ ot->modal = select_grow::select_grow_modal;
+ ot->poll = curves::selection_operator_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ PropertyRNA *prop;
+ prop = RNA_def_float(ot->srna,
+ "distance",
+ 0.1f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Distance",
+ "By how much to grow the selection",
+ -10.0f,
+ 10.f);
+ RNA_def_property_subtype(prop, PROP_DISTANCE);
+}
+
+namespace min_distance_edit {
+
+static bool min_distance_edit_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (ob == nullptr) {
+ return false;
+ }
+ if (ob->type != OB_CURVES) {
+ return false;
+ }
+ Curves *curves_id = static_cast<Curves *>(ob->data);
+ if (curves_id->surface == nullptr || curves_id->surface->type != OB_MESH) {
+ CTX_wm_operator_poll_msg_set(C, "Curves must have a mesh surface object set");
+ return false;
+ }
+ Scene *scene = CTX_data_scene(C);
+ const Brush *brush = BKE_paint_brush_for_read(&scene->toolsettings->curves_sculpt->paint);
+ if (brush == nullptr) {
+ return false;
+ }
+ if (brush->curves_sculpt_tool != CURVES_SCULPT_TOOL_DENSITY) {
+ return false;
+ }
+ return true;
+}
+
+struct MinDistanceEditData {
+ /** Brush whose minimum distance is modified. */
+ Brush *brush;
+ float4x4 curves_to_world_mat;
+
+ /** Where the preview is drawn. */
+ float3 pos_cu;
+ float3 normal_cu;
+
+ int2 initial_mouse;
+ float initial_minimum_distance;
+
+ /** The operator uses a new cursor, but the existing cursors should be restored afterwards. */
+ ListBase orig_paintcursors;
+ void *cursor;
+
+ /** Store the viewport region in case the operator was called from the header. */
+ ARegion *region;
+ RegionView3D *rv3d;
+};
+
+static int calculate_points_per_side(bContext *C, MinDistanceEditData &op_data)
+{
+ Scene *scene = CTX_data_scene(C);
+ ARegion *region = op_data.region;
+
+ const float min_distance = op_data.brush->curves_sculpt_settings->minimum_distance;
+ const float brush_radius = BKE_brush_size_get(scene, op_data.brush);
+
+ float3 tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 0, 1});
+ if (math::is_zero(tangent_x_cu)) {
+ tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 1, 0});
+ }
+ tangent_x_cu = math::normalize(tangent_x_cu);
+ const float3 tangent_y_cu = math::normalize(math::cross(op_data.normal_cu, tangent_x_cu));
+
+ /* Sample a few points to get a good estimate of how large the grid has to be. */
+ Vector<float3> points_wo;
+ points_wo.append(op_data.pos_cu + min_distance * tangent_x_cu);
+ points_wo.append(op_data.pos_cu + min_distance * tangent_y_cu);
+ points_wo.append(op_data.pos_cu - min_distance * tangent_x_cu);
+ points_wo.append(op_data.pos_cu - min_distance * tangent_y_cu);
+
+ Vector<float2> points_re;
+ for (const float3 &pos_wo : points_wo) {
+ float2 pos_re;
+ ED_view3d_project_v2(region, pos_wo, pos_re);
+ points_re.append(pos_re);
+ }
+
+ float2 origin_re;
+ ED_view3d_project_v2(region, op_data.pos_cu, origin_re);
+
+ int needed_points = 0;
+ for (const float2 &pos_re : points_re) {
+ const float distance = math::length(pos_re - origin_re);
+ const int needed_points_iter = (brush_radius * 2.0f) / distance;
+
+ if (needed_points_iter > needed_points) {
+ needed_points = needed_points_iter;
+ }
+ }
+
+ /* Limit to a hard-coded number since it only adds noise at some point. */
+ return std::min(300, needed_points);
+}
+
+static void min_distance_edit_draw(bContext *C, int UNUSED(x), int UNUSED(y), void *customdata)
+{
+ Scene *scene = CTX_data_scene(C);
+ MinDistanceEditData &op_data = *static_cast<MinDistanceEditData *>(customdata);
+
+ const float min_distance = op_data.brush->curves_sculpt_settings->minimum_distance;
+
+ float3 tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 0, 1});
+ if (math::is_zero(tangent_x_cu)) {
+ tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 1, 0});
+ }
+ tangent_x_cu = math::normalize(tangent_x_cu);
+ const float3 tangent_y_cu = math::normalize(math::cross(op_data.normal_cu, tangent_x_cu));
+
+ const int points_per_side = calculate_points_per_side(C, op_data);
+ const int points_per_axis_num = 2 * points_per_side + 1;
+
+ Vector<float3> points_wo;
+ for (const int x_i : IndexRange(points_per_axis_num)) {
+ for (const int y_i : IndexRange(points_per_axis_num)) {
+ const float x_iter = min_distance * (x_i - (points_per_axis_num - 1) / 2.0f);
+ const float y_iter = min_distance * (y_i - (points_per_axis_num - 1) / 2.0f);
+
+ const float3 point_pos_cu = op_data.pos_cu + op_data.normal_cu * 0.0001f +
+ x_iter * tangent_x_cu + y_iter * tangent_y_cu;
+ const float3 point_pos_wo = op_data.curves_to_world_mat * point_pos_cu;
+ points_wo.append(point_pos_wo);
+ }
+ }
+
+ float4 circle_col = float4(op_data.brush->add_col);
+ float circle_alpha = op_data.brush->cursor_overlay_alpha;
+ float brush_radius_re = BKE_brush_size_get(scene, op_data.brush);
+
+ /* Draw the grid. */
+ GPU_matrix_push();
+ GPU_matrix_push_projection();
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ ARegion *region = op_data.region;
+ RegionView3D *rv3d = op_data.rv3d;
+ wmWindow *win = CTX_wm_window(C);
+
+ /* It does the same as: `view3d_operator_needs_opengl(C);`. */
+ wmViewport(&region->winrct);
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+
+ GPUVertFormat *format3d = immVertexFormat();
+
+ const uint pos3d = GPU_vertformat_attr_add(format3d, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ const uint col3d = GPU_vertformat_attr_add(format3d, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR);
+
+ GPU_point_size(3.0f);
+ immBegin(GPU_PRIM_POINTS, points_wo.size());
+
+ float3 brush_origin_wo = op_data.curves_to_world_mat * op_data.pos_cu;
+ float2 brush_origin_re;
+ ED_view3d_project_v2(region, brush_origin_wo, brush_origin_re);
+
+ /* Smooth alpha transition until the brush edge. */
+ const int alpha_border_re = 20;
+ const float dist_to_inner_border_re = brush_radius_re - alpha_border_re;
+
+ for (const float3 &pos_wo : points_wo) {
+ float2 pos_re;
+ ED_view3d_project_v2(region, pos_wo, pos_re);
+
+ const float dist_to_point_re = math::distance(pos_re, brush_origin_re);
+ const float alpha = 1.0f - ((dist_to_point_re - dist_to_inner_border_re) / alpha_border_re);
+
+ immAttr4f(col3d, 0.9f, 0.9f, 0.9f, alpha);
+ immVertex3fv(pos3d, pos_wo);
+ }
+ immEnd();
+ immUnbindProgram();
+
+ /* Reset the drawing settings. */
+ GPU_point_size(1.0f);
+ GPU_matrix_pop_projection();
+ GPU_matrix_pop();
+
+ int4 scissor;
+ GPU_scissor_get(scissor);
+ wmWindowViewport(win);
+ GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+
+ /* Draw the brush circle. */
+ GPU_matrix_translate_2f((float)op_data.initial_mouse.x, (float)op_data.initial_mouse.y);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos2d = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor3fvAlpha(circle_col, circle_alpha);
+ imm_draw_circle_wire_2d(pos2d, 0.0f, 0.0f, brush_radius_re, 80);
+
+ immUnbindProgram();
+ GPU_blend(GPU_BLEND_NONE);
+}
+
+static int min_distance_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
+
+ Object &curves_ob = *CTX_data_active_object(C);
+ Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
+ Object &surface_ob = *curves_id.surface;
+ Mesh &surface_me = *static_cast<Mesh *>(surface_ob.data);
+
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_me, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
+ const int2 mouse_pos_int_re{event->mval};
+ const float2 mouse_pos_re{mouse_pos_int_re};
+
+ float3 ray_start_wo, ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ depsgraph, region, v3d, mouse_pos_re, ray_start_wo, ray_end_wo, true);
+
+ const float4x4 surface_to_world_mat = surface_ob.obmat;
+ const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
+
+ const float3 ray_start_su = world_to_surface_mat * ray_start_wo;
+ const float3 ray_end_su = world_to_surface_mat * ray_end_wo;
+ const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh.tree,
+ ray_start_su,
+ ray_direction_su,
+ 0.0f,
+ &ray_hit,
+ surface_bvh.raycast_callback,
+ &surface_bvh);
+ if (ray_hit.index == -1) {
+ WM_report(RPT_ERROR, "Cursor must be over the surface mesh");
+ return OPERATOR_CANCELLED;
+ }
+
+ const float3 hit_pos_su = ray_hit.co;
+ const float3 hit_normal_su = ray_hit.no;
+ const float4x4 curves_to_world_mat = curves_ob.obmat;
+ const float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
+ const float4x4 surface_to_curves_mat = world_to_curves_mat * surface_to_world_mat;
+ const float4x4 surface_to_curves_normal_mat = surface_to_curves_mat.inverted().transposed();
+
+ const float3 hit_pos_cu = surface_to_curves_mat * hit_pos_su;
+ const float3 hit_normal_cu = math::normalize(surface_to_curves_normal_mat * hit_normal_su);
+
+ MinDistanceEditData *op_data = MEM_new<MinDistanceEditData>(__func__);
+ op_data->curves_to_world_mat = curves_to_world_mat;
+ op_data->normal_cu = hit_normal_cu;
+ op_data->pos_cu = hit_pos_cu;
+ op_data->initial_mouse = event->xy;
+ op_data->brush = BKE_paint_brush(&scene->toolsettings->curves_sculpt->paint);
+ op_data->initial_minimum_distance = op_data->brush->curves_sculpt_settings->minimum_distance;
+
+ if (op_data->initial_minimum_distance <= 0.0f) {
+ op_data->initial_minimum_distance = 0.01f;
+ }
+
+ op->customdata = op_data;
+
+ /* Temporarily disable other paint cursors. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ op_data->orig_paintcursors = wm->paintcursors;
+ BLI_listbase_clear(&wm->paintcursors);
+
+ /* Add minimum distance paint cursor. */
+ op_data->cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, min_distance_edit_draw, op_data);
+
+ op_data->region = CTX_wm_region(C);
+ op_data->rv3d = CTX_wm_region_view3d(C);
+
+ WM_event_add_modal_handler(C, op);
+ ED_region_tag_redraw(region);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int min_distance_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *region = CTX_wm_region(C);
+ MinDistanceEditData &op_data = *static_cast<MinDistanceEditData *>(op->customdata);
+
+ auto finish = [&]() {
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ /* Remove own cursor. */
+ WM_paint_cursor_end(static_cast<wmPaintCursor *>(op_data.cursor));
+ /* Restore original paint cursors. */
+ wm->paintcursors = op_data.orig_paintcursors;
+
+ ED_region_tag_redraw(region);
+ MEM_freeN(&op_data);
+ };
+
+ switch (event->type) {
+ case MOUSEMOVE: {
+ const int2 mouse_pos_int_re{event->xy};
+ const float2 mouse_pos_re{mouse_pos_int_re};
+
+ const float mouse_diff_x = mouse_pos_int_re.x - op_data.initial_mouse.x;
+ const float factor = powf(2, mouse_diff_x / UI_UNIT_X / 10.0f);
+ op_data.brush->curves_sculpt_settings->minimum_distance = op_data.initial_minimum_distance *
+ factor;
+
+ ED_region_tag_redraw(region);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr);
+ break;
+ }
+ case LEFTMOUSE: {
+ if (event->val == KM_PRESS) {
+ finish();
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
+ case RIGHTMOUSE:
+ case EVT_ESCKEY: {
+ op_data.brush->curves_sculpt_settings->minimum_distance = op_data.initial_minimum_distance;
+ finish();
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, nullptr);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+} // namespace min_distance_edit
+
+static void SCULPT_CURVES_OT_min_distance_edit(wmOperatorType *ot)
+{
+ ot->name = "Edit Minimum Distance";
+ ot->idname = __func__;
+ ot->description = "Change the minimum distance used by the density brush";
+
+ ot->poll = min_distance_edit::min_distance_edit_poll;
+ ot->invoke = min_distance_edit::min_distance_edit_invoke;
+ ot->modal = min_distance_edit::min_distance_edit_modal;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR;
+}
+
} // namespace blender::ed::sculpt_paint
/* -------------------------------------------------------------------- */
@@ -330,6 +1284,10 @@ void ED_operatortypes_sculpt_curves()
using namespace blender::ed::sculpt_paint;
WM_operatortype_append(SCULPT_CURVES_OT_brush_stroke);
WM_operatortype_append(CURVES_OT_sculptmode_toggle);
+ WM_operatortype_append(SCULPT_CURVES_OT_select_random);
+ WM_operatortype_append(SCULPT_CURVES_OT_select_end);
+ WM_operatortype_append(SCULPT_CURVES_OT_select_grow);
+ WM_operatortype_append(SCULPT_CURVES_OT_min_distance_edit);
}
/** \} */
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_pinch.cc b/source/blender/editors/sculpt_paint/curves_sculpt_pinch.cc
new file mode 100644
index 00000000000..689b7d22e5e
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_pinch.cc
@@ -0,0 +1,307 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_vector.hh"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+#include "BKE_paint.h"
+
+#include "DNA_brush_enums.h"
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "WM_api.h"
+
+/**
+ * The code below uses a prefix naming convention to indicate the coordinate space:
+ * `cu`: Local space of the curves object that is being edited.
+ * `su`: Local space of the surface object.
+ * `wo`: World space.
+ * `re`: 2D coordinates within the region.
+ */
+
+namespace blender::ed::sculpt_paint {
+
+class PinchOperation : public CurvesSculptStrokeOperation {
+ private:
+ bool invert_pinch_;
+ Array<float> segment_lengths_cu_;
+
+ /** Only used when a 3D brush is used. */
+ CurvesBrush3D brush_3d_;
+
+ friend struct PinchOperationExecutor;
+
+ public:
+ PinchOperation(const bool invert_pinch) : invert_pinch_(invert_pinch)
+ {
+ }
+
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+struct PinchOperationExecutor {
+ PinchOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+
+ float invert_factor_;
+
+ float2 brush_pos_re_;
+
+ PinchOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(PinchOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = BKE_brush_alpha_get(ctx_.scene, brush_);
+
+ invert_factor_ = self_->invert_pinch_ ? -1.0f : 1.0f;
+
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ brush_pos_re_ = stroke_extension.mouse_position;
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+
+ if (stroke_extension.is_first) {
+ this->initialize_segment_lengths();
+
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ self_->brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
+ }
+ }
+
+ Array<bool> changed_curves(curves_->curves_num(), false);
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->pinch_projected_with_symmetry(changed_curves);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->pinch_spherical_with_symmetry(changed_curves);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ this->restore_segment_lengths(changed_curves);
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void pinch_projected_with_symmetry(MutableSpan<bool> r_changed_curves)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->pinch_projected(brush_transform, r_changed_curves);
+ }
+ }
+
+ void pinch_projected(const float4x4 &brush_transform, MutableSpan<bool> r_changed_curves)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 old_pos_cu = brush_transform_inv * positions_cu[point_i];
+ float2 old_pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
+
+ const float dist_to_brush_sq_re = math::distance_squared(old_pos_re, brush_pos_re_);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float t = safe_divide(dist_to_brush_re, brush_radius_base_re_);
+ const float radius_falloff = t * BKE_brush_curve_strength(brush_, t, 1.0f);
+ const float weight = invert_factor_ * 0.1f * brush_strength_ * radius_falloff *
+ point_factors_[point_i];
+
+ const float2 new_pos_re = math::interpolate(old_pos_re, brush_pos_re_, weight);
+
+ const float3 old_pos_wo = transforms_.curves_to_world * old_pos_cu;
+ float3 new_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d, ctx_.region, old_pos_wo, new_pos_re, new_pos_wo);
+
+ const float3 new_pos_cu = transforms_.world_to_curves * new_pos_wo;
+ positions_cu[point_i] = brush_transform * new_pos_cu;
+ r_changed_curves[curve_i] = true;
+ }
+ }
+ });
+ }
+
+ void pinch_spherical_with_symmetry(MutableSpan<bool> r_changed_curves)
+ {
+ float3 brush_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_pos_wo);
+ const float3 brush_pos_cu = transforms_.world_to_curves * brush_pos_wo;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->pinch_spherical(brush_transform * brush_pos_cu, brush_radius_cu, r_changed_curves);
+ }
+ }
+
+ void pinch_spherical(const float3 &brush_pos_cu,
+ const float brush_radius_cu,
+ MutableSpan<bool> r_changed_curves)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 old_pos_cu = positions_cu[point_i];
+
+ const float dist_to_brush_sq_cu = math::distance_squared(old_pos_cu, brush_pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float t = safe_divide(dist_to_brush_cu, brush_radius_cu);
+ const float radius_falloff = t * BKE_brush_curve_strength(brush_, t, 1.0f);
+ const float weight = invert_factor_ * 0.1f * brush_strength_ * radius_falloff *
+ point_factors_[point_i];
+
+ const float3 new_pos_cu = math::interpolate(old_pos_cu, brush_pos_cu, weight);
+ positions_cu[point_i] = new_pos_cu;
+
+ r_changed_curves[curve_i] = true;
+ }
+ }
+ });
+ }
+
+ void initialize_segment_lengths()
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ self_->segment_lengths_cu_.reinitialize(curves_->points_num());
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[point_i];
+ const float3 &p2_cu = positions_cu[point_i + 1];
+ const float length_cu = math::distance(p1_cu, p2_cu);
+ self_->segment_lengths_cu_[point_i] = length_cu;
+ }
+ }
+ });
+ }
+
+ void restore_segment_lengths(const Span<bool> changed_curves)
+ {
+ const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+
+ threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ if (!changed_curves[curve_i]) {
+ continue;
+ }
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int segment_i : IndexRange(points.size() - 1)) {
+ const float3 &p1_cu = positions_cu[points[segment_i]];
+ float3 &p2_cu = positions_cu[points[segment_i] + 1];
+ const float3 direction = math::normalize(p2_cu - p1_cu);
+ const float expected_length_cu = expected_lengths_cu[points[segment_i]];
+ p2_cu = p1_cu + direction * expected_length_cu;
+ }
+ }
+ });
+ }
+};
+
+void PinchOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
+{
+ PinchOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_pinch_operation(const BrushStrokeMode brush_mode,
+ const bContext &C)
+{
+ const Scene &scene = *CTX_data_scene(&C);
+ const Brush &brush = *BKE_paint_brush_for_read(&scene.toolsettings->curves_sculpt->paint);
+
+ const bool invert_pinch = (brush_mode == BRUSH_STROKE_INVERT) !=
+ ((brush.flag & BRUSH_DIR_IN) != 0);
+ return std::make_unique<PinchOperation>(invert_pinch);
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc b/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc
new file mode 100644
index 00000000000..83cfda6dc00
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc
@@ -0,0 +1,393 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "WM_api.h"
+
+#include "BLI_length_parameterize.hh"
+
+#include "curves_sculpt_intern.hh"
+
+namespace blender::ed::sculpt_paint {
+
+class PuffOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Only used when a 3D brush is used. */
+ CurvesBrush3D brush_3d_;
+
+ /** Length of each segment indexed by the index of the first point in the segment. */
+ Array<float> segment_lengths_cu_;
+
+ friend struct PuffOperationExecutor;
+
+ public:
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+static float3 compute_surface_point_normal(const MLoopTri &looptri,
+ const float3 &bary_coord,
+ const Span<float3> corner_normals)
+{
+ const int l0 = looptri.tri[0];
+ const int l1 = looptri.tri[1];
+ const int l2 = looptri.tri[2];
+
+ const float3 &l0_normal = corner_normals[l0];
+ const float3 &l1_normal = corner_normals[l1];
+ const float3 &l2_normal = corner_normals[l2];
+
+ const float3 normal = math::normalize(
+ attribute_math::mix3(bary_coord, l0_normal, l1_normal, l2_normal));
+ return normal;
+}
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct PuffOperationExecutor {
+ PuffOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+ float2 brush_pos_re_;
+
+ eBrushFalloffShape falloff_shape_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ Object *surface_ob_ = nullptr;
+ Mesh *surface_ = nullptr;
+ Span<MLoopTri> surface_looptris_;
+ Span<float3> corner_normals_su_;
+ BVHTreeFromMesh surface_bvh_;
+
+ PuffOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(PuffOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
+ UNUSED_VARS(C, stroke_extension);
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+ if (curves_id_->surface == nullptr || curves_id_->surface->type != OB_MESH) {
+ return;
+ }
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
+
+ surface_ob_ = curves_id_->surface;
+ surface_ = static_cast<Mesh *>(surface_ob_->data);
+
+ transforms_ = CurvesSurfaceTransforms(*object_, surface_ob_);
+
+ if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_);
+ }
+ corner_normals_su_ = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
+ surface_->totloop};
+
+ BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
+
+ surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
+ BKE_mesh_runtime_looptri_len(surface_)};
+
+ if (stroke_extension.is_first) {
+ this->initialize_segment_lengths();
+ if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
+ self.brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
+ }
+ }
+
+ Array<float> curve_weights(curve_selection_.size(), 0.0f);
+
+ if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->find_curve_weights_projected_with_symmetry(curve_weights);
+ }
+ else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->find_curves_weights_spherical_with_symmetry(curve_weights);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ this->puff(curve_weights);
+ this->restore_segment_lengths();
+
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void find_curve_weights_projected_with_symmetry(MutableSpan<float> r_curve_weights)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->find_curve_weights_projected(brush_transform, r_curve_weights);
+ }
+ }
+
+ void find_curve_weights_projected(const float4x4 &brush_transform,
+ MutableSpan<float> r_curve_weights)
+ {
+ Span<float3> positions_cu = curves_->positions();
+
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_selection_i : range) {
+ const int curve_i = curve_selection_[curve_selection_i];
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ const float3 first_pos_cu = brush_transform_inv * positions_cu[points[0]];
+ float2 prev_pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, first_pos_cu, prev_pos_re, projection.values);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 pos_cu = brush_transform_inv * positions_cu[point_i];
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ BLI_SCOPED_DEFER([&]() { prev_pos_re = pos_re; });
+
+ const float dist_to_brush_sq_re = dist_squared_to_line_segment_v2(
+ brush_pos_re_, prev_pos_re, pos_re);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re);
+ const float weight = radius_falloff;
+ math::max_inplace(r_curve_weights[curve_selection_i], weight);
+ }
+ }
+ });
+ }
+
+ void find_curves_weights_spherical_with_symmetry(MutableSpan<float> r_curve_weights)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_pos_wo);
+ const float3 brush_pos_cu = transforms_.world_to_curves * brush_pos_wo;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->find_curves_weights_spherical(
+ brush_transform * brush_pos_cu, brush_radius_cu, r_curve_weights);
+ }
+ }
+
+ void find_curves_weights_spherical(const float3 &brush_pos_cu,
+ const float brush_radius_cu,
+ MutableSpan<float> r_curve_weights)
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_selection_i : range) {
+ const int curve_i = curve_selection_[curve_selection_i];
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 &prev_pos_cu = positions_cu[point_i - 1];
+ const float3 &pos_cu = positions_cu[point_i];
+ const float dist_to_brush_sq_cu = dist_squared_to_line_segment_v3(
+ brush_pos_cu, prev_pos_cu, pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_radius_cu);
+ const float weight = radius_falloff;
+ math::max_inplace(r_curve_weights[curve_selection_i], weight);
+ }
+ }
+ });
+ }
+
+ void puff(const Span<float> curve_weights)
+ {
+ BLI_assert(curve_weights.size() == curve_selection_.size());
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ Vector<float> accumulated_lengths_cu;
+ for (const int curve_selection_i : range) {
+ const int curve_i = curve_selection_[curve_selection_i];
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ const int first_point_i = points[0];
+ const float3 first_pos_cu = positions_cu[first_point_i];
+ const float3 first_pos_su = transforms_.curves_to_surface * first_pos_cu;
+
+ /* Find the nearest position on the surface. The curve will be aligned to the normal of
+ * that point. */
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(surface_bvh_.tree,
+ first_pos_su,
+ &nearest,
+ surface_bvh_.nearest_callback,
+ &surface_bvh_);
+
+ const MLoopTri &looptri = surface_looptris_[nearest.index];
+ const float3 closest_pos_su = nearest.co;
+ const float3 &v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co;
+ const float3 &v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co;
+ const float3 &v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, v0_su, v1_su, v2_su, closest_pos_su);
+ const float3 normal_su = compute_surface_point_normal(
+ looptri, bary_coords, corner_normals_su_);
+ const float3 normal_cu = math::normalize(transforms_.surface_to_curves_normal * normal_su);
+
+ accumulated_lengths_cu.reinitialize(points.size() - 1);
+ length_parameterize::accumulate_lengths<float3>(
+ positions_cu.slice(points), false, accumulated_lengths_cu);
+
+ /* Align curve to the surface normal while making sure that the curve does not fold up much
+ * in the process (e.g. when the curve was pointing in the opposite direction before). */
+ for (const int i : IndexRange(points.size()).drop_front(1)) {
+ const int point_i = points[i];
+ const float3 old_pos_cu = positions_cu[point_i];
+
+ /* Compute final position of the point. */
+ const float length_param_cu = accumulated_lengths_cu[i - 1];
+ const float3 goal_pos_cu = first_pos_cu + length_param_cu * normal_cu;
+
+ const float weight = 0.01f * brush_strength_ * point_factors_[point_i] *
+ curve_weights[curve_selection_i];
+ float3 new_pos_cu = math::interpolate(old_pos_cu, goal_pos_cu, weight);
+
+ /* Make sure the point does not move closer to the root point than it was initially. This
+ * makes the curve kind of "rotate up". */
+ const float old_dist_to_root_cu = math::distance(old_pos_cu, first_pos_cu);
+ const float new_dist_to_root_cu = math::distance(new_pos_cu, first_pos_cu);
+ if (new_dist_to_root_cu < old_dist_to_root_cu) {
+ const float3 offset = math::normalize(new_pos_cu - first_pos_cu);
+ new_pos_cu += (old_dist_to_root_cu - new_dist_to_root_cu) * offset;
+ }
+
+ positions_cu[point_i] = new_pos_cu;
+ }
+ }
+ });
+ }
+
+ void initialize_segment_lengths()
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ self_->segment_lengths_cu_.reinitialize(curves_->points_num());
+ threading::parallel_for(curves_->curves_range(), 128, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[point_i];
+ const float3 &p2_cu = positions_cu[point_i + 1];
+ const float length_cu = math::distance(p1_cu, p2_cu);
+ self_->segment_lengths_cu_[point_i] = length_cu;
+ }
+ }
+ });
+ }
+
+ void restore_segment_lengths()
+ {
+ const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+
+ threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[segment_i];
+ float3 &p2_cu = positions_cu[segment_i + 1];
+ const float3 direction = math::normalize(p2_cu - p1_cu);
+ const float expected_length_cu = expected_lengths_cu[segment_i];
+ p2_cu = p1_cu + direction * expected_length_cu;
+ }
+ }
+ });
+ }
+};
+
+void PuffOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
+{
+ PuffOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_puff_operation()
+{
+ return std::make_unique<PuffOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
new file mode 100644
index 00000000000..f620fed5761
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection.cc
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_index_mask_ops.hh"
+
+#include "BKE_curves.hh"
+
+#include "curves_sculpt_intern.hh"
+
+namespace blender::ed::sculpt_paint {
+
+static VArray<float> get_curves_selection(const CurvesGeometry &curves, const eAttrDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_CURVE:
+ return curves.selection_curve_float();
+ case ATTR_DOMAIN_POINT:
+ return curves.adapt_domain(
+ curves.selection_point_float(), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ default:
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+
+VArray<float> get_curves_selection(const Curves &curves_id)
+{
+ if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
+ return VArray<float>::ForSingle(1.0f, CurvesGeometry::wrap(curves_id.geometry).curves_num());
+ }
+ return get_curves_selection(CurvesGeometry::wrap(curves_id.geometry),
+ eAttrDomain(curves_id.selection_domain));
+}
+
+static VArray<float> get_point_selection(const CurvesGeometry &curves, const eAttrDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_CURVE:
+ return curves.adapt_domain(
+ curves.selection_curve_float(), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
+ case ATTR_DOMAIN_POINT:
+ return curves.selection_point_float();
+ default:
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+
+VArray<float> get_point_selection(const Curves &curves_id)
+{
+ if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
+ return VArray<float>::ForSingle(1.0f, CurvesGeometry::wrap(curves_id.geometry).points_num());
+ }
+ return get_point_selection(CurvesGeometry::wrap(curves_id.geometry),
+ eAttrDomain(curves_id.selection_domain));
+}
+
+static IndexMask retrieve_selected_curves(const CurvesGeometry &curves,
+ const eAttrDomain domain,
+ Vector<int64_t> &r_indices)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT: {
+ const VArray<float> selection = curves.selection_point_float();
+ if (selection.is_single()) {
+ return selection.get_internal_single() == 0.0f ? IndexMask(0) :
+ IndexMask(curves.curves_num());
+ }
+ return index_mask_ops::find_indices_based_on_predicate(
+ curves.curves_range(), 512, r_indices, [&](const int curve_i) {
+ for (const int i : curves.points_for_curve(curve_i)) {
+ if (selection[i] > 0.0f) {
+ return true;
+ }
+ }
+ return false;
+ });
+ }
+ case ATTR_DOMAIN_CURVE: {
+ const VArray<float> selection = curves.selection_curve_float();
+ if (selection.is_single()) {
+ return selection.get_internal_single() == 0.0f ? IndexMask(0) :
+ IndexMask(curves.curves_num());
+ }
+ return index_mask_ops::find_indices_based_on_predicate(
+ curves.curves_range(), 2048, r_indices, [&](const int i) {
+ return selection[i] > 0.0f;
+ });
+ }
+ default:
+ BLI_assert_unreachable();
+ return {};
+ }
+}
+
+IndexMask retrieve_selected_curves(const Curves &curves_id, Vector<int64_t> &r_indices)
+{
+ if (!(curves_id.flag & CV_SCULPT_SELECTION_ENABLED)) {
+ return CurvesGeometry::wrap(curves_id.geometry).curves_range();
+ }
+ return retrieve_selected_curves(CurvesGeometry::wrap(curves_id.geometry),
+ eAttrDomain(curves_id.selection_domain),
+ r_indices);
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
new file mode 100644
index 00000000000..399d2c73ec3
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_selection_paint.cc
@@ -0,0 +1,395 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+#include <numeric>
+
+#include "BLI_memory_utils.hh"
+#include "BLI_task.hh"
+
+#include "DNA_brush_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "WM_api.h"
+
+#include "curves_sculpt_intern.hh"
+
+/**
+ * The code below uses a suffix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * wo: World space.
+ * re: 2D coordinates within the region.
+ */
+
+namespace blender::ed::sculpt_paint {
+
+using bke::CurvesGeometry;
+
+class SelectionPaintOperation : public CurvesSculptStrokeOperation {
+ private:
+ bool use_select_;
+ bool clear_selection_;
+
+ CurvesBrush3D brush_3d_;
+
+ friend struct SelectionPaintOperationExecutor;
+
+ public:
+ SelectionPaintOperation(const bool use_select, const bool clear_selection)
+ : use_select_(use_select), clear_selection_(clear_selection)
+ {
+ }
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+struct SelectionPaintOperationExecutor {
+ SelectionPaintOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+
+ float selection_goal_;
+
+ float2 brush_pos_re_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ SelectionPaintOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(SelectionPaintOperation &self,
+ const bContext &C,
+ const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+ object_ = CTX_data_active_object(&C);
+
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ curves_id_->flag |= CV_SCULPT_SELECTION_ENABLED;
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ brush_ = BKE_paint_brush_for_read(&ctx_.scene->toolsettings->curves_sculpt->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = BKE_brush_alpha_get(ctx_.scene, brush_);
+
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ if (self.clear_selection_) {
+ if (stroke_extension.is_first) {
+ if (curves_id_->selection_domain == ATTR_DOMAIN_POINT) {
+ curves_->selection_point_float_for_write().fill(0.0f);
+ }
+ else if (curves_id_->selection_domain == ATTR_DOMAIN_CURVE) {
+ curves_->selection_curve_float_for_write().fill(0.0f);
+ }
+ }
+ }
+
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+
+ selection_goal_ = self_->use_select_ ? 1.0f : 0.0f;
+
+ if (stroke_extension.is_first) {
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->initialize_spherical_brush_reference_point();
+ }
+ }
+
+ if (curves_id_->selection_domain == ATTR_DOMAIN_POINT) {
+ MutableSpan<float> selection = curves_->selection_point_float_for_write();
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->paint_point_selection_projected_with_symmetry(selection);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->paint_point_selection_spherical_with_symmetry(selection);
+ }
+ }
+ else {
+ MutableSpan<float> selection = curves_->selection_curve_float_for_write();
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->paint_curve_selection_projected_with_symmetry(selection);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->paint_curve_selection_spherical_with_symmetry(selection);
+ }
+ }
+
+ /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because
+ * selection is handled as a generic attribute for now. */
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ctx_.rv3d->rflag &= ~RV3D_PAINTING;
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void paint_point_selection_projected_with_symmetry(MutableSpan<float> selection)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->paint_point_selection_projected(brush_transform, selection);
+ }
+ }
+
+ void paint_point_selection_projected(const float4x4 &brush_transform,
+ MutableSpan<float> selection)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ Span<float3> positions_cu = curves_->positions();
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) {
+ for (const int point_i : point_range) {
+ const float3 pos_cu = brush_transform_inv * positions_cu[point_i];
+
+ /* Find the position of the point in screen space. */
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+
+ const float distance_to_brush_sq_re = math::distance_squared(pos_re, brush_pos_re_);
+ if (distance_to_brush_sq_re > brush_radius_sq_re) {
+ /* Ignore the point because it's too far away. */
+ continue;
+ }
+
+ const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re);
+ /* A falloff that is based on how far away the point is from the stroke. */
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, distance_to_brush_re, brush_radius_re);
+ /* Combine the falloff and brush strength. */
+ const float weight = brush_strength_ * radius_falloff;
+
+ selection[point_i] = math::interpolate(selection[point_i], selection_goal_, weight);
+ }
+ });
+ }
+
+ void paint_point_selection_spherical_with_symmetry(MutableSpan<float> selection)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_wo);
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->paint_point_selection_spherical(selection, brush_transform * brush_cu);
+ }
+ }
+
+ void paint_point_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu)
+ {
+ Span<float3> positions_cu = curves_->positions();
+
+ const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curves_->points_range(), 1024, [&](const IndexRange point_range) {
+ for (const int i : point_range) {
+ const float3 pos_old_cu = positions_cu[i];
+
+ /* Compute distance to the brush. */
+ const float distance_to_brush_sq_cu = math::distance_squared(pos_old_cu, brush_cu);
+ if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
+ /* Ignore the point because it's too far away. */
+ continue;
+ }
+
+ const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu);
+
+ /* A falloff that is based on how far away the point is from the stroke. */
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, distance_to_brush_cu, brush_radius_cu);
+ /* Combine the falloff and brush strength. */
+ const float weight = brush_strength_ * radius_falloff;
+
+ selection[i] = math::interpolate(selection[i], selection_goal_, weight);
+ }
+ });
+ }
+
+ void paint_curve_selection_projected_with_symmetry(MutableSpan<float> selection)
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->paint_curve_selection_projected(brush_transform, selection);
+ }
+ }
+
+ void paint_curve_selection_projected(const float4x4 &brush_transform,
+ MutableSpan<float> selection)
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const float max_weight = threading::parallel_reduce(
+ curves_->points_for_curve(curve_i).drop_back(1),
+ 1024,
+ 0.0f,
+ [&](const IndexRange segment_range, const float init) {
+ float max_weight = init;
+ for (const int segment_i : segment_range) {
+ const float3 pos1_cu = brush_transform_inv * positions_cu[segment_i];
+ const float3 pos2_cu = brush_transform_inv * positions_cu[segment_i + 1];
+
+ float2 pos1_re;
+ float2 pos2_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values);
+
+ const float distance_sq_re = dist_squared_to_line_segment_v2(
+ brush_pos_re_, pos1_re, pos2_re);
+ if (distance_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, std::sqrt(distance_sq_re), brush_radius_re);
+ const float weight = brush_strength_ * radius_falloff;
+ max_weight = std::max(max_weight, weight);
+ }
+ return max_weight;
+ },
+ [](float a, float b) { return std::max(a, b); });
+ selection[curve_i] = math::interpolate(selection[curve_i], selection_goal_, max_weight);
+ }
+ });
+ }
+
+ void paint_curve_selection_spherical_with_symmetry(MutableSpan<float> selection)
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_wo);
+ const float3 brush_cu = transforms_.world_to_curves * brush_wo;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->paint_curve_selection_spherical(selection, brush_transform * brush_cu);
+ }
+ }
+
+ void paint_curve_selection_spherical(MutableSpan<float> selection, const float3 &brush_cu)
+ {
+ const Span<float3> positions_cu = curves_->positions();
+
+ const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curves_->curves_range(), 1024, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const float max_weight = threading::parallel_reduce(
+ curves_->points_for_curve(curve_i).drop_back(1),
+ 1024,
+ 0.0f,
+ [&](const IndexRange segment_range, const float init) {
+ float max_weight = init;
+ for (const int segment_i : segment_range) {
+ const float3 &pos1_cu = positions_cu[segment_i];
+ const float3 &pos2_cu = positions_cu[segment_i + 1];
+
+ const float distance_sq_cu = dist_squared_to_line_segment_v3(
+ brush_cu, pos1_cu, pos2_cu);
+ if (distance_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, std::sqrt(distance_sq_cu), brush_radius_cu);
+ const float weight = brush_strength_ * radius_falloff;
+ max_weight = std::max(max_weight, weight);
+ }
+ return max_weight;
+ },
+ [](float a, float b) { return std::max(a, b); });
+ selection[curve_i] = math::interpolate(selection[curve_i], selection_goal_, max_weight);
+ }
+ });
+ }
+
+ void initialize_spherical_brush_reference_point()
+ {
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
+ if (brush_3d.has_value()) {
+ self_->brush_3d_ = *brush_3d;
+ }
+ }
+};
+
+void SelectionPaintOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
+{
+ SelectionPaintOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_selection_paint_operation(
+ const BrushStrokeMode brush_mode, const bContext &C)
+{
+ Scene &scene = *CTX_data_scene(&C);
+ Brush &brush = *BKE_paint_brush(&scene.toolsettings->curves_sculpt->paint);
+ const bool use_select = ELEM(brush_mode, BRUSH_STROKE_INVERT) ==
+ ((brush.flag & BRUSH_DIR_IN) != 0);
+ const bool clear_selection = use_select && brush_mode != BRUSH_STROKE_SMOOTH;
+
+ return std::make_unique<SelectionPaintOperation>(use_select, clear_selection);
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc
new file mode 100644
index 00000000000..aabe6fd93e4
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc
@@ -0,0 +1,307 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_vector.hh"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+#include "BKE_paint.h"
+
+#include "DNA_brush_enums.h"
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+
+namespace blender::ed::sculpt_paint {
+
+struct SlideCurveInfo {
+ /** Index of the curve to slide. */
+ int curve_i;
+ /** A weight based on the initial distance to the brush. */
+ float radius_falloff;
+};
+
+struct SlideInfo {
+ /** The transform used for the curves below (e.g. for symmetry). */
+ float4x4 brush_transform;
+ Vector<SlideCurveInfo> curves_to_slide;
+};
+
+class SlideOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Last mouse position. */
+ float2 brush_pos_last_re_;
+ /** Information about which curves to slide. This is initialized when the brush starts. */
+ Vector<SlideInfo> slide_info_;
+
+ friend struct SlideOperationExecutor;
+
+ public:
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct SlideOperationExecutor {
+ SlideOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ Object *surface_ob_ = nullptr;
+ Mesh *surface_ = nullptr;
+ Span<MLoopTri> surface_looptris_;
+ VArraySpan<float2> surface_uv_map_;
+
+ VArray<float> curve_factors_;
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ float2 brush_pos_prev_re_;
+ float2 brush_pos_re_;
+ float2 brush_pos_diff_re_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ BVHTreeFromMesh surface_bvh_;
+
+ SlideOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(SlideOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
+ UNUSED_VARS(C, stroke_extension);
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_id_->surface == nullptr || curves_id_->surface->type != OB_MESH) {
+ return;
+ }
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+
+ curve_factors_ = get_curves_selection(*curves_id_);
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
+ brush_pos_prev_re_ = self_->brush_pos_last_re_;
+ brush_pos_re_ = stroke_extension.mouse_position;
+ brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
+ BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = brush_pos_re_; });
+
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ surface_ob_ = curves_id_->surface;
+ surface_ = static_cast<Mesh *>(surface_ob_->data);
+
+ BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
+
+ surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
+ BKE_mesh_runtime_looptri_len(surface_)};
+
+ if (curves_id_->surface_uv_map != nullptr) {
+ const bke::AttributeAccessor surface_attributes = bke::mesh_attributes(*surface_);
+ surface_uv_map_ = surface_attributes.lookup<float2>(curves_id_->surface_uv_map,
+ ATTR_DOMAIN_CORNER);
+ }
+
+ if (stroke_extension.is_first) {
+ const Vector<float4x4> brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : brush_transforms) {
+ this->detect_curves_to_slide(brush_transform);
+ }
+ return;
+ }
+ this->slide_projected();
+
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void detect_curves_to_slide(const float4x4 &brush_transform)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ const Span<float3> positions_cu = curves_->positions();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ self_->slide_info_.append({brush_transform});
+ Vector<SlideCurveInfo> &curves_to_slide = self_->slide_info_.last().curves_to_slide;
+
+ /* Find curves in brush radius that should be moved. */
+ for (const int curve_i : curve_selection_) {
+ const int first_point_i = curves_->offsets()[curve_i];
+ const float3 &first_pos_cu = brush_transform_inv * positions_cu[first_point_i];
+
+ float2 first_pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, first_pos_cu, first_pos_re, projection.values);
+
+ const float dist_to_brush_sq_re = math::distance_squared(first_pos_re, brush_pos_re_);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re);
+ curves_to_slide.append({curve_i, radius_falloff});
+ }
+ }
+
+ void slide_projected()
+ {
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+
+ MutableSpan<float2> surface_uv_coords;
+ if (!surface_uv_map_.is_empty()) {
+ surface_uv_coords = curves_->surface_uv_coords_for_write();
+ }
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ for (const SlideInfo &slide_info : self_->slide_info_) {
+ const float4x4 &brush_transform = slide_info.brush_transform;
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+ const Span<SlideCurveInfo> curves_to_slide = slide_info.curves_to_slide;
+
+ threading::parallel_for(curves_to_slide.index_range(), 256, [&](const IndexRange range) {
+ for (const SlideCurveInfo &curve_slide_info : curves_to_slide.slice(range)) {
+ const int curve_i = curve_slide_info.curve_i;
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ const int first_point_i = points.first();
+ const float3 old_first_pos_cu = brush_transform_inv * positions_cu[first_point_i];
+
+ float2 old_first_pos_re;
+ ED_view3d_project_float_v2_m4(
+ ctx_.region, old_first_pos_cu, old_first_pos_re, projection.values);
+ const float first_point_weight = brush_strength_ * curve_slide_info.radius_falloff;
+
+ /* Slide root position in region space and then project it back onto the surface. */
+ const float2 new_first_pos_re = old_first_pos_re +
+ first_point_weight * brush_pos_diff_re_;
+
+ float3 ray_start_wo, ray_end_wo;
+ ED_view3d_win_to_segment_clipped(ctx_.depsgraph,
+ ctx_.region,
+ ctx_.v3d,
+ new_first_pos_re,
+ ray_start_wo,
+ ray_end_wo,
+ true);
+ const float3 ray_start_su = transforms_.world_to_surface * ray_start_wo;
+ const float3 ray_end_su = transforms_.world_to_surface * ray_end_wo;
+
+ const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
+ BVHTreeRayHit hit;
+ hit.dist = FLT_MAX;
+ hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh_.tree,
+ ray_start_su,
+ ray_direction_su,
+ 0.0f,
+ &hit,
+ surface_bvh_.raycast_callback,
+ &surface_bvh_);
+ if (hit.index == -1) {
+ continue;
+ }
+
+ const int looptri_index = hit.index;
+ const float3 attached_pos_su = hit.co;
+
+ const float3 attached_pos_cu = transforms_.surface_to_curves * attached_pos_su;
+ const float3 pos_offset_cu = brush_transform * (attached_pos_cu - old_first_pos_cu);
+
+ /* Update positions. The first point doesn't have an additional weight here, because then
+ * it wouldn't be attached to the surface anymore. */
+ positions_cu[first_point_i] += pos_offset_cu;
+ for (const int point_i : points.drop_front(1)) {
+ const float weight = point_factors_[point_i];
+ positions_cu[point_i] += weight * pos_offset_cu;
+ }
+
+ /* Update surface attachment information if necessary. */
+ if (!surface_uv_map_.is_empty()) {
+ const MLoopTri &looptri = surface_looptris_[looptri_index];
+ const float3 bary_coord = bke::mesh_surface_sample::compute_bary_coord_in_triangle(
+ *surface_, looptri, attached_pos_su);
+ const float2 &uv0 = surface_uv_map_[looptri.tri[0]];
+ const float2 &uv1 = surface_uv_map_[looptri.tri[1]];
+ const float2 &uv2 = surface_uv_map_[looptri.tri[2]];
+ const float2 uv = attribute_math::mix3(bary_coord, uv0, uv1, uv2);
+ surface_uv_coords[curve_i] = uv;
+ }
+ }
+ });
+ }
+ }
+};
+
+void SlideOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
+{
+ SlideOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_slide_operation()
+{
+ return std::make_unique<SlideOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_smooth.cc b/source/blender/editors/sculpt_paint/curves_sculpt_smooth.cc
new file mode 100644
index 00000000000..f874a9fc255
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_smooth.cc
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_brush_types.h"
+
+#include "WM_api.h"
+
+#include "BLI_enumerable_thread_specific.hh"
+
+#include "curves_sculpt_intern.hh"
+
+namespace blender::ed::sculpt_paint {
+
+class SmoothOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Only used when a 3D brush is used. */
+ CurvesBrush3D brush_3d_;
+
+ friend struct SmoothOperationExecutor;
+
+ public:
+ void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct SmoothOperationExecutor {
+ SmoothOperation *self_ = nullptr;
+ CurvesSculptCommonContext ctx_;
+
+ Object *object_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ VArray<float> point_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ const CurvesSculpt *curves_sculpt_ = nullptr;
+ const Brush *brush_ = nullptr;
+ float brush_radius_base_re_;
+ float brush_radius_factor_;
+ float brush_strength_;
+ float2 brush_pos_re_;
+
+ CurvesSurfaceTransforms transforms_;
+
+ SmoothOperationExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
+ void execute(SmoothOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
+ {
+ UNUSED_VARS(C, stroke_extension);
+ self_ = &self;
+
+ object_ = CTX_data_active_object(&C);
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+ if (curves_->curves_num() == 0) {
+ return;
+ }
+
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
+ brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ point_factors_ = get_point_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+ if (stroke_extension.is_first) {
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ self.brush_3d_ = *sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
+ }
+ }
+
+ if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->smooth_projected_with_symmetry();
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->smooth_spherical_with_symmetry();
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
+ ED_region_tag_redraw(ctx_.region);
+ }
+
+ void smooth_projected_with_symmetry()
+ {
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->smooth_projected(brush_transform);
+ }
+ }
+
+ void smooth_projected(const float4x4 &brush_transform)
+ {
+ const float4x4 brush_transform_inv = brush_transform.inverted();
+
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
+ const float brush_radius_sq_re = pow2f(brush_radius_re);
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ Vector<float2> old_curve_positions_re;
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+
+ /* Find position of control points in screen space. */
+ old_curve_positions_re.clear();
+ old_curve_positions_re.reserve(points.size());
+ for (const int point_i : points) {
+ const float3 &pos_cu = brush_transform_inv * positions_cu[point_i];
+ float2 pos_re;
+ ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
+ old_curve_positions_re.append_unchecked(pos_re);
+ }
+ for (const int i : IndexRange(points.size()).drop_front(1).drop_back(1)) {
+ const int point_i = points[i];
+ const float2 &old_pos_re = old_curve_positions_re[i];
+ const float dist_to_brush_sq_re = math::distance_squared(old_pos_re, brush_pos_re_);
+ if (dist_to_brush_sq_re > brush_radius_sq_re) {
+ continue;
+ }
+
+ const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_re, brush_radius_re);
+ /* Used to make the brush easier to use. Otherwise a strength of 1 would be way too
+ * large. */
+ const float weight_factor = 0.1f;
+ const float weight = weight_factor * brush_strength_ * radius_falloff *
+ point_factors_[point_i];
+
+ /* Move points towards the middle of their neighbors. */
+ const float2 &old_pos_prev_re = old_curve_positions_re[i - 1];
+ const float2 &old_pos_next_re = old_curve_positions_re[i + 1];
+ const float2 goal_pos_re = math::midpoint(old_pos_prev_re, old_pos_next_re);
+ const float2 new_pos_re = math::interpolate(old_pos_re, goal_pos_re, weight);
+ const float3 old_pos_cu = brush_transform_inv * positions_cu[point_i];
+ float3 new_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * old_pos_cu,
+ new_pos_re,
+ new_pos_wo);
+ const float3 new_pos_cu = brush_transform * (transforms_.world_to_curves * new_pos_wo);
+ positions_cu[point_i] = new_pos_cu;
+ }
+ }
+ });
+ }
+
+ void smooth_spherical_with_symmetry()
+ {
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
+
+ float3 brush_pos_wo;
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_pos_wo);
+ const float3 brush_pos_cu = transforms_.world_to_curves * brush_pos_wo;
+ const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
+
+ const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
+ eCurvesSymmetryType(curves_id_->symmetry));
+ for (const float4x4 &brush_transform : symmetry_brush_transforms) {
+ this->smooth_spherical(brush_transform * brush_pos_cu, brush_radius_cu);
+ }
+ }
+
+ void smooth_spherical(const float3 &brush_pos_cu, const float brush_radius_cu)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions_for_write();
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
+ Vector<float3> old_curve_positions_cu;
+ for (const int curve_i : curve_selection_.slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ /* Remember original positions so that we don't smooth based on already smoothed points
+ * below. */
+ old_curve_positions_cu.clear();
+ old_curve_positions_cu.extend(positions_cu.slice(points));
+ for (const int i : IndexRange(points.size()).drop_front(1).drop_back(1)) {
+ const int point_i = points[i];
+ const float3 &old_pos_cu = old_curve_positions_cu[i];
+ const float dist_to_brush_sq_cu = math::distance_squared(old_pos_cu, brush_pos_cu);
+ if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
+ continue;
+ }
+
+ const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, dist_to_brush_cu, brush_radius_cu);
+ /* Used to make the brush easier to use. Otherwise a strength of 1 would be way too
+ * large. */
+ const float weight_factor = 0.1f;
+ const float weight = weight_factor * brush_strength_ * radius_falloff *
+ point_factors_[point_i];
+
+ /* Move points towards the middle of their neighbors. */
+ const float3 &old_pos_prev_cu = old_curve_positions_cu[i - 1];
+ const float3 &old_pos_next_cu = old_curve_positions_cu[i + 1];
+ const float3 goal_pos_cu = math::midpoint(old_pos_prev_cu, old_pos_next_cu);
+ const float3 new_pos_cu = math::interpolate(old_pos_cu, goal_pos_cu, weight);
+ positions_cu[point_i] = new_pos_cu;
+ }
+ }
+ });
+ }
+};
+
+void SmoothOperation::on_stroke_extended(const bContext &C,
+ const StrokeExtension &stroke_extension)
+{
+ SmoothOperationExecutor executor{C};
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation()
+{
+ return std::make_unique<SmoothOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
index bcdeaaeabf2..ec0e8ff45e5 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -23,7 +23,6 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
-#include "BKE_spline.hh"
#include "DNA_brush_enums.h"
#include "DNA_brush_types.h"
@@ -72,11 +71,7 @@ class SnakeHookOperation : public CurvesSculptStrokeOperation {
*/
struct SnakeHookOperatorExecutor {
SnakeHookOperation *self_ = nullptr;
- const Depsgraph *depsgraph_ = nullptr;
- const Scene *scene_ = nullptr;
- ARegion *region_ = nullptr;
- const View3D *v3d_ = nullptr;
- const RegionView3D *rv3d_ = nullptr;
+ CurvesSculptCommonContext ctx_;
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
@@ -90,13 +85,20 @@ struct SnakeHookOperatorExecutor {
Curves *curves_id_ = nullptr;
CurvesGeometry *curves_ = nullptr;
- float4x4 curves_to_world_mat_;
- float4x4 world_to_curves_mat_;
+ VArray<float> curve_factors_;
+ Vector<int64_t> selected_curve_indices_;
+ IndexMask curve_selection_;
+
+ CurvesSurfaceTransforms transforms_;
float2 brush_pos_prev_re_;
float2 brush_pos_re_;
float2 brush_pos_diff_re_;
+ SnakeHookOperatorExecutor(const bContext &C) : ctx_(C)
+ {
+ }
+
void execute(SnakeHookOperation &self,
const bContext &C,
const StrokeExtension &stroke_extension)
@@ -104,40 +106,41 @@ struct SnakeHookOperatorExecutor {
BLI_SCOPED_DEFER([&]() { self.last_mouse_position_re_ = stroke_extension.mouse_position; });
self_ = &self;
- depsgraph_ = CTX_data_depsgraph_pointer(&C);
- scene_ = CTX_data_scene(&C);
- scene_ = CTX_data_scene(&C);
object_ = CTX_data_active_object(&C);
- region_ = CTX_wm_region(&C);
- v3d_ = CTX_wm_view3d(&C);
- rv3d_ = CTX_wm_region_view3d(&C);
- curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
- brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_radius_base_re_ = BKE_brush_size_get(ctx_.scene, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
- brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
+ brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
- curves_to_world_mat_ = object_->obmat;
- world_to_curves_mat_ = curves_to_world_mat_.inverted();
-
curves_id_ = static_cast<Curves *>(object_->data);
curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
if (curves_->curves_num() == 0) {
return;
}
+ transforms_ = CurvesSurfaceTransforms(*object_, curves_id_->surface);
+
+ curve_factors_ = get_curves_selection(*curves_id_);
+ curve_selection_ = retrieve_selected_curves(*curves_id_, selected_curve_indices_);
+
brush_pos_prev_re_ = self.last_mouse_position_re_;
brush_pos_re_ = stroke_extension.mouse_position;
brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
- std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
- *depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
+ *ctx_.region,
+ *ctx_.v3d,
+ *ctx_.rv3d,
+ *object_,
+ brush_pos_re_,
+ brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@@ -158,7 +161,7 @@ struct SnakeHookOperatorExecutor {
curves_->tag_positions_changed();
DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, &curves_id_->id);
- ED_region_tag_redraw(region_);
+ ED_region_tag_redraw(ctx_.region);
}
void projected_snake_hook_with_symmetry()
@@ -177,7 +180,7 @@ struct SnakeHookOperatorExecutor {
MutableSpan<float3> positions_cu = curves_->positions_for_write();
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
@@ -189,7 +192,7 @@ struct SnakeHookOperatorExecutor {
const float3 old_pos_cu = brush_transform_inv * positions_cu[last_point_i];
float2 old_pos_re;
- ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
+ ED_view3d_project_float_v2_m4(ctx_.region, old_pos_cu, old_pos_re, projection.values);
const float distance_to_brush_sq_re = math::distance_squared(old_pos_re,
brush_pos_prev_re_);
@@ -199,15 +202,19 @@ struct SnakeHookOperatorExecutor {
const float radius_falloff = BKE_brush_curve_strength(
brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re);
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
float3 new_position_wo;
- ED_view3d_win_to_3d(
- v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
- const float3 new_position_cu = brush_transform * (world_to_curves_mat_ * new_position_wo);
-
- this->move_last_point_and_resample(positions_cu.slice(points), new_position_cu);
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * old_pos_cu,
+ new_position_re,
+ new_position_wo);
+ const float3 new_position_cu = brush_transform *
+ (transforms_.world_to_curves * new_position_wo);
+
+ move_last_point_and_resample(positions_cu.slice(points), new_position_cu);
}
});
}
@@ -215,21 +222,21 @@ struct SnakeHookOperatorExecutor {
void spherical_snake_hook_with_symmetry()
{
float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+ ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
float3 brush_start_wo, brush_end_wo;
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_prev_re_,
brush_start_wo);
- ED_view3d_win_to_3d(v3d_,
- region_,
- curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ ED_view3d_win_to_3d(ctx_.v3d,
+ ctx_.region,
+ transforms_.curves_to_world * self_->brush_3d_.position_cu,
brush_pos_re_,
brush_end_wo);
- const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
- const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+ const float3 brush_start_cu = transforms_.world_to_curves * brush_start_wo;
+ const float3 brush_end_cu = transforms_.world_to_curves * brush_end_wo;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
@@ -265,52 +272,20 @@ struct SnakeHookOperatorExecutor {
const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_cu, brush_radius_cu);
- const float weight = brush_strength_ * radius_falloff;
+ const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
const float3 new_pos_cu = old_pos_cu + weight * brush_diff_cu;
- this->move_last_point_and_resample(positions_cu.slice(points), new_pos_cu);
+ move_last_point_and_resample(positions_cu.slice(points), new_pos_cu);
}
});
}
-
- void move_last_point_and_resample(MutableSpan<float3> positions,
- const float3 &new_last_position) const
- {
- /* Find the accumulated length of each point in the original curve,
- * treating it as a poly curve for performance reasons and simplicity. */
- Array<float> orig_lengths(length_parameterize::lengths_num(positions.size(), false));
- length_parameterize::accumulate_lengths<float3>(positions, false, orig_lengths);
- const float orig_total_length = orig_lengths.last();
-
- /* Find the factor by which the new curve is shorter or longer than the original. */
- const float new_last_segment_length = math::distance(positions.last(1), new_last_position);
- const float new_total_length = orig_lengths.last(1) + new_last_segment_length;
- const float length_factor = new_total_length / orig_total_length;
-
- /* Calculate the lengths to sample the original curve with by scaling the original lengths. */
- Array<float> new_lengths(positions.size() - 1);
- new_lengths.first() = 0.0f;
- for (const int i : new_lengths.index_range().drop_front(1)) {
- new_lengths[i] = orig_lengths[i - 1] * length_factor;
- }
-
- Array<int> indices(positions.size() - 1);
- Array<float> factors(positions.size() - 1);
- length_parameterize::create_samples_from_sorted_lengths(
- orig_lengths, new_lengths, false, indices, factors);
-
- Array<float3> new_positions(positions.size() - 1);
- length_parameterize::linear_interpolation<float3>(positions, indices, factors, new_positions);
- positions.drop_back(1).copy_from(new_positions);
- positions.last() = new_last_position;
- }
};
void SnakeHookOperation::on_stroke_extended(const bContext &C,
const StrokeExtension &stroke_extension)
{
- SnakeHookOperatorExecutor executor;
+ SnakeHookOperatorExecutor executor{C};
executor.execute(*this, C, stroke_extension);
}
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 861da185975..c5ebcf870a3 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -38,6 +38,7 @@
#include "IMB_imbuf_types.h"
+#include "ED_image.h"
#include "ED_view3d.h"
#include "DEG_depsgraph.h"
@@ -1358,7 +1359,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
ViewContext *vc = &pcontext->vc;
SculptCursorGeometryInfo gi;
- const float mouse[2] = {
+ const float mval_fl[2] = {
pcontext->x - pcontext->region->winrct.xmin,
pcontext->y - pcontext->region->winrct.ymin,
};
@@ -1368,7 +1369,7 @@ static void paint_cursor_sculpt_session_update_and_init(PaintCursorContext *pcon
pcontext->prev_active_vertex_index = ss->active_vertex_index;
if (!ups->stroke_active) {
pcontext->is_cursor_over_mesh = SCULPT_cursor_geometry_info_update(
- C, &gi, mouse, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
+ C, &gi, mval_fl, (pcontext->brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
copy_v3_v3(pcontext->location, gi.location);
copy_v3_v3(pcontext->normal, gi.normal);
}
@@ -1932,7 +1933,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* Public API */
-void paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
+void ED_paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
{
if (p && !p->paint_cursor) {
p->paint_cursor = WM_paint_cursor_activate(
diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc
index a313489885d..56cd4751881 100644
--- a/source/blender/editors/sculpt_paint/paint_image.cc
+++ b/source/blender/editors/sculpt_paint/paint_image.cc
@@ -287,7 +287,7 @@ static bool image_paint_poll_ex(bContext *C, bool check_tool)
return false;
}
-bool image_paint_poll(bContext *C)
+bool ED_image_tools_paint_poll(bContext *C)
{
return image_paint_poll_ex(C, true);
}
@@ -301,7 +301,7 @@ static bool image_paint_2d_clone_poll(bContext *C)
{
Brush *brush = image_paint_brush(C);
- if (!CTX_wm_region_view3d(C) && image_paint_poll(C)) {
+ if (!CTX_wm_region_view3d(C) && ED_image_tools_paint_poll(C)) {
if (brush && (brush->imagepaint_tool == PAINT_TOOL_CLONE)) {
if (brush->clone.image) {
return true;
@@ -430,7 +430,7 @@ static void toggle_paint_cursor(Scene *scene, bool enable)
paint_cursor_delete_textures();
}
else if (enable) {
- paint_cursor_start(p, image_paint_poll);
+ ED_paint_cursor_start(p, ED_image_tools_paint_poll);
}
}
@@ -455,7 +455,7 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
if (enabled) {
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
- paint_cursor_start(&imapaint->paint, image_paint_poll);
+ ED_paint_cursor_start(&imapaint->paint, ED_image_tools_paint_poll);
}
else {
paint_cursor_delete_textures();
@@ -736,7 +736,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
ot->poll = sample_color_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
/* properties */
PropertyRNA *prop;
@@ -925,7 +925,7 @@ static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
static bool brush_colors_flip_poll(bContext *C)
{
- if (image_paint_poll(C)) {
+ if (ED_image_tools_paint_poll(C)) {
Brush *br = image_paint_brush(C);
if (ELEM(br->imagepaint_tool, PAINT_TOOL_DRAW, PAINT_TOOL_FILL)) {
return true;
@@ -954,7 +954,7 @@ void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
ot->poll = brush_colors_flip_poll;
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
}
void ED_imapaint_bucket_fill(struct bContext *C,
@@ -991,7 +991,7 @@ static bool texture_paint_poll(bContext *C)
bool image_texture_paint_poll(bContext *C)
{
- return (texture_paint_poll(C) || image_paint_poll(C));
+ return (texture_paint_poll(C) || ED_image_tools_paint_poll(C));
}
bool facemask_paint_poll(bContext *C)
diff --git a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
index 8ddf1614e41..a671c24c514 100644
--- a/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
+++ b/source/blender/editors/sculpt_paint/paint_image_ops_paint.cc
@@ -34,6 +34,8 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "ED_image.h"
+
#include "paint_intern.h"
namespace blender::ed::sculpt_paint::image::ops::paint {
@@ -316,7 +318,7 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
pop->cursor = WM_paint_cursor_activate(
- SPACE_TYPE_ANY, RGN_TYPE_ANY, image_paint_poll, gradient_draw_line, pop);
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, ED_image_tools_paint_poll, gradient_draw_line, pop);
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
@@ -520,7 +522,7 @@ void PAINT_OT_image_paint(wmOperatorType *ot)
ot->invoke = paint_invoke;
ot->modal = paint_modal;
ot->exec = paint_exec;
- ot->poll = image_paint_poll;
+ ot->poll = ED_image_tools_paint_poll;
ot->cancel = paint_cancel;
/* flags */
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 95a7c1d8dee..50480b8aef0 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -97,8 +97,6 @@
#include "RNA_enum_types.h"
#include "RNA_types.h"
-#include "NOD_shader.h"
-
#include "IMB_colormanagement.h"
//#include "bmesh_tools.h"
@@ -3134,7 +3132,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
}
}
- /* Is this UV visible from the view? - raytrace */
+ /* Is this UV visible from the view? - ray-trace */
/* project_paint_PickFace is less complex, use for testing */
// if (project_paint_PickFace(ps, pixelScreenCo, w, &side) == tri_index) {
if ((ps->do_occlude == false) ||
@@ -3224,7 +3222,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
float seam_subsection[4][2];
float fac1, fac2;
- /* Pixelspace UVs. */
+ /* Pixel-space UV's. */
float lt_puv[3][2];
lt_puv[0][0] = lt_uv_pxoffset[0][0] * ibuf->x;
@@ -4494,7 +4492,8 @@ static void project_paint_begin(const bContext *C,
}
}
- /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
+ /* when using sub-surface or multi-resolution,
+ * mesh-data arrays are thrown away, we need to keep a copy. */
if (ps->is_shared_user == false) {
proj_paint_state_cavity_init(ps);
}
@@ -6490,14 +6489,14 @@ static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object
{
char name[MAX_NAME] = "";
float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
- AttributeDomain domain = ATTR_DOMAIN_POINT;
- CustomDataType type = CD_PROP_COLOR;
+ eAttrDomain domain = ATTR_DOMAIN_POINT;
+ eCustomDataType type = CD_PROP_COLOR;
if (op) {
RNA_string_get(op->ptr, "name", name);
RNA_float_get_array(op->ptr, "color", color);
- domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain");
- type = (CustomDataType)RNA_enum_get(op->ptr, "data_type");
+ domain = (eAttrDomain)RNA_enum_get(op->ptr, "domain");
+ type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type");
}
ID *id = (ID *)ob->data;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 187f793eefe..99c25953d50 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -46,7 +46,10 @@ typedef struct CoNo {
/* paint_stroke.c */
-typedef bool (*StrokeGetLocation)(struct bContext *C, float location[3], const float mouse[2]);
+typedef bool (*StrokeGetLocation)(struct bContext *C,
+ float location[3],
+ const float mouse[2],
+ bool force_original);
typedef bool (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, const float mouse[2]);
typedef void (*StrokeUpdateStep)(struct bContext *C,
struct wmOperator *op,
@@ -98,7 +101,6 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke);
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.
*/
@@ -135,18 +137,10 @@ void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_color(struct Scene *scene, struct VPaint *vp, bool secondary);
-/* paint_vertex_color_utils.c */
-
/**
* \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 */
@@ -379,10 +373,12 @@ void PAINT_OT_face_select_linked(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot);
void PAINT_OT_face_select_all(struct wmOperatorType *ot);
void PAINT_OT_face_select_hide(struct wmOperatorType *ot);
-void PAINT_OT_face_select_reveal(struct wmOperatorType *ot);
+
+void PAINT_OT_face_vert_reveal(struct wmOperatorType *ot);
void PAINT_OT_vert_select_all(struct wmOperatorType *ot);
void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot);
+void PAINT_OT_vert_select_hide(struct wmOperatorType *ot);
bool vert_paint_poll(struct bContext *C);
bool mask_paint_poll(struct bContext *C);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index fb5e76b578f..89bbf2a3c92 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1584,9 +1584,9 @@ static int sculpt_trim_gesture_box_invoke(bContext *C, wmOperator *op, const wmE
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
if (ss->gesture_initial_hit) {
copy_v3_v3(ss->gesture_initial_location, sgi.location);
copy_v3_v3(ss->gesture_initial_normal, sgi.normal);
@@ -1625,9 +1625,9 @@ static int sculpt_trim_gesture_lasso_invoke(bContext *C, wmOperator *op, const w
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
if (ss->gesture_initial_hit) {
copy_v3_v3(ss->gesture_initial_location, sgi.location);
copy_v3_v3(ss->gesture_initial_normal, sgi.normal);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 926a564184a..994ae4011b4 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -82,11 +82,85 @@ static void BRUSH_OT_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool,
+ enum eContextObjectMode mode)
+{
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "DRAW")) {
+ return GP_BRUSH_PRESET_PENCIL;
+ }
+ if (STREQ(tool->runtime->data_block, "FILL")) {
+ return GP_BRUSH_PRESET_FILL_AREA;
+ }
+ if (STREQ(tool->runtime->data_block, "ERASE")) {
+ return GP_BRUSH_PRESET_ERASER_SOFT;
+ }
+ if (STREQ(tool->runtime->data_block, "TINT")) {
+ return GP_BRUSH_PRESET_TINT;
+ }
+ break;
+ }
+ case CTX_MODE_SCULPT_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "SMOOTH")) {
+ return GP_BRUSH_PRESET_SMOOTH_STROKE;
+ }
+ if (STREQ(tool->runtime->data_block, "STRENGTH")) {
+ return GP_BRUSH_PRESET_STRENGTH_STROKE;
+ }
+ if (STREQ(tool->runtime->data_block, "THICKNESS")) {
+ return GP_BRUSH_PRESET_THICKNESS_STROKE;
+ }
+ if (STREQ(tool->runtime->data_block, "GRAB")) {
+ return GP_BRUSH_PRESET_GRAB_STROKE;
+ }
+ if (STREQ(tool->runtime->data_block, "PUSH")) {
+ return GP_BRUSH_PRESET_PUSH_STROKE;
+ }
+ if (STREQ(tool->runtime->data_block, "TWIST")) {
+ return GP_BRUSH_PRESET_TWIST_STROKE;
+ }
+ if (STREQ(tool->runtime->data_block, "PINCH")) {
+ return GP_BRUSH_PRESET_PINCH_STROKE;
+ }
+ if (STREQ(tool->runtime->data_block, "RANDOMIZE")) {
+ return GP_BRUSH_PRESET_RANDOMIZE_STROKE;
+ }
+ if (STREQ(tool->runtime->data_block, "CLONE")) {
+ return GP_BRUSH_PRESET_CLONE_STROKE;
+ }
+ break;
+ }
+ case CTX_MODE_WEIGHT_GPENCIL: {
+ return GP_BRUSH_PRESET_DRAW_WEIGHT;
+ }
+ case CTX_MODE_VERTEX_GPENCIL: {
+ if (STREQ(tool->runtime->data_block, "DRAW")) {
+ return GP_BRUSH_PRESET_VERTEX_DRAW;
+ }
+ if (STREQ(tool->runtime->data_block, "BLUR")) {
+ return GP_BRUSH_PRESET_VERTEX_BLUR;
+ }
+ if (STREQ(tool->runtime->data_block, "AVERAGE")) {
+ return GP_BRUSH_PRESET_VERTEX_AVERAGE;
+ }
+ if (STREQ(tool->runtime->data_block, "SMEAR")) {
+ return GP_BRUSH_PRESET_VERTEX_SMEAR;
+ }
+ if (STREQ(tool->runtime->data_block, "REPLACE")) {
+ return GP_BRUSH_PRESET_VERTEX_REPLACE;
+ }
+ break;
+ }
+ default:
+ return GP_BRUSH_PRESET_UNKNOWN;
+ }
+ return GP_BRUSH_PRESET_UNKNOWN;
+}
+
static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
{
- // int type = RNA_enum_get(op->ptr, "type");
- ToolSettings *ts = CTX_data_tool_settings(C);
- Paint *paint = &ts->gp_paint->paint;
+ Paint *paint = BKE_paint_get_active_from_context(C);
Brush *br = BKE_paint_brush(paint);
Main *bmain = CTX_data_main(C);
@@ -94,15 +168,70 @@ static int brush_add_gpencil_exec(bContext *C, wmOperator *UNUSED(op))
br = (Brush *)BKE_id_copy(bmain, &br->id);
}
else {
- br = BKE_brush_add(bmain, "Brush", OB_MODE_PAINT_GPENCIL);
+ /* Get the active tool to determine what type of brush is active. */
+ bScreen *screen = CTX_wm_screen(C);
+ if (screen == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- /* Init grease pencil specific data. */
- BKE_brush_init_gpencil_settings(br);
- }
+ bToolRef *tool = NULL;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ /* Check the current tool is a brush. */
+ bToolRef *tref = area->runtime.tool;
+ if (tref && tref->runtime && tref->runtime->data_block[0]) {
+ tool = tref;
+ break;
+ }
+ }
+ }
- id_us_min(&br->id); /* fake user only */
+ if (tool == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- BKE_paint_brush_set(paint, br);
+ /* Get Brush mode base on context mode. */
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ eObjectMode obmode = OB_MODE_PAINT_GPENCIL;
+ switch (mode) {
+ case CTX_MODE_PAINT_GPENCIL:
+ obmode = OB_MODE_PAINT_GPENCIL;
+ break;
+ case CTX_MODE_SCULPT_GPENCIL:
+ obmode = OB_MODE_SCULPT_GPENCIL;
+ break;
+ case CTX_MODE_WEIGHT_GPENCIL:
+ obmode = OB_MODE_WEIGHT_GPENCIL;
+ break;
+ case CTX_MODE_VERTEX_GPENCIL:
+ obmode = OB_MODE_VERTEX_GPENCIL;
+ break;
+ default:
+ return OPERATOR_CANCELLED;
+ break;
+ }
+
+ /* Get brush preset using the actual tool. */
+ eGPBrush_Presets preset = gpencil_get_brush_preset_from_tool(tool, mode);
+
+ /* Capitalize Brush name first letter using the tool name. */
+ char name[64];
+ BLI_strncpy(name, tool->runtime->data_block, sizeof(name));
+ BLI_str_tolower_ascii(name, sizeof(name));
+ name[0] = BLI_toupper_ascii(name[0]);
+
+ /* Create the brush and assign default values. */
+ br = BKE_brush_add(bmain, name, obmode);
+ if (br) {
+ BKE_brush_init_gpencil_settings(br);
+ BKE_gpencil_brush_preset_set(bmain, br, preset);
+ }
+ }
+
+ if (br) {
+ id_us_min(&br->id); /* fake user only */
+ BKE_paint_brush_set(paint, br);
+ }
return OPERATOR_FINISHED;
}
@@ -1325,6 +1454,7 @@ void ED_operatortypes_paint(void)
/* vertex selection */
WM_operatortype_append(PAINT_OT_vert_select_all);
WM_operatortype_append(PAINT_OT_vert_select_ungrouped);
+ WM_operatortype_append(PAINT_OT_vert_select_hide);
/* vertex */
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
@@ -1343,7 +1473,8 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
WM_operatortype_append(PAINT_OT_face_select_all);
WM_operatortype_append(PAINT_OT_face_select_hide);
- WM_operatortype_append(PAINT_OT_face_select_reveal);
+
+ WM_operatortype_append(PAINT_OT_face_vert_reveal);
/* partial visibility */
WM_operatortype_append(PAINT_OT_hide_show);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 210cffcbcda..88e7a786a47 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -79,6 +79,8 @@ typedef struct PaintStroke {
float last_mouse_position[2];
float last_world_space_position[3];
+ float last_scene_spacing_delta[3];
+
bool stroke_over_mesh;
/* space distance covered so far */
float stroke_distance;
@@ -120,6 +122,8 @@ typedef struct PaintStroke {
StrokeUpdateStep update_step;
StrokeRedraw redraw;
StrokeDone done;
+
+ bool original; /* Raycast original mesh at start of stroke */
} PaintStroke;
/*** Cursors ***/
@@ -243,6 +247,11 @@ static bool paint_stroke_use_scene_spacing(Brush *brush, ePaintMode mode)
return false;
}
+static bool paint_tool_raycast_original(Brush *brush, ePaintMode UNUSED(mode))
+{
+ return brush->flag & BRUSH_ANCHORED;
+}
+
static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode mode)
{
if (brush->flag & BRUSH_ANCHORED) {
@@ -392,7 +401,7 @@ static bool paint_brush_update(bContext *C,
halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
if (stroke->get_location) {
- if (stroke->get_location(C, r_location, halfway)) {
+ if (stroke->get_location(C, r_location, halfway, stroke->original)) {
hit = true;
location_sampled = true;
location_success = true;
@@ -466,7 +475,7 @@ static bool paint_brush_update(bContext *C,
if (!location_sampled) {
if (stroke->get_location) {
- if (stroke->get_location(C, r_location, mouse)) {
+ if (stroke->get_location(C, r_location, mouse, stroke->original)) {
location_success = true;
*r_location_is_set = true;
}
@@ -506,7 +515,7 @@ static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert)
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
static void paint_brush_stroke_add_step(
- bContext *C, wmOperator *op, PaintStroke *stroke, const float mouse_in[2], float pressure)
+ bContext *C, wmOperator *op, PaintStroke *stroke, const float mval[2], float pressure)
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
@@ -546,12 +555,20 @@ static void paint_brush_stroke_add_step(
/* copy last position -before- jittering, or space fill code
* will create too many dabs */
- copy_v2_v2(stroke->last_mouse_position, mouse_in);
+ copy_v2_v2(stroke->last_mouse_position, mval);
stroke->last_pressure = pressure;
if (paint_stroke_use_scene_spacing(brush, mode)) {
- SCULPT_stroke_get_location(C, stroke->last_world_space_position, stroke->last_mouse_position);
- mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
+ float world_space_position[3];
+
+ if (SCULPT_stroke_get_location(
+ C, world_space_position, stroke->last_mouse_position, stroke->original)) {
+ copy_v3_v3(stroke->last_world_space_position, world_space_position);
+ mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
+ }
+ else {
+ add_v3_v3(stroke->last_world_space_position, stroke->last_scene_spacing_delta);
+ }
}
if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
@@ -562,24 +579,24 @@ static void paint_brush_stroke_add_step(
factor *= pressure;
}
- BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
+ BKE_brush_jitter_pos(scene, brush, mval, mouse_out);
/* XXX: meh, this is round about because
* BKE_brush_jitter_pos isn't written in the best way to
* be reused here */
if (factor != 1.0f) {
- sub_v2_v2v2(delta, mouse_out, mouse_in);
+ sub_v2_v2v2(delta, mouse_out, mval);
mul_v2_fl(delta, factor);
- add_v2_v2v2(mouse_out, mouse_in, delta);
+ add_v2_v2v2(mouse_out, mval, delta);
}
}
else {
- copy_v2_v2(mouse_out, mouse_in);
+ copy_v2_v2(mouse_out, mval);
}
bool is_location_is_set;
ups->last_hit = paint_brush_update(
- C, brush, mode, stroke, mouse_in, mouse_out, pressure, location, &is_location_is_set);
+ C, brush, mode, stroke, mval, mouse_out, pressure, location, &is_location_is_set);
if (is_location_is_set) {
copy_v3_v3(ups->last_location, location);
}
@@ -605,7 +622,7 @@ static void paint_brush_stroke_add_step(
/* Mouse coordinates modified by the stroke type options. */
RNA_float_set_array(&itemptr, "mouse", mouse_out);
/* Original mouse coordinates. */
- RNA_float_set_array(&itemptr, "mouse_event", mouse_in);
+ RNA_float_set_array(&itemptr, "mouse_event", mval);
RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
RNA_float_set(&itemptr, "pressure", pressure);
RNA_float_set(&itemptr, "x_tilt", stroke->x_tilt);
@@ -698,7 +715,7 @@ static float paint_space_stroke_spacing(bContext *C,
spacing *= stroke->zoom_2d;
if (paint_stroke_use_scene_spacing(brush, mode)) {
- return max_ff(0.001f, size_clamp * spacing / 50.0f);
+ return size_clamp * spacing / 50.0f;
}
return max_ff(stroke->zoom_2d, size_clamp * spacing / 50.0f);
}
@@ -807,7 +824,7 @@ static int paint_space_stroke(bContext *C,
if (use_scene_spacing) {
float world_space_position[3];
- bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse);
+ bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position);
if (hit && stroke->stroke_over_mesh) {
sub_v3_v3v3(d_world_space_position, world_space_position, stroke->last_world_space_position);
@@ -838,6 +855,8 @@ static int paint_space_stroke(bContext *C,
stroke->last_world_space_position,
final_world_space_position);
ED_view3d_project_v2(region, final_world_space_position, mouse);
+
+ mul_v3_v3fl(stroke->last_scene_spacing_delta, d_world_space_position, spacing);
}
else {
mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
@@ -896,6 +915,8 @@ PaintStroke *paint_stroke_new(bContext *C,
stroke->ups = ups;
stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
+ stroke->original = paint_tool_raycast_original(br, BKE_paintmode_get_active_from_context(C));
+
get_imapaint_zoom(C, &zoomx, &zoomy);
stroke->zoom_2d = max_ff(zoomx, zoomy);
@@ -912,8 +933,13 @@ PaintStroke *paint_stroke_new(bContext *C,
rv3d->rflag |= RV3D_PAINTING;
}
- zero_v3(ups->average_stroke_accum);
- ups->average_stroke_counter = 0;
+ /* Preserve location from last stroke while applying and resetting
+ * ups->average_stroke_counter to 1.
+ */
+ if (ups->average_stroke_counter) {
+ mul_v3_fl(ups->average_stroke_accum, 1.0f / (float)ups->average_stroke_counter);
+ ups->average_stroke_counter = 1;
+ }
/* initialize here to avoid initialization conflict with threaded strokes */
BKE_curvemapping_init(br->curve);
@@ -990,7 +1016,7 @@ static void stroke_done(bContext *C, wmOperator *op, PaintStroke *stroke)
static bool curves_sculpt_brush_uses_spacing(const eBrushCurvesSculptTool tool)
{
- return ELEM(tool, CURVES_SCULPT_TOOL_ADD);
+ return ELEM(tool, CURVES_SCULPT_TOOL_ADD, CURVES_SCULPT_TOOL_DENSITY);
}
bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
@@ -1186,8 +1212,10 @@ static void paint_line_strokes_spacing(bContext *C,
copy_v2_v2(stroke->last_mouse_position, old_pos);
if (use_scene_spacing) {
- bool hit_old = SCULPT_stroke_get_location(C, world_space_position_old, old_pos);
- bool hit_new = SCULPT_stroke_get_location(C, world_space_position_new, new_pos);
+ bool hit_old = SCULPT_stroke_get_location(
+ C, world_space_position_old, old_pos, stroke->original);
+ bool hit_new = SCULPT_stroke_get_location(
+ C, world_space_position_new, new_pos, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position_old);
mul_m4_v3(stroke->vc.obact->obmat, world_space_position_new);
if (hit_old && hit_new && stroke->stroke_over_mesh) {
@@ -1331,7 +1359,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
if (paint_stroke_use_scene_spacing(br, BKE_paintmode_get_active_from_context(C))) {
stroke->stroke_over_mesh = SCULPT_stroke_get_location(
- C, stroke->last_world_space_position, data + 2 * j);
+ C, stroke->last_world_space_position, data + 2 * j, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
}
@@ -1463,7 +1491,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event, PaintS
copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
if (paint_stroke_use_scene_spacing(br, mode)) {
stroke->stroke_over_mesh = SCULPT_stroke_get_location(
- C, stroke->last_world_space_position, sample_average.mouse);
+ C, stroke->last_world_space_position, sample_average.mouse, stroke->original);
mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
}
stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 3f26f590b70..1f272882100 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -749,25 +749,68 @@ void PAINT_OT_face_select_hide(wmOperatorType *ot)
ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected objects");
}
-static int face_select_reveal_exec(bContext *C, wmOperator *op)
+static int vert_select_hide_exec(bContext *C, wmOperator *op)
+{
+ const bool unselected = RNA_boolean_get(op->ptr, "unselected");
+ Object *ob = CTX_data_active_object(C);
+ paintvert_hide(C, ob, unselected);
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vert_select_hide(wmOperatorType *ot)
+{
+ ot->name = "Vertex Select Hide";
+ ot->description = "Hide selected vertices";
+ ot->idname = "PAINT_OT_vert_select_hide";
+
+ ot->exec = vert_select_hide_exec;
+ ot->poll = vert_paint_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(
+ ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected vertices");
+}
+
+static int face_vert_reveal_exec(bContext *C, wmOperator *op)
{
const bool select = RNA_boolean_get(op->ptr, "select");
Object *ob = CTX_data_active_object(C);
- paintface_reveal(C, ob, select);
+
+ if (BKE_paint_select_vert_test(ob)) {
+ paintvert_reveal(C, ob, select);
+ }
+ else {
+ paintface_reveal(C, ob, select);
+ }
+
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
-void PAINT_OT_face_select_reveal(wmOperatorType *ot)
+static bool face_vert_reveal_poll(bContext *C)
{
- ot->name = "Face Select Reveal";
- ot->description = "Reveal hidden faces";
- ot->idname = "PAINT_OT_face_select_reveal";
+ Object *ob = CTX_data_active_object(C);
- ot->exec = face_select_reveal_exec;
- ot->poll = facemask_paint_poll;
+ /* Allow using this operator when no selection is enabled but hiding is applied. */
+ return BKE_paint_select_elem_test(ob) || BKE_paint_always_hide_test(ob);
+}
+
+void PAINT_OT_face_vert_reveal(wmOperatorType *ot)
+{
+ ot->name = "Reveal Faces/Vertices";
+ ot->description = "Reveal hidden faces and vertices";
+ ot->idname = "PAINT_OT_face_vert_reveal";
+
+ ot->exec = face_vert_reveal_exec;
+ ot->poll = face_vert_reveal_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ RNA_def_boolean(ot->srna,
+ "select",
+ true,
+ "Select",
+ "Specifies whether the newly revealed geometry should be selected");
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc
index fb1c8ceaa1a..6dc8375bb0d 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.cc
+++ b/source/blender/editors/sculpt_paint/paint_vertex.cc
@@ -36,6 +36,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -56,6 +57,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -139,8 +141,8 @@ struct NormalAnglePrecalc {
/* Returns number of elements. */
static int get_vcol_elements(Mesh *me, size_t *r_elem_size)
{
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
- AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
if (r_elem_size) {
*r_elem_size = layer->type == CD_PROP_COLOR ? sizeof(float) * 4ULL : 4ULL;
@@ -217,7 +219,7 @@ static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev,
MDeformVert *dvert_curr,
int index)
{
- MDeformVert *dv_curr = &dvert_curr[index];
+ const MDeformVert *dv_curr = &dvert_curr[index];
MDeformVert *dv_prev = &dvert_prev[index];
if (dv_prev->flag == 1) {
dv_prev->flag = 0;
@@ -226,22 +228,6 @@ static MDeformVert *defweight_prev_init(MDeformVert *dvert_prev,
return dv_prev;
}
-/* check if we can do partial updates and have them draw realtime
- * (without evaluating modifiers) */
-static bool vertex_paint_use_fast_update_check(Object *ob)
-{
- const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
-
- if (me_eval != nullptr) {
- Mesh *me = BKE_mesh_from_object(ob);
- if (me && me->mloopcol) {
- return (me->mloopcol == CustomData_get_layer(&me_eval->ldata, CD_PROP_BYTE_COLOR));
- }
- }
-
- return false;
-}
-
static void paint_last_stroke_update(Scene *scene, const float location[3])
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -252,13 +238,14 @@ static void paint_last_stroke_update(Scene *scene, const float location[3])
bool vertex_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
- if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly)) {
+ if (!(ob && ob->mode == OB_MODE_VERTEX_PAINT && ((const Mesh *)ob->data)->totpoly)) {
return false;
}
- CustomDataLayer *layer = BKE_id_attributes_active_color_get((ID *)ob->data);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(
+ static_cast<const ID *>(ob->data));
return layer != nullptr;
}
@@ -291,15 +278,15 @@ bool vertex_paint_poll_ignore_tool(bContext *C)
bool weight_paint_mode_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ const Object *ob = CTX_data_active_object(C);
- return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly;
+ return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((const Mesh *)ob->data)->totpoly;
}
static bool weight_paint_poll_ex(bContext *C, bool check_tool)
{
- Object *ob = CTX_data_active_object(C);
- ScrArea *area;
+ const Object *ob = CTX_data_active_object(C);
+ const ScrArea *area;
if ((ob != nullptr) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != nullptr) &&
@@ -324,10 +311,10 @@ bool weight_paint_poll_ignore_tool(bContext *C)
return weight_paint_poll_ex(C, false);
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static Color vpaint_get_current_col(Scene *scene, VPaint *vp, bool secondary)
{
- Brush *brush = BKE_paint_brush(&vp->paint);
+ const Brush *brush = BKE_paint_brush_for_read(&vp->paint);
float color[4];
const float *brush_color = secondary ? BKE_brush_secondary_color_get(scene, brush) :
BKE_brush_color_get(scene, brush);
@@ -360,7 +347,7 @@ static Color vpaint_blend(const VPaint *vp,
const Brush *brush = vp->paint.brush;
const IMB_BlendMode blend = (IMB_BlendMode)brush->blend;
- Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
+ const Color color_blend = BLI_mix_colors<Color, Traits>(blend, color_curr, color_paint, alpha);
/* If no accumulate, clip color adding with `color_orig` & `color_test`. */
if (!brush_use_accumulate(vp)) {
@@ -1189,12 +1176,12 @@ static void vertex_paint_init_session(Depsgraph *depsgraph,
BLI_assert(ob->sculpt == nullptr);
ob->sculpt = (SculptSession *)MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->mode_type = object_mode;
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
}
static void vwpaint_init_stroke(Depsgraph *depsgraph, Object *ob)
{
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true);
SculptSession *ss = ob->sculpt;
/* Ensure ss->cache is allocated. It will mostly be initialized in
@@ -1321,7 +1308,7 @@ static void ed_vwpaintmode_enter_generic(
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start(paint, vertex_paint_poll);
+ ED_paint_cursor_start(paint, vertex_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
}
else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
@@ -1329,7 +1316,7 @@ static void ed_vwpaintmode_enter_generic(
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start(paint, weight_paint_poll);
+ ED_paint_cursor_start(paint, weight_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
/* weight paint specific */
@@ -1606,10 +1593,10 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache
/* Initialize the stroke cache invariants from operator properties */
static void vwpaint_update_cache_invariants(
- bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mval[2])
{
StrokeCache *cache;
- Scene *scene = CTX_data_scene(C);
+ const Scene *scene = CTX_data_scene(C);
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
ViewContext *vc = paint_stroke_view_context((PaintStroke *)op->customdata);
Object *ob = CTX_data_active_object(C);
@@ -1627,8 +1614,8 @@ static void vwpaint_update_cache_invariants(
}
/* Initial mouse location */
- if (mouse) {
- copy_v2_v2(cache->initial_mouse, mouse);
+ if (mval) {
+ copy_v2_v2(cache->initial_mouse, mval);
}
else {
zero_v2(cache->initial_mouse);
@@ -1651,7 +1638,7 @@ static void vwpaint_update_cache_invariants(
}
copy_v2_v2(cache->mouse, cache->initial_mouse);
- Brush *brush = vp->paint.brush;
+ const Brush *brush = vp->paint.brush;
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
cache->brush = brush;
@@ -1802,7 +1789,8 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* set up auto-normalize, and generate map for detecting which
* vgroups affect deform bones */
wpd->lock_flags = BKE_object_defgroup_lock_flags_get(ob, wpd->defbase_tot);
- if (ts->auto_normalize || ts->multipaint || wpd->lock_flags || ts->wpaint_lock_relative) {
+ if (ts->auto_normalize || ts->multipaint || wpd->lock_flags != nullptr ||
+ ts->wpaint_lock_relative) {
wpd->vgroup_validmap = BKE_object_defgroup_validmap_get(ob, wpd->defbase_tot);
}
@@ -2591,31 +2579,14 @@ static void wpaint_stroke_done(const bContext *C, PaintStroke *stroke)
WPaintData *wpd = (WPaintData *)paint_stroke_mode_data(stroke);
if (wpd) {
- if (wpd->defbase_sel) {
- MEM_freeN((void *)wpd->defbase_sel);
- }
- if (wpd->vgroup_validmap) {
- MEM_freeN((void *)wpd->vgroup_validmap);
- }
- if (wpd->vgroup_locked) {
- MEM_freeN((void *)wpd->vgroup_locked);
- }
- if (wpd->vgroup_unlocked) {
- MEM_freeN((void *)wpd->vgroup_unlocked);
- }
- if (wpd->lock_flags) {
- MEM_freeN((void *)wpd->lock_flags);
- }
- if (wpd->active.lock) {
- MEM_freeN((void *)wpd->active.lock);
- }
- if (wpd->mirror.lock) {
- MEM_freeN((void *)wpd->mirror.lock);
- }
- if (wpd->precomputed_weight) {
- MEM_freeN(wpd->precomputed_weight);
- }
-
+ MEM_SAFE_FREE(wpd->defbase_sel);
+ MEM_SAFE_FREE(wpd->vgroup_validmap);
+ MEM_SAFE_FREE(wpd->vgroup_locked);
+ MEM_SAFE_FREE(wpd->vgroup_unlocked);
+ MEM_SAFE_FREE(wpd->lock_flags);
+ MEM_SAFE_FREE(wpd->active.lock);
+ MEM_SAFE_FREE(wpd->mirror.lock);
+ MEM_SAFE_FREE(wpd->precomputed_weight);
MEM_freeN(wpd);
}
@@ -2823,11 +2794,11 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
struct VPaintDataBase {
ViewContext vc;
- AttributeDomain domain;
- CustomDataType type;
+ eAttrDomain domain;
+ eCustomDataType type;
};
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
struct VPaintData : public VPaintDataBase {
NormalAnglePrecalc normal_angle_precalc;
@@ -2836,16 +2807,6 @@ struct VPaintData : public VPaintDataBase {
struct VertProjHandle *vp_handle;
CoNo *vertexcosnos;
- /**
- * Modify #Mesh.mloopcol directly, since the derived mesh is drawing from this
- * array, otherwise we need to refresh the modifier stack.
- */
- bool use_fast_update;
-
- /* loops tagged as having been painted, to apply shared vertex color
- * blending only to modified loops */
- bool *mlooptag;
-
bool is_texbrush;
/* Special storage for smear brush, avoid feedback loop - update each step. */
@@ -2855,7 +2816,7 @@ struct VPaintData : public VPaintDataBase {
} smear;
};
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void *vpaint_init_vpaint(bContext *C,
wmOperator *op,
Scene *scene,
@@ -2891,20 +2852,6 @@ static void *vpaint_init_vpaint(bContext *C,
vpd->is_texbrush = !(brush->vertexpaint_tool == VPAINT_TOOL_BLUR) && brush->mtex.tex;
- /* are we painting onto a modified mesh?,
- * if not we can skip face map trickiness */
- if (vertex_paint_use_fast_update_check(ob)) {
- vpd->use_fast_update = true;
- }
- else {
- vpd->use_fast_update = false;
- }
-
- /* to keep tracked of modified loops for shared vertex color blending */
- if (brush->vertexpaint_tool == VPAINT_TOOL_BLUR) {
- vpd->mlooptag = (bool *)MEM_mallocN(sizeof(bool) * elem_num, "VPaintData mlooptag");
- }
-
if (brush->vertexpaint_tool == VPAINT_TOOL_SMEAR) {
CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
@@ -2949,7 +2896,7 @@ static bool vpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
return false;
}
- AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
void *vpd = nullptr;
if (domain == ATTR_DOMAIN_POINT) {
@@ -3272,7 +3219,7 @@ static void do_vpaint_brush_blur_verts(bContext *C,
});
}
-template<typename Color = ColorPaint4b, typename Traits, AttributeDomain domain>
+template<typename Color = ColorPaint4b, typename Traits, eAttrDomain domain>
static void do_vpaint_brush_smear(bContext *C,
Sculpt *UNUSED(sd),
VPaint *vp,
@@ -3451,7 +3398,7 @@ static void do_vpaint_brush_smear(bContext *C,
});
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd,
Object *ob,
Mesh *me,
@@ -3541,7 +3488,7 @@ static void calculate_average_color(VPaintData<Color, Traits, domain> *vpd,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static float paint_and_tex_color_alpha(VPaint *vp,
VPaintData<Color, Traits, domain> *vpd,
const float v_co[3],
@@ -3559,7 +3506,7 @@ static float paint_and_tex_color_alpha(VPaint *vp,
return rgba[3];
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_draw(bContext *C,
Sculpt *UNUSED(sd),
VPaint *vp,
@@ -3699,7 +3646,7 @@ static void vpaint_do_draw(bContext *C,
});
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_blur(bContext *C,
Sculpt *sd,
VPaint *vp,
@@ -3718,7 +3665,7 @@ static void vpaint_do_blur(bContext *C,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_paint_leaves(bContext *C,
Sculpt *sd,
VPaint *vp,
@@ -3754,7 +3701,7 @@ static void vpaint_paint_leaves(bContext *C,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_paint(bContext *C,
Sculpt *sd,
VPaint *vp,
@@ -3785,7 +3732,7 @@ static void vpaint_do_paint(bContext *C,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_radial_symmetry(bContext *C,
Sculpt *sd,
VPaint *vp,
@@ -3804,7 +3751,7 @@ static void vpaint_do_radial_symmetry(bContext *C,
/* near duplicate of: sculpt.c's,
* 'do_symmetrical_brush_actions' and 'wpaint_do_symmetrical_brush_actions'. */
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_do_symmetrical_brush_actions(
bContext *C, Sculpt *sd, VPaint *vp, VPaintData<Color, Traits, domain> *vpd, Object *ob)
{
@@ -3851,7 +3798,7 @@ static void vpaint_do_symmetrical_brush_actions(
cache->is_last_valid = true;
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, PointerRNA *itemptr)
{
Scene *scene = CTX_data_scene(C);
@@ -3899,15 +3846,7 @@ static void vpaint_stroke_update_step_intern(bContext *C, PaintStroke *stroke, P
ED_region_tag_redraw(vc->region);
- if (vpd->use_fast_update == false) {
- /* recalculate modifier stack to get new colors, slow,
- * avoid this if we can! */
- DEG_id_tag_update((ID *)ob->data, 0);
- }
- else {
- /* Flush changes through DEG. */
- DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
- }
+ DEG_id_tag_update((ID *)ob->data, ID_RECALC_GEOMETRY);
}
static void vpaint_stroke_update_step(bContext *C,
@@ -3939,7 +3878,7 @@ static void vpaint_stroke_update_step(bContext *C,
}
}
-template<typename Color, typename Traits, AttributeDomain domain>
+template<typename Color, typename Traits, eAttrDomain domain>
static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd)
{
VPaintData<Color, Traits, domain> *vpd = static_cast<VPaintData<Color, Traits, domain> *>(_vpd);
@@ -3948,9 +3887,6 @@ static void vpaint_free_vpaintdata(Object *UNUSED(ob), void *_vpd)
ED_vpaint_proj_handle_free(vpd->vp_handle);
}
- if (vpd->mlooptag) {
- MEM_freeN(vpd->mlooptag);
- }
if (vpd->smear.color_prev) {
MEM_freeN(vpd->smear.color_prev);
}
@@ -4096,8 +4032,8 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
/** \name Set Vertex Colors Operator
* \{ */
-template<typename Color, typename Traits, AttributeDomain domain>
-static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_layer)
+template<typename Color, typename Traits, eAttrDomain domain>
+static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, CustomDataLayer *layer)
{
Mesh *me;
if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
@@ -4110,30 +4046,70 @@ static bool vertex_color_set(Object *ob, ColorPaint4f paintcol_in, Color *color_
const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
- const MPoly *mp = me->mpoly;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
+ if (me->edit_mesh) {
+ BMesh *bm = me->edit_mesh->bm;
+ BMFace *f;
+ BMIter iter;
+
+ int cd_offset = -1;
+
+ /* Find customdata offset inside of bmesh. */
+ CustomData *cdata = domain == ATTR_DOMAIN_POINT ? &bm->vdata : &bm->ldata;
+
+ for (int i = 0; i < cdata->totlayer; i++) {
+ if (STREQ(cdata->layers[i].name, layer->name)) {
+ cd_offset = layer->offset;
+ }
}
- int j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
+ BLI_assert(cd_offset != -1);
- if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
- if constexpr (domain == ATTR_DOMAIN_CORNER) {
- color_layer[mp->loopstart + j] = paintcol;
- }
- else {
- color_layer[vidx] = paintcol;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ Color *color;
+ BMLoop *l = f->l_first;
+
+ do {
+ if (!(use_vert_sel && !(BM_elem_flag_test(l->v, BM_ELEM_SELECT)))) {
+ if constexpr (domain == ATTR_DOMAIN_CORNER) {
+ color = static_cast<Color *>(BM_ELEM_CD_GET_VOID_P(l, cd_offset));
+ }
+ else {
+ color = static_cast<Color *>(BM_ELEM_CD_GET_VOID_P(l->v, cd_offset));
+ }
+
+ *color = paintcol;
}
- }
- j++;
- } while (j < mp->totloop);
+ } while ((l = l->next) != f->l_first);
+ }
}
+ else {
+ Color *color_layer = static_cast<Color *>(layer->data);
+
+ const MPoly *mp = me->mpoly;
+ for (int i = 0; i < me->totpoly; i++, mp++) {
+ if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
+ continue;
+ }
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
+ int j = 0;
+ do {
+ uint vidx = me->mloop[mp->loopstart + j].v;
+
+ if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
+ if constexpr (domain == ATTR_DOMAIN_CORNER) {
+ color_layer[mp->loopstart + j] = paintcol;
+ }
+ else {
+ color_layer[vidx] = paintcol;
+ }
+ }
+ j++;
+ } while (j < mp->totloop);
+ }
+
+ /* remove stale me->mcol, will be added later */
+ BKE_mesh_tessface_clear(me);
+ }
DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
@@ -4164,26 +4140,22 @@ static bool paint_object_attributes_active_color_fill_ex(Object *ob,
me->editflag &= ~ME_EDIT_PAINT_FACE_SEL;
me->editflag &= ~ME_EDIT_PAINT_VERT_SEL;
}
- AttributeDomain domain = BKE_id_attribute_domain(&me->id, layer);
+ eAttrDomain domain = BKE_id_attribute_domain(&me->id, layer);
bool ok = false;
if (domain == ATTR_DOMAIN_POINT) {
if (layer->type == CD_PROP_COLOR) {
- ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(
- ob, fill_color, static_cast<ColorPaint4f *>(layer->data));
+ ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_POINT>(ob, fill_color, layer);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
- ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(
- ob, fill_color, static_cast<ColorPaint4b *>(layer->data));
+ ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_POINT>(ob, fill_color, layer);
}
}
else {
if (layer->type == CD_PROP_COLOR) {
- ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(
- ob, fill_color, static_cast<ColorPaint4f *>(layer->data));
+ ok = vertex_color_set<ColorPaint4f, FloatTraits, ATTR_DOMAIN_CORNER>(ob, fill_color, layer);
}
else if (layer->type == CD_PROP_BYTE_COLOR) {
- ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(
- ob, fill_color, static_cast<ColorPaint4b *>(layer->data));
+ ok = vertex_color_set<ColorPaint4b, ByteTraits, ATTR_DOMAIN_CORNER>(ob, fill_color, layer);
}
}
/* Restore #Mesh.editflag. */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
deleted file mode 100644
index a2e1adff50a..00000000000
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ /dev/null
@@ -1,485 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup edsculpt
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_math_base.h"
-#include "BLI_math_color.h"
-
-#include "BKE_context.h"
-#include "BKE_deform.h"
-#include "BKE_mesh.h"
-
-#include "DEG_depsgraph.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_mesh.h"
-
-#include "paint_intern.h" /* own include */
-
-/* -------------------------------------------------------------------- */
-/** \name Internal Utility Functions
- * \{ */
-
-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 && (ELEM(ob->mode, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT))) &&
- (me && me->totpoly && me->dvert);
-}
-
-static void tag_object_after_update(Object *object)
-{
- BLI_assert(object->type == OB_MESH);
- Mesh *mesh = object->data;
- DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE);
- /* NOTE: Original mesh is used for display, so tag it directly here. */
- BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Vertex Color from Weight Operator
- * \{ */
-
-static bool vertex_paint_from_weight(Object *ob)
-{
- Mesh *me;
- const MPoly *mp;
- int vgroup_active;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL || (ED_mesh_color_ensure(me, NULL)) == false)) {
- return false;
- }
-
- /* TODO: respect selection. */
- /* TODO: Do we want to take weights from evaluated mesh instead? 2.7x was not doing it anyway. */
- mp = me->mpoly;
- vgroup_active = me->vertex_group_active_index - 1;
- for (int i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = &me->mloopcol[mp->loopstart];
- uint j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- const float weight = BKE_defvert_find_weight(&me->dvert[vidx], vgroup_active);
- const uchar grayscale = weight * 255;
- lcol->r = grayscale;
- lcol->b = grayscale;
- lcol->g = grayscale;
- lcol++;
- j++;
- } while (j < mp->totloop);
- }
-
- tag_object_after_update(ob);
-
- return true;
-}
-
-static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obact = CTX_data_active_object(C);
- if (vertex_paint_from_weight(obact)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Color from Weight";
- ot->idname = "PAINT_OT_vertex_color_from_weight";
- ot->description = "Convert active weight into gray scale vertex colors";
-
- /* api callback */
- ot->exec = vertex_paint_from_weight_exec;
- ot->poll = vertex_weight_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* TODO: invert, alpha */
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Smooth Vertex Colors Operator
- * \{ */
-
-static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag)
-{
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const MPoly *mp;
- int(*scol)[4];
- bool has_shared = false;
-
- if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) {
- return;
- }
-
- scol = MEM_callocN(sizeof(int) * me->totvert * 5, "scol");
-
- int i;
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- const MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (int j = 0; j < mp->totloop; j++, ml++, lcol++) {
- scol[ml->v][0] += lcol->r;
- scol[ml->v][1] += lcol->g;
- scol[ml->v][2] += lcol->b;
- scol[ml->v][3] += 1;
- has_shared = 1;
- }
- }
- }
-
- if (has_shared) {
- for (i = 0; i < me->totvert; i++) {
- if (scol[i][3] != 0) {
- scol[i][0] = divide_round_i(scol[i][0], scol[i][3]);
- scol[i][1] = divide_round_i(scol[i][1], scol[i][3]);
- scol[i][2] = divide_round_i(scol[i][2], scol[i][3]);
- }
- }
-
- for (i = 0, mp = me->mpoly; i < me->totpoly; i++, mp++) {
- if ((use_face_sel == false) || (mp->flag & ME_FACE_SEL)) {
- const MLoop *ml = me->mloop + mp->loopstart;
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
- for (int j = 0; j < mp->totloop; j++, ml++, lcol++) {
- if (mlooptag[mp->loopstart + j]) {
- lcol->r = scol[ml->v][0];
- lcol->g = scol[ml->v][1];
- lcol->b = scol[ml->v][2];
- }
- }
- }
- }
- }
-
- MEM_freeN(scol);
-}
-
-static bool vertex_color_smooth(Object *ob)
-{
- Mesh *me;
- const MPoly *mp;
- int i, j;
-
- bool *mlooptag;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
- return false;
- }
-
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- mlooptag = MEM_callocN(sizeof(bool) * me->totloop, "VPaintData mlooptag");
-
- /* simply tag loops of selected faces */
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- const MLoop *ml = me->mloop + mp->loopstart;
-
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- j = 0;
- do {
- if (!(use_vert_sel && !(me->mvert[ml->v].flag & SELECT))) {
- mlooptag[mp->loopstart + j] = true;
- }
- ml++;
- j++;
- } while (j < mp->totloop);
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
-
- vertex_color_smooth_looptag(me, mlooptag);
-
- MEM_freeN(mlooptag);
-
- tag_object_after_update(ob);
-
- return true;
-}
-
-static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obact = CTX_data_active_object(C);
- if (vertex_color_smooth(obact)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Smooth Vertex Colors";
- ot->idname = "PAINT_OT_vertex_color_smooth";
- ot->description = "Smooth colors across vertices";
-
- /* api callbacks */
- ot->exec = vertex_color_smooth_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Vertex Color Transformation Operators
- * \{ */
-
-struct VPaintTx_BrightContrastData {
- /* pre-calculated */
- float gain;
- float offset;
-};
-
-static void vpaint_tx_brightness_contrast(const float col[3],
- const void *user_data,
- float r_col[3])
-{
- const struct VPaintTx_BrightContrastData *data = user_data;
-
- for (int i = 0; i < 3; i++) {
- r_col[i] = data->gain * col[i] + data->offset;
- }
-}
-
-static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
-{
- Object *obact = CTX_data_active_object(C);
-
- float gain, offset;
- {
- float brightness = RNA_float_get(op->ptr, "brightness");
- float contrast = RNA_float_get(op->ptr, "contrast");
- brightness /= 100.0f;
- float delta = contrast / 200.0f;
- /*
- * The algorithm is by Werner D. Streidt
- * (http://visca.com/ffactory/archives/5-99/msg00021.html)
- * Extracted of OpenCV demhist.c
- */
- if (contrast > 0) {
- gain = 1.0f - delta * 2.0f;
- gain = 1.0f / max_ff(gain, FLT_EPSILON);
- offset = gain * (brightness - delta);
- }
- else {
- delta *= -1;
- gain = max_ff(1.0f - delta * 2.0f, 0.0f);
- offset = gain * brightness + delta;
- }
- }
-
- const struct VPaintTx_BrightContrastData user_data = {
- .gain = gain,
- .offset = offset,
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Vertex Paint Brightness/Contrast";
- ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
- ot->description = "Adjust vertex color brightness/contrast";
-
- /* api callbacks */
- ot->exec = vertex_color_brightness_contrast_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* params */
- const float min = -100, max = +100;
- prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
- prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
- RNA_def_property_ui_range(prop, min, max, 1, 1);
-}
-
-struct VPaintTx_HueSatData {
- float hue;
- float sat;
- float val;
-};
-
-static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3])
-{
- const struct VPaintTx_HueSatData *data = user_data;
- float hsv[3];
- rgb_to_hsv_v(col, hsv);
-
- hsv[0] += (data->hue - 0.5f);
- if (hsv[0] > 1.0f) {
- hsv[0] -= 1.0f;
- }
- else if (hsv[0] < 0.0f) {
- hsv[0] += 1.0f;
- }
- hsv[1] *= data->sat;
- hsv[2] *= data->val;
-
- hsv_to_rgb_v(hsv, r_col);
-}
-
-static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
-{
- Object *obact = CTX_data_active_object(C);
-
- const struct VPaintTx_HueSatData user_data = {
- .hue = RNA_float_get(op->ptr, "h"),
- .sat = RNA_float_get(op->ptr, "s"),
- .val = RNA_float_get(op->ptr, "v"),
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Paint Hue Saturation Value";
- ot->idname = "PAINT_OT_vertex_color_hsv";
- ot->description = "Adjust vertex color HSV values";
-
- /* api callbacks */
- ot->exec = vertex_color_hsv_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* params */
- RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
- RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
- RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
-}
-
-static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3])
-{
- for (int i = 0; i < 3; i++) {
- r_col[i] = 1.0f - col[i];
- }
-}
-
-static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obact = CTX_data_active_object(C);
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Paint Invert";
- ot->idname = "PAINT_OT_vertex_color_invert";
- ot->description = "Invert RGB values";
-
- /* api callbacks */
- ot->exec = vertex_color_invert_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-struct VPaintTx_LevelsData {
- float gain;
- float offset;
-};
-
-static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3])
-{
- const struct VPaintTx_LevelsData *data = user_data;
- for (int i = 0; i < 3; i++) {
- r_col[i] = data->gain * (col[i] + data->offset);
- }
-}
-
-static int vertex_color_levels_exec(bContext *C, wmOperator *op)
-{
- Object *obact = CTX_data_active_object(C);
-
- const struct VPaintTx_LevelsData user_data = {
- .gain = RNA_float_get(op->ptr, "gain"),
- .offset = RNA_float_get(op->ptr, "offset"),
- };
-
- if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) {
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Paint Levels";
- ot->idname = "PAINT_OT_vertex_color_levels";
- ot->description = "Adjust levels of vertex colors";
-
- /* api callbacks */
- ot->exec = vertex_color_levels_exec;
- ot->poll = vertex_paint_mode_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* params */
- RNA_def_float(
- ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
- RNA_def_float(
- ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
-}
-
-/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
new file mode 100644
index 00000000000..8b726c7b942
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc
@@ -0,0 +1,514 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_array.hh"
+#include "BLI_index_mask_ops.hh"
+#include "BLI_math_base.h"
+#include "BLI_math_color.h"
+#include "BLI_vector.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_geometry_set.hh"
+#include "BKE_mesh.h"
+
+#include "DEG_depsgraph.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+
+#include "paint_intern.h" /* own include */
+
+using blender::Array;
+using blender::ColorGeometry4f;
+using blender::GMutableSpan;
+using blender::IndexMask;
+using blender::Vector;
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utility Functions
+ * \{ */
+
+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 && (ELEM(ob->mode, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT))) &&
+ (me && me->totpoly && me->dvert);
+}
+
+static void tag_object_after_update(Object *object)
+{
+ BLI_assert(object->type == OB_MESH);
+ Mesh *mesh = static_cast<Mesh *>(object->data);
+ DEG_id_tag_update(&mesh->id, ID_RECALC_COPY_ON_WRITE);
+ /* NOTE: Original mesh is used for display, so tag it directly here. */
+ BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex Color from Weight Operator
+ * \{ */
+
+static bool vertex_paint_from_weight(Object *ob)
+{
+ using namespace blender;
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(ob)) == nullptr ||
+ (ED_mesh_color_ensure(me, nullptr)) == false)) {
+ return false;
+ }
+
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me->id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ const int active_vertex_group_index = me->vertex_group_active_index - 1;
+ const bDeformGroup *deform_group = static_cast<const bDeformGroup *>(
+ BLI_findlink(&me->vertex_group_names, active_vertex_group_index));
+ if (deform_group == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*me);
+
+ bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
+ if (!color_attribute) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ /* Retrieve the vertex group with the domain and type of the existing color
+ * attribute, in order to let the attribute API handle both conversions. */
+ const GVArray vertex_group = attributes.lookup(
+ deform_group->name,
+ ATTR_DOMAIN_POINT,
+ bke::cpp_type_to_custom_data_type(color_attribute.varray.type()));
+ if (!vertex_group) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ GVArraySpan interpolated{
+ attributes.adapt_domain(vertex_group, ATTR_DOMAIN_POINT, color_attribute.domain)};
+
+ color_attribute.varray.set_all(interpolated.data());
+ color_attribute.finish();
+ tag_object_after_update(ob);
+
+ return true;
+}
+
+static int vertex_paint_from_weight_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+ if (vertex_paint_from_weight(obact)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void PAINT_OT_vertex_color_from_weight(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Color from Weight";
+ ot->idname = "PAINT_OT_vertex_color_from_weight";
+ ot->description = "Convert active weight into gray scale vertex colors";
+
+ /* api callback */
+ ot->exec = vertex_paint_from_weight_exec;
+ ot->poll = vertex_weight_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* TODO: invert, alpha */
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Vertex Colors Operator
+ * \{ */
+
+static IndexMask get_selected_indices(const Mesh &mesh,
+ const eAttrDomain domain,
+ Vector<int64_t> &indices)
+{
+ using namespace blender;
+ Span<MVert> verts(mesh.mvert, mesh.totvert);
+ Span<MPoly> faces(mesh.mpoly, mesh.totpoly);
+
+ bke::AttributeAccessor attributes = bke::mesh_attributes(mesh);
+
+ if (mesh.editflag & ME_EDIT_PAINT_FACE_SEL) {
+ const VArray<bool> selection = attributes.adapt_domain(
+ VArray<bool>::ForFunc(faces.size(),
+ [&](const int i) { return faces[i].flag & ME_FACE_SEL; }),
+ ATTR_DOMAIN_FACE,
+ domain);
+
+ return index_mask_ops::find_indices_from_virtual_array(
+ IndexMask(attributes.domain_size(domain)), selection, 4096, indices);
+ }
+ if (mesh.editflag & ME_EDIT_PAINT_VERT_SEL) {
+ const VArray<bool> selection = attributes.adapt_domain(
+ VArray<bool>::ForFunc(verts.size(), [&](const int i) { return verts[i].flag & SELECT; }),
+ ATTR_DOMAIN_POINT,
+ domain);
+
+ return index_mask_ops::find_indices_from_virtual_array(
+ IndexMask(attributes.domain_size(domain)), selection, 4096, indices);
+ }
+ return IndexMask(attributes.domain_size(domain));
+}
+
+static void face_corner_color_equalize_vertices(Mesh &mesh, const IndexMask selection)
+{
+ using namespace blender;
+
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
+ return;
+ }
+
+ bke::AttributeAccessor attributes = bke::mesh_attributes(mesh);
+
+ if (attributes.lookup_meta_data(active_color_layer->name)->domain == ATTR_DOMAIN_POINT) {
+ return;
+ }
+
+ GVArray color_attribute_point = attributes.lookup(active_color_layer->name, ATTR_DOMAIN_POINT);
+
+ GVArray color_attribute_corner = attributes.adapt_domain(
+ color_attribute_point, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER);
+
+ color_attribute_corner.materialize(selection, active_color_layer->data);
+}
+
+static bool vertex_color_smooth(Object *ob)
+{
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(ob)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return false;
+ }
+
+ Vector<int64_t> indices;
+ const IndexMask selection = get_selected_indices(*me, ATTR_DOMAIN_CORNER, indices);
+
+ face_corner_color_equalize_vertices(*me, selection);
+
+ tag_object_after_update(ob);
+
+ return true;
+}
+
+static int vertex_color_smooth_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+ if (vertex_color_smooth(obact)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void PAINT_OT_vertex_color_smooth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Smooth Vertex Colors";
+ ot->idname = "PAINT_OT_vertex_color_smooth";
+ ot->description = "Smooth colors across vertices";
+
+ /* api callbacks */
+ ot->exec = vertex_color_smooth_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Vertex Color Transformation Operators
+ * \{ */
+
+template<typename TransformFn>
+static bool transform_active_color(Mesh &mesh, const TransformFn &transform_fn)
+{
+ using namespace blender;
+
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&mesh.id);
+ if (active_color_layer == nullptr) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(mesh);
+
+ bke::GAttributeWriter color_attribute = attributes.lookup_for_write(active_color_layer->name);
+ if (!color_attribute) {
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ Vector<int64_t> indices;
+ const IndexMask selection = get_selected_indices(mesh, color_attribute.domain, indices);
+
+ attribute_math::convert_to_static_type(color_attribute.varray.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for ([[maybe_unused]] const int i : selection.slice(range)) {
+ if constexpr (std::is_same_v<T, ColorGeometry4f>) {
+ ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4f>(i);
+ transform_fn(color);
+ color_attribute.varray.set_by_copy(i, &color);
+ }
+ else if constexpr (std::is_same_v<T, ColorGeometry4b>) {
+ ColorGeometry4f color = color_attribute.varray.get<ColorGeometry4b>(i).decode();
+ transform_fn(color);
+ ColorGeometry4b color_encoded = color.encode();
+ color_attribute.varray.set_by_copy(i, &color_encoded);
+ }
+ }
+ });
+ });
+
+ color_attribute.finish();
+
+ DEG_id_tag_update(&mesh.id, 0);
+
+ return true;
+}
+
+static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ float gain, offset;
+ {
+ float brightness = RNA_float_get(op->ptr, "brightness");
+ float contrast = RNA_float_get(op->ptr, "contrast");
+ brightness /= 100.0f;
+ float delta = contrast / 200.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if (contrast > 0) {
+ gain = 1.0f - delta * 2.0f;
+ gain = 1.0f / max_ff(gain, FLT_EPSILON);
+ offset = gain * (brightness - delta);
+ }
+ else {
+ delta *= -1;
+ gain = max_ff(1.0f - delta * 2.0f, 0.0f);
+ offset = gain * brightness + delta;
+ }
+ }
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = gain * color[i] + offset;
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Vertex Paint Brightness/Contrast";
+ ot->idname = "PAINT_OT_vertex_color_brightness_contrast";
+ ot->description = "Adjust vertex color brightness/contrast";
+
+ /* api callbacks */
+ ot->exec = vertex_color_brightness_contrast_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ const float min = -100, max = +100;
+ prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
+ prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
+ RNA_def_property_ui_range(prop, min, max, 1, 1);
+}
+
+static int vertex_color_hsv_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const float hue = RNA_float_get(op->ptr, "h");
+ const float sat = RNA_float_get(op->ptr, "s");
+ const float val = RNA_float_get(op->ptr, "v");
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ float hsv[3];
+ rgb_to_hsv_v(color, hsv);
+
+ hsv[0] += (hue - 0.5f);
+ if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+ else if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ hsv[1] *= sat;
+ hsv[2] *= val;
+
+ hsv_to_rgb_v(hsv, color);
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_hsv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Hue Saturation Value";
+ ot->idname = "PAINT_OT_vertex_color_hsv";
+ ot->description = "Adjust vertex color HSV values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_hsv_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
+ RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
+ RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
+}
+
+static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obact = CTX_data_active_object(C);
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = 1.0f - color[i];
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_invert(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Invert";
+ ot->idname = "PAINT_OT_vertex_color_invert";
+ ot->description = "Invert RGB values";
+
+ /* api callbacks */
+ ot->exec = vertex_color_invert_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int vertex_color_levels_exec(bContext *C, wmOperator *op)
+{
+ Object *obact = CTX_data_active_object(C);
+
+ const float gain = RNA_float_get(op->ptr, "gain");
+ const float offset = RNA_float_get(op->ptr, "offset");
+
+ Mesh *me;
+ if (((me = BKE_mesh_from_object(obact)) == nullptr) ||
+ (ED_mesh_color_ensure(me, nullptr) == false)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ transform_active_color(*me, [&](ColorGeometry4f &color) {
+ for (int i = 0; i < 3; i++) {
+ color[i] = gain * (color[i] + offset);
+ }
+ });
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINT_OT_vertex_color_levels(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Paint Levels";
+ ot->idname = "PAINT_OT_vertex_color_levels";
+ ot->description = "Adjust levels of vertex colors";
+
+ /* api callbacks */
+ ot->exec = vertex_color_levels_exec;
+ ot->poll = vertex_paint_mode_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* params */
+ RNA_def_float(
+ ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
+ RNA_def_float(
+ ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
deleted file mode 100644
index cd099f71ccd..00000000000
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup edsculpt
- *
- * Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`.
- */
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-
-#include "BLI_math_base.h"
-#include "BLI_math_color.h"
-
-#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
-
-#include "BKE_context.h"
-#include "BKE_mesh.h"
-
-#include "DEG_depsgraph.h"
-
-#include "ED_mesh.h"
-
-#include "paint_intern.h" /* own include */
-
-#define EPS_SATURATION 0.0005f
-
-bool ED_vpaint_color_transform(struct Object *ob,
- VPaintTransform_Callback vpaint_tx_fn,
- const void *user_data)
-{
- Mesh *me;
- const MPoly *mp;
- int i, j;
-
- if (((me = BKE_mesh_from_object(ob)) == NULL) || (ED_mesh_color_ensure(me, NULL) == false)) {
- return false;
- }
-
- const bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
- const bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
-
- mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
- MLoopCol *lcol = me->mloopcol + mp->loopstart;
-
- if (use_face_sel && !(mp->flag & ME_FACE_SEL)) {
- continue;
- }
-
- j = 0;
- do {
- uint vidx = me->mloop[mp->loopstart + j].v;
- if (!(use_vert_sel && !(me->mvert[vidx].flag & SELECT))) {
- float col_mix[3];
- rgb_uchar_to_float(col_mix, &lcol->r);
-
- vpaint_tx_fn(col_mix, user_data, col_mix);
-
- rgb_float_to_uchar(&lcol->r, col_mix);
- }
- lcol++;
- j++;
- } while (j < mp->totloop);
- }
-
- /* remove stale me->mcol, will be added later */
- BKE_mesh_tessface_clear(me);
-
- DEG_id_tag_update(&me->id, 0);
-
- return true;
-}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 5bb4eb7cebf..2951706ebd8 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -148,7 +148,7 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
bool SCULPT_has_loop_colors(const Object *ob)
{
Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id);
return layer && BKE_id_attribute_domain(&me->id, layer) == ATTR_DOMAIN_CORNER;
}
@@ -1181,6 +1181,12 @@ void SCULPT_floodfill_free(SculptFloodFill *flood)
/** \} */
+static bool sculpt_tool_has_cube_tip(const char sculpt_tool)
+{
+ return ELEM(
+ sculpt_tool, SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_PAINT, SCULPT_TOOL_MULTIPLANE_SCRAPE);
+}
+
/* -------------------------------------------------------------------- */
/** \name Tool Capabilities
*
@@ -1282,10 +1288,13 @@ void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, Object *ob, Scul
}
}
-void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node)
+void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
+ Object *ob,
+ PBVHNode *node,
+ SculptUndoType type)
{
SculptUndoNode *unode;
- unode = SCULPT_undo_push_node(ob, node, SCULPT_UNDO_COORDS);
+ unode = SCULPT_undo_push_node(ob, node, type);
SCULPT_orig_vert_data_unode_init(data, ob, unode);
}
@@ -1354,14 +1363,29 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
SculptUndoNode *unode;
- SculptUndoType type = (data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
- SCULPT_UNDO_COORDS);
+ SculptUndoType type;
+
+ switch (data->brush->sculpt_tool) {
+ case SCULPT_TOOL_MASK:
+ type = SCULPT_UNDO_MASK;
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
+ break;
+ case SCULPT_TOOL_PAINT:
+ case SCULPT_TOOL_SMEAR:
+ type = SCULPT_UNDO_COLOR;
+ BKE_pbvh_node_mark_update_color(data->nodes[n]);
+ break;
+ default:
+ type = SCULPT_UNDO_COORDS;
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+ break;
+ }
if (ss->bm) {
unode = SCULPT_undo_push_node(data->ob, data->nodes[n], type);
}
else {
- unode = SCULPT_undo_get_node(data->nodes[n]);
+ unode = SCULPT_undo_get_node(data->nodes[n], type);
}
if (!unode) {
@@ -1397,8 +1421,6 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
}
}
BKE_pbvh_vertex_iter_end;
-
- BKE_pbvh_node_mark_update(data->nodes[n]);
}
static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
@@ -1610,7 +1632,7 @@ bool SCULPT_brush_test_cube(SculptBrushTest *test,
const float local[4][4],
const float roundness)
{
- float side = M_SQRT1_2;
+ float side = 1.0f;
float local_co[3];
if (sculpt_brush_test_clipping(test, co)) {
@@ -2362,7 +2384,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
/* Get strength by feeding the vertex location directly into a texture. */
avg = BKE_brush_sample_tex_3d(scene, br, point, rgba, 0, ss->tex_pool);
}
- else if (ss->texcache) {
+ else {
float symm_point[3], point_2d[2];
/* Quite warnings. */
float x = 0.0f, y = 0.0f;
@@ -3097,7 +3119,7 @@ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
for (a = 0; a < me->totvert; a++, mvert++) {
copy_v3_v3(mvert->co, vertCos[a]);
}
- BKE_mesh_normals_tag_dirty(me);
+ BKE_mesh_tag_coords_changed(me);
}
/* Apply new coords on active key block, no need to re-allocate kb->data here! */
@@ -3183,24 +3205,29 @@ static void do_brush_action_task_cb(void *__restrict userdata,
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ bool need_coords = ss->cache->supports_gravity;
+
/* Face Sets modifications do a single undo push */
if (data->brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) {
BKE_pbvh_node_mark_redraw(data->nodes[n]);
/* Draw face sets in smooth mode moves the vertices. */
if (ss->cache->alt_smooth) {
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(data->nodes[n]);
+ need_coords = true;
}
}
else if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) {
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
BKE_pbvh_node_mark_update_mask(data->nodes[n]);
}
- else if (SCULPT_TOOL_NEEDS_COLOR(data->brush->sculpt_tool)) {
+ else if (SCULPT_tool_is_paint(data->brush->sculpt_tool)) {
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
BKE_pbvh_node_mark_update_color(data->nodes[n]);
}
else {
+ need_coords = true;
+ }
+
+ if (need_coords) {
SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_node_mark_update(data->nodes[n]);
}
@@ -3219,7 +3246,7 @@ static void do_brush_action(Sculpt *sd,
/* Check for unsupported features. */
PBVHType type = BKE_pbvh_type(ss->pbvh);
- if (SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool) && SCULPT_has_loop_colors(ob)) {
+ if (SCULPT_tool_is_paint(brush->sculpt_tool) && SCULPT_has_loop_colors(ob)) {
if (type != PBVH_FACES) {
return;
}
@@ -3241,6 +3268,11 @@ static void do_brush_action(Sculpt *sd,
ss->cache->original;
float radius_scale = 1.0f;
+ /* Corners of square brushes can go outside the brush radius. */
+ if (sculpt_tool_has_cube_tip(brush->sculpt_tool)) {
+ radius_scale = M_SQRT2;
+ }
+
/* With these options enabled not all required nodes are inside the original brush radius, so
* the brush can produce artifacts in some situations. */
if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) {
@@ -3522,15 +3554,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
Object *ob = data->ob;
-
- /* These brushes start from original coordinates. */
- const bool use_orco = ELEM(data->brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM,
- SCULPT_TOOL_BOUNDARY,
- SCULPT_TOOL_POSE);
+ const bool use_orco = data->use_proxies_orco;
PBVHVertexIter vd;
PBVHProxyNode *proxies;
@@ -3585,17 +3609,49 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
return;
}
+ /* First line is tools that don't support proxies. */
+ const bool use_orco = ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_BOUNDARY,
+ SCULPT_TOOL_POSE);
+
BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
+ .use_proxies_orco = use_orco,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+ MEM_SAFE_FREE(nodes);
+}
+
+void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .use_proxies_orco = false,
};
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+
MEM_SAFE_FREE(nodes);
}
@@ -3889,27 +3945,6 @@ static void do_symmetrical_brush_actions(Sculpt *sd,
}
}
-static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- const int radius = BKE_brush_size_get(scene, brush);
-
- MEM_SAFE_FREE(ss->texcache);
-
- if (ss->tex_pool) {
- BKE_image_pool_free(ss->tex_pool);
- ss->tex_pool = NULL;
- }
-
- /* Need to allocate a bigger buffer for bigger brush size. */
- ss->texcache_side = 2 * radius;
- if (!ss->texcache || ss->texcache_side > ss->texcache_actual) {
- ss->texcache = BKE_brush_gen_texture_cache(brush, radius, false);
- ss->texcache_actual = ss->texcache_side;
- ss->tex_pool = BKE_image_pool_new();
- }
-}
-
bool SCULPT_mode_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -4137,7 +4172,7 @@ static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache
/* Initialize the stroke cache invariants from operator properties. */
static void sculpt_update_cache_invariants(
- bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2])
+ bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mval[2])
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
@@ -4167,8 +4202,8 @@ static void sculpt_update_cache_invariants(
sculpt_init_mirror_clipping(ob, ss);
/* Initial mouse location. */
- if (mouse) {
- copy_v2_v2(cache->initial_mouse, mouse);
+ if (mval) {
+ copy_v2_v2(cache->initial_mouse, mval);
}
else {
zero_v2(cache->initial_mouse);
@@ -4301,6 +4336,10 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
* generally used to create grab deformations. */
static bool sculpt_needs_delta_from_anchored_origin(Brush *brush)
{
+ if (brush->sculpt_tool == SCULPT_TOOL_SMEAR && (brush->flag & BRUSH_ANCHORED)) {
+ return true;
+ }
+
if (ELEM(brush->sculpt_tool,
SCULPT_TOOL_GRAB,
SCULPT_TOOL_POSE,
@@ -4336,7 +4375,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
{
SculptSession *ss = ob->sculpt;
StrokeCache *cache = ss->cache;
- const float mouse[2] = {
+ const float mval[2] = {
cache->mouse_event[0],
cache->mouse_event[1],
};
@@ -4355,6 +4394,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_POSE,
SCULPT_TOOL_BOUNDARY,
+ SCULPT_TOOL_SMEAR,
SCULPT_TOOL_THUMB) &&
!sculpt_brush_use_topology_rake(ss, brush)) {
return;
@@ -4376,9 +4416,9 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
add_v3_v3(cache->true_location, cache->grab_delta);
}
- /* Compute 3d coordinate at same z from original location + mouse. */
+ /* Compute 3d coordinate at same z from original location + mval. */
mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location);
- ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mouse, grab_location);
+ ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->region, loc, mval, grab_location);
/* Compute delta to move verts by. */
if (!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
@@ -4653,8 +4693,8 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd,
(brush->sculpt_tool == SCULPT_TOOL_POSE) ||
(brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) ||
(brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) ||
- SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool) ||
- (brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) ||
+ SCULPT_tool_is_paint(brush->sculpt_tool) || (brush->sculpt_tool == SCULPT_TOOL_CLOTH) ||
+ (brush->sculpt_tool == SCULPT_TOOL_SMEAR) ||
(brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) ||
(brush->sculpt_tool == SCULPT_TOOL_DISPLACEMENT_SMEAR) ||
(brush->sculpt_tool == SCULPT_TOOL_PAINT));
@@ -4670,7 +4710,8 @@ void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *b
if (ss->shapekey_active || ss->deform_modifiers_active ||
(!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false, false);
+ BKE_sculpt_update_object_for_edit(
+ depsgraph, ob, need_pmap, false, SCULPT_tool_is_paint(brush->sculpt_tool));
}
}
@@ -4689,7 +4730,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
}
else {
/* Intersect with coordinates from before we started stroke. */
- SculptUndoNode *unode = SCULPT_undo_get_node(node);
+ SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS);
origco = (unode) ? unode->co : NULL;
use_origco = origco ? true : false;
}
@@ -4726,7 +4767,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
}
else {
/* Intersect with coordinates from before we started stroke. */
- SculptUndoNode *unode = SCULPT_undo_get_node(node);
+ SculptUndoNode *unode = SCULPT_undo_get_node(node, SCULPT_UNDO_COORDS);
origco = (unode) ? unode->co : NULL;
use_origco = origco ? true : false;
}
@@ -4746,7 +4787,7 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
}
float SCULPT_raycast_init(ViewContext *vc,
- const float mouse[2],
+ const float mval[2],
float ray_start[3],
float ray_end[3],
float ray_normal[3],
@@ -4760,7 +4801,7 @@ float SCULPT_raycast_init(ViewContext *vc,
/* TODO: what if the segment is totally clipped? (return == 0). */
ED_view3d_win_to_segment_clipped(
- vc->depsgraph, vc->region, vc->v3d, mouse, ray_start, ray_end, true);
+ vc->depsgraph, vc->region, vc->v3d, mval, ray_start, ray_end, true);
invert_m4_m4(obimat, ob->obmat);
mul_m4_v3(obimat, ray_start);
@@ -4784,7 +4825,7 @@ float SCULPT_raycast_init(ViewContext *vc,
bool SCULPT_cursor_geometry_info_update(bContext *C,
SculptCursorGeometryInfo *out,
- const float mouse[2],
+ const float mval[2],
bool use_sampled_normal)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -4813,7 +4854,7 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
}
/* PBVH raycast to get active vertex and face normal. */
- depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
SCULPT_stroke_modifiers_check(C, ob, brush);
SculptRaycastData srd = {
@@ -4911,7 +4952,10 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
return true;
}
-bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
+bool SCULPT_stroke_get_location(bContext *C,
+ float out[3],
+ const float mval[2],
+ bool force_original)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
@@ -4927,13 +4971,13 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
ss = ob->sculpt;
cache = ss->cache;
- original = (cache) ? cache->original : false;
+ original = force_original || ((cache) ? cache->original : false);
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
SCULPT_stroke_modifiers_check(C, ob, brush);
- depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = SCULPT_raycast_init(&vc, mval, ray_start, ray_end, ray_normal, original);
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
@@ -4990,7 +5034,7 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
return hit;
}
-static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession *ss)
+static void sculpt_brush_init_tex(Sculpt *sd, SculptSession *ss)
{
Brush *brush = BKE_paint_brush(&sd->paint);
MTex *mtex = &brush->mtex;
@@ -5001,16 +5045,16 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession
ntreeTexBeginExecTree(mtex->tex->nodetree);
}
- /* TODO: Shouldn't really have to do this at the start of every stroke, but sculpt would need
- * some sort of notification when changes are made to the texture. */
- sculpt_update_tex(scene, sd, ss);
+ if (ss->tex_pool == NULL) {
+ ss->tex_pool = BKE_image_pool_new();
+ }
}
static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ ToolSettings *tool_settings = CTX_data_tool_settings(C);
+ Sculpt *sd = tool_settings->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
int mode = RNA_enum_get(op->ptr, "mode");
@@ -5027,10 +5071,11 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
}
view3d_operator_needs_opengl(C);
- sculpt_brush_init_tex(scene, sd, ss);
+ sculpt_brush_init_tex(sd, ss);
need_pmap = sculpt_needs_connectivity_info(sd, brush, ss, mode);
- needs_colors = SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool);
+ needs_colors = SCULPT_tool_is_paint(brush->sculpt_tool) &&
+ !SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob);
if (needs_colors) {
BKE_sculpt_color_layer_create_if_needed(ob);
@@ -5039,7 +5084,8 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
/* CTX_data_ensure_evaluated_depsgraph should be used at the end to include the updates of
* earlier steps modifying the data. */
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, need_mask, needs_colors);
+ BKE_sculpt_update_object_for_edit(
+ depsgraph, ob, need_pmap, need_mask, SCULPT_tool_is_paint(brush->sculpt_tool));
ED_paint_tool_update_sticky_shading_color(C, ob);
}
@@ -5238,14 +5284,10 @@ void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType up
/* Returns whether the mouse/stylus is over the mesh (1)
* or over the background (0). */
-static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), float x, float y)
+static bool over_mesh(bContext *C, struct wmOperator *UNUSED(op), const float mval[2])
{
- float mouse[2], co[3];
-
- mouse[0] = x;
- mouse[1] = y;
-
- return SCULPT_stroke_get_location(C, co, mouse);
+ float co_dummy[3];
+ return SCULPT_stroke_get_location(C, co_dummy, mval, false);
}
bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
@@ -5266,14 +5308,13 @@ bool SCULPT_handles_colors_report(SculptSession *ss, ReportList *reports)
return false;
}
-static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
+static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const float mval[2])
{
- /* Don't start the stroke until mouse goes over the mesh.
- * NOTE: mouse will only be null when re-executing the saved stroke.
- * We have exception for 'exec' strokes since they may not set 'mouse',
+ /* Don't start the stroke until `mval` goes over the mesh.
+ * NOTE: `mval` will only be null when re-executing the saved stroke.
+ * We have exception for 'exec' strokes since they may not set `mval`,
* only 'location', see: T52195. */
- if (((op->flag & OP_IS_INVOKE) == 0) || (mouse == NULL) ||
- over_mesh(C, op, mouse[0], mouse[1])) {
+ if (((op->flag & OP_IS_INVOKE) == 0) || (mval == NULL) || over_mesh(C, op, mval)) {
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -5282,7 +5323,8 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* NOTE: This should be removed when paint mode is available. Paint mode can force based on the
* canvas it is painting on. (ref. use_sculpt_texture_paint). */
- if (brush && SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool)) {
+ if (brush && SCULPT_tool_is_paint(brush->sculpt_tool) &&
+ !SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
View3D *v3d = CTX_wm_view3d(C);
if (v3d->shading.type == OB_SOLID) {
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
@@ -5291,10 +5333,10 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
- sculpt_update_cache_invariants(C, sd, ss, op, mouse);
+ sculpt_update_cache_invariants(C, sd, ss, op, mval);
SculptCursorGeometryInfo sgi;
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval, false);
/* Setup the correct undo system. Image painting and sculpting are mutual exclusive.
* Color attributes are part of the sculpting undo system. */
@@ -5374,7 +5416,7 @@ static void sculpt_stroke_update_step(bContext *C,
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
}
- else if (ELEM(brush->sculpt_tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)) {
+ else if (SCULPT_tool_is_paint(brush->sculpt_tool)) {
if (SCULPT_use_image_paint_brush(&tool_settings->paint_mode, ob)) {
SCULPT_flush_update_step(C, SCULPT_UPDATE_IMAGE);
}
@@ -5460,14 +5502,27 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
struct PaintStroke *stroke;
int ignore_background_click;
int retval;
+ Object *ob = CTX_data_active_object(C);
+
+ /* Test that ob is visible; otherwise we won't be able to get evaluated data
+ * from the depsgraph. We do this here instead of SCULPT_mode_poll
+ * to avoid falling through to the translate operator in the
+ * global view3d keymap.
+ *
+ * Note: BKE_object_is_visible_in_viewport is not working here (it returns false
+ * if the object is in local view); instead, test for OB_HIDE_VIEWPORT directly.
+ */
+
+ if (ob->visibility_flag & OB_HIDE_VIEWPORT) {
+ return OPERATOR_CANCELLED;
+ }
sculpt_brush_stroke_init(C, op);
- Object *ob = CTX_data_active_object(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- if (SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool) &&
+ if (SCULPT_tool_is_paint(brush->sculpt_tool) &&
!SCULPT_handles_colors_report(ob->sculpt, op->reports)) {
return OPERATOR_CANCELLED;
}
@@ -5486,7 +5541,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->xy[0], event->xy[1])) {
+ if (ignore_background_click && !over_mesh(C, op, (const float[2]){UNPACK2(event->mval)})) {
paint_stroke_free(C, op, op->customdata);
return OPERATOR_PASS_THROUGH;
}
@@ -5746,7 +5801,8 @@ void SCULPT_connected_components_ensure(Object *ob)
{
SculptSession *ss = ob->sculpt;
- /* Topology IDs already initialized. They only need to be recalculated when the PBVH is rebuild.
+ /* Topology IDs already initialized. They only need to be recalculated when the PBVH is
+ * rebuild.
*/
if (ss->vertex_info.connected_component) {
return;
@@ -5810,7 +5866,8 @@ void SCULPT_fake_neighbors_ensure(Sculpt *sd, Object *ob, const float max_dist)
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);
- /* Fake neighbors were already initialized with the same distance, so no need to be recalculated.
+ /* Fake neighbors were already initialized with the same distance, so no need to be
+ * recalculated.
*/
if (ss->fake_neighbors.fake_neighbor_index &&
ss->fake_neighbors.current_max_distance == max_dist) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
index d7a2a18504c..bb101717c9b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_automasking.c
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc
@@ -9,6 +9,7 @@
#include "BLI_blenlib.h"
#include "BLI_hash.h"
+#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_task.h"
@@ -43,8 +44,10 @@
#include "bmesh.h"
-#include <math.h>
-#include <stdlib.h>
+#include <cmath>
+#include <cstdlib>
+
+using blender::IndexRange;
AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss)
{
@@ -54,7 +57,7 @@ AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss)
if (ss->filter_cache) {
return ss->filter_cache->automasking;
}
- return NULL;
+ return nullptr;
}
bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
@@ -167,18 +170,18 @@ static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
return false;
}
-typedef struct AutomaskFloodFillData {
+struct AutomaskFloodFillData {
float *automask_factor;
float radius;
bool use_radius;
float location[3];
char symm;
-} AutomaskFloodFillData;
+};
static bool automask_floodfill_cb(
SculptSession *ss, int from_v, int to_v, bool UNUSED(is_duplicate), void *userdata)
{
- AutomaskFloodFillData *data = userdata;
+ AutomaskFloodFillData *data = (AutomaskFloodFillData *)userdata;
data->automask_factor[to_v] = 1.0f;
data->automask_factor[from_v] = 1.0f;
@@ -194,11 +197,11 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
BLI_assert_msg(0, "Topology masking: pmap missing");
- return NULL;
+ return nullptr;
}
const int totvert = SCULPT_vertex_count_get(ss);
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
automask_factor[i] = 0.0f;
}
@@ -209,12 +212,13 @@ static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *au
const float radius = ss->cache ? ss->cache->radius : FLT_MAX;
SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius);
- AutomaskFloodFillData fdata = {
- .automask_factor = automask_factor,
- .radius = radius,
- .use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush),
- .symm = SCULPT_mesh_symmetry_xyz_get(ob),
- };
+ AutomaskFloodFillData fdata = {nullptr};
+
+ fdata.automask_factor = automask_factor;
+ fdata.radius = radius;
+ fdata.use_radius = ss->cache && sculpt_automasking_is_constrained_by_radius(brush);
+ fdata.symm = SCULPT_mesh_symmetry_xyz_get(ob);
+
copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
SCULPT_floodfill_free(&flood);
@@ -228,17 +232,17 @@ static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *a
Brush *brush = BKE_paint_brush(&sd->paint);
if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
- return NULL;
+ return nullptr;
}
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
BLI_assert_msg(0, "Face Sets automasking: pmap missing");
- return NULL;
+ return nullptr;
}
int tot_vert = SCULPT_vertex_count_get(ss);
int active_face_set = SCULPT_active_face_set_get(ss);
- for (int i = 0; i < tot_vert; i++) {
+ for (int i : IndexRange(tot_vert)) {
if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
automask_factor[i] *= 0.0f;
}
@@ -258,13 +262,13 @@ float *SCULPT_boundary_automasking_init(Object *ob,
if (!ss->pmap) {
BLI_assert_msg(0, "Boundary Edges masking: pmap missing");
- return NULL;
+ return nullptr;
}
const int totvert = SCULPT_vertex_count_get(ss);
- int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
+ int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor");
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
edge_distance[i] = EDGE_DISTANCE_INF;
switch (mode) {
case AUTOMASK_INIT_BOUNDARY_EDGES:
@@ -280,8 +284,8 @@ float *SCULPT_boundary_automasking_init(Object *ob,
}
}
- for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
- for (int i = 0; i < totvert; i++) {
+ for (int propagation_it : IndexRange(propagation_steps)) {
+ for (int i : IndexRange(totvert)) {
if (edge_distance[i] != EDGE_DISTANCE_INF) {
continue;
}
@@ -295,7 +299,7 @@ float *SCULPT_boundary_automasking_init(Object *ob,
}
}
- for (int i = 0; i < totvert; i++) {
+ for (int i : IndexRange(totvert)) {
if (edge_distance[i] == EDGE_DISTANCE_INF) {
continue;
}
@@ -323,10 +327,11 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
const int totvert = SCULPT_vertex_count_get(ss);
if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
- return NULL;
+ return nullptr;
}
- AutomaskingCache *automasking = MEM_callocN(sizeof(AutomaskingCache), "automasking cache");
+ AutomaskingCache *automasking = (AutomaskingCache *)MEM_callocN(sizeof(AutomaskingCache),
+ "automasking cache");
SCULPT_automasking_cache_settings_update(automasking, ss, sd, brush);
SCULPT_boundary_info_ensure(ob);
@@ -334,8 +339,8 @@ AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object
return automasking;
}
- automasking->factor = MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor");
- for (int i = 0; i < totvert; i++) {
+ automasking->factor = (float *)MEM_malloc_arrayN(totvert, sizeof(float), "automask_factor");
+ for (int i : IndexRange(totvert)) {
automasking->factor[i] = 1.0f;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 8bf09ce3d05..44e2dfae480 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -638,7 +638,7 @@ static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
@@ -692,7 +692,7 @@ static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
@@ -738,7 +738,7 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
@@ -784,7 +784,7 @@ static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
@@ -827,7 +827,7 @@ static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
float angle_factor = disp / ss->cache->radius;
@@ -881,7 +881,7 @@ static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
index 39544a41a87..cba97f9b968 100644
--- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
@@ -1330,7 +1330,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -1403,7 +1403,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -1477,7 +1477,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
@@ -1964,7 +1964,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
float(*proxy)[3];
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -2052,7 +2052,7 @@ static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -2163,7 +2163,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
float(*proxy)[3];
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -2247,7 +2247,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
SculptOrigVertData orig_data;
float(*proxy)[3];
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
@@ -2404,7 +2404,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index dcf90f9e819..9d231f2ccd2 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -1553,11 +1553,9 @@ static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent
const eSculptClothFilterType filter_type = RNA_enum_get(op->ptr, "type");
/* Update the active vertex */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
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 fe69cf6b84f..00503087e39 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -158,7 +158,7 @@ static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = {
{0, NULL, 0, NULL, NULL},
};
-static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
+static void sample_detail_voxel(bContext *C, ViewContext *vc, const int mval[2])
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = vc->obact;
@@ -169,8 +169,8 @@ static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
SCULPT_vertex_random_access_ensure(ss);
/* Update the active vertex. */
- const float mouse[2] = {mx, my};
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ const float mval_fl[2] = {UNPACK2(mval)};
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false);
/* Average the edge length of the connected edges to the active vertex. */
@@ -201,7 +201,7 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
}
}
-static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, int mx, int my)
+static void sample_detail_dyntopo(bContext *C, ViewContext *vc, const int mval[2])
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob = vc->obact;
@@ -209,9 +209,9 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region,
SCULPT_stroke_modifiers_check(C, ob, brush);
- const float mouse[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
+ const float mval_fl[2] = {UNPACK2(mval)};
float ray_start[3], ray_end[3], ray_normal[3];
- float depth = SCULPT_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false);
+ float depth = SCULPT_raycast_init(vc, mval_fl, ray_start, ray_end, ray_normal, false);
SculptDetailRaycastData srd;
srd.hit = 0;
@@ -228,14 +228,12 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region,
}
}
-static int sample_detail(bContext *C, int mx, int my, int mode)
+static int sample_detail(bContext *C, const int event_xy[2], int mode)
{
/* Find 3D view to pick from. */
bScreen *screen = CTX_wm_screen(C);
- 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;
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, event_xy);
+ ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, event_xy) : NULL;
if (region == NULL) {
return OPERATOR_CANCELLED;
}
@@ -260,6 +258,11 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
return OPERATOR_CANCELLED;
}
+ const int mval[2] = {
+ event_xy[0] - region->winrct.xmin,
+ event_xy[1] - region->winrct.ymin,
+ };
+
/* Pick sample detail. */
switch (mode) {
case SAMPLE_DETAIL_DYNTOPO:
@@ -268,7 +271,7 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
CTX_wm_region_set(C, prev_region);
return OPERATOR_CANCELLED;
}
- sample_detail_dyntopo(C, &vc, region, mx, my);
+ sample_detail_dyntopo(C, &vc, mval);
break;
case SAMPLE_DETAIL_VOXEL:
if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
@@ -276,7 +279,7 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
CTX_wm_region_set(C, prev_region);
return OPERATOR_CANCELLED;
}
- sample_detail_voxel(C, &vc, mx, my);
+ sample_detail_voxel(C, &vc, mval);
break;
}
@@ -292,7 +295,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
int ss_co[2];
RNA_int_get_array(op->ptr, "location", ss_co);
int mode = RNA_enum_get(op->ptr, "mode");
- return sample_detail(C, ss_co[0], ss_co[1], mode);
+ return sample_detail(C, ss_co, mode);
}
static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
@@ -308,12 +311,10 @@ 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->xy[0], event->xy[1]};
-
int mode = RNA_enum_get(op->ptr, "mode");
- sample_detail(C, ss_co[0], ss_co[1], mode);
+ sample_detail(C, event->xy, mode);
- RNA_int_set_array(op->ptr, "location", ss_co);
+ RNA_int_set_array(op->ptr, "location", event->xy);
WM_cursor_modal_restore(CTX_wm_window(C));
ED_workspace_status_text(C, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
@@ -657,11 +658,13 @@ static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmE
ED_region_tag_redraw(region);
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) {
- cd->sample_mode = true;
- }
- if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) {
- cd->sample_mode = false;
+ if (ELEM(event->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ if (event->val == KM_PRESS) {
+ cd->sample_mode = true;
+ }
+ else if (event->val == KM_RELEASE) {
+ cd->sample_mode = false;
+ }
}
/* Sample mode sets the detail size sampling the average edge length under the surface. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.c b/source/blender/editors/sculpt_paint/sculpt_expand.c
index 644f14905ba..9648f558049 100644
--- a/source/blender/editors/sculpt_paint/sculpt_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_expand.c
@@ -1450,13 +1450,11 @@ static void sculpt_expand_update_for_vertex(bContext *C, Object *ob, const int v
* Updates the #SculptSession cursor data and gets the active vertex
* if the cursor is over the mesh.
*/
-static int sculpt_expand_target_vertex_update_and_get(bContext *C,
- Object *ob,
- const float mouse[2])
+static int sculpt_expand_target_vertex_update_and_get(bContext *C, Object *ob, const float mval[2])
{
SculptSession *ss = ob->sculpt;
SculptCursorGeometryInfo sgi;
- if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ if (SCULPT_cursor_geometry_info_update(C, &sgi, mval, false)) {
return SCULPT_active_vertex_get(ss);
}
return SCULPT_EXPAND_VERTEX_NONE;
@@ -1588,16 +1586,16 @@ static void sculpt_expand_find_active_connected_components_from_vert(Object *ob,
static void sculpt_expand_set_initial_components_for_mouse(bContext *C,
Object *ob,
ExpandCache *expand_cache,
- const float mouse[2])
+ const float mval[2])
{
SculptSession *ss = ob->sculpt;
- int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse);
+ int initial_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval);
if (initial_vertex == SCULPT_EXPAND_VERTEX_NONE) {
/* Cursor not over the mesh, for creating valid initial falloffs, fallback to the last active
* vertex in the sculpt session. */
initial_vertex = SCULPT_active_vertex_get(ss);
}
- copy_v2_v2(ss->expand_cache->initial_mouse, mouse);
+ copy_v2_v2(ss->expand_cache->initial_mouse, mval);
expand_cache->initial_active_vertex = initial_vertex;
expand_cache->initial_active_face_set = SCULPT_active_face_set_get(ss);
@@ -1629,14 +1627,14 @@ static void sculpt_expand_move_propagation_origin(bContext *C,
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- const float mouse[2] = {event->mval[0], event->mval[1]};
+ const float mval_fl[2] = {UNPACK2(event->mval)};
float move_disp[2];
- sub_v2_v2v2(move_disp, mouse, expand_cache->initial_mouse_move);
+ sub_v2_v2v2(move_disp, mval_fl, expand_cache->initial_mouse_move);
- float new_mouse[2];
- add_v2_v2v2(new_mouse, move_disp, expand_cache->original_mouse_move);
+ float new_mval[2];
+ add_v2_v2v2(new_mval, move_disp, expand_cache->original_mouse_move);
- sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mouse);
+ sculpt_expand_set_initial_components_for_mouse(C, ob, expand_cache, new_mval);
sculpt_expand_falloff_factors_from_vertex_and_symm_create(
expand_cache,
sd,
@@ -1697,8 +1695,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
sculpt_expand_ensure_sculptsession_data(ob);
/* Update and get the active vertex (and face) from the cursor. */
- const float mouse[2] = {event->mval[0], event->mval[1]};
- const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mouse);
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ const int target_expand_vertex = sculpt_expand_target_vertex_update_and_get(C, ob, mval_fl);
/* Handle the modal keymap state changes. */
ExpandCache *expand_cache = ss->expand_cache;
@@ -1756,7 +1754,7 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
}
expand_cache->move = true;
expand_cache->move_original_falloff_type = expand_cache->falloff_type;
- copy_v2_v2(expand_cache->initial_mouse_move, mouse);
+ copy_v2_v2(expand_cache->initial_mouse_move, mval_fl);
copy_v2_v2(expand_cache->original_mouse_move, expand_cache->initial_mouse);
if (expand_cache->falloff_type == SCULPT_EXPAND_FALLOFF_GEODESIC &&
SCULPT_vertex_count_get(ss) > expand_cache->max_geodesic_move_preview) {
@@ -1866,10 +1864,8 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
/* Add new Face Sets IDs to the snapping gset if enabled. */
if (expand_cache->snap) {
const int active_face_set_id = sculpt_expand_active_face_set_id_get(ss, expand_cache);
- if (!BLI_gset_haskey(expand_cache->snap_enabled_face_sets,
- POINTER_FROM_INT(active_face_set_id))) {
- BLI_gset_add(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(active_face_set_id));
- }
+ /* The key may exist, in that case this does nothing. */
+ BLI_gset_add(expand_cache->snap_enabled_face_sets, POINTER_FROM_INT(active_face_set_id));
}
/* Update the sculpt data with the current state of the #ExpandCache. */
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index d03c5ecab4d..ce704e619ea 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -949,11 +949,9 @@ static int sculpt_face_sets_change_visibility_invoke(bContext *C,
/* Update the active vertex and Face Set using the cursor position to avoid relying on the paint
* cursor updates. */
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
return sculpt_face_sets_change_visibility_exec(C, op);
}
@@ -1401,8 +1399,8 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven
/* Update the current active Face Set and Vertex as the operator can be used directly from the
* tool without brush cursor. */
SculptCursorGeometryInfo sgi;
- const float mouse[2] = {event->mval[0], event->mval[1]};
- if (!SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
/* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.c b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
index 26d18823b37..a9186010a9f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.c
@@ -93,7 +93,7 @@ static void color_filter_task_cb(void *__restrict userdata,
const int mode = data->filter_type;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
@@ -339,11 +339,9 @@ static int sculpt_color_filter_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_automasking) {
/* Update the active face set manually as the paint cursor is not enabled when using the Mesh
* Filter Tool. */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
}
/* Disable for multires and dyntopo for now */
@@ -378,7 +376,7 @@ void SCULPT_OT_color_filter(struct wmOperatorType *ot)
/* identifiers */
ot->name = "Filter Color";
ot->idname = "SCULPT_OT_color_filter";
- ot->description = "Applies a filter to modify the current sculpt vertex colors";
+ ot->description = "Applies a filter to modify the active color attribute";
/* api callbacks */
ot->invoke = sculpt_color_filter_invoke;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index a32b1c3015b..c0adf5aef20 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -281,7 +281,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
const eSculptMeshFilterType filter_type = data->filter_type;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS);
/* When using the relax face sets meshes filter,
* each 3 iterations, do a whole mesh relax to smooth the contents of the Face Set. */
@@ -675,11 +675,9 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
if (use_automasking) {
/* Update the active face set manually as the paint cursor is not enabled when using the Mesh
* Filter Tool. */
- float mouse[2];
+ float mval_fl[2] = {UNPACK2(event->mval)};
SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
}
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 5fa115ed629..83526006d7d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -247,6 +247,10 @@ typedef struct SculptThreadedTaskData {
float (*mat)[4];
float (*vertCos)[3];
+ /* When true, the displacement stored in the proxies will be applied to the original coordinates
+ * instead of to the current coordinates. */
+ bool use_proxies_orco;
+
/* X and Z vectors aligned to the stroke direction for operations where perpendicular vectors to
* the stroke direction are needed. */
float (*stroke_xz)[3];
@@ -290,6 +294,10 @@ typedef struct SculptThreadedTaskData {
bool mask_expand_create_face_set;
float transform_mats[8][4][4];
+ float elastic_transform_mat[4][4];
+ float elastic_transform_pivot[3];
+ float elastic_transform_pivot_init[3];
+ float elastic_transform_radius;
/* Boundary brush */
float boundary_deform_strength;
@@ -372,6 +380,14 @@ typedef enum SculptFilterOrientation {
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;
+
#define SCULPT_CLAY_STABILIZER_LEN 10
typedef struct AutomaskingSettings {
@@ -440,6 +456,8 @@ typedef struct FilterCache {
int active_face_set;
+ SculptTransformDisplacementMode transform_displacement_mode;
+
/* Auto-masking. */
AutomaskingCache *automasking;
@@ -827,7 +845,10 @@ void SCULPT_tag_update_overlays(bContext *C);
* (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]);
+bool SCULPT_stroke_get_location(struct bContext *C,
+ float out[3],
+ const float mouse[2],
+ bool force_original);
/**
* 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
@@ -840,7 +861,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss,
void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
float SCULPT_raycast_init(struct ViewContext *vc,
- const float mouse[2],
+ const float mval[2],
float ray_start[3],
float ray_end[3],
float ray_normal[3],
@@ -1011,7 +1032,10 @@ void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
* 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);
+void SCULPT_orig_vert_data_init(SculptOrigVertData *data,
+ Object *ob,
+ PBVHNode *node,
+ SculptUndoType type);
/**
* Update a #SculptOrigVertData for a particular vertex from the PBVH iterator.
*/
@@ -1137,12 +1161,15 @@ bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v);
*/
bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v);
+void SCULPT_combine_transform_proxies(Sculpt *sd, Object *ob);
+
/**
* 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);
@@ -1446,7 +1473,7 @@ void SCULPT_cache_free(StrokeCache *cache);
* \{ */
SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type);
-SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node);
+SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type);
SculptUndoNode *SCULPT_undo_get_first_node(void);
/**
@@ -1781,7 +1808,10 @@ void SCULPT_OT_brush_stroke(struct wmOperatorType *ot);
/* end sculpt_ops.c */
-#define SCULPT_TOOL_NEEDS_COLOR(tool) ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)
+BLI_INLINE bool SCULPT_tool_is_paint(int tool)
+{
+ return ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR);
+}
#ifdef __cplusplus
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
index 201e02b8235..4593c6a8b60 100644
--- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -167,10 +167,8 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
if (RNA_boolean_get(op->ptr, "use_cursor")) {
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- if (SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false)) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ if (SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) {
/* The cursor is over the mesh, get the update iteration from the updated active vertex. */
mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
}
@@ -340,16 +338,14 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
+ const float mval_fl[2] = {UNPACK2(event->mval)};
SCULPT_vertex_random_access_ensure(ss);
op->customdata = MEM_mallocN(sizeof(float[2]), "initial mouse position");
- copy_v2_v2(op->customdata, mouse);
+ copy_v2_v2(op->customdata, mval_fl);
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
index dc620f0ee93..f16763be735 100644
--- a/source/blender/editors/sculpt_paint/sculpt_ops.c
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -84,6 +84,7 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "ED_image.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
@@ -349,7 +350,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
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);
+ ED_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. */
@@ -1060,10 +1061,8 @@ static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEven
/* 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);
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false);
SCULPT_undo_push_begin(ob, "Mask by color");
BKE_sculpt_color_layer_create_if_needed(ob);
@@ -1098,7 +1097,7 @@ 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";
+ ot->description = "Creates a mask based on the active color attribute";
/* api callbacks */
ot->invoke = sculpt_mask_by_color_invoke;
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index ac05652b058..7e813590e21 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -111,7 +111,7 @@ static void do_paint_brush_task_cb_ex(void *__restrict userdata,
PBVHColorBufferNode *color_buffer;
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COLOR);
color_buffer = BKE_pbvh_node_color_buffer_get(data->nodes[n]);
@@ -380,6 +380,15 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
+ float brush_delta[3];
+
+ if (brush->flag & BRUSH_ANCHORED) {
+ copy_v3_v3(brush_delta, ss->cache->grab_delta_symmetry);
+ }
+ else {
+ sub_v3_v3v3(brush_delta, ss->cache->location, ss->cache->last_location);
+ }
+
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
continue;
@@ -404,7 +413,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
switch (brush->smear_deform_type) {
case BRUSH_SMEAR_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ copy_v3_v3(current_disp, brush_delta);
break;
case BRUSH_SMEAR_DEFORM_PINCH:
sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
@@ -418,7 +427,7 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
madd_v3_v3fl(current_disp, no, -dot_v3v3(current_disp, no));
normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+ mul_v3_v3fl(current_disp, current_disp_norm, bstrength);
float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
float totw = 0.0f;
@@ -448,12 +457,12 @@ static void do_smear_brush_task_cb_exec(void *__restrict userdata,
sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
/* Weight by how close we are to our target distance from vd.co. */
- float w = (1.0f + fabsf(len_v3(vertex_disp) / ss->cache->bstrength - 1.0f));
+ float w = (1.0f + fabsf(len_v3(vertex_disp) / bstrength - 1.0f));
/* TODO: use cotangents (or at least face areas) here. */
float len = len_v3v3(SCULPT_vertex_co_get(ss, ni.index), nco);
if (len > 0.0f) {
- len = ss->cache->bstrength / len;
+ len = bstrength / len;
}
else { /* Coincident point. */
len = 1.0f;
@@ -523,18 +532,16 @@ void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- if (!SCULPT_has_colors(ss)) {
+ if (!SCULPT_has_colors(ss) || ss->cache->bstrength == 0.0f) {
return;
}
const int totvert = SCULPT_vertex_count_get(ss);
- if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
- if (!ss->cache->prev_colors) {
- ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
- for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]);
- }
+ if (!ss->cache->prev_colors) {
+ ss->cache->prev_colors = MEM_callocN(sizeof(float[4]) * totvert, "prev colors");
+ for (int i = 0; i < totvert; i++) {
+ SCULPT_vertex_color_get(ss, i, ss->cache->prev_colors[i]);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index 666cdd3fe50..479ed43c6bf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -156,7 +156,7 @@ static void do_pose_brush_task_cb_ex(void *__restrict userdata,
float final_pos[3];
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 53babc3d36d..c31863d892f 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -460,7 +460,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
ss, &test, data->brush->falloff_shape);
const int thread_id = BLI_task_parallel_thread_id(tls);
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
index b3616254b26..8856e3bf3db 100644
--- a/source/blender/editors/sculpt_paint/sculpt_transform.c
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -16,6 +16,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_kelvinlet.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
@@ -33,6 +34,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
+#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -54,6 +56,10 @@ 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);
@@ -61,10 +67,18 @@ 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);
+
+ if (sd->transform_mode == SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC) {
+ ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL;
+ }
+ else {
+ 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])
{
@@ -73,9 +87,18 @@ 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];
- 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);
+ 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;
+ }
for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
ePaintSymmetryAreas v_symm = i;
@@ -127,23 +150,33 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
PBVHNode *node = data->nodes[i];
SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS);
PBVHVertexIter vd;
SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float *start_co;
float transformed_co[3], orig_co[3], disp[3];
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);
- copy_v3_v3(transformed_co, 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);
mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
- sub_v3_v3v3(disp, transformed_co, orig_co);
+ sub_v3_v3v3(disp, transformed_co, start_co);
mul_v3_fl(disp, 1.0f - fade);
- add_v3_v3v3(vd.co, orig_co, disp);
+ add_v3_v3v3(vd.co, start_co, disp);
if (vd.mvert) {
BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
@@ -165,7 +198,8 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
.nodes = ss->filter_cache->nodes,
};
- sculpt_transform_matrices_init(ss, symm, data.transform_mats);
+ sculpt_transform_matrices_init(
+ ss, symm, ss->filter_cache->transform_displacement_mode, 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). */
@@ -175,6 +209,98 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob)
0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
}
+static void sculpt_elastic_transform_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[i])->co;
+
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i], SCULPT_UNDO_COORDS);
+
+ KelvinletParams params;
+ /* TODO(pablodp606): These parameters can be exposed if needed as transform strength and volume
+ * preservation like in the elastic deform brushes. Setting them to the same default as elastic
+ * deform triscale grab because they work well in most cases. */
+ const float force = 1.0f;
+ const float shear_modulus = 1.0f;
+ const float poisson_ratio = 0.4f;
+ BKE_kelvinlet_init_params(
+ &params, data->elastic_transform_radius, force, shear_modulus, poisson_ratio);
+
+ SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+
+ PBVHVertexIter vd;
+ 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];
+ const float fade = vd.mask ? *vd.mask : 0.0f;
+ copy_v3_v3(orig_co, orig_data.co);
+
+ copy_v3_v3(transformed_co, vd.co);
+ mul_m4_v3(data->elastic_transform_mat, transformed_co);
+ sub_v3_v3v3(disp, transformed_co, vd.co);
+
+ float final_disp[3];
+ BKE_kelvinlet_grab_triscale(final_disp, &params, vd.co, data->elastic_transform_pivot, disp);
+ mul_v3_fl(final_disp, 20.0f * (1.0f - fade));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ BKE_pbvh_vert_mark_update(ss->pbvh, vd.index);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+static void sculpt_transform_radius_elastic(Sculpt *sd, Object *ob, const float transform_radius)
+{
+ SculptSession *ss = ob->sculpt;
+ BLI_assert(ss->filter_cache->transform_displacement_mode ==
+ SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL);
+
+ const char symm = SCULPT_mesh_symmetry_xyz_get(ob);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .elastic_transform_radius = transform_radius,
+ };
+
+ sculpt_transform_matrices_init(
+ ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats);
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, ss->filter_cache->totnode);
+
+ /* Elastic transform needs to apply all transform matrices to all vertices and then combine the
+ * displacement proxies as all vertices are modified by all symmetry passes. */
+ for (ePaintSymmetryFlags symmpass = 0; symmpass <= symm; symmpass++) {
+ if (SCULPT_is_symmetry_iteration_valid(symmpass, symm)) {
+ flip_v3_v3(data.elastic_transform_pivot, ss->pivot_pos, symmpass);
+ flip_v3_v3(data.elastic_transform_pivot_init, ss->init_pivot_pos, symmpass);
+
+ printf(
+ "%.2f %.2f %.2f\n", ss->init_pivot_pos[0], ss->init_pivot_pos[1], ss->init_pivot_pos[2]);
+
+ const int symm_area = SCULPT_get_vertex_symm_area(data.elastic_transform_pivot);
+ copy_m4_m4(data.elastic_transform_mat, data.transform_mats[symm_area]);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, sculpt_elastic_transform_task_cb, &settings);
+ }
+ }
+ SCULPT_combine_transform_proxies(sd, ob);
+}
+
void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -184,7 +310,36 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob)
SCULPT_vertex_random_access_ensure(ss);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
- sculpt_transform_all_vertices(sd, ob);
+ switch (sd->transform_mode) {
+ case SCULPT_TRANSFORM_MODE_ALL_VERTICES: {
+ sculpt_transform_all_vertices(sd, ob);
+ break;
+ }
+ case SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC: {
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ Scene *scene = CTX_data_scene(C);
+ float transform_radius;
+
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ transform_radius = BKE_brush_unprojected_radius_get(scene, brush);
+ }
+ else {
+ ViewContext vc;
+
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ transform_radius = paint_calc_object_space_radius(
+ &vc, ss->init_pivot_pos, BKE_brush_size_get(scene, brush));
+ }
+
+ sculpt_transform_radius_elastic(sd, ob, transform_radius);
+ break;
+ }
+ }
+
+ 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);
@@ -267,10 +422,11 @@ static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
/* Pivot to ray-cast surface. */
else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
float stroke_location[3];
- float mouse[2];
- mouse[0] = RNA_float_get(op->ptr, "mouse_x");
- mouse[1] = RNA_float_get(op->ptr, "mouse_y");
- if (SCULPT_stroke_get_location(C, stroke_location, mouse)) {
+ const float mval[2] = {
+ RNA_float_get(op->ptr, "mouse_x"),
+ RNA_float_get(op->ptr, "mouse_y"),
+ };
+ if (SCULPT_stroke_get_location(C, stroke_location, mval, false)) {
copy_v3_v3(ss->pivot_pos, stroke_location);
}
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 1fee20444e7..1e050fedf8e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -50,6 +50,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_geometry.h"
#include "ED_object.h"
#include "ED_sculpt.h"
#include "ED_undo.h"
@@ -105,7 +106,7 @@ typedef struct UndoSculpt {
} UndoSculpt;
typedef struct SculptAttrRef {
- AttributeDomain domain;
+ eAttrDomain domain;
int type;
char name[MAX_CUSTOMDATA_LAYER_NAME];
bool was_set;
@@ -854,7 +855,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
if (tag_update) {
Mesh *mesh = ob->data;
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_tag_coords_changed(mesh);
BKE_sculptsession_free_deformMats(ss);
}
@@ -960,7 +961,7 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
}
#endif
-SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
+SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
@@ -968,7 +969,13 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
return NULL;
}
- return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
+ LISTBASE_FOREACH (SculptUndoNode *, unode, &usculpt->nodes) {
+ if (unode->node == node && unode->type == type) {
+ return unode;
+ }
+ }
+
+ return NULL;
}
SculptUndoNode *SCULPT_undo_get_first_node()
@@ -1380,7 +1387,7 @@ SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
- if ((unode = SCULPT_undo_get_node(node))) {
+ if ((unode = SCULPT_undo_get_node(node, type))) {
BLI_thread_unlock(LOCK_CUSTOM1);
return unode;
}
@@ -1464,7 +1471,7 @@ static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b)
static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr)
{
Mesh *me = BKE_object_get_original_mesh(ob);
- CustomDataLayer *layer;
+ const CustomDataLayer *layer;
if (ob && me && (layer = BKE_id_attributes_active_color_get((ID *)me))) {
attr->domain = BKE_id_attribute_domain((ID *)me, layer);
@@ -1565,6 +1572,24 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr
CustomDataLayer *layer;
layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
+ /* Temporary fix for T97408. This is a fundamental
+ * bug in the undo stack; the operator code needs to push
+ * an extra undo step before running an operator if a
+ * non-memfile undo system is active.
+ *
+ * For now, detect if the layer does exist but with a different
+ * domain and just unconvert it.
+ */
+ if (!layer) {
+ layer = BKE_id_attribute_search(&me->id, attr->name, CD_MASK_PROP_ALL, ATTR_DOMAIN_MASK_ALL);
+ eAttrDomain domain = layer ? BKE_id_attribute_domain(&me->id, layer) : ATTR_DOMAIN_NUM;
+
+ if (layer && ED_geometry_attribute_convert(
+ me, attr->name, layer->type, domain, attr->type, attr->domain)) {
+ layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain);
+ }
+ }
+
if (!layer) {
/* Memfile undo killed the layer; re-create it. */
CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata;
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 8e1f4f4d495..5c2dff7b252 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -500,20 +500,10 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
if (do_island_optimization) {
/* We will need island information */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, true);
- }
- else {
- data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, true);
- }
+ data->elementMap = BM_uv_element_map_create(bm, scene, false, true, true);
}
else {
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, false);
- }
- else {
- data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, false);
- }
+ data->elementMap = BM_uv_element_map_create(bm, scene, false, true, false);
}
if (!data->elementMap) {
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 2a8a2be8b65..08b795db0c3 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -340,7 +340,8 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
AUD_DeviceSpecs specs;
AUD_Container container;
AUD_Codec codec;
- const char *result;
+ int result;
+ char error_message[1024] = {'\0'};
sound_bake_animation_exec(C, op);
@@ -372,7 +373,9 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
codec,
bitrate,
NULL,
- NULL);
+ NULL,
+ error_message,
+ sizeof(error_message));
}
else {
result = AUD_mixdown(scene_eval->sound_scene,
@@ -385,13 +388,15 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
codec,
bitrate,
NULL,
- NULL);
+ NULL,
+ error_message,
+ sizeof(error_message));
}
BKE_sound_reset_scene_specs(scene_eval);
- if (result) {
- BKE_report(op->reports, RPT_ERROR, result);
+ if (!result) {
+ BKE_report(op->reports, RPT_ERROR, error_message);
return OPERATOR_CANCELLED;
}
#else /* WITH_AUDASPACE */
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 87a271543d1..23c92cbdaa0 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -158,8 +158,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
/* get data to filter, from Action or Dopesheet */
/* XXX: what is sel doing here?!
* Commented it, was breaking things (eg. the "auto preview range" tool). */
- filter = (ANIMFILTER_DATA_VISIBLE |
- ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL */ /*| ANIMFILTER_CURVESONLY*/ |
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL */ |
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -178,10 +177,12 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
/* Find gp-frame which is less than or equal to current-frame. */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- const float framenum = (float)gpf->framenum;
- *min = min_ff(*min, framenum);
- *max = max_ff(*max, framenum);
- found = true;
+ if (!onlySel || (gpf->flag & GP_FRAME_SELECT)) {
+ const float framenum = (float)gpf->framenum;
+ *min = min_ff(*min, framenum);
+ *max = max_ff(*max, framenum);
+ found = true;
+ }
}
}
else if (ale->datatype == ALE_MASKLAY) {
@@ -498,7 +499,7 @@ static short copy_action_keys(bAnimContext *ac)
ANIM_fcurves_copybuf_free();
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FCURVESONLY |
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -511,13 +512,13 @@ static short copy_action_keys(bAnimContext *ac)
return ok;
}
-static short paste_action_keys(bAnimContext *ac,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
- bool flip)
+static eKeyPasteError paste_action_keys(bAnimContext *ac,
+ const eKeyPasteOffset offset_mode,
+ const eKeyMergeMode merge_mode,
+ bool flip)
{
ListBase anim_data = {NULL, NULL};
- int filter, ok = 0;
+ int filter;
/* filter data
* - First time we try to filter more strictly, allowing only selected channels
@@ -525,15 +526,15 @@ static short paste_action_keys(bAnimContext *ac,
* - Second time, we loosen things up if nothing was found the first time, allowing
* users to just paste keyframes back into the original curve again T31670.
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) {
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
}
/* paste keyframes */
- ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
+ const eKeyPasteError ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
/* clean up */
ANIM_animdata_freelist(&anim_data);
@@ -555,7 +556,8 @@ static int actkeys_copy_exec(bContext *C, wmOperator *op)
/* copy keyframes */
if (ac.datatype == ANIMCONT_GPENCIL) {
if (ED_gpencil_anim_copybuf_copy(&ac) == false) {
- /* Nothing got copied - An error about this should be been logged already */
+ /* check if anything ended up in the buffer */
+ BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
return OPERATOR_CANCELLED;
}
}
@@ -565,7 +567,11 @@ static int actkeys_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
- if (copy_action_keys(&ac)) {
+ /* Both copy function needs to be evaluated to account for mixed selection */
+ const short kf_empty = copy_action_keys(&ac);
+ const bool gpf_ok = ED_gpencil_anim_copybuf_copy(&ac);
+
+ if (kf_empty && !gpf_ok) {
BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
return OPERATOR_CANCELLED;
}
@@ -597,6 +603,8 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
const bool flipped = RNA_boolean_get(op->ptr, "flipped");
+ bool gpframes_inbuf = false;
+
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
return OPERATOR_CANCELLED;
@@ -608,7 +616,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
/* paste keyframes */
if (ac.datatype == ANIMCONT_GPENCIL) {
if (ED_gpencil_anim_copybuf_paste(&ac, offset_mode) == false) {
- /* An error occurred - Reports should have been fired already */
+ BKE_report(op->reports, RPT_ERROR, "No data in buffer to paste");
return OPERATOR_CANCELLED;
}
}
@@ -620,14 +628,31 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else {
+ /* Both paste function needs to be evaluated to account for mixed selection */
+ const eKeyPasteError kf_empty = paste_action_keys(&ac, offset_mode, merge_mode, flipped);
/* non-zero return means an error occurred while trying to paste */
- if (paste_action_keys(&ac, offset_mode, merge_mode, flipped)) {
- return OPERATOR_CANCELLED;
+ gpframes_inbuf = ED_gpencil_anim_copybuf_paste(&ac, offset_mode);
+
+ /* Only report an error if nothing was pasted, i.e. when both FCurve and GPencil failed. */
+ if (!gpframes_inbuf) {
+ switch (kf_empty) {
+ case KEYFRAME_PASTE_OK:
+ /* FCurve paste was ok, so it's all good. */
+ break;
+
+ case KEYFRAME_PASTE_NOWHERE_TO_PASTE:
+ BKE_report(op->reports, RPT_ERROR, "No selected F-Curves to paste into");
+ return OPERATOR_CANCELLED;
+
+ case KEYFRAME_PASTE_NOTHING_TO_PASTE:
+ BKE_report(op->reports, RPT_ERROR, "No data in buffer to paste");
+ return OPERATOR_CANCELLED;
+ }
}
}
/* Grease Pencil needs extra update to refresh the added keyframes. */
- if (ac.datatype == ANIMCONT_GPENCIL) {
+ if (ac.datatype == ANIMCONT_GPENCIL || gpframes_inbuf) {
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
}
/* set notifier that keyframes have changed */
@@ -697,94 +722,86 @@ static const EnumPropertyItem prop_actkeys_insertkey_types[] = {
{0, NULL, 0, NULL, NULL},
};
-/* this function is responsible for inserting new keyframes */
-static void insert_action_keys(bAnimContext *ac, short mode)
+static void insert_gpencil_key(bAnimContext *ac,
+ bAnimListElem *ale,
+ const eGP_GetFrame_Mode add_frame_mode,
+ bGPdata **gpd_old)
{
- ListBase anim_data = {NULL, NULL};
- ListBase nla_cache = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
+ Scene *scene = ac->scene;
+ bGPdata *gpd = (bGPdata *)ale->id;
+ bGPDlayer *gpl = (bGPDlayer *)ale->data;
+ BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, add_frame_mode);
+ /* Check if the gpd changes to tag only once. */
+ if (gpd != *gpd_old) {
+ BKE_gpencil_tag(gpd);
+ *gpd_old = gpd;
+ }
+}
+
+static void insert_fcurve_key(bAnimContext *ac,
+ bAnimListElem *ale,
+ const AnimationEvalContext anim_eval_context,
+ eInsertKeyFlags flag,
+ ListBase *nla_cache)
+{
+ FCurve *fcu = (FCurve *)ale->key_data;
ReportList *reports = ac->reports;
Scene *scene = ac->scene;
ToolSettings *ts = scene->toolsettings;
- eInsertKeyFlags flag;
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
- if (mode == 2) {
- filter |= ANIMFILTER_SEL;
- }
- else if (mode == 3) {
- filter |= ANIMFILTER_ACTGROUPED;
+ /* Read value from property the F-Curve represents, or from the curve only?
+ * - ale->id != NULL:
+ * Typically, this means that we have enough info to try resolving the path.
+ *
+ * - ale->owner != NULL:
+ * If this is set, then the path may not be resolvable from the ID alone,
+ * so it's easier for now to just read the F-Curve directly.
+ * (TODO: add the full-blown PointerRNA relative parsing case here...)
+ */
+ if (ale->id && !ale->owner) {
+ insert_keyframe(ac->bmain,
+ reports,
+ ale->id,
+ NULL,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ fcu->array_index,
+ &anim_eval_context,
+ ts->keyframe_type,
+ nla_cache,
+ flag);
}
+ else {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
-
- /* Init keyframing flag. */
- flag = ANIM_get_keyframing_flags(scene, true);
-
- /* insert keyframes */
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(ac->depsgraph,
- (float)CFRA);
- for (ale = anim_data.first; ale; ale = ale->next) {
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* Read value from property the F-Curve represents, or from the curve only?
- * - ale->id != NULL:
- * Typically, this means that we have enough info to try resolving the path.
- *
- * - ale->owner != NULL:
- * If this is set, then the path may not be resolvable from the ID alone,
- * so it's easier for now to just read the F-Curve directly.
- * (TODO: add the full-blown PointerRNA relative parsing case here...)
- */
- if (ale->id && !ale->owner) {
- insert_keyframe(ac->bmain,
- reports,
- ale->id,
- NULL,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- fcu->array_index,
- &anim_eval_context,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
- else {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-
- /* adjust current frame for NLA-scaling */
- float cfra = anim_eval_context.eval_time;
- if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
- }
-
- const float curval = evaluate_fcurve(fcu, cfra);
- insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
+ /* adjust current frame for NLA-scaling */
+ float cfra = anim_eval_context.eval_time;
+ if (adt) {
+ cfra = BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
}
- ale->update |= ANIM_UPDATE_DEFAULT;
+ const float curval = evaluate_fcurve(fcu, cfra);
+ insert_vert_fcurve(fcu, cfra, curval, ts->keyframe_type, 0);
}
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
-
- ANIM_animdata_update(ac, &anim_data);
- ANIM_animdata_freelist(&anim_data);
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-/* this function is for inserting new grease pencil frames */
-static void insert_gpencil_keys(bAnimContext *ac, short mode)
+/* this function is responsible for inserting new keyframes */
+static void insert_action_keys(bAnimContext *ac, short mode)
{
ListBase anim_data = {NULL, NULL};
+ ListBase nla_cache = {NULL, NULL};
bAnimListElem *ale;
int filter;
Scene *scene = ac->scene;
ToolSettings *ts = scene->toolsettings;
+ eInsertKeyFlags flag;
+
eGP_GetFrame_Mode add_frame_mode;
+ bGPdata *gpd_old = NULL;
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
@@ -792,30 +809,43 @@ static void insert_gpencil_keys(bAnimContext *ac, short mode)
if (mode == 2) {
filter |= ANIMFILTER_SEL;
}
+ else if (mode == 3) {
+ filter |= ANIMFILTER_ACTGROUPED;
+ }
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- /* add a copy or a blank frame? */
+ /* Init keyframing flag. */
+ flag = ANIM_get_keyframing_flags(scene, true);
+
+ /* GPLayers specific flags */
if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
- add_frame_mode = GP_GETFRAME_ADD_COPY; /* XXX: actframe may not be what we want? */
+ add_frame_mode = GP_GETFRAME_ADD_COPY;
}
else {
add_frame_mode = GP_GETFRAME_ADD_NEW;
}
- /* Insert gp frames. */
- bGPdata *gpd_old = NULL;
+ /* insert keyframes */
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ ac->depsgraph, (float)scene->r.cfra);
for (ale = anim_data.first; ale; ale = ale->next) {
- bGPdata *gpd = (bGPdata *)ale->id;
- bGPDlayer *gpl = (bGPDlayer *)ale->data;
- BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode);
- /* Check if the gpd changes to tag only once. */
- if (gpd != gpd_old) {
- BKE_gpencil_tag(gpd);
- gpd_old = gpd;
+ switch (ale->type) {
+ case ANIMTYPE_GPLAYER:
+ insert_gpencil_key(ac, ale, add_frame_mode, &gpd_old);
+ break;
+
+ case ANIMTYPE_FCURVE:
+ insert_fcurve_key(ac, ale, anim_eval_context, flag, &nla_cache);
+ break;
+
+ default:
+ BLI_assert_msg(false, "Keys cannot be inserted into this animation type.");
}
}
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
+
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
@@ -841,12 +871,7 @@ static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
mode = RNA_enum_get(op->ptr, "type");
/* insert keyframes */
- if (ac.datatype == ANIMCONT_GPENCIL) {
- insert_gpencil_keys(&ac, mode);
- }
- else {
- insert_action_keys(&ac, mode);
- }
+ insert_action_keys(&ac, mode);
/* set notifier that keyframes have changed */
if (ac.datatype == ANIMCONT_GPENCIL) {
@@ -886,14 +911,8 @@ static bool duplicate_action_keys(bAnimContext *ac)
bool changed = false;
/* filter data */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and delete selected keys */
@@ -968,14 +987,8 @@ static bool delete_action_keys(bAnimContext *ac)
bool changed_final = false;
/* filter data */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and delete selected keys */
@@ -993,7 +1006,7 @@ static bool delete_action_keys(bAnimContext *ac)
AnimData *adt = ale->adt;
/* delete selected keyframes only */
- changed = delete_fcurve_keys(fcu);
+ changed = BKE_fcurve_delete_keys_selected(fcu);
/* Only delete curve too if it won't be doing anything anymore */
if (BKE_fcurve_is_empty(fcu)) {
@@ -1063,7 +1076,7 @@ static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan)
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ ANIMFILTER_SEL | ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and clean curves */
@@ -1139,8 +1152,8 @@ static void sample_action_keys(bAnimContext *ac)
int filter;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
@@ -1238,7 +1251,7 @@ static void setexpo_action_keys(bAnimContext *ac, short mode)
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ ANIMFILTER_SEL | ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through setting mode per F-Curve */
@@ -1352,7 +1365,8 @@ static int actkeys_ipo_exec(bContext *C, wmOperator *op)
/* set handle type */
ANIM_animdata_keyframe_callback(&ac,
(ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS),
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY),
ANIM_editkeyframes_ipo(mode));
/* set notifier that keyframe properties have changed */
@@ -1401,7 +1415,8 @@ static int actkeys_easing_exec(bContext *C, wmOperator *op)
/* set handle type */
ANIM_animdata_keyframe_callback(&ac,
(ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS),
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY),
ANIM_editkeyframes_easing(mode));
/* set notifier that keyframe properties have changed */
@@ -1444,8 +1459,8 @@ static void sethandles_action_keys(bAnimContext *ac, short mode)
KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting flags for handles
@@ -1458,7 +1473,7 @@ static void sethandles_action_keys(bAnimContext *ac, short mode)
/* any selected keyframes for editing? */
if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
/* change type of selected handles */
- ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -1527,8 +1542,8 @@ static void setkeytype_action_keys(bAnimContext *ac, short mode)
KeyframeEditFunc set_cb = ANIM_editkeyframes_keytype(mode);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting BezTriple interpolation
@@ -1536,32 +1551,19 @@ static void setkeytype_action_keys(bAnimContext *ac, short mode)
* Currently that's not necessary here.
*/
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL);
-
- ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
- }
-
- ANIM_animdata_update(ac, &anim_data);
- ANIM_animdata_freelist(&anim_data);
-}
-
-/* this function is responsible for setting the keyframe type for Grease Pencil frames */
-static void setkeytype_gpencil_keys(bAnimContext *ac, short mode)
-{
- ListBase anim_data = {NULL, NULL};
- bAnimListElem *ale;
- int filter;
+ switch (ale->type) {
+ case ANIMTYPE_GPLAYER:
+ ED_gpencil_layer_frames_keytype_set(ale->data, mode);
+ ale->update |= ANIM_UPDATE_DEPS;
+ break;
- /* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
- ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+ case ANIMTYPE_FCURVE:
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL);
+ ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
+ break;
- /* loop through each layer */
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_layer_frames_keytype_set(ale->data, mode);
- ale->update |= ANIM_UPDATE_DEPS;
+ default:
+ BLI_assert_msg(false, "Keytype cannot be set into this animation type.");
}
}
@@ -1590,12 +1592,7 @@ static int actkeys_keytype_exec(bContext *C, wmOperator *op)
mode = RNA_enum_get(op->ptr, "type");
/* set handle type */
- if (ac.datatype == ANIMCONT_GPENCIL) {
- setkeytype_gpencil_keys(&ac, mode);
- }
- else {
- setkeytype_action_keys(&ac, mode);
- }
+ setkeytype_action_keys(&ac, mode);
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1653,19 +1650,44 @@ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
/* init edit data */
/* loop over action data, averaging values */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
- }
- else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
+ switch (ale->datatype) {
+ case ALE_GPFRAME: {
+ bGPDlayer *gpl = ale->data;
+ bGPDframe *gpf;
+
+ for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* only if selected */
+ if (!(gpf->flag & GP_FRAME_SELECT)) {
+ continue;
+ }
+ /* store average time in float 1 (only do rounding at last step) */
+ ked.f1 += gpf->framenum;
+
+ /* increment number of items */
+ ked.i1++;
+ }
+ break;
+ }
+
+ case ALE_FCURVE: {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ }
+ else {
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
+ }
+ break;
+ }
+
+ default:
+ BLI_assert_msg(false, "Cannot jump to keyframe into this animation type.");
}
}
@@ -1674,8 +1696,8 @@ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
/* set the new current frame value, based on the average time */
if (ked.i1) {
Scene *scene = ac.scene;
- CFRA = round_fl_to_int(ked.f1 / ked.i1);
- SUBFRA = 0.0f;
+ scene->r.cfra = round_fl_to_int(ked.f1 / ked.i1);
+ scene->r.subframe = 0.0f;
}
/* set notifier that things have changed */
@@ -1742,8 +1764,8 @@ static void snap_action_keys(bAnimContext *ac, short mode)
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
}
else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
}
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -1768,11 +1790,11 @@ static void snap_action_keys(bAnimContext *ac, short mode)
}
else if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
}
ale->update |= ANIM_UPDATE_DEFAULT;
@@ -1876,14 +1898,8 @@ static void mirror_action_keys(bAnimContext *ac, short mode)
}
/* filter data */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
- ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* mirror keyframes */
@@ -1898,11 +1914,11 @@ static void mirror_action_keys(bAnimContext *ac, short mode)
}
else if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
}
ale->update |= ANIM_UPDATE_DEFAULT;
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index aff888818e0..d1a8592ae9d 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -235,13 +235,7 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel)
KeyframeEditFunc test_cb, sel_cb;
/* determine type-based settings */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
- ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
/* filter data */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -416,7 +410,7 @@ static void box_select_elem(
break;
}
- if (ale->type == ANIMTYPE_SUMMARY && ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (ale->type == ANIMTYPE_SUMMARY) {
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, ac->datatype);
@@ -428,8 +422,10 @@ static void box_select_elem(
ANIM_animdata_freelist(&anim_data);
}
- ANIM_animchannel_keyframes_loop(
- &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
+ if (!ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ ANIM_animchannel_keyframes_loop(
+ &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
+ }
}
}
}
@@ -658,7 +654,7 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
break;
}
- if (ale->type == ANIMTYPE_SUMMARY && ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (ale->type == ANIMTYPE_SUMMARY) {
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, ac->datatype);
@@ -670,8 +666,10 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
ANIM_animdata_freelist(&anim_data);
}
- ANIM_animchannel_keyframes_loop(
- &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
+ if (!ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ ANIM_animchannel_keyframes_loop(
+ &sel_data->ked, ac->ads, ale, sel_data->ok_cb, sel_data->select_cb, NULL);
+ }
}
}
}
@@ -946,28 +944,36 @@ static void markers_selectkeys_between(bAnimContext *ac)
ked.f2 = max;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select keys in-between */
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ switch (ale->type) {
+ case ANIMTYPE_GPLAYER:
+ ED_gpencil_layer_frames_select_box(ale->data, min, max, SELECT_ADD);
+ ale->update |= ANIM_UPDATE_DEPS;
+ break;
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
- }
- else if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_layer_frames_select_box(ale->data, min, max, SELECT_ADD);
- ale->update |= ANIM_UPDATE_DEPS;
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_masklayer_frames_select_box(ale->data, min, max, SELECT_ADD);
- }
- else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ case ANIMTYPE_MASKLAYER:
+ ED_masklayer_frames_select_box(ale->data, min, max, SELECT_ADD);
+ break;
+
+ case ANIMTYPE_FCURVE: {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ }
+ else {
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
+ break;
+ }
+
+ default:
+ BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
}
}
@@ -1000,11 +1006,16 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
}
}
else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
+ if (ale->datatype == ALE_GPFRAME) {
+ ED_gpencil_layer_make_cfra_list(ale->data, &ked.list, 1);
+ }
+ else {
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
+ }
}
}
ANIM_animdata_freelist(&anim_data);
@@ -1015,7 +1026,7 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
BLI_addtail(&ked.list, ce);
- ce->cfra = (float)CFRA;
+ ce->cfra = (float)scene->r.cfra;
break;
case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
@@ -1033,12 +1044,7 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1144,7 +1150,7 @@ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
}
/* loop through all of the keys and select additional keyframes based on these */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FCURVESONLY |
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -1200,7 +1206,7 @@ static void select_moreless_action_keys(bAnimContext *ac, short mode)
build_cb = ANIM_editkeyframes_buildselmap(mode);
/* loop through all of the keys and select additional keyframes based on these */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FCURVESONLY |
ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -1346,41 +1352,44 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
if (leftright == ACTKEYS_LRSEL_LEFT) {
ked.f1 = MINAFRAMEF;
- ked.f2 = (float)(CFRA + 0.1f);
+ ked.f2 = (float)(scene->r.cfra + 0.1f);
}
else {
- ked.f1 = (float)(CFRA - 0.1f);
+ ked.f1 = (float)(scene->r.cfra - 0.1f);
ked.f2 = MAXFRAMEF;
}
/* filter data */
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ |
- ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select keys */
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ switch (ale->type) {
+ case ANIMTYPE_GPLAYER:
+ ED_gpencil_layer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
+ ale->update |= ANIM_UPDATE_DEPS;
+ break;
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
- ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
- }
- else if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_layer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
- ale->update |= ANIM_UPDATE_DEPS;
- }
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_masklayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
- }
- else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ case ANIMTYPE_MASKLAYER:
+ ED_masklayer_frames_select_box(ale->data, ked.f1, ked.f2, select_mode);
+ break;
+
+ case ANIMTYPE_FCURVE: {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
+ }
+ else {
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
+ }
+ break;
+ }
+
+ default:
+ BLI_assert_msg(false, "Keys cannot be selected into this animation type.");
}
}
@@ -1393,8 +1402,8 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
TimeMarker *marker;
for (marker = markers->first; marker; marker = marker->next) {
- if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < CFRA)) ||
- ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= CFRA))) {
+ if (((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < scene->r.cfra)) ||
+ ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= scene->r.cfra))) {
marker->flag |= SELECT;
}
else {
@@ -1464,7 +1473,7 @@ static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wm
/* determine which side of the current frame mouse is on */
x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
- if (x < CFRA) {
+ if (x < scene->r.cfra) {
RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT);
}
else {
@@ -1539,29 +1548,29 @@ static void actkeys_mselect_single(bAnimContext *ac,
ED_mask_select_frame(ale->data, selx, select_mode);
}
else {
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && (ale->type == ANIMTYPE_SUMMARY) &&
- (ale->datatype == ALE_ALL)) {
+ if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
ListBase anim_data = {NULL, NULL};
int filter;
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_select_frame(ale->data, selx, select_mode);
- ale->update |= ANIM_UPDATE_DEPS;
+ /* Loop over all keys that are represented by this summary key. */
+ LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
+ if (ale2->type == ANIMTYPE_GPLAYER) {
+ ED_gpencil_select_frame(ale2->data, selx, select_mode);
+ ale2->update |= ANIM_UPDATE_DEPS;
}
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_mask_select_frame(ale->data, selx, select_mode);
+ else if (ale2->type == ANIMTYPE_MASKLAYER) {
+ ED_mask_select_frame(ale2->data, selx, select_mode);
}
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
- else {
+
+ if (!ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
}
}
@@ -1588,35 +1597,29 @@ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float se
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(ac, ale);
-
- /* set frame for validation callback to refer to */
- if (adt) {
- ked.f1 = BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP);
- }
- else {
- ked.f1 = selx;
- }
-
/* select elements with frame number matching cfra */
if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_select_frame(ale->key_data, selx, select_mode);
+ ED_gpencil_select_frame(ale->data, selx, select_mode);
ale->update |= ANIM_UPDATE_DEPS;
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_mask_select_frame(ale->key_data, selx, select_mode);
+ ED_mask_select_frame(ale->data, selx, select_mode);
}
else {
+ AnimData *adt = ANIM_nla_mapping_get(ac, ale);
+
+ /* set frame for validation callback to refer to */
+ if (adt) {
+ ked.f1 = BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ ked.f1 = selx;
+ }
+
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
}
}
@@ -1645,29 +1648,28 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
ED_mask_select_frames(ale->data, select_mode);
}
else {
- if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) && (ale->type == ANIMTYPE_SUMMARY) &&
- (ale->datatype == ALE_ALL)) {
+ if (ale->type == ANIMTYPE_SUMMARY && ale->datatype == ALE_ALL) {
ListBase anim_data = {NULL, NULL};
int filter;
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
- for (ale = anim_data.first; ale; ale = ale->next) {
- if (ale->type == ANIMTYPE_GPLAYER) {
- ED_gpencil_select_frames(ale->data, select_mode);
- ale->update |= ANIM_UPDATE_DEPS;
+ LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
+ if (ale2->type == ANIMTYPE_GPLAYER) {
+ ED_gpencil_select_frames(ale2->data, select_mode);
+ ale2->update |= ANIM_UPDATE_DEPS;
}
- else if (ale->type == ANIMTYPE_MASKLAYER) {
- ED_mask_select_frames(ale->data, select_mode);
+ else if (ale2->type == ANIMTYPE_MASKLAYER) {
+ ED_mask_select_frames(ale2->data, select_mode);
}
}
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
}
- else {
+
+ if (!ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
ANIM_animchannel_keyframes_loop(NULL, ac->ads, ale, NULL, select_cb, NULL);
}
}
@@ -1734,6 +1736,12 @@ static int mouse_action_keys(bAnimContext *ac,
fcu->flag |= FCURVE_SELECTED;
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
}
+ else if (ale->type == ANIMTYPE_GPLAYER) {
+ bGPdata *gpd = (bGPdata *)ale->id;
+ bGPDlayer *gpl = ale->data;
+
+ ED_gpencil_set_active_channel(gpd, gpl);
+ }
}
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
@@ -1745,13 +1753,7 @@ static int mouse_action_keys(bAnimContext *ac,
bGPdata *gpd = (bGPdata *)ale->id;
bGPDlayer *gpl = ale->data;
- gpl->flag |= GP_LAYER_SELECT;
- /* Update other layer status. */
- if (BKE_gpencil_layer_active_get(gpd) != gpl) {
- BKE_gpencil_layer_active_set(gpd, gpl);
- BKE_gpencil_layer_autolock_set(gpd, false);
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- }
+ ED_gpencil_set_active_channel(gpd, gpl);
}
}
else if (ac->datatype == ANIMCONT_MASK) {
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 09163842587..3e507f73d1a 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -98,9 +98,9 @@ static SpaceLink *action_create(const ScrArea *area, const Scene *scene)
BLI_addtail(&saction->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
- region->v2d.tot.xmin = (float)(SFRA - 10);
+ region->v2d.tot.xmin = (float)(scene->r.sfra - 10);
region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
- region->v2d.tot.xmax = (float)(EFRA + 10);
+ region->v2d.tot.xmax = (float)(scene->r.efra + 10);
region->v2d.tot.ymax = 0.0f;
region->v2d.cur = region->v2d.tot;
@@ -506,8 +506,8 @@ static void action_listener(const wmSpaceTypeListenerParams *params)
/* context changes */
switch (wmn->category) {
case NC_GPENCIL:
- /* only handle these events in GPencil mode for performance considerations */
- if (saction->mode == SACTCONT_GPENCIL) {
+ /* only handle these events for containers in which GPencil frames are displayed */
+ if (ELEM(saction->mode, SACTCONT_GPENCIL, SACTCONT_DOPESHEET, SACTCONT_TIMELINE)) {
if (wmn->action == NA_EDITED) {
ED_area_tag_redraw(area);
}
@@ -561,8 +561,8 @@ static void action_listener(const wmSpaceTypeListenerParams *params)
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
Scene *scene = wmn->reference;
- region->v2d.tot.xmin = (float)(SFRA - 4);
- region->v2d.tot.xmax = (float)(EFRA + 4);
+ region->v2d.tot.xmin = (float)(scene->r.sfra - 4);
+ region->v2d.tot.xmax = (float)(scene->r.efra + 4);
break;
}
}
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index b2b9ef8cd04..a2f99ef1a53 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -164,6 +164,7 @@ void ED_spacemacros_init(void)
ED_operatormacros_sequencer();
ED_operatormacros_paint();
ED_operatormacros_gpencil();
+ ED_operatormacros_nla();
/* Register dropboxes (can use macros). */
ED_dropboxes_ui();
diff --git a/source/blender/editors/space_assets/asset_catalog_tree_view.cc b/source/blender/editors/space_assets/asset_catalog_tree_view.cc
index 02ba6fdeec2..b88bf0271a1 100644
--- a/source/blender/editors/space_assets/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_assets/asset_catalog_tree_view.cc
@@ -96,12 +96,12 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
bool rename(StringRefNull new_name) override;
/** Add drag support for catalog items. */
- std::unique_ptr<ui::AbstractTreeViewItemDragController> create_drag_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
/** Add dropping support for catalog items. */
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
-class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController {
+class AssetCatalogDragController : public ui::AbstractViewItemDragController {
AssetCatalogTreeItem &catalog_item_;
public:
@@ -113,7 +113,7 @@ class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController
void on_drag_start() override;
};
-class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController {
+class AssetCatalogDropController : public ui::AbstractViewItemDropController {
AssetCatalogTreeItem &catalog_item_;
public:
@@ -152,7 +152,7 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
void build_row(uiLayout &row) override;
- struct DropController : public ui::AbstractTreeViewItemDropController {
+ struct DropController : public ui::AbstractViewItemDropController {
DropController(AssetCatalogTreeView &tree_view);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
@@ -160,13 +160,13 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
- struct DropController : public ui::AbstractTreeViewItemDropController {
+ struct DropController : public ui::AbstractViewItemDropController {
DropController(AssetCatalogTreeView &tree_view);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
@@ -174,7 +174,7 @@ class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
/* ---------------------------------------------------------------------- */
@@ -320,11 +320,11 @@ void AssetCatalogTreeViewItem::build_row(uiLayout &row)
return;
}
- uiButTreeRow *tree_row_but = tree_row_button();
+ uiButViewItem *item_but = view_item_button();
PointerRNA *props;
props = UI_but_extra_operator_icon_add(
- (uiBut *)tree_row_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ (uiBut *)item_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
RNA_string_set(props, "parent_path", catalog_item_.catalog_path().c_str());
}
@@ -353,7 +353,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
0,
&props);
RNA_string_set(&props, "catalog_id", catalog_id_str_buffer);
- uiItemO(&column, "Rename", ICON_NONE, "UI_OT_tree_view_item_rename");
+ uiItemO(&column, "Rename", ICON_NONE, "UI_OT_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
@@ -381,14 +381,14 @@ bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
return true;
}
-std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogDropController>(
static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
}
-std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem::
+std::unique_ptr<ui::AbstractViewItemDragController> AssetCatalogTreeViewItem::
create_drag_controller() const
{
return std::make_unique<AssetCatalogDragController>(
@@ -399,7 +399,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem
AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
- : ui::AbstractTreeViewItemDropController(tree_view), catalog_item_(catalog_item)
+ : ui::AbstractViewItemDropController(tree_view), catalog_item_(catalog_item)
{
}
@@ -455,18 +455,25 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr
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() +
- ")";
+ basic_tip += ": " + catalog_item_.get_name();
+
+ /* Display the full catalog path, but only if it's not exactly the same as the already shown name
+ * (i.e. not a root level catalog with no parent). */
+ if (catalog_item_.get_name() != catalog_item_.catalog_path().str()) {
+ basic_tip += " (" + catalog_item_.catalog_path().str() + ")";
+ }
+
+ return basic_tip;
}
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());
+ drag, get_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
}
return drop_assets_into_catalog(C,
- tree_view<AssetCatalogTreeView>(),
+ get_view<AssetCatalogTreeView>(),
drag,
catalog_item_.get_catalog_id(),
catalog_item_.get_simple_name());
@@ -556,14 +563,14 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
::AssetLibrary &AssetCatalogDropController::get_asset_library() const
{
- return *tree_view<AssetCatalogTreeView>().asset_library_;
+ return *get_view<AssetCatalogTreeView>().asset_library_;
}
/* ---------------------------------------------------------------------- */
AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
- : ui::AbstractTreeViewItemDragController(tree_view), catalog_item_(catalog_item)
+ : ui::AbstractViewItemDragController(tree_view), catalog_item_(catalog_item)
{
}
@@ -582,7 +589,7 @@ void *AssetCatalogDragController::create_drag_data() const
void AssetCatalogDragController::on_drag_start()
{
- AssetCatalogTreeView &tree_view_ = tree_view<AssetCatalogTreeView>();
+ AssetCatalogTreeView &tree_view_ = get_view<AssetCatalogTreeView>();
tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
}
@@ -595,15 +602,15 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
PointerRNA *props;
UI_but_extra_operator_icon_add(
- (uiBut *)tree_row_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK);
+ (uiBut *)view_item_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);
+ (uiBut *)view_item_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::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewAllItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewAllItem::DropController>(
@@ -611,7 +618,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllI
}
AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view)
- : ui::AbstractTreeViewItemDropController(tree_view)
+ : ui::AbstractViewItemDropController(tree_view)
{
}
@@ -623,7 +630,7 @@ bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag,
}
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
- drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ drag, *get_view<AssetCatalogTreeView>().asset_library_);
if (drag_catalog->path.parent() == "") {
*r_disabled_hint = "Catalog is already placed at the highest level";
return false;
@@ -636,7 +643,7 @@ std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDr
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
- drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ drag, *get_view<AssetCatalogTreeView>().asset_library_);
return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " +
TIP_("to the top level of the tree");
@@ -648,14 +655,14 @@ bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext *UNUSE
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
return AssetCatalogDropController::drop_asset_catalog_into_catalog(
drag,
- tree_view<AssetCatalogTreeView>(),
+ get_view<AssetCatalogTreeView>(),
/* No value to drop into the root level. */
std::nullopt);
}
/* ---------------------------------------------------------------------- */
-std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewUnassignedItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropController>(
@@ -663,7 +670,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnas
}
AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view)
- : ui::AbstractTreeViewItemDropController(tree_view)
+ : ui::AbstractViewItemDropController(tree_view)
{
}
@@ -691,7 +698,7 @@ bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext
{
/* Assign to nil catalog ID. */
return AssetCatalogDropController::drop_assets_into_catalog(
- C, tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
+ C, get_view<AssetCatalogTreeView>(), drag, CatalogID{});
}
} // namespace blender::ed::asset_browser
diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt
index e2f1df74446..7d4f38b1841 100644
--- a/source/blender/editors/space_buttons/CMakeLists.txt
+++ b/source/blender/editors/space_buttons/CMakeLists.txt
@@ -35,7 +35,6 @@ endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
add_definitions(-DWITH_POINT_CLOUD)
- add_definitions(-DWITH_NEW_CURVES_TYPE)
endif()
blender_add_lib(bf_editor_space_buttons "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 5780b0c9df7..c3479409f0d 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -258,11 +258,9 @@ static bool buttons_context_path_data(ButsContextPath *path, int type)
if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && (ELEM(type, -1, OB_GPENCIL))) {
return true;
}
-#ifdef WITH_NEW_CURVES_TYPE
if (RNA_struct_is_a(ptr->type, &RNA_Curves) && (ELEM(type, -1, OB_CURVES))) {
return true;
}
-#endif
#ifdef WITH_POINT_CLOUD
if (RNA_struct_is_a(ptr->type, &RNA_PointCloud) && (ELEM(type, -1, OB_POINTCLOUD))) {
return true;
@@ -830,9 +828,7 @@ const char *buttons_context_dir[] = {
"line_style",
"collection",
"gpencil",
-#ifdef WITH_NEW_CURVES_TYPE
"curves",
-#endif
#ifdef WITH_POINT_CLOUD
"pointcloud",
#endif
@@ -926,12 +922,10 @@ int /*eContextResult*/ buttons_context(const bContext *C,
set_pointer_type(path, result, &RNA_LightProbe);
return CTX_RESULT_OK;
}
-#ifdef WITH_NEW_CURVES_TYPE
if (CTX_data_equals(member, "curves")) {
set_pointer_type(path, result, &RNA_Curves);
return CTX_RESULT_OK;
}
-#endif
#ifdef WITH_POINT_CLOUD
if (CTX_data_equals(member, "pointcloud")) {
set_pointer_type(path, result, &RNA_PointCloud);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 052af39319c..e60946b8f66 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -778,6 +778,9 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params)
sbuts->preview = 1;
}
break;
+ case NC_WORKSPACE:
+ buttons_area_redraw(area, BCONTEXT_TOOL);
+ break;
case NC_SPACE:
if (wmn->data == ND_SPACE_PROPERTIES) {
ED_area_tag_redraw(area);
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 7800ce797aa..78174160eb8 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -131,7 +131,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *region, MovieClip *clip
{
float x;
int *points, totseg, i, a;
- float sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
+ float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *act_object = BKE_tracking_object_get_active(tracking);
MovieTrackingTrack *act_track = BKE_tracking_track_get_active(&clip->tracking);
@@ -245,14 +245,16 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *region, MovieClip *clip
/* solver keyframes */
immUniformColor4ub(175, 255, 0, 255);
- draw_keyframe(act_object->keyframe1 + clip->start_frame - 1, CFRA, sfra, framelen, 2, pos);
- draw_keyframe(act_object->keyframe2 + clip->start_frame - 1, CFRA, sfra, framelen, 2, pos);
+ draw_keyframe(
+ act_object->keyframe1 + clip->start_frame - 1, scene->r.cfra, sfra, framelen, 2, pos);
+ draw_keyframe(
+ act_object->keyframe2 + clip->start_frame - 1, scene->r.cfra, sfra, framelen, 2, pos);
immUnbindProgram();
/* movie clip animation */
if ((sc->mode == SC_MODE_MASKEDIT) && sc->mask_info.mask) {
- ED_mask_draw_frames(sc->mask_info.mask, region, CFRA, sfra, efra);
+ ED_mask_draw_frames(sc->mask_info.mask, region, scene->r.cfra, sfra, efra);
}
}
@@ -1175,17 +1177,9 @@ static void draw_plane_marker_image(Scene *scene,
ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
if (ibuf) {
- uchar *display_buffer;
void *cache_handle;
-
- if (image->flag & IMA_VIEW_AS_RENDER) {
- display_buffer = IMB_display_buffer_acquire(
- ibuf, &scene->view_settings, &scene->display_settings, &cache_handle);
- }
- else {
- display_buffer = IMB_display_buffer_acquire(
- ibuf, NULL, &scene->display_settings, &cache_handle);
- }
+ uchar *display_buffer = IMB_display_buffer_acquire(
+ ibuf, &scene->view_settings, &scene->display_settings, &cache_handle);
if (display_buffer) {
float frame_corners[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 87e88d094d7..9a690f36aab 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -102,6 +102,16 @@ bool ED_space_clip_maskedit_poll(bContext *C)
return false;
}
+bool ED_space_clip_maskedit_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_clip_maskedit_poll(C)) {
+ return false;
+ }
+
+ const SpaceClip *space_clip = CTX_wm_space_clip(C);
+ return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_clip_maskedit_mask_poll(bContext *C)
{
if (ED_space_clip_maskedit_poll(C)) {
@@ -117,6 +127,16 @@ bool ED_space_clip_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_space_clip_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_clip_maskedit_mask_poll(C)) {
+ return false;
+ }
+
+ const SpaceClip *space_clip = CTX_wm_space_clip(C);
+ return space_clip->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -272,7 +292,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc,
return true;
}
-bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], float r_col[3])
+bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, const int mval[2], float r_col[3])
{
ImBuf *ibuf;
float fx, fy, co[2];
@@ -1026,7 +1046,7 @@ static int prefetch_get_start_frame(const bContext *C)
{
Scene *scene = CTX_data_scene(C);
- return SFRA;
+ return scene->r.sfra;
}
static int prefetch_get_final_frame(const bContext *C)
@@ -1037,10 +1057,10 @@ static int prefetch_get_final_frame(const bContext *C)
int end_frame;
/* check whether all the frames from prefetch range are cached */
- end_frame = EFRA;
+ end_frame = scene->r.efra;
if (clip->len) {
- end_frame = min_ii(end_frame, SFRA + clip->len - 1);
+ end_frame = min_ii(end_frame, scene->r.sfra + clip->len - 1);
}
return end_frame;
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index d07cf09ffa6..67565a88bab 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -629,8 +629,8 @@ static int view_all_exec(bContext *C, wmOperator *UNUSED(op))
NULL);
/* set extents of view to start/end frames */
- v2d->cur.xmin = (float)SFRA;
- v2d->cur.xmax = (float)EFRA;
+ v2d->cur.xmin = (float)scene->r.sfra;
+ v2d->cur.xmax = (float)scene->r.efra;
if (userdata.min < userdata.max) {
v2d->cur.ymin = userdata.min;
@@ -675,8 +675,8 @@ void ED_clip_graph_center_current_frame(Scene *scene, ARegion *region)
float extra = BLI_rctf_size_x(&v2d->cur) / 2.0f;
/* set extents of view to start/end frames */
- v2d->cur.xmin = (float)CFRA - extra;
- v2d->cur.xmax = (float)CFRA + extra;
+ v2d->cur.xmin = (float)scene->r.cfra - extra;
+ v2d->cur.xmax = (float)scene->r.cfra + extra;
}
static int center_current_frame_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 7f9cf61b748..2efd6b6b473 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -251,6 +251,9 @@ void CLIP_OT_slide_plane_marker(struct wmOperatorType *ot);
void CLIP_OT_keyframe_insert(struct wmOperatorType *ot);
void CLIP_OT_keyframe_delete(struct wmOperatorType *ot);
+void CLIP_OT_new_image_from_plane_marker(struct wmOperatorType *ot);
+void CLIP_OT_update_image_from_plane_marker(struct wmOperatorType *ot);
+
/* tracking_select.c */
void CLIP_OT_select(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index e61c264ca06..f276c2acd1a 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -777,7 +777,7 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float_vector(ot->srna,
@@ -834,7 +834,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
prop = RNA_def_float_vector(ot->srna,
@@ -883,7 +883,7 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* flags */
- ot->flag |= OPTYPE_LOCK_BYPASS;
+ ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
RNA_def_float(ot->srna,
@@ -1061,9 +1061,9 @@ static void change_frame_apply(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
/* set the new frame number */
- CFRA = RNA_int_get(op->ptr, "frame");
- FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.0f;
+ scene->r.cfra = RNA_int_get(op->ptr, "frame");
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
+ scene->r.subframe = 0.0f;
/* do updates */
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
@@ -1084,7 +1084,7 @@ static int frame_from_event(bContext *C, const wmEvent *event)
int framenr = 0;
if (region->regiontype == RGN_TYPE_WINDOW) {
- float sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
+ float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
framenr = sfra + event->mval[0] / framelen;
}
@@ -1399,7 +1399,7 @@ static void do_sequence_proxy(void *pjv,
ProxyJob *pj = pjv;
MovieClip *clip = pj->clip;
Scene *scene = pj->scene;
- int sfra = SFRA, efra = EFRA;
+ int sfra = scene->r.sfra, efra = scene->r.efra;
ProxyThread *handles;
int tot_thread = BLI_task_scheduler_num_threads();
int width, height;
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 01f2b24c8a4..221b87a8b5a 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -617,8 +617,8 @@ void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f);
- immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)SFRA, v2d->cur.ymax);
- immRectf(pos, (float)EFRA, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, (float)scene->r.sfra, v2d->cur.ymax);
+ immRectf(pos, (float)scene->r.efra, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
GPU_blend(GPU_BLEND_NONE);
@@ -628,10 +628,10 @@ void clip_draw_sfra_efra(View2D *v2d, Scene *scene)
GPU_line_width(1.0f);
immBegin(GPU_PRIM_LINES, 4);
- immVertex2f(pos, (float)SFRA, v2d->cur.ymin);
- immVertex2f(pos, (float)SFRA, v2d->cur.ymax);
- immVertex2f(pos, (float)EFRA, v2d->cur.ymin);
- immVertex2f(pos, (float)EFRA, v2d->cur.ymax);
+ immVertex2f(pos, (float)scene->r.sfra, v2d->cur.ymin);
+ immVertex2f(pos, (float)scene->r.sfra, v2d->cur.ymax);
+ immVertex2f(pos, (float)scene->r.efra, v2d->cur.ymin);
+ immVertex2f(pos, (float)scene->r.efra, v2d->cur.ymax);
immEnd();
immUnbindProgram();
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 5f52e1a3071..ce6409a7784 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -515,6 +515,9 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_keyframe_insert);
WM_operatortype_append(CLIP_OT_keyframe_delete);
+ WM_operatortype_append(CLIP_OT_new_image_from_plane_marker);
+ WM_operatortype_append(CLIP_OT_update_image_from_plane_marker);
+
/* ** clip_graph_ops.c ** */
/* graph editing */
@@ -860,6 +863,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
sc->mask_info.draw_flag,
sc->mask_info.draw_type,
sc->mask_info.overlay_mode,
+ sc->mask_info.blend_factor,
mask_width,
mask_height,
aspx,
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index ca224b04da5..cba4157d044 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -16,6 +16,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_movieclip.h"
#include "BKE_report.h"
#include "BKE_tracking.h"
@@ -33,6 +34,9 @@
#include "BLT_translation.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "clip_intern.h"
#include "tracking_ops_intern.h"
@@ -1267,7 +1271,8 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
}
delta = pos == 1 ? 1 : -1;
- while (sc->user.framenr + delta >= SFRA && sc->user.framenr + delta <= EFRA) {
+ while (sc->user.framenr + delta >= scene->r.sfra &&
+ sc->user.framenr + delta <= scene->r.efra) {
int framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, sc->user.framenr + delta);
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
@@ -1286,7 +1291,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
delta = pos == 3 ? 1 : -1;
framenr += delta;
- while (framenr + delta >= SFRA && framenr + delta <= EFRA) {
+ while (framenr + delta >= scene->r.sfra && framenr + delta <= scene->r.efra) {
MovieReconstructedCamera *cam = BKE_tracking_camera_get_reconstructed(
tracking, object, framenr);
@@ -1300,8 +1305,8 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
}
}
- if (CFRA != sc->user.framenr) {
- CFRA = sc->user.framenr;
+ if (scene->r.cfra != sc->user.framenr) {
+ scene->r.cfra = sc->user.framenr;
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@@ -2212,3 +2217,144 @@ void CLIP_OT_keyframe_delete(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image from plane track marker
+ * \{ */
+
+static ImBuf *sample_plane_marker_image_for_operator(bContext *C)
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ const int clip_frame_number = ED_space_clip_get_clip_frame_number(space_clip);
+
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track = tracking->act_plane_track;
+ const MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track,
+ clip_frame_number);
+
+ ImBuf *frame_ibuf = ED_space_clip_get_buffer(space_clip);
+ if (frame_ibuf == NULL) {
+ return NULL;
+ }
+
+ ImBuf *plane_ibuf = BKE_tracking_get_plane_imbuf(frame_ibuf, plane_marker);
+
+ IMB_freeImBuf(frame_ibuf);
+
+ return plane_ibuf;
+}
+
+static bool new_image_from_plane_marker_poll(bContext *C)
+{
+ if (!ED_space_clip_tracking_poll(C)) {
+ return false;
+ }
+
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ const MovieTracking *tracking = &clip->tracking;
+
+ if (tracking->act_plane_track == NULL) {
+ return false;
+ }
+
+ return true;
+}
+
+static int new_image_from_plane_marker_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track = tracking->act_plane_track;
+
+ ImBuf *plane_ibuf = sample_plane_marker_image_for_operator(C);
+ if (plane_ibuf == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ plane_track->image = BKE_image_add_from_imbuf(CTX_data_main(C), plane_ibuf, plane_track->name);
+
+ IMB_freeImBuf(plane_ibuf);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_new_image_from_plane_marker(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Image from Plane Marker";
+ ot->description = "Create new image from the content of the plane marker";
+ ot->idname = "CLIP_OT_new_image_from_plane_marker";
+
+ /* api callbacks */
+ ot->poll = new_image_from_plane_marker_poll;
+ ot->exec = new_image_from_plane_marker_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static bool update_image_from_plane_marker_poll(bContext *C)
+{
+ if (!ED_space_clip_tracking_poll(C)) {
+ return false;
+ }
+
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ const MovieTracking *tracking = &clip->tracking;
+
+ if (tracking->act_plane_track == NULL || tracking->act_plane_track->image == NULL) {
+ return false;
+ }
+
+ const Image *image = tracking->act_plane_track->image;
+ return image->type == IMA_TYPE_IMAGE && ELEM(image->source, IMA_SRC_FILE, IMA_SRC_GENERATED);
+}
+
+static int update_image_from_plane_marker_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *space_clip = CTX_wm_space_clip(C);
+ MovieClip *clip = ED_space_clip_get_clip(space_clip);
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingPlaneTrack *plane_track = tracking->act_plane_track;
+
+ ImBuf *plane_ibuf = sample_plane_marker_image_for_operator(C);
+ if (plane_ibuf == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_image_replace_imbuf(plane_track->image, plane_ibuf);
+
+ IMB_freeImBuf(plane_ibuf);
+
+ WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, plane_track->image);
+
+ BKE_image_partial_update_mark_full_update(plane_track->image);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_update_image_from_plane_marker(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Update Image from Plane Marker";
+ ot->description =
+ "Update current image used by plane marker from the content of the plane marker";
+ ot->idname = "CLIP_OT_update_image_from_plane_marker";
+
+ /* api callbacks */
+ ot->poll = update_image_from_plane_marker_poll;
+ ot->exec = update_image_from_plane_marker_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index d5223d57490..f6fd2980c19 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -131,10 +131,10 @@ static bool track_markers_initjob(bContext *C, TrackMarkersJob *tmj, bool backwa
if (sequence) {
if (backwards) {
- tmj->efra = SFRA;
+ tmj->efra = scene->r.sfra;
}
else {
- tmj->efra = EFRA;
+ tmj->efra = scene->r.efra;
}
tmj->efra = BKE_movieclip_remap_scene_to_clip_frame(clip, tmj->efra);
}
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index bbfbbd2cc58..28e304bfa74 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -394,8 +394,6 @@ static int select_exec(bContext *C, wmOperator *op)
else if (deselect_all) {
ed_tracking_deselect_all_tracks(tracksbase);
ed_tracking_deselect_all_plane_tracks(plane_tracks_base);
- /* Mask as well if we are in combined mask / track view. */
- ED_mask_deselect_all(C);
}
ED_clip_view_lock_state_restore_no_jump(C, &lock_state);
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index 17fbef23eac..ef22b1b9f0b 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -413,16 +413,8 @@ static int console_insert_invoke(bContext *C, wmOperator *op, const wmEvent *eve
}
char str[BLI_UTF8_MAX + 1];
- size_t len;
-
- if (event->utf8_buf[0]) {
- len = BLI_str_utf8_size_safe(event->utf8_buf);
- memcpy(str, event->utf8_buf, len);
- }
- else {
- /* in theory, ghost can set value to extended ascii here */
- len = BLI_str_utf8_from_unicode(event->ascii, str, sizeof(str) - 1);
- }
+ const size_t len = BLI_str_utf8_size_safe(event->utf8_buf);
+ memcpy(str, event->utf8_buf, len);
str[len] = '\0';
RNA_string_set(op->ptr, "text", str);
}
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 161dbdc905d..79e32287d26 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -86,12 +86,12 @@ class AssetCatalogTreeViewItem : public ui::BasicTreeViewItem {
bool rename(StringRefNull new_name) override;
/** Add drag support for catalog items. */
- std::unique_ptr<ui::AbstractTreeViewItemDragController> create_drag_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDragController> create_drag_controller() const override;
/** Add dropping support for catalog items. */
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
-class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController {
+class AssetCatalogDragController : public ui::AbstractViewItemDragController {
AssetCatalogTreeItem &catalog_item_;
public:
@@ -103,7 +103,7 @@ class AssetCatalogDragController : public ui::AbstractTreeViewItemDragController
void on_drag_start() override;
};
-class AssetCatalogDropController : public ui::AbstractTreeViewItemDropController {
+class AssetCatalogDropController : public ui::AbstractViewItemDropController {
AssetCatalogTreeItem &catalog_item_;
public:
@@ -142,7 +142,7 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
void build_row(uiLayout &row) override;
- struct DropController : public ui::AbstractTreeViewItemDropController {
+ struct DropController : public ui::AbstractViewItemDropController {
DropController(AssetCatalogTreeView &tree_view);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
@@ -150,13 +150,13 @@ class AssetCatalogTreeViewAllItem : public ui::BasicTreeViewItem {
bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
using BasicTreeViewItem::BasicTreeViewItem;
- struct DropController : public ui::AbstractTreeViewItemDropController {
+ struct DropController : public ui::AbstractViewItemDropController {
DropController(AssetCatalogTreeView &tree_view);
bool can_drop(const wmDrag &drag, const char **r_disabled_hint) const override;
@@ -164,7 +164,7 @@ class AssetCatalogTreeViewUnassignedItem : public ui::BasicTreeViewItem {
bool on_drop(struct bContext *C, const wmDrag &drag) override;
};
- std::unique_ptr<ui::AbstractTreeViewItemDropController> create_drop_controller() const override;
+ std::unique_ptr<ui::AbstractViewItemDropController> create_drop_controller() const override;
};
/* ---------------------------------------------------------------------- */
@@ -272,11 +272,11 @@ void AssetCatalogTreeViewItem::build_row(uiLayout &row)
return;
}
- uiButTreeRow *tree_row_but = tree_row_button();
+ uiButViewItem *view_item_but = view_item_button();
PointerRNA *props;
props = UI_but_extra_operator_icon_add(
- (uiBut *)tree_row_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
+ (uiBut *)view_item_but, "ASSET_OT_catalog_new", WM_OP_INVOKE_DEFAULT, ICON_ADD);
RNA_string_set(props, "parent_path", catalog_item_.catalog_path().c_str());
}
@@ -305,7 +305,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column)
0,
&props);
RNA_string_set(&props, "catalog_id", catalog_id_str_buffer);
- uiItemO(&column, "Rename", ICON_NONE, "UI_OT_tree_view_item_rename");
+ uiItemO(&column, "Rename", ICON_NONE, "UI_OT_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
@@ -333,14 +333,14 @@ bool AssetCatalogTreeViewItem::rename(StringRefNull new_name)
return true;
}
-std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewItem::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogDropController>(
static_cast<AssetCatalogTreeView &>(get_tree_view()), catalog_item_);
}
-std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem::
+std::unique_ptr<ui::AbstractViewItemDragController> AssetCatalogTreeViewItem::
create_drag_controller() const
{
return std::make_unique<AssetCatalogDragController>(
@@ -351,7 +351,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDragController> AssetCatalogTreeViewItem
AssetCatalogDropController::AssetCatalogDropController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
- : ui::AbstractTreeViewItemDropController(tree_view), catalog_item_(catalog_item)
+ : ui::AbstractViewItemDropController(tree_view), catalog_item_(catalog_item)
{
}
@@ -407,18 +407,25 @@ std::string AssetCatalogDropController::drop_tooltip_asset_list(const wmDrag &dr
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() +
- ")";
+ basic_tip += ": " + catalog_item_.get_name();
+
+ /* Display the full catalog path, but only if it's not exactly the same as the already shown name
+ * (i.e. not a root level catalog with no parent). */
+ if (catalog_item_.get_name() != catalog_item_.catalog_path().str()) {
+ basic_tip += " (" + catalog_item_.catalog_path().str() + ")";
+ }
+
+ return basic_tip;
}
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());
+ drag, get_view<AssetCatalogTreeView>(), catalog_item_.get_catalog_id());
}
return drop_assets_into_catalog(C,
- tree_view<AssetCatalogTreeView>(),
+ get_view<AssetCatalogTreeView>(),
drag,
catalog_item_.get_catalog_id(),
catalog_item_.get_simple_name());
@@ -505,14 +512,14 @@ bool AssetCatalogDropController::has_droppable_asset(const wmDrag &drag,
::AssetLibrary &AssetCatalogDropController::get_asset_library() const
{
- return *tree_view<AssetCatalogTreeView>().asset_library_;
+ return *get_view<AssetCatalogTreeView>().asset_library_;
}
/* ---------------------------------------------------------------------- */
AssetCatalogDragController::AssetCatalogDragController(AssetCatalogTreeView &tree_view,
AssetCatalogTreeItem &catalog_item)
- : ui::AbstractTreeViewItemDragController(tree_view), catalog_item_(catalog_item)
+ : ui::AbstractViewItemDragController(tree_view), catalog_item_(catalog_item)
{
}
@@ -531,7 +538,7 @@ void *AssetCatalogDragController::create_drag_data() const
void AssetCatalogDragController::on_drag_start()
{
- AssetCatalogTreeView &tree_view_ = tree_view<AssetCatalogTreeView>();
+ AssetCatalogTreeView &tree_view_ = get_view<AssetCatalogTreeView>();
tree_view_.activate_catalog_by_id(catalog_item_.get_catalog_id());
}
@@ -544,15 +551,15 @@ void AssetCatalogTreeViewAllItem::build_row(uiLayout &row)
PointerRNA *props;
UI_but_extra_operator_icon_add(
- (uiBut *)tree_row_button(), "ASSET_OT_catalogs_save", WM_OP_INVOKE_DEFAULT, ICON_FILE_TICK);
+ (uiBut *)view_item_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);
+ (uiBut *)view_item_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::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewAllItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewAllItem::DropController>(
@@ -560,7 +567,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewAllI
}
AssetCatalogTreeViewAllItem::DropController::DropController(AssetCatalogTreeView &tree_view)
- : ui::AbstractTreeViewItemDropController(tree_view)
+ : ui::AbstractViewItemDropController(tree_view)
{
}
@@ -572,7 +579,7 @@ bool AssetCatalogTreeViewAllItem::DropController::can_drop(const wmDrag &drag,
}
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
- drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ drag, *get_view<AssetCatalogTreeView>().asset_library_);
if (drag_catalog->path.parent() == "") {
*r_disabled_hint = "Catalog is already placed at the highest level";
return false;
@@ -585,7 +592,7 @@ std::string AssetCatalogTreeViewAllItem::DropController::drop_tooltip(const wmDr
{
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
const AssetCatalog *drag_catalog = AssetCatalogDropController::get_drag_catalog(
- drag, *tree_view<AssetCatalogTreeView>().asset_library_);
+ drag, *get_view<AssetCatalogTreeView>().asset_library_);
return std::string(TIP_("Move Catalog")) + " '" + drag_catalog->path.name() + "' " +
TIP_("to the top level of the tree");
@@ -597,14 +604,14 @@ bool AssetCatalogTreeViewAllItem::DropController::on_drop(struct bContext *UNUSE
BLI_assert(drag.type == WM_DRAG_ASSET_CATALOG);
return AssetCatalogDropController::drop_asset_catalog_into_catalog(
drag,
- tree_view<AssetCatalogTreeView>(),
+ get_view<AssetCatalogTreeView>(),
/* No value to drop into the root level. */
std::nullopt);
}
/* ---------------------------------------------------------------------- */
-std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnassignedItem::
+std::unique_ptr<ui::AbstractViewItemDropController> AssetCatalogTreeViewUnassignedItem::
create_drop_controller() const
{
return std::make_unique<AssetCatalogTreeViewUnassignedItem::DropController>(
@@ -612,7 +619,7 @@ std::unique_ptr<ui::AbstractTreeViewItemDropController> AssetCatalogTreeViewUnas
}
AssetCatalogTreeViewUnassignedItem::DropController::DropController(AssetCatalogTreeView &tree_view)
- : ui::AbstractTreeViewItemDropController(tree_view)
+ : ui::AbstractViewItemDropController(tree_view)
{
}
@@ -640,7 +647,7 @@ bool AssetCatalogTreeViewUnassignedItem::DropController::on_drop(struct bContext
{
/* Assign to nil catalog ID. */
return AssetCatalogDropController::drop_assets_into_catalog(
- C, tree_view<AssetCatalogTreeView>(), drag, CatalogID{});
+ C, get_view<AssetCatalogTreeView>(), drag, CatalogID{});
}
} // namespace blender::ed::space_file::asset_browser
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 0e2b98ca349..f3359336b14 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -202,7 +202,7 @@ static void file_draw_string(int sx,
}
const uiStyle *style = UI_style_get();
- fs = style->widgetlabel;
+ fs = style->widget;
BLI_strncpy(fname, string, FILE_MAXFILE);
UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0');
@@ -245,7 +245,7 @@ static void file_draw_string_multiline(int sx,
}
const uiStyle *style = UI_style_get();
- int font_id = style->widgetlabel.uifont_id;
+ int font_id = style->widget.uifont_id;
int len = strlen(string);
rcti textbox;
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 0545bdf2ac0..ce0a2e8fc04 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -83,6 +83,7 @@ void FILE_OT_rename(struct wmOperatorType *ot);
void FILE_OT_smoothscroll(struct wmOperatorType *ot);
void FILE_OT_filepath_drop(struct wmOperatorType *ot);
void FILE_OT_start_filter(struct wmOperatorType *ot);
+void FILE_OT_edit_directory_path(struct wmOperatorType *ot);
void FILE_OT_view_selected(struct wmOperatorType *ot);
void file_directory_enter_handle(bContext *C, void *arg_unused, void *arg_but);
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 578288ca289..59d9a15fbab 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1793,7 +1793,7 @@ static bool file_execute(bContext *C, SpaceFile *sfile)
}
ED_file_change_dir(C);
}
- /* opening file - sends events now, so things get handled on windowqueue level */
+ /* Opening file, sends events now, so things get handled on window-queue level. */
else if (sfile->op) {
wmOperator *op = sfile->op;
char filepath[FILE_MAX];
@@ -2914,9 +2914,9 @@ void FILE_OT_delete(struct wmOperatorType *ot)
static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *area = CTX_wm_area(C);
- SpaceFile *sfile = CTX_wm_space_file(C);
- FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+ const ScrArea *area = CTX_wm_area(C);
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
ARegion *region_ctx = CTX_wm_region(C);
@@ -2950,6 +2950,46 @@ void FILE_OT_start_filter(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Edit Directory Path Operator
+ * \{ */
+
+static int file_edit_directory_path_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ const ScrArea *area = CTX_wm_area(C);
+ const SpaceFile *sfile = CTX_wm_space_file(C);
+ const FileSelectParams *params = ED_fileselect_get_active_params(sfile);
+
+ ARegion *region_ctx = CTX_wm_region(C);
+
+ if (area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+ CTX_wm_region_set(C, region);
+ if (UI_textbutton_activate_rna(C, region, params, "directory")) {
+ break;
+ }
+ }
+ }
+
+ CTX_wm_region_set(C, region_ctx);
+
+ return OPERATOR_FINISHED;
+}
+
+void FILE_OT_edit_directory_path(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Directory Path";
+ ot->description = "Start editing directory field";
+ ot->idname = "FILE_OT_edit_directory_path";
+
+ /* api callbacks */
+ ot->exec = file_edit_directory_path_exec;
+ ot->poll = ED_operator_file_active;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Macro Operators
* \{ */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index bc7dc452ae9..1859e7ccdfc 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -486,6 +486,7 @@ static int groupname_to_code(const char *group);
static uint64_t groupname_to_filter_id(const char *group);
static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size);
+static bool filelist_intern_entry_is_main_file(const FileListInternEntry *intern_entry);
/* ********** Sort helpers ********** */
@@ -1027,13 +1028,6 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis
return is_filtered_lib_type(file, root, filter) && is_filtered_file_relpath(file, filter);
}
-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,
const char *UNUSED(dir),
FileListFilter *filter)
@@ -1050,6 +1044,17 @@ static bool is_filtered_main_assets(FileListInternEntry *file,
is_filtered_asset(file, filter);
}
+static bool is_filtered_asset_library(FileListInternEntry *file,
+ const char *root,
+ FileListFilter *filter)
+{
+ if (filelist_intern_entry_is_main_file(file)) {
+ return is_filtered_main_assets(file, root, filter);
+ }
+
+ return is_filtered_lib_type(file, root, filter) && is_filtered_asset(file, filter);
+}
+
void filelist_tag_needs_filtering(FileList *filelist)
{
filelist->flags |= FL_NEED_FILTERING;
@@ -2807,7 +2812,7 @@ int ED_path_extension_type(const char *path)
return FILE_TYPE_ARCHIVE;
}
if (BLI_path_extension_check_n(
- path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", NULL)) {
+ path, ".obj", ".mtl", ".3ds", ".fbx", ".glb", ".gltf", ".svg", ".stl", NULL)) {
return FILE_TYPE_OBJECT_IO;
}
if (BLI_path_extension_check_array(path, imb_ext_image)) {
@@ -3079,7 +3084,7 @@ static int filelist_readjob_list_dir(const char *root,
}
target = entry->redirection_path;
#ifdef WIN32
- /* On Windows don't show ".lnk" extension for valid shortcuts. */
+ /* On Windows don't show `.lnk` extension for valid shortcuts. */
BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, "");
#endif
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 10cde239987..310c688383b 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -890,7 +890,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
continue;
}
- /* Exclude "all my files" as it makes no sense in blender fileselector */
+ /* Exclude "all my files" as it makes no sense in blender file-selector. */
/* Exclude "airdrop" if wlan not active as it would show "" ) */
if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
fsmenu_insert_entry(
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 0170361f244..a462476aae0 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -695,6 +695,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_smoothscroll);
WM_operatortype_append(FILE_OT_filepath_drop);
WM_operatortype_append(FILE_OT_start_filter);
+ WM_operatortype_append(FILE_OT_edit_directory_path);
WM_operatortype_append(FILE_OT_view_selected);
}
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index bc2705df314..3b8c6cbd1d0 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -277,7 +277,7 @@ static void graphedit_activekey_update_cb(bContext *UNUSED(C),
/* make sure F-Curve and its handles are still valid after this editing */
sort_time_fcurve(fcu);
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
/* update callback for active keyframe properties - handle-editing wrapper */
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index a946ce22139..608a1f4d73e 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -1348,7 +1348,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
int filter;
/* build list of curves to draw */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY);
filter |= ((sel) ? (ANIMFILTER_SEL) : (ANIMFILTER_UNSEL));
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -1393,7 +1393,8 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
size_t items;
/* build list of channels to draw */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index cfc4fcf8dad..64a3c603e73 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -109,8 +109,8 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
eInsertKeyFlags flag = 0;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
if (mode & GRAPHKEYS_INSERTKEY_SEL) {
filter |= ANIMFILTER_SEL;
}
@@ -156,10 +156,10 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
x = sipo->cursorTime;
}
else if (adt) {
- x = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ x = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- x = (float)CFRA;
+ x = (float)scene->r.cfra;
}
/* Normalize units of cursor's value. */
@@ -178,7 +178,7 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
}
else {
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
- ac->depsgraph, (float)CFRA);
+ ac->depsgraph, (float)scene->r.cfra);
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
@@ -211,12 +211,12 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
/* Adjust current frame for NLA-mapping. */
- float cfra = (float)CFRA;
+ float cfra = (float)scene->r.cfra;
if ((sipo) && (sipo->mode == SIPO_MODE_DRIVERS)) {
cfra = sipo->cursorTime;
}
else if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
const float curval = evaluate_fcurve_only_curve(fcu, cfra);
@@ -457,7 +457,8 @@ static short copy_graph_keys(bAnimContext *ac)
* - First time we try to filter more strictly, allowing only selected channels
* to allow copying animation between channels.
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) {
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -472,13 +473,13 @@ static short copy_graph_keys(bAnimContext *ac)
return ok;
}
-static short paste_graph_keys(bAnimContext *ac,
- const eKeyPasteOffset offset_mode,
- const eKeyMergeMode merge_mode,
- bool flip)
+static eKeyPasteError paste_graph_keys(bAnimContext *ac,
+ const eKeyPasteOffset offset_mode,
+ const eKeyMergeMode merge_mode,
+ bool flip)
{
ListBase anim_data = {NULL, NULL};
- int filter, ok = 0;
+ int filter;
/* Filter data
* - First time we try to filter more strictly, allowing only selected channels
@@ -486,15 +487,15 @@ static short paste_graph_keys(bAnimContext *ac,
* - Second time, we loosen things up if nothing was found the first time, allowing
* users to just paste keyframes back into the original curve again T31670.
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0) {
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
}
/* Paste keyframes. */
- ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
+ const eKeyPasteError ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode, flip);
/* Clean up. */
ANIM_animdata_freelist(&anim_data);
@@ -554,9 +555,18 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
/* Ac.reports by default will be the global reports list, which won't show warnings. */
ac.reports = op->reports;
- /* Paste keyframes - non-zero return means an error occurred while trying to paste. */
- if (paste_graph_keys(&ac, offset_mode, merge_mode, flipped)) {
- return OPERATOR_CANCELLED;
+ const eKeyPasteError kf_empty = paste_graph_keys(&ac, offset_mode, merge_mode, flipped);
+ switch (kf_empty) {
+ case KEYFRAME_PASTE_OK:
+ break;
+
+ case KEYFRAME_PASTE_NOWHERE_TO_PASTE:
+ BKE_report(op->reports, RPT_ERROR, "No selected F-Curves to paste into");
+ return OPERATOR_CANCELLED;
+
+ case KEYFRAME_PASTE_NOTHING_TO_PASTE:
+ BKE_report(op->reports, RPT_ERROR, "No data in buffer to paste");
+ return OPERATOR_CANCELLED;
}
/* Set notifier that keyframes have changed. */
@@ -631,8 +641,8 @@ static bool duplicate_graph_keys(bAnimContext *ac)
bool changed = false;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and delete selected keys. */
@@ -702,8 +712,8 @@ static bool delete_graph_keys(bAnimContext *ac)
bool changed_final = false;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and delete selected keys. */
@@ -713,7 +723,7 @@ static bool delete_graph_keys(bAnimContext *ac)
bool changed;
/* Delete selected keyframes only. */
- changed = delete_fcurve_keys(fcu);
+ changed = BKE_fcurve_delete_keys_selected(fcu);
if (changed) {
ale->update |= ANIM_UPDATE_DEFAULT;
@@ -785,8 +795,8 @@ static void clean_graph_keys(bAnimContext *ac, float thresh, bool clean_chan)
int filter;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and clean curves. */
@@ -862,8 +872,8 @@ static void bake_graph_curves(bAnimContext *ac, int start, int end)
int filter;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
@@ -949,8 +959,8 @@ static void unbake_graph_curves(bAnimContext *ac, int start, int end)
bAnimListElem *ale;
/* Filter data. */
- const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
@@ -1096,12 +1106,12 @@ static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
}
/* Determine extents of the baking. */
- sbi.cfra = start = CFRA;
- end = CFRA + sbi.length - 1;
+ sbi.cfra = start = scene->r.cfra;
+ end = scene->r.cfra + sbi.length - 1;
/* Filter anim channels. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Loop through all selected F-Curves, replacing its data with the sound samples. */
@@ -1267,8 +1277,8 @@ static void sample_graph_keys(bAnimContext *ac)
int filter;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
@@ -1364,8 +1374,8 @@ static void setexpo_graph_keys(bAnimContext *ac, short mode)
int filter;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting mode per F-Curve. */
@@ -1469,8 +1479,8 @@ static void setipo_graph_keys(bAnimContext *ac, short mode)
KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode);
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting BezTriple interpolation
@@ -1478,7 +1488,7 @@ static void setipo_graph_keys(bAnimContext *ac, short mode)
* Currently that's not necessary here.
*/
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
}
@@ -1547,8 +1557,8 @@ static void seteasing_graph_keys(bAnimContext *ac, short mode)
KeyframeEditFunc set_cb = ANIM_editkeyframes_easing(mode);
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting BezTriple easing.
@@ -1556,7 +1566,7 @@ static void seteasing_graph_keys(bAnimContext *ac, short mode)
* Currently that's not necessary here.
*/
for (ale = anim_data.first; ale; ale = ale->next) {
- ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
}
@@ -1625,8 +1635,8 @@ static void sethandles_graph_keys(bAnimContext *ac, short mode)
KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through setting flags for handles.
@@ -1639,7 +1649,7 @@ static void sethandles_graph_keys(bAnimContext *ac, short mode)
/* Any selected keyframes for editing? */
if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
/* Change type of selected handles. */
- ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, BKE_fcurve_handles_recalc);
ale->update |= ANIM_UPDATE_DEFAULT;
}
@@ -1945,7 +1955,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
/* Step 1: extract only the rotation f-curves. */
const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVE_VISIBLE |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ ANIMFILTER_FCURVESONLY | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -2056,7 +2066,8 @@ static KeyframeEditData sum_selected_keyframes(bAnimContext *ac)
memset(&ked, 0, sizeof(KeyframeEditData));
/* Loop over action data, averaging values. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -2119,8 +2130,8 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
}
else {
/* Animation Mode - Affects current frame (int) */
- CFRA = round_fl_to_int(sum_time / num_keyframes);
- SUBFRA = 0.0f;
+ scene->r.cfra = round_fl_to_int(sum_time / num_keyframes);
+ scene->r.subframe = 0.0f;
}
sipo->cursorVal = sum_value / (float)num_keyframes;
@@ -2240,8 +2251,8 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
float cursor_value = 0.0f;
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Init custom data for iterating over keyframes. */
@@ -2284,11 +2295,11 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
/* Perform snapping. */
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
}
ale->update |= ANIM_UPDATE_DEFAULT;
@@ -2361,8 +2372,8 @@ static const EnumPropertyItem prop_graphkeys_equalize_handles_sides[] = {
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);
+ const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -2523,8 +2534,8 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
edit_cb = ANIM_editkeyframes_mirror(mode);
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Mirror keyframes. */
@@ -2544,11 +2555,11 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
/* Perform actual mirroring. */
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
else {
- ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+ ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, BKE_fcurve_handles_recalc);
}
ale->update |= ANIM_UPDATE_DEFAULT;
@@ -2620,8 +2631,8 @@ static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op))
}
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Smooth keyframes. */
@@ -2720,7 +2731,8 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
type = RNA_enum_get(op->ptr, "type");
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY);
if (RNA_boolean_get(op->ptr, "only_active")) {
/* FIXME: enforce in this case only a single channel to get handled? */
filter |= ANIMFILTER_ACTIVE;
@@ -2875,14 +2887,14 @@ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
/* Filter data. */
if (RNA_boolean_get(op->ptr, "only_active")) {
/* This should be the default (for buttons) - Just paste to the active FCurve. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_ACTIVE |
+ ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
}
else {
/* This is only if the operator gets called from a hotkey or search -
* Paste to all visible curves. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
}
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -3065,7 +3077,8 @@ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
/* NOTE: We might need a scene update to evaluate the driver flags. */
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Find invalid drivers. */
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 128925d4591..8deea21318c 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -72,21 +72,21 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
* NOTE: sync this part of the code with ANIM_OT_change_frame
*/
/* 1) frame is rounded to the nearest int, since frames are ints */
- CFRA = round_fl_to_int(frame);
+ scene->r.cfra = round_fl_to_int(frame);
if (scene->r.flag & SCER_LOCK_FRAME_SELECTION) {
/* Clip to preview range
* NOTE: Preview range won't go into negative values,
* so only clamping once should be fine.
*/
- CLAMP(CFRA, PSFRA, PEFRA);
+ CLAMP(scene->r.cfra, PSFRA, PEFRA);
}
else {
/* Prevent negative frames */
- FRAMENUMBER_MIN_CLAMP(CFRA);
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
}
- SUBFRA = 0.0f;
+ scene->r.subframe = 0.0f;
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
}
@@ -234,14 +234,16 @@ static int graphview_curves_hide_exec(bContext *C, wmOperator *op)
/* get list of all channels that selection may need to be flushed to
* - hierarchy must not affect what we have access to here...
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
/* filter data
* - of the remaining visible curves, we want to hide the ones that are
* selected/unselected (depending on "unselected" prop)
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_NODUPLIS);
if (unselected) {
filter |= ANIMFILTER_UNSEL;
}
@@ -275,7 +277,8 @@ static int graphview_curves_hide_exec(bContext *C, wmOperator *op)
/* unhide selected */
if (unselected) {
/* turn off requirement for visible */
- filter = ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_LIST_CHANNELS;
+ filter = ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY;
/* flushing has been done */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
@@ -344,13 +347,15 @@ static int graphview_curves_reveal_exec(bContext *C, wmOperator *op)
/* get list of all channels that selection may need to be flushed to
* - hierarchy must not affect what we have access to here...
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
/* filter data
* - just go through all visible channels, ensuring that everything is set to be curve-visible
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index e71c5114b0a..a36bd5c1461 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -172,7 +172,8 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L
* - if the option to only show keyframes that belong to selected F-Curves is enabled,
* include the 'only selected' flag...
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
if (sipo->flag &
SIPO_SELCUVERTSONLY) { /* FIXME: this should really be check for by the filtering code... */
filter |= ANIMFILTER_SEL;
@@ -342,7 +343,8 @@ void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channel
KeyframeEditFunc test_cb, sel_cb;
/* determine type-based settings */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
/* filter data */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -498,7 +500,8 @@ static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rec
static int initialize_animdata_selection_filter(const SpaceGraph *sipo)
{
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
if (sipo->flag & SIPO_SELCUVERTSONLY) {
filter |= ANIMFILTER_FOREDIT | ANIMFILTER_SELEDIT;
}
@@ -1150,7 +1153,8 @@ static void markers_selectkeys_between(bAnimContext *ac)
ked.f2 = max;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select keys in-between */
@@ -1189,7 +1193,8 @@ static void columnselect_graph_keys(bAnimContext *ac, short mode)
/* build list of columns */
switch (mode) {
case GRAPHKEYS_COLUMNSEL_KEYS: /* list of selected keys */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1204,7 +1209,7 @@ static void columnselect_graph_keys(bAnimContext *ac, short mode)
ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
BLI_addtail(&ked.list, ce);
- ce->cfra = (float)CFRA;
+ ce->cfra = (float)scene->r.cfra;
break;
case GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
@@ -1222,7 +1227,8 @@ static void columnselect_graph_keys(bAnimContext *ac, short mode)
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1314,7 +1320,8 @@ static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
}
/* loop through all of the keys and select additional keyframes based on these */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1372,7 +1379,8 @@ static void select_moreless_graph_keys(bAnimContext *ac, short mode)
memset(&ked, 0, sizeof(KeyframeEditData));
/* loop through all of the keys and select additional keyframes based on these */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -1513,15 +1521,15 @@ static void graphkeys_select_leftright(bAnimContext *ac, short leftright, short
if (leftright == GRAPHKEYS_LRSEL_LEFT) {
ked.f1 = MINAFRAMEF;
- ked.f2 = (float)(CFRA + 0.1f);
+ ked.f2 = (float)(scene->r.cfra + 0.1f);
}
else {
- ked.f1 = (float)(CFRA - 0.1f);
+ ked.f1 = (float)(scene->r.cfra - 0.1f);
ked.f2 = MAXFRAMEF;
}
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select keys */
@@ -1597,7 +1605,7 @@ static int graphkeys_select_leftright_invoke(bContext *C, wmOperator *op, const
/* determine which side of the current frame mouse is on */
x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
- if (x < CFRA) {
+ if (x < scene->r.cfra) {
RNA_enum_set(op->ptr, "mode", GRAPHKEYS_LRSEL_LEFT);
}
else {
@@ -1797,7 +1805,8 @@ static int mouse_graph_keys(bAnimContext *ac,
* otherwise the active flag won't be set T26452. */
if (!run_modal && (nvi->fcu->flag & FCURVE_SELECTED) && something_was_selected) {
/* NOTE: Sync the filter flags with findnearest_fcurve_vert. */
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, nvi->ctype);
}
@@ -1873,7 +1882,8 @@ static int graphkeys_mselect_column(bAnimContext *ac,
/* loop through all of the keys and select additional keyframes
* based on the keys found to be selected above
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 313f6ca1561..f3d92911155 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -48,8 +48,8 @@
/* 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)
+ (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY | \
+ ANIMFILTER_FOREDIT | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS)
/* This data type is only used for modal operation. */
typedef struct tGraphSliderOp {
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index d8baa4c643d..82067661d57 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -81,7 +81,8 @@ void ED_drivers_editor_init(bContext *C, ScrArea *area)
bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE |
+ ANIMFILTER_FCURVESONLY);
size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* We take the first F-Curve only, since some other ones may have had 'active' flag set
@@ -131,7 +132,7 @@ bool graphop_visible_keyframes_poll(bContext *C)
/* loop over the visible (selection doesn't matter) F-Curves, and see if they're suitable
* stopping on the first successful match
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0) {
return found;
@@ -183,7 +184,8 @@ bool graphop_editable_keyframes_poll(bContext *C)
/* loop over the editable F-Curves, and see if they're suitable
* stopping on the first successful match
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0) {
CTX_wm_operator_poll_msg_set(C, "There is no animation data to operate on");
@@ -286,7 +288,8 @@ bool graphop_selected_fcurve_poll(bContext *C)
/* Get the editable + selected F-Curves, and as long as we got some, we can return.
* NOTE: curve-visible flag isn't included,
* otherwise selecting a curve via list to edit is too cumbersome. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0) {
return false;
diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c
index 18465018d35..f80c7c17c3a 100644
--- a/source/blender/editors/space_graph/graph_view.c
+++ b/source/blender/editors/space_graph/graph_view.c
@@ -56,7 +56,8 @@ void get_graph_keyframe_extents(bAnimContext *ac,
int filter;
/* Get data to filter, from Dopesheet. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_NODUPLIS);
if (sipo->flag & SIPO_SELCUVERTSONLY) {
filter |= ANIMFILTER_SEL;
}
@@ -398,8 +399,8 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
}
/* Filter data. */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY |
+ ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Loop through filtered data and add keys between selected keyframes on every frame. */
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index c385420b18e..39fb41245bf 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -61,7 +61,7 @@ if(WITH_IMAGE_CINEON)
endif()
if(WITH_IMAGE_WEBP)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
blender_add_lib(bf_editor_space_image "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 208928afc1f..0a774ee679c 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -845,7 +845,10 @@ void uiTemplateImage(uiLayout *layout,
row = uiLayoutRow(row, true);
uiLayoutSetEnabled(row, is_packed == false);
- uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
+
+ prop = RNA_struct_find_property(&imaptr, "filepath");
+ uiDefAutoButR(block, &imaptr, prop, -1, "", ICON_NONE, 0, 0, 200, UI_UNIT_Y);
+ uiItemO(row, "", ICON_FILEBROWSER, "image.file_browse");
uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
}
@@ -1215,7 +1218,7 @@ void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *i
if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
/* don't use iuser->framenr directly because it may not be updated if auto-refresh is off */
Scene *scene = CTX_data_scene(C);
- const int framenr = BKE_image_user_frame_get(iuser, CFRA, NULL);
+ const int framenr = BKE_image_user_frame_get(iuser, scene->r.cfra, NULL);
char str[MAX_IMAGE_INFO_LEN];
int duration = 0;
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 048c7345b97..f6f9428213f 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -515,7 +515,8 @@ void draw_image_cache(const bContext *C, ARegion *region)
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
Image *image = ED_space_image(sima);
- float x, cfra = CFRA, sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
+ float x, cfra = scene->r.cfra, sfra = scene->r.sfra, efra = scene->r.efra,
+ framelen = region->winx / (efra - sfra + 1);
Mask *mask = NULL;
if (!ED_space_image_show_cache(sima)) {
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index e851b99d3ba..0de50474ab8 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -20,6 +20,7 @@
#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_scene.h"
#include "IMB_imbuf_types.h"
@@ -212,13 +213,7 @@ void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
}
else if (sima->image && sima->image->type == IMA_TYPE_R_RESULT && scene) {
/* not very important, just nice */
- *r_width = (scene->r.xsch * scene->r.size) / 100;
- *r_height = (scene->r.ysch * scene->r.size) / 100;
-
- if ((scene->r.mode & R_BORDER) && (scene->r.mode & R_CROP)) {
- *r_width *= BLI_rctf_size_x(&scene->r.border);
- *r_height *= BLI_rctf_size_y(&scene->r.border);
- }
+ BKE_render_resolution(&scene->r, true, r_width, r_height);
}
/* I know a bit weak... but preview uses not actual image size */
// XXX else if (image_preview_active(sima, r_width, r_height));
@@ -483,6 +478,16 @@ bool ED_space_image_maskedit_poll(bContext *C)
return false;
}
+bool ED_space_image_maskedit_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_image_maskedit_poll(C)) {
+ return false;
+ }
+
+ const SpaceImage *space_image = CTX_wm_space_image(C);
+ return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_image_paint_curve(const bContext *C)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -508,6 +513,16 @@ bool ED_space_image_maskedit_mask_poll(bContext *C)
return false;
}
+bool ED_space_image_maskedit_mask_visible_splines_poll(bContext *C)
+{
+ if (!ED_space_image_maskedit_mask_poll(C)) {
+ return false;
+ }
+
+ const SpaceImage *space_image = CTX_wm_space_image(C);
+ return space_image->mask_info.draw_flag & MASK_DRAWFLAG_SPLINE;
+}
+
bool ED_space_image_cursor_poll(bContext *C)
{
return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 2322420069e..364bec1377d 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -49,6 +49,7 @@ void IMAGE_OT_new(struct wmOperatorType *ot);
* Called by other space types too.
*/
void IMAGE_OT_open(struct wmOperatorType *ot);
+void IMAGE_OT_file_browse(struct wmOperatorType *ot);
/**
* Called by other space types too.
*/
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 336331e44e7..4036f859231 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -45,6 +45,7 @@
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
+#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@@ -197,6 +198,27 @@ static ImageUser *image_user_from_context(const bContext *C)
return (sima) ? &sima->iuser : NULL;
}
+static ImageUser image_user_from_context_and_active_tile(const bContext *C, Image *ima)
+{
+ /* Try to get image user from context if available, otherwise use default. */
+ ImageUser *iuser_context = image_user_from_context(C);
+ ImageUser iuser;
+ if (iuser_context) {
+ iuser = *iuser_context;
+ }
+ else {
+ BKE_imageuser_default(&iuser);
+ }
+
+ /* Use the file associated with the active tile. Otherwise use the first tile. */
+ if (ima && ima->source == IMA_SRC_TILED) {
+ const ImageTile *active = (ImageTile *)BLI_findlink(&ima->tiles, ima->active_tile_index);
+ iuser.tile = active ? active->tile_number : ((ImageTile *)ima->tiles.first)->tile_number;
+ }
+
+ return iuser;
+}
+
static bool image_from_context_has_data_poll(bContext *C)
{
Image *ima = image_from_context(C);
@@ -214,13 +236,14 @@ static bool image_from_context_has_data_poll(bContext *C)
}
/**
- * Use this when the image buffer is accessed without the image user.
+ * Use this when the image buffer is accessing the active tile without the image user.
*/
-static bool image_from_context_has_data_poll_no_image_user(bContext *C)
+static bool image_from_context_has_data_poll_active_tile(bContext *C)
{
Image *ima = image_from_context(C);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
- return BKE_image_has_ibuf(ima, NULL);
+ return BKE_image_has_ibuf(ima, &iuser);
}
static bool image_not_packed_poll(bContext *C)
@@ -949,7 +972,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
static bool image_view_selected_poll(bContext *C)
{
- return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_operator_mask(C)));
+ return (space_image_main_region_poll(C) && (ED_operator_uvedit(C) || ED_maskedit_poll(C)));
}
void IMAGE_OT_view_selected(wmOperatorType *ot)
@@ -1274,8 +1297,8 @@ static Image *image_open_single(Main *bmain,
BKE_image_free_views(ima);
}
- if ((range->length > 1) && (ima->source == IMA_SRC_FILE)) {
- if (range->udim_tiles.first) {
+ if (ima->source == IMA_SRC_FILE) {
+ if (range->udims_detected && range->udim_tiles.first) {
ima->source = IMA_SRC_TILED;
ImageTile *first_tile = ima->tiles.first;
first_tile->tile_number = range->offset;
@@ -1283,7 +1306,7 @@ static Image *image_open_single(Main *bmain,
BKE_image_add_tile(ima, POINTER_AS_INT(node->data), NULL);
}
}
- else {
+ else if (range->length > 1) {
ima->source = IMA_SRC_SEQUENCE;
}
}
@@ -1446,7 +1469,7 @@ static int image_open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
image_open_init(C, op);
- /* show multiview save options only if scene has multiviews */
+ /* Show multi-view save options only if scene has multi-views. */
PropertyRNA *prop;
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
@@ -1535,6 +1558,115 @@ void IMAGE_OT_open(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Browse Image Operator
+ * \{ */
+
+static int image_file_browse_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = op->customdata;
+ if (ima == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char filepath[FILE_MAX];
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ /* If loading into a tiled texture, ensure that the filename is tokenized. */
+ if (ima->source == IMA_SRC_TILED) {
+ char *filename = (char *)BLI_path_basename(filepath);
+ BKE_image_ensure_tile_token(filename);
+ }
+
+ PointerRNA imaptr;
+ PropertyRNA *imaprop;
+ RNA_id_pointer_create(&ima->id, &imaptr);
+ imaprop = RNA_struct_find_property(&imaptr, "filepath");
+
+ RNA_property_string_set(&imaptr, imaprop, filepath);
+ RNA_property_update(C, &imaptr, imaprop);
+
+ return OPERATOR_FINISHED;
+}
+
+static int image_file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Image *ima = image_from_context(C);
+ if (!ima) {
+ return OPERATOR_CANCELLED;
+ }
+
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, ima->filepath, sizeof(filepath));
+
+ /* Shift+Click to open the file, Alt+Click to browse a folder in the OS's browser. */
+ if (event->modifier & (KM_SHIFT | KM_ALT)) {
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true);
+ PointerRNA props_ptr;
+
+ if (event->modifier & KM_ALT) {
+ char *lslash = (char *)BLI_path_slash_rfind(filepath);
+ if (lslash) {
+ *lslash = '\0';
+ }
+ }
+ else if (ima->source == IMA_SRC_TILED) {
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
+ BKE_image_user_file_path(&iuser, ima, filepath);
+ }
+
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_string_set(&props_ptr, "filepath", filepath);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr, NULL);
+ WM_operator_properties_free(&props_ptr);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ /* The image is typically passed to the operator via layout/button context (e.g.
+ * #uiLayoutSetContextPointer()). The File Browser doesn't support restoring this context
+ * when calling `exec()` though, so we have to pass it the image via custom data. */
+ op->customdata = ima;
+
+ image_filesel(C, op, filepath);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static bool image_file_browse_poll(bContext *C)
+{
+ return image_from_context(C) != NULL;
+}
+
+void IMAGE_OT_file_browse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Browse Image";
+ ot->description =
+ "Open an image file browser, hold Shift to open the file, Alt to browse containing "
+ "directory";
+ ot->idname = "IMAGE_OT_file_browse";
+
+ /* api callbacks */
+ ot->exec = image_file_browse_exec;
+ ot->invoke = image_file_browse_invoke;
+ ot->poll = image_file_browse_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
+ FILE_SPECIAL,
+ FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_DEFAULT);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Match Movie Length Operator
* \{ */
@@ -1696,11 +1828,10 @@ static void image_save_options_from_op(Main *bmain, ImageSaveOptions *opts, wmOp
RNA_boolean_get(op->ptr, "copy"));
opts->save_as_render = (RNA_struct_find_property(op->ptr, "save_as_render") &&
RNA_boolean_get(op->ptr, "save_as_render"));
- opts->do_newpath = true;
}
static bool save_image_op(
- Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, ImageSaveOptions *opts)
+ Main *bmain, Image *ima, ImageUser *iuser, wmOperator *op, const ImageSaveOptions *opts)
{
WM_cursor_wait(true);
@@ -1727,12 +1858,14 @@ static ImageSaveData *image_save_as_init(bContext *C, wmOperator *op)
isd->image = image;
isd->iuser = iuser;
- if (!BKE_image_save_options_init(&isd->opts, bmain, scene, image, iuser, true)) {
+ if (!BKE_image_save_options_init(&isd->opts, bmain, scene, image, iuser, true, false)) {
BKE_image_save_options_free(&isd->opts);
MEM_freeN(isd);
return NULL;
}
+ isd->opts.do_newpath = true;
+
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
RNA_string_set(op->ptr, "filepath", isd->opts.filepath);
}
@@ -1994,7 +2127,7 @@ static int image_save_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- if (!BKE_image_save_options_init(&opts, bmain, scene, image, iuser, false)) {
+ if (!BKE_image_save_options_init(&opts, bmain, scene, image, iuser, false, false)) {
BKE_image_save_options_free(&opts);
return OPERATOR_CANCELLED;
}
@@ -2266,7 +2399,7 @@ bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
if (image_has_valid_path(ima)) {
ImageSaveOptions opts;
Scene *scene = CTX_data_scene(C);
- if (!BKE_image_save_options_init(&opts, bmain, scene, ima, NULL, false)) {
+ if (BKE_image_save_options_init(&opts, bmain, scene, ima, NULL, false, false)) {
bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts);
ok = ok && saved_successfully;
}
@@ -2573,7 +2706,8 @@ void IMAGE_OT_new(wmOperatorType *ot)
static int image_flip_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2590,7 +2724,7 @@ static int image_flip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
if (is_paint) {
ED_imapaint_clear_partial_redraw();
@@ -2670,7 +2804,7 @@ void IMAGE_OT_flip(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_flip_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
PropertyRNA *prop;
@@ -2693,7 +2827,8 @@ void IMAGE_OT_flip(wmOperatorType *ot)
static int image_invert_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2710,7 +2845,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
if (is_paint) {
ED_imapaint_clear_partial_redraw();
@@ -2791,7 +2926,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_invert_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert red channel");
@@ -2816,9 +2951,10 @@ void IMAGE_OT_invert(wmOperatorType *ot)
static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Image *ima = image_from_context(C);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
if (!RNA_property_is_set(op->ptr, prop)) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
const int size[2] = {ibuf->x, ibuf->y};
RNA_property_int_set_array(op->ptr, prop, size);
BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -2829,7 +2965,8 @@ static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
static int image_scale_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ ImageUser iuser = image_user_from_context_and_active_tile(C, ima);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
@@ -2853,7 +2990,7 @@ static int image_scale_exec(bContext *C, wmOperator *op)
RNA_property_int_set_array(op->ptr, prop, size);
}
- ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &sima->iuser);
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf, &iuser);
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
IMB_scaleImBuf(ibuf, size[0], size[1]);
@@ -2879,7 +3016,7 @@ void IMAGE_OT_resize(wmOperatorType *ot)
/* api callbacks */
ot->invoke = image_scale_invoke;
ot->exec = image_scale_exec;
- ot->poll = image_from_context_has_data_poll_no_image_user;
+ ot->poll = image_from_context_has_data_poll_active_tile;
/* properties */
RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
@@ -3075,7 +3212,7 @@ bool ED_space_image_get_position(SpaceImage *sima,
}
bool ED_space_image_color_sample(
- SpaceImage *sima, ARegion *region, int mval[2], float r_col[3], bool *r_is_data)
+ SpaceImage *sima, ARegion *region, const int mval[2], float r_col[3], bool *r_is_data)
{
if (r_is_data) {
*r_is_data = false;
@@ -3335,10 +3472,10 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = image_from_context(C);
+ ImageUser *iuser = image_user_from_context(C);
- if (!BKE_image_clear_renderslot(ima, &sima->iuser, ima->render_slot)) {
+ if (!BKE_image_clear_renderslot(ima, iuser, ima->render_slot)) {
return OPERATOR_CANCELLED;
}
@@ -3403,10 +3540,10 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot)
static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
- SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = image_from_context(C);
+ ImageUser *iuser = image_user_from_context(C);
- if (!BKE_image_remove_renderslot(ima, &sima->iuser, ima->render_slot)) {
+ if (!BKE_image_remove_renderslot(ima, iuser, ima->render_slot)) {
return OPERATOR_CANCELLED;
}
@@ -3451,9 +3588,9 @@ static void change_frame_apply(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
/* set the new frame number */
- CFRA = RNA_int_get(op->ptr, "frame");
- FRAMENUMBER_MIN_CLAMP(CFRA);
- SUBFRA = 0.0f;
+ scene->r.cfra = RNA_int_get(op->ptr, "frame");
+ FRAMENUMBER_MIN_CLAMP(scene->r.cfra);
+ scene->r.subframe = 0.0f;
/* do updates */
DEG_id_tag_update(&scene->id, ID_RECALC_FRAME_CHANGE);
@@ -3474,7 +3611,7 @@ static int frame_from_event(bContext *C, const wmEvent *event)
int framenr = 0;
if (region->regiontype == RGN_TYPE_WINDOW) {
- float sfra = SFRA, efra = EFRA, framelen = region->winx / (efra - sfra + 1);
+ float sfra = scene->r.sfra, efra = scene->r.efra, framelen = region->winx / (efra - sfra + 1);
framenr = sfra + event->mval[0] / framelen;
}
@@ -3596,38 +3733,52 @@ static int render_border_exec(bContext *C, wmOperator *op)
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
Render *re = RE_GetSceneRender(scene);
- RenderData *rd;
- rctf border;
+ SpaceImage *sima = CTX_wm_space_image(C);
if (re == NULL) {
/* Shouldn't happen, but better be safe close to the release. */
return OPERATOR_CANCELLED;
}
- rd = RE_engine_get_render_data(re);
- if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
- BKE_report(op->reports, RPT_INFO, "Can not set border from a cropped render");
- return OPERATOR_CANCELLED;
- }
+ /* Get information about the previous render, or current scene if no render yet. */
+ int width, height;
+ BKE_render_resolution(&scene->r, false, &width, &height);
+ const RenderData *rd = ED_space_image_has_buffer(sima) ? RE_engine_get_render_data(re) :
+ &scene->r;
- /* get rectangle from operator */
+ /* Get rectangle from the operator. */
+ rctf border;
WM_operator_properties_border_to_rctf(op, &border);
UI_view2d_region_to_view_rctf(&region->v2d, &border, &border);
- /* actually set border */
+ /* Adjust for cropping. */
+ if ((rd->mode & (R_BORDER | R_CROP)) == (R_BORDER | R_CROP)) {
+ border.xmin = rd->border.xmin + border.xmin * (rd->border.xmax - rd->border.xmin);
+ border.xmax = rd->border.xmin + border.xmax * (rd->border.xmax - rd->border.xmin);
+ border.ymin = rd->border.ymin + border.ymin * (rd->border.ymax - rd->border.ymin);
+ border.ymax = rd->border.ymin + border.ymax * (rd->border.ymax - rd->border.ymin);
+ }
+
CLAMP(border.xmin, 0.0f, 1.0f);
CLAMP(border.ymin, 0.0f, 1.0f);
CLAMP(border.xmax, 0.0f, 1.0f);
CLAMP(border.ymax, 0.0f, 1.0f);
- scene->r.border = border;
- /* drawing a border surrounding the entire camera view switches off border rendering
- * or the border covers no pixels */
+ /* Drawing a border surrounding the entire camera view switches off border rendering
+ * or the border covers no pixels. */
if ((border.xmin <= 0.0f && border.xmax >= 1.0f && border.ymin <= 0.0f && border.ymax >= 1.0f) ||
(border.xmin == border.xmax || border.ymin == border.ymax)) {
scene->r.mode &= ~R_BORDER;
}
else {
+ /* Snap border to pixel boundaries, so drawing a border within a pixel selects that pixel. */
+ border.xmin = floorf(border.xmin * width) / width;
+ border.xmax = ceilf(border.xmax * width) / width;
+ border.ymin = floorf(border.ymin * height) / height;
+ border.ymax = ceilf(border.ymax * height) / height;
+
+ /* Set border. */
+ scene->r.border = border;
scene->r.mode |= R_BORDER;
}
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index 365cf2542b2..fbeef47e278 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -107,10 +107,10 @@ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_u
/* UDIM */
if (detect_udim) {
int udim_start, udim_range;
- bool result = BKE_image_get_tile_info(
+ range->udims_detected = BKE_image_get_tile_info(
range->filepath, &range->udim_tiles, &udim_start, &udim_range);
- if (result) {
+ if (range->udims_detected) {
range->offset = udim_start;
range->length = udim_range;
return;
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 1fd9fde084b..a7a8bde1115 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -287,7 +287,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
}
if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* Force MIP-MAP recreation. */
}
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 63f919a1713..785a5419e04 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -199,6 +199,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_new);
WM_operatortype_append(IMAGE_OT_open);
+ WM_operatortype_append(IMAGE_OT_file_browse);
WM_operatortype_append(IMAGE_OT_match_movie_length);
WM_operatortype_append(IMAGE_OT_replace);
WM_operatortype_append(IMAGE_OT_reload);
@@ -315,6 +316,9 @@ static void image_listener(const wmSpaceTypeListenerParams *params)
ED_area_tag_redraw(area);
break;
case ND_MODE:
+ ED_paint_cursor_start(&params->scene->toolsettings->imapaint.paint,
+ ED_image_tools_paint_poll);
+
if (wmn->subtype == NS_EDITMODE_MESH) {
ED_area_tag_refresh(area);
}
@@ -690,6 +694,7 @@ static void image_main_region_draw(const bContext *C, ARegion *region)
sima->mask_info.draw_flag & ~MASK_DRAWFLAG_OVERLAY,
sima->mask_info.draw_type,
sima->mask_info.overlay_mode,
+ sima->mask_info.blend_factor,
width,
height,
aspx,
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index b817ff887ce..29a7eb150a1 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -46,6 +46,7 @@
#include "BKE_pbvh.h"
#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
+#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph_query.h"
@@ -92,15 +93,18 @@ static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *st
}
int totvert, totedge, totface, totloop;
- if (me_eval->runtime.subdiv_ccg != nullptr) {
- const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+
+ const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg;
+ const SubsurfRuntimeData *subsurf_runtime_data = me_eval->runtime.subsurf_runtime_data;
+
+ if (subdiv_ccg != nullptr) {
BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop);
}
- else if (me_eval->runtime.subsurf_resolution != 0) {
- totvert = me_eval->runtime.subsurf_totvert;
- totedge = me_eval->runtime.subsurf_totedge;
- totface = me_eval->runtime.subsurf_totpoly;
- totloop = me_eval->runtime.subsurf_totloop;
+ else if (subsurf_runtime_data && subsurf_runtime_data->resolution != 0) {
+ totvert = subsurf_runtime_data->stats_totvert;
+ totedge = subsurf_runtime_data->stats_totedge;
+ totface = subsurf_runtime_data->stats_totpoly;
+ totloop = subsurf_runtime_data->stats_totloop;
}
else {
totvert = me_eval->totvert;
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index 8fc61f78a6c..bc2b539474c 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -245,9 +245,6 @@ static bool textview_draw_string(TextViewDrawState *tds,
const int final_offset = offsets[tot_lines - 1];
len = str_len - final_offset;
s = str + final_offset;
- BLF_position(tds->font_id, tds->xy[0], tds->lofs + line_bottom + tds->row_vpadding, 0);
- BLF_color4ubv(tds->font_id, fg);
- BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
if (tds->sel[0] != tds->sel[1]) {
textview_step_sel(tds, -final_offset);
@@ -255,6 +252,10 @@ static bool textview_draw_string(TextViewDrawState *tds,
textview_draw_sel(s, pos, len, tds, bg_sel);
}
+ BLF_position(tds->font_id, tds->xy[0], tds->lofs + line_bottom + tds->row_vpadding, 0);
+ BLF_color4ubv(tds->font_id, fg);
+ BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
+
tds->xy[1] += tds->lheight;
BLF_color4ubv(tds->font_id, fg);
@@ -263,14 +264,14 @@ static bool textview_draw_string(TextViewDrawState *tds,
len = offsets[i] - offsets[i - 1];
s = str + offsets[i - 1];
- BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
- BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
-
if (tds->sel[0] != tds->sel[1]) {
textview_step_sel(tds, len);
textview_draw_sel(s, tds->xy, len, tds, bg_sel);
}
+ BLF_position(tds->font_id, tds->xy[0], tds->lofs + tds->xy[1], 0);
+ BLF_draw_mono(tds->font_id, s, len, tds->cwidth);
+
tds->xy[1] += tds->lheight;
/* Check if we're out of view bounds. */
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index f89bfd2a36a..9652819404e 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -79,7 +79,7 @@ bool nla_panel_context(const bContext *C,
*/
/* XXX: double-check active! */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ACTIVE |
- ANIMFILTER_LIST_CHANNELS);
+ ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -393,8 +393,8 @@ static void nla_panel_properties(const bContext *C, Panel *panel)
/* strip extents */
column = uiLayoutColumn(layout, true);
- uiItemR(column, &strip_ptr, "frame_start", 0, IFACE_("Frame Start"), ICON_NONE);
- uiItemR(column, &strip_ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "frame_start_ui", 0, IFACE_("Frame Start"), ICON_NONE);
+ uiItemR(column, &strip_ptr, "frame_end_ui", 0, IFACE_("End"), ICON_NONE);
/* Evaluation-Related Strip Properties ------------------ */
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 40082b08806..a0c6a29c422 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -68,7 +68,8 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index,
/* get the channel that was clicked on */
/* filter channels */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* get channel from index */
@@ -394,7 +395,8 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
int filter;
/* filter channels */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* get channel from index */
@@ -561,7 +563,7 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
/* get a list of the (selected) NLA Tracks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* add tracks... */
@@ -608,7 +610,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac)
/* get a list of the selected AnimData blocks in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA |
- ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+ ANIMFILTER_SEL | ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* check if selected AnimData blocks are empty, and add tracks if so... */
@@ -710,7 +712,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
/* get a list of the AnimData blocks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* delete tracks */
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 6c631f46069..3b108a3ba8a 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -617,11 +617,10 @@ static void nla_draw_strip(SpaceNla *snla,
immUnbindProgram();
}
-/* add the relevant text to the cache of text-strings to draw in pixelspace */
+/** Add the relevant text to the cache of text-strings to draw in pixel-space. */
static void nla_draw_strip_text(AnimData *adt,
NlaTrack *nlt,
NlaStrip *strip,
- int index,
View2D *v2d,
float xminc,
float xmaxc,
@@ -636,7 +635,7 @@ static void nla_draw_strip_text(AnimData *adt,
/* just print the name and the range */
if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- str_len = BLI_snprintf_rlen(str, sizeof(str), "%d) Temp-Meta", index);
+ str_len = BLI_snprintf_rlen(str, sizeof(str), "Temp-Meta");
}
else {
str_len = BLI_strncpy_rlen(str, strip->name, sizeof(str));
@@ -702,6 +701,89 @@ static void nla_draw_strip_frames_text(
/* ---------------------- */
+/**
+ * Gets the first and last visible NLA strips on a track.
+ * Note that this also includes tracks that might only be
+ * visible because of their extendmode.
+ */
+static ListBase get_visible_nla_strips(NlaTrack *nlt, View2D *v2d)
+{
+ if (BLI_listbase_is_empty(&nlt->strips)) {
+ ListBase empty = {NULL, NULL};
+ return empty;
+ }
+
+ NlaStrip *first = NULL;
+ NlaStrip *last = NULL;
+
+ /* Find the first strip that is within the bounds of the view. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
+ if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
+ first = last = strip;
+ break;
+ }
+ }
+
+ const bool has_strips_within_bounds = first != NULL;
+
+ if (has_strips_within_bounds) {
+ /* Find the last visible strip. */
+ for (NlaStrip *strip = first->next; strip; strip = strip->next) {
+ if (!BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
+ break;
+ }
+ last = strip;
+ }
+ /* Check if the first strip is adjacent to a strip outside the view to the left
+ * that has an extendmode region that should be drawn.
+ * If so, adjust the first strip to include drawing that strip as well.
+ */
+ NlaStrip *prev = first->prev;
+ if (prev && prev->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ first = prev;
+ }
+ }
+ else {
+ /* No immediately visible strips.
+ * Figure out where our view is relative to the strips, then determine
+ * if the view is adjacent to a strip that should have its extendmode
+ * rendered.
+ */
+ NlaStrip *first_strip = nlt->strips.first;
+ NlaStrip *last_strip = nlt->strips.last;
+ if (first_strip && v2d->cur.xmax < first_strip->start &&
+ first_strip->extendmode == NLASTRIP_EXTEND_HOLD) {
+ /* The view is to the left of all strips and the first strip has an
+ * extendmode that should be drawn.
+ */
+ first = last = first_strip;
+ }
+ else if (last_strip && v2d->cur.xmin > last_strip->end &&
+ last_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ /* The view is to the right of all strips and the last strip has an
+ * extendmode that should be drawn.
+ */
+ first = last = last_strip;
+ }
+ else {
+ /* The view is in the middle of two strips. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
+ /* Find the strip to the left by finding the strip to the right and getting its prev. */
+ if (v2d->cur.xmax < strip->start) {
+ /* If the strip to the left has an extendmode, set that as the only visible strip. */
+ if (strip->prev && strip->prev->extendmode != NLASTRIP_EXTEND_NOTHING) {
+ first = last = strip->prev;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ ListBase visible_strips = {first, last};
+ return visible_strips;
+}
+
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
{
View2D *v2d = &region->v2d;
@@ -710,7 +792,8 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
/* build list of channels to draw */
ListBase anim_data = {NULL, NULL};
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
@@ -737,29 +820,26 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
case ANIMTYPE_NLATRACK: {
AnimData *adt = ale->adt;
NlaTrack *nlt = (NlaTrack *)ale->data;
- NlaStrip *strip;
- int index;
-
- /* draw each strip in the track (if visible) */
- for (strip = nlt->strips.first, index = 1; strip; strip = strip->next, index++) {
- if (BKE_nlastrip_within_bounds(strip, v2d->cur.xmin, v2d->cur.xmax)) {
- const float xminc = strip->start + text_margin_x;
- const float xmaxc = strip->end - text_margin_x;
-
- /* draw the visualization of the strip */
- nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax);
-
- /* add the text for this strip to the cache */
- if (xminc < xmaxc) {
- nla_draw_strip_text(adt, nlt, strip, index, v2d, xminc, xmaxc, ymin, ymax);
- }
-
- /* if transforming strips (only real reason for temp-metas currently),
- * add to the cache the frame numbers of the strip's extents
- */
- if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
- nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax);
- }
+ ListBase visible_nla_strips = get_visible_nla_strips(nlt, v2d);
+
+ /* Draw each visible strip in the track. */
+ LISTBASE_FOREACH (NlaStrip *, strip, &visible_nla_strips) {
+ const float xminc = strip->start + text_margin_x;
+ const float xmaxc = strip->end - text_margin_x;
+
+ /* draw the visualization of the strip */
+ nla_draw_strip(snla, adt, nlt, strip, v2d, ymin, ymax);
+
+ /* add the text for this strip to the cache */
+ if (xminc < xmaxc) {
+ nla_draw_strip_text(adt, nlt, strip, v2d, xminc, xmaxc, ymin, ymax);
+ }
+
+ /* if transforming strips (only real reason for temp-metas currently),
+ * add to the cache the frame numbers of the strip's extents
+ */
+ if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
+ nla_draw_strip_frames_text(nlt, strip, v2d, ymin, ymax);
}
}
break;
@@ -823,7 +903,8 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *region)
size_t items;
/* build list of channels to draw */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* Update max-extent of channels here (taking into account scrollers):
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 2aa9b347ed7..801d032a861 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -60,7 +60,8 @@ void ED_nla_postop_refresh(bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
/* get blocks to work on */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -107,7 +108,7 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
}
/* get a list of the AnimData blocks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* if no blocks, popup error? */
@@ -211,7 +212,7 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac, bool do_solo)
int filter;
/* get a list of the AnimData blocks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* if no blocks, popup error? */
@@ -318,7 +319,8 @@ static void get_nlastrip_extents(bAnimContext *ac, float *min, float *max, const
bool found_bounds = false;
/* get data to filter */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* set large values to try to override */
@@ -436,7 +438,8 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *r_min, fl
short found = 0;
/* get all items - we need to do it this way */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through all channels, finding the first one that's selected */
@@ -625,7 +628,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
}
scene = ac.scene;
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
/* get action to use */
act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"));
@@ -654,7 +657,8 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
/* get a list of the editable tracks being shown in the NLA
* - this is limited to active ones for now, but could be expanded to
*/
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0) {
@@ -771,7 +775,8 @@ static int nlaedit_add_transition_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each track, find pairs of strips to add transitions to */
@@ -901,11 +906,11 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
}
scene = ac.scene;
- cfra = CFRA;
+ cfra = scene->r.cfra;
/* get a list of the editable tracks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
- ANIMFILTER_FOREDIT);
+ ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each track, add sound clips if it belongs to a speaker */
@@ -994,7 +999,8 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each track, find pairs of strips to add transitions to */
@@ -1004,7 +1010,7 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
NlaStrip *strip;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
- /* No making metastrips in non-local tracks of override data. */
+ /* No making meta-strips in non-local tracks of override data. */
continue;
}
@@ -1070,7 +1076,8 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each track, find pairs of strips to add transitions to */
@@ -1078,7 +1085,7 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
NlaTrack *nlt = (NlaTrack *)ale->data;
if (BKE_nlatrack_is_nonlocal_in_liboverride(ale->id, nlt)) {
- /* No removing metastrips from non-local tracks of override data. */
+ /* No removing meta-strips from non-local tracks of override data. */
continue;
}
@@ -1140,7 +1147,8 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
}
/* get a list of editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* duplicate strips in tracks starting from the last one so that we're
@@ -1208,13 +1216,10 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
nlaedit_duplicate_exec(C, op);
- RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
- WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr, event);
-
return OPERATOR_FINISHED;
}
@@ -1240,9 +1245,6 @@ void NLA_OT_duplicate(wmOperatorType *ot)
false,
"Linked",
"When duplicating strips, assign new copies of the actions they use");
-
- /* to give to transform */
- RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
/** \} */
@@ -1267,7 +1269,8 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, delete all selected strips */
@@ -1430,7 +1433,8 @@ static int nlaedit_split_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, split all selected strips into two strips */
@@ -1518,7 +1522,8 @@ static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* go over all selected strips */
@@ -1587,7 +1592,8 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* consider each track in turn */
@@ -1714,7 +1720,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
BKE_nlatrack_add_strip(nlt, sb, is_liboverride);
}
- /* clear (temp) metastrips */
+ /* Clear (temp) meta-strips. */
BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
}
@@ -1769,7 +1775,8 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* since we're potentially moving strips from lower tracks to higher tracks, we should
@@ -1860,7 +1867,8 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* loop through the tracks in normal order, since we're pushing strips down,
@@ -1952,7 +1960,8 @@ static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
if (active_only) {
filter |= ANIMFILTER_ACTIVE;
}
@@ -2047,7 +2056,8 @@ static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* Ensure that each action used only has a single user
@@ -2155,7 +2165,8 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, apply scale of all selected strips */
@@ -2187,8 +2198,13 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
/* setup iterator, and iterate over all the keyframes in the action,
* applying this scaling */
ked.data = strip;
- ANIM_animchanneldata_keyframes_loop(
- &ked, ac.ads, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve);
+ ANIM_animchanneldata_keyframes_loop(&ked,
+ ac.ads,
+ strip->act,
+ ALE_ACT,
+ NULL,
+ bezt_apply_nlamapping,
+ BKE_fcurve_handles_recalc);
/* clear scale of strip now that it has been applied,
* and recalculate the extents of the action now that it has been scaled
@@ -2265,7 +2281,8 @@ static int nlaedit_clear_scale_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, reset scale of all selected strips */
@@ -2350,7 +2367,8 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* get some necessary vars */
@@ -2388,7 +2406,7 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
/* calculate new start position based on snapping mode */
switch (mode) {
case NLAEDIT_SNAP_CFRA: /* to current frame */
- strip->start = (float)CFRA;
+ strip->start = (float)scene->r.cfra;
break;
case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
strip->start = floorf(start + 0.5f);
@@ -2544,7 +2562,8 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
}
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
@@ -2655,7 +2674,8 @@ static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
ANIM_fmodifiers_copybuf_free();
/* get a list of the editable tracks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
@@ -2734,7 +2754,7 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
/* get a list of the editable tracks being shown in the NLA */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
- ANIMFILTER_NODUPLIS);
+ ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* for each NLA-Track, add the specified modifier to all selected strips */
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 902e7a176a3..3ae73282230 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -16,6 +16,8 @@
#include "ED_anim_api.h"
#include "ED_screen.h"
+#include "RNA_access.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -138,6 +140,28 @@ void nla_operatortypes(void)
WM_operatortype_append(NLA_OT_fmodifier_paste);
}
+void ED_operatormacros_nla()
+{
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ ot = WM_operatortype_append_macro("NLA_OT_duplicate_move",
+ "Duplicate",
+ "Duplicate selected strips and their Actions and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "NLA_OT_duplicate");
+ RNA_boolean_set(otmacro->ptr, "linked", false);
+ WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+
+ ot = WM_operatortype_append_macro("NLA_OT_duplicate_linked_move",
+ "Duplicate Linked",
+ "Duplicate selected strips and move them",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "NLA_OT_duplicate");
+ RNA_boolean_set(otmacro->ptr, "linked", true);
+ WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+}
+
/* ************************** registration - keymaps **********************************/
void nla_keymap(wmKeyConfig *keyconf)
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 1efb91bc99f..a816f8fa4f6 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -85,7 +85,7 @@ static void deselect_nla_strips(bAnimContext *ac, short test, short sel)
/* determine type-based settings */
/* FIXME: double check whether ANIMFILTER_LIST_VISIBLE is needed! */
- filter = (ANIMFILTER_DATA_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FCURVESONLY);
/* filter data */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
@@ -223,7 +223,8 @@ static void box_select_nla_strips(bAnimContext *ac, rcti rect, short mode, short
UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* convert selection modes to selection modes */
@@ -278,7 +279,8 @@ static void nlaedit_strip_at_region_position(
0, NLACHANNEL_STEP(snla), 0, NLACHANNEL_FIRST_TOP(ac), view_x, view_y, NULL, &channel_index);
ListBase anim_data = {NULL, NULL};
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click
@@ -455,17 +457,17 @@ static void nlaedit_select_leftright(bContext *C,
/* get range, and get the right flag-setting mode */
if (leftright == NLAEDIT_LRSEL_LEFT) {
xmin = MINAFRAMEF;
- xmax = (float)(CFRA + 0.1f);
+ xmax = (float)(scene->r.cfra + 0.1f);
}
else {
- xmin = (float)(CFRA - 0.1f);
+ xmin = (float)(scene->r.cfra - 0.1f);
xmax = MAXFRAMEF;
}
select_mode = selmodes_to_flagmodes(select_mode);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select strips on the side where most data occurs */
@@ -540,7 +542,7 @@ static int nlaedit_select_leftright_invoke(bContext *C, wmOperator *op, const wm
/* determine which side of the current frame mouse is on */
x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
- if (x < CFRA) {
+ if (x < scene->r.cfra) {
RNA_enum_set(op->ptr, "mode", NLAEDIT_LRSEL_LEFT);
}
else {
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 42d3d841f4b..13035a9d5fd 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -87,9 +87,9 @@ static SpaceLink *nla_create(const ScrArea *area, const Scene *scene)
BLI_addtail(&snla->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
- region->v2d.tot.xmin = (float)(SFRA - 10);
+ region->v2d.tot.xmin = (float)(scene->r.sfra - 10);
region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
- region->v2d.tot.xmax = (float)(EFRA + 10);
+ region->v2d.tot.xmax = (float)(scene->r.efra + 10);
region->v2d.tot.ymax = 0.0f;
region->v2d.cur = region->v2d.tot;
@@ -235,7 +235,7 @@ static void nla_main_region_draw(const bContext *C, ARegion *region)
/* strips and backdrops */
draw_nla_main_data(&ac, snla, region);
- /* text draw cached, in pixelspace now */
+ /* Text draw cached, in pixel-space now. */
UI_view2d_text_cache_draw(region);
}
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index d5507619e0d..66e07c804b6 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -20,6 +20,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
@@ -328,7 +329,7 @@ static void node_buts_image_user(uiLayout *layout,
Scene *scene = CTX_data_scene(C);
char numstr[32];
- const int framenr = BKE_image_user_frame_get(iuser, CFRA, nullptr);
+ const int framenr = BKE_image_user_frame_get(iuser, scene->r.cfra, nullptr);
BLI_snprintf(numstr, sizeof(numstr), IFACE_("Frame: %d"), framenr);
uiItemL(layout, numstr, ICON_NONE);
}
@@ -1271,14 +1272,14 @@ static void node_file_output_socket_draw(bContext *C,
static bool socket_needs_attribute_search(bNode &node, bNodeSocket &socket)
{
- if (node.declaration == nullptr) {
+ if (node.runtime->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();
+ return node.runtime->declaration->inputs()[socket_index]->is_attribute_name();
}
static void std_node_socket_draw(
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 975d4eda7e3..a89b5444a4d 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -382,7 +382,7 @@ static bool node_add_group_poll(bContext *C)
if (snode->edittree->type == NTREE_CUSTOM) {
CTX_wm_operator_poll_msg_set(C,
"This node editor displays a custom (Python defined) node tree. "
- "Dropping node groups isn't supported for this.");
+ "Dropping node groups isn't supported for this");
return false;
}
return true;
@@ -690,8 +690,8 @@ static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *even
snode->runtime->cursor[0] /= UI_DPI_FAC;
snode->runtime->cursor[1] /= UI_DPI_FAC;
- if (RNA_struct_property_is_set(op->ptr, "filepath") ||
- RNA_struct_property_is_set(op->ptr, "name")) {
+ if (WM_operator_properties_id_lookup_is_set(op->ptr) ||
+ RNA_struct_property_is_set(op->ptr, "filepath")) {
return node_add_file_exec(C, op);
}
return WM_operator_filesel(C, op, event);
diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc
index dfc0beb13fc..b9bee3ed15e 100644
--- a/source/blender/editors/space_node/node_context_path.cc
+++ b/source/blender/editors/space_node/node_context_path.cc
@@ -26,8 +26,6 @@
#include "UI_interface.hh"
#include "UI_resources.h"
-#include "UI_interface.hh"
-
#include "node_intern.hh"
struct Curve;
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index f5048e0cc67..b879219e39c 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -66,6 +66,7 @@
#include "NOD_geometry_nodes_eval_log.hh"
#include "NOD_node_declaration.hh"
+#include "NOD_socket_declarations_geometry.hh"
#include "FN_field.hh"
#include "FN_field_cpp_type.hh"
@@ -75,7 +76,7 @@
using blender::GPointer;
using blender::fn::GField;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
-using geo_log::NamedAttributeUsage;
+using geo_log::eNamedAttrUsage;
extern "C" {
/* XXX interface.h */
@@ -748,15 +749,14 @@ static void node_socket_outline_color_get(const bool selected,
if (selected) {
UI_GetThemeColor4fv(TH_ACTIVE, r_outline_color);
}
+ else if (socket_type == SOCK_CUSTOM) {
+ /* Until there is a better place for per socket color,
+ * the outline color for virtual sockets is set here. */
+ copy_v4_v4(r_outline_color, virtual_node_socket_outline_color);
+ }
else {
UI_GetThemeColor4fv(TH_WIRE, r_outline_color);
}
-
- /* Until there is a better place for per socket color,
- * the outline color for virtual sockets is set here. */
- if (socket_type == SOCK_CUSTOM) {
- copy_v4_v4(r_outline_color, virtual_node_socket_outline_color);
- }
}
void node_socket_color_get(const bContext &C,
@@ -871,7 +871,8 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v
}
static void create_inspection_string_for_geometry(const geo_log::GeometryValueLog &value_log,
- std::stringstream &ss)
+ std::stringstream &ss,
+ const nodes::decl::Geometry *geometry)
{
Span<GeometryComponentType> component_types = value_log.component_types();
if (component_types.is_empty()) {
@@ -938,6 +939,45 @@ static void create_inspection_string_for_geometry(const geo_log::GeometryValueLo
}
}
}
+
+ /* If the geometry declaration is null, as is the case for input to group output,
+ * or it is an output socket don't show supported types. */
+ if (geometry == nullptr || geometry->in_out() == SOCK_OUT) {
+ return;
+ }
+
+ Span<GeometryComponentType> supported_types = geometry->supported_types();
+ if (supported_types.is_empty()) {
+ ss << ".\n\n" << TIP_("Supported: All Types");
+ return;
+ }
+
+ ss << ".\n\n" << TIP_("Supported: ");
+ for (GeometryComponentType type : supported_types) {
+ switch (type) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ ss << TIP_("Mesh");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ ss << TIP_("Point Cloud");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ ss << TIP_("Curve");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ ss << TIP_("Instances");
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ ss << TIP_("Volume");
+ break;
+ }
+ }
+ ss << ((type == supported_types.last()) ? "" : ", ");
+ }
}
static std::optional<std::string> create_socket_inspection_string(bContext *C,
@@ -970,7 +1010,10 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C,
}
else if (const geo_log::GeometryValueLog *geo_value_log =
dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
- create_inspection_string_for_geometry(*geo_value_log, ss);
+ create_inspection_string_for_geometry(
+ *geo_value_log,
+ ss,
+ dynamic_cast<const nodes::decl::Geometry *>(socket.runtime->declaration));
}
return ss.str();
@@ -982,8 +1025,8 @@ static bool node_socket_has_tooltip(bNodeTree *ntree, bNodeSocket *socket)
return true;
}
- if (socket->declaration != nullptr) {
- const blender::nodes::SocketDeclaration &socket_decl = *socket->declaration;
+ if (socket->runtime->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration;
return !socket_decl.description().is_empty();
}
@@ -996,8 +1039,8 @@ static char *node_socket_get_tooltip(bContext *C,
bNodeSocket *socket)
{
std::stringstream output;
- if (socket->declaration != nullptr) {
- const blender::nodes::SocketDeclaration &socket_decl = *socket->declaration;
+ if (socket->runtime->declaration != nullptr) {
+ const blender::nodes::SocketDeclaration &socket_decl = *socket->runtime->declaration;
blender::StringRef description = socket_decl.description();
if (!description.is_empty()) {
output << TIP_(description.data());
@@ -1695,7 +1738,7 @@ struct NodeExtraInfoRow {
};
struct NamedAttributeTooltipArg {
- Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ Map<std::string, eNamedAttrUsage> usage_by_attribute;
};
static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char *UNUSED(tip))
@@ -1707,7 +1750,7 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char
struct NameWithUsage {
StringRefNull name;
- NamedAttributeUsage usage;
+ eNamedAttrUsage usage;
};
Vector<NameWithUsage> sorted_used_attribute;
@@ -1722,16 +1765,16 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char
for (const NameWithUsage &attribute : sorted_used_attribute) {
const StringRefNull name = attribute.name;
- const NamedAttributeUsage usage = attribute.usage;
+ const eNamedAttrUsage usage = attribute.usage;
ss << " \u2022 \"" << name << "\": ";
Vector<std::string> usages;
- if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) {
usages.append(TIP_("read"));
}
- if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) {
usages.append(TIP_("write"));
}
- if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) {
usages.append(TIP_("remove"));
}
for (const int i : usages.index_range()) {
@@ -1749,7 +1792,7 @@ static char *named_attribute_tooltip(bContext *UNUSED(C), void *argN, const char
}
static NodeExtraInfoRow row_from_used_named_attribute(
- const Map<std::string, NamedAttributeUsage> &usage_by_attribute_name)
+ const Map<std::string, eNamedAttrUsage> &usage_by_attribute_name)
{
const int attributes_num = usage_by_attribute_name.size();
@@ -1777,7 +1820,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const Sp
return std::nullopt;
}
- Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ Map<std::string, eNamedAttrUsage> usage_by_attribute;
tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) {
for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
usage_by_attribute.lookup_or_add_as(used_attribute.name,
@@ -1807,7 +1850,7 @@ static std::optional<NodeExtraInfoRow> node_get_accessed_attributes_row(const Sp
if (node_log == nullptr) {
return std::nullopt;
}
- Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ Map<std::string, eNamedAttrUsage> usage_by_attribute;
for (const geo_log::UsedNamedAttribute &used_attribute : node_log->used_named_attributes()) {
usage_by_attribute.lookup_or_add_as(used_attribute.name,
used_attribute.usage) |= used_attribute.usage;
@@ -2654,7 +2697,7 @@ static void frame_node_draw_label(const bNodeTree &ntree,
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);
+ BLF_size(fontid, MIN2(24.0f, font_size) * U.pixelsize, U.dpi);
/* title color */
int color_id = node_get_colorid(node);
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index ab80a44d636..ffc9befc81c 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -15,6 +15,7 @@
#include "DNA_text_types.h"
#include "DNA_world_types.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -275,6 +276,7 @@ static void compo_startjob(void *cjv,
// XXX BIF_store_spare();
/* 1 is do_previews */
+ BKE_callback_exec_id(cj->bmain, &scene->id, BKE_CB_EVT_COMPOSITE_PRE);
if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, "");
@@ -293,6 +295,22 @@ static void compo_startjob(void *cjv,
ntree->progress = nullptr;
}
+static void compo_canceljob(void *cjv)
+{
+ CompoJob *cj = (CompoJob *)cjv;
+ Main *bmain = cj->bmain;
+ Scene *scene = cj->scene;
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_CANCEL);
+}
+
+static void compo_completejob(void *cjv)
+{
+ CompoJob *cj = (CompoJob *)cjv;
+ Main *bmain = cj->bmain;
+ Scene *scene = cj->scene;
+ BKE_callback_exec_id(bmain, &scene->id, BKE_CB_EVT_COMPOSITE_POST);
+}
+
/** \} */
} // namespace blender::ed::space_node
@@ -339,7 +357,13 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
/* setup job */
WM_jobs_customdata_set(wm_job, cj, compo_freejob);
WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_COMPO_RESULT, NC_SCENE | ND_COMPO_RESULT);
- WM_jobs_callbacks(wm_job, compo_startjob, compo_initjob, compo_updatejob, nullptr);
+ WM_jobs_callbacks_ex(wm_job,
+ compo_startjob,
+ compo_initjob,
+ compo_updatejob,
+ nullptr,
+ compo_completejob,
+ compo_canceljob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
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 9c0172cfabf..e328a86b0fd 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -82,8 +82,10 @@ static Vector<const GeometryAttributeInfo *> get_attribute_info_from_context(
if (const geo_log::GeometryValueLog *geo_value_log =
dynamic_cast<const geo_log::GeometryValueLog *>(value_log)) {
for (const GeometryAttributeInfo &attribute : geo_value_log->attributes()) {
- if (names.add(attribute.name)) {
- attributes.append(&attribute);
+ if (bke::allow_procedural_attribute_access(attribute.name)) {
+ if (names.add(attribute.name)) {
+ attributes.append(&attribute);
+ }
}
}
}
@@ -111,14 +113,6 @@ static void attribute_search_update_fn(
Vector<const GeometryAttributeInfo *> infos = get_attribute_info_from_context(*C, *data);
- /* Remove the deprecated normal attribute from the search. */
- for (const int i : infos.index_range()) {
- if (infos[i]->domain == ATTR_DOMAIN_FACE && infos[i]->name == "normal") {
- infos.remove(i);
- break;
- }
- }
-
ui::attribute_search_add_items(str, true, infos, items, is_first);
}
@@ -126,7 +120,7 @@ static void attribute_search_update_fn(
* Some custom data types don't correspond to node types and therefore can't be
* used by the named attribute input node. Find the best option or fallback to float.
*/
-static CustomDataType data_type_in_attribute_input_node(const CustomDataType type)
+static eCustomDataType data_type_in_attribute_input_node(const eCustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT:
@@ -185,7 +179,7 @@ static void attribute_search_exec_fn(bContext *C, void *data_v, void *item_v)
/* For the attribute input node, also adjust the type and links connected to the output. */
if (node->type == GEO_NODE_INPUT_NAMED_ATTRIBUTE && item->data_type.has_value()) {
NodeGeometryInputNamedAttribute &storage = *(NodeGeometryInputNamedAttribute *)node->storage;
- const CustomDataType new_type = data_type_in_attribute_input_node(*item->data_type);
+ const eCustomDataType new_type = data_type_in_attribute_input_node(*item->data_type);
if (new_type != storage.data_type) {
storage.data_type = new_type;
/* Make the output socket with the new type on the attribute input node active. */
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index c757fb46407..e10bedb18f4 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -454,7 +454,7 @@ static bool socket_can_be_viewed(const OutputSocketRef &socket)
SOCK_RGBA);
}
-static CustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type)
+static eCustomDataType socket_type_to_custom_data_type(const eNodeSocketDatatype socket_type)
{
switch (socket_type) {
case SOCK_FLOAT:
@@ -491,7 +491,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
return viewer_socket;
}
NodeGeometryViewer *storage = (NodeGeometryViewer *)viewer_node.storage;
- const CustomDataType data_type = socket_type_to_custom_data_type(
+ const eCustomDataType 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;
@@ -2048,7 +2048,7 @@ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketIn
/* Try to get the main socket based on the socket declaration. */
nodeDeclarationEnsure(&ntree, &node);
- const nodes::NodeDeclaration *node_decl = node.declaration;
+ const nodes::NodeDeclaration *node_decl = node.runtime->declaration;
if (node_decl != nullptr) {
Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() :
node_decl->outputs();
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc
index e20958c1b1e..7435fa50a93 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.cc
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc
@@ -1124,8 +1124,7 @@ static Collection *collection_parent_from_ID(ID *id)
return nullptr;
}
-static bool collection_drop_init(
- bContext *C, wmDrag *drag, const int xy[2], const bool is_link, CollectionDrop *data)
+static bool collection_drop_init(bContext *C, wmDrag *drag, const int xy[2], CollectionDrop *data)
{
/* Get collection to drop into. */
TreeElementInsertType insert_type;
@@ -1157,9 +1156,6 @@ static bool collection_drop_init(
/* Get collection to drag out of. */
ID *parent = drag_id->from_parent;
Collection *from_collection = collection_parent_from_ID(parent);
- if (is_link) {
- from_collection = nullptr;
- }
/* Currently this should not be allowed, cannot edit items in an override of a Collection. */
if (from_collection != nullptr && ID_IS_OVERRIDE_LIBRARY(from_collection)) {
@@ -1197,29 +1193,22 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
bool changed = outliner_flag_set(*space_outliner, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
CollectionDrop data;
- if (((event->modifier & KM_SHIFT) == 0) &&
- collection_drop_init(C, drag, event->xy, event->modifier & KM_CTRL, &data)) {
+ if (((event->modifier & KM_SHIFT) == 0) && collection_drop_init(C, drag, event->xy, &data)) {
TreeElement *te = data.te;
TreeStoreElem *tselem = TREESTORE(te);
- if (!data.from || event->modifier & KM_CTRL) {
- tselem->flag |= TSE_DRAG_INTO;
- changed = true;
- }
- else {
- switch (data.insert_type) {
- case TE_INSERT_BEFORE:
- tselem->flag |= TSE_DRAG_BEFORE;
- changed = true;
- break;
- case TE_INSERT_AFTER:
- tselem->flag |= TSE_DRAG_AFTER;
- changed = true;
- break;
- case TE_INSERT_INTO: {
- tselem->flag |= TSE_DRAG_INTO;
- changed = true;
- break;
- }
+ switch (data.insert_type) {
+ case TE_INSERT_BEFORE:
+ tselem->flag |= TSE_DRAG_BEFORE;
+ changed = true;
+ break;
+ case TE_INSERT_AFTER:
+ tselem->flag |= TSE_DRAG_AFTER;
+ changed = true;
+ break;
+ case TE_INSERT_INTO: {
+ tselem->flag |= TSE_DRAG_INTO;
+ changed = true;
+ break;
}
}
if (changed) {
@@ -1242,30 +1231,49 @@ static char *collection_drop_tooltip(bContext *C,
const wmEvent *event = win ? win->eventstate : nullptr;
CollectionDrop data;
- if (event && ((event->modifier & KM_SHIFT) == 0) &&
- collection_drop_init(C, drag, xy, event->modifier & KM_CTRL, &data)) {
- TreeElement *te = data.te;
- if (!data.from || event->modifier & KM_CTRL) {
- return BLI_strdup(TIP_("Link inside Collection"));
+ if (event && ((event->modifier & KM_SHIFT) == 0) && collection_drop_init(C, drag, xy, &data)) {
+ const bool is_link = !data.from || (event->modifier & KM_CTRL);
+
+ /* Test if we are moving within same parent collection. */
+ bool same_level = false;
+ LISTBASE_FOREACH (CollectionParent *, parent, &data.to->parents) {
+ if (data.from == parent->collection) {
+ same_level = true;
+ }
}
+
+ /* Tooltips when not moving directly into another collection i.e. mouse on border of
+ * collections. Later we will decide which tooltip to return. */
+ const bool tooltip_link = (is_link && !same_level);
+ const char *tooltip_before = tooltip_link ? TIP_("Link before collection") :
+ TIP_("Move before collection");
+ const char *tooltip_between = tooltip_link ? TIP_("Link between collections") :
+ TIP_("Move between collections");
+ const char *tooltip_after = tooltip_link ? TIP_("Link after collection") :
+ TIP_("Move after collection");
+
+ TreeElement *te = data.te;
switch (data.insert_type) {
case TE_INSERT_BEFORE:
if (te->prev && outliner_is_collection_tree_element(te->prev)) {
- return BLI_strdup(TIP_("Move between collections"));
+ return BLI_strdup(tooltip_between);
}
else {
- return BLI_strdup(TIP_("Move before collection"));
+ return BLI_strdup(tooltip_before);
}
break;
case TE_INSERT_AFTER:
if (te->next && outliner_is_collection_tree_element(te->next)) {
- return BLI_strdup(TIP_("Move between collections"));
+ return BLI_strdup(tooltip_between);
}
else {
- return BLI_strdup(TIP_("Move after collection"));
+ return BLI_strdup(tooltip_after);
}
break;
case TE_INSERT_INTO: {
+ if (is_link) {
+ return BLI_strdup(TIP_("Link inside collection"));
+ }
/* Check the type of the drag IDs to avoid the incorrect "Shift to parent"
* for collections. Checking the type of the first ID works fine here since
@@ -1296,7 +1304,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first);
CollectionDrop data;
- if (!collection_drop_init(C, drag, event->xy, event->modifier & KM_CTRL, &data)) {
+ if (!collection_drop_init(C, drag, event->xy, &data)) {
return OPERATOR_CANCELLED;
}
@@ -1447,7 +1455,7 @@ 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, nullptr, 0.0, WM_DRAG_NOP);
+ wmDrag *drag = WM_drag_data_create(C, data.icon, wm_drag_type, nullptr, 0.0, WM_DRAG_NOP);
if (use_datastack_drag) {
TreeElement *te_bone = nullptr;
@@ -1537,6 +1545,8 @@ static int outliner_item_drag_drop_invoke(bContext *C,
WM_drag_add_local_ID(drag, data.drag_id, data.drag_parent);
}
+ WM_event_start_prepared_drag(C, drag);
+
ED_outliner_select_sync_from_outliner(C, space_outliner);
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index 753de83a10d..6bab0b938e8 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -37,6 +37,7 @@
#include "BKE_lib_override.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_main_namemap.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_object.h"
@@ -677,6 +678,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem);
if (tselem->type == TSE_SOME_ID) {
+ BKE_main_namemap_remove_name(bmain, tselem->id, oldname);
BLI_libblock_ensure_unique_name(bmain, tselem->id->name);
WM_msg_publish_rna_prop(mbus, tselem->id, tselem->id, ID, name);
@@ -742,6 +744,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
}
case TSE_NLA_ACTION: {
bAction *act = (bAction *)tselem->id;
+ BKE_main_namemap_remove_name(bmain, &act->id, oldname);
BLI_libblock_ensure_unique_name(bmain, act->id.name);
WM_msg_publish_rna_prop(mbus, &act->id, &act->id, ID, name);
break;
@@ -852,6 +855,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname)
case TSE_LAYER_COLLECTION: {
/* The ID is a #Collection, not a #LayerCollection */
Collection *collection = (Collection *)tselem->id;
+ BKE_main_namemap_remove_name(bmain, &collection->id, oldname);
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, nullptr);
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index c4a9398a5f7..32860bc2cff 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -447,7 +447,7 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
/** \name ID Delete Operator
* \{ */
-static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
+static void id_delete_tag(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
Main *bmain = CTX_data_main(C);
ID *id = tselem->id;
@@ -484,35 +484,39 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
return;
}
if (te->idcode == ID_WS) {
- BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT);
- if (id->tag & LIB_TAG_DOIT) {
+ BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_PRE_EXISTING);
+ if (id->tag & LIB_TAG_PRE_EXISTING) {
BKE_reportf(
reports, RPT_WARNING, "Cannot delete currently visible workspace id '%s'", id->name);
+ BKE_main_id_tag_idcode(bmain, ID_WS, LIB_TAG_PRE_EXISTING, false);
return;
}
+ BKE_main_id_tag_idcode(bmain, ID_WS, LIB_TAG_PRE_EXISTING, false);
}
- BKE_id_delete(bmain, id);
+ id->tag |= LIB_TAG_DOIT;
WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
-void id_delete_fn(bContext *C,
- ReportList *reports,
- Scene *UNUSED(scene),
- TreeElement *te,
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
+void id_delete_tag_fn(bContext *C,
+ ReportList *reports,
+ Scene *UNUSED(scene),
+ TreeElement *te,
+ TreeStoreElem *UNUSED(tsep),
+ TreeStoreElem *tselem,
+ void *UNUSED(user_data))
{
- id_delete(C, reports, te, tselem);
+ id_delete_tag(C, reports, te, tselem);
}
-static int outliner_id_delete_invoke_do(bContext *C,
- ReportList *reports,
- TreeElement *te,
- const float mval[2])
+static int outliner_id_delete_tag(bContext *C,
+ ReportList *reports,
+ TreeElement *te,
+ const float mval[2])
{
+ int id_tagged_num = 0;
+
if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) {
TreeStoreElem *tselem = TREESTORE(te);
@@ -522,26 +526,27 @@ static int outliner_id_delete_invoke_do(bContext *C,
RPT_ERROR_INVALID_INPUT,
"Cannot delete indirectly linked library '%s'",
((Library *)tselem->id)->filepath_abs);
- return OPERATOR_CANCELLED;
}
- id_delete(C, reports, te, tselem);
- return OPERATOR_FINISHED;
+ else {
+ id_delete_tag(C, reports, te, tselem);
+ id_tagged_num++;
+ }
}
}
else {
LISTBASE_FOREACH (TreeElement *, te_sub, &te->subtree) {
- int ret;
- if ((ret = outliner_id_delete_invoke_do(C, reports, te_sub, mval))) {
- return ret;
+ if ((id_tagged_num += outliner_id_delete_tag(C, reports, te_sub, mval)) != 0) {
+ break;
}
}
}
- return 0;
+ return id_tagged_num;
}
static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Main *bmain = CTX_data_main(C);
ARegion *region = CTX_wm_region(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
float fmval[2];
@@ -550,15 +555,21 @@ static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+ int id_tagged_num = 0;
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) {
- int ret;
-
- if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) {
- return ret;
+ if ((id_tagged_num += outliner_id_delete_tag(C, op->reports, te, fmval)) != 0) {
+ break;
}
}
+ if (id_tagged_num == 0) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ return OPERATOR_CANCELLED;
+ }
- return OPERATOR_CANCELLED;
+ BKE_id_multi_tagged_delete(bmain);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ return OPERATOR_FINISHED;
}
void OUTLINER_OT_id_delete(wmOperatorType *ot)
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index a0dcb49aa43..18173b37123 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -437,13 +437,13 @@ void lib_reload_fn(struct bContext *C,
struct TreeStoreElem *tselem,
void *user_data);
-void id_delete_fn(struct bContext *C,
- struct ReportList *reports,
- struct Scene *scene,
- struct TreeElement *te,
- struct TreeStoreElem *tsep,
- struct TreeStoreElem *tselem,
- void *user_data);
+void id_delete_tag_fn(struct bContext *C,
+ struct ReportList *reports,
+ struct Scene *scene,
+ struct TreeElement *te,
+ struct TreeStoreElem *tsep,
+ struct TreeStoreElem *tselem,
+ void *user_data);
void id_remap_fn(struct bContext *C,
struct ReportList *reports,
struct Scene *scene,
diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc
index bd6d3d89706..877e0fc325c 100644
--- a/source/blender/editors/space_outliner/outliner_select.cc
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -1693,7 +1693,7 @@ void OUTLINER_OT_item_activate(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection for activation");
@@ -2028,7 +2028,7 @@ void OUTLINER_OT_select_walk(wmOperatorType *ot)
ot->invoke = outliner_walk_select_invoke;
ot->poll = ED_operator_outliner_active;
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop;
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 3b018d59881..9d52103a266 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -222,13 +222,33 @@ static void unlink_action_fn(bContext *C,
}
static void unlink_material_fn(bContext *UNUSED(C),
- ReportList *UNUSED(reports),
+ ReportList *reports,
Scene *UNUSED(scene),
TreeElement *te,
TreeStoreElem *tsep,
- TreeStoreElem *UNUSED(tselem),
+ TreeStoreElem *tselem,
void *UNUSED(user_data))
{
+ const bool te_is_material = TSE_IS_REAL_ID(tselem) && (GS(tselem->id->name) == ID_MA);
+
+ if (!te_is_material) {
+ /* Just fail silently. Another element may be selected that is a material, we don't want to
+ * confuse users with an error in that case. */
+ return;
+ }
+
+ if (!tsep || !TSE_IS_REAL_ID(tsep)) {
+ /* Valid case, no parent element of the material or it is not an ID (could be a #TSE_ID_BASE
+ * for example) so there's no data to unlink from. */
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Cannot unlink material '%s'. It's not clear which object or object-data it "
+ "should be unlinked from, there's no object or object-data as parent in the "
+ "Outliner tree",
+ tselem->id->name + 2);
+ return;
+ }
+
Material **matar = nullptr;
int a, totcol = 0;
@@ -855,7 +875,7 @@ static void id_override_library_create_fn(bContext *C,
/* For now, remap all local usages of linked ID to local override one here. */
ID *id_iter;
FOREACH_MAIN_ID_BEGIN (bmain, id_iter) {
- if (ID_IS_LINKED(id_iter)) {
+ if (ID_IS_LINKED(id_iter) || ID_IS_OVERRIDE_LIBRARY(id_iter)) {
id_iter->tag &= ~LIB_TAG_DOIT;
}
else {
@@ -1954,7 +1974,7 @@ void OUTLINER_OT_delete(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* flags */
- ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop = RNA_def_boolean(
@@ -1975,7 +1995,6 @@ enum eOutlinerIdOpTypes {
OUTLINER_IDOP_LOCAL,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY,
- OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET,
OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY,
@@ -2008,7 +2027,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, nullptr, nullptr},
+ RNA_ENUM_ITEM_SEPR,
{OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE,
"OVERRIDE_LIBRARY_CREATE",
0,
@@ -2021,12 +2040,6 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Make Library Override Hierarchy",
"Make a local override of this linked data-block, and its hierarchy of dependencies - only "
"applies to active Outliner item"},
- {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE,
- "OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE",
- 0,
- "Make Library Override Hierarchy Fully Editable",
- "Make a local override of this linked data-block, and its hierarchy of dependencies, making "
- "them all fully user-editable - only applies to active Outliner item"},
{OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE,
"OVERRIDE_LIBRARY_MAKE_EDITABLE",
0,
@@ -2067,10 +2080,10 @@ static const EnumPropertyItem prop_id_op_types[] = {
"Clear Library Override Hierarchy",
"Delete this local override (including its hierarchy of override dependencies) and relink "
"its usages to the linked data-blocks"},
- {0, "", 0, nullptr, nullptr},
+ RNA_ENUM_ITEM_SEPR,
{OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""},
{OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""},
- {0, "", 0, nullptr, nullptr},
+ RNA_ENUM_ITEM_SEPR,
{OUTLINER_IDOP_FAKE_ADD,
"ADD_FAKE",
0,
@@ -2106,7 +2119,6 @@ static bool outliner_id_operation_item_poll(bContext *C,
}
return false;
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY:
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE:
if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id) || (ID_IS_LINKED(tselem->id))) {
return true;
}
@@ -2165,6 +2177,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -2249,6 +2262,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: {
OutlinerLibOverrideData override_data{};
override_data.do_hierarchy = true;
+ override_data.do_fully_editable = U.experimental.use_override_new_fully_editable;
outliner_do_libdata_operation(C,
op->reports,
scene,
@@ -2262,23 +2276,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
ED_undo_push(C, "Overridden Data Hierarchy");
break;
}
- case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY_FULLY_EDITABLE: {
- OutlinerLibOverrideData override_data{};
- override_data.do_hierarchy = true;
- override_data.do_fully_editable = true;
- outliner_do_libdata_operation(C,
- op->reports,
- scene,
- space_outliner,
- id_override_library_create_hierarchy_pre_process_fn,
- &override_data);
- outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_override_library_create_fn, &override_data);
- id_override_library_create_hierarchy_post_process(C, &override_data);
-
- ED_undo_push(C, "Overridden Data Hierarchy Fully Editable");
- break;
- }
case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: {
outliner_do_libdata_operation(C,
op->reports,
@@ -2361,8 +2358,10 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
}
case OUTLINER_IDOP_DELETE: {
if (idlevel > 0) {
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
outliner_do_libdata_operation(
- C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
+ C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
+ BKE_id_multi_tagged_delete(bmain);
ED_undo_push(C, "Delete");
}
break;
@@ -2487,6 +2486,7 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = {
static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
@@ -2502,7 +2502,10 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type");
switch (event) {
case OL_LIB_DELETE: {
- outliner_do_libdata_operation(C, op->reports, scene, space_outliner, id_delete_fn, nullptr);
+ BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
+ outliner_do_libdata_operation(
+ C, op->reports, scene, space_outliner, id_delete_tag_fn, nullptr);
+ BKE_id_multi_tagged_delete(bmain);
ED_undo_push(C, "Delete Library");
break;
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc
index 7b3ce499929..aa739758ecb 100644
--- a/source/blender/editors/space_outliner/outliner_tree.cc
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -802,7 +802,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
void *idv,
TreeElement *parent,
short type,
- short index)
+ short index,
+ const bool expand)
{
ID *id = reinterpret_cast<ID *>(idv);
@@ -894,10 +895,10 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
te->idcode = GS(id->name);
}
- if (te->abstract_element && te->abstract_element->isExpandValid()) {
+ if (expand && te->abstract_element && te->abstract_element->isExpandValid()) {
tree_element_expand(*te->abstract_element, *space_outliner);
}
- else if (type == TSE_SOME_ID) {
+ else if (expand && (type == TSE_SOME_ID)) {
/* ID types not (fully) ported to new design yet. */
if (te->abstract_element->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
@@ -1682,6 +1683,9 @@ void outliner_build_tree(Main *mainvar,
space_outliner->storeflag &= ~SO_TREESTORE_REBUILD;
if (region->do_draw & RGN_DRAW_NO_REBUILD) {
+ BLI_assert_msg(space_outliner->runtime->tree_display != nullptr,
+ "Skipping rebuild before tree was built properly, a full redraw should be "
+ "triggered instead");
return;
}
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index 190e35c81d6..f8e35655c26 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -161,7 +161,6 @@ class TreeDisplayOverrideLibraryHierarchies final : public AbstractTreeDisplay {
ListBase build_hierarchy_for_lib_or_main(Main *bmain,
TreeElement &parent_te,
Library *lib = nullptr);
- void build_hierarchy_for_ID(Main *bmain, ID &override_root_id, TreeElementID &te_id) const;
};
/* -------------------------------------------------------------------- */
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 46a89f17687..405f1dd73f4 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc
@@ -116,6 +116,11 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase
ID *id = static_cast<ID *>(lbarray[a]->first);
const bool is_library = (GS(id->name) == ID_LI) && (lib != nullptr);
+ /* Don't show deprecated types. */
+ if (ID_TYPE_IS_DEPRECATED(GS(id->name))) {
+ continue;
+ }
+
/* check if there's data in current lib */
for (ID *id_iter : List<ID>(lbarray[a])) {
if (id_iter->lib == lib) {
diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
index 38025b58fd2..f8705c3f0ad 100644
--- a/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
+++ b/source/blender/editors/space_outliner/tree/tree_display_override_library_hierarchies.cc
@@ -4,25 +4,23 @@
* \ingroup spoutliner
*/
-#include "DNA_ID.h"
-#include "DNA_collection_types.h"
#include "DNA_key_types.h"
#include "DNA_space_types.h"
-#include "BLI_listbase.h"
+#include "BLI_function_ref.hh"
+#include "BLI_ghash.h"
#include "BLI_map.hh"
+
#include "BLI_set.hh"
#include "BLT_translation.h"
-#include "BKE_collection.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "../outliner_intern.hh"
#include "common.hh"
#include "tree_display.hh"
-#include "tree_element_id.hh"
namespace blender::ed::outliner {
@@ -34,13 +32,6 @@ TreeDisplayOverrideLibraryHierarchies::TreeDisplayOverrideLibraryHierarchies(
{
}
-/* XXX Remove expanded subtree, we add our own items here. Expanding should probably be
- * optional. */
-static void remove_expanded_children(TreeElement &te)
-{
- outliner_free_tree(&te.subtree);
-}
-
ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &source_data)
{
ListBase tree = {nullptr};
@@ -49,8 +40,8 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &
TreeElement *current_file_te = outliner_add_element(
&space_outliner_, &tree, source_data.bmain, nullptr, TSE_ID_BASE, -1);
current_file_te->name = IFACE_("Current File");
+ AbstractTreeElement::uncollapse_by_default(current_file_te);
{
- AbstractTreeElement::uncollapse_by_default(current_file_te);
build_hierarchy_for_lib_or_main(source_data.bmain, *current_file_te);
/* Add dummy child if there's nothing to display. */
@@ -83,11 +74,49 @@ ListBase TreeDisplayOverrideLibraryHierarchies::buildTree(const TreeSourceData &
return tree;
}
+/* -------------------------------------------------------------------- */
+/** \name Library override hierarchy building
+ * \{ */
+
+class OverrideIDHierarchyBuilder {
+ SpaceOutliner &space_outliner_;
+ MainIDRelations &id_relations_;
+
+ struct HierarchyBuildData {
+ const ID &override_root_id_;
+ /* The ancestor IDs leading to the current ID, to avoid IDs recursing into themselves. Changes
+ * with every level of recursion. */
+ Set<const ID *> parent_ids{};
+ /* The IDs that were already added to #parent_te, to avoid duplicates. Entirely new set with
+ * every level of recursion. */
+ Set<const ID *> sibling_ids{};
+ };
+
+ public:
+ OverrideIDHierarchyBuilder(SpaceOutliner &space_outliner, MainIDRelations &id_relations)
+ : space_outliner_(space_outliner), id_relations_(id_relations)
+ {
+ }
+
+ void build_hierarchy_for_ID(ID &root_id, TreeElement &te_to_expand);
+
+ private:
+ void build_hierarchy_for_ID_recursive(const ID &parent_id,
+ HierarchyBuildData &build_data,
+ TreeElement &te_to_expand);
+};
+
ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main(
Main *bmain, TreeElement &parent_te, Library *lib)
{
ListBase tree = {nullptr};
+ /* Ensure #Main.relations contains the latest mapping of relations. Must be freed before
+ * returning. */
+ BKE_main_relations_create(bmain, 0);
+
+ OverrideIDHierarchyBuilder builder(space_outliner_, *bmain->relations);
+
/* Keep track over which ID base elements were already added, and expand them once added. */
Map<ID_Type, TreeElement *> id_base_te_map;
/* Index for the ID base elements ("Objects", "Materials", etc). */
@@ -114,111 +143,176 @@ ListBase TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_lib_or_main(
});
TreeElement *new_id_te = outliner_add_element(
- &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0);
- remove_expanded_children(*new_id_te);
+ &space_outliner_, &new_base_te->subtree, iter_id, new_base_te, TSE_SOME_ID, 0, false);
- build_hierarchy_for_ID(bmain, *iter_id, *tree_element_cast<TreeElementID>(new_id_te));
+ builder.build_hierarchy_for_ID(*iter_id, *new_id_te);
}
FOREACH_MAIN_ID_END;
+ BKE_main_relations_free(bmain);
+
return tree;
}
-struct BuildHierarchyForeachIDCbData {
- /* Don't allow copies, the sets below would need deep copying. */
- BuildHierarchyForeachIDCbData(const BuildHierarchyForeachIDCbData &) = delete;
-
- Main &bmain;
- SpaceOutliner &space_outliner;
- ID &override_root_id;
-
- /* The tree element to expand. Changes with every level of recursion. */
- TreeElementID *parent_te;
- /* The ancestor IDs leading to the current ID, to avoid IDs recursing into themselves. Changes
- * with every level of recursion. */
- Set<ID *> parent_ids{};
- /* The IDs that were already added to #parent_te, to avoid duplicates. Entirely new set with
- * every level of recursion. */
- Set<ID *> sibling_ids{};
-};
+void OverrideIDHierarchyBuilder::build_hierarchy_for_ID(ID &override_root_id,
+ TreeElement &te_to_expand)
+{
+ HierarchyBuildData build_data{override_root_id};
+ build_hierarchy_for_ID_recursive(override_root_id, build_data, te_to_expand);
+}
-static int build_hierarchy_foreach_ID_cb(LibraryIDLinkCallbackData *cb_data)
+/* Helpers (defined below). */
+static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations,
+ const ID &parent_id,
+ FunctionRef<void(ID &)> fn);
+static bool id_is_in_override_hierarchy(const ID &id,
+ const ID &relationship_parent_id,
+ const ID &override_root_id);
+
+void OverrideIDHierarchyBuilder::build_hierarchy_for_ID_recursive(const ID &parent_id,
+ HierarchyBuildData &build_data,
+ TreeElement &te_to_expand)
{
- if (!*cb_data->id_pointer) {
- return IDWALK_RET_NOP;
+ /* In case this isn't added to the parents yet (does nothing if already there). */
+ build_data.parent_ids.add(&parent_id);
+
+ foreach_natural_hierarchy_child(id_relations_, parent_id, [&](ID &id) {
+ if (!id_is_in_override_hierarchy(id, parent_id, build_data.override_root_id_)) {
+ return;
+ }
+
+ /* Avoid endless recursion: If there is an ancestor for this ID already, it recurses into
+ * itself. */
+ if (build_data.parent_ids.lookup_key_default(&id, nullptr)) {
+ return;
+ }
+
+ /* Avoid duplicates: If there is a sibling for this ID already, the same ID is just used
+ * multiple times by the same parent. */
+ if (build_data.sibling_ids.lookup_key_default(&id, nullptr)) {
+ return;
+ }
+
+ TreeElement *new_te = outliner_add_element(
+ &space_outliner_, &te_to_expand.subtree, &id, &te_to_expand, TSE_SOME_ID, 0, false);
+
+ build_data.sibling_ids.add(&id);
+
+ /* Recurse into this ID. */
+ HierarchyBuildData child_build_data{build_data.override_root_id_};
+ child_build_data.parent_ids = build_data.parent_ids;
+ child_build_data.parent_ids.add(&id);
+ child_build_data.sibling_ids.reserve(10);
+ build_hierarchy_for_ID_recursive(id, child_build_data, *new_te);
+ });
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Helpers for library override hierarchy building
+ * \{ */
+
+/**
+ * Iterate over the IDs \a parent_id uses. E.g. the child collections and contained objects of a
+ * parent collection. Also does special handling for object parenting, so that:
+ * - When iterating over a child object, \a fn is executed for the parent instead.
+ * - When iterating over a parent object, \a fn is _additionally_ executed for all children. Given
+ * that the parent object isn't skipped, the caller has to ensure it's not added in the hierarchy
+ * twice.
+ * This allows us to build the hierarchy in the expected ("natural") order, where parent objects
+ * are actual parent elements in the hierarchy, even though in data, the relation goes the other
+ * way around (children point to or "use" the parent).
+ *
+ * Only handles regular object parenting, not cases like the "Child of" constraint. Other Outliner
+ * display modes don't show this as parent in the hierarchy either.
+ */
+static void foreach_natural_hierarchy_child(const MainIDRelations &id_relations,
+ const ID &parent_id,
+ FunctionRef<void(ID &)> fn)
+{
+ const MainIDRelationsEntry *relations_of_id = static_cast<MainIDRelationsEntry *>(
+ BLI_ghash_lookup(id_relations.relations_from_pointers, &parent_id));
+
+ /* Iterate over all IDs used by the parent ID (e.g. the child-collections of a collection). */
+ for (MainIDRelationsEntryItem *to_id_entry = relations_of_id->to_ids; to_id_entry;
+ to_id_entry = to_id_entry->next) {
+ /* An ID pointed to (used) by the ID to recurse into. */
+ ID &target_id = **to_id_entry->id_pointer.to;
+
+ /* Don't walk up the hierarchy, e.g. ignore pointers to parent collections. */
+ if (to_id_entry->usage_flag & IDWALK_CB_LOOPBACK) {
+ continue;
+ }
+
+ /* Special case for objects: Process the parent object instead of the child object. Below the
+ * parent will add the child objects then. */
+ if (GS(target_id.name) == ID_OB) {
+ const Object &potential_child_ob = reinterpret_cast<const Object &>(target_id);
+ if (potential_child_ob.parent) {
+ fn(potential_child_ob.parent->id);
+ continue;
+ }
+ }
+
+ fn(target_id);
}
- BuildHierarchyForeachIDCbData &build_data = *reinterpret_cast<BuildHierarchyForeachIDCbData *>(
- cb_data->user_data);
- /* Note that this may be an embedded ID (see #real_override_id). */
- ID &id = **cb_data->id_pointer;
+ /* If the ID is an object, find and iterate over any child objects. */
+ if (GS(parent_id.name) == ID_OB) {
+ for (MainIDRelationsEntryItem *from_id_entry = relations_of_id->from_ids; from_id_entry;
+ from_id_entry = from_id_entry->next) {
+ ID &potential_child_id = *from_id_entry->id_pointer.from;
+
+ if (GS(potential_child_id.name) != ID_OB) {
+ continue;
+ }
+
+ Object &potential_child_ob = reinterpret_cast<Object &>(potential_child_id);
+ if (potential_child_ob.parent && &potential_child_ob.parent->id == &parent_id) {
+ fn(potential_child_id);
+ }
+ }
+ }
+}
+
+static bool id_is_in_override_hierarchy(const ID &id,
+ const ID &relationship_parent_id,
+ const ID &override_root_id)
+{
/* If #id is an embedded ID, this will be set to the owner, which is a real ID and contains the
* override data. So queries of override data should be done via this, but the actual tree
* element we add is the embedded ID. */
const ID *real_override_id = &id;
if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(&id)) {
+ /* This assumes that the parent ID is always the owner of the 'embedded' one, I.e. that no
+ * other ID directly uses the embedded one. Should be true, but the debug code adds some checks
+ * to validate this assumption. */
+ real_override_id = &relationship_parent_id;
+
+#ifndef NDEBUG
if (GS(id.name) == ID_KE) {
- Key *key = (Key *)&id;
- real_override_id = key->from;
+ const Key *key = (Key *)&id;
+ BLI_assert(real_override_id == key->from);
}
- else if (id.flag & LIB_EMBEDDED_DATA) {
- /* TODO Needs double-checking if this handles all embedded IDs correctly. */
- real_override_id = cb_data->id_owner;
+ else {
+ BLI_assert((id.flag & LIB_EMBEDDED_DATA) != 0);
}
+#endif
}
if (!ID_IS_OVERRIDE_LIBRARY(real_override_id)) {
- return IDWALK_RET_NOP;
+ return false;
}
/* Is this ID part of the same override hierarchy? */
- if (real_override_id->override_library->hierarchy_root != &build_data.override_root_id) {
- return IDWALK_RET_NOP;
- }
-
- /* Avoid endless recursion: If there is an ancestor for this ID already, it recurses into itself.
- */
- if (build_data.parent_ids.lookup_key_default(&id, nullptr)) {
- return IDWALK_RET_NOP;
- }
-
- /* Avoid duplicates: If there is a sibling for this ID already, the same ID is just used multiple
- * times by the same parent. */
- if (build_data.sibling_ids.lookup_key_default(&id, nullptr)) {
- return IDWALK_RET_NOP;
+ if (real_override_id->override_library->hierarchy_root != &override_root_id) {
+ return false;
}
- TreeElement *new_te = outliner_add_element(&build_data.space_outliner,
- &build_data.parent_te->getLegacyElement().subtree,
- &id,
- &build_data.parent_te->getLegacyElement(),
- TSE_SOME_ID,
- 0);
- remove_expanded_children(*new_te);
- build_data.sibling_ids.add(&id);
-
- BuildHierarchyForeachIDCbData child_build_data{build_data.bmain,
- build_data.space_outliner,
- build_data.override_root_id,
- tree_element_cast<TreeElementID>(new_te)};
- child_build_data.parent_ids = build_data.parent_ids;
- child_build_data.parent_ids.add(&id);
- child_build_data.sibling_ids.reserve(10);
- BKE_library_foreach_ID_link(
- &build_data.bmain, &id, build_hierarchy_foreach_ID_cb, &child_build_data, IDWALK_READONLY);
-
- return IDWALK_RET_NOP;
+ return true;
}
-void TreeDisplayOverrideLibraryHierarchies::build_hierarchy_for_ID(Main *bmain,
- ID &override_root_id,
- TreeElementID &te_id) const
-{
- BuildHierarchyForeachIDCbData build_data{*bmain, space_outliner_, override_root_id, &te_id};
- build_data.parent_ids.add(&override_root_id);
-
- BKE_library_foreach_ID_link(
- bmain, &te_id.get_ID(), build_hierarchy_foreach_ID_cb, &build_data, IDWALK_READONLY);
-}
+/** \} */
} // namespace blender::ed::outliner
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 80b3365766a..c8869d90eca 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
@@ -271,14 +271,14 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections()
if (!found) {
/* We add the child in the tree even if it is not in the collection.
- * We deliberately clear its sub-tree though, to make it less prominent. */
+ * We don't expand its sub-tree though, to make it less prominent. */
TreeElement *child_ob_tree_element = outliner_add_element(&outliner_,
&parent_ob_tree_element->subtree,
child,
parent_ob_tree_element,
TSE_SOME_ID,
- 0);
- outliner_free_tree(&child_ob_tree_element->subtree);
+ 0,
+ false);
child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION;
child_ob_tree_elements.append(child_ob_tree_element);
}
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 0dcd75d340d..1098068d628 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -94,13 +94,19 @@ class AbstractTreeElement {
* \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().
+ *
+ * \param expand: If true, the element may add its own sub-tree. E.g. objects will list their
+ * animation data, object data, constraints, modifiers, ... This often adds visual
+ * noise, and can be expensive to add in big scenes. So prefer setting this to
+ * false.
*/
struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
ListBase *lb,
void *idv,
struct TreeElement *parent,
short type,
- short index);
+ short index,
+ const bool expand = true);
void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner);
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 ef5e056f229..86f5fd4eff5 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -27,6 +27,11 @@ namespace blender::ed::outliner {
std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_te, ID &id)
{
+ if (ID_TYPE_IS_DEPRECATED(GS(id.name))) {
+ BLI_assert_msg(0, "Outliner trying to build tree-element for deprecated ID type");
+ return nullptr;
+ }
+
switch (ID_Type type = GS(id.name); type) {
case ID_LI:
return std::make_unique<TreeElementIDLibrary>(legacy_te, (Library &)id);
@@ -70,10 +75,9 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
case ID_PC:
case ID_CF:
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");
- return nullptr;
+ BLI_assert_unreachable();
+ break;
}
return nullptr;
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 53e7b88c923..d1babda642e 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -67,21 +67,36 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
for (auto *override_prop :
ListBaseWrapper<IDOverrideLibraryProperty>(id.override_library->properties)) {
+ int rnaprop_index = 0;
const bool is_rna_path_valid = BKE_lib_override_rna_property_find(
- &idpoin, override_prop, &override_rna_ptr, &override_rna_prop);
- if (is_rna_path_valid && !show_system_overrides &&
- ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) &&
- RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) {
- bool do_continue = true;
- for (auto *override_prop_op :
- ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) {
- if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
- do_continue = false;
- break;
+ &idpoin, override_prop, &override_rna_ptr, &override_rna_prop, &rnaprop_index);
+
+ /* Check for conditions where the liboverride property should be considered as a system
+ * override, if needed. */
+ if (is_rna_path_valid && !show_system_overrides) {
+ bool do_skip = true;
+ bool is_system_override = false;
+
+ /* Matching ID pointers are considered as system overrides. */
+ if (ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) &&
+ RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) {
+ for (auto *override_prop_op :
+ ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) {
+ if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
+ do_skip = false;
+ break;
+ }
+ is_system_override = true;
}
}
- if (do_continue) {
+ /* Animated/driven properties are considered as system overrides. */
+ if (!is_system_override && !BKE_lib_override_library_property_is_animated(
+ &id, override_prop, override_rna_prop, rnaprop_index)) {
+ do_skip = false;
+ }
+
+ if (do_skip) {
continue;
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.cc b/source/blender/editors/space_outliner/tree/tree_iterator.cc
index 85ff9e6437e..8d2b0b21433 100644
--- a/source/blender/editors/space_outliner/tree/tree_iterator.cc
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.cc
@@ -43,13 +43,14 @@ void all_open(const SpaceOutliner &space_outliner,
{
LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) {
/* Get needed data out in case element gets freed. */
- const bool is_open = TSELEM_OPEN(element->store_elem, &space_outliner);
+ const TreeStoreElem *tselem = TREESTORE(element);
const ListBase subtree = element->subtree;
visitor(element);
- /* Don't access element from now on, it may be freed. */
+ /* Don't access element from now on, it may be freed. Note that the open/collapsed state may
+ * also have been changed in the visitor callback. */
- if (is_open) {
+ if (TSELEM_OPEN(tselem, &space_outliner)) {
all_open(space_outliner, subtree, visitor);
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_iterator.hh b/source/blender/editors/space_outliner/tree/tree_iterator.hh
index e3b3c90eaad..de5bcd2c462 100644
--- a/source/blender/editors/space_outliner/tree/tree_iterator.hh
+++ b/source/blender/editors/space_outliner/tree/tree_iterator.hh
@@ -26,7 +26,7 @@ void all(const ListBase &subtree, VisitorFn visitor);
/**
* Preorder (meaning depth-first) traversal of all elements not part of a collapsed sub-tree.
- * Freeing the currently visited element in \a visitor is fine.
+ * Freeing the currently visited element in \a visitor is fine (but not its tree-store element).
*/
void all_open(const SpaceOutliner &, VisitorFn visitor);
void all_open(const SpaceOutliner &, const ListBase &subtree, VisitorFn visitor);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 10c6e828e96..dd6d58ee5a2 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -85,6 +85,7 @@ typedef struct SequencerAddData {
#define SEQPROP_NOCHAN (1 << 3)
#define SEQPROP_FIT_METHOD (1 << 4)
#define SEQPROP_VIEW_TRANSFORM (1 << 5)
+#define SEQPROP_PLAYBACK_RATE (1 << 6)
static const EnumPropertyItem scale_fit_methods[] = {
{SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"},
@@ -158,6 +159,14 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
"Set View Transform",
"Set appropriate view transform based on media color space");
}
+
+ if (flag & SEQPROP_PLAYBACK_RATE) {
+ ot->prop = RNA_def_boolean(ot->srna,
+ "adjust_playback_rate",
+ true,
+ "Adjust Playback Rate",
+ "Play at normal speed regardless of scene FPS");
+ }
}
static void sequencer_generic_invoke_path__internal(bContext *C,
@@ -183,7 +192,7 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
Sequence *seq;
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_ensure(scene);
- int timeline_frame = (int)CFRA;
+ int timeline_frame = (int)scene->r.cfra;
int proximity = INT_MAX;
if (!ed || !ed->seqbasep) {
@@ -191,10 +200,11 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if ((ELEM(type, -1, seq->type)) && (seq->enddisp < timeline_frame) &&
- (timeline_frame - seq->enddisp < proximity)) {
+ const int strip_end = SEQ_time_right_handle_frame_get(scene, seq);
+ if ((ELEM(type, -1, seq->type)) && (strip_end < timeline_frame) &&
+ (timeline_frame - strip_end < proximity)) {
tgt = seq;
- proximity = timeline_frame - seq->enddisp;
+ proximity = timeline_frame - strip_end;
}
}
@@ -208,7 +218,7 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i
{
Scene *scene = CTX_data_scene(C);
- int timeline_frame = (int)CFRA;
+ int timeline_frame = (int)scene->r.cfra;
/* Effect strips don't need a channel initialized from the mouse. */
if (!(flag & SEQPROP_NOCHAN) && RNA_struct_property_is_set(op->ptr, "channel") == 0) {
@@ -249,6 +259,10 @@ static void load_data_init_from_operator(SeqLoadData *load_data, bContext *C, wm
SEQ_tool_settings_fit_method_set(CTX_data_scene(C), load_data->fit_method);
}
+ if ((prop = RNA_struct_find_property(op->ptr, "adjust_playback_rate"))) {
+ load_data->adjust_playback_rate = RNA_boolean_get(op->ptr, "adjust_playback_rate");
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
RNA_property_string_get(op->ptr, prop, load_data->path);
BLI_strncpy(load_data->name, BLI_path_basename(load_data->path), sizeof(load_data->name));
@@ -326,7 +340,7 @@ static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence
}
if (RNA_boolean_get(op->ptr, "overlap") == true ||
- !SEQ_transform_test_overlap(ed->seqbasep, seq)) {
+ !SEQ_transform_test_overlap(scene, ed->seqbasep, seq)) {
/* No overlap should be handled or the strip is not overlapping, exit early. */
return;
}
@@ -339,7 +353,7 @@ static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & SEQ_MARKER_TRANS) !=
0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
SEQ_collection_free(strip_col);
}
@@ -369,7 +383,7 @@ static bool seq_load_apply_generic_options_only_test_overlap(bContext *C,
SEQ_collection_append_strip(seq, strip_col);
- return SEQ_transform_test_overlap(ed->seqbasep, seq);
+ return SEQ_transform_test_overlap(scene, ed->seqbasep, seq);
}
static bool seq_effect_add_properties_poll(const bContext *UNUSED(C),
@@ -785,7 +799,6 @@ static void seq_build_proxy(bContext *C, SeqCollection *movie_strips)
}
static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
- ListBase *seqbase,
Sequence *seq_movie,
Sequence *seq_sound)
{
@@ -793,9 +806,10 @@ static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
return;
}
- SEQ_time_right_handle_frame_set(seq_sound, SEQ_time_right_handle_frame_get(seq_movie));
- SEQ_time_left_handle_frame_set(seq_sound, SEQ_time_left_handle_frame_get(seq_movie));
- SEQ_time_update_sequence(scene, seqbase, seq_sound);
+ SEQ_time_right_handle_frame_set(
+ scene, seq_sound, SEQ_time_right_handle_frame_get(scene, seq_movie));
+ SEQ_time_left_handle_frame_set(
+ scene, seq_sound, SEQ_time_left_handle_frame_get(scene, seq_movie));
}
static void sequencer_add_movie_multiple_strips(bContext *C,
@@ -833,7 +847,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
else {
if (RNA_boolean_get(op->ptr, "sound")) {
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
- sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
+ sequencer_add_movie_clamp_sound_strip_length(scene, seq_movie, seq_sound);
if (seq_sound) {
/* The video has sound, shift the video strip up a channel to make room for the sound
@@ -842,7 +856,8 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
}
}
- load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
+ load_data->start_frame += SEQ_time_right_handle_frame_get(scene, seq_movie) -
+ SEQ_time_left_handle_frame_get(scene, seq_movie);
if (overlap_shuffle_override) {
has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap(
C, op, seq_sound, strip_col);
@@ -863,7 +878,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
}
SEQ_collection_free(strip_col);
@@ -890,7 +905,7 @@ static bool sequencer_add_movie_single_strip(bContext *C,
}
if (RNA_boolean_get(op->ptr, "sound")) {
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data);
- sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
+ sequencer_add_movie_clamp_sound_strip_length(scene, seq_movie, seq_sound);
if (seq_sound) {
/* The video has sound, shift the video strip up a channel to make room for the sound
* strip. */
@@ -913,7 +928,7 @@ static bool sequencer_add_movie_single_strip(bContext *C,
ScrArea *area = CTX_wm_area(C);
const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
- SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers);
+ SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, NULL, use_sync_markers);
}
SEQ_collection_free(strip_col);
@@ -976,6 +991,7 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
sequencer_disable_one_time_properties(C, op);
RNA_enum_set(op->ptr, "fit_method", SEQ_tool_settings_fit_method_get(scene));
+ RNA_boolean_set(op->ptr, "adjust_playback_rate", true);
/* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") &&
@@ -1042,8 +1058,9 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
- sequencer_generic_props__internal(
- ot, SEQPROP_STARTFRAME | SEQPROP_FIT_METHOD | SEQPROP_VIEW_TRANSFORM);
+ sequencer_generic_props__internal(ot,
+ SEQPROP_STARTFRAME | SEQPROP_FIT_METHOD |
+ SEQPROP_VIEW_TRANSFORM | SEQPROP_PLAYBACK_RATE);
RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie");
RNA_def_boolean(ot->srna,
"use_framerate",
@@ -1073,7 +1090,8 @@ static void sequencer_add_sound_multiple_strips(bContext *C,
}
else {
seq_load_apply_generic_options(C, op, seq);
- load_data->start_frame += seq->enddisp - seq->startdisp;
+ load_data->start_frame += SEQ_time_right_handle_frame_get(scene, seq) -
+ SEQ_time_left_handle_frame_get(scene, seq);
}
}
RNA_END;
@@ -1249,8 +1267,12 @@ static int sequencer_add_image_strip_calculate_length(wmOperator *op,
return RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
}
-static void sequencer_add_image_strip_load_files(
- wmOperator *op, Sequence *seq, SeqLoadData *load_data, const int minframe, const int numdigits)
+static void sequencer_add_image_strip_load_files(wmOperator *op,
+ Scene *scene,
+ Sequence *seq,
+ SeqLoadData *load_data,
+ const int minframe,
+ const int numdigits)
{
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
/* size of Strip->dir. */
@@ -1266,7 +1288,7 @@ static void sequencer_add_image_strip_load_files(
size_t strip_frame = 0;
RNA_BEGIN (op->ptr, itemptr, "files") {
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0, NULL);
- SEQ_add_image_load_file(seq, strip_frame, filename);
+ SEQ_add_image_load_file(scene, seq, strip_frame, filename);
MEM_freeN(filename);
strip_frame++;
}
@@ -1295,13 +1317,12 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
}
Sequence *seq = SEQ_add_image_strip(CTX_data_main(C), scene, ed->seqbasep, &load_data);
- sequencer_add_image_strip_load_files(op, seq, &load_data, minframe, numdigits);
+ sequencer_add_image_strip_load_files(op, scene, seq, &load_data, minframe, numdigits);
SEQ_add_image_init_alpha_mode(seq);
/* Adjust length. */
if (load_data.image.len == 1) {
- SEQ_time_right_handle_frame_set(seq, load_data.image.end_frame);
- SEQ_time_update_sequence(scene, SEQ_active_seqbase_get(ed), seq);
+ SEQ_time_right_handle_frame_set(scene, seq, load_data.image.end_frame);
}
seq_load_apply_generic_options(C, op, seq);
diff --git a/source/blender/editors/space_sequencer/sequencer_channels_draw.c b/source/blender/editors/space_sequencer/sequencer_channels_draw.c
index c11388e8555..81fc87598f8 100644
--- a/source/blender/editors/space_sequencer/sequencer_channels_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_channels_draw.c
@@ -97,7 +97,7 @@ static void displayed_channel_range_get(const SeqChannelDrawContext *context,
rctf strip_boundbox;
BLI_rctf_init(&strip_boundbox, 0.0f, 0.0f, 1.0f, r_channel_range[1]);
- SEQ_timeline_expand_boundbox(context->seqbase, &strip_boundbox);
+ SEQ_timeline_expand_boundbox(context->scene, context->seqbase, &strip_boundbox);
CLAMP(r_channel_range[0], strip_boundbox.ymin, strip_boundbox.ymax);
CLAMP(r_channel_range[1], strip_boundbox.ymin, MAXSEQ);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c
index 645c0dc9a1d..f6561cf07b9 100644
--- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c
+++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c
@@ -167,7 +167,7 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
SpaceSeq *sseq = CTX_wm_space_seq(C);
SeqCollection *strips = SEQ_query_rendered_strips(
- channels, seqbase, scene->r.cfra, sseq->chanshown);
+ scene, channels, seqbase, scene->r.cfra, sseq->chanshown);
/* Get the top most strip channel that is in view.*/
Sequence *seq;
@@ -179,6 +179,7 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
if (max_channel != -1) {
RNA_int_set(drop->ptr, "channel", max_channel);
}
+ SEQ_collection_free(strips);
}
}
}
@@ -231,13 +232,12 @@ static void update_overlay_strip_poistion_data(bContext *C, const int mval[2])
else {
/* Check if there is a strip that would intersect with the new strip(s). */
coords->is_intersecting = false;
- Sequence dummy_seq = {.machine = coords->channel,
- .startdisp = coords->start_frame,
- .enddisp = coords->start_frame + coords->strip_len};
- Editing *ed = SEQ_editing_get(scene);
+ Sequence dummy_seq = {
+ .machine = coords->channel, .start = coords->start_frame, .len = coords->strip_len};
+ Editing *ed = SEQ_editing_ensure(scene);
for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) {
- coords->is_intersecting = SEQ_transform_test_overlap(ed->seqbasep, &dummy_seq);
+ coords->is_intersecting = SEQ_transform_test_overlap(scene, ed->seqbasep, &dummy_seq);
dummy_seq.machine++;
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 02e77732e02..eb2e4ef05e5 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -241,329 +241,296 @@ typedef struct WaveVizData {
float pos[2];
float rms_pos;
bool clip;
- bool end;
+ bool draw_line; /* Draw triangle otherwise. */
+ bool final_sample; /* There are no more samples. */
} WaveVizData;
-static int get_section_len(WaveVizData *start, WaveVizData *end)
+static bool seq_draw_waveforms_poll(const bContext *UNUSED(C), SpaceSeq *sseq, Sequence *seq)
{
- int len = 0;
- while (start != end) {
- len++;
- if (start->end) {
- return len;
- }
- start++;
- }
- return len;
-}
+ const bool strip_is_valid = seq->type == SEQ_TYPE_SOUND_RAM && seq->sound != NULL;
+ const bool overlays_enabled = (sseq->flag & SEQ_SHOW_OVERLAY) != 0;
+ const bool ovelay_option = ((sseq->timeline_overlay.flag & SEQ_TIMELINE_ALL_WAVEFORMS) != 0 ||
+ (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM));
-static void draw_waveform(WaveVizData *iter, WaveVizData *end, GPUPrimType prim_type, bool use_rms)
-{
- int strip_len = get_section_len(iter, end);
- if (strip_len > 1) {
- GPU_blend(GPU_BLEND_ALPHA);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_NO_WAVEFORMS) != 0) {
+ return false;
+ }
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- immBegin(prim_type, strip_len);
+ if (strip_is_valid && overlays_enabled && ovelay_option) {
+ return true;
+ }
- while (iter != end) {
- if (iter->clip) {
- immAttr4f(col, 1.0f, 0.0f, 0.0f, 0.5f);
- }
- else if (use_rms) {
- immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.8f);
- }
- else {
- immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.5f);
- }
+ return false;
+}
- if (use_rms) {
- immVertex2f(pos, iter->pos[0], iter->rms_pos);
- }
- else {
- immVertex2f(pos, iter->pos[0], iter->pos[1]);
- }
+static void waveform_job_start_if_needed(const bContext *C, Sequence *seq)
+{
+ bSound *sound = seq->sound;
- if (iter->end) {
- /* End of line. */
- iter++;
- strip_len = get_section_len(iter, end);
- if (strip_len != 0) {
- immEnd();
- immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- immBegin(prim_type, strip_len);
- }
- }
- else {
- iter++;
- }
+ BLI_spin_lock(sound->spinlock);
+ if (!sound->waveform) {
+ /* Load the waveform data if it hasn't been loaded and cached already. */
+ if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {
+ /* Prevent sounds from reloading. */
+ sound->tags |= SOUND_TAGS_WAVEFORM_LOADING;
+ BLI_spin_unlock(sound->spinlock);
+ sequencer_preview_add_sound(C, seq);
+ }
+ else {
+ BLI_spin_unlock(sound->spinlock);
}
- immEnd();
- immUnbindProgram();
-
- GPU_blend(GPU_BLEND_NONE);
}
+ BLI_spin_unlock(sound->spinlock);
}
-static float clamp_frame_coord_to_pixel(float frame_coord,
- float pixel_frac,
- float frames_per_pixel)
+static size_t get_vertex_count(WaveVizData *waveform_data)
{
- float cur_pixel = (frame_coord / frames_per_pixel);
- float new_pixel = (int)(frame_coord / frames_per_pixel) + pixel_frac;
- if (cur_pixel > new_pixel) {
- new_pixel += 1.0f;
+ bool draw_line = waveform_data->draw_line;
+ size_t length = 0;
+
+ while (waveform_data->draw_line == draw_line && !waveform_data->final_sample) {
+ waveform_data++;
+ length++;
}
- return new_pixel * frames_per_pixel;
+
+ return length;
}
-/**
- * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2.
- * \param frames_per_pixel: The amount of pixels a whole frame takes up (x-axis direction).
- */
-static void draw_seq_waveform_overlay(View2D *v2d,
- const bContext *C,
- SpaceSeq *sseq,
- Scene *scene,
- Sequence *seq,
- float x1,
- float y1,
- float x2,
- float y2,
- float frames_per_pixel)
+static size_t draw_waveform_segment(WaveVizData *waveform_data, bool use_rms)
{
- 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
- * window starts.
- * We then append this pixel offset to our strip start coordinate to ensure we are aligned to
- * the screen pixel grid. */
- float pixel_frac = v2d->cur.xmin / frames_per_pixel - floor(v2d->cur.xmin / frames_per_pixel);
- float x1_adj = clamp_frame_coord_to_pixel(x1, pixel_frac, frames_per_pixel);
-
- /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
- float x1_offset = max_ff(v2d->cur.xmin, x1_adj);
- float x2_offset = min_ff(v2d->cur.xmax, x2);
-
- /* Calculate how long the strip that is in view is in pixels. */
- int pix_strip_len = round((x2_offset - x1_offset) / frames_per_pixel);
-
- if (pix_strip_len < 2) {
- return;
- }
+ size_t vertices_done = 0;
+ size_t vertex_count = get_vertex_count(waveform_data);
- bSound *sound = seq->sound;
+ /* Not enough data to draw. */
+ if (vertex_count <= 2) {
+ return vertex_count;
+ }
- BLI_spin_lock(sound->spinlock);
- if (!sound->waveform) {
- /* Load the waveform data if it hasn't been loaded and cached already. */
- if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {
- /* Prevent sounds from reloading. */
- sound->tags |= SOUND_TAGS_WAVEFORM_LOADING;
- BLI_spin_unlock(sound->spinlock);
- sequencer_preview_add_sound(C, seq);
- }
- else {
- BLI_spin_unlock(sound->spinlock);
- }
- return; /* Nothing to draw. */
- }
- BLI_spin_unlock(sound->spinlock);
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPUVertFormat *format = immVertexFormat();
+ GPUPrimType prim_type = waveform_data->draw_line ? GPU_PRIM_LINE_STRIP : GPU_PRIM_TRI_STRIP;
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ immBegin(prim_type, vertex_count);
- SoundWaveform *waveform = sound->waveform;
+ while (vertices_done < vertex_count && !waveform_data->final_sample) {
+ /* Color. */
+ if (waveform_data->clip) {
+ immAttr4f(col, 1.0f, 0.0f, 0.0f, 0.5f);
+ }
+ else if (use_rms) {
+ immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.8f);
+ }
+ else {
+ immAttr4f(col, 1.0f, 1.0f, 1.0f, 0.5f);
+ }
- /* Waveform could not be built. */
- if (waveform->length == 0) {
- return;
+ /* Vertices. */
+ if (use_rms) {
+ immVertex2f(pos, waveform_data->pos[0], waveform_data->rms_pos);
+ }
+ else {
+ immVertex2f(pos, waveform_data->pos[0], waveform_data->pos[1]);
}
- /* F-Curve lookup is quite expensive, so do this after precondition. */
- FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
+ vertices_done++;
+ waveform_data++;
+ }
- WaveVizData *tri_strip_arr = MEM_callocN(sizeof(*tri_strip_arr) * pix_strip_len * 2,
- "tri_strip");
- WaveVizData *line_strip_arr = MEM_callocN(sizeof(*line_strip_arr) * pix_strip_len,
- "line_strip");
+ immEnd();
+ immUnbindProgram();
- WaveVizData *tri_strip_iter = tri_strip_arr;
- WaveVizData *line_strip_iter = line_strip_arr;
+ GPU_blend(GPU_BLEND_NONE);
- /* The y coordinate for the middle of the strip. */
- float y_mid = (y1 + y2) / 2.0f;
- /* The length from the middle of the strip to the top/bottom. */
- float y_scale = (y2 - y1) / 2.0f;
- float volume = seq->volume;
+ return vertices_done;
+}
- /* Value to keep track if the previous item to be drawn was a line strip. */
- int8_t was_line_strip = -1; /* -1 == no previous value. */
+static void draw_waveform(WaveVizData *waveform_data, size_t wave_data_len)
+{
+ size_t items_done = 0;
+ while (items_done < wave_data_len) {
+ if (!waveform_data[items_done].draw_line) { /* Draw RMS. */
+ draw_waveform_segment(&waveform_data[items_done], true);
+ }
+ items_done += draw_waveform_segment(&waveform_data[items_done], false);
+ }
+}
- float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS;
+static float align_frame_with_pixel(float frame_coord, float frames_per_pixel)
+{
+ return round_fl_to_int(frame_coord / frames_per_pixel) * frames_per_pixel;
+}
- /* How many samples do we have for each pixel? */
- float samples_per_pix = samples_per_frame * frames_per_pixel;
+static void write_waveform_data(WaveVizData *waveform_data,
+ const vec2f pos,
+ const float rms,
+ const bool is_clipping,
+ const bool draw_line)
+{
+ waveform_data->pos[0] = pos.x;
+ waveform_data->pos[1] = pos.y;
+ waveform_data->clip = is_clipping;
+ waveform_data->rms_pos = rms;
+ waveform_data->draw_line = draw_line;
+}
- float strip_start_offset = seq->startofs + seq->anim_startofs;
- float start_sample = 0;
+static size_t waveform_append_sample(WaveVizData *waveform_data,
+ vec2f pos,
+ const float value_min,
+ const float value_max,
+ const float y_mid,
+ const float y_scale,
+ const float rms,
+ const bool is_clipping,
+ const bool is_line_strip)
+{
+ size_t data_written = 0;
+ pos.y = y_mid + value_min * y_scale;
+ float rms_value = y_mid + max_ff(-rms, value_min) * y_scale;
+ write_waveform_data(&waveform_data[0], pos, rms_value, is_clipping, is_line_strip);
+ data_written++;
+
+ /* Use `value_max` as second vertex for triangle drawing. */
+ if (!is_line_strip) {
+ pos.y = y_mid + value_max * y_scale;
+ rms_value = y_mid + min_ff(rms, value_max) * y_scale;
+ write_waveform_data(&waveform_data[1], pos, rms_value, is_clipping, is_line_strip);
+ data_written++;
+ }
+ return data_written;
+}
- if (strip_start_offset != 0) {
- /* If start offset is not zero, we need to make sure that we pick the same start sample as if
- * we simply scrolled the start of the strip off-screen. Otherwise we will get flickering
- * when changing start offset as the pixel alignment will not be the same for the drawn
- * samples. */
- strip_start_offset = clamp_frame_coord_to_pixel(
- x1 - strip_start_offset, pixel_frac, frames_per_pixel);
- start_sample = fabsf(strip_start_offset - x1_adj) * samples_per_frame;
- }
+/**
+ * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2.
+ * \param frames_per_pixel: The amount of pixels a whole frame takes up (x-axis direction).
+ */
+static void draw_seq_waveform_overlay(
+ const bContext *C, ARegion *region, Sequence *seq, float x1, float y1, float x2, float y2)
+{
+ const View2D *v2d = &region->v2d;
+ Scene *scene = CTX_data_scene(C);
- start_sample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND;
- /* If we scrolled the start off-screen, then the start sample should be at the first visible
- * sample. */
- start_sample += (x1_offset - x1_adj) * samples_per_frame;
+ const float frames_per_pixel = BLI_rctf_size_x(&region->v2d.cur) / region->winx;
+ const float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS;
+ float samples_per_pixel = samples_per_frame * frames_per_pixel;
- for (int i = 0; i < pix_strip_len; i++) {
- float sample_offset = start_sample + i * samples_per_pix;
- int p = sample_offset;
+ /* Align strip start with nearest pixel to prevent waveform flickering. */
+ const float x1_aligned = align_frame_with_pixel(x1, frames_per_pixel);
+ /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
+ const float frame_start = max_ff(v2d->cur.xmin, x1_aligned);
+ const float frame_end = min_ff(v2d->cur.xmax, x2);
+ const int pixels_to_draw = round_fl_to_int((frame_end - frame_start) / frames_per_pixel);
- if (p < 0) {
- continue;
- }
+ if (pixels_to_draw < 2) {
+ return; /* Not much to draw, exit before running job. */
+ }
- if (p >= waveform->length) {
- break;
- }
+ waveform_job_start_if_needed(C, seq);
- float value_min = waveform->data[p * 3];
- float value_max = waveform->data[p * 3 + 1];
- float rms = waveform->data[p * 3 + 2];
-
- if (p + 1 < waveform->length) {
- /* Use simple linear interpolation. */
- float f = sample_offset - p;
- value_min = (1.0f - f) * value_min + f * waveform->data[p * 3 + 3];
- value_max = (1.0f - f) * value_max + f * waveform->data[p * 3 + 4];
- rms = (1.0f - f) * rms + f * waveform->data[p * 3 + 5];
- if (samples_per_pix > 1.0f) {
- /* We need to sum up the values we skip over until the next step. */
- float next_pos = sample_offset + samples_per_pix;
- int end_idx = next_pos;
-
- for (int j = p + 1; (j < waveform->length) && (j < end_idx); j++) {
- value_min = min_ff(value_min, waveform->data[j * 3]);
- value_max = max_ff(value_max, waveform->data[j * 3 + 1]);
- rms = max_ff(rms, waveform->data[j * 3 + 2]);
- }
- }
- }
+ SoundWaveform *waveform = seq->sound->waveform;
+ if (waveform == NULL || waveform->length == 0) {
+ return; /* Waveform was not built. */
+ }
- if (fcu && !BKE_fcurve_is_empty(fcu)) {
- float evaltime = x1_offset + (i * frames_per_pixel);
- volume = evaluate_fcurve(fcu, evaltime);
- CLAMP_MIN(volume, 0.0f);
- }
+ /* F-Curve lookup is quite expensive, so do this after precondition. */
+ FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
+ WaveVizData *waveform_data = MEM_callocN(sizeof(WaveVizData) * pixels_to_draw * 3, __func__);
+ size_t wave_data_len = 0;
- value_min *= volume;
- value_max *= volume;
- rms *= volume;
+ /* Offset must be also aligned, otherwise waveform flickers when moving left handle. */
+ const float strip_offset = align_frame_with_pixel(seq->startofs + seq->anim_startofs,
+ frames_per_pixel);
+ float start_sample = strip_offset * samples_per_frame;
+ start_sample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND;
+ /* Add off-screen part of strip to offset. */
+ start_sample += (frame_start - x1_aligned) * samples_per_frame;
- bool clipping = false;
+ for (int i = 0; i < pixels_to_draw; i++) {
+ float sample = start_sample + i * samples_per_pixel;
+ int sample_index = round_fl_to_int(sample);
- if (value_max > 1 || value_min < -1) {
- clipping = true;
+ if (sample_index < 0) {
+ continue;
+ }
- CLAMP_MAX(value_max, 1.0f);
- CLAMP_MIN(value_min, -1.0f);
- }
+ if (sample_index >= waveform->length) {
+ break;
+ }
- bool is_line_strip = (value_max - value_min < 0.05f);
-
- if (!ELEM(was_line_strip, -1, is_line_strip)) {
- /* If the previously added strip type isn't the same as the current one,
- * add transition areas so they transition smoothly between each other. */
- if (is_line_strip) {
- /* This will be a line strip, end the tri strip. */
- tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel;
- tri_strip_iter->pos[1] = y_mid + value_min * y_scale;
- tri_strip_iter->clip = clipping;
- tri_strip_iter->rms_pos = tri_strip_iter->pos[1];
- tri_strip_iter->end = true;
-
- /* End of section. */
- tri_strip_iter++;
-
- /* Check if we are at the end.
- * If so, skip one point line. */
- if (i + 1 == pix_strip_len) {
- continue;
- }
- }
- else {
- /* This will be a tri strip. */
- line_strip_iter--;
- tri_strip_iter->pos[0] = line_strip_iter->pos[0];
- tri_strip_iter->pos[1] = line_strip_iter->pos[1];
- tri_strip_iter->clip = line_strip_iter->clip;
- tri_strip_iter->rms_pos = line_strip_iter->pos[1];
- tri_strip_iter++;
-
- /* Check if line had only one point. */
- line_strip_iter--;
- if (line_strip_iter < line_strip_arr || line_strip_iter->end) {
- /* Only one point, skip it. */
- line_strip_iter++;
- }
- else {
- /* End of section. */
- line_strip_iter++;
- line_strip_iter->end = true;
- line_strip_iter++;
- }
+ float value_min = waveform->data[sample_index * 3];
+ float value_max = waveform->data[sample_index * 3 + 1];
+ float rms = waveform->data[sample_index * 3 + 2];
+
+ if (sample_index + 1 < waveform->length) {
+ /* Use simple linear interpolation. */
+ float f = sample - sample_index;
+ value_min = (1.0f - f) * value_min + f * waveform->data[sample_index * 3 + 3];
+ value_max = (1.0f - f) * value_max + f * waveform->data[sample_index * 3 + 4];
+ rms = (1.0f - f) * rms + f * waveform->data[sample_index * 3 + 5];
+ if (samples_per_pixel > 1.0f) {
+ /* We need to sum up the values we skip over until the next step. */
+ float next_pos = sample + samples_per_pixel;
+ int end_idx = next_pos;
+
+ for (int j = sample_index + 1; (j < waveform->length) && (j < end_idx); j++) {
+ value_min = min_ff(value_min, waveform->data[j * 3]);
+ value_max = max_ff(value_max, waveform->data[j * 3 + 1]);
+ rms = max_ff(rms, waveform->data[j * 3 + 2]);
}
}
+ }
- was_line_strip = is_line_strip;
-
- if (is_line_strip) {
- line_strip_iter->pos[0] = x1_offset + i * frames_per_pixel;
- line_strip_iter->pos[1] = y_mid + value_min * y_scale;
- line_strip_iter->clip = clipping;
- line_strip_iter++;
- }
- else {
- tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel;
- tri_strip_iter->pos[1] = y_mid + value_min * y_scale;
- tri_strip_iter->clip = clipping;
- tri_strip_iter->rms_pos = y_mid + max_ff(-rms, value_min) * y_scale;
- tri_strip_iter++;
-
- tri_strip_iter->pos[0] = x1_offset + i * frames_per_pixel;
- tri_strip_iter->pos[1] = y_mid + value_max * y_scale;
- tri_strip_iter->clip = clipping;
- tri_strip_iter->rms_pos = y_mid + min_ff(rms, value_max) * y_scale;
- tri_strip_iter++;
- }
+ float volume = seq->volume;
+ if (fcu && !BKE_fcurve_is_empty(fcu)) {
+ float evaltime = frame_start + (i * frames_per_pixel);
+ volume = evaluate_fcurve(fcu, evaltime);
+ CLAMP_MIN(volume, 0.0f);
}
- WaveVizData *tri_strip_end = tri_strip_iter;
- WaveVizData *line_strip_end = line_strip_iter;
+ value_min *= volume;
+ value_max *= volume;
+ rms *= volume;
- tri_strip_iter = tri_strip_arr;
- line_strip_iter = line_strip_arr;
+ bool is_clipping = false;
- draw_waveform(line_strip_iter, line_strip_end, GPU_PRIM_LINE_STRIP, false);
- draw_waveform(tri_strip_iter, tri_strip_end, GPU_PRIM_TRI_STRIP, false);
- draw_waveform(tri_strip_iter, tri_strip_end, GPU_PRIM_TRI_STRIP, true);
+ if (value_max > 1 || value_min < -1) {
+ is_clipping = true;
- MEM_freeN(tri_strip_arr);
- MEM_freeN(line_strip_arr);
+ CLAMP_MAX(value_max, 1.0f);
+ CLAMP_MIN(value_min, -1.0f);
+ }
+
+ bool is_line_strip = (value_max - value_min < 0.05f);
+ /* The y coordinate for the middle of the strip. */
+ float y_mid = (y1 + y2) / 2.0f;
+ /* The length from the middle of the strip to the top/bottom. */
+ float y_scale = (y2 - y1) / 2.0f;
+
+ vec2f pos = {frame_start + i * frames_per_pixel, y_mid + value_min * y_scale};
+ WaveVizData *new_data = &waveform_data[wave_data_len];
+ wave_data_len += waveform_append_sample(
+ new_data, pos, value_min, value_max, y_mid, y_scale, rms, is_clipping, is_line_strip);
}
+
+ /* Terminate array, so `get_segment_length()` can know when to stop. */
+ waveform_data[wave_data_len].final_sample = true;
+ draw_waveform(waveform_data, wave_data_len);
+ MEM_freeN(waveform_data);
}
+/*
+static size_t *waveform_append(WaveVizData *waveform_data,
+ vec2f pos,
+ const float value_min,
+ const float value_max,
+ const float y_mid,
+ const float y_scale,
+ const float rms,
+ const bool is_clipping,
+ const bool is_line_strip)
+*/
+
static void drawmeta_contents(Scene *scene,
Sequence *seqm,
float x1,
@@ -617,8 +584,8 @@ static void drawmeta_contents(Scene *scene,
/* Draw only immediate children (1 level depth). */
for (seq = meta_seqbase->first; seq; seq = seq->next) {
- const int startdisp = seq->startdisp + offset;
- const int enddisp = seq->enddisp + offset;
+ const int startdisp = SEQ_time_left_handle_frame_get(scene, seq) + offset;
+ const int enddisp = SEQ_time_right_handle_frame_get(scene, seq) + offset;
if ((startdisp > x2 || enddisp < x1) == 0) {
float y_chan = (seq->machine - chan_min) / (float)(chan_range)*draw_range;
@@ -663,16 +630,20 @@ static void drawmeta_contents(Scene *scene,
GPU_blend(GPU_BLEND_NONE);
}
-float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
+float sequence_handle_size_get_clamped(const Scene *scene, Sequence *seq, const float pixelx)
{
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
/* Ensure that handle is not wider, than quarter of strip. */
- return min_ff(maxhandle, ((float)(seq->enddisp - seq->startdisp) / 4.0f));
+ return min_ff(maxhandle,
+ ((float)(SEQ_time_right_handle_frame_get(scene, seq) -
+ SEQ_time_left_handle_frame_get(scene, seq)) /
+ 4.0f));
}
/* Draw a handle, on left or right side of strip. */
-static void draw_seq_handle(View2D *v2d,
+static void draw_seq_handle(const Scene *scene,
+ View2D *v2d,
Sequence *seq,
const float handsize_clamped,
const short direction,
@@ -686,8 +657,8 @@ static void draw_seq_handle(View2D *v2d,
uint whichsel = 0;
uchar col[4];
- x1 = seq->startdisp;
- x2 = seq->enddisp;
+ x1 = SEQ_time_left_handle_frame_get(scene, seq);
+ x2 = SEQ_time_right_handle_frame_get(scene, seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
@@ -739,7 +710,11 @@ static void draw_seq_handle(View2D *v2d,
BLF_set_default();
/* Calculate if strip is wide enough for showing the labels. */
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d%d", seq->startdisp, seq->enddisp);
+ numstr_len = BLI_snprintf_rlen(numstr,
+ sizeof(numstr),
+ "%d%d",
+ SEQ_time_left_handle_frame_get(scene, seq),
+ SEQ_time_right_handle_frame_get(scene, seq));
float tot_width = BLF_width(fontid, numstr, numstr_len);
if ((x2 - x1) / pixelx > 20 + tot_width) {
@@ -747,12 +722,14 @@ static void draw_seq_handle(View2D *v2d,
float text_margin = 1.2f * handsize_clamped;
if (direction == SEQ_LEFTHANDLE) {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->startdisp);
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%d", SEQ_time_left_handle_frame_get(scene, seq));
x1 += text_margin;
y1 += 0.09f;
}
else {
- numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%d", seq->enddisp - 1);
+ numstr_len = BLI_snprintf_rlen(
+ numstr, sizeof(numstr), "%d", SEQ_time_right_handle_frame_get(scene, seq) - 1);
x1 = x2 - (text_margin + pixelx * BLF_width(fontid, numstr, numstr_len));
y1 += 0.09f;
}
@@ -887,7 +864,8 @@ static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t sourc
}
}
-static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq,
+static size_t draw_seq_text_get_overlay_string(const Scene *scene,
+ SpaceSeq *sseq,
Sequence *seq,
char *r_overlay_string,
size_t overlay_string_len)
@@ -913,7 +891,8 @@ static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq,
char strip_duration_text[16];
if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) {
- const int strip_duration = seq->enddisp - seq->startdisp;
+ const int strip_duration = SEQ_time_right_handle_frame_get(scene, seq) -
+ SEQ_time_left_handle_frame_get(scene, seq);
SNPRINTF(strip_duration_text, "%d", strip_duration);
if (i != 0) {
text_array[i++] = text_sep;
@@ -942,7 +921,7 @@ static void draw_seq_text_overlay(Scene *scene,
ListBase *channels = SEQ_channels_displayed_get(ed);
char overlay_string[FILE_MAX];
size_t overlay_string_len = draw_seq_text_get_overlay_string(
- sseq, seq, overlay_string, sizeof(overlay_string));
+ scene, sseq, seq, overlay_string, sizeof(overlay_string));
if (overlay_string_len == 0) {
return;
@@ -980,8 +959,8 @@ static void draw_sequence_extensions_overlay(
float x1, x2, y1, y2;
uchar col[4], blend_col[3];
- x1 = seq->startdisp;
- x2 = seq->enddisp;
+ x1 = SEQ_time_left_handle_frame_get(scene, seq);
+ x2 = SEQ_time_right_handle_frame_get(scene, seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
@@ -995,28 +974,32 @@ static void draw_sequence_extensions_overlay(
col[3] = SEQ_render_is_muted(channels, seq) ? MUTE_ALPHA : 200;
UI_GetColorPtrShade3ubv(col, blend_col, 10);
- if (seq->startofs) {
+ const float strip_content_start = SEQ_time_start_frame_get(seq);
+ const float strip_content_end = SEQ_time_start_frame_get(seq) +
+ SEQ_time_strip_length_get(scene, seq);
+ float right_handle_frame = SEQ_time_right_handle_frame_get(scene, seq);
+ float left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
+
+ if (left_handle_frame > strip_content_start) {
immUniformColor4ubv(col);
- immRectf(pos, (float)(seq->start), y1 - pixely, x1, y1 - SEQ_STRIP_OFSBOTTOM);
+ immRectf(pos, strip_content_start, y1 - pixely, x1, y1 - SEQ_STRIP_OFSBOTTOM);
/* Outline. */
immUniformColor3ubv(blend_col);
- imm_draw_box_wire_2d(pos, x1, y1 - pixely, (float)(seq->start), y1 - SEQ_STRIP_OFSBOTTOM);
+ imm_draw_box_wire_2d(pos, x1, y1 - pixely, strip_content_start, y1 - SEQ_STRIP_OFSBOTTOM);
}
- if (seq->endofs) {
+ if (right_handle_frame < strip_content_end) {
immUniformColor4ubv(col);
- immRectf(pos, x2, y2 + pixely, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
+ immRectf(pos, x2, y2 + pixely, strip_content_end, y2 + SEQ_STRIP_OFSBOTTOM);
- /* Outline. */
- immUniformColor3ubv(blend_col);
- imm_draw_box_wire_2d(
- pos, x2, y2 + pixely, (float)(seq->start + seq->len), y2 + SEQ_STRIP_OFSBOTTOM);
+ /* Outline. */ immUniformColor3ubv(blend_col);
+ imm_draw_box_wire_2d(pos, x2, y2 + pixely, strip_content_end, y2 + SEQ_STRIP_OFSBOTTOM);
}
GPU_blend(GPU_BLEND_NONE);
}
static void draw_color_strip_band(
- ListBase *channels, Sequence *seq, uint pos, float text_margin_y, float y1)
+ const Scene *scene, ListBase *channels, Sequence *seq, uint pos, float text_margin_y, float y1)
{
uchar col[4];
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
@@ -1038,15 +1021,19 @@ static void draw_color_strip_band(
immUniformColor4ubv(col);
- immRectf(pos, seq->startdisp, y1, seq->enddisp, text_margin_y);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ y1,
+ SEQ_time_right_handle_frame_get(scene, seq),
+ text_margin_y);
/* 1px line to better separate the color band. */
UI_GetColorPtrShade3ubv(col, col, -20);
immUniformColor4ubv(col);
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, seq->startdisp, text_margin_y);
- immVertex2f(pos, seq->enddisp, text_margin_y);
+ immVertex2f(pos, SEQ_time_left_handle_frame_get(scene, seq), text_margin_y);
+ immVertex2f(pos, SEQ_time_right_handle_frame_get(scene, seq), text_margin_y);
immEnd();
GPU_blend(GPU_BLEND_NONE);
@@ -1098,25 +1085,31 @@ static void draw_seq_background(Scene *scene,
/* Draw the main strip body. */
if (is_single_image) {
- immRectf(
- pos, SEQ_time_left_handle_frame_get(seq), y1, SEQ_time_right_handle_frame_get(seq), y2);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ y1,
+ SEQ_time_right_handle_frame_get(scene, seq),
+ y2);
}
else {
immRectf(pos, x1, y1, x2, y2);
}
/* Draw background for hold still regions. */
- if (!is_single_image && SEQ_time_has_still_frames(seq)) {
+ if (!is_single_image) {
UI_GetColorPtrShade3ubv(col, col, -35);
immUniformColor4ubv(col);
- if (SEQ_time_has_left_still_frames(seq)) {
- const float content_start = min_ff(seq->enddisp, seq->start);
- immRectf(pos, seq->startdisp, y1, content_start, y2);
+ if (SEQ_time_has_left_still_frames(scene, seq)) {
+ float left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
+ const float content_start = SEQ_time_start_frame_get(seq);
+ immRectf(pos, left_handle_frame, y1, content_start, y2);
}
- if (SEQ_time_has_right_still_frames(seq)) {
- const float content_end = max_ff(seq->startdisp, seq->start + seq->len);
- immRectf(pos, content_end, y1, seq->enddisp, y2);
+ if (SEQ_time_has_right_still_frames(scene, seq)) {
+ float right_handle_frame = SEQ_time_right_handle_frame_get(scene, seq);
+ const float content_end = SEQ_time_start_frame_get(seq) +
+ SEQ_time_strip_length_get(scene, seq);
+ immRectf(pos, content_end, y1, right_handle_frame, y2);
}
}
@@ -1186,9 +1179,9 @@ static void draw_seq_invalid(float x1, float x2, float y2, float text_margin_y)
}
static void calculate_seq_text_offsets(
- View2D *v2d, Sequence *seq, float *x1, float *x2, float pixelx)
+ const Scene *scene, View2D *v2d, Sequence *seq, float *x1, float *x2, float pixelx)
{
- const float handsize_clamped = sequence_handle_size_get_clamped(seq, pixelx);
+ const float handsize_clamped = sequence_handle_size_get_clamped(scene, seq, pixelx);
float text_margin = 2.0f * handsize_clamped;
*x1 += text_margin;
@@ -1322,7 +1315,7 @@ static void draw_seq_strip(const bContext *C,
View2D *v2d = &region->v2d;
float x1, x2, y1, y2;
- const float handsize_clamped = sequence_handle_size_get_clamped(seq, pixelx);
+ const float handsize_clamped = sequence_handle_size_get_clamped(scene, seq, pixelx);
float pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
/* Check if we are doing "solo preview". */
@@ -1333,14 +1326,17 @@ static void draw_seq_strip(const bContext *C,
SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG);
/* Draw strip body. */
- x1 = SEQ_time_has_left_still_frames(seq) ? seq->start : seq->startdisp;
+ x1 = SEQ_time_has_left_still_frames(scene, seq) ? SEQ_time_start_frame_get(seq) :
+ SEQ_time_left_handle_frame_get(scene, seq);
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
- x2 = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) : seq->enddisp;
+ x2 = SEQ_time_has_right_still_frames(scene, seq) ?
+ SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq) :
+ SEQ_time_right_handle_frame_get(scene, seq);
y2 = seq->machine + SEQ_STRIP_OFSTOP;
/* Limit body to strip bounds. Meta strip can end up with content outside of strip range. */
- x1 = min_ff(x1, seq->enddisp);
- x2 = max_ff(x2, seq->startdisp);
+ x1 = min_ff(x1, SEQ_time_right_handle_frame_get(scene, seq));
+ x2 = max_ff(x2, SEQ_time_left_handle_frame_get(scene, seq));
float text_margin_y;
bool y_threshold;
@@ -1366,12 +1362,12 @@ static void draw_seq_strip(const bContext *C,
/* Draw a color band inside color strip. */
if (seq->type == SEQ_TYPE_COLOR && y_threshold) {
- draw_color_strip_band(channels, seq, pos, text_margin_y, y1);
+ draw_color_strip_band(scene, channels, seq, pos, text_margin_y, y1);
}
/* Draw strip offsets when flag is enabled or during "solo preview". */
if (sseq->flag & SEQ_SHOW_OVERLAY) {
- if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) {
+ if (!is_single_image && pixely > 0) {
if ((sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_OFFSETS) ||
(seq == special_seq_update)) {
draw_sequence_extensions_overlay(scene, seq, pos, pixely, show_strip_color_tag);
@@ -1380,8 +1376,8 @@ static void draw_seq_strip(const bContext *C,
}
immUnbindProgram();
- x1 = seq->startdisp;
- x2 = seq->enddisp;
+ x1 = SEQ_time_left_handle_frame_get(scene, seq);
+ x2 = SEQ_time_right_handle_frame_get(scene, seq);
if ((seq->type == SEQ_TYPE_META) ||
((seq->type == SEQ_TYPE_SCENE) && (seq->flag & SEQ_SCENE_STRIPS))) {
@@ -1401,18 +1397,9 @@ static void draw_seq_strip(const bContext *C,
}
/* Draw sound strip waveform. */
- if ((seq->type == SEQ_TYPE_SOUND_RAM) && ((sseq->flag & SEQ_SHOW_OVERLAY)) &&
- (sseq->timeline_overlay.flag & SEQ_TIMELINE_NO_WAVEFORMS) == 0) {
- draw_seq_waveform_overlay(v2d,
- C,
- sseq,
- scene,
- seq,
- x1,
- y_threshold ? y1 + 0.05f : y1,
- x2,
- y_threshold ? text_margin_y : y2,
- BLI_rctf_size_x(&region->v2d.cur) / region->winx);
+ if (seq_draw_waveforms_poll(C, sseq, seq)) {
+ draw_seq_waveform_overlay(
+ C, region, seq, x1, y_threshold ? y1 + 0.05f : y1, x2, y_threshold ? text_margin_y : y2);
}
/* Draw locked state. */
if (SEQ_transform_is_locked(channels, seq)) {
@@ -1429,16 +1416,16 @@ static void draw_seq_strip(const bContext *C,
if (!SEQ_transform_is_locked(channels, seq)) {
draw_seq_handle(
- v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos, seq_active, pixelx, y_threshold);
+ scene, v2d, seq, handsize_clamped, SEQ_LEFTHANDLE, pos, seq_active, pixelx, y_threshold);
draw_seq_handle(
- v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE, pos, seq_active, pixelx, y_threshold);
+ scene, v2d, seq, handsize_clamped, SEQ_RIGHTHANDLE, pos, seq_active, pixelx, y_threshold);
}
draw_seq_outline(scene, seq, pos, x1, x2, y1, y2, pixelx, pixely, seq_active);
immUnbindProgram();
- calculate_seq_text_offsets(v2d, seq, &x1, &x2, pixelx);
+ calculate_seq_text_offsets(scene, v2d, seq, &x1, &x2, pixelx);
/* If a waveform is drawn, avoid drawing text when there is not enough vertical space. */
if (seq->type == SEQ_TYPE_SOUND_RAM) {
@@ -1459,7 +1446,7 @@ static void draw_seq_strip(const bContext *C,
}
}
-static void draw_effect_inputs_highlight(Sequence *seq)
+static void draw_effect_inputs_highlight(const Scene *scene, Sequence *seq)
{
Sequence *seq1 = seq->seq1;
Sequence *seq2 = seq->seq2;
@@ -1471,23 +1458,23 @@ static void draw_effect_inputs_highlight(Sequence *seq)
immUniformColor4ub(255, 255, 255, 48);
immRectf(pos,
- seq1->startdisp,
+ SEQ_time_left_handle_frame_get(scene, seq1),
seq1->machine + SEQ_STRIP_OFSBOTTOM,
- seq1->enddisp,
+ SEQ_time_right_handle_frame_get(scene, seq1),
seq1->machine + SEQ_STRIP_OFSTOP);
if (seq2 && seq2 != seq1) {
immRectf(pos,
- seq2->startdisp,
+ SEQ_time_left_handle_frame_get(scene, seq2),
seq2->machine + SEQ_STRIP_OFSBOTTOM,
- seq2->enddisp,
+ SEQ_time_right_handle_frame_get(scene, seq2),
seq2->machine + SEQ_STRIP_OFSTOP);
}
if (seq3 && !ELEM(seq3, seq1, seq2)) {
immRectf(pos,
- seq3->startdisp,
+ SEQ_time_left_handle_frame_get(scene, seq3),
seq3->machine + SEQ_STRIP_OFSBOTTOM,
- seq3->enddisp,
+ SEQ_time_right_handle_frame_get(scene, seq3),
seq3->machine + SEQ_STRIP_OFSTOP);
}
immUnbindProgram();
@@ -1576,7 +1563,8 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain,
}
if (viewport) {
- /* Follows same logic as wm_draw_window_offscreen to make sure to restore the same viewport. */
+ /* Follows same logic as wm_draw_window_offscreen to make sure to restore the same
+ * viewport. */
int view = (sseq->multiview_eye == STEREO_RIGHT_ID) ? 1 : 0;
GPU_viewport_bind(viewport, view, &region->winrct);
}
@@ -1732,8 +1720,7 @@ void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, S
// ED_mask_get_size(C, &width, &height);
//Scene *scene = CTX_data_scene(C);
- width = (scene->r.size * scene->r.xsch) / 100;
- height = (scene->r.size * scene->r.ysch) / 100;
+ BKE_render_resolution(&scene->r, false, &width, &height);
ED_mask_draw_region(mask,
region,
@@ -2081,10 +2068,10 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene)
int preview_frame;
if (last_seq->flag & SEQ_RIGHTSEL) {
- preview_frame = last_seq->enddisp - 1;
+ preview_frame = SEQ_time_right_handle_frame_get(scene, last_seq) - 1;
}
else {
- preview_frame = last_seq->startdisp;
+ preview_frame = SEQ_time_left_handle_frame_get(scene, last_seq);
}
return preview_frame;
@@ -2238,7 +2225,7 @@ void sequencer_draw_preview(const bContext *C,
Editing *ed = SEQ_editing_get(scene);
ListBase *channels = SEQ_channels_displayed_get(ed);
SeqCollection *collection = SEQ_query_rendered_strips(
- channels, ed->seqbasep, timeline_frame, 0);
+ scene, channels, ed->seqbasep, timeline_frame, 0);
Sequence *seq;
Sequence *active_seq = SEQ_select_active_get(scene);
SEQ_ITERATOR_FOREACH (seq, collection) {
@@ -2310,10 +2297,13 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
if (seq == last_seq && (last_seq->flag & SELECT)) {
continue;
}
- if (min_ii(seq->startdisp, seq->start) > v2d->cur.xmax) {
+ if (min_ii(SEQ_time_left_handle_frame_get(scene, seq), SEQ_time_start_frame_get(seq)) >
+ v2d->cur.xmax) {
continue;
}
- if (max_ii(seq->enddisp, seq->start + seq->len) < v2d->cur.xmin) {
+ if (max_ii(SEQ_time_right_handle_frame_get(scene, seq),
+ SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq)) <
+ v2d->cur.xmin) {
continue;
}
if (seq->machine + 1.0f < v2d->cur.ymin) {
@@ -2338,7 +2328,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
/* When active strip is an effect, highlight its inputs. */
if (SEQ_effect_get_num_inputs(last_seq->type) > 0) {
- draw_effect_inputs_highlight(last_seq);
+ draw_effect_inputs_highlight(scene, last_seq);
}
/* When active is a Multi-cam strip, highlight its source channel. */
else if (last_seq->type == SEQ_TYPE_MULTICAM) {
@@ -2368,9 +2358,9 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
immUniformColor4ub(255, 255, 255, 48);
immRectf(pos,
- seq->startdisp,
+ SEQ_time_left_handle_frame_get(scene, seq),
seq->machine + SEQ_STRIP_OFSBOTTOM,
- seq->enddisp,
+ SEQ_time_right_handle_frame_get(scene, seq),
seq->machine + SEQ_STRIP_OFSTOP);
immUnbindProgram();
@@ -2597,7 +2587,8 @@ static void draw_cache_view(const bContext *C)
continue;
}
- if (seq->startdisp > v2d->cur.xmax || seq->enddisp < v2d->cur.xmin) {
+ if (SEQ_time_left_handle_frame_get(scene, seq) > v2d->cur.xmax ||
+ SEQ_time_right_handle_frame_get(scene, seq) < v2d->cur.xmin) {
continue;
}
@@ -2607,7 +2598,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) {
const float bg_color[4] = {1.0f, 0.1f, 0.02f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(scene, seq),
+ stripe_top);
}
stripe_bot += stripe_ht + stripe_ofs_y;
@@ -2616,7 +2611,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) {
const float bg_color[4] = {0.1f, 0.1f, 0.75f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(scene, seq),
+ stripe_top);
}
stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y;
@@ -2625,7 +2624,11 @@ static void draw_cache_view(const bContext *C)
if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) {
const float bg_color[4] = {1.0f, 0.6f, 0.0f, 0.1f};
immUniformColor4f(bg_color[0], bg_color[1], bg_color[2], bg_color[3]);
- immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top);
+ immRectf(pos,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ stripe_bot,
+ SEQ_time_right_handle_frame_get(scene, seq),
+ stripe_top);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 08f98dfb161..cb95e9a75de 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -77,11 +77,11 @@
typedef struct TransSeq {
int start, machine;
- int startdisp, enddisp;
int startofs, endofs;
int anim_startofs, anim_endofs;
/* int final_left, final_right; */ /* UNUSED */
int len;
+ float content_start;
} TransSeq;
/** \} */
@@ -174,6 +174,11 @@ bool sequencer_edit_poll(bContext *C)
return (SEQ_editing_get(CTX_data_scene(C)) != NULL);
}
+bool sequencer_editing_initialized_and_active(bContext *C)
+{
+ return ED_operator_sequencer_active(C) && sequencer_edit_poll(C);
+}
+
#if 0 /* UNUSED */
bool sequencer_strip_poll(bContext *C)
{
@@ -260,7 +265,7 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
const bool do_all = RNA_boolean_get(op->ptr, "all");
const Editing *ed = SEQ_editing_get(scene);
- SEQ_edit_remove_gaps(scene, ed->seqbasep, CFRA, do_all);
+ SEQ_edit_remove_gaps(scene, ed->seqbasep, scene->r.cfra, do_all);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -299,7 +304,7 @@ static int sequencer_gap_insert_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
const int frames = RNA_int_get(op->ptr, "frames");
const Editing *ed = SEQ_editing_get(scene);
- SEQ_transform_offset_after_frame(scene, ed->seqbasep, frames, CFRA);
+ SEQ_transform_offset_after_frame(scene, ed->seqbasep, frames, scene->r.cfra);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -345,7 +350,6 @@ 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);
ListBase *channels = SEQ_channels_displayed_get(ed);
Sequence *seq;
int snap_frame;
@@ -361,15 +365,13 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
}
else {
if (seq->flag & SEQ_LEFTSEL) {
- SEQ_time_left_handle_frame_set(seq, snap_frame);
+ SEQ_time_left_handle_frame_set(scene, seq, snap_frame);
}
else { /* SEQ_RIGHTSEL */
- SEQ_time_right_handle_frame_set(seq, snap_frame);
+ SEQ_time_right_handle_frame_set(scene, seq, snap_frame);
}
- SEQ_transform_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
- SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_transform_fix_single_image_seq_offsets(scene, seq);
}
- SEQ_time_update_sequence(scene, seqbase, seq);
}
}
@@ -377,7 +379,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && !SEQ_transform_is_locked(channels, seq)) {
seq->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
+ if (SEQ_transform_test_overlap(scene, ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
}
}
@@ -390,27 +392,25 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
if (seq->seq1 && (seq->seq1->flag & SELECT)) {
if (!either_handle_selected) {
- SEQ_offset_animdata(scene, seq, (snap_frame - seq->startdisp));
+ SEQ_offset_animdata(
+ scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(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_offset_animdata(
+ scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(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_offset_animdata(
+ scene, seq, (snap_frame - SEQ_time_left_handle_frame_get(scene, seq)));
}
- SEQ_time_update_sequence(scene, seqbase, seq);
}
}
}
- SEQ_sort(SEQ_active_seqbase_get(ed));
-
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -423,7 +423,7 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
int snap_frame;
- snap_frame = CFRA;
+ snap_frame = scene->r.cfra;
RNA_int_set(op->ptr, "frame", snap_frame);
return sequencer_snap_exec(C, op);
@@ -475,10 +475,9 @@ typedef struct SlipData {
static void transseq_backup(TransSeq *ts, Sequence *seq)
{
+ ts->content_start = SEQ_time_start_frame_get(seq);
ts->start = seq->start;
ts->machine = seq->machine;
- ts->startdisp = seq->startdisp;
- ts->enddisp = seq->enddisp;
ts->startofs = seq->startofs;
ts->endofs = seq->endofs;
ts->anim_startofs = seq->anim_startofs;
@@ -490,8 +489,6 @@ static void transseq_restore(TransSeq *ts, Sequence *seq)
{
seq->start = ts->start;
seq->machine = ts->machine;
- seq->startdisp = ts->startdisp;
- seq->enddisp = ts->enddisp;
seq->startofs = ts->startofs;
seq->endofs = ts->endofs;
seq->anim_startofs = ts->anim_startofs;
@@ -592,35 +589,13 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
{
- /* Iterate in reverse so meta-strips are iterated after their children. */
for (int i = data->num_seq - 1; i >= 0; i--) {
Sequence *seq = data->seq_array[i];
- int endframe;
- /* Offset seq start. */
seq->start = data->ts[i].start + offset;
-
if (data->trim[i]) {
- /* Find the end-frame. */
- endframe = seq->start + seq->len;
-
- /* Compute the sequence offsets. */
- seq->endofs = endframe - seq->enddisp;
- seq->startofs = seq->startdisp - seq->start;
- }
- else {
- /* No transform data (likely effect strip). Only move start and end. */
- seq->startdisp = data->ts[i].startdisp + offset;
- seq->enddisp = data->ts[i].enddisp + offset;
- }
-
- /* Effects are only added if we they are in a meta-strip.
- * In this case, dependent strips will just be transformed and
- * we can skip calculating for effects.
- * This way we can avoid an extra loop just for effects. */
- if (!(seq->type & SEQ_TYPE_EFFECT)) {
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SEQ_time_update_sequence(scene, seqbase, seq);
+ seq->startofs = data->ts[i].startofs - offset;
+ seq->endofs = data->ts[i].endofs + offset;
}
}
@@ -631,7 +606,7 @@ static void sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
}
/* Make sure, that each strip contains at least 1 frame of content. */
-static void sequencer_slip_apply_limits(SlipData *data, int *offset)
+static void sequencer_slip_apply_limits(const Scene *scene, SlipData *data, int *offset)
{
for (int i = 0; i < data->num_seq; i++) {
if (data->trim[i]) {
@@ -640,12 +615,12 @@ static void sequencer_slip_apply_limits(SlipData *data, int *offset)
int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs;
int diff = 0;
- if (seq_content_start >= seq->enddisp) {
- diff = seq->enddisp - seq_content_start - 1;
+ if (seq_content_start >= SEQ_time_right_handle_frame_get(scene, seq)) {
+ diff = SEQ_time_right_handle_frame_get(scene, seq) - seq_content_start - 1;
}
- if (seq_content_end <= seq->startdisp) {
- diff = seq->startdisp - seq_content_end + 1;
+ if (seq_content_end <= SEQ_time_left_handle_frame_get(scene, seq)) {
+ diff = SEQ_time_left_handle_frame_get(scene, seq) - seq_content_end + 1;
}
*offset += diff;
}
@@ -677,7 +652,7 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
transseq_backup(data->ts + i, data->seq_array[i]);
}
- sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_recursively(scene, data, offset);
MEM_freeN(data->seq_array);
@@ -723,7 +698,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
applyNumInput(&data->num_input, &offset_fl);
int offset = round_fl_to_int(offset_fl);
- sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -755,7 +730,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]);
offset = mouseloc[0] - data->init_mouseloc[0];
- sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -791,8 +766,6 @@ 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);
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
- SEQ_time_update_sequence(scene, seqbase, seq);
}
MEM_freeN(data->seq_array);
@@ -834,7 +807,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
applyNumInput(&data->num_input, &offset_fl);
int offset = round_fl_to_int(offset_fl);
- sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_apply_limits(scene, data, &offset);
sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -1082,7 +1055,7 @@ static int sequencer_reload_exec(bContext *C, wmOperator *op)
SEQ_add_reload_new_file(bmain, scene, seq, !adjust_length);
if (adjust_length) {
- if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
+ if (SEQ_transform_test_overlap(scene, ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
}
}
@@ -1288,7 +1261,6 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
last_seq->seq3 = seq3;
int old_start = last_seq->start;
- 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));
@@ -1446,13 +1418,15 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
if (ignore_selection) {
if (use_cursor_position) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
- if (seq->enddisp == split_frame && seq->machine == split_channel) {
+ if (SEQ_time_right_handle_frame_get(scene, seq) == split_frame &&
+ seq->machine == split_channel) {
seq_selected = seq->flag & SEQ_ALLSEL;
}
}
if (!seq_selected) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
- if (seq->startdisp == split_frame && seq->machine == split_channel) {
+ if (SEQ_time_left_handle_frame_get(scene, seq) == split_frame &&
+ seq->machine == split_channel) {
seq->flag &= ~SEQ_ALLSEL;
}
}
@@ -1463,20 +1437,18 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
if (split_side != SEQ_SIDE_BOTH) {
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
if (split_side == SEQ_SIDE_LEFT) {
- if (seq->startdisp >= split_frame) {
+ if (SEQ_time_left_handle_frame_get(scene, seq) >= split_frame) {
seq->flag &= ~SEQ_ALLSEL;
}
}
else {
- if (seq->enddisp <= split_frame) {
+ if (SEQ_time_right_handle_frame_get(scene, seq) <= split_frame) {
seq->flag &= ~SEQ_ALLSEL;
}
}
}
}
}
-
- SEQ_sort(SEQ_active_seqbase_get(ed));
}
if (changed) {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1493,7 +1465,7 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
View2D *v2d = UI_view2d_fromcontext(C);
int split_side = RNA_enum_get(op->ptr, "side");
- int split_frame = CFRA;
+ int split_frame = scene->r.cfra;
if (split_side == SEQ_SIDE_MOUSE) {
if (ED_operator_sequencer_active(C) && v2d) {
@@ -1731,8 +1703,10 @@ static int sequencer_delete_exec(bContext *C, wmOperator *op)
static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ ListBase *markers = &scene->markers;
- if (region->regiontype == RGN_TYPE_WINDOW) {
+ if (region->regiontype == RGN_TYPE_WINDOW && !BLI_listbase_is_empty(markers)) {
/* Bounding box of 30 pixels is used for markers shortcuts,
* prevent conflict with markers shortcuts here.
*/
@@ -1791,15 +1765,13 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
/* Update lengths, etc. */
seq = ed->seqbasep->first;
while (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;
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) {
- if (SEQ_transform_test_overlap(ed->seqbasep, seq)) {
+ if (SEQ_transform_test_overlap(scene, ed->seqbasep, seq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene);
}
}
@@ -1858,12 +1830,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
/* TODO: remove f-curve and assign to split image strips.
* The old animation system would remove the user of `seq->ipo`. */
- start_ofs = timeline_frame = SEQ_time_left_handle_frame_get(seq);
- frame_end = SEQ_time_right_handle_frame_get(seq);
+ start_ofs = timeline_frame = SEQ_time_left_handle_frame_get(scene, seq);
+ frame_end = SEQ_time_right_handle_frame_get(scene, seq);
while (timeline_frame < frame_end) {
/* New seq. */
- se = SEQ_render_give_stripelem(seq, timeline_frame);
+ se = SEQ_render_give_stripelem(scene, seq, timeline_frame);
seq_new = SEQ_sequence_dupli_recursive(scene, scene, seqbase, seq, SEQ_DUPE_UNIQUE_NAME);
@@ -1883,11 +1855,9 @@ 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, seqbase, seq_new);
-
if (step > 1) {
seq_new->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(seqbase, seq_new)) {
+ if (SEQ_transform_test_overlap(scene, seqbase, seq_new)) {
SEQ_transform_seqbase_shuffle(seqbase, seq_new, scene);
}
}
@@ -1908,9 +1878,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
SEQ_edit_remove_flagged_sequences(scene, seqbase);
-
- SEQ_sort(seqbase);
-
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -1949,11 +1916,9 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
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);
- SEQ_seqbase_active_set(ed, &active_seq->seqbase);
- SEQ_channels_displayed_set(ed, &active_seq->channels);
+ /* Deselect active meta seq. */
SEQ_select_active_set(scene, NULL);
+ SEQ_meta_stack_set(scene, active_seq);
}
else {
/* Exit meta-strip if possible. */
@@ -1961,14 +1926,12 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- MetaStack *ms = SEQ_meta_stack_active_get(ed);
- SEQ_seqbase_active_set(ed, ms->oldbasep);
- SEQ_channels_displayed_set(ed, ms->old_channels);
- SEQ_select_active_set(scene, ms->parseq);
- SEQ_meta_stack_free(ed, ms);
+ /* Display parent meta. */
+ Sequence *meta_parent = SEQ_meta_stack_pop(ed);
+ SEQ_select_active_set(scene, meta_parent);
}
- DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
+ // DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -2020,8 +1983,8 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
BLI_addtail(&seqm->seqbase, seq);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
channel_max = max_ii(seq->machine, channel_max);
- meta_start_frame = min_ii(seq->startdisp, meta_start_frame);
- meta_end_frame = max_ii(seq->enddisp, meta_end_frame);
+ meta_start_frame = min_ii(SEQ_time_left_handle_frame_get(scene, seq), meta_start_frame);
+ meta_end_frame = max_ii(SEQ_time_right_handle_frame_get(scene, seq), meta_end_frame);
}
}
@@ -2030,9 +1993,8 @@ 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, active_seqbase, seqm);
SEQ_select_active_set(scene, seqm);
- if (SEQ_transform_test_overlap(active_seqbase, seqm)) {
+ if (SEQ_transform_test_overlap(scene, active_seqbase, seqm)) {
SEQ_transform_seqbase_shuffle(active_seqbase, seqm, scene);
}
@@ -2092,13 +2054,12 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
LISTBASE_FOREACH (Sequence *, seq, active_seqbase) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(active_seqbase, seq)) {
+ if (SEQ_transform_test_overlap(scene, active_seqbase, seq)) {
SEQ_transform_seqbase_shuffle(active_seqbase, seq, scene);
}
}
}
- SEQ_sort(active_seqbase);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -2132,12 +2093,12 @@ static bool strip_jump_internal(Scene *scene,
const bool do_center)
{
bool changed = false;
- int timeline_frame = CFRA;
+ int timeline_frame = scene->r.cfra;
int next_frame = SEQ_time_find_next_prev_edit(
scene, timeline_frame, side, do_skip_mute, do_center, false);
if (next_frame != timeline_frame) {
- CFRA = next_frame;
+ scene->r.cfra = next_frame;
changed = true;
}
@@ -2204,19 +2165,19 @@ 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 gap = SEQ_time_left_handle_frame_get(scene, seqb) -
+ SEQ_time_right_handle_frame_get(scene, seqa);
int seq_a_start;
int seq_b_start;
- seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp;
+ seq_b_start = (seqb->start - SEQ_time_left_handle_frame_get(scene, seqb)) +
+ SEQ_time_left_handle_frame_get(scene, seqa);
SEQ_transform_translate_sequence(scene, seqb, seq_b_start - seqb->start);
- 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_a_start = (seqa->start - SEQ_time_left_handle_frame_get(scene, seqa)) +
+ SEQ_time_right_handle_frame_get(scene, seqb) + gap;
SEQ_transform_translate_sequence(scene, seqa, seq_a_start - seqa->start);
- SEQ_time_update_sequence(scene, seqbase, seqa);
SEQ_relations_invalidate_cache_preprocessed(scene, seqa);
}
@@ -2241,13 +2202,17 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i
switch (lr) {
case SEQ_SIDE_LEFT:
- if (seq->enddisp <= test->startdisp) {
- dist = test->enddisp - seq->startdisp;
+ if (SEQ_time_right_handle_frame_get(scene, seq) <=
+ SEQ_time_left_handle_frame_get(scene, test)) {
+ dist = SEQ_time_right_handle_frame_get(scene, test) -
+ SEQ_time_left_handle_frame_get(scene, seq);
}
break;
case SEQ_SIDE_RIGHT:
- if (seq->startdisp >= test->enddisp) {
- dist = seq->startdisp - test->enddisp;
+ if (SEQ_time_left_handle_frame_get(scene, seq) >=
+ SEQ_time_right_handle_frame_get(scene, test)) {
+ dist = SEQ_time_left_handle_frame_get(scene, seq) -
+ SEQ_time_right_handle_frame_get(scene, test);
}
break;
}
@@ -2307,29 +2272,18 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
break;
}
- /* XXX: Should be a generic function. */
- 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, seqbase, iseq);
- }
- }
-
/* Do this in a new loop since both effects need to be calculated first. */
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(seqbase, iseq)) {
+ if (SEQ_transform_test_overlap(scene, seqbase, iseq)) {
SEQ_transform_seqbase_shuffle(seqbase, iseq, scene);
}
}
}
- SEQ_sort(SEQ_active_seqbase_get(ed));
-
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
-
return OPERATOR_FINISHED;
}
@@ -2373,7 +2327,7 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op))
switch (active_seq->type) {
case SEQ_TYPE_IMAGE:
- se = SEQ_render_give_stripelem(active_seq, scene->r.cfra);
+ se = SEQ_render_give_stripelem(scene, active_seq, scene->r.cfra);
break;
case SEQ_TYPE_MOVIE:
se = active_seq->strip->stripdata;
@@ -2446,6 +2400,13 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq)
return;
}
+ /* Add curves for strips inside meta strip. */
+ if (seq->type == SEQ_TYPE_META) {
+ LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
+ sequencer_copy_animation(scene, meta_child);
+ }
+ }
+
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves);
if (fcurves == NULL) {
return;
@@ -2455,6 +2416,7 @@ static void sequencer_copy_animation(Scene *scene, Sequence *seq)
BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu));
}
GSET_FOREACH_END();
+
BLI_gset_free(fcurves, NULL);
}
@@ -2576,8 +2538,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
else {
int min_seq_startdisp = INT_MAX;
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
- if (seq->startdisp < min_seq_startdisp) {
- min_seq_startdisp = seq->startdisp;
+ if (SEQ_time_left_handle_frame_get(scene, seq) < min_seq_startdisp) {
+ min_seq_startdisp = SEQ_time_left_handle_frame_get(scene, seq);
}
}
/* Paste strips relative to the current-frame. */
@@ -2608,18 +2570,22 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
* in the new list. */
BLI_movelisttolist(ed->seqbasep, &nseqbase);
+ /* Make sure, that pasted strips have unique names. This has to be done immediately after adding
+ * strips to seqbase, for lookup cache to work correctly. */
+ for (iseq = iseq_first; iseq; iseq = iseq->next) {
+ SEQ_ensure_unique_name(iseq, scene);
+ }
+
for (iseq = iseq_first; iseq; iseq = iseq->next) {
if (SEQ_clipboard_pasted_seq_was_active(iseq)) {
SEQ_select_active_set(scene, iseq);
}
- /* Make sure, that pasted strips have unique names. */
- SEQ_ensure_unique_name(iseq, scene);
/* Translate after name has been changed, otherwise this will affect animdata of original
* strip. */
SEQ_transform_translate_sequence(scene, iseq, ofs);
/* Ensure, that pasted strips don't overlap. */
- if (SEQ_transform_test_overlap(ed->seqbasep, iseq)) {
+ if (SEQ_transform_test_overlap(scene, ed->seqbasep, iseq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene);
}
}
@@ -2676,7 +2642,7 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (SEQ_edit_sequence_swap(seq_act, seq_other, &error_msg) == 0) {
+ if (SEQ_edit_sequence_swap(scene, seq_act, seq_other, &error_msg) == 0) {
BKE_report(op->reports, RPT_ERROR, error_msg);
return OPERATOR_CANCELLED;
}
@@ -2692,10 +2658,6 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
seq_act->scene_sound = NULL;
seq_other->scene_sound = NULL;
- 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);
}
@@ -2938,9 +2900,6 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
/* Correct start/end frames so we don't move.
* Important not to set seq->len = len; allow the function to handle it. */
SEQ_add_reload_new_file(bmain, scene, seq, true);
-
- 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;
@@ -3108,15 +3067,16 @@ void SEQUENCER_OT_change_scene(struct wmOperatorType *ot)
* \{ */
/** Comparison function suitable to be used with BLI_listbase_sort(). */
-static int seq_cmp_time_startdisp_channel(const void *a, const void *b)
+static int seq_cmp_time_startdisp_channel(void *thunk, const void *a, const void *b)
{
+ const Scene *scene = thunk;
Sequence *seq_a = (Sequence *)a;
Sequence *seq_b = (Sequence *)b;
- int seq_a_start = SEQ_time_left_handle_frame_get(seq_a);
- int seq_b_start = SEQ_time_left_handle_frame_get(seq_b);
+ int seq_a_start = SEQ_time_left_handle_frame_get(scene, seq_a);
+ int seq_b_start = SEQ_time_left_handle_frame_get(scene, seq_b);
- /* If strips have the same start frame favor the one with a higher channel. */
+ /* If strips have the same start frame favor the one with a higher channel.*/
if (seq_a_start == seq_b_start) {
return seq_a->machine > seq_b->machine;
}
@@ -3160,7 +3120,7 @@ static bool seq_get_text_strip_cb(Sequence *seq, void *user_data)
ListBase *channels = SEQ_channels_displayed_get(ed);
/* Only text strips that are not muted and don't end with negative frame. */
if ((seq->type == SEQ_TYPE_TEXT) && !SEQ_render_is_muted(channels, seq) &&
- (seq->enddisp > cd->scene->r.sfra)) {
+ (SEQ_time_right_handle_frame_get(cd->scene, seq) > cd->scene->r.sfra)) {
BLI_addtail(cd->text_seq, MEM_dupallocN(seq));
}
return true;
@@ -3207,7 +3167,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BLI_listbase_sort(&text_seq, seq_cmp_time_startdisp_channel);
+ BLI_listbase_sort_r(&text_seq, seq_cmp_time_startdisp_channel, scene);
/* Open and write file. */
file = BLI_fopen(filepath, "w");
@@ -3218,18 +3178,20 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
char timecode_str_end[32];
/* Write time-code relative to start frame of scene. Don't allow negative time-codes. */
- BLI_timecode_string_from_time(timecode_str_start,
- sizeof(timecode_str_start),
- -2,
- FRA2TIME(max_ii(seq->startdisp - scene->r.sfra, 0)),
- FPS,
- USER_TIMECODE_SUBRIP);
- BLI_timecode_string_from_time(timecode_str_end,
- sizeof(timecode_str_end),
- -2,
- FRA2TIME(seq->enddisp - scene->r.sfra),
- FPS,
- USER_TIMECODE_SUBRIP);
+ BLI_timecode_string_from_time(
+ timecode_str_start,
+ sizeof(timecode_str_start),
+ -2,
+ FRA2TIME(max_ii(SEQ_time_left_handle_frame_get(scene, seq) - scene->r.sfra, 0)),
+ FPS,
+ USER_TIMECODE_SUBRIP);
+ BLI_timecode_string_from_time(
+ timecode_str_end,
+ sizeof(timecode_str_end),
+ -2,
+ FRA2TIME(SEQ_time_right_handle_frame_get(scene, seq) - scene->r.sfra),
+ FPS,
+ USER_TIMECODE_SUBRIP);
fprintf(
file, "%d\n%s --> %s\n%s\n\n", iter++, timecode_str_start, timecode_str_end, data->text);
@@ -3295,8 +3257,8 @@ static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT) {
selected = true;
- sfra = min_ii(sfra, seq->startdisp);
- efra = max_ii(efra, seq->enddisp - 1);
+ sfra = min_ii(sfra, SEQ_time_left_handle_frame_get(scene, seq));
+ efra = max_ii(efra, SEQ_time_right_handle_frame_get(scene, seq) - 1);
}
}
@@ -3448,8 +3410,8 @@ static int sequencer_strip_transform_fit_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) {
- const int timeline_frame = CFRA;
- StripElem *strip_elem = SEQ_render_give_stripelem(seq, timeline_frame);
+ const int timeline_frame = scene->r.cfra;
+ StripElem *strip_elem = SEQ_render_give_stripelem(scene, seq, timeline_frame);
if (strip_elem == NULL) {
continue;
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 3307c3fde2f..644e897f631 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -70,7 +70,9 @@ void color3ubv_from_seq(const struct Scene *curscene,
void sequencer_special_update_set(Sequence *seq);
/* Get handle width in 2d-View space. */
-float sequence_handle_size_get_clamped(struct Sequence *seq, float pixelx);
+float sequence_handle_size_get_clamped(const struct Scene *scene,
+ struct Sequence *seq,
+ float pixelx);
/* UNUSED */
/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
@@ -113,7 +115,7 @@ void channel_draw_context_init(const struct bContext *C,
/* sequencer_edit.c */
struct View2D;
-void seq_rectf(struct Sequence *seq, struct rctf *rectf);
+void seq_rectf(const struct Scene *scene, struct Sequence *seq, struct rctf *rectf);
struct Sequence *find_nearest_seq(struct Scene *scene,
struct View2D *v2d,
int *hand,
@@ -133,6 +135,7 @@ int seq_effect_find_selected(struct Scene *scene,
/* Operator helpers. */
bool sequencer_edit_poll(struct bContext *C);
+bool sequencer_editing_initialized_and_active(struct bContext *C);
/* UNUSED */
/* bool sequencer_strip_poll(struct bContext *C); */
bool sequencer_strip_has_path_poll(struct bContext *C);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 074be0fd120..4aaa3aeb2ff 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -59,7 +59,7 @@ SeqCollection *all_strips_from_context(bContext *C)
const bool is_preview = sequencer_view_has_preview_poll(C);
if (is_preview) {
- return SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ return SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
}
return SEQ_query_all_strips(seqbase);
@@ -74,7 +74,7 @@ SeqCollection *selected_strips_from_context(bContext *C)
const bool is_preview = sequencer_view_has_preview_poll(C);
if (is_preview) {
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
return strips;
}
@@ -108,7 +108,8 @@ static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRIN
}
/* Used for mouse selection in SEQUENCER_OT_select. */
-static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
+static void select_active_side(
+ const Scene *scene, ListBase *seqbase, int sel_side, int channel, int frame)
{
Sequence *seq;
@@ -116,13 +117,13 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
if (channel == seq->machine) {
switch (sel_side) {
case SEQ_SIDE_LEFT:
- if (frame > (seq->startdisp)) {
+ if (frame > (SEQ_time_left_handle_frame_get(scene, seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
break;
case SEQ_SIDE_RIGHT:
- if (frame < (seq->startdisp)) {
+ if (frame < (SEQ_time_left_handle_frame_get(scene, seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
@@ -137,7 +138,8 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
}
/* Used for mouse selection in SEQUENCER_OT_select_side. */
-static void select_active_side_range(ListBase *seqbase,
+static void select_active_side_range(const Scene *scene,
+ ListBase *seqbase,
const int sel_side,
const int frame_ranges[MAXSEQ],
const int frame_ignore)
@@ -152,13 +154,13 @@ static void select_active_side_range(ListBase *seqbase,
}
switch (sel_side) {
case SEQ_SIDE_LEFT:
- if (frame > (seq->startdisp)) {
+ if (frame > (SEQ_time_left_handle_frame_get(scene, seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
break;
case SEQ_SIDE_RIGHT:
- if (frame < (seq->startdisp)) {
+ if (frame < (SEQ_time_left_handle_frame_get(scene, seq))) {
seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
seq->flag |= SELECT;
}
@@ -173,14 +175,14 @@ static void select_active_side_range(ListBase *seqbase,
}
/* Used for mouse selection in SEQUENCER_OT_select */
-static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
+static void select_linked_time(const Scene *scene, ListBase *seqbase, Sequence *seq_link)
{
Sequence *seq;
for (seq = seqbase->first; seq; seq = seq->next) {
if (seq_link->machine != seq->machine) {
- int left_match = (seq->startdisp == seq_link->startdisp) ? 1 : 0;
- int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0;
+ int left_match = (SEQ_time_left_handle_frame_get(scene, seq) == seq_link->startdisp) ? 1 : 0;
+ int right_match = (SEQ_time_right_handle_frame_get(scene, seq) == seq_link->enddisp) ? 1 : 0;
if (left_match && right_match) {
/* Direct match, copy the selection settings. */
@@ -245,10 +247,10 @@ void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool desel
recurs_sel_seq(seq);
}
-void seq_rectf(Sequence *seq, rctf *rect)
+void seq_rectf(const Scene *scene, Sequence *seq, rctf *rect)
{
- rect->xmin = seq->startdisp;
- rect->xmax = seq->enddisp;
+ rect->xmin = SEQ_time_left_handle_frame_get(scene, seq);
+ rect->xmax = SEQ_time_right_handle_frame_get(scene, seq);
rect->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM;
rect->ymax = seq->machine + SEQ_STRIP_OFSTOP;
}
@@ -273,12 +275,14 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se
(sel == 0 && (seq->flag & SELECT) == 0))) {
switch (lr) {
case SEQ_SIDE_LEFT:
- if (test->startdisp == (seq->enddisp)) {
+ if (SEQ_time_left_handle_frame_get(scene, test) ==
+ (SEQ_time_right_handle_frame_get(scene, seq))) {
return seq;
}
break;
case SEQ_SIDE_RIGHT:
- if (test->enddisp == (seq->startdisp)) {
+ if (SEQ_time_right_handle_frame_get(scene, test) ==
+ (SEQ_time_left_handle_frame_get(scene, seq))) {
return seq;
}
break;
@@ -311,13 +315,20 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
while (seq) {
if (seq->machine == (int)y) {
/* Check for both normal strips, and strips that have been flipped horizontally. */
- if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) ||
- ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) {
+ if (((SEQ_time_left_handle_frame_get(scene, seq) <
+ SEQ_time_right_handle_frame_get(scene, seq)) &&
+ (SEQ_time_left_handle_frame_get(scene, seq) <= x &&
+ SEQ_time_right_handle_frame_get(scene, seq) >= x)) ||
+ ((SEQ_time_left_handle_frame_get(scene, seq) >
+ SEQ_time_right_handle_frame_get(scene, seq)) &&
+ (SEQ_time_left_handle_frame_get(scene, seq) >= x &&
+ SEQ_time_right_handle_frame_get(scene, seq) <= x))) {
if (SEQ_transform_sequence_can_be_translated(seq)) {
/* Clamp handles to defined size in pixel space. */
- handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx);
- displen = (float)abs(seq->startdisp - seq->enddisp);
+ handsize = 2.0f * sequence_handle_size_get_clamped(scene, seq, pixelx);
+ displen = (float)abs(SEQ_time_left_handle_frame_get(scene, seq) -
+ SEQ_time_right_handle_frame_get(scene, seq));
/* Don't even try to grab the handles of small strips. */
if (displen / pixelx > 16) {
@@ -332,10 +343,10 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[
CLAMP(handsize, 7 * pixelx, 30 * pixelx);
}
- if (handsize + seq->startdisp >= x) {
+ if (handsize + SEQ_time_left_handle_frame_get(scene, seq) >= x) {
*hand = SEQ_SIDE_LEFT;
}
- else if (-handsize + seq->enddisp <= x) {
+ else if (-handsize + SEQ_time_right_handle_frame_get(scene, seq) <= x) {
*hand = SEQ_SIDE_RIGHT;
}
}
@@ -578,8 +589,10 @@ static void sequencer_select_side_of_frame(const bContext *C,
const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
- if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
- ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
+ if (((x < scene->r.cfra) &&
+ (SEQ_time_right_handle_frame_get(scene, seq_iter) <= scene->r.cfra)) ||
+ ((x >= scene->r.cfra) &&
+ (SEQ_time_left_handle_frame_get(scene, seq_iter) >= scene->r.cfra))) {
/* Select left or right. */
seq_iter->flag |= SELECT;
recurs_sel_seq(seq_iter);
@@ -592,8 +605,8 @@ static void sequencer_select_side_of_frame(const bContext *C,
TimeMarker *tmarker;
for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
- if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
- ((x >= CFRA) && (tmarker->frame >= CFRA))) {
+ if (((x < scene->r.cfra) && (tmarker->frame <= scene->r.cfra)) ||
+ ((x >= scene->r.cfra) && (tmarker->frame >= scene->r.cfra))) {
tmarker->flag |= SELECT;
}
else {
@@ -634,7 +647,11 @@ static void sequencer_select_linked_handle(const bContext *C,
case SEQ_SIDE_LEFT:
if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
seq->flag |= SELECT;
- select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
+ select_active_side(scene,
+ ed->seqbasep,
+ SEQ_SIDE_LEFT,
+ seq->machine,
+ SEQ_time_left_handle_frame_get(scene, seq));
}
else {
seq->flag |= SELECT;
@@ -647,7 +664,11 @@ static void sequencer_select_linked_handle(const bContext *C,
case SEQ_SIDE_RIGHT:
if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
seq->flag |= SELECT;
- select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
+ select_active_side(scene,
+ ed->seqbasep,
+ SEQ_SIDE_RIGHT,
+ seq->machine,
+ SEQ_time_left_handle_frame_get(scene, seq));
}
else {
seq->flag |= SELECT;
@@ -661,7 +682,8 @@ static void sequencer_select_linked_handle(const bContext *C,
}
else {
- select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
+ select_active_side(
+ scene, ed->seqbasep, sel_side, seq->machine, SEQ_time_left_handle_frame_get(scene, seq));
}
}
}
@@ -726,7 +748,7 @@ static Sequence *seq_select_seq_from_preview(
const bool use_cycle = (!WM_cursor_test_motion_and_update(mval) || extend || toggle);
SeqCollection *strips = SEQ_query_rendered_strips(
- channels, seqbase, scene->r.cfra, sseq->chanshown);
+ scene, channels, 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
@@ -913,7 +935,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
ED_sequencer_deselect_all(scene);
}
sequencer_select_strip_impl(ed, seq, handle_clicked, extend, deselect, toggle);
- select_linked_time(ed->seqbasep, seq);
+ select_linked_time(scene, ed->seqbasep, seq);
sequencer_select_do_updates(C, scene);
sequencer_select_set_active(scene, seq);
return OPERATOR_FINISHED;
@@ -1423,18 +1445,18 @@ static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op)
if (extend == false) {
ED_sequencer_deselect_all(scene);
}
- const int timeline_frame = CFRA;
+ const int timeline_frame = scene->r.cfra;
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
bool test = false;
switch (side) {
case -1:
- test = (timeline_frame >= seq->enddisp);
+ test = (timeline_frame >= SEQ_time_right_handle_frame_get(scene, seq));
break;
case 1:
- test = (timeline_frame <= seq->startdisp);
+ test = (timeline_frame <= SEQ_time_left_handle_frame_get(scene, seq));
break;
case 2:
- test = SEQ_time_strip_intersects_frame(seq, timeline_frame);
+ test = SEQ_time_strip_intersects_frame(scene, seq, timeline_frame);
break;
}
@@ -1505,10 +1527,10 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
if (seq->flag & SELECT) {
selected = true;
if (sel_side == SEQ_SIDE_LEFT) {
- *frame_limit_p = max_ii(*frame_limit_p, seq->startdisp);
+ *frame_limit_p = max_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(scene, seq));
}
else {
- *frame_limit_p = min_ii(*frame_limit_p, seq->startdisp);
+ *frame_limit_p = min_ii(*frame_limit_p, SEQ_time_left_handle_frame_get(scene, seq));
}
}
}
@@ -1517,7 +1539,7 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- select_active_side_range(ed->seqbasep, sel_side, frame_ranges, frame_init);
+ select_active_side_range(scene, ed->seqbasep, sel_side, frame_ranges, frame_init);
ED_outliner_select_sync_from_sequence_tag(C);
@@ -1587,7 +1609,7 @@ static void seq_box_select_seq_from_preview(const bContext *C, rctf *rect, const
SpaceSeq *sseq = CTX_wm_space_seq(C);
SeqCollection *strips = SEQ_query_rendered_strips(
- channels, seqbase, scene->r.cfra, sseq->chanshown);
+ scene, channels, seqbase, scene->r.cfra, sseq->chanshown);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
if (!seq_box_select_rect_image_isect(scene, seq, rect)) {
@@ -1640,15 +1662,15 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
rctf rq;
- seq_rectf(seq, &rq);
+ seq_rectf(scene, seq, &rq);
if (BLI_rctf_isect(&rq, &rectf, NULL)) {
if (handles) {
/* Get the handles draw size. */
float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
- float handsize = sequence_handle_size_get_clamped(seq, pixelx);
+ float handsize = sequence_handle_size_get_clamped(scene, seq, pixelx);
/* Right handle. */
- if (rectf.xmax > (seq->enddisp - handsize)) {
+ if (rectf.xmax > (SEQ_time_right_handle_frame_get(scene, seq) - handsize)) {
if (select) {
seq->flag |= SELECT | SEQ_RIGHTSEL;
}
@@ -1661,7 +1683,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
}
}
/* Left handle. */
- if (rectf.xmin < (seq->startdisp + handsize)) {
+ if (rectf.xmin < (SEQ_time_left_handle_frame_get(scene, seq) + handsize)) {
if (select) {
seq->flag |= SELECT | SEQ_LEFTSEL;
}
@@ -1945,7 +1967,8 @@ static bool select_grouped_effect(SeqCollection *strips,
return changed;
}
-static bool select_grouped_time_overlap(SeqCollection *strips,
+static bool select_grouped_time_overlap(const Scene *scene,
+ SeqCollection *strips,
ListBase *UNUSED(seqbase),
Sequence *actseq)
{
@@ -1953,7 +1976,10 @@ static bool select_grouped_time_overlap(SeqCollection *strips,
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
- if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
+ if (SEQ_time_left_handle_frame_get(scene, seq) <
+ SEQ_time_right_handle_frame_get(scene, actseq) &&
+ SEQ_time_right_handle_frame_get(scene, seq) >
+ SEQ_time_left_handle_frame_get(scene, actseq)) {
seq->flag |= SELECT;
changed = true;
}
@@ -1963,7 +1989,8 @@ static bool select_grouped_time_overlap(SeqCollection *strips,
}
/* Query strips that are in lower channel and intersect in time with seq_reference. */
-static void query_lower_channel_strips(Sequence *seq_reference,
+static void query_lower_channel_strips(const Scene *scene,
+ Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
{
@@ -1971,8 +1998,10 @@ static void query_lower_channel_strips(Sequence *seq_reference,
if (seq_test->machine > seq_reference->machine) {
continue; /* Not lower channel. */
}
- if (seq_test->enddisp <= seq_reference->startdisp ||
- seq_test->startdisp >= seq_reference->enddisp) {
+ if (SEQ_time_right_handle_frame_get(scene, seq_test) <=
+ SEQ_time_left_handle_frame_get(scene, seq_reference) ||
+ SEQ_time_left_handle_frame_get(scene, seq_test) >=
+ SEQ_time_right_handle_frame_get(scene, seq_reference)) {
continue; /* Not intersecting in time. */
}
SEQ_collection_append_strip(seq_test, collection);
@@ -1981,7 +2010,8 @@ 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(SeqCollection *strips,
+static bool select_grouped_effect_link(const Scene *scene,
+ SeqCollection *strips,
ListBase *seqbase,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
@@ -1989,8 +2019,10 @@ static bool select_grouped_effect_link(SeqCollection *strips,
/* Get collection of strips. */
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);
+ // XXX this uses scene as arg, so it does not work with iterator :( I had thought about this, but
+ // expand function is just so useful... I can just add scene and inject it I guess.....
+ SEQ_collection_expand(scene, seqbase, strips, query_lower_channel_strips);
+ SEQ_collection_expand(scene, seqbase, strips, SEQ_query_strip_effect_chain);
/* Check if other strips will be affected. */
const bool changed = SEQ_collection_len(strips) > selected_strip_count;
@@ -2056,10 +2088,10 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
changed |= select_grouped_effect(strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT_LINK:
- changed |= select_grouped_effect_link(strips, seqbase, actseq, channel);
+ changed |= select_grouped_effect_link(scene, strips, seqbase, actseq, channel);
break;
case SEQ_SELECT_GROUP_OVERLAP:
- changed |= select_grouped_time_overlap(strips, seqbase, actseq);
+ changed |= select_grouped_time_overlap(scene, strips, seqbase, actseq);
break;
default:
BLI_assert(0);
diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
index eab17d876f3..a11b5663620 100644
--- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c
+++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c
@@ -69,15 +69,16 @@ static void thumbnail_endjob(void *data)
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, tj->scene);
}
-static bool check_seq_need_thumbnails(Sequence *seq, rctf *view_area)
+static bool check_seq_need_thumbnails(const Scene *scene, 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) {
+ if (min_ii(SEQ_time_left_handle_frame_get(scene, seq), seq->start) > view_area->xmax) {
return false;
}
- if (max_ii(seq->enddisp, seq->start + seq->len) < view_area->xmin) {
+ if (max_ii(SEQ_time_right_handle_frame_get(scene, seq), seq->start + seq->len) <
+ view_area->xmin) {
return false;
}
if (seq->machine + 1.0f < view_area->ymin) {
@@ -135,6 +136,7 @@ static void thumbnail_start_job(void *data,
float *UNUSED(progress))
{
ThumbnailDrawJob *tj = data;
+ const Scene *scene = tj->scene;
float frame_step;
GHashIterator gh_iter;
@@ -145,7 +147,7 @@ static void thumbnail_start_job(void *data,
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)) {
+ if (check_seq_need_thumbnails(scene, seq_orig, tj->view_area)) {
seq_get_thumb_image_dimensions(
val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL);
SEQ_render_thumbnails(
@@ -161,7 +163,7 @@ static void thumbnail_start_job(void *data,
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)) {
+ if (check_seq_need_thumbnails(scene, seq_orig, tj->view_area)) {
seq_get_thumb_image_dimensions(
val->seq_dupli, tj->pixelx, tj->pixely, &frame_step, tj->thumb_height, NULL, NULL);
SEQ_render_thumbnails_base_set(&tj->context, val->seq_dupli, seq_orig, tj->view_area, stop);
@@ -197,7 +199,7 @@ static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Edi
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)) {
+ if (val_need_update == NULL && check_seq_need_thumbnails(scene, 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;
@@ -206,7 +208,7 @@ static GHash *sequencer_thumbnail_ghash_init(const bContext *C, View2D *v2d, Edi
else {
if (val_need_update != NULL) {
val_need_update->seq_dupli->start = seq->start;
- val_need_update->seq_dupli->startdisp = seq->startdisp;
+ val_need_update->seq_dupli->startdisp = SEQ_time_left_handle_frame_get(scene, seq);
}
}
}
@@ -361,17 +363,20 @@ static int sequencer_thumbnail_closest_previous_frame_get(int timeline_frame,
return best_frame;
}
-static int sequencer_thumbnail_closest_guaranteed_frame_get(Sequence *seq, int timeline_frame)
+static int sequencer_thumbnail_closest_guaranteed_frame_get(struct Scene *scene,
+ Sequence *seq,
+ int timeline_frame)
{
- if (timeline_frame <= seq->startdisp) {
- return seq->startdisp;
+ if (timeline_frame <= SEQ_time_left_handle_frame_get(scene, seq)) {
+ return SEQ_time_left_handle_frame_get(scene, seq);
}
/* 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 frame_index = timeline_frame - SEQ_time_left_handle_frame_get(scene, seq);
+ const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(scene, 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;
+ const int nearest_guaranted_absolute_frame = relative_base_frame +
+ SEQ_time_left_handle_frame_get(scene, seq);
return nearest_guaranted_absolute_frame;
}
@@ -386,7 +391,8 @@ static ImBuf *sequencer_thumbnail_closest_from_memory(const SeqRenderData *conte
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);
+ int frame_guaranteed = sequencer_thumbnail_closest_guaranteed_frame_get(
+ context->scene, seq, timeline_frame);
ImBuf *ibuf_guaranteed = SEQ_get_thumbnail(context, seq, frame_guaranteed, crop, clipped);
ImBuf *closest_in_memory = NULL;
@@ -426,6 +432,11 @@ void draw_seq_strip_thumbnail(View2D *v2d,
float image_height, image_width, thumb_width;
rcti crop;
+ StripElem *se = seq->strip->stripdata;
+ if (se->orig_height == 0 || se->orig_width == 0) {
+ return;
+ }
+
/* If width of the strip too small ignore drawing thumbnails. */
if ((y2 - y1) / pixely <= 20 * U.dpi_fac) {
return;
@@ -444,13 +455,14 @@ void draw_seq_strip_thumbnail(View2D *v2d,
float thumb_y_end = y1 + thumb_height;
float cut_off = 0;
- float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) :
- seq->enddisp;
+ float upper_thumb_bound = SEQ_time_has_right_still_frames(scene, seq) ?
+ (seq->start + seq->len) :
+ SEQ_time_right_handle_frame_get(scene, seq);
if (seq->type == SEQ_TYPE_IMAGE) {
- upper_thumb_bound = seq->enddisp;
+ upper_thumb_bound = SEQ_time_right_handle_frame_get(scene, seq);
}
- float timeline_frame = SEQ_render_thumbnail_first_frame_get(seq, thumb_width, &v2d->cur);
+ float timeline_frame = SEQ_render_thumbnail_first_frame_get(scene, seq, thumb_width, &v2d->cur);
float thumb_x_end;
GSet *last_displayed_thumbnails = last_displayed_thumbnails_list_ensure(C, seq);
@@ -473,8 +485,8 @@ void draw_seq_strip_thumbnail(View2D *v2d,
}
/* Set the clipping bound to show the left handle moving over thumbs and not shift thumbs. */
- if (IN_RANGE_INCL(seq->startdisp, timeline_frame, thumb_x_end)) {
- cut_off = seq->startdisp - timeline_frame;
+ if (IN_RANGE_INCL(SEQ_time_left_handle_frame_get(scene, seq), timeline_frame, thumb_x_end)) {
+ cut_off = SEQ_time_left_handle_frame_get(scene, seq) - timeline_frame;
clipped = true;
}
@@ -551,7 +563,7 @@ void draw_seq_strip_thumbnail(View2D *v2d,
IMB_freeImBuf(ibuf);
GPU_blend(GPU_BLEND_NONE);
cut_off = 0;
- timeline_frame = SEQ_render_thumbnail_next_frame_get(seq, timeline_frame, thumb_width);
+ timeline_frame = SEQ_render_thumbnail_next_frame_get(scene, seq, timeline_frame, thumb_width);
}
last_displayed_thumbnails_list_cleanup(last_displayed_thumbnails, timeline_frame, FLT_MAX);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index b3dbc3c72d1..78fa8c379d9 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -12,6 +12,7 @@
#include "DNA_scene_types.h"
#include "BKE_context.h"
+#include "BKE_scene.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -20,8 +21,6 @@
#include "UI_view2d.h"
-#include "RNA_define.h"
-
#include "SEQ_iterator.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
@@ -86,7 +85,7 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op)
box.xmin = ms->disp_range[0] - 1;
box.xmax = ms->disp_range[1] + 1;
}
- SEQ_timeline_expand_boundbox(SEQ_active_seqbase_get(ed), &box);
+ SEQ_timeline_expand_boundbox(scene, SEQ_active_seqbase_get(ed), &box);
View2D *v2d = &region->v2d;
rcti scrub_rect;
@@ -176,8 +175,7 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
seq_reset_imageofs(sseq);
- imgwidth = (scene->r.size * scene->r.xsch) / 100;
- imgheight = (scene->r.size * scene->r.ysch) / 100;
+ BKE_render_resolution(&scene->r, false, &imgwidth, &imgheight);
/* Apply aspect, doesn't need to be that accurate. */
imgwidth = (int)(imgwidth * (scene->r.xasp / scene->r.yasp));
@@ -229,11 +227,11 @@ static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op)
float ratio = RNA_float_get(op->ptr, "ratio");
- float winx = (int)(rd->size * rd->xsch) / 100;
- float winy = (int)(rd->size * rd->ysch) / 100;
+ int winx, winy;
+ BKE_render_resolution(rd, false, &winx, &winy);
- float facx = BLI_rcti_size_x(&v2d->mask) / winx;
- float facy = BLI_rcti_size_y(&v2d->mask) / winy;
+ float facx = BLI_rcti_size_x(&v2d->mask) / (float)winx;
+ float facy = BLI_rcti_size_y(&v2d->mask) / (float)winy;
BLI_rctf_resize(&v2d->cur, ceilf(winx * facx / ratio + 0.5f), ceilf(winy * facy / ratio + 0.5f));
@@ -308,8 +306,8 @@ static void seq_view_collection_rect_timeline(Scene *scene, SeqCollection *strip
int xmargin = FPS;
SEQ_ITERATOR_FOREACH (seq, strips) {
- xmin = min_ii(xmin, seq->startdisp);
- xmax = max_ii(xmax, seq->enddisp);
+ xmin = min_ii(xmin, SEQ_time_left_handle_frame_get(scene, seq));
+ xmax = max_ii(xmax, SEQ_time_right_handle_frame_get(scene, seq));
ymin = min_ii(ymin, seq->machine);
ymax = max_ii(ymax, seq->machine);
@@ -375,7 +373,7 @@ void SEQUENCER_OT_view_selected(wmOperatorType *ot)
/* Api callbacks. */
ot->exec = sequencer_view_selected_exec;
- ot->poll = ED_operator_sequencer_active;
+ ot->poll = sequencer_editing_initialized_and_active;
/* Flags. */
ot->flag = OPTYPE_REGISTER;
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index f95c5f196b6..0199fa81928 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -548,7 +548,8 @@ static void sequencer_main_clamp_view(const bContext *C, ARegion *region)
}
View2D *v2d = &region->v2d;
- Editing *ed = SEQ_editing_get(CTX_data_scene(C));
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
if (ed == NULL) {
return;
@@ -563,7 +564,7 @@ static void sequencer_main_clamp_view(const bContext *C, ARegion *region)
/* Initialize default view with 7 channels, that are visible even if empty. */
rctf strip_boundbox;
BLI_rctf_init(&strip_boundbox, 0.0f, 0.0f, 1.0f, 7.0f);
- SEQ_timeline_expand_boundbox(ed->seqbasep, &strip_boundbox);
+ SEQ_timeline_expand_boundbox(scene, ed->seqbasep, &strip_boundbox);
/* Clamp Y max. Scrubbing area height must be added, so strips aren't occluded. */
rcti scrub_rect;
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index b3d6c395e89..8dbb4a2ee0c 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -32,8 +32,6 @@
#include "BLF_api.h"
-#include "spreadsheet_intern.hh"
-
#include "spreadsheet_context.hh"
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_dataset_draw.hh"
@@ -300,10 +298,10 @@ static float get_default_column_width(const ColumnValues &values)
return values.default_width;
}
static const float float_width = 3;
- static const float int_width = 2;
switch (values.type()) {
case SPREADSHEET_VALUE_TYPE_BOOL:
return 2.0f;
+ case SPREADSHEET_VALUE_TYPE_INT8:
case SPREADSHEET_VALUE_TYPE_INT32:
return float_width;
case SPREADSHEET_VALUE_TYPE_FLOAT:
@@ -313,13 +311,12 @@ static float get_default_column_width(const ColumnValues &values)
case SPREADSHEET_VALUE_TYPE_FLOAT3:
return 3.0f * float_width;
case SPREADSHEET_VALUE_TYPE_COLOR:
+ case SPREADSHEET_VALUE_TYPE_BYTE_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_BYTE_COLOR:
- return 4.0f * int_width;
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
return 2.0f;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index a29aa1fd026..46e98acb8e8 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -23,6 +23,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<bool>()) {
return SPREADSHEET_VALUE_TYPE_BOOL;
}
+ if (type.is<int8_t>()) {
+ return SPREADSHEET_VALUE_TYPE_INT8;
+ }
if (type.is<int>()) {
return SPREADSHEET_VALUE_TYPE_INT32;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
index 76c7131e268..6a09d3f84c6 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source.hh
@@ -27,9 +27,8 @@ class DataSource {
* column. (This can be made a bit more generic in the future when necessary.)
*/
virtual void foreach_default_column_ids(
- FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
+ FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> /*fn*/) const
{
- UNUSED_VARS(fn);
}
/**
@@ -37,9 +36,8 @@ class DataSource {
* returned.
*/
virtual std::unique_ptr<ColumnValues> get_column_values(
- const SpreadsheetColumnID &column_id) const
+ const SpreadsheetColumnID & /*column_id*/) const
{
- UNUSED_VARS(column_id);
return {};
}
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 7f696efabf7..c7653e94b4d 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -1,7 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_index_mask_ops.hh"
#include "BLI_virtual_array.hh"
+#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_geometry_fields.hh"
@@ -64,7 +66,12 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
void GeometryDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const
{
- if (component_->attribute_domain_num(domain_) == 0) {
+ if (!component_->attributes().has_value()) {
+ return;
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+
+ if (attributes.domain_size(domain_) == 0) {
return;
}
@@ -73,14 +80,18 @@ void GeometryDataSource::foreach_default_column_ids(
}
extra_columns_.foreach_default_column_ids(fn);
- component_->attribute_foreach(
- [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+
+ attributes.for_all(
+ [&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) {
if (meta_data.domain != domain_) {
return true;
}
if (attribute_id.is_anonymous()) {
return true;
}
+ if (!bke::allow_procedural_attribute_access(attribute_id.name())) {
+ return true;
+ }
SpreadsheetColumnID column_id;
column_id.name = (char *)attribute_id.name().data();
fn(column_id, false);
@@ -110,7 +121,11 @@ void GeometryDataSource::foreach_default_column_ids(
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const SpreadsheetColumnID &column_id) const
{
- const int domain_num = component_->attribute_domain_num(domain_);
+ if (!component_->attributes().has_value()) {
+ return {};
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+ const int domain_num = attributes.domain_size(domain_);
if (domain_num == 0) {
return {};
}
@@ -196,7 +211,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
}
}
- bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
+ bke::GAttributeReader attribute = attributes.lookup(column_id.name);
if (!attribute) {
return {};
}
@@ -210,7 +225,11 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
int GeometryDataSource::tot_rows() const
{
- return component_->attribute_domain_num(domain_);
+ if (!component_->attributes().has_value()) {
+ return {};
+ }
+ const bke::AttributeAccessor attributes = *component_->attributes();
+ return attributes.domain_size(domain_);
}
/**
@@ -232,20 +251,10 @@ bool GeometryDataSource::has_selection_filter() const
return true;
}
-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_};
+ const IndexMask full_range(this->tot_rows());
BLI_assert(object_eval_->mode == OB_MODE_EDIT);
BLI_assert(component_->type() == GEO_COMPONENT_TYPE_MESH);
@@ -259,7 +268,7 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) c
const int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX);
if (orig_indices != nullptr) {
/* Use CD_ORIGINDEX layer if it exists. */
- VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool> selection = mesh_component->attributes()->adapt_domain<bool>(
VArray<bool>::ForFunc(mesh_eval->totvert,
[bm, orig_indices](int vertex_index) -> bool {
const int i_orig = orig_indices[vertex_index];
@@ -274,12 +283,12 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) c
}),
ATTR_DOMAIN_POINT,
domain_);
- return index_mask_from_bool_array(selection, indices);
+ return index_mask_ops::find_indices_from_virtual_array(full_range, selection, 1024, indices);
}
if (mesh_eval->totvert == bm->totvert) {
/* Use a simple heuristic to match original vertices to evaluated ones. */
- VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>(
+ VArray<bool> selection = mesh_component->attributes()->adapt_domain<bool>(
VArray<bool>::ForFunc(mesh_eval->totvert,
[bm](int vertex_index) -> bool {
BMVert *vert = bm->vtable[vertex_index];
@@ -287,10 +296,10 @@ IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) c
}),
ATTR_DOMAIN_POINT,
domain_);
- return index_mask_from_bool_array(selection, indices);
+ return index_mask_ops::find_indices_from_virtual_array(full_range, selection, 2048, indices);
}
- return IndexMask(mesh_eval->totvert);
+ return full_range;
}
void VolumeDataSource::foreach_default_column_ids(
@@ -395,10 +404,15 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
geometry_set.get_component_for_write<PointCloudComponent>();
pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
}
+ else if (object_orig->type == OB_CURVES) {
+ const Curves &curves_id = *(const Curves *)object_orig->data;
+ CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
+ curve_component.replace(&const_cast<Curves &>(curves_id), GeometryOwnershipType::ReadOnly);
+ }
}
else {
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);
+ Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval);
if (mesh == nullptr) {
return geometry_set;
}
@@ -469,18 +483,6 @@ static void find_fields_to_evaluate(const SpaceSpreadsheet *sspreadsheet,
}
}
-static GeometryComponentType get_display_component_type(const bContext *C, Object *object_eval)
-{
- SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
- if (sspreadsheet->object_eval_state != SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
- return (GeometryComponentType)sspreadsheet->geometry_component_type;
- }
- if (object_eval->type == OB_POINTCLOUD) {
- return GEO_COMPONENT_TYPE_POINT_CLOUD;
- }
- 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. */
@@ -509,7 +511,7 @@ 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>, GArray<>> arrays;
+ Map<std::pair<eAttrDomain, GField>, GArray<>> arrays;
};
static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
@@ -523,10 +525,10 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
sspreadsheet->runtime->cache.lookup_or_add<GeometryComponentCacheValue>(
std::make_unique<GeometryComponentCacheKey>(component));
- const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain;
- const int domain_num = component.attribute_domain_num(domain);
+ const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain;
+ const int domain_num = component.attributes()->domain_size(domain);
for (const auto item : fields_to_show.items()) {
- StringRef name = item.key;
+ const StringRef name = item.key;
const GField &field = item.value;
/* Use the cached evaluated array if it exists, otherwise evaluate the field now. */
@@ -540,17 +542,17 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
return evaluated_array;
});
- r_extra_columns.add(std::move(name), evaluated_array.as_span());
+ r_extra_columns.add(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);
+ const eAttrDomain domain = (eAttrDomain)sspreadsheet->attribute_domain;
+ const GeometryComponentType component_type = GeometryComponentType(
+ sspreadsheet->geometry_component_type);
GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval);
-
if (!geometry_set.has(component_type)) {
return {};
}
@@ -560,10 +562,10 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object
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<VolumeDataSource>(std::move(geometry_set));
}
return std::make_unique<GeometryDataSource>(
- object_eval, geometry_set, component_type, domain, std::move(extra_columns));
+ object_eval, std::move(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 8b281e5a558..04b4f6d8d06 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -40,7 +40,7 @@ class GeometryDataSource : public DataSource {
Object *object_eval_;
const GeometrySet geometry_set_;
const GeometryComponent *component_;
- AttributeDomain domain_;
+ eAttrDomain domain_;
ExtraColumns extra_columns_;
/* Some data is computed on the fly only when it is requested. Computing it does not change the
@@ -53,7 +53,7 @@ class GeometryDataSource : public DataSource {
GeometryDataSource(Object *object_eval,
GeometrySet geometry_set,
const GeometryComponentType component_type,
- const AttributeDomain domain,
+ const eAttrDomain domain,
ExtraColumns extra_columns)
: object_eval_(object_eval),
geometry_set_(std::move(geometry_set)),
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
index 724d0783707..146b6091bde 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc
@@ -27,7 +27,7 @@ class GeometryDataSetTreeView;
class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem {
GeometryComponentType component_type_;
- std::optional<AttributeDomain> domain_;
+ std::optional<eAttrDomain> domain_;
BIFIconID icon_;
public:
@@ -35,7 +35,7 @@ class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem {
StringRef label,
BIFIconID icon);
GeometryDataSetTreeViewItem(GeometryComponentType component_type,
- AttributeDomain domain,
+ eAttrDomain domain,
StringRef label,
BIFIconID icon);
@@ -113,7 +113,7 @@ GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType c
this->set_collapsed(false);
}
GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type,
- AttributeDomain domain,
+ eAttrDomain domain,
StringRef label,
BIFIconID icon)
: component_type_(component_type), domain_(domain), icon_(icon)
@@ -145,7 +145,7 @@ void GeometryDataSetTreeViewItem::build_row(uiLayout &row)
* to the right side of the number, which it didn't have with the button. */
char element_count[7];
BLI_str_format_decimal_unit(element_count, *count);
- UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count);
+ UI_but_hint_drawstr_set((uiBut *)this->view_item_button(), element_count);
}
}
@@ -194,7 +194,7 @@ std::optional<int> GeometryDataSetTreeViewItem::count() const
}
if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) {
- return component->attribute_domain_num(*domain_);
+ return component->attribute_domain_size(*domain_);
}
return 0;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index e19a343335a..780dd0303cd 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -19,6 +19,8 @@
#include "BLF_api.h"
+#include "BLT_translation.h"
+
namespace blender::ed::spreadsheet {
class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
@@ -193,7 +195,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
else if (data.type().is<ColorGeometry4b>()) {
const ColorGeometry4b value = data.get<ColorGeometry4b>(real_index);
- this->draw_int_vector(params, {value.r, value.g, value.b, value.a});
+ this->draw_byte_color(params, value);
}
else if (data.type().is<InstanceReference>()) {
const InstanceReference value = data.get<InstanceReference>(real_index);
@@ -308,13 +310,16 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
}
}
- void draw_int_vector(const CellDrawParams &params, const Span<int> values) const
+ void draw_byte_color(const CellDrawParams &params, const ColorGeometry4b color) const
{
- BLI_assert(!values.is_empty());
+ const ColorGeometry4f float_color = color.decode();
+ Span<float> values(&float_color.r, 4);
const float segment_width = (float)params.width / values.size();
for (const int i : values.index_range()) {
- const int value = values[i];
- const std::string value_str = std::to_string(value);
+ std::stringstream ss;
+ const float value = values[i];
+ ss << std::fixed << std::setprecision(3) << value;
+ const std::string value_str = ss.str();
uiBut *but = uiDefIconTextBut(params.block,
UI_BTYPE_LABEL,
0,
@@ -330,9 +335,24 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
0,
0,
nullptr);
- /* Right-align Ints. */
+ /* Right-align Floats. */
UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT);
+
+ /* Tooltip showing raw byte values. Encode values in pointer to avoid memory allocation. */
+ UI_but_func_tooltip_set(
+ but,
+ [](bContext * /*C*/, void *argN, const char *UNUSED(tip)) {
+ const uint32_t uint_color = POINTER_AS_UINT(argN);
+ ColorGeometry4b color = *(ColorGeometry4b *)&uint_color;
+ return BLI_sprintfN(TIP_("Byte Color (sRGB encoded):\n%3d %3d %3d %3d"),
+ color.r,
+ color.g,
+ color.b,
+ color.a);
+ },
+ POINTER_FROM_UINT(*(uint32_t *)&color),
+ nullptr);
}
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
index 4d6dc3b4166..166c5de9fc3 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc
@@ -5,12 +5,6 @@
#include "ED_screen.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
#include "BLI_listbase.h"
#include "MEM_guardedalloc.h"
@@ -20,8 +14,6 @@
#include "RNA_access.h"
#include "RNA_define.h"
-#include "ED_screen.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -92,7 +84,7 @@ static int select_component_domain_invoke(bContext *C,
{
GeometryComponentType component_type = static_cast<GeometryComponentType>(
RNA_int_get(op->ptr, "component_type"));
- AttributeDomain attribute_domain = static_cast<AttributeDomain>(
+ eAttrDomain attribute_domain = static_cast<eAttrDomain>(
RNA_int_get(op->ptr, "attribute_domain_type"));
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index eb8f111baa0..6806e185cfe 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -14,8 +14,6 @@
#include "RNA_access.h"
-#include "spreadsheet_intern.hh"
-
#include "spreadsheet_data_source_geometry.hh"
#include "spreadsheet_intern.hh"
#include "spreadsheet_layout.hh"
@@ -73,6 +71,35 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
}
}
+ else if (column_data.type().is<int8_t>()) {
+ const int value = row_filter.value_int;
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [&](const int cell) { return cell == value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [value](const int cell) { return cell > value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<int8_t>(),
+ [&](const int cell) { return cell < value; },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
+ }
else if (column_data.type().is<int>()) {
const int value = row_filter.value_int;
switch (row_filter.operation) {
@@ -168,49 +195,76 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
else if (column_data.type().is<ColorGeometry4f>()) {
const ColorGeometry4f value = row_filter.value_color;
- const float threshold_sq = pow2f(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);
+ switch (row_filter.operation) {
+ case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float threshold_sq = pow2f(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;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4f>(),
+ [&](const ColorGeometry4f cell) {
+ return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ }
}
else if (column_data.type().is<ColorGeometry4b>()) {
- const ColorGeometry4b value = row_filter.value_byte_color;
- const float4 value_floats = {(float)value.r, (float)value.g, (float)value.b, (float)value.a};
- const float threshold_sq = pow2f(row_filter.threshold);
- apply_filter_operation(
- column_data.typed<ColorGeometry4b>(),
- [&](const ColorGeometry4b cell) {
- const float4 cell_floats = {(float)cell.r, (float)cell.g, (float)cell.b, (float)cell.a};
- return len_squared_v4v4(value_floats, cell_floats) <= threshold_sq;
- },
- prev_mask,
- new_indices);
- }
- else if (column_data.type().is<InstanceReference>()) {
- const StringRef value = row_filter.value_string;
+ const ColorGeometry4f value = row_filter.value_color;
switch (row_filter.operation) {
case SPREADSHEET_ROW_FILTER_EQUAL: {
+ const float4 value_floats = {
+ (float)value.r, (float)value.g, (float)value.b, (float)value.a};
+ const float threshold_sq = pow2f(row_filter.threshold);
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;
+ column_data.typed<ColorGeometry4b>(),
+ [&](const ColorGeometry4b cell_bytes) {
+ const ColorGeometry4f cell = cell_bytes.decode();
+ const float4 cell_floats = {
+ (float)cell.r, (float)cell.g, (float)cell.b, (float)cell.a};
+ return len_squared_v4v4(value_floats, cell_floats) <= threshold_sq;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_GREATER: {
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4b>(),
+ [&](const ColorGeometry4b cell_bytes) {
+ const ColorGeometry4f cell = cell_bytes.decode();
+ return cell.r > value.r && cell.g > value.g && cell.b > value.b && cell.a > value.a;
+ },
+ prev_mask,
+ new_indices);
+ break;
+ }
+ case SPREADSHEET_ROW_FILTER_LESS: {
+ apply_filter_operation(
+ column_data.typed<ColorGeometry4b>(),
+ [&](const ColorGeometry4b cell_bytes) {
+ const ColorGeometry4f cell = cell_bytes.decode();
+ return cell.r < value.r && cell.g < value.g && cell.b < value.b && cell.a < value.a;
},
prev_mask,
new_indices);
@@ -218,6 +272,32 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
}
}
}
+ else if (column_data.type().is<InstanceReference>()) {
+ const StringRef value = row_filter.value_string;
+
+ 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);
+ }
}
static bool use_row_filters(const SpaceSpreadsheet &sspreadsheet)
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 7c1ac024c12..548e6cf29e4 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -39,11 +39,7 @@ static void filter_panel_id_fn(void *UNUSED(row_filter_v), char *r_name)
static std::string operation_string(const eSpreadsheetColumnValueType data_type,
const eSpreadsheetFilterOperation operation)
{
- if (ELEM(data_type,
- SPREADSHEET_VALUE_TYPE_BOOL,
- SPREADSHEET_VALUE_TYPE_INSTANCES,
- SPREADSHEET_VALUE_TYPE_COLOR,
- SPREADSHEET_VALUE_TYPE_BYTE_COLOR)) {
+ if (ELEM(data_type, SPREADSHEET_VALUE_TYPE_BOOL, SPREADSHEET_VALUE_TYPE_INSTANCES)) {
return "=";
}
@@ -63,6 +59,7 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
const eSpreadsheetColumnValueType data_type)
{
switch (data_type) {
+ case SPREADSHEET_VALUE_TYPE_INT8:
case SPREADSHEET_VALUE_TYPE_INT32:
return std::to_string(row_filter.value_int);
case SPREADSHEET_VALUE_TYPE_FLOAT: {
@@ -93,7 +90,8 @@ 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:
+ case SPREADSHEET_VALUE_TYPE_BYTE_COLOR: {
std::ostringstream result;
result.precision(3);
result << std::fixed << "(" << row_filter.value_color[0] << ", " << row_filter.value_color[1]
@@ -102,14 +100,6 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
}
case SPREADSHEET_VALUE_TYPE_STRING:
return row_filter.value_string;
- case SPREADSHEET_VALUE_TYPE_BYTE_COLOR: {
- std::ostringstream result;
- result.precision(3);
- result << std::fixed << "(" << (int)row_filter.value_byte_color[0] << ", "
- << (int)row_filter.value_byte_color[1] << ", " << (int)row_filter.value_byte_color[2]
- << ", " << (int)row_filter.value_byte_color[3] << ")";
- return result.str();
- }
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
return "";
}
@@ -200,6 +190,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
}
switch (static_cast<eSpreadsheetColumnValueType>(column->data_type)) {
+ case SPREADSHEET_VALUE_TYPE_INT8:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
+ uiItemR(layout, filter_ptr, "value_int8", 0, IFACE_("Value"), ICON_NONE);
+ break;
case SPREADSHEET_VALUE_TYPE_INT32:
uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_int", 0, IFACE_("Value"), ICON_NONE);
@@ -232,16 +226,16 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_COLOR:
+ case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
+ uiItemR(layout, filter_ptr, "operation", 0, nullptr, ICON_NONE);
uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE);
- uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
+ if (operation == SPREADSHEET_ROW_FILTER_EQUAL) {
+ 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_BYTE_COLOR:
- uiItemR(layout, filter_ptr, "value_byte_color", 0, IFACE_("Value"), ICON_NONE);
- uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE);
- break;
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
uiItemL(layout, IFACE_("Unknown column type"), ICON_ERROR);
break;
diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c
index f7d7f9c6238..4b3ee1c15c7 100644
--- a/source/blender/editors/space_text/text_format_lua.c
+++ b/source/blender/editors/space_text/text_format_lua.c
@@ -264,7 +264,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;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -287,18 +287,19 @@ static void txtfmt_lua_format_line(SpaceText *st, TextLine *line, const bool do_
else if ((*str != '#') && text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space/delimiters so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words. */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
- /* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_osl_format_identifier()' */
+ /* Special `vars(v)` or built-in `keywords(b)` */
+ /* keep in sync with `txtfmt_osl_format_identifier()`. */
if ((i = txtfmt_lua_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_lua_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
}
diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c
index 27dc1174c49..575eadeee66 100644
--- a/source/blender/editors/space_text/text_format_osl.c
+++ b/source/blender/editors/space_text/text_format_osl.c
@@ -285,7 +285,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;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -298,18 +298,19 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_
else if ((*str != '#') && text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space or delimiters. so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words. */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
/* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_osl_format_identifier()' */
+ /* keep in sync with `txtfmt_osl_format_identifier()`. */
if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c
index 7c2f098f0fa..7c2c4829ad3 100644
--- a/source/blender/editors/space_text/text_format_pov.c
+++ b/source/blender/editors/space_text/text_format_pov.c
@@ -857,7 +857,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;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -880,18 +880,19 @@ static void txtfmt_pov_format_line(SpaceText *st, TextLine *line, const bool do_
else if (text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space/delimiters so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words. */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
/* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_pov_format_identifier()' */
+ /* keep in sync with `txtfmt_pov_format_identifier()`. */
if ((i = txtfmt_pov_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_pov_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_pov_find_reserved_keywords(str)) != -1) { prev = FMT_TYPE_RESERVED;
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 6844f08cca6..dda3b7089fe 100644
--- a/source/blender/editors/space_text/text_format_pov_ini.c
+++ b/source/blender/editors/space_text/text_format_pov_ini.c
@@ -435,7 +435,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;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -458,18 +458,19 @@ static void txtfmt_pov_ini_format_line(SpaceText *st, TextLine *line, const bool
else if ((*str != '#') && text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space/delimiters so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
/* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_ini_format_identifier()' */
+ /* keep in sync with `txtfmt_ini_format_identifier()`. */
if ((i = txtfmt_ini_find_keyword(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_ini_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
}
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index 47d0168195b..28f536ffa98 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -59,9 +59,9 @@ static int txtfmt_py_find_builtinfunc(const char *string)
/* clang-format off */
if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len;
@@ -425,7 +425,7 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const bool do_n
}
*fmt = FMT_TYPE_STRING;
}
- /* White-space (all ws. has been converted to spaces). */
+ /* White-space (all white-space has been converted to spaces). */
else if (*str == ' ') {
*fmt = FMT_TYPE_WHITESPACE;
}
@@ -447,18 +447,19 @@ static void txtfmt_py_format_line(SpaceText *st, TextLine *line, const bool do_n
else if ((*str != '@') && text_check_delim(*str)) {
*fmt = FMT_TYPE_SYMBOL;
}
- /* Identifiers and other text (no previous ws. or delims. so text continues) */
+ /* Identifiers and other text (no previous white-space/delimiters so text continues). */
else if (prev == FMT_TYPE_DEFAULT) {
str += BLI_str_utf8_size_safe(str) - 1;
*fmt = FMT_TYPE_DEFAULT;
}
- /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */
+ /* Not white-space, a digit, punctuation, or continuing text.
+ * Must be new, check for special words. */
else {
- /* Keep aligned args for readability. */
+ /* Keep aligned arguments for readability. */
/* clang-format off */
/* Special vars(v) or built-in keywords(b) */
- /* keep in sync with 'txtfmt_py_format_identifier()' */
+ /* keep in sync with `txtfmt_py_format_identifier()`. */
if ((i = txtfmt_py_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_py_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_py_find_decorator(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 05d51cf6362..33219092d20 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -3396,7 +3396,8 @@ static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wm
return OPERATOR_PASS_THROUGH;
}
- if (!(event->ascii >= '0' && event->ascii <= '9')) {
+ const char event_ascii = WM_event_utf8_to_ascii(event);
+ if (!(event_ascii >= '0' && event_ascii <= '9')) {
return OPERATOR_PASS_THROUGH;
}
@@ -3406,7 +3407,7 @@ static int text_line_number_invoke(bContext *C, wmOperator *UNUSED(op), const wm
}
jump_to *= 10;
- jump_to += (int)(event->ascii - '0');
+ jump_to += (int)(event_ascii - '0');
txt_move_toline(text, jump_to - 1, 0);
last_jump = time;
@@ -3495,16 +3496,8 @@ static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
char str[BLI_UTF8_MAX + 1];
- size_t len;
-
- if (event->utf8_buf[0]) {
- len = BLI_str_utf8_size_safe(event->utf8_buf);
- memcpy(str, event->utf8_buf, len);
- }
- else {
- /* in theory, ghost can set value to extended ascii here */
- len = BLI_str_utf8_from_unicode(event->ascii, str, sizeof(str) - 1);
- }
+ const size_t len = BLI_str_utf8_size_safe(event->utf8_buf);
+ memcpy(str, event->utf8_buf, len);
str[len] = '\0';
RNA_string_set(op->ptr, "text", str);
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index e9a9e690e60..bc68de1dfce 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -155,6 +155,9 @@ static void topbar_header_listener(const wmRegionListenerParams *params)
ED_region_tag_redraw(region);
}
break;
+ case NC_WORKSPACE:
+ ED_region_tag_redraw(region);
+ break;
case NC_SPACE:
if (wmn->data == ND_SPACE_INFO) {
ED_region_tag_redraw(region);
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 48abe71e35f..a423a842019 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -594,7 +594,7 @@ static char *view3d_mat_drop_tooltip(bContext *C,
{
const char *name = WM_drag_get_item_name(drag);
ARegion *region = CTX_wm_region(C);
- int mval[2] = {
+ const int mval[2] = {
xy[0] - region->winrct.xmin,
xy[1] - region->winrct.ymin,
};
@@ -1300,6 +1300,10 @@ static void view3d_main_region_listener(const wmRegionListenerParams *params)
ED_region_tag_redraw(region);
}
break;
+ case NC_WORKSPACE:
+ /* In case the region displays workspace settings. */
+ ED_region_tag_redraw(region);
+ break;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c
index 96a193cc10d..4a1bd6ba945 100644
--- a/source/blender/editors/space_view3d/view3d_cursor_snap.c
+++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c
@@ -8,11 +8,9 @@
*/
#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"
@@ -54,7 +52,7 @@ typedef struct SnapCursorDataIntern {
struct SnapObjectContext *snap_context_v3d;
const Scene *scene;
- short snap_elem_hidden;
+ eSnapMode snap_elem_hidden;
float prevpoint_stack[3];
@@ -374,7 +372,7 @@ void ED_view3d_cursor_snap_draw_util(RegionView3D *rv3d,
const float normal[3],
const uchar color_line[4],
const uchar color_point[4],
- const short snap_elem_type)
+ const eSnapMode snap_elem_type)
{
if (!loc_prev && !loc_curr) {
return;
@@ -539,9 +537,9 @@ static bool v3d_cursor_is_snap_invert(SnapCursorDataIntern *data_intern, const w
/** \name Update
* \{ */
-static short v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene)
+static eSnapMode v3d_cursor_snap_elements(V3DSnapCursorState *snap_state, Scene *scene)
{
- short snap_elements = snap_state->snap_elem_force;
+ eSnapMode snap_elements = snap_state->snap_elem_force;
if (!snap_elements) {
return scene->toolsettings->snap_mode;
}
@@ -587,7 +585,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
v3d_cursor_snap_context_ensure(scene);
float co[3], no[3], face_nor[3], obmat[4][4], omat[3][3];
- short snap_elem = 0;
+ eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
int snap_elem_index[3] = {-1, -1, -1};
int index = -1;
@@ -596,12 +594,12 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
zero_v3(face_nor);
unit_m3(omat);
- ushort snap_elements = v3d_cursor_snap_elements(state, scene);
- data_intern->snap_elem_hidden = 0;
+ eSnapMode snap_elements = v3d_cursor_snap_elements(state, scene);
+ data_intern->snap_elem_hidden = SCE_SNAP_MODE_NONE;
const bool calc_plane_omat = v3d_cursor_snap_calc_plane();
- if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE)) {
- data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
- snap_elements |= SCE_SNAP_MODE_FACE;
+ if (calc_plane_omat && !(snap_elements & SCE_SNAP_MODE_FACE_RAYCAST)) {
+ data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE_RAYCAST;
+ snap_elements |= SCE_SNAP_MODE_FACE_RAYCAST;
}
snap_data->is_enabled = true;
@@ -613,16 +611,15 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
if (snap_data->is_snap_invert != !(ts->snap_flag & SCE_SNAP)) {
snap_data->is_enabled = false;
if (!calc_plane_omat) {
- snap_data->snap_elem = 0;
+ snap_data->snap_elem = SCE_SNAP_MODE_NONE;
return;
}
- snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE;
+ snap_elements = data_intern->snap_elem_hidden = SCE_SNAP_MODE_FACE_RAYCAST;
}
}
#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)) {
+ if (snap_elements & SCE_SNAP_MODE_GEOM) {
float prev_co[3] = {0.0f};
if (state->prevpoint) {
copy_v3_v3(prev_co, state->prevpoint);
@@ -648,10 +645,11 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
v3d,
snap_elements,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = edit_mode_type,
.use_occlusion_test = use_occlusion_test,
},
+ NULL,
mval_fl,
prev_co,
&dist_px,
@@ -663,13 +661,10 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
face_nor);
}
- if (is_zero_v3(face_nor)) {
- face_nor[state->plane_axis] = 1.0f;
- }
-
if (calc_plane_omat) {
RegionView3D *rv3d = region->regiondata;
- bool orient_surface = snap_elem && (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
+ bool orient_surface = (snap_elem != SCE_SNAP_MODE_NONE) &&
+ (state->plane_orient == V3D_PLACE_ORIENT_SURFACE);
if (orient_surface) {
copy_m3_m4(omat, obmat);
}
@@ -693,16 +688,36 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
orthogonalize_m3(omat, state->plane_axis);
if (orient_surface) {
- if (dot_v3v3(rv3d->viewinv[2], face_nor) < 0.0f) {
- negate_v3(face_nor);
+ if (!is_zero_v3(face_nor)) {
+ /* Negate the face normal according to the view. */
+ float ray_dir[3];
+ if (rv3d->is_persp) {
+ BLI_assert_msg(snap_elem != SCE_SNAP_MODE_NONE,
+ "Use of variable `co` without it being computed");
+
+ sub_v3_v3v3(ray_dir, co, rv3d->viewinv[3]); /* No need to normalize. */
+ }
+ else {
+ negate_v3_v3(ray_dir, rv3d->viewinv[2]);
+ }
+
+ if (dot_v3v3(ray_dir, face_nor) >= 0.0f) {
+ negate_v3(face_nor);
+ }
+ }
+ else if (!is_zero_v3(no)) {
+ copy_v3_v3(face_nor, no);
+ }
+ else {
+ face_nor[state->plane_axis] = 1.0f;
}
v3d_cursor_poject_surface_normal(face_nor, obmat, omat);
}
}
- float *co_depth = snap_elem ? co : scene->cursor.location;
+ float *co_depth = (snap_elem != SCE_SNAP_MODE_NONE) ? co : scene->cursor.location;
snap_elem &= ~data_intern->snap_elem_hidden;
- if (snap_elem == 0) {
+ if (snap_elem == SCE_SNAP_MODE_NONE) {
RegionView3D *rv3d = region->regiondata;
const float *plane_normal = omat[state->plane_axis];
bool do_plane_isect = (state->plane_depth != V3D_PLACE_DEPTH_CURSOR_VIEW) &&
@@ -730,7 +745,7 @@ static void v3d_cursor_snap_update(V3DSnapCursorState *state,
(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) {
+ else if (snap_elem == SCE_SNAP_MODE_FACE_RAYCAST) {
snap_elem_index[2] = index;
}
@@ -816,7 +831,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
}
const bool draw_plane = state->draw_plane || state->draw_box;
- if (!snap_data->snap_elem && !draw_plane) {
+ if (snap_data->snap_elem == SCE_SNAP_MODE_NONE && !draw_plane) {
return;
}
@@ -834,7 +849,7 @@ static void v3d_cursor_snap_draw_fn(bContext *C, int x, int y, void *UNUSED(cust
v3d_cursor_plane_draw(rv3d, state->plane_axis, matrix);
}
- if (snap_data->snap_elem && (state->draw_point || state->draw_box)) {
+ if (snap_data->snap_elem != SCE_SNAP_MODE_NONE && (state->draw_point || state->draw_box)) {
const float *prev_point = (snap_data->snap_elem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) ?
state->prevpoint :
NULL;
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 5b068750d76..5405867be56 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1294,7 +1294,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y
static void draw_selected_name(
Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset)
{
- const int cfra = CFRA;
+ const int cfra = scene->r.cfra;
const char *msg_pin = " (Pinned)";
const char *msg_sep = " : ";
@@ -1786,11 +1786,13 @@ void ED_view3d_draw_offscreen_simple(Depsgraph *depsgraph,
}
/* 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_ORIGINS;
+ V3D_OVERLAY_HIDE_MOTION_PATHS | V3D_OVERLAY_HIDE_OBJECT_ORIGINS;
if ((draw_flags & V3D_OFSDRAW_SHOW_OBJECT_EXTRAS) == 0) {
v3d.overlay.flag |= V3D_OVERLAY_HIDE_OBJECT_XTRAS;
}
+ if ((object_type_exclude_viewport_override & (1 << OB_ARMATURE)) != 0) {
+ v3d.overlay.flag |= V3D_OVERLAY_HIDE_BONES;
+ }
v3d.flag |= V3D_HIDE_HELPLINES;
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 9f8d7afd9a8..d6ddd6d044e 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -413,7 +413,9 @@ static void view3d_set_1_to_1_viewborder(Scene *scene,
{
RegionView3D *rv3d = region->regiondata;
float size[2];
- int im_width = (scene->r.size * scene->r.xsch) / 100;
+
+ int im_width, im_height;
+ BKE_render_resolution(&scene->r, false, &im_width, &im_height);
ED_view3d_calc_camera_border_size(scene, depsgraph, region, v3d, rv3d, size);
@@ -631,13 +633,20 @@ static int background_image_remove_exec(bContext *C, wmOperator *op)
CameraBGImage *bgpic_rem = BLI_findlink(&cam->bg_images, index);
if (bgpic_rem) {
- if (bgpic_rem->source == CAM_BGIMG_SOURCE_IMAGE) {
- id_us_min((ID *)bgpic_rem->ima);
- }
- else if (bgpic_rem->source == CAM_BGIMG_SOURCE_MOVIE) {
- id_us_min((ID *)bgpic_rem->clip);
+ if (ID_IS_OVERRIDE_LIBRARY(cam) &&
+ (bgpic_rem->flag & CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL) == 0) {
+ BKE_reportf(op->reports,
+ RPT_WARNING,
+ "Cannot remove background image %d from camera '%s', as it is from the linked "
+ "reference data",
+ index,
+ cam->id.name + 2);
+ return OPERATOR_CANCELLED;
}
+ id_us_min((ID *)bgpic_rem->ima);
+ id_us_min((ID *)bgpic_rem->clip);
+
BKE_camera_background_image_remove(cam, bgpic_rem);
WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
@@ -657,7 +666,7 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = background_image_remove_exec;
- ot->poll = ED_operator_camera;
+ ot->poll = ED_operator_camera_poll;
/* flags */
ot->flag = 0;
@@ -901,12 +910,13 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
CTX_data_ensure_evaluated_depsgraph(C),
region,
v3d,
- SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_FACE_RAYCAST,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
+ NULL,
mval_fl,
NULL,
&dist_px,
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 567022cc9d1..62dc461e05c 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -357,11 +357,12 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
depsgraph,
ruler_info->region,
v3d,
- SCE_SNAP_MODE_FACE,
+ SCE_SNAP_MODE_FACE_RAYCAST,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_CAGE,
},
+ NULL,
mval_fl,
NULL,
&dist_px,
@@ -374,7 +375,7 @@ static bool view3d_ruler_item_mousemove(const bContext *C,
depsgraph,
v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
.edit_mode_type = SNAP_GEOM_CAGE,
},
ray_start,
@@ -522,7 +523,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER;
}
- gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
+ gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_ADD_NEW);
BKE_gpencil_free_strokes(gpf);
for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item;
@@ -576,7 +577,7 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup)
gpl = view3d_ruler_layer_get(scene->gpd);
if (gpl) {
bGPDframe *gpf;
- gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_USE_PREV);
+ gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV);
if (gpf) {
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
@@ -1228,11 +1229,7 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
- RNA_enum_set(gizmo->ptr,
- "snap_elements_force",
- (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));
+ RNA_enum_set(gizmo->ptr, "snap_elements_force", SCE_SNAP_MODE_GEOM);
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});
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 f0557205e8f..aa287403e23 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_tool_generic.c
@@ -19,8 +19,6 @@
#include "MEM_guardedalloc.h"
-#include "WM_toolsystem.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 4606908b91f..35d4746608b 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -335,7 +335,7 @@ void mesh_foreachScreenVert(
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
- me = BKE_mesh_wrapper_ensure_subdivision(vc->obedit, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -398,7 +398,7 @@ void mesh_foreachScreenEdge(ViewContext *vc,
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
- me = BKE_mesh_wrapper_ensure_subdivision(vc->obedit, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -486,7 +486,7 @@ void mesh_foreachScreenEdge_clip_bb_segment(ViewContext *vc,
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
- me = BKE_mesh_wrapper_ensure_subdivision(vc->obedit, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -558,7 +558,7 @@ void mesh_foreachScreenFace(
Mesh *me = editbmesh_get_eval_cage_from_orig(
vc->depsgraph, vc->scene, vc->obedit, &CD_MASK_BAREMESH);
- me = BKE_mesh_wrapper_ensure_subdivision(vc->obedit, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
ED_view3d_check_mats_rv3d(vc->rv3d);
data.vc = *vc;
diff --git a/source/blender/editors/space_view3d/view3d_navigate_walk.c b/source/blender/editors/space_view3d/view3d_navigate_walk.c
index 19e064438fc..471231b5f27 100644
--- a/source/blender/editors/space_view3d/view3d_navigate_walk.c
+++ b/source/blender/editors/space_view3d/view3d_navigate_walk.c
@@ -55,9 +55,6 @@
#define USE_TABLET_SUPPORT
-/* ensure the target position is one we can reach, see: T45771 */
-#define USE_PIXELSIZE_NATIVE_SUPPORT
-
/* -------------------------------------------------------------------- */
/** \name Modal Key-map
* \{ */
@@ -226,8 +223,8 @@ typedef struct WalkInfo {
/** Previous 2D mouse values. */
int prev_mval[2];
- /** Center mouse values. */
- int center_mval[2];
+ /** Initial mouse location. */
+ int init_mval[2];
int moffset[2];
@@ -271,9 +268,6 @@ typedef struct WalkInfo {
bool is_reversed;
#ifdef USE_TABLET_SUPPORT
- /** Check if we had a cursor event before. */
- bool is_cursor_first;
-
/** Tablet devices (we can't relocate the cursor). */
bool is_cursor_absolute;
#endif
@@ -412,7 +406,7 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
walk->depsgraph,
walk->v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
/* Avoid having to convert the edit-mesh to a regular mesh. */
.edit_mode_type = SNAP_GEOM_EDIT,
},
@@ -454,7 +448,7 @@ static bool walk_ray_cast(RegionView3D *rv3d,
walk->depsgraph,
walk->v3d,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
ray_start,
ray_normal,
@@ -484,7 +478,7 @@ enum {
static float base_speed = -1.0f;
static float userdef_speed = -1.0f;
-static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
+static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, const int mval[2])
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -565,8 +559,6 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
#ifdef USE_TABLET_SUPPORT
- walk->is_cursor_first = true;
-
walk->is_cursor_absolute = false;
#endif
@@ -599,28 +591,10 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
walk->depsgraph, walk->scene, walk->v3d, walk->rv3d);
- /* center the mouse */
- walk->center_mval[0] = walk->region->winx * 0.5f;
- walk->center_mval[1] = walk->region->winy * 0.5f;
-
-#ifdef USE_PIXELSIZE_NATIVE_SUPPORT
- walk->center_mval[0] += walk->region->winrct.xmin;
- walk->center_mval[1] += walk->region->winrct.ymin;
-
- WM_cursor_compatible_xy(win, &walk->center_mval[0], &walk->center_mval[1]);
-
- walk->center_mval[0] -= walk->region->winrct.xmin;
- walk->center_mval[1] -= walk->region->winrct.ymin;
-#endif
+ copy_v2_v2_int(walk->init_mval, mval);
+ copy_v2_v2_int(walk->prev_mval, mval);
- copy_v2_v2_int(walk->prev_mval, walk->center_mval);
-
- WM_cursor_warp(win,
- walk->region->winrct.xmin + walk->center_mval[0],
- walk->region->winrct.ymin + walk->center_mval[1]);
-
- /* remove the mouse cursor temporarily */
- WM_cursor_modal_set(win, WM_CURSOR_NONE);
+ WM_cursor_grab_enable(win, 0, true, NULL);
return 1;
}
@@ -669,18 +643,7 @@ static int walkEnd(bContext *C, WalkInfo *walk)
}
#endif
- /* restore the cursor */
- WM_cursor_modal_restore(win);
-
-#ifdef USE_TABLET_SUPPORT
- if (walk->is_cursor_absolute == false)
-#endif
- {
- /* center the mouse */
- WM_cursor_warp(win,
- walk->region->winrct.xmin + walk->center_mval[0],
- walk->region->winrct.ymin + walk->center_mval[1]);
- }
+ WM_cursor_grab_enable(win, 0, true, NULL);
if (walk->state == WALK_CONFIRM) {
MEM_freeN(walk);
@@ -691,7 +654,7 @@ static int walkEnd(bContext *C, WalkInfo *walk)
return OPERATOR_CANCELLED;
}
-static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
+static void walkEvent(WalkInfo *walk, const wmEvent *event)
{
if (event->type == TIMER && event->customdata == walk->timer) {
walk->redraw = true;
@@ -699,26 +662,8 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
#ifdef USE_TABLET_SUPPORT
- if (walk->is_cursor_first) {
- /* wait until we get the 'warp' event */
- if ((walk->center_mval[0] == event->mval[0]) && (walk->center_mval[1] == event->mval[1])) {
- walk->is_cursor_first = false;
- }
- else {
- /* NOTE: its possible the system isn't giving us the warp event
- * ideally we shouldn't have to worry about this, see: T45361 */
- wmWindow *win = CTX_wm_window(C);
- WM_cursor_warp(win,
- walk->region->winrct.xmin + walk->center_mval[0],
- walk->region->winrct.ymin + walk->center_mval[1]);
- }
- return;
- }
-
if ((walk->is_cursor_absolute == false) && event->tablet.is_motion_absolute) {
walk->is_cursor_absolute = true;
- copy_v2_v2_int(walk->prev_mval, event->mval);
- copy_v2_v2_int(walk->center_mval, event->mval);
}
#endif /* USE_TABLET_SUPPORT */
@@ -727,29 +672,8 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
copy_v2_v2_int(walk->prev_mval, event->mval);
- if ((walk->center_mval[0] != event->mval[0]) || (walk->center_mval[1] != event->mval[1])) {
+ if (walk->moffset[0] || walk->moffset[1]) {
walk->redraw = true;
-
-#ifdef USE_TABLET_SUPPORT
- if (walk->is_cursor_absolute) {
- /* pass */
- }
- else
-#endif
- if (WM_event_is_last_mousemove(event)) {
- wmWindow *win = CTX_wm_window(C);
-
-#ifdef __APPLE__
- if ((abs(walk->prev_mval[0] - walk->center_mval[0]) > walk->center_mval[0] / 2) ||
- (abs(walk->prev_mval[1] - walk->center_mval[1]) > walk->center_mval[1] / 2))
-#endif
- {
- WM_cursor_warp(win,
- walk->region->winrct.xmin + walk->center_mval[0],
- walk->region->winrct.ymin + walk->center_mval[1]);
- copy_v2_v2_int(walk->prev_mval, walk->center_mval);
- }
- }
}
}
#ifdef WITH_INPUT_NDOF
@@ -1436,12 +1360,12 @@ static int walk_invoke(bContext *C, wmOperator *op, const wmEvent *event)
op->customdata = walk;
- if (initWalkInfo(C, walk, op) == false) {
+ if (initWalkInfo(C, walk, op, event->mval) == false) {
MEM_freeN(op->customdata);
return OPERATOR_CANCELLED;
}
- walkEvent(C, walk, event);
+ walkEvent(walk, event);
WM_event_add_modal_handler(C, op);
@@ -1467,7 +1391,7 @@ static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event)
walk->redraw = false;
- walkEvent(C, walk, event);
+ walkEvent(walk, event);
#ifdef WITH_INPUT_NDOF
if (walk->ndof) { /* 3D mouse overrules [2D mouse + timer] */
@@ -1515,7 +1439,9 @@ void VIEW3D_OT_walk(wmOperatorType *ot)
ot->poll = ED_operator_region_view3d_active;
/* flags */
- ot->flag = OPTYPE_BLOCKING;
+ /* NOTE: #OPTYPE_BLOCKING isn't used because this needs to grab & hide the cursor.
+ * where as blocking confines the cursor to the window bounds, even when hidden. */
+ ot->flag = 0;
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index eefc085bdf8..d3b82476d09 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -695,7 +695,7 @@ static bool view3d_interactive_add_calc_snap(bContext *UNUSED(C),
if (r_is_snap_invert) {
*r_is_snap_invert = snap_data->is_snap_invert;
}
- return snap_data->snap_elem != 0;
+ return snap_data->snap_elem != SCE_SNAP_MODE_NONE;
}
/** \} */
@@ -1303,7 +1303,7 @@ 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) {
+ if (snap_state->snap_elem_force == SCE_SNAP_MODE_NONE) {
return PLACE_SNAP_TO_DEFAULT;
}
@@ -1316,7 +1316,7 @@ 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. */
+ eSnapMode snap_mode = SCE_SNAP_MODE_NONE; /* #toolsettings->snap_mode. */
const enum ePlace_SnapTo snap_to = value;
if (snap_to == PLACE_SNAP_TO_GEOMETRY) {
snap_mode = SCE_SNAP_MODE_GEOM;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index efe89621e7b..8eff9ee472f 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -57,8 +57,6 @@
#include "BKE_tracking.h"
#include "BKE_workspace.h"
-#include "DEG_depsgraph.h"
-
#include "WM_api.h"
#include "WM_toolsystem.h"
#include "WM_types.h"
@@ -2878,6 +2876,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
struct SelectPick_Params params = {0};
ED_select_pick_params_from_operator(op->ptr, &params);
+ const bool vert_without_handles = RNA_boolean_get(op->ptr, "vert_without_handles");
bool center = RNA_boolean_get(op->ptr, "center");
bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
/* Only force object select for edit-mode to support vertex parenting,
@@ -2932,7 +2931,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
changed = ED_lattice_select_pick(C, mval, &params);
}
else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
- changed = ED_curve_editnurb_select_pick(C, mval, ED_view3d_select_dist_px(), &params);
+ changed = ED_curve_editnurb_select_pick(
+ C, mval, ED_view3d_select_dist_px(), vert_without_handles, &params);
}
else if (obedit->type == OB_MBALL) {
changed = ED_mball_select_pick(C, mval, &params);
@@ -3009,6 +3009,15 @@ void VIEW3D_OT_select(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit mode only)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ /* Needed for select-through to usefully drag handles, see: T98254.
+ * NOTE: this option may be removed and become default behavior, see design task: T98552. */
+ prop = RNA_def_boolean(ot->srna,
+ "vert_without_handles",
+ 0,
+ "Control Point Without Handles",
+ "Only select the curve control point, not it's handles");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_int_vector(ot->srna,
"location",
2,
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 306394ce53d..85b1af8e55d 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -633,7 +633,7 @@ bool ED_view3d_camera_autokey(const Scene *scene,
const bool do_translate)
{
if (autokeyframe_cfra_can_key(scene, id_key)) {
- const float cfra = (float)CFRA;
+ const float cfra = (float)scene->r.cfra;
ListBase dsources = {NULL, NULL};
/* add data-source override for the camera object */
@@ -1492,10 +1492,12 @@ static bool view3d_camera_to_view_selected_impl(struct Main *bmain,
depsgraph, scene, camera_ob_eval, co, &scale, r_clip_start, r_clip_end)) {
ObjectTfmProtectedChannels obtfm;
float obmat_new[4][4];
+ bool is_ortho_camera = false;
if ((camera_ob_eval->type == OB_CAMERA) &&
(((Camera *)camera_ob_eval->data)->type == CAM_ORTHO)) {
((Camera *)camera_ob->data)->ortho_scale = scale;
+ is_ortho_camera = true;
}
copy_m4_m4(obmat_new, camera_ob_eval->obmat);
@@ -1508,6 +1510,9 @@ static bool view3d_camera_to_view_selected_impl(struct Main *bmain,
/* notifiers */
DEG_id_tag_update_ex(bmain, &camera_ob->id, ID_RECALC_TRANSFORM);
+ if (is_ortho_camera) {
+ DEG_id_tag_update_ex(bmain, camera_ob->data, ID_RECALC_PARAMETERS);
+ }
return true;
}
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 68c4f4e76ca..6984dcb18d4 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -39,6 +39,7 @@ set(SRC
transform_convert_mesh_edge.c
transform_convert_mesh_skin.c
transform_convert_mesh_uv.c
+ transform_convert_mesh_vert_cdata.c
transform_convert_nla.c
transform_convert_node.c
transform_convert_object.c
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index a7e2f616c9e..d9e23b98c66 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1425,9 +1425,6 @@ static void drawTransformView(const struct bContext *C, ARegion *region, void *a
/* edge slide, vert slide */
drawEdgeSlide(t);
drawVertSlide(t);
-
- /* Rotation */
- drawDial3d(t);
}
}
@@ -1579,7 +1576,8 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
/* do we check for parameter? */
if (transformModeUseSnap(t)) {
if (!(t->modifiers & MOD_SNAP) != !(t->tsnap.flag & SCE_SNAP)) {
- char *snap_flag_ptr;
+ /* Type is #eSnapFlag, but type must match various snap attributes in #ToolSettings. */
+ short *snap_flag_ptr;
wmMsgParams_RNA msg_key_params = {{0}};
RNA_pointer_create(&t->scene->id, &RNA_ToolSettings, ts, &msg_key_params.ptr);
@@ -1786,13 +1784,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->launch_event = event ? WM_userdef_event_type_from_keymap_type(event->type) : -1;
t->is_launch_event_drag = event ? (event->val == KM_CLICK_DRAG) : false;
- /* XXX Remove this when wm_operator_call_internal doesn't use window->eventstate
- * (which can have type = 0) */
- /* For gizmo only, so assume LEFTMOUSE. */
- if (t->launch_event == 0) {
- t->launch_event = LEFTMOUSE;
- }
-
unit_m3(t->spacemtx);
initTransInfo(C, t, op, event);
@@ -2061,3 +2052,17 @@ bool checkUseAxisMatrix(TransInfo *t)
return false;
}
+
+bool transform_apply_matrix(TransInfo *t, float mat[4][4])
+{
+ if (t->transform_matrix != NULL) {
+ t->transform_matrix(t, mat);
+ return true;
+ }
+ return false;
+}
+
+void transform_final_value_get(const TransInfo *t, float *value, const int value_num)
+{
+ memcpy(value, t->values_final, sizeof(float) * value_num);
+}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index a3df6a44682..b01affc7307 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -13,6 +13,7 @@
#include "DNA_listBase.h"
#include "DNA_object_enums.h"
+#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
@@ -153,7 +154,8 @@ typedef enum {
} eTModifier;
/** #TransSnap.status */
-typedef enum {
+typedef enum eTSnap {
+ SNAP_RESETTED = 0,
SNAP_FORCED = 1 << 0,
TARGET_INIT = 1 << 1,
/* Special flag for snap to grid. */
@@ -220,6 +222,7 @@ typedef enum {
TC_MESH_EDGES,
TC_MESH_SKIN,
TC_MESH_UV,
+ TC_MESH_VERT_CDATA,
TC_NLA_DATA,
TC_NODE_DATA,
TC_OBJECT,
@@ -294,19 +297,22 @@ typedef struct TransSnapPoint {
} TransSnapPoint;
typedef struct TransSnap {
- char flag;
- char mode;
- short target;
- short modePoint;
- short modeSelect;
+ /* Snapping options stored as flags */
+ eSnapFlag flag;
+ /* Method(s) used for snapping source to target */
+ eSnapMode mode;
+ /* Part of source to snap to target */
+ eSnapSourceSelect source_select;
+ /* Determines which objects are possible target */
+ eSnapTargetSelect target_select;
bool align;
bool project;
- bool snap_self;
bool peel;
bool use_backface_culling;
+ short face_nearest_steps;
eTSnap status;
/* Snapped Element Type (currently for objects only). */
- char snapElem;
+ eSnapMode snapElem;
/** snapping from this point (in global-space). */
float snapTarget[3];
/** to this point (in global-space). */
@@ -458,6 +464,8 @@ typedef struct TransDataContainer {
int data_len;
/** Total number of transformed data_mirror. */
int data_mirror_len;
+ /** Total number of transformed gp-frames. */
+ int data_gpf_len;
struct Object *obedit;
@@ -533,6 +541,13 @@ typedef struct TransInfo {
/* Event handler function that determines whether the viewport needs to be redrawn. */
eRedrawFlag (*handleEvent)(struct TransInfo *, const struct wmEvent *);
+ /**
+ * Optional callback to transform a single matrix.
+ *
+ * \note used by the gizmo to transform the matrix used to position it.
+ */
+ void (*transform_matrix)(struct TransInfo *t, float mat_xform[4][4]);
+
/** Constraint Data. */
TransCon con;
@@ -713,6 +728,12 @@ void removeAspectRatio(TransInfo *t, float vec[2]);
*/
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
+/**
+ * Transform a single matrix using the current `t->final_values`.
+ */
+bool transform_apply_matrix(TransInfo *t, float mat[4][4]);
+void transform_final_value_get(const TransInfo *t, float *value, int value_num);
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -725,7 +746,6 @@ struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
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);
/** \} */
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 0bb00032561..658901a6991 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -402,7 +402,7 @@ static void applyAxisConstraintVec(const TransInfo *t,
if (activeSnap(t)) {
if (validSnap(t)) {
is_snap_to_edge = (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE) != 0;
- is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE) != 0;
+ is_snap_to_face = (t->tsnap.snapElem & SCE_SNAP_MODE_FACE_RAYCAST) != 0;
is_snap_to_point = !is_snap_to_edge && !is_snap_to_face;
}
else if (t->tsnap.snapElem & SCE_SNAP_MODE_GRID) {
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 018468dcd03..b0148ce508c 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -479,132 +479,6 @@ TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTr
/** \name UV Coordinates
* \{ */
-/**
- * Find the correction for the scaling factor when "Constrain to Bounds" is active.
- * \param numerator: How far the UV boundary (unit square) is from the origin of the scale.
- * \param denominator: How far the AABB is from the origin of the scale.
- * \param scale: Scale parameter to update.
- */
-static void constrain_scale_to_boundary(const float numerator,
- const float denominator,
- float *scale)
-{
- if (denominator == 0.0f) {
- /* The origin of the scale is on the edge of the boundary. */
- if (numerator < 0.0f) {
- /* Negative scale will wrap around and put us outside the boundary. */
- *scale = 0.0f; /* Hold at the boundary instead. */
- }
- return; /* Nothing else we can do without more info. */
- }
-
- const float correction = numerator / denominator;
- if (correction < 0.0f || !isfinite(correction)) {
- /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */
- return;
- }
-
- if (denominator < 0.0f) {
- /* Scale origin is outside boundary, only make scale bigger. */
- if (*scale < correction) {
- *scale = correction;
- }
- return;
- }
-
- /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */
- if (*scale > correction) {
- *scale = correction;
- }
-}
-
-bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
-{
- bool clipx = true, clipy = true;
- float min[2], max[2];
-
- /* Check if the current image in UV editor is a tiled image or not. */
- const SpaceImage *sima = t->area->spacedata.first;
- const Image *image = sima->image;
- const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
- /* Stores the coordinates of the closest UDIM tile.
- * Also acts as an offset to the tile from the origin of UV space. */
- float base_offset[2] = {0.0f, 0.0f};
-
- /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */
- if (is_tiled_image) {
- int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global);
- if (nearest_tile_index != -1) {
- nearest_tile_index -= 1001;
- /* Getting coordinates of nearest tile from the tile index. */
- base_offset[0] = nearest_tile_index % 10;
- base_offset[1] = nearest_tile_index / 10;
- }
- }
-
- min[0] = min[1] = FLT_MAX;
- max[0] = max[1] = FLT_MIN;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- TransData *td;
- int a;
-
- for (a = 0, td = tc->data; a < tc->data_len; a++, td++) {
- minmax_v2v2_v2(min, max, td->loc);
- }
- }
-
- if (resize) {
- /* Assume no change is required. */
- float scalex = 1.0f;
- float scaley = 1.0f;
-
- /* Update U against the left border. */
- constrain_scale_to_boundary(
- t->center_global[0] - base_offset[0], t->center_global[0] - min[0], &scalex);
- /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */
- constrain_scale_to_boundary(base_offset[0] + t->aspect[0] - t->center_global[0],
- max[0] - t->center_global[0],
- &scalex);
-
- /* Do the same for the V co-ordinate, which is called `y`. */
- constrain_scale_to_boundary(
- t->center_global[1] - base_offset[1], t->center_global[1] - min[1], &scaley);
- constrain_scale_to_boundary(base_offset[1] + t->aspect[1] - t->center_global[1],
- max[1] - t->center_global[1],
- &scaley);
-
- clipx = (scalex != 1.0f);
- clipy = (scaley != 1.0f);
- vec[0] *= scalex;
- vec[1] *= scaley;
- }
- else {
- if (min[0] < base_offset[0]) {
- vec[0] += base_offset[0] - min[0];
- }
- else if (max[0] > base_offset[0] + t->aspect[0]) {
- vec[0] -= max[0] - base_offset[0] - t->aspect[0];
- }
- else {
- clipx = 0;
- }
-
- if (min[1] < base_offset[1]) {
- vec[1] += base_offset[1] - min[1];
- }
- else if (max[1] > base_offset[1] + t->aspect[1]) {
- vec[1] -= max[1] - base_offset[1] - t->aspect[1];
- }
- else {
- clipy = 0;
- }
- }
-
- return (clipx || clipy);
-}
-
void clipUVData(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -769,7 +643,7 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand
}
else {
/* Delete Keyframe */
- delete_fcurve_key(fcu, i, 0);
+ BKE_fcurve_delete_key(fcu, i);
}
/* Update count of how many we've deleted
@@ -779,7 +653,7 @@ void posttrans_fcurve_clean(FCurve *fcu, const int sel_flag, const bool use_hand
}
else {
/* Always delete - Unselected keys don't matter */
- delete_fcurve_key(fcu, i, 0);
+ BKE_fcurve_delete_key(fcu, i);
}
/* Stop the RK search... we've found our match now */
@@ -949,6 +823,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_GPENCIL:
case TC_LATTICE_VERTS:
case TC_MBALL_VERTS:
+ case TC_MESH_VERT_CDATA:
case TC_MESH_UV:
case TC_MESH_SKIN:
case TC_OBJECT_TEXSPACE:
@@ -1031,6 +906,7 @@ static void init_proportional_edit(TransInfo *t)
case TC_MESH_EDGES:
case TC_MESH_SKIN:
case TC_MESH_UV:
+ case TC_MESH_VERT_CDATA:
case TC_NODE_DATA:
case TC_OBJECT:
case TC_PARTICLE_VERTS:
@@ -1065,7 +941,7 @@ static void init_proportional_edit(TransInfo *t)
if (ELEM(convert_type, TC_ACTION_DATA, TC_GRAPH_EDIT_DATA)) {
/* Distance has already been set. */
}
- else if (ELEM(convert_type, TC_MESH_VERTS, TC_MESH_SKIN)) {
+ else if (ELEM(convert_type, TC_MESH_VERTS, TC_MESH_SKIN, TC_MESH_VERT_CDATA)) {
if (t->flag & T_PROP_CONNECTED) {
/* Already calculated by transform_convert_mesh_connectivity_distance. */
}
@@ -1110,6 +986,7 @@ static void init_TransDataContainers(TransInfo *t,
case TC_MESH_EDGES:
case TC_MESH_SKIN:
case TC_MESH_UV:
+ case TC_MESH_VERT_CDATA:
break;
case TC_ACTION_DATA:
case TC_GRAPH_EDIT_DATA:
@@ -1221,6 +1098,7 @@ static eTFlag flags_from_data_type(eTConvertType data_type)
case TC_MBALL_VERTS:
case TC_MESH_VERTS:
case TC_MESH_SKIN:
+ case TC_MESH_VERT_CDATA:
return T_EDIT | T_POINTS;
case TC_MESH_EDGES:
return T_EDIT;
@@ -1320,6 +1198,9 @@ static eTConvertType convert_type_get(const TransInfo *t, Object **r_obj_armatur
if (t->mode == TFM_SKIN_RESIZE) {
convert_type = TC_MESH_SKIN;
}
+ else if (ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)) {
+ convert_type = TC_MESH_VERT_CDATA;
+ }
else {
convert_type = TC_MESH_VERTS;
}
@@ -1443,6 +1324,9 @@ void createTransData(bContext *C, TransInfo *t)
case TC_NLA_DATA:
createTransNlaData(C, t);
break;
+ case TC_MESH_VERT_CDATA:
+ createTransMeshVertCData(t);
+ break;
case TC_NODE_DATA:
createTransNodeData(t);
break;
@@ -1607,10 +1491,9 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
}
}
-void animrecord_check_state(TransInfo *t, struct Object *ob)
+void animrecord_check_state(TransInfo *t, struct ID *id)
{
Scene *scene = t->scene;
- ID *id = &ob->id;
wmTimer *animtimer = t->animtimer;
ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
@@ -1750,6 +1633,9 @@ void recalcData(TransInfo *t)
case TC_MESH_UV:
recalcData_uv(t);
break;
+ case TC_MESH_VERT_CDATA:
+ recalcData_mesh_cdata(t);
+ break;
case TC_NLA_DATA:
recalcData_nla(t);
break;
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 7080deaec66..1b7c33e443c 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -34,7 +34,6 @@ int special_transform_moving(TransInfo *t);
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], bool resize);
void clipUVData(TransInfo *t);
void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, float y_fac);
/**
@@ -95,7 +94,7 @@ 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);
+void animrecord_check_state(TransInfo *t, struct ID *id);
/* transform_convert_action.c */
@@ -253,6 +252,11 @@ void createTransUVs(bContext *C, TransInfo *t);
/* helper for recalcData() - for Image Editor transforms */
void recalcData_uv(TransInfo *t);
+/* transform_convert_mesh_vert_cdata.c */
+
+void createTransMeshVertCData(TransInfo *t);
+void recalcData_mesh_cdata(TransInfo *t);
+
/* transform_convert_nla.c */
void createTransNlaData(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 71c245cd512..71a78321e12 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -311,6 +311,7 @@ void createTransActionData(bContext *C, TransInfo *t)
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
int count = 0;
+ int gpf_count = 0;
float cfra;
float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->region->v2d.cur);
@@ -320,17 +321,12 @@ void createTransActionData(bContext *C, TransInfo *t)
}
/* filter data */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
- }
- else {
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
- }
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -345,10 +341,10 @@ void createTransActionData(bContext *C, TransInfo *t)
* higher scaling ratios, but is faster than converting all points)
*/
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
@@ -365,13 +361,16 @@ void createTransActionData(bContext *C, TransInfo *t)
}
if (adt_count > 0) {
+ if (ELEM(ale->type, ANIMTYPE_GPLAYER, ANIMTYPE_MASKLAYER)) {
+ gpf_count += adt_count;
+ }
count += adt_count;
ale->tag = true;
}
}
/* stop if trying to build list if nothing selected */
- if (count == 0) {
+ if (count == 0 && gpf_count == 0) {
/* cleanup temp list */
ANIM_animdata_freelist(&anim_data);
return;
@@ -387,8 +386,9 @@ void createTransActionData(bContext *C, TransInfo *t)
td = tc->data;
td2d = tc->data_2d;
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
- tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * count, "tGPFtransdata");
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
+ tc->data_gpf_len = gpf_count;
+ tc->custom.type.data = tfd = MEM_callocN(sizeof(tGPFtransdata) * gpf_count, "tGPFtransdata");
tc->custom.type.use_free = true;
}
@@ -399,7 +399,7 @@ void createTransActionData(bContext *C, TransInfo *t)
continue;
}
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
{
AnimData *adt;
@@ -447,10 +447,10 @@ void createTransActionData(bContext *C, TransInfo *t)
adt = ANIM_nla_mapping_get(&ac, ale);
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
if (ale->type == ANIMTYPE_GPLAYER) {
@@ -558,8 +558,9 @@ static void flushTransIntFrameActionData(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
tGPFtransdata *tfd = tc->custom.type.data;
- /* flush data! */
- for (int i = 0; i < tc->data_len; i++, tfd++) {
+ /* flush data!
+ * Expects data_gpf_len to be set in the data container. */
+ for (int i = 0; i < tc->data_gpf_len; i++, tfd++) {
*(tfd->sdata) = round_fl_to_int(tfd->val);
}
}
@@ -589,7 +590,7 @@ void recalcData_actedit(TransInfo *t)
ANIM_animdata_context_getdata(&ac);
/* perform flush */
- if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
/* flush transform values back to actual coordinates */
flushTransIntFrameActionData(t);
}
@@ -735,7 +736,7 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
int filter;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, act, ANIMCONT_ACTION);
/* loop through relevant data, removing keyframes as appropriate
@@ -776,32 +777,44 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
if (ELEM(ac.datatype, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY, ANIMCONT_TIMELINE)) {
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/);
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
/* get channels to work on */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- /* these should all be F-Curves */
for (ale = anim_data.first; ale; ale = ale->next) {
- AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
- FCurve *fcu = (FCurve *)ale->key_data;
-
- /* 3 cases here for curve cleanups:
- * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
- * 2) canceled == 0 -> user confirmed the transform,
- * so duplicates should be removed
- * 3) canceled + duplicate -> user canceled the transform,
- * but we made duplicates, so get rid of these
- */
- if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- if (adt) {
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
- posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
- ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
- }
- else {
- posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
+ switch (ale->datatype) {
+ case ALE_GPFRAME:
+ ale->id->tag &= ~LIB_TAG_DOIT;
+ posttrans_gpd_clean((bGPdata *)ale->id);
+ break;
+
+ case ALE_FCURVE: {
+ AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ /* 3 cases here for curve cleanups:
+ * 1) NOTRANSKEYCULL on -> cleanup of duplicates shouldn't be done
+ * 2) canceled == 0 -> user confirmed the transform,
+ * so duplicates should be removed
+ * 3) canceled + duplicate -> user canceled the transform,
+ * but we made duplicates, so get rid of these
+ */
+ if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
+ if (adt) {
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0);
+ posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
+ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0);
+ }
+ else {
+ posttrans_fcurve_clean(fcu, SELECT, false); /* only use handles in graph editor */
+ }
+ }
+ break;
}
+
+ default:
+ BLI_assert_msg(false, "Keys cannot be transformed into this animation type.");
}
}
@@ -847,15 +860,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_GPFRAME) {
- ale->id->tag |= LIB_TAG_DOIT;
- }
- }
- LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
- if (ale->datatype == ALE_GPFRAME) {
- if (ale->id->tag & LIB_TAG_DOIT) {
- ale->id->tag &= ~LIB_TAG_DOIT;
- posttrans_gpd_clean((bGPdata *)ale->id);
- }
+ ale->id->tag &= ~LIB_TAG_DOIT;
+ posttrans_gpd_clean((bGPdata *)ale->id);
}
}
ANIM_animdata_freelist(&anim_data);
@@ -878,15 +884,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t)
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_MASKLAY) {
- ale->id->tag |= LIB_TAG_DOIT;
- }
- }
- LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
- if (ale->datatype == ALE_MASKLAY) {
- if (ale->id->tag & LIB_TAG_DOIT) {
- ale->id->tag &= ~LIB_TAG_DOIT;
- posttrans_mask_clean((Mask *)ale->id);
- }
+ ale->id->tag &= ~LIB_TAG_DOIT;
+ posttrans_mask_clean((Mask *)ale->id);
}
}
ANIM_animdata_freelist(&anim_data);
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 3c1101d48a5..1613218ca29 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -93,8 +93,8 @@ static void autokeyframe_pose(
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
ListBase nla_cache = {NULL, NULL};
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
eInsertKeyFlags flag = 0;
/* flag is initialized from UserPref keyframing settings
@@ -1192,7 +1192,7 @@ static void restoreBones(TransDataContainer *tc)
void recalcData_edit_armature(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -1471,7 +1471,7 @@ void recalcData_pose(TransInfo *t)
/* XXX: this currently doesn't work, since flags aren't set yet! */
int targetless_ik = (t->flag & T_AUTOIK);
- animrecord_check_state(t, ob);
+ animrecord_check_state(t, &ob->id);
autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
}
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 51acfb2a788..b9581aa1e31 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -418,7 +418,7 @@ void createTransCurveVerts(TransInfo *t)
void recalcData_curve(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index a88d42b7f30..4bd02b0a45b 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -685,7 +685,7 @@ void createTransGPencil(bContext *C, TransInfo *t)
bGPdata *gpd = obact->data;
BLI_assert(gpd != NULL);
- const int cfra_scene = CFRA;
+ const int cfra_scene = scene->r.cfra;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) !=
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index 54222fbb117..b57f5b78939 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -24,12 +24,9 @@
#include "UI_view2d.h"
#include "transform.h"
-#include "transform_snap.h"
-
#include "transform_convert.h"
-#include "transform_snap.h"
-
#include "transform_mode.h"
+#include "transform_snap.h"
typedef struct TransDataGraph {
float unit_scale;
@@ -235,13 +232,14 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
anim_map_flag |= ANIM_get_normalization_flags(&ac);
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* which side of the current frame should be allowed */
/* XXX we still want this mode, but how to get this using standard transform too? */
if (t->mode == TFM_TIME_EXTEND) {
- t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -266,10 +264,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
* higher scaling ratios, but is faster than converting all points)
*/
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -372,10 +370,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
* higher scaling ratios, but is faster than converting all points)
*/
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
unit_scale = ANIM_unit_mapping_get_factor(
@@ -563,10 +561,10 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
* higher scaling ratios, but is faster than converting all points)
*/
if (adt) {
- cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
+ cfra = BKE_nla_tweakedit_remap(adt, (float)scene->r.cfra, NLATIME_CONVERT_UNMAP);
}
else {
- cfra = (float)CFRA;
+ cfra = (float)scene->r.cfra;
}
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -918,7 +916,8 @@ void recalcData_graphedit(TransInfo *t)
flushTransGraphData(t);
/* get curves to check if a re-sort is needed */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* now test if there is a need to re-sort */
@@ -935,7 +934,7 @@ void recalcData_graphedit(TransInfo *t)
dosort++;
}
else {
- calchandles_fcurve_ex(fcu, BEZT_FLAG_TEMP_TAG);
+ BKE_fcurve_handles_recalc_ex(fcu, BEZT_FLAG_TEMP_TAG);
}
/* set refresh tags for objects using this animation,
@@ -978,7 +977,8 @@ void special_aftertrans_update__graph(bContext *C, TransInfo *t)
if (ac.datatype) {
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE |
+ ANIMFILTER_FCURVESONLY);
/* get channels to work on */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c
index f02d4e94448..d3c34697237 100644
--- a/source/blender/editors/transform/transform_convert_lattice.c
+++ b/source/blender/editors/transform/transform_convert_lattice.c
@@ -101,7 +101,7 @@ void createTransLatticeVerts(TransInfo *t)
void recalcData_lattice(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 5255cc4412e..f035cfc7aa9 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -117,7 +117,7 @@ static void MaskPointToTransData(Scene *scene,
const bool is_sel_any = MASKPOINT_ISSEL_ANY(point);
float parent_matrix[3][3], parent_inverse_matrix[3][3];
- BKE_mask_point_parent_matrix_get(point, CFRA, parent_matrix);
+ BKE_mask_point_parent_matrix_get(point, scene->r.cfra, parent_matrix);
invert_m3_m3(parent_inverse_matrix, parent_matrix);
if (is_prop_edit || is_sel_point) {
@@ -261,18 +261,10 @@ void createTransMaskingData(bContext *C, TransInfo *t)
tc->data_len = 0;
- if (!mask) {
+ if (!ED_maskedit_mask_visible_splines_poll(C)) {
return;
}
- if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->area->spacedata.first;
- MovieClip *clip = ED_space_clip_get_clip(sc);
- if (!clip) {
- return;
- }
- }
-
/* count */
for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
MaskSpline *spline;
@@ -463,7 +455,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t)
if (IS_AUTOKEY_ON(t->scene)) {
Scene *scene = t->scene;
- if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) {
+ if (ED_mask_layer_shape_auto_key_select(mask, scene->r.cfra)) {
WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
DEG_id_tag_update(&mask->id, 0);
}
diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c
index 7cba4f97886..5b2a1f8336d 100644
--- a/source/blender/editors/transform/transform_convert_mball.c
+++ b/source/blender/editors/transform/transform_convert_mball.c
@@ -122,7 +122,7 @@ void createTransMBallVerts(TransInfo *t)
void recalcData_mball(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (tc->data_len) {
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index d4b12142162..de736fad94e 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1408,7 +1408,6 @@ static void VertsToTransData(TransInfo *t,
TransDataExtension *tx,
BMEditMesh *em,
BMVert *eve,
- float *bweight,
const struct TransIslandData *island_data,
const int island_index)
{
@@ -1449,11 +1448,7 @@ static void VertsToTransData(TransInfo *t,
td->ext = NULL;
td->val = NULL;
td->extra = eve;
- if (ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE)) {
- td->val = bweight;
- td->ival = *bweight;
- }
- else if (t->mode == TFM_SHRINKFATTEN) {
+ if (t->mode == TFM_SHRINKFATTEN) {
td->ext = tx;
tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT);
}
@@ -1589,17 +1584,6 @@ void createTransEditVerts(TransInfo *t)
"TransObData ext");
}
- 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;
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
@@ -1632,15 +1616,9 @@ void createTransEditVerts(TransInfo *t)
td_mirror++;
}
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
* only to get axis for snap/rotate to normal... */
- VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index);
+ VertsToTransData(t, tob, tx, em, eve, &island_data, island_index);
if (tx) {
tx++;
}
@@ -1940,7 +1918,7 @@ static void tc_mesh_partial_types_calc(TransInfo *t, struct PartialTypeState *r_
}
/* With projection, transform isn't affine. */
- if (activeSnap_with_project(t)) {
+ if (activeSnap_SnappingIndividual(t)) {
if (partial_for_looptri == PARTIAL_TYPE_GROUP) {
partial_for_looptri = PARTIAL_TYPE_ALL;
}
@@ -2056,7 +2034,7 @@ void recalcData_mesh(TransInfo *t)
bool is_canceling = t->state == TRANS_CANCEL;
/* Apply corrections. */
if (!is_canceling) {
- applyProject(t);
+ applySnappingIndividual(t);
bool do_mirror = !(t->flag & T_NO_MIRROR);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c
index 2d6c6a933d6..4a8ddb78587 100644
--- a/source/blender/editors/transform/transform_convert_mesh_edge.c
+++ b/source/blender/editors/transform/transform_convert_mesh_edge.c
@@ -99,8 +99,8 @@ void createTransEdge(TransInfo *t)
td->ext = NULL;
fl_ptr = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_float_offset);
- td->val = fl_ptr;
- td->ival = *fl_ptr;
+ td->loc = fl_ptr;
+ td->iloc[0] = *fl_ptr;
td++;
}
diff --git a/source/blender/editors/transform/transform_convert_mesh_uv.c b/source/blender/editors/transform/transform_convert_mesh_uv.c
index 18868643b6d..bb550909407 100644
--- a/source/blender/editors/transform/transform_convert_mesh_uv.c
+++ b/source/blender/editors/transform/transform_convert_mesh_uv.c
@@ -238,7 +238,6 @@ void createTransUVs(bContext *C, TransInfo *t)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = t->scene;
- ToolSettings *ts = CTX_data_tool_settings(C);
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_connected = (t->flag & T_PROP_CONNECTED) != 0;
@@ -266,8 +265,7 @@ void createTransUVs(bContext *C, TransInfo *t)
/* count */
if (is_island_center) {
/* create element map with island information */
- const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
- elementmap = BM_uv_element_map_create(em->bm, scene, use_facesel, true, false, true);
+ elementmap = BM_uv_element_map_create(em->bm, scene, true, false, true);
if (elementmap == NULL) {
continue;
}
diff --git a/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c
new file mode 100644
index 00000000000..104b45de138
--- /dev/null
+++ b/source/blender/editors/transform/transform_convert_mesh_vert_cdata.c
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_crazyspace.h"
+#include "BKE_editmesh.h"
+#include "BKE_modifier.h"
+#include "BKE_scene.h"
+
+#include "ED_mesh.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "transform.h"
+#include "transform_orientations.h"
+
+#include "transform_convert.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Mesh #CD_BWEIGHT and #CD_CREASE Transform Creation
+ * \{ */
+
+static float *tc_mesh_cdata_transdata_center(const struct TransIslandData *island_data,
+ const int island_index,
+ BMVert *eve)
+{
+ if (island_data->center && island_index != -1) {
+ return island_data->center[island_index];
+ }
+ return eve->co;
+}
+
+static void tc_mesh_cdata_transdata_create(TransDataBasic *td,
+ BMVert *eve,
+ float *weight,
+ const struct TransIslandData *island_data,
+ const int island_index)
+{
+ BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
+
+ td->loc = weight;
+ td->iloc[0] = *weight;
+
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ td->flag |= TD_SELECTED;
+ }
+
+ copy_v3_v3(td->center, tc_mesh_cdata_transdata_center(island_data, island_index, eve));
+ td->extra = eve;
+}
+
+void createTransMeshVertCData(TransInfo *t)
+{
+ BLI_assert(ELEM(t->mode, TFM_BWEIGHT, TFM_VERT_CREASE));
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ Mesh *me = tc->obedit->data;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMIter iter;
+ float mtx[3][3], smtx[3][3];
+ int a;
+ const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
+
+ struct TransIslandData island_data = {NULL};
+ struct TransMirrorData mirror_data = {NULL};
+ struct TransMeshDataCrazySpace crazyspace_data = {NULL};
+
+ /* Support other objects using PET to adjust these, unless connected is enabled. */
+ if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) {
+ continue;
+ }
+
+ int cd_offset = -1;
+ if (t->mode == TFM_BWEIGHT) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
+ cd_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ }
+ else {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE);
+ cd_offset = CustomData_get_offset(&bm->vdata, CD_CREASE);
+ }
+
+ if (cd_offset == -1) {
+ continue;
+ }
+
+ int data_len = 0;
+ if (prop_mode) {
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ data_len++;
+ }
+ }
+ }
+ else {
+ data_len = bm->totvertsel;
+ }
+
+ if (data_len == 0) {
+ continue;
+ }
+
+ const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS);
+ if (is_island_center) {
+ /* In this specific case, near-by vertices will need to know
+ * the island of the nearest connected vertex. */
+ const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) &&
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ (em->selectmode & SCE_SELECT_VERTEX));
+
+ const bool calc_island_center = false;
+ const bool calc_island_axismtx = false;
+
+ transform_convert_mesh_islands_calc(
+ em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data);
+ }
+
+ copy_m3_m4(mtx, tc->obedit->obmat);
+ /* we use a pseudo-inverse so that when one of the axes is scaled to 0,
+ * matrix inversion still works and we can still moving along the other */
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ /* Original index of our connected vertex when connected distances are calculated.
+ * Optional, allocate if needed. */
+ int *dists_index = NULL;
+ float *dists = NULL;
+ if (prop_mode & T_PROP_CONNECTED) {
+ dists = MEM_mallocN(bm->totvert * sizeof(float), __func__);
+ if (is_island_center) {
+ dists_index = MEM_mallocN(bm->totvert * sizeof(int), __func__);
+ }
+ transform_convert_mesh_connectivity_distance(em->bm, mtx, dists, dists_index);
+ }
+
+ /* Create TransDataMirror. */
+ if (tc->use_mirror_axis_any) {
+ bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ bool use_select = (t->flag & T_PROP_EDIT) == 0;
+ const bool mirror_axis[3] = {
+ tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z};
+ transform_convert_mesh_mirrordata_calc(
+ em, use_select, use_topology, mirror_axis, &mirror_data);
+
+ if (mirror_data.vert_map) {
+ tc->data_mirror_len = mirror_data.mirror_elem_len;
+ tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror),
+ __func__);
+
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (mirror_data.vert_map[a].index != -1) {
+ data_len--;
+ }
+ }
+ }
+ }
+ }
+
+ /* Detect CrazySpace [tm]. */
+ transform_convert_mesh_crazyspace_detect(t, tc, em, &crazyspace_data);
+
+ /* Create TransData. */
+ BLI_assert(data_len >= 1);
+ tc->data_len = data_len;
+ tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
+
+ TransData *td = tc->data;
+ TransDataMirror *td_mirror = tc->data_mirror;
+ BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
+ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ continue;
+ }
+
+ int island_index = -1;
+ if (island_data.island_vert_map) {
+ const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
+ island_index = island_data.island_vert_map[connected_index];
+ }
+
+ float *weight = BM_ELEM_CD_GET_VOID_P(eve, cd_offset);
+ if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) {
+ tc_mesh_cdata_transdata_create(
+ (TransDataBasic *)td_mirror, eve, weight, &island_data, island_index);
+
+ int elem_index = mirror_data.vert_map[a].index;
+ BMVert *v_src = BM_vert_at_index(bm, elem_index);
+
+ td_mirror->flag |= mirror_data.vert_map[a].flag;
+ td_mirror->loc_src = BM_ELEM_CD_GET_VOID_P(v_src, cd_offset);
+ td_mirror++;
+ }
+ else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ tc_mesh_cdata_transdata_create(
+ (TransDataBasic *)td, eve, weight, &island_data, island_index);
+
+ if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
+ createSpaceNormal(td->axismtx, eve->no);
+ }
+ else {
+ /* Setting normals */
+ copy_v3_v3(td->axismtx[2], eve->no);
+ td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] =
+ td->axismtx[1][1] = td->axismtx[1][2] = 0.0f;
+ }
+
+ if (prop_mode) {
+ if (prop_mode & T_PROP_CONNECTED) {
+ td->dist = dists[a];
+ }
+ else {
+ td->flag |= TD_NOTCONNECTED;
+ td->dist = FLT_MAX;
+ }
+ }
+
+ /* CrazySpace */
+ transform_convert_mesh_crazyspace_transdata_set(
+ mtx,
+ smtx,
+ crazyspace_data.defmats ? crazyspace_data.defmats[a] : NULL,
+ crazyspace_data.quats && BM_elem_flag_test(eve, BM_ELEM_TAG) ?
+ crazyspace_data.quats[a] :
+ NULL,
+ td);
+
+ td++;
+ }
+ }
+
+ transform_convert_mesh_islanddata_free(&island_data);
+ transform_convert_mesh_mirrordata_free(&mirror_data);
+ transform_convert_mesh_crazyspace_free(&crazyspace_data);
+ if (dists) {
+ MEM_freeN(dists);
+ }
+ if (dists_index) {
+ MEM_freeN(dists_index);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalc Mesh Data
+ * \{ */
+
+static void tc_mesh_cdata_apply_to_mirror(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (tc->use_mirror_axis_any) {
+ TransDataMirror *td_mirror = tc->data_mirror;
+ for (int i = 0; i < tc->data_mirror_len; i++, td_mirror++) {
+ td_mirror->loc[0] = td_mirror->loc_src[0];
+ }
+ }
+ }
+}
+
+void recalcData_mesh_cdata(TransInfo *t)
+{
+ bool is_canceling = t->state == TRANS_CANCEL;
+ /* mirror modifier clipping? */
+ if (!is_canceling) {
+ if (!(t->flag & T_NO_MIRROR)) {
+ tc_mesh_cdata_apply_to_mirror(t);
+ }
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BKE_editmesh_looptri_and_normals_calc(em);
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index 685c35489de..32f70fc010b 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -26,12 +26,9 @@
#include "RNA_prototypes.h"
#include "transform.h"
-#include "transform_snap.h"
-
#include "transform_convert.h"
-#include "transform_snap.h"
-
#include "transform_mode.h"
+#include "transform_snap.h"
/** Used for NLA transform (stored in #TransData.extra pointer). */
typedef struct TransDataNla {
@@ -85,12 +82,13 @@ void createTransNlaData(bContext *C, TransInfo *t)
snla = (SpaceNla *)ac.sl;
/* filter data */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT |
+ ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -111,10 +109,10 @@ void createTransNlaData(bContext *C, TransInfo *t)
/* transition strips can't get directly transformed */
if (strip->type != NLASTRIP_TYPE_TRANSITION) {
if (strip->flag & NLASTRIP_FLAG_SELECT) {
- if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
+ if (FrameOnMouseSide(t->frame_side, strip->start, (float)scene->r.cfra)) {
count++;
}
- if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
+ if (FrameOnMouseSide(t->frame_side, strip->end, (float)scene->r.cfra)) {
count++;
}
}
@@ -125,7 +123,7 @@ void createTransNlaData(bContext *C, TransInfo *t)
/* stop if trying to build list if nothing selected */
if (count == 0) {
/* clear temp metas that may have been created but aren't needed now
- * because they fell on the wrong side of CFRA
+ * because they fell on the wrong side of scene->r.cfra
*/
for (ale = anim_data.first; ale; ale = ale->next) {
NlaTrack *nlt = (NlaTrack *)ale->data;
@@ -184,12 +182,12 @@ void createTransNlaData(bContext *C, TransInfo *t)
tdn->h2[0] = strip->end;
tdn->h2[1] = yval;
- center[0] = (float)CFRA;
+ center[0] = (float)scene->r.cfra;
center[1] = yval;
center[2] = 0.0f;
/* set td's based on which handles are applicable */
- if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
+ if (FrameOnMouseSide(t->frame_side, strip->start, (float)scene->r.cfra)) {
/* just set tdn to assume that it only has one handle for now */
tdn->handle = -1;
@@ -209,7 +207,7 @@ void createTransNlaData(bContext *C, TransInfo *t)
td->extra = tdn;
td++;
}
- if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
+ if (FrameOnMouseSide(t->frame_side, strip->end, (float)scene->r.cfra)) {
/* if tdn is already holding the start handle,
* then we're doing both, otherwise, only end */
tdn->handle = (tdn->handle) ? 2 : 1;
@@ -478,7 +476,7 @@ void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t))
if (ac.datatype) {
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
- short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
+ short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY);
/* get channels to work on */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index d2585493679..26d57ae1e58 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -732,8 +732,8 @@ static void autokeyframe_object(
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
ListBase dsources = {NULL, NULL};
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
- (float)CFRA);
+ const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
+ depsgraph, (float)scene->r.cfra);
eInsertKeyFlags flag = 0;
/* Get flags used for inserting keyframes. */
@@ -865,7 +865,7 @@ void recalcData_objects(TransInfo *t)
bool motionpath_update = false;
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -884,7 +884,7 @@ void recalcData_objects(TransInfo *t)
/* TODO: autokeyframe calls need some setting to specify to add samples
* (FPoints) instead of keyframes? */
if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
- animrecord_check_state(t, ob);
+ animrecord_check_state(t, &ob->id);
autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
}
diff --git a/source/blender/editors/transform/transform_convert_object_texspace.c b/source/blender/editors/transform/transform_convert_object_texspace.c
index 1f58ec80f02..e5a66f8a1d2 100644
--- a/source/blender/editors/transform/transform_convert_object_texspace.c
+++ b/source/blender/editors/transform/transform_convert_object_texspace.c
@@ -90,7 +90,7 @@ void recalcData_texspace(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
index d7b0f378c8a..31e73288ad0 100644
--- a/source/blender/editors/transform/transform_convert_particle.c
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -238,7 +238,7 @@ static void flushTransParticles(TransInfo *t)
void recalcData_particles(TransInfo *t)
{
if (t->state != TRANS_CANCEL) {
- applyProject(t);
+ applySnappingIndividual(t);
}
flushTransParticles(t);
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 3735ff0727c..dcc1739606f 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -90,9 +90,9 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_count, int *r_flag)
if (t->mode == TFM_TIME_EXTEND) {
/* *** Extend Transform *** */
- int cfra = CFRA;
- int left = SEQ_time_left_handle_frame_get(seq);
- int right = SEQ_time_right_handle_frame_get(seq);
+ int cfra = scene->r.cfra;
+ int left = SEQ_time_left_handle_frame_get(scene, seq);
+ int right = SEQ_time_right_handle_frame_get(scene, seq);
if (((seq->flag & SELECT) == 0 || SEQ_transform_is_locked(channels, seq))) {
*r_count = 0;
@@ -163,8 +163,13 @@ static int SeqTransCount(TransInfo *t, ListBase *seqbase)
return tot;
}
-static TransData *SeqToTransData(
- TransData *td, TransData2D *td2d, TransDataSeq *tdsq, Sequence *seq, int flag, int sel_flag)
+static TransData *SeqToTransData(Scene *scene,
+ TransData *td,
+ TransData2D *td2d,
+ TransDataSeq *tdsq,
+ Sequence *seq,
+ int flag,
+ int sel_flag)
{
int start_left;
@@ -173,16 +178,16 @@ static TransData *SeqToTransData(
/* Use seq_tx_get_final_left() and an offset here
* so transform has the left hand location of the strip.
* tdsq->start_offset is used when flushing the tx data back */
- start_left = SEQ_time_left_handle_frame_get(seq);
+ start_left = SEQ_time_left_handle_frame_get(scene, seq);
td2d->loc[0] = start_left;
tdsq->start_offset = start_left - seq->start; /* use to apply the original location */
break;
case SEQ_LEFTSEL:
- start_left = SEQ_time_left_handle_frame_get(seq);
+ start_left = SEQ_time_left_handle_frame_get(scene, seq);
td2d->loc[0] = start_left;
break;
case SEQ_RIGHTSEL:
- td2d->loc[0] = SEQ_time_right_handle_frame_get(seq);
+ td2d->loc[0] = SEQ_time_right_handle_frame_get(scene, seq);
break;
}
@@ -227,6 +232,7 @@ static int SeqToTransData_build(
TransInfo *t, ListBase *seqbase, TransData *td, TransData2D *td2d, TransDataSeq *tdsq)
{
Sequence *seq;
+ Scene *scene = t->scene;
int count, flag;
int tot = 0;
@@ -238,16 +244,16 @@ static int SeqToTransData_build(
if (flag & SELECT) {
if (flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
if (flag & SEQ_LEFTSEL) {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
+ SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SEQ_LEFTSEL);
tot++;
}
if (flag & SEQ_RIGHTSEL) {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
+ SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SEQ_RIGHTSEL);
tot++;
}
}
else {
- SeqToTransData(td++, td2d++, tdsq++, seq, flag, SELECT);
+ SeqToTransData(scene, td++, td2d++, tdsq++, seq, flag, SELECT);
tot++;
}
}
@@ -275,322 +281,27 @@ static void seq_transform_cancel(TransInfo *t, SeqCollection *transformed_strips
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
/* Handle pre-existing overlapping strips even when operator is canceled.
* This is necessary for SEQUENCER_OT_duplicate_move macro for example. */
- if (SEQ_transform_test_overlap(seqbase, seq)) {
+ if (SEQ_transform_test_overlap(t->scene, seqbase, seq)) {
SEQ_transform_seqbase_shuffle(seqbase, seq, t->scene);
}
-
- SEQ_time_update_sequence(t->scene, seqbase, seq);
}
}
-static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
-{
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if (seq->flag & SEQ_OVERLAP) {
- return true;
- }
- }
- return false;
-}
-
-static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
-{
- SeqCollection *collection = SEQ_collection_create(__func__);
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
-/* 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;
- {
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- minframe = min_ii(minframe, seq->startdisp);
- }
- }
-
- SeqCollection *collection = SEQ_collection_create(__func__);
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if ((seq->flag & SELECT) == 0 && seq->startdisp >= minframe) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
-static void seq_transform_update_effects(Scene *scene,
- ListBase *seqbasep,
- 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(scene, seqbasep, seq);
- }
- }
-}
-
-/* Check if effect strips with input are transformed. */
-static bool seq_transform_check_strip_effects(SeqCollection *transformed_strips)
-{
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) {
- return true;
- }
- }
- return false;
-}
-
static ListBase *seqbase_active_get(const TransInfo *t)
{
Editing *ed = SEQ_editing_get(t->scene);
return SEQ_active_seqbase_get(ed);
}
-/* 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(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
-{
- ListBase *markers = &scene->markers;
-
- SeqCollection *right_side_strips = query_right_side_strips(seqbasep, transformed_strips);
-
- /* Temporarily move right side strips beyond timeline boundary. */
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
- seq->machine += MAXSEQ * 2;
- }
-
- /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
- * strips on left side. */
- SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
- SEQ_transform_seqbase_shuffle_time(
- standalone_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(standalone_strips);
-
- /* Move temporarily moved strips back to their original place and tag for shuffling. */
- SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
- seq->machine -= MAXSEQ * 2;
- }
- /* Shuffle again to displace strips on right side. Final effect shuffling is done in
- * SEQ_transform_handle_overlap. */
- SEQ_transform_seqbase_shuffle_time(
- right_side_strips, seqbasep, scene, markers, use_sync_markers);
- seq_transform_update_effects(scene, seqbasep, right_side_strips);
- SEQ_collection_free(right_side_strips);
-}
-
-static SeqCollection *query_overwrite_targets(ListBase *seqbasep,
- SeqCollection *transformed_strips)
-{
- SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
-
- Sequence *seq, *seq_transformed;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- bool does_overlap = false;
-
- SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
- /* Effects of transformed strips can be unselected. These must not be included. */
- if (seq == seq_transformed) {
- SEQ_collection_remove_strip(seq, collection);
- }
- if (SEQ_transform_test_overlap_seq_seq(seq, seq_transformed)) {
- does_overlap = true;
- }
- }
-
- if (!does_overlap) {
- SEQ_collection_remove_strip(seq, collection);
- }
- }
-
- return collection;
-}
-
-typedef enum eOvelapDescrition {
- /* No overlap. */
- STRIP_OVERLAP_NONE,
- /* Overlapping strip covers overlapped completely. */
- STRIP_OVERLAP_IS_FULL,
- /* Overlapping strip is inside overlapped. */
- STRIP_OVERLAP_IS_INSIDE,
- /* Partial overlap between 2 strips. */
- STRIP_OVERLAP_LEFT_SIDE,
- STRIP_OVERLAP_RIGHT_SIDE,
-} eOvelapDescrition;
-
-static eOvelapDescrition overlap_description_get(const Sequence *transformed,
- const Sequence *target)
-{
- if (transformed->startdisp <= target->startdisp && transformed->enddisp >= target->enddisp) {
- return STRIP_OVERLAP_IS_FULL;
- }
- if (transformed->startdisp > target->startdisp && transformed->enddisp < target->enddisp) {
- return STRIP_OVERLAP_IS_INSIDE;
- }
- if (transformed->startdisp <= target->startdisp && target->startdisp <= transformed->enddisp) {
- return STRIP_OVERLAP_LEFT_SIDE;
- }
- if (transformed->startdisp <= target->enddisp && target->enddisp <= transformed->enddisp) {
- return STRIP_OVERLAP_RIGHT_SIDE;
- }
- return STRIP_OVERLAP_NONE;
-}
-
-/* Split strip in 3 parts, remove middle part and fit transformed inside. */
-static void seq_transform_handle_overwrite_split(Scene *scene,
- ListBase *seqbasep,
- const Sequence *transformed,
- Sequence *target)
-{
- /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
- * NULL here. */
- Main *bmain = NULL;
-
- Sequence *split_strip = SEQ_edit_strip_split(
- bmain, scene, seqbasep, target, transformed->startdisp, SEQ_SPLIT_SOFT, NULL);
- SEQ_edit_strip_split(
- bmain, scene, seqbasep, split_strip, transformed->enddisp, SEQ_SPLIT_SOFT, NULL);
- SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
- SEQ_edit_remove_flagged_sequences(scene, seqbasep);
-}
-
-/* Trim strips by adjusting handle position.
- * This is bit more complicated in case overlap happens on effect. */
-static void seq_transform_handle_overwrite_trim(Scene *scene,
- ListBase *seqbasep,
- const Sequence *transformed,
- Sequence *target,
- const eOvelapDescrition overlap)
-{
- SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain);
-
- /* Expand collection by adding all target's children, effects and their children. */
- if ((target->type & SEQ_TYPE_EFFECT) != 0) {
- SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain);
- }
-
- /* Trim all non effects, that have influence on effect length which is overlapping. */
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, targets) {
- if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
- continue;
- }
- if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
- SEQ_time_left_handle_frame_set(seq, transformed->enddisp);
- }
- else {
- BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
- SEQ_time_right_handle_frame_set(seq, transformed->startdisp);
- }
-
- SEQ_time_update_sequence(scene, seqbasep, seq);
- }
- SEQ_collection_free(targets);
-}
-
-static void seq_transform_handle_overwrite(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips)
-{
- SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips);
- SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
-
- Sequence *target;
- Sequence *transformed;
- SEQ_ITERATOR_FOREACH (target, targets) {
- SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
- if (transformed->machine != target->machine) {
- continue;
- }
-
- const eOvelapDescrition overlap = overlap_description_get(transformed, target);
-
- if (overlap == STRIP_OVERLAP_IS_FULL) {
- SEQ_collection_append_strip(target, strips_to_delete);
- }
- else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
- seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
- }
- else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
- seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
- }
- }
- }
-
- SEQ_collection_free(targets);
-
- /* 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(scene, seqbasep, seq);
- }
- SEQ_edit_remove_flagged_sequences(scene, seqbasep);
- }
- SEQ_collection_free(strips_to_delete);
-}
-
-static void seq_transform_handle_overlap_shuffle(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
-{
- ListBase *markers = &scene->markers;
-
- /* Shuffle non strips with no effects attached. */
- SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
- SEQ_transform_seqbase_shuffle_time(
- standalone_strips, seqbasep, scene, markers, use_sync_markers);
- SEQ_collection_free(standalone_strips);
-}
-
-void SEQ_transform_handle_overlap(Scene *scene,
- ListBase *seqbasep,
- SeqCollection *transformed_strips,
- bool use_sync_markers)
+static bool seq_transform_check_overlap(SeqCollection *transformed_strips)
{
- const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
-
- switch (overlap_mode) {
- case SEQ_OVERLAP_EXPAND:
- seq_transform_handle_expand_to_fit(scene, seqbasep, transformed_strips, use_sync_markers);
- break;
- case SEQ_OVERLAP_OVERWRITE:
- seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
- break;
- case SEQ_OVERLAP_SHUFFLE:
- seq_transform_handle_overlap_shuffle(scene, seqbasep, transformed_strips, use_sync_markers);
- break;
- }
-
- if (seq_transform_check_strip_effects(transformed_strips)) {
- /* Update effect strips based on strips just moved in time. */
- seq_transform_update_effects(scene, seqbasep, transformed_strips);
- }
-
- /* If any effects still overlap, we need to move them up.
- * In some cases other strips can be overlapping still, see T90646. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
- if (SEQ_transform_test_overlap(seqbasep, seq)) {
- SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ if (seq->flag & SEQ_OVERLAP) {
+ return true;
}
- seq->flag &= ~SEQ_OVERLAP;
}
+ return false;
}
static SeqCollection *seq_transform_collection_from_transdata(TransDataContainer *tc)
@@ -613,7 +324,8 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
}
SeqCollection *transformed_strips = seq_transform_collection_from_transdata(tc);
- SEQ_collection_expand(seqbase_active_get(t), transformed_strips, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(
+ t->scene, seqbase_active_get(t), transformed_strips, SEQ_query_strip_effect_chain);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
@@ -627,18 +339,17 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
return;
}
+ TransSeq *ts = tc->custom.type.data;
ListBase *seqbasep = seqbase_active_get(t);
Scene *scene = t->scene;
const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
if (seq_transform_check_overlap(transformed_strips)) {
- SEQ_transform_handle_overlap(scene, seqbasep, transformed_strips, use_sync_markers);
+ SEQ_transform_handle_overlap(
+ scene, seqbasep, transformed_strips, ts->time_dependent_strips, use_sync_markers);
}
- seq_transform_update_effects(scene, seqbasep, transformed_strips);
SEQ_collection_free(transformed_strips);
-
- SEQ_sort(ed->seqbasep);
DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
free_transform_custom_data(custom_data);
}
@@ -659,21 +370,24 @@ typedef enum SeqInputSide {
SEQ_INPUT_RIGHT = 1,
} SeqInputSide;
-static Sequence *effect_input_get(Sequence *effect, SeqInputSide side)
+static Sequence *effect_input_get(const Scene *scene, Sequence *effect, SeqInputSide side)
{
Sequence *input = effect->seq1;
- if (effect->seq2 && (effect->seq2->startdisp - effect->seq1->startdisp) * side > 0) {
+ if (effect->seq2 && (SEQ_time_left_handle_frame_get(scene, effect->seq2) -
+ SEQ_time_left_handle_frame_get(scene, effect->seq1)) *
+ side >
+ 0) {
input = effect->seq2;
}
return input;
}
-static Sequence *effect_base_input_get(Sequence *effect, SeqInputSide side)
+static Sequence *effect_base_input_get(const Scene *scene, Sequence *effect, SeqInputSide side)
{
Sequence *input = effect, *seq_iter = effect;
while (seq_iter != NULL) {
input = seq_iter;
- seq_iter = effect_input_get(seq_iter, side);
+ seq_iter = effect_input_get(scene, seq_iter, side);
}
return input;
}
@@ -693,7 +407,7 @@ static SeqCollection *query_time_dependent_strips_strips(TransInfo *t)
SeqCollection *strips_no_handles = query_selected_strips_no_handles(seqbase);
/* Selection is needed as reference for related strips. */
SeqCollection *dependent = SEQ_collection_duplicate(strips_no_handles);
- SEQ_collection_expand(seqbase, strips_no_handles, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(t->scene, seqbase, strips_no_handles, SEQ_query_strip_effect_chain);
bool strip_added = true;
while (strip_added) {
@@ -723,7 +437,7 @@ static SeqCollection *query_time_dependent_strips_strips(TransInfo *t)
* With single input effect, it is less likely desirable to move animation. */
SeqCollection *selected_strips = SEQ_query_selected_strips(seqbase);
- SEQ_collection_expand(seqbase, selected_strips, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(t->scene, seqbase, selected_strips, SEQ_query_strip_effect_chain);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, selected_strips) {
/* Check only 2 input effects. */
@@ -732,8 +446,8 @@ static SeqCollection *query_time_dependent_strips_strips(TransInfo *t)
}
/* Find immediate base inputs(left and right side). */
- Sequence *input_left = effect_base_input_get(seq, SEQ_INPUT_LEFT);
- Sequence *input_right = effect_base_input_get(seq, SEQ_INPUT_RIGHT);
+ Sequence *input_left = effect_base_input_get(t->scene, seq, SEQ_INPUT_LEFT);
+ Sequence *input_right = effect_base_input_get(t->scene, seq, SEQ_INPUT_RIGHT);
if ((input_left->flag & SEQ_RIGHTSEL) != 0 && (input_right->flag & SEQ_LEFTSEL) != 0) {
SEQ_collection_append_strip(seq, dependent);
@@ -775,7 +489,7 @@ void createTransSeqData(TransInfo *t)
}
tc->custom.type.free_cb = freeSeqData;
- t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)scene->r.cfra);
count = SeqTransCount(t, ed->seqbasep);
@@ -825,23 +539,6 @@ void createTransSeqData(TransInfo *t)
/** \name UVs Transform Flush
* \{ */
-/* commented _only_ because the meta may have animation data which
- * needs moving too T28158. */
-
-BLI_INLINE void trans_update_seq(Scene *sce, Sequence *seq, int old_start, int sel_flag)
-{
- /* Calculate this strip and all nested strips.
- * Children are ALWAYS transformed first so we don't need to do this in another loop.
- */
-
- 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);
- }
-}
-
static void view2d_edge_pan_loc_compensate(TransInfo *t, float loc_in[2], float r_loc[2])
{
TransSeq *ts = (TransSeq *)TRANS_DATA_CONTAINER_FIRST_SINGLE(t)->custom.type.data;
@@ -881,6 +578,8 @@ static void flushTransSeq(TransInfo *t)
TransDataSeq *tdsq = NULL;
Sequence *seq;
+ Scene *scene = t->scene;
+
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* This is calculated for offsetting animation of effects that change position with inputs.
@@ -904,7 +603,7 @@ static void flushTransSeq(TransInfo *t)
case SELECT: {
if (SEQ_transform_sequence_can_be_translated(seq)) {
offset = new_frame - tdsq->start_offset - seq->start;
- SEQ_transform_translate_sequence(t->scene, seq, offset);
+ SEQ_transform_translate_sequence(scene, seq, offset);
if (abs(offset) > abs(max_offset)) {
max_offset = offset;
}
@@ -914,24 +613,22 @@ static void flushTransSeq(TransInfo *t)
break;
}
case SEQ_LEFTSEL: { /* No vertical transform. */
- int old_startdisp = seq->startdisp;
- SEQ_time_left_handle_frame_set(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, seqbasep, seq);
- if (abs(seq->startdisp - old_startdisp) > abs(max_offset)) {
- max_offset = seq->startdisp - old_startdisp;
+ int old_startdisp = SEQ_time_left_handle_frame_get(scene, seq);
+ SEQ_time_left_handle_frame_set(t->scene, seq, new_frame);
+ SEQ_transform_fix_single_image_seq_offsets(t->scene, seq);
+
+ if (abs(SEQ_time_left_handle_frame_get(scene, seq) - old_startdisp) > abs(max_offset)) {
+ max_offset = SEQ_time_left_handle_frame_get(scene, seq) - old_startdisp;
}
break;
}
case SEQ_RIGHTSEL: { /* No vertical transform. */
- int old_enddisp = seq->enddisp;
- SEQ_time_right_handle_frame_set(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, seqbasep, seq);
- if (abs(seq->enddisp - old_enddisp) > abs(max_offset)) {
- max_offset = seq->enddisp - old_enddisp;
+ int old_enddisp = SEQ_time_right_handle_frame_get(scene, seq);
+ SEQ_time_right_handle_frame_set(t->scene, seq, new_frame);
+ SEQ_transform_fix_single_image_seq_offsets(t->scene, seq);
+
+ if (abs(SEQ_time_right_handle_frame_get(scene, seq) - old_enddisp) > abs(max_offset)) {
+ max_offset = SEQ_time_right_handle_frame_get(scene, seq) - old_enddisp;
}
break;
}
@@ -945,24 +642,16 @@ static void flushTransSeq(TransInfo *t)
SEQ_offset_animdata(t->scene, seq, max_offset);
}
- /* Update effect length and position. */
- 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, seqbasep, seq);
- }
- }
- }
-
/* need to do the overlap check in a new loop otherwise adjacent strips
* will not be updated and we'll get false positives */
SeqCollection *transformed_strips = seq_transform_collection_from_transdata(tc);
- SEQ_collection_expand(seqbase_active_get(t), transformed_strips, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(
+ t->scene, seqbase_active_get(t), transformed_strips, SEQ_query_strip_effect_chain);
SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
/* test overlap, displays red outline */
seq->flag &= ~SEQ_OVERLAP;
- if (SEQ_transform_test_overlap(seqbasep, seq)) {
+ if (SEQ_transform_test_overlap(scene, seqbasep, seq)) {
seq->flag |= SEQ_OVERLAP;
}
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index deae51a1149..8be454b540c 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -123,7 +123,8 @@ void createTransSeqImageData(TransInfo *t)
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, t->scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(
+ t->scene, channels, seqbase, t->scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
const int count = SEQ_collection_len(strips);
@@ -154,6 +155,42 @@ void createTransSeqImageData(TransInfo *t)
SEQ_collection_free(strips);
}
+static bool autokeyframe_sequencer_image(bContext *C,
+ Scene *scene,
+ StripTransform *transform,
+ const int tmode)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
+
+ const bool around_cursor = scene->toolsettings->sequencer_tool_settings->pivot_point ==
+ V3D_AROUND_CURSOR;
+ const bool do_loc = tmode == TFM_TRANSLATION || around_cursor;
+ const bool do_rot = tmode == TFM_ROTATION;
+ const bool do_scale = tmode == TFM_RESIZE;
+
+ bool changed = false;
+ if (do_rot) {
+ prop = RNA_struct_find_property(&ptr, "rotation");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
+ }
+ if (do_loc) {
+ prop = RNA_struct_find_property(&ptr, "offset_x");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
+ prop = RNA_struct_find_property(&ptr, "offset_y");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
+ }
+ if (do_scale) {
+ prop = RNA_struct_find_property(&ptr, "scale_x");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
+ prop = RNA_struct_find_property(&ptr, "scale_y");
+ changed |= ED_autokeyframe_property(C, scene, &ptr, prop, -1, scene->r.cfra, false);
+ }
+
+ return changed;
+}
+
void recalcData_sequencer_image(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -187,6 +224,7 @@ void recalcData_sequencer_image(TransInfo *t)
copy_v2_v2(translation, tdseq->orig_origin_position);
sub_v2_v2(translation, origin);
mul_v2_v2(translation, mirror);
+ translation[0] *= t->scene->r.yasp / t->scene->r.xasp;
transform->xofs = tdseq->orig_translation[0] - translation[0];
transform->yofs = tdseq->orig_translation[1] - translation[1];
@@ -199,6 +237,12 @@ void recalcData_sequencer_image(TransInfo *t)
if (t->mode == TFM_ROTATION) {
transform->rotation = tdseq->orig_rotation - t->values_final[0];
}
+
+ if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
+ animrecord_check_state(t, &t->scene->id);
+ autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
+ }
+
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
}
}
@@ -211,9 +255,6 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *
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;
@@ -225,24 +266,8 @@ void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *
continue;
}
- 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);
+ if (IS_AUTOKEY_ON(t->scene)) {
+ autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
}
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 975dbc2e986..e45cac36736 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -358,6 +358,10 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_SEQ && region->regiontype == RGN_TYPE_PREVIEW) {
t->options |= CTX_SEQUENCER_IMAGE;
+
+ /* Needed for autokeying transforms in preview during playback. */
+ bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
+ t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
}
setTransformViewAspect(t, t->aspect);
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 838b40c2040..426b338f8a7 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -247,7 +247,7 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
int selected_strips = SEQ_collection_len(strips);
if (selected_strips > 0) {
@@ -299,7 +299,7 @@ static int gizmo2d_calc_transform_orientation(const bContext *C)
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
bool use_local_orient = SEQ_collection_len(strips) == 1;
@@ -322,7 +322,7 @@ static float gizmo2d_calc_rotation(const bContext *C)
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
if (SEQ_collection_len(strips) == 1) {
@@ -348,7 +348,7 @@ static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
bool has_select = SEQ_collection_len(strips) != 0;
@@ -387,7 +387,8 @@ static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
Editing *ed = SEQ_editing_get(scene);
ListBase *seqbase = SEQ_active_seqbase_get(ed);
ListBase *channels = SEQ_channels_displayed_get(ed);
- SeqCollection *strips = SEQ_query_rendered_strips(channels, seqbase, scene->r.cfra, 0);
+ SeqCollection *strips = SEQ_query_rendered_strips(
+ scene, channels, seqbase, scene->r.cfra, 0);
SEQ_filter_selected_strips(strips);
has_select = SEQ_collection_len(strips) != 0;
SEQ_collection_free(strips);
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index aa8dad2b95f..5b749e05052 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -45,7 +45,6 @@
#include "WM_api.h"
#include "WM_message.h"
#include "WM_types.h"
-#include "wm.h"
#include "ED_armature.h"
#include "ED_gizmo_library.h"
@@ -71,6 +70,10 @@
#include "GPU_state.h"
+static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup,
+ const float twmat[4][4],
+ const float scale[3]);
+
/* return codes for select, and drawing flags */
#define MAN_TRANS_X (1 << 0)
@@ -155,6 +158,9 @@ typedef struct GizmoGroup {
float viewinv_m3[3][3];
} prev;
+ /* Only for Rotate operator. */
+ float rotation;
+
struct wmGizmo *gizmos[MAN_AXIS_LAST];
} GizmoGroup;
@@ -1269,103 +1275,31 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh);
}
-void drawDial3d(const TransInfo *t)
+static void gizmo_3d_dial_matrixbasis_calc(const ARegion *region,
+ float axis[3],
+ float center_global[3],
+ float mval_init[2],
+ float r_mat_basis[4][4])
{
- if (t->mode == TFM_ROTATION && t->spacetype == SPACE_VIEW3D) {
- if (t->options & CTX_PAINT_CURVE) {
- /* Matrices are in the screen space. Not supported. */
- return;
- }
-
- wmGizmo *gz = wm_gizmomap_modal_get(t->region->gizmo_map);
- if (gz == NULL) {
- /* We only draw Dial3d if the operator has been called by a gizmo. */
- return;
- }
-
- float mat_basis[4][4];
- float mat_final[4][4];
- float color[4];
- float increment = 0.0f;
- float line_with = GIZMO_AXIS_LINE_WIDTH + 1.0f;
- float scale = UI_DPI_FAC * U.gizmo_size;
-
- int axis_idx;
-
- const TransCon *tc = &(t->con);
- if (tc->mode & CON_APPLY) {
- if (tc->mode & CON_AXIS0) {
- axis_idx = MAN_AXIS_ROT_X;
- negate_v3_v3(mat_basis[2], t->spacemtx[0]);
- }
- else if (tc->mode & CON_AXIS1) {
- axis_idx = MAN_AXIS_ROT_Y;
- negate_v3_v3(mat_basis[2], t->spacemtx[1]);
- }
- else {
- BLI_assert((tc->mode & CON_AXIS2) != 0);
- axis_idx = MAN_AXIS_ROT_Z;
- negate_v3_v3(mat_basis[2], t->spacemtx[2]);
- }
- }
- else {
- axis_idx = MAN_AXIS_ROT_C;
- copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
- scale *= 1.2f;
- line_with -= 1.0f;
- }
-
- copy_v3_v3(mat_basis[3], t->center_global);
- mat_basis[2][3] = -dot_v3v3(mat_basis[2], mat_basis[3]);
-
- if (ED_view3d_win_to_3d_on_plane(
- t->region, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) {
- sub_v3_v3(mat_basis[1], mat_basis[3]);
- normalize_v3(mat_basis[1]);
- cross_v3_v3v3(mat_basis[0], mat_basis[1], mat_basis[2]);
- }
- else {
- /* The plane and the mouse direction are parallel.
- * Calculate a matrix orthogonal to the axis. */
- ortho_basis_v3v3_v3(mat_basis[0], mat_basis[1], mat_basis[2]);
- }
-
- mat_basis[0][3] = 0.0f;
- mat_basis[1][3] = 0.0f;
- mat_basis[2][3] = 0.0f;
- mat_basis[3][3] = 1.0f;
-
- copy_m4_m4(mat_final, mat_basis);
- scale *= ED_view3d_pixel_size_no_ui_scale(t->region->regiondata, mat_final[3]);
- mul_mat3_m4_fl(mat_final, scale);
+ copy_v3_v3(r_mat_basis[2], axis);
+ copy_v3_v3(r_mat_basis[3], center_global);
+ r_mat_basis[2][3] = -dot_v3v3(axis, center_global);
- if (activeSnap(t) && (!transformModeUseSnap(t) ||
- (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
- increment = (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
- }
-
- BLI_assert(axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END);
- gizmo_get_axis_color(axis_idx, NULL, color, color);
-
- GPU_depth_test(GPU_DEPTH_NONE);
- GPU_blend(GPU_BLEND_ALPHA);
- GPU_line_smooth(true);
-
- ED_gizmotypes_dial_3d_draw_util(mat_basis,
- mat_final,
- line_with,
- color,
- false,
- &(struct Dial3dParams){
- .draw_options = ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE,
- .angle_delta = t->values_final[0],
- .angle_increment = increment,
- });
-
- GPU_line_smooth(false);
- GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
- GPU_blend(GPU_BLEND_NONE);
+ if (ED_view3d_win_to_3d_on_plane(region, axis, mval_init, false, r_mat_basis[1])) {
+ sub_v3_v3(r_mat_basis[1], center_global);
+ normalize_v3(r_mat_basis[1]);
+ cross_v3_v3v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]);
+ }
+ else {
+ /* The plane and the mouse direction are parallel.
+ * Calculate a matrix orthogonal to the axis. */
+ ortho_basis_v3v3_v3(r_mat_basis[0], r_mat_basis[1], r_mat_basis[2]);
}
+
+ r_mat_basis[0][3] = 0.0f;
+ r_mat_basis[1][3] = 0.0f;
+ r_mat_basis[2][3] = 0.0f;
+ r_mat_basis[3][3] = 1.0f;
}
/** \} */
@@ -1374,6 +1308,23 @@ void drawDial3d(const TransInfo *t)
/** \name Transform Gizmo
* \{ */
+/** Scale of the two-axis planes. */
+#define MAN_AXIS_SCALE_PLANE_SCALE 0.07f
+/** Offset of the two-axis planes, depends on the gizmos scale. Define to avoid repeating. */
+#define MAN_AXIS_SCALE_PLANE_OFFSET 7.0f
+
+static void rotation_get_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value)
+{
+ const GizmoGroup *ggd = (const GizmoGroup *)gz_prop->custom_func.user_data;
+ *(float *)value = ggd->rotation;
+}
+
+static void rotation_set_fn(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value)
+{
+ GizmoGroup *ggd = (GizmoGroup *)gz_prop->custom_func.user_data;
+ ggd->rotation = *(const float *)value;
+}
+
static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd;
@@ -1384,6 +1335,9 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
const wmGizmoType *gzt_dial = WM_gizmotype_find("GIZMO_GT_dial_3d", true);
const wmGizmoType *gzt_prim = WM_gizmotype_find("GIZMO_GT_primitive_3d", true);
+ wmGizmoPropertyFnParams params = {
+ .value_get_fn = rotation_get_fn, .value_set_fn = rotation_set_fn, .user_data = ggd};
+
#define GIZMO_NEW_ARROW(v, draw_style) \
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL); \
@@ -1394,6 +1348,7 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup)
{ \
ggd->gizmos[v] = WM_gizmo_new_ptr(gzt_dial, gzgroup, NULL); \
RNA_enum_set(ggd->gizmos[v]->ptr, "draw_options", draw_options); \
+ WM_gizmo_target_property_def_func(ggd->gizmos[v], "offset", &params); \
} \
((void)0)
#define GIZMO_NEW_PRIM(v, draw_style) \
@@ -1461,18 +1416,104 @@ static int gizmo_modal(bContext *C,
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
- struct TransformBounds tbounds;
-
- if (ED_transform_calc_gizmo_stats(C,
- &(struct TransformCalcParams){
- .use_only_center = true,
- },
- &tbounds)) {
- gizmo_prepare_mat(C, rv3d, &tbounds);
- WM_gizmo_set_matrix_location(widget, rv3d->twmat[3]);
+ wmGizmoGroup *gzgroup = widget->parent_gzgroup;
+
+ /* Recalculating the orientation has two problems.
+ * - The matrix calculated based on the transformed selection may not match the matrix
+ * that was set when transform started.
+ * - Inspecting the selection for every update is expensive (for *every* redraw).
+ *
+ * Instead, use #transform_apply_matrix to transform `rv3d->twmat` or the final scale value
+ * when scaling.
+ */
+ if (false) {
+ struct TransformBounds tbounds;
+
+ if (ED_transform_calc_gizmo_stats(C,
+ &(struct TransformCalcParams){
+ .use_only_center = true,
+ },
+ &tbounds)) {
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+ for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ WM_gizmo_set_matrix_location(gz, rv3d->twmat[3]);
+ }
+ }
}
+ else {
+ GizmoGroup *ggd = gzgroup->customdata;
+
+ short axis_type = 0;
+ MAN_ITER_AXES_BEGIN (axis, axis_idx) {
+ if (axis == widget) {
+ axis_type = gizmo_get_axis_type(axis_idx);
+ break;
+ }
+ }
+ MAN_ITER_AXES_END;
+
+ /* Showing axes which aren't being manipulated doesn't always work so well.
+ *
+ * For rotate: global axis will reset after finish.
+ * Also, gimbal axis isn't properly recalculated while transforming.
+ */
+ if (axis_type == MAN_AXES_ROTATE) {
+ MAN_ITER_AXES_BEGIN (axis, axis_idx) {
+ if (axis == widget) {
+ continue;
+ }
+
+ bool is_plane_dummy;
+ const uint aidx_norm = gizmo_orientation_axis(axis_idx, &is_plane_dummy);
+ /* Always show the axis-aligned handle as it's distracting when it's disabled. */
+ if (aidx_norm == 3) {
+ continue;
+ }
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
+ MAN_ITER_AXES_END;
+ }
- ED_region_tag_redraw_editor_overlays(region);
+ wmWindow *win = CTX_wm_window(C);
+ wmOperator *op = NULL;
+ for (int i = 0; i < widget->op_data_len; i++) {
+ wmGizmoOpElem *gzop = WM_gizmo_operator_get(widget, i);
+ op = WM_operator_find_modal_by_type(win, gzop->type);
+ if (op != NULL) {
+ break;
+ }
+ }
+
+ if (op != NULL) {
+ float twmat[4][4];
+ float scale_buf[3];
+ float *scale = NULL;
+ bool update = false;
+ copy_m4_m4(twmat, rv3d->twmat);
+
+ if (axis_type == MAN_AXES_SCALE) {
+ scale = scale_buf;
+ transform_final_value_get(op->customdata, scale, 3);
+ update = true;
+ }
+ else if (axis_type == MAN_AXES_ROTATE) {
+ transform_final_value_get(op->customdata, &ggd->rotation, 1);
+ if (widget != ggd->gizmos[MAN_AXIS_ROT_C]) {
+ ggd->rotation *= -1;
+ }
+ RNA_float_set(
+ widget->ptr, "incremental_angle", transform_snap_increment_get(op->customdata));
+ }
+ else if (transform_apply_matrix(op->customdata, twmat)) {
+ update = true;
+ }
+
+ if (update) {
+ gizmo_refresh_from_matrix(gzgroup, twmat, scale);
+ ED_region_tag_redraw_editor_overlays(region);
+ }
+ }
+ }
return OPERATOR_RUNNING_MODAL;
}
@@ -1524,9 +1565,8 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup)
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
- const float ofs_ax = 7.0f;
- const float ofs[3] = {ofs_ax, ofs_ax, 0.0f};
- WM_gizmo_set_scale(axis, 0.07f);
+ const float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
+ WM_gizmo_set_scale(axis, MAN_AXIS_SCALE_PLANE_SCALE);
WM_gizmo_set_matrix_offset_location(axis, ofs);
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
break;
@@ -1638,46 +1678,23 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
gizmogroup_init_properties_from_twtype(gzgroup);
}
-static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+/**
+ * Set properties for axes.
+ *
+ * \param twmat: The transform matrix (typically #RegionView3D.twmat).
+ * \param scale: Optional scale, to show scale while modally dragging the scale handles.
+ */
+static void gizmo_refresh_from_matrix(wmGizmoGroup *gzgroup,
+ const float twmat[4][4],
+ const float scale[3])
{
GizmoGroup *ggd = gzgroup->customdata;
- Scene *scene = CTX_data_scene(C);
- ScrArea *area = CTX_wm_area(C);
- View3D *v3d = area->spacedata.first;
- ARegion *region = CTX_wm_region(C);
- RegionView3D *rv3d = region->regiondata;
- struct TransformBounds tbounds;
-
- if (ggd->use_twtype_refresh) {
- ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
- if (ggd->twtype != ggd->twtype_prev) {
- ggd->twtype_prev = ggd->twtype;
- gizmogroup_init_properties_from_twtype(gzgroup);
- }
- }
-
- const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init);
-
- /* skip, we don't draw anything anyway */
- if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C,
- &(struct TransformCalcParams){
- .use_only_center = true,
- .orientation_index = orient_index + 1,
- },
- &tbounds) == 0))) {
- return;
- }
-
- gizmo_prepare_mat(C, rv3d, &tbounds);
-
- /* *** set properties for axes *** */
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
const int aidx_norm = gizmo_orientation_axis(axis_idx, NULL);
- WM_gizmo_set_matrix_location(axis, rv3d->twmat[3]);
-
+ WM_gizmo_set_matrix_location(axis, twmat[3]);
switch (axis_idx) {
case MAN_AXIS_TRANS_X:
case MAN_AXIS_TRANS_Y:
@@ -1690,8 +1707,17 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
gizmo_line_range(ggd->twtype, axis_type, &start_co[2], &len);
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
- RNA_float_set(axis->ptr, "length", len);
+ const float *z_axis = twmat[aidx_norm];
+ if (axis_type == MAN_AXES_SCALE) {
+ /* Scale handles are cubes that don't look right when not aligned with other axes.
+ * This is noticeable when the axis is rotated to something besides the global-axis. */
+ const int aidx_norm_y = (aidx_norm + 2) % 3;
+ const float *y_axis = twmat[aidx_norm_y];
+ WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
+ }
+ else {
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, z_axis);
+ }
if (axis_idx >= MAN_AXIS_RANGE_TRANS_START && axis_idx < MAN_AXIS_RANGE_TRANS_END) {
if (ggd->twtype & V3D_GIZMO_SHOW_OBJECT_ROTATE) {
@@ -1699,24 +1725,56 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
start_co[2] += 0.215f;
}
}
+
+ if (scale) {
+ if (axis_type == MAN_AXES_SCALE) {
+ len = ((start_co[2] + len) * scale[aidx_norm]) - start_co[2];
+ }
+ }
+
+ RNA_float_set(axis->ptr, "length", len);
+
WM_gizmo_set_matrix_offset_location(axis, start_co);
+
WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_OFFSET_SCALE, true);
+
break;
}
case MAN_AXIS_ROT_X:
case MAN_AXIS_ROT_Y:
case MAN_AXIS_ROT_Z:
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->twmat[aidx_norm]);
- break;
+ case MAN_AXIS_ROT_C: {
+ if (axis_idx != MAN_AXIS_ROT_C) {
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, twmat[aidx_norm]);
+ }
+
+ /* Remove #ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE. It is used only for modal drawing. */
+ PropertyRNA *prop = RNA_struct_find_property(axis->ptr, "draw_options");
+ RNA_property_enum_set(axis->ptr,
+ prop,
+ RNA_property_enum_get(axis->ptr, prop) &
+ ~ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
+ } break;
case MAN_AXIS_TRANS_XY:
case MAN_AXIS_TRANS_YZ:
case MAN_AXIS_TRANS_ZX:
case MAN_AXIS_SCALE_XY:
case MAN_AXIS_SCALE_YZ:
case MAN_AXIS_SCALE_ZX: {
- const float *y_axis = rv3d->twmat[aidx_norm - 1 < 0 ? 2 : aidx_norm - 1];
- const float *z_axis = rv3d->twmat[aidx_norm];
+ const int aidx_norm_x = (aidx_norm + 1) % 3;
+ const int aidx_norm_y = (aidx_norm + 2) % 3;
+ const float *y_axis = twmat[aidx_norm_y];
+ const float *z_axis = twmat[aidx_norm];
WM_gizmo_set_matrix_rotation_from_yz_axis(axis, y_axis, z_axis);
+
+ if (axis_type == MAN_AXES_SCALE) {
+ float ofs[3] = {MAN_AXIS_SCALE_PLANE_OFFSET, MAN_AXIS_SCALE_PLANE_OFFSET, 0.0f};
+ if (scale) {
+ ofs[0] *= scale[aidx_norm_x];
+ ofs[1] *= scale[aidx_norm_y];
+ }
+ WM_gizmo_set_matrix_offset_location(axis, ofs);
+ }
break;
}
}
@@ -1733,6 +1791,49 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
}
}
+static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
+{
+ ARegion *region = CTX_wm_region(C);
+
+ {
+ wmGizmo *gz = WM_gizmomap_get_modal(region->gizmo_map);
+ if (gz && gz->parent_gzgroup == gzgroup) {
+ return;
+ }
+ }
+
+ GizmoGroup *ggd = gzgroup->customdata;
+ Scene *scene = CTX_data_scene(C);
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
+ RegionView3D *rv3d = region->regiondata;
+ struct TransformBounds tbounds;
+
+ if (ggd->use_twtype_refresh) {
+ ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init;
+ if (ggd->twtype != ggd->twtype_prev) {
+ ggd->twtype_prev = ggd->twtype;
+ gizmogroup_init_properties_from_twtype(gzgroup);
+ }
+ }
+
+ const int orient_index = BKE_scene_orientation_get_index_from_flag(scene, ggd->twtype_init);
+
+ /* skip, we don't draw anything anyway */
+ if ((ggd->all_hidden = (ED_transform_calc_gizmo_stats(C,
+ &(struct TransformCalcParams){
+ .use_only_center = true,
+ .orientation_index = orient_index + 1,
+ },
+ &tbounds) == 0))) {
+ return;
+ }
+
+ gizmo_prepare_mat(C, rv3d, &tbounds);
+
+ gizmo_refresh_from_matrix(gzgroup, rv3d->twmat, NULL);
+}
+
static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus)
@@ -1756,11 +1857,22 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
copy_m3_m4(viewinv_m3, rv3d->viewinv);
float idot[3];
+ /* Re-calculate hidden unless modal. */
+ bool is_modal = false;
+ {
+ wmGizmo *gz = WM_gizmomap_get_modal(region->gizmo_map);
+ if (gz && gz->parent_gzgroup == gzgroup) {
+ is_modal = true;
+ }
+ }
+
/* when looking through a selected camera, the gizmo can be at the
* exact same position as the view, skip so we don't break selection */
if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 5e-7f) {
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
}
MAN_ITER_AXES_END;
return;
@@ -1771,12 +1883,15 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
const short axis_type = gizmo_get_axis_type(axis_idx);
/* XXX maybe unset _HIDDEN flag on redraw? */
-
if (gizmo_is_axis_visible(rv3d, ggd->twtype, idot, axis_type, axis_idx)) {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, false);
+ }
}
else {
- WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ if (!is_modal) {
+ WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
+ }
continue;
}
@@ -1785,13 +1900,15 @@ static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgr
WM_gizmo_set_color(axis, color);
WM_gizmo_set_color_highlight(axis, color_hi);
- switch (axis_idx) {
- case MAN_AXIS_TRANS_C:
- case MAN_AXIS_ROT_C:
- case MAN_AXIS_SCALE_C:
- case MAN_AXIS_ROT_T:
- WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
- break;
+ if (!is_modal) {
+ switch (axis_idx) {
+ case MAN_AXIS_TRANS_C:
+ case MAN_AXIS_ROT_C:
+ case MAN_AXIS_SCALE_C:
+ case MAN_AXIS_ROT_T:
+ WM_gizmo_set_matrix_rotation_from_z_axis(axis, rv3d->viewinv[2]);
+ break;
+ }
}
}
MAN_ITER_AXES_END;
@@ -1879,6 +1996,17 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C,
}
}
}
+ else if (ELEM(axis_idx, MAN_AXIS_ROT_X, MAN_AXIS_ROT_Y, MAN_AXIS_ROT_Z, MAN_AXIS_ROT_C)) {
+ gizmo_3d_dial_matrixbasis_calc(CTX_wm_region(C),
+ gz->matrix_basis[2],
+ gz->matrix_basis[3],
+ (float[2]){UNPACK2(event->mval)},
+ gz->matrix_basis);
+ PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "draw_options");
+ RNA_property_enum_set(
+ gz->ptr, prop, RNA_property_enum_get(gz->ptr, prop) | ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE);
+ RNA_float_set(gz->ptr, "incremental_angle", 0.0f);
+ }
}
static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)
@@ -1944,8 +2072,8 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
gzgt->name = "3D View: Transform Gizmo";
gzgt->idname = "VIEW3D_GGT_xform_gizmo";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
- WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 2fd81486bb6..356828f513f 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -35,7 +35,7 @@
/* Own include. */
#include "transform_mode.h"
-int transform_mode_really_used(bContext *C, int mode)
+eTfmMode transform_mode_really_used(bContext *C, eTfmMode mode)
{
if (mode == TFM_BONESIZE) {
Object *ob = CTX_data_active_object(C);
@@ -292,6 +292,9 @@ void constraintTransLim(const TransInfo *t, TransData *td)
continue;
}
+ /* Initialize the custom space for use in calculating the matrices. */
+ BKE_constraint_custom_object_space_init(&cob, con);
+
/* get constraint targets if needed */
BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
@@ -549,18 +552,14 @@ void ElementRotation_ex(const TransInfo *t,
mul_m3_m3m3(totmat, mat, td->mtx);
mul_m3_m3m3(smat, td->smtx, totmat);
- /* apply gpencil falloff */
+ /* Apply gpencil falloff. */
if (t->options & CTX_GPENCIL_STROKES) {
bGPDstroke *gps = (bGPDstroke *)td->extra;
- float sx = smat[0][0];
- float sy = smat[1][1];
- float sz = smat[2][2];
-
- mul_m3_fl(smat, gps->runtime.multi_frame_falloff);
- /* fix scale */
- smat[0][0] = sx;
- smat[1][1] = sy;
- smat[2][2] = sz;
+ if (gps->runtime.multi_frame_falloff != 1.0f) {
+ float ident_mat[3][3];
+ unit_m3(ident_mat);
+ interp_m3_m3m3(smat, ident_mat, smat, gps->runtime.multi_frame_falloff);
+ }
}
sub_v3_v3v3(vec, td->iloc, center);
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index 6930b87090c..eac6734ed88 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -25,7 +25,7 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
-int transform_mode_really_used(struct bContext *C, int mode);
+eTfmMode transform_mode_really_used(struct bContext *C, eTfmMode mode);
bool transdata_check_local_center(const TransInfo *t, short around);
/**
* Informs if the mode can be switched during modal.
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index aa4d608de04..f7f9e14b8ac 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -64,10 +64,8 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (td->val) {
*td->val = td->ival * ratio;
/* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- if (*td->val <= 0.0f) {
- *td->val = 0.001f;
- }
+ *td->val = interpf(*td->val, td->ival, td->factor);
+ CLAMP_MIN(*td->val, 0.0f);
}
}
}
@@ -93,10 +91,6 @@ void initCurveShrinkFatten(TransInfo *t)
t->num.unit_sys = t->scene->unit.system;
t->num.unit_type[0] = B_UNIT_NONE;
-#ifdef USE_NUM_NO_ZERO
- t->num.val_flag[0] |= NUM_NO_ZERO;
-#endif
-
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 987d8396907..e96e74b596c 100644
--- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c
+++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
@@ -44,16 +44,11 @@ static void transdata_elem_bevel_weight(const TransInfo *UNUSED(t),
TransData *td,
const float weight)
{
- if (td->val == NULL) {
+ if (td->loc == NULL) {
return;
}
- *td->val = td->ival + weight * td->factor;
- if (*td->val < 0.0f) {
- *td->val = 0.0f;
- }
- if (*td->val > 1.0f) {
- *td->val = 1.0f;
- }
+ *td->loc = td->iloc[0] + weight * td->factor;
+ CLAMP(*td->loc, 0.0f, 1.0f);
}
static void transdata_elem_bevel_weight_fn(void *__restrict iter_data_v,
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index f1acc2a4c9a..1a3ccf30387 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -44,17 +44,12 @@ static void transdata_elem_crease(const TransInfo *UNUSED(t),
TransData *td,
const float crease)
{
- if (td->val == NULL) {
+ if (td->loc == NULL) {
return;
}
- *td->val = td->ival + crease * td->factor;
- if (*td->val < 0.0f) {
- *td->val = 0.0f;
- }
- if (*td->val > 1.0f) {
- *td->val = 1.0f;
- }
+ *td->loc = td->iloc[0] + crease * td->factor;
+ CLAMP(*td->loc, 0.0f, 1.0f);
}
static void transdata_elem_crease_fn(void *__restrict iter_data_v,
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 2327aa4e9c4..8d790b4699b 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -84,7 +84,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
transform_snap_increment(t, &angle);
- applySnapping(t, &angle);
+ applySnappingAsGroup(t, &angle);
applyNumInput(&t->num, &angle);
diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
index 9a732562709..5ca1fdf75c6 100644
--- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -87,7 +87,7 @@ static void applySeqSlide(TransInfo *t, const int UNUSED(mval[2]))
}
else {
copy_v2_v2(values_final, t->values);
- applySnapping(t, values_final);
+ applySnappingAsGroup(t, values_final);
transform_convert_sequencer_channel_clamp(t, values_final);
if (t->con.mode & CON_APPLY) {
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index b8e9a0d1a4d..a3c49d2362f 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -1292,7 +1292,7 @@ static void edge_slide_snap_apply(TransInfo *t, float *value)
side_index = t_snap >= t_mid;
}
- if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) {
+ if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) {
float co_dir[3];
sub_v3_v3v3(co_dir, co_dest[side_index], co_orig);
normalize_v3(co_dir);
@@ -1444,7 +1444,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0] + t->values_modal_offset[0];
- applySnapping(t, &final);
+ applySnappingAsGroup(t, &final);
if (!validSnap(t)) {
transform_snap_increment(t, &final);
}
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
index 83dce17d104..8b9431b65ea 100644
--- a/source/blender/editors/transform/transform_mode_gpopacity.c
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -74,7 +74,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
if (td->val) {
*td->val = td->ival * ratio;
/* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ *td->val = interpf(*td->val, td->ival, td->factor);
CLAMP(*td->val, 0.0f, 1.0f);
}
}
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
index 796d5c7ae9c..d8ec7d4ff50 100644
--- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -74,7 +74,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (td->val) {
*td->val = td->ival * ratio;
/* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ *td->val = interpf(*td->val, td->ival, td->factor);
if (*td->val <= 0.0f) {
*td->val = 0.001f;
}
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index 19a3deade63..e2ccf61796b 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -90,7 +90,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
}
/* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ *td->val = interpf(*td->val, td->ival, td->factor);
if (*td->val <= 0.0f) {
*td->val = 0.001f;
}
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index ffae651e4aa..bbe1cfdf521 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -11,6 +11,7 @@
#include "BLI_task.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_unit.h"
#include "ED_screen.h"
@@ -84,6 +85,109 @@ static void ApplySnapResize(TransInfo *t, float vec[3])
}
}
+/**
+ * Find the correction for the scaling factor when "Constrain to Bounds" is active.
+ * \param numerator: How far the UV boundary (unit square) is from the origin of the scale.
+ * \param denominator: How far the AABB is from the origin of the scale.
+ * \param scale: Scale parameter to update.
+ */
+static void constrain_scale_to_boundary(const float numerator,
+ const float denominator,
+ float *scale)
+{
+ if (denominator == 0.0f) {
+ /* The origin of the scale is on the edge of the boundary. */
+ if (numerator < 0.0f) {
+ /* Negative scale will wrap around and put us outside the boundary. */
+ *scale = 0.0f; /* Hold at the boundary instead. */
+ }
+ return; /* Nothing else we can do without more info. */
+ }
+
+ const float correction = numerator / denominator;
+ if (correction < 0.0f || !isfinite(correction)) {
+ /* TODO: Correction is negative or invalid, but we lack context to fix `*scale`. */
+ return;
+ }
+
+ if (denominator < 0.0f) {
+ /* Scale origin is outside boundary, only make scale bigger. */
+ if (*scale < correction) {
+ *scale = correction;
+ }
+ return;
+ }
+
+ /* Scale origin is inside boundary, the "regular" case, limit maximum scale. */
+ if (*scale > correction) {
+ *scale = correction;
+ }
+}
+
+static bool clip_uv_transform_resize(TransInfo *t, float vec[2])
+{
+ /* Check if the current image in UV editor is a tiled image or not. */
+ const SpaceImage *sima = t->area->spacedata.first;
+ const Image *image = sima->image;
+ const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
+
+ /* Stores the coordinates of the closest UDIM tile.
+ * Also acts as an offset to the tile from the origin of UV space. */
+ float base_offset[2] = {0.0f, 0.0f};
+
+ /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */
+ if (is_tiled_image) {
+ int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global);
+ if (nearest_tile_index != -1) {
+ nearest_tile_index -= 1001;
+ /* Getting coordinates of nearest tile from the tile index. */
+ base_offset[0] = nearest_tile_index % 10;
+ base_offset[1] = nearest_tile_index / 10;
+ }
+ }
+
+ /* Assume no change is required. */
+ float scale = 1.0f;
+
+ /* Are we scaling U and V together, or just one axis? */
+ const bool adjust_u = !(t->con.mode & CON_AXIS1);
+ const bool adjust_v = !(t->con.mode & CON_AXIS0);
+ const bool use_local_center = transdata_check_local_center(t, t->around);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ for (TransData *td = tc->data; td < tc->data + tc->data_len; td++) {
+
+ /* Get scale origin. */
+ const float *scale_origin = use_local_center ? td->center : t->center_global;
+
+ /* Alias td->loc as min and max just in case we need to optimize later. */
+ const float *min = td->loc;
+ const float *max = td->loc;
+
+ if (adjust_u) {
+ /* Update U against the left border. */
+ constrain_scale_to_boundary(
+ scale_origin[0] - base_offset[0], scale_origin[0] - min[0], &scale);
+
+ /* Now the right border, negated, because `-1.0 / -1.0 = 1.0` */
+ constrain_scale_to_boundary(
+ base_offset[0] + t->aspect[0] - scale_origin[0], max[0] - scale_origin[0], &scale);
+ }
+
+ /* Do the same for the V co-ordinate. */
+ if (adjust_v) {
+ constrain_scale_to_boundary(
+ scale_origin[1] - base_offset[1], scale_origin[1] - min[1], &scale);
+
+ constrain_scale_to_boundary(
+ base_offset[1] + t->aspect[1] - scale_origin[1], max[1] - scale_origin[1], &scale);
+ }
+ }
+ }
+ vec[0] *= scale;
+ vec[1] *= scale;
+ return scale != 1.0f;
+}
+
static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
{
float mat[3][3];
@@ -105,7 +209,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
constraintNumInput(t, t->values_final);
}
- applySnapping(t, t->values_final);
+ applySnappingAsGroup(t, t->values_final);
}
size_to_mat3(mat, t->values_final);
@@ -157,7 +261,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
}
/* Evil hack - redo resize if clipping needed. */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) {
+ if (t->flag & T_CLIP_UV && clip_uv_transform_resize(t, t->values_final)) {
size_to_mat3(mat, t->values_final);
if (t->con.mode & CON_APPLY) {
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index 4b86adc4f46..a7207b36578 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -11,6 +11,7 @@
#include "BLI_task.h"
#include "BKE_context.h"
+#include "BKE_report.h"
#include "BKE_unit.h"
#include "ED_screen.h"
@@ -304,7 +305,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
final = large_rotation_limit(final);
}
else {
- applySnapping(t, &final);
+ applySnappingAsGroup(t, &final);
if (!(activeSnap(t) && validSnap(t))) {
transform_snap_increment(t, &final);
}
@@ -322,10 +323,35 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
+static void applyRotationMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ float axis_final[3];
+ const float angle_final = t->values_final[0];
+ if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
+ t->con.applyRot(t, NULL, NULL, axis_final, NULL);
+ }
+ else {
+ negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
+ }
+
+ float mat3[3][3];
+ float mat4[4][4];
+ axis_angle_normalized_to_mat3(mat3, axis_final, angle_final);
+ copy_m4_m3(mat4, mat3);
+ transform_pivot_set_m4(mat4, t->center_global);
+ mul_m4_m4m4(mat_xform, mat4, mat_xform);
+}
+
void initRotation(TransInfo *t)
{
+ if (t->spacetype == SPACE_ACTION) {
+ BKE_report(t->reports, RPT_ERROR, "Rotation is not supported in the Dope Sheet Editor");
+ t->state = TRANS_CANCEL;
+ }
+
t->mode = TFM_ROTATION;
t->transform = applyRotation;
+ t->transform_matrix = applyRotationMatrix;
t->tsnap.applySnap = ApplySnapRotation;
t->tsnap.distance = RotationBetween;
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
index 8099449ec23..bdbb66b72f4 100644
--- a/source/blender/editors/transform/transform_mode_skin_resize.c
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -99,7 +99,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
constraintNumInput(t, t->values_final);
}
- applySnapping(t, t->values_final);
+ applySnappingAsGroup(t, t->values_final);
}
size_to_mat3(mat_final, t->values_final);
diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c
index 4130f6dc034..1474bc4591a 100644
--- a/source/blender/editors/transform/transform_mode_timescale.c
+++ b/source/blender/editors/transform/transform_mode_timescale.c
@@ -59,7 +59,7 @@ static void applyTimeScaleValue(TransInfo *t, float value)
* (this is only valid when not in NLA)
*/
AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
- float startx = CFRA;
+ float startx = scene->r.cfra;
float fac = value;
/* take proportional editing into account */
@@ -107,7 +107,7 @@ void initTimeScale(TransInfo *t)
t->mode = TFM_TIME_SCALE;
t->transform = applyTimeScale;
- /* recalculate center2d to use CFRA and mouse Y, since that's
+ /* recalculate center2d to use scene->r.cfra and mouse Y, since that's
* what is used in time scale */
if ((t->flag & T_OVERRIDE_CENTER) == 0) {
t->center_global[0] = t->scene->r.cfra;
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
index 2e405449bc3..3716826800b 100644
--- a/source/blender/editors/transform/transform_mode_trackball.c
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -75,19 +75,25 @@ static void transdata_elem_trackball_fn(void *__restrict iter_data_v,
/** \name Transform (Rotation - Trackball)
* \{ */
-static void applyTrackballValue(TransInfo *t,
- const float axis1[3],
- const float axis2[3],
- const float angles[2])
+static void applyTrackballValue_calc_axis_angle(const TransInfo *t,
+ const float phi[2],
+ float r_axis[3],
+ float *r_angle)
+{
+ float axis1[3], axis2[3];
+ normalize_v3_v3(axis1, t->persinv[0]);
+ normalize_v3_v3(axis2, t->persinv[1]);
+
+ mul_v3_v3fl(r_axis, axis1, phi[0]);
+ madd_v3_v3fl(r_axis, axis2, phi[1]);
+ *r_angle = normalize_v3(r_axis);
+}
+
+static void applyTrackballValue(TransInfo *t, const float axis[3], const float angle)
{
float mat_final[3][3];
- float axis[3];
- float angle;
int i;
- mul_v3_v3fl(axis, axis1, angles[0]);
- madd_v3_v3fl(axis, axis2, angles[1]);
- angle = normalize_v3(axis);
axis_angle_normalized_to_mat3(mat_final, axis, angle);
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
@@ -120,17 +126,8 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
size_t ofs = 0;
- float axis1[3], axis2[3];
-#if 0 /* UNUSED */
- float mat[3][3], totmat[3][3], smat[3][3];
-#endif
float phi[2];
- copy_v3_v3(axis1, t->persinv[0]);
- copy_v3_v3(axis2, t->persinv[1]);
- normalize_v3(axis1);
- normalize_v3(axis2);
-
copy_v2_v2(phi, t->values);
transform_snap_increment(t, phi);
@@ -165,27 +162,35 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
str + ofs, sizeof(str) - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
}
-#if 0 /* UNUSED */
- axis_angle_normalized_to_mat3(smat, axis1, phi[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, phi[1]);
+ float axis_final[3], angle_final;
+ applyTrackballValue_calc_axis_angle(t, phi, axis_final, &angle_final);
+ applyTrackballValue(t, axis_final, angle_final);
- mul_m3_m3m3(mat, smat, totmat);
+ recalcData(t);
- /* TRANSFORM_FIX_ME */
- // copy_m3_m3(t->mat, mat); /* used in gizmo. */
-#endif
+ ED_area_status_text(t->area, str);
+}
- applyTrackballValue(t, axis1, axis2, phi);
+static void applyTrackballMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ const float phi[2] = {UNPACK2(t->values_final)};
- recalcData(t);
+ float axis_final[3], angle_final;
+ applyTrackballValue_calc_axis_angle(t, phi, axis_final, &angle_final);
- ED_area_status_text(t->area, str);
+ float mat3[3][3], mat4[4][4];
+ axis_angle_normalized_to_mat3(mat3, axis_final, angle_final);
+
+ copy_m4_m3(mat4, mat3);
+ transform_pivot_set_m4(mat4, t->center_global);
+ mul_m4_m4m4(mat_xform, mat4, mat_xform);
}
void initTrackball(TransInfo *t)
{
t->mode = TFM_TRACKBALL;
t->transform = applyTrackball;
+ t->transform_matrix = applyTrackballMatrix;
initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index c881cde351e..67bdeb3fed0 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -16,6 +16,7 @@
#include "BLI_task.h"
#include "BKE_context.h"
+#include "BKE_image.h"
#include "BKE_report.h"
#include "BKE_unit.h"
@@ -434,6 +435,60 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
custom_data->prev.rotate_mode = rotate_mode;
}
+static bool clip_uv_transform_translation(TransInfo *t, float vec[2])
+{
+ /* Check if the current image in UV editor is a tiled image or not. */
+ const SpaceImage *sima = t->area->spacedata.first;
+ const Image *image = sima->image;
+ const bool is_tiled_image = image && (image->source == IMA_SRC_TILED);
+
+ /* Stores the coordinates of the closest UDIM tile.
+ * Also acts as an offset to the tile from the origin of UV space. */
+ float base_offset[2] = {0.0f, 0.0f};
+
+ /* If tiled image then constrain to correct/closest UDIM tile, else 0-1 UV space. */
+ if (is_tiled_image) {
+ int nearest_tile_index = BKE_image_find_nearest_tile(image, t->center_global);
+ if (nearest_tile_index != -1) {
+ nearest_tile_index -= 1001;
+ /* Getting coordinates of nearest tile from the tile index. */
+ base_offset[0] = nearest_tile_index % 10;
+ base_offset[1] = nearest_tile_index / 10;
+ }
+ }
+
+ float min[2], max[2];
+ min[0] = min[1] = FLT_MAX;
+ max[0] = max[1] = -FLT_MAX;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ for (TransData *td = tc->data; td < tc->data + tc->data_len; td++) {
+ minmax_v2v2_v2(min, max, td->loc);
+ }
+ }
+
+ bool result = false;
+ if (min[0] < base_offset[0]) {
+ vec[0] += base_offset[0] - min[0];
+ result = true;
+ }
+ else if (max[0] > base_offset[0] + t->aspect[0]) {
+ vec[0] -= max[0] - base_offset[0] - t->aspect[0];
+ result = true;
+ }
+
+ if (min[1] < base_offset[1]) {
+ vec[1] += base_offset[1] - min[1];
+ result = true;
+ }
+ else if (max[1] > base_offset[1] + t->aspect[1]) {
+ vec[1] -= max[1] - base_offset[1] - t->aspect[1];
+ result = true;
+ }
+
+ return result;
+}
+
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
@@ -469,8 +524,8 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
add_v3_v3(global_dir, values_ofs);
}
- t->tsnap.snapElem = 0;
- applySnapping(t, global_dir);
+ t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
+ applySnappingAsGroup(t, global_dir);
transform_snap_grid(t, global_dir);
if (t->con.mode & CON_APPLY) {
@@ -486,7 +541,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
/* Test for mixed snap with grid. */
float snap_dist_sq = FLT_MAX;
- if (t->tsnap.snapElem != 0) {
+ if (t->tsnap.snapElem != SCE_SNAP_MODE_NONE) {
snap_dist_sq = len_squared_v3v3(t->values, global_dir);
}
if ((snap_dist_sq == FLT_MAX) || (len_squared_v3v3(global_dir, incr_dir) < snap_dist_sq)) {
@@ -498,7 +553,7 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
applyTranslationValue(t, global_dir);
/* evil hack - redo translation if clipping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) {
+ if (t->flag & T_CLIP_UV && clip_uv_transform_translation(t, global_dir)) {
applyTranslationValue(t, global_dir);
/* In proportional edit it can happen that */
@@ -518,6 +573,13 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
ED_area_status_text(t->area, str);
}
+static void applyTranslationMatrix(TransInfo *t, float mat_xform[4][4])
+{
+ float delta[3];
+ mul_v3_m3v3(delta, t->spacemtx, t->values_final);
+ add_v3_v3(mat_xform[3], delta);
+}
+
void initTranslation(TransInfo *t)
{
if (t->spacetype == SPACE_ACTION) {
@@ -530,6 +592,7 @@ void initTranslation(TransInfo *t)
}
t->transform = applyTranslation;
+ t->transform_matrix = applyTranslationMatrix;
t->tsnap.applySnap = ApplySnapTranslation;
t->tsnap.distance = transform_snap_distance_len_squared_fn;
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
index 77c5707d814..674ffcf17a8 100644
--- a/source/blender/editors/transform/transform_mode_vert_slide.c
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -539,7 +539,7 @@ static void vert_slide_snap_apply(TransInfo *t, float *value)
getSnapPoint(t, dvec);
sub_v3_v3(dvec, t->tsnap.snapTarget);
- if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) {
+ if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) {
float co_dir[3];
sub_v3_v3v3(co_dir, co_curr_3d, co_orig_3d);
normalize_v3(co_dir);
@@ -568,7 +568,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
final = t->values[0] + t->values_modal_offset[0];
- applySnapping(t, &final);
+ applySnappingAsGroup(t, &final);
if (!validSnap(t)) {
transform_snap_increment(t, &final);
}
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 600f525b428..7c94241f3e3 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -419,7 +419,7 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* XXX, workaround: active needs to be calculated before transforming,
* since we're not reading from 'td->center' in this case. see: T40241 */
- if (t->tsnap.target == SCE_SNAP_TARGET_ACTIVE) {
+ if (t->tsnap.source_select == SCE_SNAP_SOURCE_ACTIVE) {
/* In camera view, tsnap callback is not set
* (see #initSnappingMode() in transform_snap.c, and T40348). */
if (t->tsnap.targetSnap && ((t->tsnap.status & TARGET_INIT) == 0)) {
@@ -566,6 +566,17 @@ static bool transform_poll_property(const bContext *UNUSED(C),
}
}
+ /* Snapping. */
+ {
+ PropertyRNA *prop_snap = RNA_struct_find_property(op->ptr, "snap");
+ if (prop_snap && (prop_snap != prop) &&
+ (RNA_property_boolean_get(op->ptr, prop_snap) == false)) {
+ if (STRPREFIX(prop_id, "snap") || STRPREFIX(prop_id, "use_snap")) {
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -644,24 +655,63 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
}
if (flags & P_SNAP) {
- prop = RNA_def_boolean(ot->srna, "snap", 0, "Use Snapping Options", "");
+ prop = RNA_def_boolean(ot->srna, "snap", false, "Use Snapping Options", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_enum(ot->srna,
+ "snap_elements",
+ rna_enum_snap_element_items,
+ SCE_SNAP_MODE_INCREMENT,
+ "Snap to Elements",
+ "");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+
+ RNA_def_boolean(ot->srna, "use_snap_project", false, "Project Individual Elements", "");
+
if (flags & P_GEO_SNAP) {
- prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_target_items, 0, "Target", "");
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
+ * "target" (now, "source" is geometry to be moved and "target" is geometry to which moved
+ * geometry is snapped). Use "Source snap point" and "Point on source that will snap to
+ * target" for name and description, respectively. */
+ prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_source_items, 0, "Snap With", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ /* Target selection. */
+ prop = RNA_def_boolean(ot->srna, "use_snap_self", true, "Target: Include Active", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "use_snap_edit", true, "Target: Include Edit", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "use_snap_nonedit", true, "Target: Include Non-Edited", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_boolean(
+ ot->srna, "use_snap_selectable_only", false, "Target: Exclude Non-Selectable", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
+ /* Face Nearest options */
+ prop = RNA_def_boolean(
+ ot->srna, "use_snap_to_same_target", false, "Snap to Same Target", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_int(
+ ot->srna, "snap_face_nearest_steps", 1, 1, 32767, "Face Nearest Steps", "", 1, 32767);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+
prop = RNA_def_float_vector(
ot->srna, "snap_point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
if (flags & P_ALIGN_SNAP) {
- prop = RNA_def_boolean(ot->srna, "snap_align", 0, "Align with Point Normal", "");
+ prop = RNA_def_boolean(ot->srna, "snap_align", false, "Align with Point Normal", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_float_vector(
ot->srna, "snap_normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "", -FLT_MAX, FLT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
}
}
+ else {
+ prop = RNA_def_boolean(
+ ot->srna, "use_snap_selectable_only", false, "Target: Exclude Non-Selectable", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
}
if (flags & P_GPENCIL_EDIT) {
@@ -845,17 +895,6 @@ static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
-/* Similar to #transform_shear_poll. */
-static bool transform_rotate_poll(bContext *C)
-{
- if (!ED_operator_screenactive(C)) {
- return false;
- }
-
- ScrArea *area = CTX_wm_area(C);
- return area && !ELEM(area->spacetype, SPACE_ACTION);
-}
-
static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
{
/* identifiers */
@@ -869,7 +908,7 @@ static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
ot->exec = transform_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
- ot->poll = transform_rotate_poll;
+ ot->poll = ED_operator_screenactive;
ot->poll_property = transform_poll_property;
RNA_def_float_rotation(
@@ -934,7 +973,6 @@ static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
}
-/* Similar to #transform_rotate_poll. */
static bool transform_shear_poll(bContext *C)
{
if (!ED_operator_screenactive(C)) {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 769fd28c57b..22d062a71dc 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -79,8 +79,8 @@ static void TargetSnapActive(TransInfo *t);
/** \name Implementations
* \{ */
-static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select);
-static NodeBorder snapNodeBorder(int snap_node_mode);
+static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select);
+static NodeBorder snapNodeBorder(eSnapMode snap_node_mode);
#if 0
int BIF_snappingSupported(Object *obedit)
@@ -126,8 +126,12 @@ bool activeSnap(const TransInfo *t)
((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) == MOD_SNAP_INVERT);
}
-bool activeSnap_with_project(const TransInfo *t)
+bool activeSnap_SnappingIndividual(const TransInfo *t)
{
+ if (activeSnap(t) && t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST) {
+ return true;
+ }
+
if (!t->tsnap.project) {
return false;
}
@@ -143,6 +147,27 @@ bool activeSnap_with_project(const TransInfo *t)
return true;
}
+bool activeSnap_SnappingAsGroup(const TransInfo *t)
+{
+ if (!activeSnap(t)) {
+ return false;
+ }
+
+ if (t->tsnap.mode == SCE_SNAP_MODE_FACE_RAYCAST && t->tsnap.project) {
+ return false;
+ }
+
+ if (t->tsnap.mode == SCE_SNAP_MODE_FACE_NEAREST) {
+ return false;
+ }
+
+ if (doForceIncrementSnap(t)) {
+ return false;
+ }
+
+ return true;
+}
+
bool transformModeUseSnap(const TransInfo *t)
{
ToolSettings *ts = t->settings;
@@ -343,88 +368,155 @@ eRedrawFlag handleSnapping(TransInfo *t, const wmEvent *event)
return status;
}
-void applyProject(TransInfo *t)
+static bool applyFaceProject(TransInfo *t, TransDataContainer *tc, TransData *td)
{
- if (!activeSnap_with_project(t)) {
- return;
+ if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) {
+ return false;
+ }
+
+ float iloc[3], loc[3], no[3];
+ float mval_fl[2];
+
+ copy_v3_v3(iloc, td->loc);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, iloc);
+ }
+ else if (t->options & CTX_OBJECT) {
+ BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+ copy_v3_v3(iloc, td->ob->obmat[3]);
+ }
+
+ if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) !=
+ V3D_PROJ_RET_OK) {
+ return false;
+ }
+
+ eSnapMode hit = ED_transform_snap_object_project_view3d(
+ t->tsnap.object_context,
+ t->depsgraph,
+ t->region,
+ t->view,
+ SCE_SNAP_MODE_FACE_RAYCAST,
+ &(const struct SnapObjectParams){
+ .snap_target_select = t->tsnap.target_select,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
+ .use_occlusion_test = false,
+ .use_backface_culling = t->tsnap.use_backface_culling,
+ },
+ NULL,
+ mval_fl,
+ NULL,
+ 0,
+ loc,
+ no);
+ if (hit != SCE_SNAP_MODE_FACE_RAYCAST) {
+ return false;
}
float tvec[3];
- int i;
+ sub_v3_v3v3(tvec, loc, iloc);
- /* XXX FLICKER IN OBJECT MODE */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- float iloc[3], loc[3], no[3];
- float mval_fl[2];
- if (td->flag & TD_SKIP) {
- continue;
- }
+ mul_m3_v3(td->smtx, tvec);
- if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
- continue;
- }
+ add_v3_v3(td->loc, tvec);
- copy_v3_v3(iloc, td->loc);
- if (tc->use_local_mat) {
- mul_m4_v3(tc->mat, iloc);
- }
- else if (t->options & CTX_OBJECT) {
- BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
- copy_v3_v3(iloc, td->ob->obmat[3]);
- }
+ if (t->tsnap.align && (t->options & CTX_OBJECT)) {
+ /* handle alignment as well */
+ const float *original_normal;
+ float mat[3][3];
- if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
- V3D_PROJ_RET_OK) {
- 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,
- .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
- .use_occlusion_test = false,
- .use_backface_culling = t->tsnap.use_backface_culling,
- },
- mval_fl,
- NULL,
- 0,
- loc,
- no)) {
-#if 0
- if (tc->use_local_mat) {
- mul_m4_v3(tc->imat, loc);
- }
-#endif
+ /* In pose mode, we want to align normals with Y axis of bones. */
+ original_normal = td->axismtx[2];
+
+ rotation_between_vecs_to_mat3(mat, original_normal, no);
+
+ transform_data_ext_rotate(td, mat, true);
+
+ /* TODO: support constraints for rotation too? see #ElementRotation. */
+ }
+ return true;
+}
- sub_v3_v3v3(tvec, loc, iloc);
+static void applyFaceNearest(TransInfo *t, TransDataContainer *tc, TransData *td)
+{
+ if (!(t->tsnap.mode & SCE_SNAP_MODE_FACE_NEAREST)) {
+ return;
+ }
+
+ float init_loc[3];
+ float prev_loc[3];
+ float snap_loc[3], snap_no[3];
- mul_m3_v3(td->smtx, tvec);
+ copy_v3_v3(init_loc, td->iloc);
+ copy_v3_v3(prev_loc, td->loc);
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->mat, init_loc);
+ mul_m4_v3(tc->mat, prev_loc);
+ }
+ else if (t->options & CTX_OBJECT) {
+ BKE_object_eval_transform_all(t->depsgraph, t->scene, td->ob);
+ copy_v3_v3(init_loc, td->ob->obmat[3]);
+ }
- add_v3_v3(td->loc, tvec);
+ eSnapMode hit = ED_transform_snap_object_project_view3d(
+ t->tsnap.object_context,
+ t->depsgraph,
+ t->region,
+ t->view,
+ SCE_SNAP_MODE_FACE_NEAREST,
+ &(const struct SnapObjectParams){
+ .snap_target_select = t->tsnap.target_select,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
+ .use_occlusion_test = false,
+ .use_backface_culling = false,
+ .face_nearest_steps = t->tsnap.face_nearest_steps,
+ .keep_on_same_target = t->tsnap.flag & SCE_SNAP_KEEP_ON_SAME_OBJECT,
+ },
+ init_loc,
+ NULL,
+ prev_loc,
+ 0,
+ snap_loc,
+ snap_no);
+
+ if (hit != SCE_SNAP_MODE_FACE_NEAREST) {
+ return;
+ }
- if (t->tsnap.align && (t->options & CTX_OBJECT)) {
- /* handle alignment as well */
- const float *original_normal;
- float mat[3][3];
+ float tvec[3];
+ sub_v3_v3v3(tvec, snap_loc, prev_loc);
+ mul_m3_v3(td->smtx, tvec);
+ add_v3_v3(td->loc, tvec);
- /* In pose mode, we want to align normals with Y axis of bones... */
- original_normal = td->axismtx[2];
+ /* TODO: support snap alignment similar to #SCE_SNAP_MODE_FACE_RAYCAST? */
+}
- rotation_between_vecs_to_mat3(mat, original_normal, no);
+void applySnappingIndividual(TransInfo *t)
+{
+ if (!activeSnap_SnappingIndividual(t)) {
+ return;
+ }
- transform_data_ext_rotate(td, mat, true);
+ /* XXX FLICKER IN OBJECT MODE */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
- /* TODO: support constraints for rotation too? see #ElementRotation. */
- }
- }
+ if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f)) {
+ continue;
}
+ /* If both face ray-cast and face nearest methods are enabled, start with face ray-cast and
+ * fallback to face nearest ray-cast does not hit. */
+ bool hit = applyFaceProject(t, tc, td);
+ if (!hit) {
+ applyFaceNearest(t, tc, td);
+ }
#if 0 /* TODO: support this? */
- constraintTransLim(t, td);
+ constraintTransLim(t, td);
#endif
}
}
@@ -480,15 +572,9 @@ void applyGridAbsolute(TransInfo *t)
}
}
-void applySnapping(TransInfo *t, float *vec)
+void applySnappingAsGroup(TransInfo *t, float *vec)
{
- /* Each Trans Data already makes the snap to face */
- if (doForceIncrementSnap(t)) {
- return;
- }
-
- if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) {
- /* A similar snap will be applied to each transdata in `applyProject`. */
+ if (!activeSnap_SnappingAsGroup(t)) {
return;
}
@@ -522,13 +608,13 @@ void applySnapping(TransInfo *t, float *vec)
void resetSnapping(TransInfo *t)
{
- t->tsnap.status = 0;
- t->tsnap.snapElem = 0;
+ t->tsnap.status = SNAP_RESETTED;
+ t->tsnap.snapElem = SCE_SNAP_MODE_NONE;
t->tsnap.align = false;
- t->tsnap.project = 0;
- t->tsnap.mode = 0;
- t->tsnap.modeSelect = 0;
- t->tsnap.target = 0;
+ t->tsnap.project = false;
+ t->tsnap.mode = SCE_SNAP_MODE_NONE;
+ t->tsnap.target_select = SCE_SNAP_TARGET_ALL;
+ t->tsnap.source_select = SCE_SNAP_SOURCE_CLOSEST;
t->tsnap.last = 0;
t->tsnap.snapNormal[0] = 0;
@@ -581,7 +667,7 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
return true;
}
-static char snap_flag_from_spacetype(TransInfo *t)
+static eSnapFlag snap_flag_from_spacetype(TransInfo *t)
{
ToolSettings *ts = t->settings;
if (t->spacetype == SPACE_NODE) {
@@ -596,7 +682,7 @@ static char snap_flag_from_spacetype(TransInfo *t)
return ts->snap_flag;
}
-static short snap_mode_from_spacetype(TransInfo *t)
+static eSnapMode snap_mode_from_spacetype(TransInfo *t)
{
ToolSettings *ts = t->settings;
@@ -605,7 +691,7 @@ static short snap_mode_from_spacetype(TransInfo *t)
}
if (t->spacetype == SPACE_IMAGE) {
- short snap_mode = ts->snap_uv_mode;
+ eSnapMode snap_mode = ts->snap_uv_mode;
if ((snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) &&
(t->mode == TFM_TRANSLATION)) {
snap_mode &= ~SCE_SNAP_MODE_INCREMENT;
@@ -623,7 +709,7 @@ static short snap_mode_from_spacetype(TransInfo *t)
return SCE_SNAP_MODE_INCREMENT;
}
- short snap_mode = ts->snap_mode;
+ eSnapMode snap_mode = ts->snap_mode;
if ((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. */
@@ -641,72 +727,78 @@ static short snap_mode_from_spacetype(TransInfo *t)
return SCE_SNAP_MODE_INCREMENT;
}
-static short snap_select_type_get(TransInfo *t)
+static eSnapTargetSelect snap_target_select_from_spacetype(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
Base *base_act = view_layer->basact;
+
+ eSnapTargetSelect ret = SCE_SNAP_TARGET_ALL;
+
+ bool use_snap_active = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_ACTIVE) == 0;
+ bool use_snap_edit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_EDITED) == 0;
+ bool use_snap_nonedit = (t->tsnap.target_select & SCE_SNAP_TARGET_NOT_NONEDITED) == 0;
+ bool use_snap_selectable_only = (t->tsnap.target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) != 0;
+
if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) {
+ if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
+ /* Particles edit mode. */
+ return ret;
+ }
+
+ if (use_snap_selectable_only) {
+ ret |= SCE_SNAP_TARGET_ONLY_SELECTABLE;
+ }
+
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). */
- return SNAP_ALL;
+ return ret;
}
const int obedit_type = t->obedit_type;
if (obedit_type != -1) {
/* Edit mode */
- if (ELEM(obedit_type,
- OB_MESH,
- OB_ARMATURE,
- OB_CURVES_LEGACY,
- OB_SURF,
- OB_LATTICE,
- OB_MBALL)) {
- /* Temporary limited to edit mode meshes, armature, curves, lattice and metaballs. */
-
- if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
- /* Exclude editmesh if using proportional edit */
- return SNAP_NOT_EDITED;
+ if (obedit_type == OB_MESH) {
+ /* Editing a mesh */
+ if ((t->flag & T_PROP_EDIT) != 0) {
+ /* Exclude editmesh when using proportional edit */
+ ret |= SCE_SNAP_TARGET_NOT_EDITED;
}
-
- if (!t->tsnap.snap_self) {
- return SNAP_NOT_ACTIVE;
+ if (!use_snap_active) {
+ ret |= SCE_SNAP_TARGET_NOT_ACTIVE;
+ }
+ if (!use_snap_edit) {
+ ret |= SCE_SNAP_TARGET_NOT_EDITED;
+ }
+ if (!use_snap_nonedit) {
+ ret |= SCE_SNAP_TARGET_NOT_NONEDITED;
}
-
- return SNAP_NOT_SELECTED;
}
-
- return SNAP_ALL;
+ else if (ELEM(obedit_type, OB_ARMATURE, OB_CURVES_LEGACY, OB_SURF, OB_LATTICE, OB_MBALL)) {
+ /* Temporary limited to edit mode armature, curves, surfaces, lattices, and metaballs. */
+ ret |= SCE_SNAP_TARGET_NOT_SELECTED;
+ }
}
-
- if (base_act && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) {
- /* Particles edit mode. */
- return SNAP_ALL;
+ else {
+ /* Object or pose mode. */
+ ret |= SCE_SNAP_TARGET_NOT_SELECTED | SCE_SNAP_TARGET_NOT_ACTIVE;
}
-
- /* Object or pose mode. */
- return SNAP_NOT_SELECTED;
}
-
- if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
- return SNAP_NOT_SELECTED;
+ else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
+ ret |= SCE_SNAP_TARGET_NOT_SELECTED;
}
- return SNAP_ALL;
+ return ret;
}
static void initSnappingMode(TransInfo *t)
{
- ToolSettings *ts = t->settings;
- t->tsnap.mode = snap_mode_from_spacetype(t);
- t->tsnap.modeSelect = snap_select_type_get(t);
-
- if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) {
+ if ((t->spacetype != SPACE_VIEW3D) || !(t->tsnap.mode & SCE_SNAP_MODE_FACE_RAYCAST)) {
/* Force project off when not supported. */
- t->tsnap.project = 0;
+ t->tsnap.project = false;
}
if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) {
@@ -750,9 +842,14 @@ static void initSnappingMode(TransInfo *t)
void initSnapping(TransInfo *t, wmOperator *op)
{
+ ToolSettings *ts = t->settings;
+ eSnapSourceSelect snap_source = ts->snap_target;
+
resetSnapping(t);
+ t->tsnap.mode = snap_mode_from_spacetype(t);
t->tsnap.flag = snap_flag_from_spacetype(t);
- short snap_target = t->settings->snap_target;
+ t->tsnap.target_select = snap_target_select_from_spacetype(t);
+ t->tsnap.face_nearest_steps = max_ii(ts->snap_face_nearest_steps, 1);
/* if snap property exists */
PropertyRNA *prop;
@@ -761,9 +858,17 @@ void initSnapping(TransInfo *t, wmOperator *op)
if (RNA_property_boolean_get(op->ptr, prop)) {
t->modifiers |= MOD_SNAP;
+ if ((prop = RNA_struct_find_property(op->ptr, "snap_elements")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ t->tsnap.mode = RNA_property_enum_get(op->ptr, prop);
+ }
+
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
+ * "target" (now, "source" is geometry to be moved and "target" is geometry to which moved
+ * geometry is snapped). */
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);
+ snap_source = RNA_property_enum_get(op->ptr, prop);
}
if ((prop = RNA_struct_find_property(op->ptr, "snap_point")) &&
@@ -785,9 +890,33 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.project = RNA_property_boolean_get(op->ptr, prop);
}
+ /* use_snap_self is misnamed and should be use_snap_active */
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);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_NOT_ACTIVE);
+ }
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_edit")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_NOT_EDITED);
+ }
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_nonedit")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_NOT_NONEDITED);
+ }
+
+ if ((prop = RNA_struct_find_property(op->ptr, "use_snap_selectable")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ RNA_property_boolean_get(op->ptr, prop),
+ SCE_SNAP_TARGET_ONLY_SELECTABLE);
}
}
}
@@ -799,11 +928,22 @@ void initSnapping(TransInfo *t, wmOperator *op)
t->tsnap.align = ((t->tsnap.flag & SCE_SNAP_ROTATE) != 0);
t->tsnap.project = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
- t->tsnap.snap_self = !((t->tsnap.flag & SCE_SNAP_NO_SELF) != 0);
t->tsnap.peel = ((t->tsnap.flag & SCE_SNAP_PROJECT) != 0);
- }
-
- t->tsnap.target = snap_target;
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ (ts->snap_flag & SCE_SNAP_NOT_TO_ACTIVE),
+ SCE_SNAP_TARGET_NOT_ACTIVE);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !(ts->snap_flag & SCE_SNAP_TO_INCLUDE_EDITED),
+ SCE_SNAP_TARGET_NOT_EDITED);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ !(ts->snap_flag & SCE_SNAP_TO_INCLUDE_NONEDITED),
+ SCE_SNAP_TARGET_NOT_NONEDITED);
+ SET_FLAG_FROM_TEST(t->tsnap.target_select,
+ (ts->snap_flag & SCE_SNAP_TO_ONLY_SELECTABLE),
+ SCE_SNAP_TARGET_ONLY_SELECTABLE);
+ }
+
+ t->tsnap.source_select = snap_source;
initSnappingMode(t);
}
@@ -844,11 +984,11 @@ static void setSnappingCallback(TransInfo *t)
return;
}
- switch (t->tsnap.target) {
- case SCE_SNAP_TARGET_CLOSEST:
+ switch (t->tsnap.source_select) {
+ case SCE_SNAP_SOURCE_CLOSEST:
t->tsnap.targetSnap = TargetSnapClosest;
break;
- case SCE_SNAP_TARGET_CENTER:
+ case SCE_SNAP_SOURCE_CENTER:
if (!ELEM(t->mode, TFM_ROTATION, TFM_RESIZE)) {
t->tsnap.targetSnap = TargetSnapCenter;
break;
@@ -856,10 +996,10 @@ static void setSnappingCallback(TransInfo *t)
/* Can't do TARGET_CENTER with these modes,
* use TARGET_MEDIAN instead. */
ATTR_FALLTHROUGH;
- case SCE_SNAP_TARGET_MEDIAN:
+ case SCE_SNAP_SOURCE_MEDIAN:
t->tsnap.targetSnap = TargetSnapMedian;
break;
- case SCE_SNAP_TARGET_ACTIVE:
+ case SCE_SNAP_SOURCE_ACTIVE:
t->tsnap.targetSnap = TargetSnapActive;
break;
}
@@ -973,7 +1113,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
float no[3];
float mval[2];
bool found = false;
- short snap_elem = 0;
+ eSnapMode snap_elem = SCE_SNAP_MODE_NONE;
float dist_px = SNAP_MIN_DISTANCE; /* Use a user defined value here. */
mval[0] = t->mval[0];
@@ -982,11 +1122,11 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
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;
+ found = (snap_elem != SCE_SNAP_MODE_NONE);
}
if ((found == false) && (t->tsnap.mode & SCE_SNAP_MODE_VOLUME)) {
- found = peelObjectsTransform(
- t, mval, (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0, loc, no, NULL);
+ bool use_peel = (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT) != 0;
+ found = peelObjectsTransform(t, mval, use_peel, loc, no, NULL);
if (found) {
snap_elem = SCE_SNAP_MODE_VOLUME;
@@ -1003,7 +1143,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec))
t->tsnap.status &= ~POINT_INIT;
}
- t->tsnap.snapElem = (char)snap_elem;
+ t->tsnap.snapElem = snap_elem;
}
static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
@@ -1020,7 +1160,7 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
objects,
objects_len,
t->mval,
- t->tsnap.modeSelect == SNAP_NOT_SELECTED,
+ t->tsnap.target_select & SCE_SNAP_TARGET_NOT_SELECTED,
&dist_sq,
t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
@@ -1190,7 +1330,7 @@ static void TargetSnapActive(TransInfo *t)
}
/* No active, default to median */
else {
- t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
+ t->tsnap.source_select = SCE_SNAP_SOURCE_MEDIAN;
t->tsnap.targetSnap = TargetSnapMedian;
TargetSnapMedian(t);
}
@@ -1302,7 +1442,7 @@ static void TargetSnapClosest(TransInfo *t)
/** \name Snap Objects
* \{ */
-short snapObjectsTransform(
+eSnapMode 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;
@@ -1313,11 +1453,12 @@ short snapObjectsTransform(
t->view,
t->tsnap.mode,
&(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
+ .snap_target_select = t->tsnap.target_select,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
- .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
+ .use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE_RAYCAST,
.use_backface_culling = t->tsnap.use_backface_culling,
},
+ NULL,
mval,
target,
dist_px,
@@ -1346,7 +1487,7 @@ bool peelObjectsTransform(TransInfo *t,
t->region,
t->view,
&(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
+ .snap_target_select = t->tsnap.target_select,
.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
},
mval,
@@ -1414,16 +1555,16 @@ bool peelObjectsTransform(TransInfo *t,
/** \name snap Nodes
* \{ */
-static bool snapNodeTest(View2D *v2d, bNode *node, eSnapSelect snap_select)
+static bool snapNodeTest(View2D *v2d, bNode *node, eSnapTargetSelect snap_target_select)
{
/* node is use for snapping only if a) snap mode matches and b) node is inside the view */
- return ((snap_select == SNAP_NOT_SELECTED && !(node->flag & NODE_SELECT)) ||
- (snap_select == SNAP_ALL && !(node->flag & NODE_ACTIVE))) &&
+ return (((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && !(node->flag & NODE_SELECT)) ||
+ (snap_target_select == SCE_SNAP_TARGET_ALL && !(node->flag & NODE_ACTIVE))) &&
(node->totr.xmin < v2d->cur.xmax && node->totr.xmax > v2d->cur.xmin &&
node->totr.ymin < v2d->cur.ymax && node->totr.ymax > v2d->cur.ymin);
}
-static NodeBorder snapNodeBorder(int snap_node_mode)
+static NodeBorder snapNodeBorder(eSnapMode snap_node_mode)
{
NodeBorder flag = 0;
if (snap_node_mode & SCE_SNAP_MODE_NODE_X) {
@@ -1499,7 +1640,7 @@ static bool snapNodes(ToolSettings *ts,
SpaceNode *snode,
ARegion *region,
const int mval[2],
- eSnapSelect snap_select,
+ eSnapTargetSelect snap_target_select,
float r_loc[2],
float *r_dist_px,
char *r_node_border)
@@ -1511,7 +1652,7 @@ static bool snapNodes(ToolSettings *ts,
*r_node_border = 0;
for (node = ntree->nodes.first; node; node = node->next) {
- if (snapNodeTest(&region->v2d, node, snap_select)) {
+ if (snapNodeTest(&region->v2d, node, snap_target_select)) {
retval |= snapNode(ts, snode, region, node, mval, r_loc, r_dist_px, r_node_border);
}
}
@@ -1526,7 +1667,7 @@ bool snapNodesTransform(
t->area->spacedata.first,
t->region,
mval,
- t->tsnap.modeSelect,
+ t->tsnap.target_select,
r_loc,
r_dist_px,
r_node_border);
@@ -1548,7 +1689,7 @@ static void snap_grid_apply(
float in[3];
if (t->con.mode & CON_APPLY) {
- BLI_assert(t->tsnap.snapElem == 0);
+ BLI_assert(t->tsnap.snapElem == SCE_SNAP_MODE_NONE);
t->con.applyVec(t, NULL, NULL, loc, in);
}
else {
@@ -1676,6 +1817,16 @@ bool transform_snap_increment(const TransInfo *t, float *r_val)
return transform_snap_increment_ex(t, false, r_val);
}
+float transform_snap_increment_get(const TransInfo *t)
+{
+ if (activeSnap(t) && (!transformModeUseSnap(t) ||
+ (t->tsnap.mode & (SCE_SNAP_MODE_INCREMENT | SCE_SNAP_MODE_GRID)))) {
+ return (t->modifiers & MOD_PRECISION) ? t->snap[1] : t->snap[0];
+ }
+
+ return 0.0f;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index cde97d14be4..3672e76c778 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -19,12 +19,12 @@ bool peelObjectsTransform(struct TransInfo *t,
float r_no[3],
float *r_thickness);
-short snapObjectsTransform(struct TransInfo *t,
- const float mval[2],
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3]);
+eSnapMode snapObjectsTransform(struct TransInfo *t,
+ const float mval[2],
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3]);
bool snapNodesTransform(struct TransInfo *t,
const int mval[2],
/* return args */
@@ -36,18 +36,20 @@ bool transformModeUseSnap(const TransInfo *t);
bool transform_snap_increment_ex(const TransInfo *t, bool use_local_space, float *r_val);
bool transform_snap_increment(const TransInfo *t, float *val);
+float transform_snap_increment_get(const TransInfo *t);
bool transform_snap_grid(TransInfo *t, float *val);
bool activeSnap(const TransInfo *t);
-bool activeSnap_with_project(const TransInfo *t);
+bool activeSnap_SnappingIndividual(const TransInfo *t);
+bool activeSnap_SnappingAsGroup(const TransInfo *t);
bool validSnap(const TransInfo *t);
void initSnapping(struct TransInfo *t, struct wmOperator *op);
void freeSnapping(struct TransInfo *t);
-void applyProject(TransInfo *t);
+void applySnappingIndividual(TransInfo *t);
void applyGridAbsolute(TransInfo *t);
-void applySnapping(TransInfo *t, float *vec);
+void applySnappingAsGroup(TransInfo *t, float *vec);
void resetSnapping(TransInfo *t);
eRedrawFlag handleSnapping(TransInfo *t, const struct wmEvent *event);
void drawSnapping(const struct bContext *C, TransInfo *t);
diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc
index 0505772c668..479214ee2d3 100644
--- a/source/blender/editors/transform/transform_snap_object.cc
+++ b/source/blender/editors/transform/transform_snap_object.cc
@@ -157,7 +157,7 @@ struct SnapObjectContext {
enum eViewProj view_proj;
float clip_plane[MAX_CLIPPLANE_LEN][4];
short clip_plane_len;
- short snap_to_flag;
+ eSnapMode snap_to_flag;
bool has_occlusion_plane; /* Ignore plane of occlusion in curves. */
} runtime;
};
@@ -283,8 +283,10 @@ static SnapData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx,
}
}
else {
- /* Any existing #SnapData_EditMesh is now invalid. */
- sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
+ if (ob_eval->type == OB_MESH) {
+ /* Any existing #SnapData_EditMesh is now invalid. */
+ sctx->editmesh_caches.remove(BKE_editmesh_from_object(ob_eval));
+ }
std::unique_ptr<SnapData_Mesh> sod_ptr = std::make_unique<SnapData_Mesh>();
sod = sod_ptr.get();
@@ -403,6 +405,62 @@ static SnapData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
return sod;
}
+static BVHTreeFromMesh *snap_object_data_mesh_treedata_get(SnapObjectContext *sctx,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ bool use_hide)
+{
+ SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
+ return &sod->treedata_mesh;
+}
+
+static BVHTreeFromEditMesh *snap_object_data_editmesh_treedata_get(SnapObjectContext *sctx,
+ Object *ob_eval,
+ BMEditMesh *em)
+{
+ SnapData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
+
+ BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh;
+
+ if (treedata->tree == nullptr) {
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BLI_assert(sod->treedata_editmesh.em ==
+ BKE_editmesh_from_object(DEG_get_original_object(ob_eval)));
+ em = sod->treedata_editmesh.em;
+
+ if (sctx->callbacks.edit_mesh.test_face_fn) {
+ BMesh *bm = em->bm;
+ BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri);
+
+ BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
+ int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
+ bm,
+ elem_mask,
+ sctx->callbacks.edit_mesh.test_face_fn,
+ sctx->callbacks.edit_mesh.user_data);
+
+ bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6);
+
+ MEM_freeN(elem_mask);
+ }
+ else {
+ /* Only cache if BVH-tree is created without a mask.
+ * This helps keep a standardized BVH-tree in cache. */
+ BKE_bvhtree_from_editmesh_get(treedata,
+ em,
+ 4,
+ BVHTREE_FROM_EM_LOOPTRI,
+ &sod->mesh_runtime->bvh_cache,
+ static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
+ }
+ }
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return nullptr;
+ }
+
+ return treedata;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -417,16 +475,16 @@ using IterSnapObjsCallback = void (*)(SnapObjectContext *sctx,
void *data);
static bool snap_object_is_snappable(const SnapObjectContext *sctx,
- const eSnapSelect snap_select,
+ const eSnapTargetSelect snap_target_select,
const Base *base_act,
- const Base *base,
- const bool is_in_object_mode)
+ const Base *base)
{
if (!BASE_VISIBLE(sctx->runtime.v3d, base)) {
return false;
}
- if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
+ if ((snap_target_select == SCE_SNAP_TARGET_ALL) ||
+ (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
return true;
}
@@ -434,25 +492,37 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx,
return false;
}
- if (snap_select == SNAP_NOT_ACTIVE) {
- return base_act != base;
- }
+ /* Get attributes of potential target. */
+ const bool is_active = (base_act == base);
+ const bool is_selected = (base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL);
+ const bool is_edited = (base->object->mode == OB_MODE_EDIT);
+ const bool is_selectable = (base->flag & BASE_SELECTABLE);
+ /* Get attributes of state. */
+ const bool is_in_object_mode = (base_act == NULL) || (base_act->object->mode == OB_MODE_OBJECT);
- if (snap_select == SNAP_NOT_EDITED) {
- return base->object->mode != OB_MODE_EDIT;
+ if (is_in_object_mode) {
+ /* Handle target selection options that make sense for object mode. */
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED) && is_selected) {
+ /* What is selectable or not is part of the object and depends on the mode. */
+ return false;
+ }
}
-
- if (snap_select == SNAP_NOT_SELECTED) {
- if (is_in_object_mode) {
- return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL));
+ else {
+ /* Handle target selection options that make sense for edit/pose mode. */
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_ACTIVE) && is_active) {
+ return false;
+ }
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_EDITED) && is_edited && !is_active) {
+ /* Base is edited, but not active. */
+ return false;
+ }
+ if ((snap_target_select & SCE_SNAP_TARGET_NOT_NONEDITED) && !is_edited) {
+ return false;
}
-
- /* What is selectable or not is part of the object and depends on the mode. */
- return true;
}
- if (snap_select == SNAP_SELECTABLE) {
- return (base->flag & BASE_SELECTABLE) != 0;
+ if ((snap_target_select & SCE_SNAP_TARGET_ONLY_SELECTABLE) && !is_selectable) {
+ return false;
}
return true;
@@ -467,12 +537,11 @@ static void iter_snap_objects(SnapObjectContext *sctx,
void *data)
{
ViewLayer *view_layer = DEG_get_input_view_layer(sctx->runtime.depsgraph);
- const eSnapSelect snap_select = params->snap_select;
-
+ const eSnapTargetSelect snap_target_select = params->snap_target_select;
Base *base_act = view_layer->basact;
- const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT;
+
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
- if (!snap_object_is_snappable(sctx, snap_select, base_act, base, is_in_object_mode)) {
+ if (!snap_object_is_snappable(sctx, snap_target_select, base_act, base)) {
continue;
}
@@ -848,40 +917,9 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
len_diff = 0.0f;
}
- BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh;
-
- if (treedata->tree == nullptr) {
- em = sod->treedata_editmesh.em;
-
- if (sctx->callbacks.edit_mesh.test_face_fn) {
- BMesh *bm = em->bm;
- BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri);
-
- BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
- int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
- bm,
- elem_mask,
- sctx->callbacks.edit_mesh.test_face_fn,
- sctx->callbacks.edit_mesh.user_data);
-
- bvhtree_from_editmesh_looptri_ex(treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6);
-
- MEM_freeN(elem_mask);
- }
- else {
- /* Only cache if bvhtree is created without a mask.
- * This helps keep a standardized bvhtree in cache. */
- BKE_bvhtree_from_editmesh_get(treedata,
- em,
- 4,
- BVHTREE_FROM_EM_LOOPTRI,
- &sod->mesh_runtime->bvh_cache,
- static_cast<ThreadMutex *>(sod->mesh_runtime->eval_mutex));
- }
-
- if (treedata->tree == nullptr) {
- return retval;
- }
+ BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em);
+ if (treedata == nullptr) {
+ return retval;
}
float timat[3][3]; /* transpose inverse matrix for normals */
@@ -1096,7 +1134,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
* \param r_loc: Hit location.
* \param r_no: Hit normal (optional).
* \param r_index: Hit index or -1 when no valid index is found.
- * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`).
+ * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
@@ -1148,6 +1186,324 @@ static bool raycastObjects(SnapObjectContext *sctx,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Surface Snap Funcs
+ * \{ */
+
+struct NearestWorldObjUserData {
+ const float *init_co;
+ const float *curr_co;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ float r_dist_sq;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ ListBase *r_hit_list;
+ bool ret;
+};
+
+static void nearest_world_tree_co(BVHTree *tree,
+ BVHTree_NearestPointCallback nearest_cb,
+ void *treedata,
+ float co[3],
+ float r_co[3],
+ float r_no[3],
+ int *r_index,
+ float *r_dist_sq)
+{
+ BVHTreeNearest nearest = {};
+ nearest.index = -1;
+ copy_v3_fl(nearest.co, FLT_MAX);
+ nearest.dist_sq = FLT_MAX;
+
+ BLI_bvhtree_find_nearest(tree, co, &nearest, nearest_cb, treedata);
+
+ if (r_co) {
+ copy_v3_v3(r_co, nearest.co);
+ }
+ if (r_no) {
+ copy_v3_v3(r_no, nearest.no);
+ }
+ if (r_index) {
+ *r_index = nearest.index;
+ }
+ if (r_dist_sq) {
+ float diff[3];
+ sub_v3_v3v3(diff, co, nearest.co);
+ *r_dist_sq = len_squared_v3(diff);
+ }
+}
+
+static bool nearest_world_tree(SnapObjectContext *UNUSED(sctx),
+ const struct SnapObjectParams *params,
+ BVHTree *tree,
+ BVHTree_NearestPointCallback nearest_cb,
+ void *treedata,
+ const float (*obmat)[4],
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ if (curr_co == nullptr || init_co == nullptr) {
+ /* No location to work with, so just return. */
+ return false;
+ }
+
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+
+ float timat[3][3]; /* transpose inverse matrix for normals */
+ transpose_m3_m4(timat, imat);
+
+ /* compute offset between init co and prev co in local space */
+ float init_co_local[3], curr_co_local[3];
+ float delta_local[3];
+ mul_v3_m4v3(init_co_local, imat, init_co);
+ mul_v3_m4v3(curr_co_local, imat, curr_co);
+ sub_v3_v3v3(delta_local, curr_co_local, init_co_local);
+
+ float dist_sq;
+ if (params->keep_on_same_target) {
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, init_co_local, nullptr, nullptr, nullptr, &dist_sq);
+ }
+ else {
+ /* NOTE: when `params->face_nearest_steps == 1`, the return variables of function below contain
+ * the answer. We could return immediately after updating r_loc, r_no, r_index, but that would
+ * also complicate the code. Foregoing slight optimization for code clarity. */
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, curr_co_local, nullptr, nullptr, nullptr, &dist_sq);
+ }
+ if (*r_dist_sq <= dist_sq) {
+ return false;
+ }
+ *r_dist_sq = dist_sq;
+
+ /* scale to make `snap_face_nearest_steps` steps */
+ float step_scale_factor = 1.0f / max_ff(1.0f, (float)params->face_nearest_steps);
+ mul_v3_fl(delta_local, step_scale_factor);
+
+ float co_local[3];
+ float no_local[3];
+ int index;
+
+ copy_v3_v3(co_local, init_co_local);
+
+ for (int i = 0; i < params->face_nearest_steps; i++) {
+ add_v3_v3(co_local, delta_local);
+ nearest_world_tree_co(
+ tree, nearest_cb, treedata, co_local, co_local, no_local, &index, nullptr);
+ }
+
+ mul_v3_m4v3(r_loc, obmat, co_local);
+
+ if (r_no) {
+ mul_v3_m3v3(r_no, timat, no_local);
+ normalize_v3(r_no);
+ }
+
+ if (r_index) {
+ *r_index = index;
+ }
+
+ return true;
+}
+
+static bool nearest_world_mesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ const float (*obmat)[4],
+ bool use_hide,
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ BVHTreeFromMesh *treedata = snap_object_data_mesh_treedata_get(sctx, ob_eval, me_eval, use_hide);
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return false;
+ }
+
+ return nearest_world_tree(sctx,
+ params,
+ treedata->tree,
+ treedata->nearest_callback,
+ treedata,
+ obmat,
+ init_co,
+ curr_co,
+ r_dist_sq,
+ r_loc,
+ r_no,
+ r_index);
+}
+
+static bool nearest_world_editmesh(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ BMEditMesh *em,
+ const float (*obmat)[4],
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_dist_sq,
+ float *r_loc,
+ float *r_no,
+ int *r_index)
+{
+ BVHTreeFromEditMesh *treedata = snap_object_data_editmesh_treedata_get(sctx, ob_eval, em);
+ if (treedata == nullptr || treedata->tree == nullptr) {
+ return false;
+ }
+
+ return nearest_world_tree(sctx,
+ params,
+ treedata->tree,
+ treedata->nearest_callback,
+ treedata,
+ obmat,
+ init_co,
+ curr_co,
+ r_dist_sq,
+ r_loc,
+ r_no,
+ r_index);
+}
+static void nearest_world_object_fn(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ bool is_object_active,
+ void *data)
+{
+ struct NearestWorldObjUserData *dt = static_cast<NearestWorldObjUserData *>(data);
+
+ bool retval = false;
+ switch (ob_eval->type) {
+ case OB_MESH: {
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
+ bool use_hide = false;
+ const Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
+ if (me_eval) {
+ retval = nearest_world_mesh(sctx,
+ params,
+ ob_eval,
+ me_eval,
+ obmat,
+ use_hide,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ else {
+ BMEditMesh *em = BKE_editmesh_from_object(ob_eval);
+ BLI_assert_msg(em == BKE_editmesh_from_object(DEG_get_original_object(ob_eval)),
+ "Make sure there is only one pointer for looptris");
+ retval = nearest_world_editmesh(sctx,
+ params,
+ ob_eval,
+ em,
+ obmat,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ break;
+ }
+ case OB_CURVES_LEGACY:
+ case OB_SURF:
+ case OB_FONT:
+ if (!is_object_active) {
+ const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
+ if (me_eval) {
+ retval = nearest_world_mesh(sctx,
+ params,
+ ob_eval,
+ me_eval,
+ obmat,
+ false,
+ dt->init_co,
+ dt->curr_co,
+ &dt->r_dist_sq,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ }
+ }
+ break;
+ }
+
+ if (retval) {
+ if (dt->r_ob) {
+ *dt->r_ob = ob_eval;
+ }
+ if (dt->r_obmat) {
+ copy_m4_m4(dt->r_obmat, obmat);
+ }
+ dt->ret = true;
+ }
+}
+
+/**
+ * Main Nearest World Surface Function
+ * ===================================
+ *
+ * Walks through all objects in the scene to find the nearest location on target surface.
+ *
+ * \param sctx: Snap context to store data.
+ * \param params: Settings for snapping.
+ * \param init_co: Initial location of source point.
+ * \param prev_co: Current location of source point after transformation but before snapping.
+ *
+ * Output Args
+ * -----------
+ *
+ * \param r_loc: Location of nearest point on target surface.
+ * \param r_no: Normal of nearest point on target surface.
+ * \param r_index: Index of nearest polygon on target surface.
+ * \param r_ob: Nearest target object.
+ * \param r_obmat: Nearest target matrix (may not be #Object.obmat with dupli-instances).
+ */
+static bool nearestWorldObjects(SnapObjectContext *sctx,
+ const struct SnapObjectParams *params,
+ const float init_co[3],
+ const float curr_co[3],
+ float *r_loc /* NOLINT */,
+ float *r_no /* NOLINT */,
+ int *r_index /* NOLINT */,
+ Object **r_ob,
+ float r_obmat[4][4])
+{
+ NearestWorldObjUserData data = {};
+ data.init_co = init_co;
+ data.curr_co = curr_co;
+ data.r_loc = r_loc;
+ data.r_no = r_no;
+ data.r_index = r_index;
+ data.r_dist_sq = FLT_MAX;
+ data.r_ob = r_ob;
+ data.r_obmat = r_obmat;
+ data.ret = false;
+
+ iter_snap_objects(sctx, params, nearest_world_object_fn, &data);
+ return data.ret;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Snap Nearest utilities
* \{ */
@@ -1533,18 +1889,18 @@ static void nearest2d_data_init_editmesh(SnapData_EditMesh *sod,
/** \name Internal Object Snapping API
* \{ */
-static short snap_mesh_polygon(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snap_mesh_polygon(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- short elem = 0;
+ eSnapMode elem = SCE_SNAP_MODE_NONE;
float lpmat[4][4];
mul_m4_m4m4(lpmat, sctx->runtime.pmat, obmat);
@@ -1663,23 +2019,23 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- float original_dist_px,
- const float prev_co[3],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ float original_dist_px,
+ const float prev_co[3],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- short elem = SCE_SNAP_MODE_EDGE;
+ eSnapMode elem = SCE_SNAP_MODE_EDGE;
if (ob_eval->type != OB_MESH) {
return elem;
@@ -1826,21 +2182,22 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
return elem;
}
-static short snapArmature(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- bool is_object_active,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snapArmature(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ bool is_object_active,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
- if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE) { /* Currently only edge and vert */
+ if (sctx->runtime.snap_to_flag == SCE_SNAP_MODE_FACE_RAYCAST) {
+ /* Currently only edge and vert */
return retval;
}
@@ -1875,7 +2232,7 @@ static short snapArmature(SnapObjectContext *sctx,
const bool is_posemode = is_object_active && (ob_eval->mode & OB_MODE_POSE);
const bool skip_selected = (is_editmode || is_posemode) &&
- (params->snap_select == SNAP_NOT_SELECTED);
+ (params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED);
const bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
if (arm->edbo) {
@@ -1990,25 +2347,25 @@ static short snapArmature(SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapCurve(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snapCurve(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
bool has_snap = false;
/* only vertex snapping mode (eg control points and handles) supported for now) */
if ((sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
Curve *cu = static_cast<Curve *>(ob_eval->data);
@@ -2032,7 +2389,7 @@ static short snapCurve(SnapObjectContext *sctx,
sctx->runtime.win_size,
sctx->runtime.mval,
dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
@@ -2054,7 +2411,7 @@ static short snapCurve(SnapObjectContext *sctx,
}
bool is_persp = sctx->runtime.view_proj == VIEW_PROJ_PERSP;
- bool skip_selected = params->snap_select == SNAP_NOT_SELECTED;
+ bool skip_selected = params->snap_target_select & SCE_SNAP_TARGET_NOT_SELECTED;
LISTBASE_FOREACH (Nurb *, nu, (use_obedit ? &cu->editnurb->nurbs : &cu->nurb)) {
for (int u = 0; u < nu->pntsu; u++) {
@@ -2077,11 +2434,14 @@ static short snapCurve(SnapObjectContext *sctx,
nu->bezt[u].vec[1],
&dist_px_sq,
r_loc);
+
/* Don't snap if handle is selected (moving),
* or if it is aligning to a moving handle. */
- is_selected = (!(nu->bezt[u].f1 & SELECT) &&
- !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) != 0;
- if (!(is_selected && skip_selected)) {
+ bool is_selected_h1 = (nu->bezt[u].f1 & SELECT) != 0;
+ bool is_selected_h2 = (nu->bezt[u].f3 & SELECT) != 0;
+ bool is_autoalign_h1 = (nu->bezt[u].h1 & HD_ALIGN) != 0;
+ bool is_autoalign_h2 = (nu->bezt[u].h2 & HD_ALIGN) != 0;
+ if (!skip_selected || !(is_selected_h1 || (is_autoalign_h1 && is_selected_h2))) {
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2091,9 +2451,7 @@ static short snapCurve(SnapObjectContext *sctx,
r_loc);
}
- is_selected = (!(nu->bezt[u].f3 & SELECT) &&
- !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) != 0;
- if (!(is_selected && skip_selected)) {
+ if (!skip_selected || !(is_selected_h2 || (is_autoalign_h2 && is_selected_h1))) {
has_snap |= test_projected_vert_dist(&neasrest_precalc,
clip_planes_local,
clip_plane_len,
@@ -2159,21 +2517,21 @@ static short snapCurve(SnapObjectContext *sctx,
return SCE_SNAP_MODE_VERTEX;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
/* may extend later (for now just snaps to empty center) */
-static short snap_object_center(const SnapObjectContext *sctx,
- Object *ob_eval,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *UNUSED(r_no),
- int *r_index)
+static eSnapMode snap_object_center(const SnapObjectContext *sctx,
+ Object *ob_eval,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *UNUSED(r_no),
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
if (ob_eval->transflag & OB_DUPLI) {
return retval;
@@ -2215,20 +2573,20 @@ static short snap_object_center(const SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapCamera(const SnapObjectContext *sctx,
- Object *object,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float *r_no,
- int *r_index)
+static eSnapMode snapCamera(const SnapObjectContext *sctx,
+ Object *object,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float *r_no,
+ int *r_index)
{
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
Scene *scene = sctx->scene;
@@ -2265,7 +2623,7 @@ static short snapCamera(const SnapObjectContext *sctx,
if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) {
BKE_tracking_camera_get_reconstructed_interpolate(
- tracking, tracking_object, CFRA, reconstructed_camera_mat);
+ tracking, tracking_object, scene->r.cfra, reconstructed_camera_mat);
invert_m4_m4(reconstructed_camera_imat, reconstructed_camera_mat);
}
@@ -2309,28 +2667,28 @@ static short snapCamera(const SnapObjectContext *sctx,
return retval;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapMesh(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- const Mesh *me_eval,
- const float obmat[4][4],
- bool use_hide,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snapMesh(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ const Mesh *me_eval,
+ const float obmat[4][4],
+ bool use_hide,
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
+ BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST);
if (me_eval->totvert == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
if (me_eval->totedge == 0 && !(sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
float lpmat[4][4];
@@ -2343,7 +2701,7 @@ static short snapMesh(SnapObjectContext *sctx,
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;
+ return SCE_SNAP_MODE_NONE;
}
SnapData_Mesh *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
@@ -2384,7 +2742,7 @@ static short snapMesh(SnapObjectContext *sctx,
nearest.dist_sq = dist_px_sq;
int last_index = nearest.index;
- short elem = SCE_SNAP_MODE_VERTEX;
+ eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
@@ -2488,31 +2846,31 @@ static short snapMesh(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
-static short snapEditMesh(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- Object *ob_eval,
- BMEditMesh *em,
- const float obmat[4][4],
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index)
+static eSnapMode snapEditMesh(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ Object *ob_eval,
+ BMEditMesh *em,
+ const float obmat[4][4],
+ /* read/write args */
+ float *dist_px,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ int *r_index)
{
- BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE);
+ BLI_assert(sctx->runtime.snap_to_flag != SCE_SNAP_MODE_FACE_RAYCAST);
- if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE) == SCE_SNAP_MODE_VERTEX) {
+ if ((sctx->runtime.snap_to_flag & ~SCE_SNAP_MODE_FACE_RAYCAST) == SCE_SNAP_MODE_VERTEX) {
if (em->bm->totvert == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
else {
if (em->bm->totedge == 0) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
}
@@ -2528,7 +2886,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!snap_bound_box_check_dist(
sod->min, sod->max, lpmat, sctx->runtime.win_size, sctx->runtime.mval, dist_px_sq)) {
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
if (sctx->runtime.snap_to_flag & SCE_SNAP_MODE_VERTEX) {
@@ -2603,7 +2961,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
nearest.index = -1;
nearest.dist_sq = dist_px_sq;
- short elem = SCE_SNAP_MODE_VERTEX;
+ eSnapMode elem = SCE_SNAP_MODE_VERTEX;
float tobmat[4][4], clip_planes_local[MAX_CLIPPLANE_LEN][4];
transpose_m4_m4(tobmat, obmat);
@@ -2669,7 +3027,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
return elem;
}
- return 0;
+ return SCE_SNAP_MODE_NONE;
}
struct SnapObjUserData {
@@ -2681,7 +3039,7 @@ struct SnapObjUserData {
int *r_index;
Object **r_ob;
float (*r_obmat)[4];
- short ret;
+ eSnapMode ret;
};
/**
@@ -2695,7 +3053,7 @@ static void snap_obj_fn(SnapObjectContext *sctx,
void *data)
{
SnapObjUserData *dt = static_cast<SnapObjUserData *>(data);
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
switch (ob_eval->type) {
case OB_MESH: {
@@ -2742,11 +3100,8 @@ static void snap_obj_fn(SnapObjectContext *sctx,
dt->r_index);
break;
case OB_CURVES_LEGACY:
- 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:
- if (BKE_object_is_in_editmode(ob_eval)) {
+ if (ob_eval->type == OB_CURVES_LEGACY || BKE_object_is_in_editmode(ob_eval)) {
retval = snapCurve(
sctx, params, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
if (params->edit_mode_type != SNAP_GEOM_FINAL) {
@@ -2811,22 +3166,22 @@ static void snap_obj_fn(SnapObjectContext *sctx,
* \param r_loc: Hit location.
* \param r_no: Hit normal (optional).
* \param r_index: Hit index or -1 when no valid index is found.
- * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE`).
+ * (currently only set to the polygon index when using `snap_to == SCE_SNAP_MODE_FACE_RAYCAST`).
* \param r_ob: Hit object.
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
-static short snapObjectsRay(SnapObjectContext *sctx,
- const SnapObjectParams *params,
- /* read/write args */
- /* Parameters below cannot be const, because they are assigned to a
- * non-const variable (readability-non-const-parameter). */
- float *dist_px /* NOLINT */,
- /* return args */
- float r_loc[3] /* NOLINT */,
- float r_no[3] /* NOLINT */,
- int *r_index /* NOLINT */,
- Object **r_ob,
- float r_obmat[4][4])
+static eSnapMode snapObjectsRay(SnapObjectContext *sctx,
+ const SnapObjectParams *params,
+ /* read/write args */
+ /* Parameters below cannot be const, because they are assigned to a
+ * non-const variable (readability-non-const-parameter). */
+ float *dist_px /* NOLINT */,
+ /* return args */
+ float r_loc[3] /* NOLINT */,
+ float r_no[3] /* NOLINT */,
+ int *r_index /* NOLINT */,
+ Object **r_ob,
+ float r_obmat[4][4])
{
SnapObjUserData data = {};
data.dist_px = dist_px;
@@ -2835,7 +3190,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
data.r_ob = r_ob;
data.r_index = r_index;
data.r_obmat = r_obmat;
- data.ret = 0;
+ data.ret = SCE_SNAP_MODE_NONE;
iter_snap_objects(sctx, params, snap_obj_fn, &data);
@@ -3008,31 +3363,30 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
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 SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3])
+static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to_flag,
+ const SnapObjectParams *params,
+ const float init_co[3],
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ Object **r_ob,
+ 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);
+ BLI_assert((snap_to_flag & SCE_SNAP_MODE_GEOM) != 0);
- short retval = 0;
+ eSnapMode retval = SCE_SNAP_MODE_NONE;
bool has_hit = false;
Object *ob_eval = nullptr;
@@ -3047,11 +3401,36 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d);
- if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
+ /* Note: if both face raycast and face nearest are enabled, first find result of nearest, then
+ * override with raycast. */
+ if ((snap_to_flag & SCE_SNAP_MODE_FACE_NEAREST) && !has_hit) {
+ has_hit = nearestWorldObjects(
+ sctx, params, init_co, prev_co, loc, no, &index, &ob_eval, obmat);
+
+ if (has_hit) {
+ retval = SCE_SNAP_MODE_FACE_NEAREST;
+
+ 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;
+ }
+ }
+ }
+
+ if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST || use_occlusion_test) {
float ray_start[3], ray_normal[3];
if (!ED_view3d_win_to_ray_clipped_ex(
depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) {
- return 0;
+ return retval;
}
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
@@ -3073,8 +3452,8 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
copy_v3_v3(r_face_nor, no);
}
- if ((snap_to_flag & SCE_SNAP_MODE_FACE)) {
- retval = SCE_SNAP_MODE_FACE;
+ if ((snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST)) {
+ retval = SCE_SNAP_MODE_FACE_RAYCAST;
copy_v3_v3(r_loc, loc);
if (r_no) {
@@ -3095,7 +3474,7 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
if (snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
- short elem_test, elem = 0;
+ eSnapMode elem_test, elem = SCE_SNAP_MODE_NONE;
float dist_px_tmp = *dist_px;
copy_m4_m4(sctx->runtime.pmat, rv3d->persmat);
@@ -3105,9 +3484,11 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
sctx->runtime.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
/* First snap to edge instead of middle or perpendicular. */
- sctx->runtime.snap_to_flag = snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE);
+ sctx->runtime.snap_to_flag = static_cast<eSnapMode>(
+ 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)) {
- sctx->runtime.snap_to_flag |= SCE_SNAP_MODE_EDGE;
+ sctx->runtime.snap_to_flag = static_cast<eSnapMode>(sctx->runtime.snap_to_flag |
+ SCE_SNAP_MODE_EDGE);
}
planes_from_projmat(sctx->runtime.pmat,
@@ -3179,10 +3560,6 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
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;
}
@@ -3191,21 +3568,22 @@ static short transform_snap_context_project_view3d_mixed_impl(SnapObjectContext
return retval;
}
-short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- float r_face_nor[3])
+eSnapMode ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const SnapObjectParams *params,
+ const float init_co[3],
+ const float mval[2],
+ const float prev_co[3],
+ float *dist_px,
+ float r_loc[3],
+ float r_no[3],
+ int *r_index,
+ Object **r_ob,
+ float r_obmat[4][4],
+ float r_face_nor[3])
{
return transform_snap_context_project_view3d_mixed_impl(sctx,
depsgraph,
@@ -3213,6 +3591,7 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
v3d,
snap_to,
params,
+ init_co,
mval,
prev_co,
dist_px,
@@ -3224,17 +3603,18 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
r_face_nor);
}
-short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
- Depsgraph *depsgraph,
- const ARegion *region,
- const View3D *v3d,
- const ushort snap_to,
- const SnapObjectParams *params,
- const float mval[2],
- const float prev_co[3],
- float *dist_px,
- float r_loc[3],
- float r_no[3])
+eSnapMode ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const eSnapMode snap_to,
+ const SnapObjectParams *params,
+ const float init_co[3],
+ 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,
@@ -3242,6 +3622,7 @@ short ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
v3d,
snap_to,
params,
+ init_co,
mval,
prev_co,
dist_px,
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index 7dc361ff5bb..5ac526b1e91 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -25,6 +25,7 @@
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "transform.h"
#include "transform_snap.h"
@@ -58,21 +59,23 @@ static int cmp_fn(const void *a, const void *b)
return (*(int *)a - *(int *)b);
}
-static void seq_snap_source_points_build(TransSeqSnapData *snap_data, SeqCollection *snap_sources)
+static void seq_snap_source_points_build(const Scene *scene,
+ TransSeqSnapData *snap_data,
+ SeqCollection *snap_sources)
{
int i = 0;
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, snap_sources) {
int left = 0, right = 0;
if (seq->flag & SEQ_LEFTSEL) {
- left = right = seq->startdisp;
+ left = right = SEQ_time_left_handle_frame_get(scene, seq);
}
else if (seq->flag & SEQ_RIGHTSEL) {
- left = right = seq->enddisp;
+ left = right = SEQ_time_right_handle_frame_get(scene, seq);
}
else {
- left = seq->startdisp;
- right = seq->enddisp;
+ left = SEQ_time_left_handle_frame_get(scene, seq);
+ right = SEQ_time_right_handle_frame_get(scene, seq);
}
snap_data->source_snap_points[i] = left;
@@ -91,7 +94,8 @@ static void seq_snap_source_points_build(TransSeqSnapData *snap_data, SeqCollect
* \{ */
/* Add effect strips directly or indirectly connected to `seq_reference` to `collection`. */
-static void query_strip_effects_fn(Sequence *seq_reference,
+static void query_strip_effects_fn(const Scene *scene,
+ Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
{
@@ -102,7 +106,7 @@ static void query_strip_effects_fn(Sequence *seq_reference,
/* Find all strips connected to `seq_reference`. */
LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
if (SEQ_relation_is_effect_of_strip(seq_test, seq_reference)) {
- query_strip_effects_fn(seq_test, seqbase, collection);
+ query_strip_effects_fn(scene, seq_test, seqbase, collection);
}
}
}
@@ -144,7 +148,7 @@ static SeqCollection *query_snap_targets(Scene *scene,
/* Effects will always change position with strip to which they are connected and they don't have
* to be selected. Remove such strips from `snap_targets` collection. */
SeqCollection *snap_sources_temp = SEQ_collection_duplicate(snap_sources);
- SEQ_collection_expand(seqbase, snap_sources_temp, query_strip_effects_fn);
+ SEQ_collection_expand(scene, seqbase, snap_sources_temp, query_strip_effects_fn);
SeqCollection *snap_sources_effects = seq_collection_extract_effects(snap_sources_temp);
SEQ_collection_exclude(snap_targets, snap_sources_effects);
SEQ_collection_free(snap_sources_temp);
@@ -187,27 +191,31 @@ static void seq_snap_target_points_build(Scene *scene,
int i = 0;
if (snap_mode & SEQ_SNAP_TO_CURRENT_FRAME) {
- snap_data->target_snap_points[i] = CFRA;
+ snap_data->target_snap_points[i] = scene->r.cfra;
i++;
}
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, snap_targets) {
- snap_data->target_snap_points[i] = seq->startdisp;
- snap_data->target_snap_points[i + 1] = seq->enddisp;
+ snap_data->target_snap_points[i] = SEQ_time_left_handle_frame_get(scene, seq);
+ snap_data->target_snap_points[i + 1] = SEQ_time_right_handle_frame_get(scene, seq);
i += 2;
if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) {
- int content_start = min_ii(seq->enddisp, seq->start);
- int content_end = max_ii(seq->startdisp, seq->start + seq->len);
+ int content_start = min_ii(SEQ_time_right_handle_frame_get(scene, seq), seq->start);
+ int content_end = max_ii(SEQ_time_left_handle_frame_get(scene, seq), 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) {
- content_start = seq->startdisp;
- content_end = seq->enddisp;
+ content_start = SEQ_time_left_handle_frame_get(scene, seq);
+ content_end = SEQ_time_right_handle_frame_get(scene, seq);
}
- CLAMP(content_start, seq->startdisp, seq->enddisp);
- CLAMP(content_end, seq->startdisp, seq->enddisp);
+ CLAMP(content_start,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ SEQ_time_right_handle_frame_get(scene, seq));
+ CLAMP(content_end,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ SEQ_time_right_handle_frame_get(scene, seq));
snap_data->target_snap_points[i] = content_start;
snap_data->target_snap_points[i + 1] = content_end;
@@ -256,7 +264,7 @@ TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t)
/* Build arrays of snap points. */
seq_snap_source_points_alloc(snap_data, snap_sources);
- seq_snap_source_points_build(snap_data, snap_sources);
+ seq_snap_source_points_build(scene, snap_data, snap_sources);
SEQ_collection_free(snap_sources);
short snap_mode = t->tsnap.mode;
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 5c2a3374aa1..cdfe40c7d35 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -91,6 +91,7 @@ set(SRC
../include/ED_uvedit.h
../include/ED_view3d.h
../include/ED_view3d_offscreen.h
+ ../include/UI_abstract_view.hh
../include/UI_grid_view.hh
../include/UI_icons.h
../include/UI_interface.h
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index e7b3bce700e..3cfe6bd61a4 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -41,6 +41,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_paint.h"
+#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_util.h"
@@ -187,6 +188,18 @@ void ED_editors_init(bContext *C)
ED_space_image_paint_update(bmain, wm, scene);
}
+ /* Enforce a full redraw for the first time areas/regions get drawn. Further region init/refresh
+ * just triggers non-rebuild redraws (#RGN_DRAW_NO_REBUILD). Usually a full redraw would be
+ * triggered by a `NC_WM | ND_FILEREAD` notifier, but if a startup script calls an operator that
+ * redraws the window, notifiers are not handled before the operator runs. See T98461. */
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ ED_screen_areas_iter (win, screen, area) {
+ ED_area_tag_redraw(area);
+ }
+ }
+
ED_assetlist_storage_tag_main_data_dirty();
SWAP(int, reports->flag, reports_flag_prev);
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
index cf6f26652a7..fc5fb9f9c28 100644
--- a/source/blender/editors/util/ed_util_imbuf.c
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -291,7 +291,7 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e
Scene *scene = CTX_data_scene(C);
SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
ARegion *region = CTX_wm_region(C);
- ImBuf *ibuf = sequencer_ibuf_get(bmain, region, depsgraph, scene, sseq, CFRA, 0, NULL);
+ ImBuf *ibuf = sequencer_ibuf_get(bmain, region, depsgraph, scene, sseq, scene->r.cfra, 0, NULL);
ImageSampleInfo *info = op->customdata;
float fx, fy;
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index be6ac6e13e6..60cbc2a2df6 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -311,6 +311,7 @@ static bool editstr_is_simple_numinput(const char ascii)
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
{
const char *utf8_buf = NULL;
+ const char event_ascii = WM_event_utf8_to_ascii(event);
char ascii[2] = {'\0', '\0'};
bool updated = false;
short idx = n->idx, idx_max = n->idx_max;
@@ -321,8 +322,8 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
if (U.flag & USER_FLAG_NUMINPUT_ADVANCED)
#endif
{
- if (((event->modifier & (KM_CTRL | KM_ALT)) == 0) && (event->ascii != '\0') &&
- strchr("01234567890@%^&*-+/{}()[]<>.|", event->ascii)) {
+ if (((event->modifier & (KM_CTRL | KM_ALT)) == 0) && (event_ascii != '\0') &&
+ strchr("01234567890@%^&*-+/{}()[]<>.|", event_ascii)) {
if (!(n->flag & NUM_EDIT_FULL)) {
n->flag |= NUM_EDITED;
n->flag |= NUM_EDIT_FULL;
@@ -333,7 +334,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
#ifdef USE_FAKE_EDIT
/* XXX Hack around keyboards without direct access to '=' nor '*'... */
- if (ELEM(event->ascii, '=', '*')) {
+ if (ELEM(event_ascii, '=', '*')) {
if (!(n->flag & NUM_EDIT_FULL)) {
n->flag |= NUM_EDIT_FULL;
n->val_flag[idx] |= NUM_EDITED;
@@ -357,7 +358,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
else {
/* might be a char too... */
utf8_buf = event->utf8_buf;
- ascii[0] = event->ascii;
+ ascii[0] = event_ascii;
}
break;
case EVT_BACKSPACEKEY:
@@ -523,9 +524,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
break;
}
- if (!updated && !utf8_buf && (event->utf8_buf[0] || event->ascii)) {
+ if (!updated && !utf8_buf && event->utf8_buf[0]) {
utf8_buf = event->utf8_buf;
- ascii[0] = event->ascii;
+ ascii[0] = event_ascii;
}
/* Up to this point, if we have a ctrl modifier, skip.
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
index 263ef06718f..660afa4c3d7 100644
--- a/source/blender/editors/util/select_utils.c
+++ b/source/blender/editors/util/select_utils.c
@@ -66,15 +66,18 @@ eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first)
return sel_op;
}
-int ED_select_similar_compare_float(const float delta, const float thresh, const int compare)
+bool ED_select_similar_compare_float(const float delta,
+ const float thresh,
+ const eSimilarCmp compare)
{
+ BLI_assert(thresh >= 0.0f);
switch (compare) {
case SIM_CMP_EQ:
return (fabsf(delta) <= thresh);
case SIM_CMP_GT:
- return ((delta + thresh) >= 0.0);
+ return ((delta + thresh) >= 0.0f);
case SIM_CMP_LT:
- return ((delta - thresh) <= 0.0);
+ return ((delta - thresh) <= 0.0f);
default:
BLI_assert_unreachable();
return 0;
@@ -84,8 +87,10 @@ int ED_select_similar_compare_float(const float delta, const float thresh, const
bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
const float length,
const float thresh,
- const int compare)
+ const eSimilarCmp compare)
{
+ BLI_assert(compare == SIM_CMP_EQ || length >= 0.0f); /* See precision note below. */
+
/* Length of the edge we want to compare against. */
float nearest_edge_length;
@@ -112,6 +117,7 @@ bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
KDTreeNearest_1d nearest;
if (BLI_kdtree_1d_find_nearest(tree, &nearest_edge_length, &nearest) != -1) {
+ BLI_assert(compare == SIM_CMP_EQ || nearest.co[0] >= 0.0f); /* See precision note above. */
float delta = length - nearest.co[0];
return ED_select_similar_compare_float(delta, thresh, compare);
}
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 181982f0b2c..04128cf378c 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -182,5 +182,6 @@ void UV_OT_select_circle(struct wmOperatorType *ot);
void UV_OT_select_more(struct wmOperatorType *ot);
void UV_OT_select_less(struct wmOperatorType *ot);
void UV_OT_select_overlap(struct wmOperatorType *ot);
+void UV_OT_select_similar(struct wmOperatorType *ot);
/* Used only when UV sync select is disabled. */
void UV_OT_select_mode(struct wmOperatorType *ot);
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index fe6f9f0d513..74a9989f550 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -372,6 +372,198 @@ typedef enum eUVWeldAlign {
UV_WELD,
} eUVWeldAlign;
+static bool uvedit_uv_align_weld(Scene *scene,
+ BMesh *bm,
+ const eUVWeldAlign tool,
+ const float cent[2])
+{
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
+ if (luv->uv[0] != cent[0]) {
+ luv->uv[0] = cent[0];
+ changed = true;
+ }
+ }
+ if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
+ if (luv->uv[1] != cent[1]) {
+ luv->uv[1] = cent[1];
+ changed = true;
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+/** Bitwise-or together, then choose #MLoopUV with highest value. */
+typedef enum eUVEndPointPrecedence {
+ UVEP_INVALID = 0,
+ UVEP_SELECTED = (1 << 0),
+ UVEP_PINNED = (1 << 1), /* i.e. Pinned verts are preferred to selected. */
+} eUVEndPointPrecedence;
+
+static eUVEndPointPrecedence uvedit_line_update_get_precedence(const MLoopUV *luv)
+{
+ eUVEndPointPrecedence precedence = UVEP_SELECTED;
+ if (luv->flag & MLOOPUV_PINNED) {
+ precedence |= UVEP_PINNED;
+ }
+ return precedence;
+}
+
+/**
+ * Helper to find two endpoints (`a` and `b`) which have higher precedence, and are far apart.
+ * Note that is only a heuristic and won't always find the best two endpoints.
+ */
+static bool uvedit_line_update_endpoint(const MLoopUV *luv,
+ float uv_a[2],
+ eUVEndPointPrecedence *prec_a,
+ float uv_b[2],
+ eUVEndPointPrecedence *prec_b)
+{
+ eUVEndPointPrecedence flags = uvedit_line_update_get_precedence(luv);
+
+ float len_sq_a = len_squared_v2v2(uv_a, luv->uv);
+ float len_sq_b = len_squared_v2v2(uv_b, luv->uv);
+
+ /* Caching the value of `len_sq_ab` is unlikely to be faster than recalculating.
+ * Profile before optimizing. */
+ float len_sq_ab = len_squared_v2v2(uv_a, uv_b);
+
+ if ((*prec_a < flags && 0.0f < len_sq_b) || (*prec_a == flags && len_sq_ab < len_sq_b)) {
+ *prec_a = flags;
+ copy_v2_v2(uv_a, luv->uv);
+ return true;
+ }
+
+ if ((*prec_b < flags && 0.0f < len_sq_a) || (*prec_b == flags && len_sq_ab < len_sq_a)) {
+ *prec_b = flags;
+ copy_v2_v2(uv_b, luv->uv);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Find two end extreme points to specify a line, then straighten `len` elements
+ * by moving UVs on the X-axis, Y-axis, or the closest point on the line segment.
+ */
+static bool uvedit_uv_straighten_elements(const UvElement *element,
+ const int len,
+ const int cd_loop_uv_offset,
+ const eUVWeldAlign tool)
+{
+ float uv_start[2];
+ float uv_end[2];
+ eUVEndPointPrecedence prec_start = UVEP_INVALID;
+ eUVEndPointPrecedence prec_end = UVEP_INVALID;
+
+ /* Find start and end of line. */
+ for (int i = 0; i < 10; i++) { /* Heuristic to prevent infinite loop. */
+ bool update = false;
+ for (int j = 0; j < len; j++) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(element[j].l, cd_loop_uv_offset);
+ update |= uvedit_line_update_endpoint(luv, uv_start, &prec_start, uv_end, &prec_end);
+ }
+ if (!update) {
+ break;
+ }
+ }
+
+ if (prec_start == UVEP_INVALID || prec_end == UVEP_INVALID) {
+ return false; /* Unable to find two endpoints. */
+ }
+
+ float a = 0.0f; /* Similar to "slope". */
+ eUVWeldAlign tool_local = tool;
+
+ if (tool_local == UV_STRAIGHTEN_X) {
+ if (uv_start[1] == uv_end[1]) {
+ /* Caution, different behavior outside line segment. */
+ tool_local = UV_STRAIGHTEN;
+ }
+ else {
+ a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
+ }
+ }
+ else if (tool_local == UV_STRAIGHTEN_Y) {
+ if (uv_start[0] == uv_end[0]) {
+ /* Caution, different behavior outside line segment. */
+ tool_local = UV_STRAIGHTEN;
+ }
+ else {
+ a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
+ }
+ }
+
+ bool changed = false;
+ for (int j = 0; j < len; j++) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(element[j].l, cd_loop_uv_offset);
+ /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
+ * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
+ * Maybe this should be a BLI func? Or is it already existing?
+ * Could use interp_v2_v2v2, but not sure it's worth it here. */
+ if (tool_local == UV_STRAIGHTEN_X) {
+ luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
+ }
+ else if (tool_local == UV_STRAIGHTEN_Y) {
+ luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
+ }
+ else {
+ closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
+ }
+ changed = true; /* TODO: Did the UV actually move? */
+ }
+ return changed;
+}
+
+/**
+ * Group selected UVs into islands, then apply uvedit_uv_straighten_elements to each island.
+ */
+static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool)
+{
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ if (cd_loop_uv_offset == -1) {
+ return false;
+ }
+
+ UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true);
+ if (element_map == NULL) {
+ return false;
+ }
+
+ bool changed = false;
+
+ /* Loop backwards to simplify logic. */
+ int j1 = element_map->totalUVs;
+ for (int i = element_map->totalIslands - 1; i >= 0; --i) {
+ int j0 = element_map->islandIndices[i];
+ changed |= uvedit_uv_straighten_elements(
+ element_map->buf + j0, j1 - j0, cd_loop_uv_offset, tool);
+ j1 = j0;
+ }
+
+ BM_uv_element_map_free(element_map);
+ return changed;
+}
+
static void uv_weld_align(bContext *C, eUVWeldAlign tool)
{
Scene *scene = CTX_data_scene(C);
@@ -429,194 +621,12 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
continue;
}
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[0] = cent[0];
- changed = true;
- }
- }
- }
- }
-
- if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->uv[1] = cent[1];
- changed = true;
- }
- }
- }
+ if (ELEM(tool, UV_ALIGN_AUTO, UV_ALIGN_X, UV_ALIGN_Y, UV_WELD)) {
+ changed |= uvedit_uv_align_weld(scene, em->bm, tool, cent);
}
if (ELEM(tool, UV_STRAIGHTEN, UV_STRAIGHTEN_X, UV_STRAIGHTEN_Y)) {
- BMEdge *eed;
- BMLoop *l;
- BMVert *eve;
- BMVert *eve_start;
- BMIter iter, liter, eiter;
-
- /* clear tag */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- /* tag verts with a selected UV */
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, l->f)) {
- continue;
- }
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- BM_elem_flag_enable(eve, BM_ELEM_TAG);
- break;
- }
- }
- }
-
- /* flush vertex tags to edges */
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(
- eed,
- BM_ELEM_TAG,
- (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
- }
-
- /* find a vertex with only one tagged edge */
- eve_start = NULL;
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- int tot_eed_tag = 0;
- BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
- tot_eed_tag++;
- }
- }
-
- if (tot_eed_tag == 1) {
- eve_start = eve;
- break;
- }
- }
-
- if (eve_start) {
- BMVert **eve_line = NULL;
- BMVert *eve_next = NULL;
- BLI_array_declare(eve_line);
- int i;
-
- eve = eve_start;
-
- /* walk over edges, building an array of verts in a line */
- while (eve) {
- BLI_array_append(eve_line, eve);
- /* don't touch again */
- BM_elem_flag_disable(eve, BM_ELEM_TAG);
-
- eve_next = NULL;
-
- /* find next eve */
- BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
- BMVert *eve_other = BM_edge_other_vert(eed, eve);
- if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
- /* this is a tagged vert we didn't walk over yet, step onto it */
- eve_next = eve_other;
- break;
- }
- }
- }
-
- eve = eve_next;
- }
-
- /* now we have all verts, make into a line */
- if (BLI_array_len(eve_line) > 2) {
-
- /* we know the returns from these must be valid */
- const float *uv_start = uvedit_first_selected_uv_from_vertex(
- scene, eve_line[0], cd_loop_uv_offset);
- const float *uv_end = uvedit_first_selected_uv_from_vertex(
- scene, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset);
- /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
- float a = 0.0f;
- eUVWeldAlign tool_local = tool;
-
- if (tool_local == UV_STRAIGHTEN_X) {
- if (uv_start[1] == uv_end[1]) {
- tool_local = UV_STRAIGHTEN;
- }
- else {
- a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
- }
- }
- else if (tool_local == UV_STRAIGHTEN_Y) {
- if (uv_start[0] == uv_end[0]) {
- tool_local = UV_STRAIGHTEN;
- }
- else {
- a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
- }
- }
-
- /* go over all verts except for endpoints */
- for (i = 0; i < BLI_array_len(eve_line); i++) {
- BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, l->f)) {
- continue;
- }
-
- if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
- * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
- * Maybe this should be a BLI func? Or is it already existing?
- * Could use interp_v2_v2v2, but not sure it's worth it here. */
- if (tool_local == UV_STRAIGHTEN_X) {
- luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
- }
- else if (tool_local == UV_STRAIGHTEN_Y) {
- luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
- }
- else {
- closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
- }
- changed = true;
- }
- }
- }
- }
- else {
- /* error - not a line, needs 3+ points. */
- }
-
- if (eve_line) {
- MEM_freeN(eve_line);
- }
- }
- else {
- /* error - can't find an endpoint. */
- }
+ changed |= uvedit_uv_straighten(scene, em->bm, tool);
}
if (changed) {
@@ -1026,6 +1036,12 @@ static bool uv_snap_cursor_to_selection(Scene *scene,
return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around);
}
+static void uv_snap_cursor_to_origin(float uvco[2])
+{
+ uvco[0] = 0;
+ uvco[1] = 0;
+}
+
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -1048,6 +1064,10 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
MEM_freeN(objects);
break;
}
+ case 2:
+ uv_snap_cursor_to_origin(sima->cursor);
+ changed = true;
+ break;
}
if (!changed) {
@@ -1064,6 +1084,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
static const EnumPropertyItem target_items[] = {
{0, "PIXELS", 0, "Pixels", ""},
{1, "SELECTED", 0, "Selected", ""},
+ {2, "ORIGIN", 0, "Origin", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -2044,6 +2065,7 @@ void ED_operatortypes_uvedit(void)
WM_operatortype_append(UV_OT_select_pinned);
WM_operatortype_append(UV_OT_select_box);
WM_operatortype_append(UV_OT_select_lasso);
+ WM_operatortype_append(UV_OT_select_similar);
WM_operatortype_append(UV_OT_select_circle);
WM_operatortype_append(UV_OT_select_more);
WM_operatortype_append(UV_OT_select_less);
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index ead017a91bf..d59dcb4f4ed 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -12,6 +12,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_image_types.h"
+#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
@@ -22,6 +23,7 @@
#include "BLI_blenlib.h"
#include "BLI_hash.h"
#include "BLI_kdopbvh.h"
+#include "BLI_kdtree.h"
#include "BLI_lasso_2d.h"
#include "BLI_math.h"
#include "BLI_polyfill_2d.h"
@@ -31,6 +33,7 @@
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_report.h"
@@ -75,6 +78,16 @@ static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
const ToolSettings *ts,
Object *obedit);
+typedef enum {
+ UV_SSIM_AREA_UV = 1000,
+ UV_SSIM_AREA_3D,
+ UV_SSIM_LENGTH_UV,
+ UV_SSIM_LENGTH_3D,
+ UV_SSIM_SIDES,
+ UV_SSIM_PIN,
+ UV_SSIM_MATERIAL,
+} eUVSelectSimilar;
+
/* -------------------------------------------------------------------- */
/** \name Active Selection Tracking
*
@@ -586,12 +599,25 @@ bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_lo
if (ts->selectmode & SCE_SELECT_FACE) {
return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
}
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_test(...)` instead? */
+ }
return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
}
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ /* Are you looking for `uvedit_face_select_test(...)` instead? */
+ }
+
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_test(...)` instead? */
+ }
+
return (luv->flag & MLOOPUV_VERTSEL) != 0;
}
+
bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
{
return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
@@ -699,6 +725,10 @@ void uvedit_uv_select_enable(const Scene *scene,
{
const ToolSettings *ts = scene->toolsettings;
+ if (ts->selectmode & SCE_SELECT_EDGE) {
+ /* Are you looking for `uvedit_edge_select_set(...)` instead? */
+ }
+
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (ts->selectmode & SCE_SELECT_FACE) {
BM_face_select_set(em->bm, l->f, true);
@@ -2425,7 +2455,7 @@ static bool uv_mouse_select_multi(bContext *C,
UvNearestHit hit = UV_NEAREST_HIT_INIT_DIST_PX(&region->v2d, 75.0f);
int selectmode, sticky;
bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
int flush = 0;
/* Penalty (in pixels) applied to elements that are already selected
@@ -2514,8 +2544,15 @@ static bool uv_mouse_select_multi(bContext *C,
else if (selectmode == UV_SELECT_EDGE) {
is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset);
}
- else { /* Vertex or island. */
- is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ else {
+ /* Vertex or island. For island (if we were using #uv_find_nearest_face_multi_ex, see above),
+ * `hit.l` is NULL, use `hit.efa` instead. */
+ if (hit.l != NULL) {
+ is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ }
+ else {
+ is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset);
+ }
}
}
@@ -2728,7 +2765,7 @@ static int uv_mouse_select_loop_generic_multi(bContext *C,
const ToolSettings *ts = scene->toolsettings;
UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ /* 0 == don't flush, 1 == sel, -1 == deselect; only use when selection sync is enabled. */
int flush = 0;
/* Find edge. */
@@ -2898,12 +2935,14 @@ void UV_OT_select_edge_ring(wmOperatorType *ot)
ot->poll = ED_operator_uvedit; /* requires space image */
/* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- RNA_def_float_vector(
+ PropertyRNA *prop;
+ prop = RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_float_vector(
ot->srna,
"location",
2,
@@ -2914,6 +2953,7 @@ void UV_OT_select_edge_ring(wmOperatorType *ot)
"Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
-100.0f,
100.0f);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -3282,8 +3322,6 @@ static void uv_select_flush_from_tag_face(const Scene *scene, Object *obedit, co
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (select) {
@@ -3353,8 +3391,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co
/* now select tagged verts */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
@@ -3373,8 +3409,6 @@ static void uv_select_flush_from_tag_loop(const Scene *scene, Object *obedit, co
}
BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
uv_select_flush_from_tag_sticky_loc_internal(
@@ -3548,6 +3582,7 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
}
}
else if (use_edge && !pinned) {
+ bool do_second_pass = true;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, efa)) {
continue;
@@ -3562,11 +3597,35 @@ static int uv_box_select_exec(bContext *C, wmOperator *op)
uvedit_edge_select_set_with_sticky(
scene, em, l_prev, select, false, cd_loop_uv_offset);
changed = true;
+ do_second_pass = false;
}
l_prev = l;
luv_prev = luv;
}
}
+ /* Do a second pass if no complete edges could be selected.
+ * This matches wire-frame edit-mesh selection in the 3D view. */
+ if (do_second_pass) {
+ /* Second pass to check if edges partially overlap with the selection area (box). */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (BLI_rctf_isect_segment(&rectf, luv_prev->uv, luv->uv)) {
+ uvedit_edge_select_set_with_sticky(
+ scene, em, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ l_prev = l;
+ luv_prev = luv;
+ }
+ }
+ }
}
else {
/* other selection modes */
@@ -3886,6 +3945,24 @@ static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region,
return false;
}
+static bool do_lasso_select_mesh_uv_is_edge_inside(const ARegion *region,
+ const rcti *clip_rect,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const float co_test_a[2],
+ const float co_test_b[2])
+{
+ int co_screen_a[2], co_screen_b[2];
+ if (UI_view2d_view_to_region_segment_clip(
+ &region->v2d, co_test_a, co_test_b, co_screen_a, co_screen_b) &&
+ BLI_rcti_isect_segment(clip_rect, co_screen_a, co_screen_b) &&
+ BLI_lasso_is_edge_inside(
+ mcoords, mcoords_len, UNPACK2(co_screen_a), UNPACK2(co_screen_b), V2D_IS_CLIPPED)) {
+ return true;
+ }
+ return false;
+}
+
static bool do_lasso_select_mesh_uv(bContext *C,
const int mcoords[][2],
const int mcoords_len,
@@ -3954,6 +4031,7 @@ static bool do_lasso_select_mesh_uv(bContext *C,
}
}
else if (use_edge) {
+ bool do_second_pass = true;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, efa)) {
continue;
@@ -3970,12 +4048,37 @@ static bool do_lasso_select_mesh_uv(bContext *C,
region, &rect, mcoords, mcoords_len, luv_prev->uv)) {
uvedit_edge_select_set_with_sticky(
scene, em, l_prev, select, false, cd_loop_uv_offset);
+ do_second_pass = false;
changed = true;
}
l_prev = l;
luv_prev = luv;
}
}
+ /* Do a second pass if no complete edges could be selected.
+ * This matches wire-frame edit-mesh selection in the 3D view. */
+ if (do_second_pass) {
+ /* Second pass to check if edges partially overlap with the selection area (lasso). */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev;
+ MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset);
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (do_lasso_select_mesh_uv_is_edge_inside(
+ region, &rect, mcoords, mcoords_len, luv->uv, luv_prev->uv)) {
+ uvedit_edge_select_set_with_sticky(
+ scene, em, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ l_prev = l;
+ luv_prev = luv;
+ }
+ }
+ }
}
else { /* Vert Selection. */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
@@ -4411,6 +4514,550 @@ void UV_OT_select_overlap(wmOperatorType *ot)
}
/** \} */
+/** \name Select Similar Operator
+ * \{ */
+
+static float get_uv_vert_needle(const eUVSelectSimilar type,
+ BMVert *vert,
+ const float ob_m3[3][3],
+ MLoopUV *luv,
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) {
+ result += BM_face_calc_area_uv(f, cd_loop_uv_offset);
+ }
+ } break;
+ case UV_SSIM_AREA_3D: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, vert, BM_FACES_OF_VERT) {
+ result += BM_face_calc_area_with_mat3(f, ob_m3);
+ }
+ } break;
+ case UV_SSIM_SIDES: {
+ BMEdge *e;
+ BMIter iter;
+ BM_ITER_ELEM (e, &iter, vert, BM_EDGES_OF_VERT) {
+ result += 1.0f;
+ }
+ } break;
+ case UV_SSIM_PIN:
+ return (luv->flag & MLOOPUV_PINNED) ? 1.0f : 0.0f;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ return result;
+}
+
+static float get_uv_edge_needle(const eUVSelectSimilar type,
+ BMEdge *edge,
+ const float ob_m3[3][3],
+ MLoopUV *luv_a,
+ MLoopUV *luv_b,
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) {
+ result += BM_face_calc_area_uv(f, cd_loop_uv_offset);
+ }
+ } break;
+ case UV_SSIM_AREA_3D: {
+ BMFace *f;
+ BMIter iter;
+ BM_ITER_ELEM (f, &iter, edge, BM_FACES_OF_EDGE) {
+ result += BM_face_calc_area_with_mat3(f, ob_m3);
+ }
+ } break;
+ case UV_SSIM_LENGTH_UV:
+ return len_v2v2(luv_a->uv, luv_b->uv);
+ case UV_SSIM_LENGTH_3D:
+ return len_v3v3(edge->v1->co, edge->v2->co);
+ case UV_SSIM_SIDES: {
+ BMEdge *e;
+ BMIter iter;
+ BM_ITER_ELEM (e, &iter, edge, BM_FACES_OF_EDGE) {
+ result += 1.0f;
+ }
+ } break;
+ case UV_SSIM_PIN:
+ if (luv_a->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ if (luv_b->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ break;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ return result;
+}
+
+static float get_uv_face_needle(const eUVSelectSimilar type,
+ BMFace *face,
+ const float ob_m3[3][3],
+ const int cd_loop_uv_offset)
+{
+ float result = 0.0f;
+ switch (type) {
+ case UV_SSIM_AREA_UV:
+ return BM_face_calc_area_uv(face, cd_loop_uv_offset);
+ case UV_SSIM_AREA_3D:
+ return BM_face_calc_area_with_mat3(face, ob_m3);
+ case UV_SSIM_SIDES:
+ return face->len;
+ case UV_SSIM_PIN: {
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_PINNED) {
+ result += 1.0f;
+ }
+ }
+ } break;
+ case UV_SSIM_MATERIAL:
+ return face->mat_nr;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+ return result;
+}
+
+static int uv_select_similar_vert_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_verts_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ max_verts_selected_all += face->len;
+ }
+ /* TODO: Get a tighter bounds */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_verts_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset);
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ continue; /* Already selected. */
+ }
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ const float needle = get_uv_vert_needle(type, l->v, ob_m3, luv, cd_loop_uv_offset);
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_uv_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_similar_edge_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_edges_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ max_edges_selected_all += face->len;
+ }
+ /* TODO: Get a tighter bounds. */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_edges_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (!uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset);
+ if (tree_1d) {
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+
+ bool changed = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, face, BM_LOOPS_OF_FACE) {
+ if (uvedit_edge_select_test(scene, l, cd_loop_uv_offset)) {
+ continue; /* Already selected. */
+ }
+
+ MLoopUV *luv_a = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_b = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ float needle = get_uv_edge_needle(type, l->e, ob_m3, luv_a, luv_b, cd_loop_uv_offset);
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_edge_select_set(scene, em, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_similar_face_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+
+ const eUVSelectSimilar type = RNA_enum_get(op->ptr, "type");
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const eSimilarCmp compare = RNA_enum_get(op->ptr, "compare");
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ int max_faces_selected_all = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ max_faces_selected_all += em->bm->totfacesel;
+ /* TODO: Get a tighter bounds */
+ }
+
+ int tree_index = 0;
+ KDTree_1d *tree_1d = BLI_kdtree_1d_new(max_faces_selected_all);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ if (!uvedit_face_select_test(scene, face, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset);
+ if (tree_1d) {
+ BLI_kdtree_1d_insert(tree_1d, tree_index++, &needle);
+ }
+ }
+ }
+
+ if (tree_1d != NULL) {
+ BLI_kdtree_1d_deduplicate(tree_1d);
+ BLI_kdtree_1d_balance(tree_1d);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMesh *bm = em->bm;
+ bool changed = false;
+ bool do_history = false;
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ float ob_m3[3][3];
+ copy_m3_m4(ob_m3, ob->obmat);
+
+ BMFace *face;
+ BMIter iter;
+ BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, face)) {
+ continue;
+ }
+ if (uvedit_face_select_test(scene, face, cd_loop_uv_offset)) {
+ continue;
+ }
+
+ float needle = get_uv_face_needle(type, face, ob_m3, cd_loop_uv_offset);
+
+ bool select = ED_select_similar_compare_float_tree(tree_1d, needle, threshold, compare);
+ if (select) {
+ uvedit_face_select_set(scene, em, face, select, do_history, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, ob);
+ }
+ }
+
+ MEM_SAFE_FREE(objects);
+ BLI_kdtree_1d_free(tree_1d);
+ return OPERATOR_FINISHED;
+}
+
+/* Select similar UV faces/edges/verts based on current selection. */
+static int uv_select_similar_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
+
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set(op->ptr, prop, ts->select_thresh);
+ }
+ else {
+ ts->select_thresh = RNA_property_float_get(op->ptr, prop);
+ }
+
+ int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode;
+ if (selectmode & UV_SELECT_EDGE) {
+ return uv_select_similar_edge_exec(C, op);
+ }
+ if (selectmode & UV_SELECT_FACE) {
+ return uv_select_similar_face_exec(C, op);
+ }
+ if (selectmode & UV_SELECT_ISLAND) {
+ // return uv_select_similar_island_exec(C, op);
+ }
+
+ return uv_select_similar_vert_exec(C, op);
+}
+
+static EnumPropertyItem prop_vert_similar_types[] = {{UV_SSIM_PIN, "PIN", 0, "Pinned", ""}, {0}};
+
+static EnumPropertyItem prop_edge_similar_types[] = {
+ {UV_SSIM_LENGTH_UV, "LENGTH", 0, "Length", ""},
+ {UV_SSIM_LENGTH_3D, "LENGTH_3D", 0, "Length 3D", ""},
+ {UV_SSIM_PIN, "PIN", 0, "Pinned", ""},
+ {0}};
+
+static EnumPropertyItem prop_face_similar_types[] = {
+ {UV_SSIM_AREA_UV, "AREA", 0, "Area", ""},
+ {UV_SSIM_AREA_3D, "AREA_3D", 0, "Area 3D", ""},
+ {UV_SSIM_SIDES, "SIDES", 0, "Polygon Sides", ""},
+ {UV_SSIM_MATERIAL, "MATERIAL", 0, "Material", ""},
+ {0}};
+
+static EnumPropertyItem prop_similar_compare_types[] = {{SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
+ {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
+ {SIM_CMP_LT, "LESS", 0, "Less", ""},
+ {0}};
+
+static const EnumPropertyItem *uv_select_similar_type_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *UNUSED(r_free))
+{
+ const ToolSettings *ts = CTX_data_tool_settings(C);
+ if (ts) {
+ int selectmode = (ts->uv_flag & UV_SYNC_SELECTION) ? ts->selectmode : ts->uv_selectmode;
+ if (selectmode & UV_SELECT_EDGE) {
+ return prop_edge_similar_types;
+ }
+ if (selectmode & UV_SELECT_FACE) {
+ return prop_face_similar_types;
+ }
+ }
+
+ return prop_vert_similar_types;
+}
+void UV_OT_select_similar(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Similar";
+ ot->description = "Select similar UVs by property types";
+ ot->idname = "UV_OT_select_similar";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = uv_select_similar_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ PropertyRNA *prop = ot->prop = RNA_def_enum(
+ ot->srna, "type", prop_vert_similar_types, SIMVERT_NORMAL, "Type", "");
+ RNA_def_enum_funcs(prop, uv_select_similar_type_itemf);
+ RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
+ RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/** \name Selected Elements as Arrays (Vertex, Edge & Faces)
@@ -4576,7 +5223,7 @@ static void uv_isolate_selected_islands(const Scene *scene,
BLI_assert((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) == 0);
BMFace *efa;
BMIter iter, liter;
- UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, true, false, false, true);
+ UvElementMap *elementmap = BM_uv_element_map_create(em->bm, scene, false, false, true);
if (elementmap == NULL) {
return;
}
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index bacf321fce1..579674930a6 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1716,7 +1716,7 @@ static void stitch_draw_vbo(GPUVertBuf *vbo, GPUPrimType prim_type, const float
GPU_batch_discard(batch);
}
-/* TODO: make things pretier : store batches inside StitchPreviewer instead of the bare verts pos
+/* TODO: make things prettier : store batches inside StitchPreviewer instead of the bare verts pos
*/
static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
{
@@ -1902,15 +1902,7 @@ static StitchState *stitch_init(bContext *C,
* for stitch this isn't useful behavior, see T86924. */
const int selectmode_orig = scene->toolsettings->selectmode;
scene->toolsettings->selectmode = SCE_SELECT_VERTEX;
-
- /* in uv synch selection, all uv's are visible */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, false, true, true);
- }
- else {
- state->element_map = BM_uv_element_map_create(state->em->bm, scene, true, false, true, true);
- }
-
+ state->element_map = BM_uv_element_map_create(state->em->bm, scene, false, true, true);
scene->toolsettings->selectmode = selectmode_orig;
if (!state->element_map) {
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 84dca352c9f..2c7ad012dd2 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -204,6 +204,8 @@ typedef struct UnwrapOptions {
bool fill_holes;
/** Correct for mapped image texture aspect ratio. */
bool correct_aspect;
+ /** Treat unselected uvs as if they were pinned. */
+ bool pin_unselected;
} UnwrapOptions;
typedef struct UnwrapResultInfo {
@@ -240,7 +242,7 @@ static bool uvedit_have_selection(const Scene *scene, BMEditMesh *em, const Unwr
}
}
- if (options->topology_from_uvs && !l) {
+ if (options->only_selected_uvs && !l) {
continue;
}
@@ -298,41 +300,133 @@ void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy);
}
+static bool uvedit_is_face_affected(const Scene *scene,
+ BMFace *efa,
+ const UnwrapOptions *options,
+ const int cd_loop_uv_offset)
+{
+ if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ return false;
+ }
+
+ if (options->only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ return false;
+ }
+
+ if (options->only_selected_uvs) {
+ BMLoop *l;
+ BMIter iter;
+ BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return true;
+}
+
+/* Prepare unique indices for each unique pinned UV, even if it shares a BMVert.
+ */
+static void uvedit_prepare_pinned_indices(ParamHandle *handle,
+ const Scene *scene,
+ BMFace *efa,
+ const UnwrapOptions *options,
+ const int cd_loop_uv_offset)
+{
+ BMIter liter;
+ BMLoop *l;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ bool pin = luv->flag & MLOOPUV_PINNED;
+ if (options->pin_unselected && !pin) {
+ pin = !uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ }
+ if (pin) {
+ int bmvertindex = BM_elem_index_get(l->v);
+ GEO_uv_prepare_pin_index(handle, bmvertindex, luv->uv);
+ }
+ }
+}
+
static void construct_param_handle_face_add(ParamHandle *handle,
const Scene *scene,
BMFace *efa,
- int face_index,
+ ParamKey face_index,
+ const UnwrapOptions *options,
const int cd_loop_uv_offset)
{
- ParamKey key;
ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
- ParamBool *pin = BLI_array_alloca(pin, efa->len);
- ParamBool *select = BLI_array_alloca(select, efa->len);
- float **co = BLI_array_alloca(co, efa->len);
+ bool *pin = BLI_array_alloca(pin, efa->len);
+ bool *select = BLI_array_alloca(select, efa->len);
+ const float **co = BLI_array_alloca(co, efa->len);
float **uv = BLI_array_alloca(uv, efa->len);
int i;
BMIter liter;
BMLoop *l;
- key = (ParamKey)face_index;
-
/* let parametrizer split the ngon, it can make better decisions
* about which split is best for unwrapping than poly-fill. */
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- vkeys[i] = (ParamKey)BM_elem_index_get(l->v);
+ vkeys[i] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv);
co[i] = l->v->co;
uv[i] = luv->uv;
pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if (options->pin_unselected && !select[i]) {
+ pin[i] = true;
+ }
}
- GEO_uv_parametrizer_face_add(handle, key, i, vkeys, co, uv, pin, select);
+ GEO_uv_parametrizer_face_add(handle, face_index, i, vkeys, co, uv, pin, select);
+}
+
+/* Set seams on UV Parametrizer based on options. */
+static void construct_param_edge_set_seams(ParamHandle *handle,
+ BMesh *bm,
+ const UnwrapOptions *options)
+{
+ if (options->topology_from_uvs && !options->topology_from_uvs_use_seams) {
+ return; /* Seams are not required with these options. */
+ }
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ if (cd_loop_uv_offset == -1) {
+ return; /* UVs aren't present on BMesh. Nothing to do. */
+ }
+
+ BMEdge *edge;
+ BMIter iter;
+ BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(edge, BM_ELEM_SEAM)) {
+ continue; /* No seam on this edge, nothing to do. */
+ }
+
+ /* Pinned vertices might have more than one ParamKey per BMVert.
+ * Check all the BM_LOOPS_OF_EDGE to find all the ParamKeys.
+ */
+ BMLoop *l;
+ BMIter liter;
+ BM_ITER_ELEM (l, &liter, edge, BM_LOOPS_OF_EDGE) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ ParamKey vkeys[2];
+ vkeys[0] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv);
+ vkeys[1] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->next->v), luv_next->uv);
+
+ /* Set the seam. */
+ GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
+ }
+ }
}
-/* See: construct_param_handle_multi to handle multiple objects at once. */
+/*
+ * Version of #construct_param_handle_multi with a separate BMesh parameter.
+ */
static ParamHandle *construct_param_handle(const Scene *scene,
Object *ob,
BMesh *bm,
@@ -340,13 +434,9 @@ static ParamHandle *construct_param_handle(const Scene *scene,
UnwrapResultInfo *result_info)
{
BMFace *efa;
- BMLoop *l;
- BMEdge *eed;
- BMIter iter, liter;
+ BMIter iter;
int i;
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
if (options->correct_aspect) {
@@ -362,43 +452,21 @@ static ParamHandle *construct_param_handle(const Scene *scene,
/* we need the vert indices */
BM_mesh_elem_index_ensure(bm, BM_VERT);
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ||
- (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
- continue;
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ uvedit_prepare_pinned_indices(handle, scene, efa, options, cd_loop_uv_offset);
}
-
- if (options->topology_from_uvs) {
- bool is_loopsel = false;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (options->only_selected_uvs &&
- (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
- continue;
- }
- is_loopsel = true;
- break;
- }
- if (is_loopsel == false) {
- continue;
- }
- }
-
- construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
}
- if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
- ParamKey vkeys[2];
- vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
- vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
- GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
- }
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ construct_param_handle_face_add(handle, scene, efa, i, options, cd_loop_uv_offset);
}
}
+ construct_param_edge_set_seams(handle, bm, options);
+
GEO_uv_parametrizer_construct_end(handle,
options->fill_holes,
options->topology_from_uvs,
@@ -408,18 +476,15 @@ static ParamHandle *construct_param_handle(const Scene *scene,
}
/**
- * Version of #construct_param_handle_single that handles multiple objects.
+ * Version of #construct_param_handle that handles multiple objects.
*/
static ParamHandle *construct_param_handle_multi(const Scene *scene,
Object **objects,
const uint objects_len,
- const UnwrapOptions *options,
- int *count_fail)
+ const UnwrapOptions *options)
{
BMFace *efa;
- BMLoop *l;
- BMEdge *eed;
- BMIter iter, liter;
+ BMIter iter;
int i;
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
@@ -451,46 +516,24 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
}
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
-
- if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ||
- (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
- continue;
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ uvedit_prepare_pinned_indices(handle, scene, efa, options, cd_loop_uv_offset);
}
-
- if (options->topology_from_uvs) {
- bool is_loopsel = false;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (options->only_selected_uvs &&
- (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
- continue;
- }
- is_loopsel = true;
- break;
- }
- if (is_loopsel == false) {
- continue;
- }
- }
-
- construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
}
- if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
- ParamKey vkeys[2];
- vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
- vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
- GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
- }
+ BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
+ if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
+ construct_param_handle_face_add(
+ handle, scene, efa, i + offset, options, cd_loop_uv_offset);
}
}
+
+ construct_param_edge_set_seams(handle, bm, options);
+
offset += bm->totface;
}
- GEO_uv_parametrizer_construct_end(
- handle, options->fill_holes, options->topology_from_uvs, count_fail);
+ GEO_uv_parametrizer_construct_end(handle, options->fill_holes, options->topology_from_uvs, NULL);
return handle;
}
@@ -500,8 +543,8 @@ static void texface_from_original_index(const Scene *scene,
BMFace *efa,
int index,
float **r_uv,
- ParamBool *r_pin,
- ParamBool *r_select)
+ bool *r_pin,
+ bool *r_select)
{
BMLoop *l;
BMIter liter;
@@ -633,8 +676,8 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
/* Prepare and feed faces to the solver */
for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
ParamKey key, vkeys[4];
- ParamBool pin[4], select[4];
- float *co[4];
+ bool pin[4], select[4];
+ const float *co[4];
float *uv[4];
BMFace *origFace = faceMap[i];
@@ -652,7 +695,7 @@ static ParamHandle *construct_param_handle_subsurfed(const Scene *scene,
mloop = &subsurfedLoops[mpoly->loopstart];
- /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
+ /* We will not check for v4 here. Sub-surface faces always have 4 vertices. */
BLI_assert(mpoly->totloop == 4);
key = (ParamKey)i;
vkeys[0] = (ParamKey)mloop[0].v;
@@ -769,7 +812,7 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
ms->blend = RNA_float_get(op->ptr, "blend");
ms->iterations = RNA_int_get(op->ptr, "iterations");
ms->i = 0;
- ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL);
+ ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options);
ms->lasttime = PIL_check_seconds_timer();
GEO_uv_parametrizer_stretch_begin(ms->handle);
@@ -1039,7 +1082,7 @@ static void uvedit_pack_islands_multi(const Scene *scene,
bool rotate,
bool ignore_pinned)
{
- ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL);
+ ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options);
GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
@@ -1148,7 +1191,7 @@ void UV_OT_pack_islands(wmOperatorType *ot)
/** \name Average UV Islands Scale Operator
* \{ */
-static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
+static int average_islands_scale_exec(bContext *C, wmOperator *op)
{
const Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1172,8 +1215,12 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL);
- GEO_uv_parametrizer_average(handle, false);
+ /* RNA props */
+ const bool scale_uv = RNA_boolean_get(op->ptr, "scale_uv");
+ const bool shear = RNA_boolean_get(op->ptr, "shear");
+
+ ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options);
+ GEO_uv_parametrizer_average(handle, false, scale_uv, shear);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
@@ -1204,6 +1251,10 @@ void UV_OT_average_islands_scale(wmOperatorType *ot)
/* api callbacks */
ot->exec = average_islands_scale_exec;
ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "scale_uv", false, "Non-Uniform", "Scale U and V independently");
+ RNA_def_boolean(ot->srna, "shear", false, "Shear", "Reduce shear within islands");
}
/** \} */
@@ -1233,7 +1284,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
const UnwrapOptions options = {
.topology_from_uvs = false,
.only_selected_faces = false,
- .only_selected_uvs = true,
+ .only_selected_uvs = false,
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
@@ -1245,7 +1296,7 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
handle = construct_param_handle(scene, obedit, em->bm, &options, NULL);
}
- GEO_uv_parametrizer_lscm_begin(handle, PARAM_TRUE, abf);
+ GEO_uv_parametrizer_lscm_begin(handle, true, abf);
/* Create or increase size of g_live_unwrap.handles array */
if (g_live_unwrap.handles == NULL) {
@@ -1796,13 +1847,13 @@ static void uvedit_unwrap(const Scene *scene,
handle = construct_param_handle(scene, obedit, em->bm, options, result_info);
}
- GEO_uv_parametrizer_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
+ GEO_uv_parametrizer_lscm_begin(handle, false, scene->toolsettings->unwrapper == 0);
GEO_uv_parametrizer_lscm_solve(handle,
result_info ? &result_info->count_changed : NULL,
result_info ? &result_info->count_failed : NULL);
GEO_uv_parametrizer_lscm_end(handle);
- GEO_uv_parametrizer_average(handle, true);
+ GEO_uv_parametrizer_average(handle, true, false, false);
GEO_uv_parametrizer_flush(handle);
@@ -1829,7 +1880,7 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len
const UnwrapOptions options = {
.topology_from_uvs = false,
.only_selected_faces = false,
- .only_selected_uvs = true,
+ .only_selected_uvs = false,
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
@@ -1862,16 +1913,21 @@ static int unwrap_exec(bContext *C, wmOperator *op)
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
view_layer, CTX_wm_view3d(C), &objects_len);
- const UnwrapOptions options = {
+ UnwrapOptions options = {
.topology_from_uvs = false,
.only_selected_faces = true,
- .only_selected_uvs = true,
+ .only_selected_uvs = false,
.fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
.correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
};
bool rotate = true;
bool ignore_pinned = true;
+ if (CTX_wm_space_image(C)) {
+ /* Inside the UV Editor, only unwrap selected UVs. */
+ options.only_selected_uvs = true;
+ options.pin_unselected = true;
+ }
if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
MEM_freeN(objects);
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 46051a58e8b..a8136d06c5f 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -476,6 +476,8 @@ template<typename T> T evaluate_constant_field(const Field<T> &field)
return value;
}
+Field<bool> invert_boolean_field(const Field<bool> &field);
+
GField make_constant_field(const CPPType &type, const void *value);
template<typename T> Field<T> make_constant_field(T value)
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 9d09378ab63..16a33c9cda7 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -41,6 +41,10 @@ class MFParamsBuilder {
MFParamsBuilder(const MFSignature &signature, const IndexMask mask)
: signature_(&signature), mask_(mask), min_array_size_(mask.min_array_size())
{
+ virtual_arrays_.reserve(signature.virtual_array_num);
+ mutable_spans_.reserve(signature.span_num);
+ virtual_vector_arrays_.reserve(signature.virtual_vector_array_num);
+ vector_arrays_.reserve(signature.vector_array_num);
}
public:
@@ -53,28 +57,33 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input_value(T value, StringRef expected_name = "")
{
- this->add_readonly_single_input(VArray<T>::ForSingle(std::move(value), min_array_size_),
- expected_name);
+ this->assert_current_param_type(MFParamType::ForSingleInput(CPPType::get<T>()), expected_name);
+ virtual_arrays_.append_unchecked_as(
+ varray_tag::single{}, CPPType::get<T>(), min_array_size_, &value);
}
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
- this->add_readonly_single_input(
- GVArray::ForSingleRef(CPPType::get<T>(), min_array_size_, value), expected_name);
+ this->assert_current_param_type(MFParamType::ForSingleInput(CPPType::get<T>()), expected_name);
+ virtual_arrays_.append_unchecked_as(
+ varray_tag::single_ref{}, CPPType::get<T>(), min_array_size_, value);
}
void add_readonly_single_input(const GSpan span, StringRef expected_name = "")
{
- this->add_readonly_single_input(GVArray::ForSpan(span), expected_name);
+ this->assert_current_param_type(MFParamType::ForSingleInput(span.type()), expected_name);
+ BLI_assert(span.size() >= min_array_size_);
+ virtual_arrays_.append_unchecked_as(varray_tag::span{}, span);
}
void add_readonly_single_input(GPointer value, StringRef expected_name = "")
{
- this->add_readonly_single_input(
- GVArray::ForSingleRef(*value.type(), min_array_size_, value.get()), expected_name);
+ this->assert_current_param_type(MFParamType::ForSingleInput(*value.type()), expected_name);
+ virtual_arrays_.append_unchecked_as(
+ varray_tag::single_ref{}, *value.type(), min_array_size_, value.get());
}
void add_readonly_single_input(GVArray varray, StringRef expected_name = "")
{
this->assert_current_param_type(MFParamType::ForSingleInput(varray.type()), expected_name);
BLI_assert(varray.size() >= min_array_size_);
- virtual_arrays_.append(varray);
+ virtual_arrays_.append_unchecked_as(std::move(varray));
}
void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "")
@@ -92,7 +101,7 @@ class MFParamsBuilder {
{
this->assert_current_param_type(MFParamType::ForVectorInput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
- virtual_vector_arrays_.append(&ref);
+ virtual_vector_arrays_.append_unchecked(&ref);
}
template<typename T> void add_uninitialized_single_output(T *value, StringRef expected_name = "")
@@ -104,7 +113,7 @@ class MFParamsBuilder {
{
this->assert_current_param_type(MFParamType::ForSingleOutput(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
- mutable_spans_.append(ref);
+ mutable_spans_.append_unchecked(ref);
}
void add_ignored_single_output(StringRef expected_name = "")
{
@@ -115,7 +124,7 @@ class MFParamsBuilder {
const CPPType &type = param_type.data_type().single_type();
/* An empty span indicates that this is ignored. */
const GMutableSpan dummy_span{type};
- mutable_spans_.append(dummy_span);
+ mutable_spans_.append_unchecked(dummy_span);
}
void add_vector_output(GVectorArray &vector_array, StringRef expected_name = "")
@@ -123,14 +132,14 @@ class MFParamsBuilder {
this->assert_current_param_type(MFParamType::ForVectorOutput(vector_array.type()),
expected_name);
BLI_assert(vector_array.size() >= min_array_size_);
- vector_arrays_.append(&vector_array);
+ vector_arrays_.append_unchecked(&vector_array);
}
void add_single_mutable(GMutableSpan ref, StringRef expected_name = "")
{
this->assert_current_param_type(MFParamType::ForMutableSingle(ref.type()), expected_name);
BLI_assert(ref.size() >= min_array_size_);
- mutable_spans_.append(ref);
+ mutable_spans_.append_unchecked(ref);
}
void add_vector_mutable(GVectorArray &vector_array, StringRef expected_name = "")
@@ -138,7 +147,7 @@ class MFParamsBuilder {
this->assert_current_param_type(MFParamType::ForMutableVector(vector_array.type()),
expected_name);
BLI_assert(vector_array.size() >= min_array_size_);
- vector_arrays_.append(&vector_array);
+ vector_arrays_.append_unchecked(&vector_array);
}
GMutableSpan computed_array(int param_index)
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index 75a54992a48..da269b08155 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -87,7 +87,7 @@ class MFVariable : NonCopyable, NonMovable {
MFDataType data_type_;
Vector<MFInstruction *> users_;
std::string name_;
- int id_;
+ int index_in_graph_;
friend MFProcedure;
friend MFCallInstruction;
@@ -101,7 +101,7 @@ class MFVariable : NonCopyable, NonMovable {
StringRefNull name() const;
void set_name(std::string name);
- int id() const;
+ int index_in_procedure() const;
};
/** Base class for all instruction types. */
@@ -376,9 +376,9 @@ inline StringRefNull MFVariable::name() const
return name_;
}
-inline int MFVariable::id() const
+inline int MFVariable::index_in_procedure() const
{
- return id_;
+ return index_in_graph_;
}
/** \} */
diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh
index 62c491609a4..6181555dbd1 100644
--- a/source/blender/functions/FN_multi_function_signature.hh
+++ b/source/blender/functions/FN_multi_function_signature.hh
@@ -29,6 +29,15 @@ struct MFSignature {
Vector<int> param_data_indices;
bool depends_on_context = false;
+ /**
+ * Number of elements of each of these types that has to be passed into the multi-function as an
+ * input or output.
+ */
+ int span_num = 0;
+ int virtual_array_num = 0;
+ int virtual_vector_array_num = 0;
+ int vector_array_num = 0;
+
int data_index(int param_index) const
{
return param_data_indices[param_index];
@@ -38,10 +47,6 @@ struct MFSignature {
class MFSignatureBuilder {
private:
MFSignature signature_;
- int span_count_ = 0;
- int virtual_array_count_ = 0;
- int virtual_vector_array_count_ = 0;
- int vector_array_count_ = 0;
public:
MFSignatureBuilder(const char *function_name)
@@ -79,10 +84,10 @@ class MFSignatureBuilder {
switch (data_type.category()) {
case MFDataType::Single:
- signature_.param_data_indices.append(virtual_array_count_++);
+ signature_.param_data_indices.append(signature_.virtual_array_num++);
break;
case MFDataType::Vector:
- signature_.param_data_indices.append(virtual_vector_array_count_++);
+ signature_.param_data_indices.append(signature_.virtual_vector_array_num++);
break;
}
}
@@ -112,10 +117,10 @@ class MFSignatureBuilder {
switch (data_type.category()) {
case MFDataType::Single:
- signature_.param_data_indices.append(span_count_++);
+ signature_.param_data_indices.append(signature_.span_num++);
break;
case MFDataType::Vector:
- signature_.param_data_indices.append(vector_array_count_++);
+ signature_.param_data_indices.append(signature_.vector_array_num++);
break;
}
}
@@ -145,10 +150,10 @@ class MFSignatureBuilder {
switch (data_type.category()) {
case MFDataType::Single:
- signature_.param_data_indices.append(span_count_++);
+ signature_.param_data_indices.append(signature_.span_num++);
break;
case MFDataType::Vector:
- signature_.param_data_indices.append(vector_array_count_++);
+ signature_.param_data_indices.append(signature_.vector_array_num++);
break;
}
}
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index a53da717606..fd5eab57d33 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -518,6 +518,14 @@ GField make_field_constant_if_possible(GField field)
return new_field;
}
+Field<bool> invert_boolean_field(const Field<bool> &field)
+{
+ static CustomMF_SI_SO<bool, bool> not_fn{
+ "Not", [](bool a) { return !a; }, CustomMF_presets::AllSpanOrSingle()};
+ auto not_op = std::make_shared<FieldOperation>(FieldOperation(not_fn, {field}));
+ return Field<bool>(not_op);
+}
+
GField make_constant_field(const CPPType &type, const void *value)
{
auto constant_node = std::make_shared<FieldConstant>(type, value);
@@ -700,20 +708,11 @@ GPointer FieldConstant::value() const
*/
static IndexMask index_mask_from_selection(const IndexMask full_mask,
- VArray<bool> &selection,
+ const VArray<bool> &selection,
ResourceScope &scope)
{
- if (selection.is_span()) {
- Span<bool> span = selection.get_internal_span();
- return index_mask_ops::find_indices_based_on_predicate(
- full_mask, 4096, scope.construct<Vector<int64_t>>(), [&](const int curve_index) {
- return span[curve_index];
- });
- }
- return index_mask_ops::find_indices_based_on_predicate(
- full_mask, 1024, scope.construct<Vector<int64_t>>(), [&](const int curve_index) {
- return selection[curve_index];
- });
+ return index_mask_ops::find_indices_from_virtual_array(
+ full_mask, selection, 1024, scope.construct<Vector<int64_t>>());
}
int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst)
@@ -756,12 +755,6 @@ static IndexMask evaluate_selection(const Field<bool> &selection_field,
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 index_mask_from_selection(full_mask, selection, scope);
}
return full_mask;
diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc
index bc045bfd44b..7ad324a9574 100644
--- a/source/blender/functions/intern/multi_function_procedure.cc
+++ b/source/blender/functions/intern/multi_function_procedure.cc
@@ -173,7 +173,7 @@ MFVariable &MFProcedure::new_variable(MFDataType data_type, std::string name)
MFVariable &variable = *allocator_.construct<MFVariable>().release();
variable.name_ = std::move(name);
variable.data_type_ = data_type;
- variable.id_ = variables_.size();
+ variable.index_in_graph_ = variables_.size();
variables_.append(&variable);
return variable;
}
@@ -753,7 +753,7 @@ class MFProcedureDotExport {
ss << "null";
}
else {
- ss << "$" << variable->id();
+ ss << "$" << variable->index_in_procedure();
if (!variable->name().is_empty()) {
ss << "(" << variable->name() << ")";
}
diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc
index d852fe19924..7d9b2fcd1f0 100644
--- a/source/blender/functions/intern/multi_function_procedure_executor.cc
+++ b/source/blender/functions/intern/multi_function_procedure_executor.cc
@@ -144,23 +144,20 @@ class ValueAllocator : NonCopyable, NonMovable {
* 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_;
+ Stack<void *> small_span_buffers_free_list_;
+ Map<int, Stack<void *>> span_buffers_free_lists_;
/** Cache buffers for single values of different types. */
+ static constexpr inline int small_value_max_size = 16;
+ static constexpr inline int small_value_max_alignment = 8;
+ Stack<void *> small_single_value_free_list_;
Map<const CPPType *, Stack<void *>> single_value_free_lists_;
- /** The cached memory buffers can hold #VariableState values. */
- Stack<void *> variable_state_free_list_;
-
public:
ValueAllocator(LinearAllocator<> &linear_allocator) : linear_allocator_(linear_allocator)
{
}
- template<typename... Args> VariableState *obtain_variable_state(Args &&...args);
-
- void release_variable_state(VariableState *state);
-
VariableValue_GVArray *obtain_GVArray(const GVArray &varray)
{
return this->obtain<VariableValue_GVArray>(varray);
@@ -188,9 +185,13 @@ class ValueAllocator : NonCopyable, NonMovable {
buffer = linear_allocator_.allocate(element_size * size, alignment);
}
else {
- Stack<void *> *stack = span_buffers_free_list_.lookup_ptr(element_size);
+ Stack<void *> *stack = type.can_exist_in_buffer(small_value_max_size,
+ small_value_max_alignment) ?
+ &small_span_buffers_free_list_ :
+ span_buffers_free_lists_.lookup_ptr(element_size);
if (stack == nullptr || stack->is_empty()) {
- buffer = linear_allocator_.allocate(element_size * size, min_alignment);
+ buffer = linear_allocator_.allocate(
+ std::max<int64_t>(element_size, small_value_max_size) * size, min_alignment);
}
else {
/* Reuse existing buffer. */
@@ -214,10 +215,15 @@ class ValueAllocator : NonCopyable, NonMovable {
VariableValue_OneSingle *obtain_OneSingle(const CPPType &type)
{
- Stack<void *> &stack = single_value_free_lists_.lookup_or_add_default(&type);
+ const bool is_small = type.can_exist_in_buffer(small_value_max_size,
+ small_value_max_alignment);
+ Stack<void *> &stack = is_small ? small_single_value_free_list_ :
+ single_value_free_lists_.lookup_or_add_default(&type);
void *buffer;
if (stack.is_empty()) {
- buffer = linear_allocator_.allocate(type.size(), type.alignment());
+ buffer = linear_allocator_.allocate(
+ std::max<int>(small_value_max_size, type.size()),
+ std::max<int>(small_value_max_alignment, type.alignment()));
}
else {
buffer = stack.pop();
@@ -242,7 +248,10 @@ class ValueAllocator : NonCopyable, NonMovable {
if (value_typed->owned) {
const CPPType &type = data_type.single_type();
/* Assumes all values in the buffer are uninitialized already. */
- Stack<void *> &buffers = span_buffers_free_list_.lookup_or_add_default(type.size());
+ Stack<void *> &buffers = type.can_exist_in_buffer(small_value_max_size,
+ small_value_max_alignment) ?
+ small_span_buffers_free_list_ :
+ span_buffers_free_lists_.lookup_or_add_default(type.size());
buffers.push(value_typed->data);
}
break;
@@ -263,7 +272,14 @@ class ValueAllocator : NonCopyable, NonMovable {
if (value_typed->is_initialized) {
type.destruct(value_typed->data);
}
- single_value_free_lists_.lookup_or_add_default(&type).push(value_typed->data);
+ const bool is_small = type.can_exist_in_buffer(small_value_max_size,
+ small_value_max_alignment);
+ if (is_small) {
+ small_single_value_free_list_.push(value_typed->data);
+ }
+ else {
+ single_value_free_lists_.lookup_or_add_default(&type).push(value_typed->data);
+ }
break;
}
case ValueType::OneVector: {
@@ -294,32 +310,27 @@ class ValueAllocator : NonCopyable, NonMovable {
* This class keeps track of a single variable during evaluation.
*/
class VariableState : NonCopyable, NonMovable {
- private:
+ public:
/** The current value of the variable. The storage format may change over time. */
- VariableValue *value_;
+ VariableValue *value_ = nullptr;
/** Number of indices that are currently initialized in this variable. */
- int tot_initialized_;
+ int tot_initialized_ = 0;
/* This a non-owning pointer to either span buffer or #GVectorArray or null. */
void *caller_provided_storage_ = nullptr;
- public:
- VariableState(VariableValue &value, int tot_initialized, void *caller_provided_storage = nullptr)
- : value_(&value),
- tot_initialized_(tot_initialized),
- caller_provided_storage_(caller_provided_storage)
- {
- }
-
- void destruct_self(ValueAllocator &value_allocator, const MFDataType &data_type)
+ void destruct_value(ValueAllocator &value_allocator, const MFDataType &data_type)
{
value_allocator.release_value(value_, data_type);
- value_allocator.release_variable_state(this);
+ value_ = nullptr;
}
/* True if this contains only one value for all indices, i.e. the value for all indices is
* the same. */
bool is_one() const
{
+ if (value_ == nullptr) {
+ return true;
+ }
switch (value_->type) {
case ValueType::GVArray:
return this->value_as<VariableValue_GVArray>()->data.is_single();
@@ -353,6 +364,7 @@ class VariableState : NonCopyable, NonMovable {
{
/* Sanity check to make sure that enough values are initialized. */
BLI_assert(mask.size() <= tot_initialized_);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::GVArray: {
@@ -391,7 +403,7 @@ class VariableState : NonCopyable, NonMovable {
const MFDataType &data_type,
ValueAllocator &value_allocator)
{
- if (ELEM(value_->type, ValueType::Span, ValueType::GVectorArray)) {
+ if (value_ != nullptr && ELEM(value_->type, ValueType::Span, ValueType::GVectorArray)) {
return;
}
@@ -408,22 +420,24 @@ class VariableState : NonCopyable, NonMovable {
/* Reuse the storage provided caller when possible. */
new_value = value_allocator.obtain_Span_not_owned(caller_provided_storage_);
}
- if (value_->type == ValueType::GVArray) {
- /* Fill new buffer with data from virtual array. */
- this->value_as<VariableValue_GVArray>()->data.materialize_to_uninitialized(
- full_mask, new_value->data);
- }
- else if (value_->type == ValueType::OneSingle) {
- auto *old_value_typed_ = this->value_as<VariableValue_OneSingle>();
- if (old_value_typed_->is_initialized) {
- /* Fill the buffer with a single value. */
- type.fill_construct_indices(old_value_typed_->data, new_value->data, full_mask);
+ if (value_ != nullptr) {
+ if (value_->type == ValueType::GVArray) {
+ /* Fill new buffer with data from virtual array. */
+ this->value_as<VariableValue_GVArray>()->data.materialize_to_uninitialized(
+ full_mask, new_value->data);
}
+ else if (value_->type == ValueType::OneSingle) {
+ auto *old_value_typed_ = this->value_as<VariableValue_OneSingle>();
+ if (old_value_typed_->is_initialized) {
+ /* Fill the buffer with a single value. */
+ type.fill_construct_indices(old_value_typed_->data, new_value->data, full_mask);
+ }
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ value_allocator.release_value(value_, data_type);
}
- else {
- BLI_assert_unreachable();
- }
- value_allocator.release_value(value_, data_type);
value_ = new_value;
break;
}
@@ -437,19 +451,21 @@ class VariableState : NonCopyable, NonMovable {
new_value = value_allocator.obtain_GVectorArray_not_owned(
*(GVectorArray *)caller_provided_storage_);
}
- if (value_->type == ValueType::GVVectorArray) {
- /* Fill new vector array with data from virtual vector array. */
- new_value->data.extend(full_mask, this->value_as<VariableValue_GVVectorArray>()->data);
- }
- else if (value_->type == ValueType::OneVector) {
- /* Fill all indices with the same value. */
- const GSpan vector = this->value_as<VariableValue_OneVector>()->data[0];
- new_value->data.extend(full_mask, GVVectorArray_For_SingleGSpan{vector, array_size});
- }
- else {
- BLI_assert_unreachable();
+ if (value_ != nullptr) {
+ if (value_->type == ValueType::GVVectorArray) {
+ /* Fill new vector array with data from virtual vector array. */
+ new_value->data.extend(full_mask, this->value_as<VariableValue_GVVectorArray>()->data);
+ }
+ else if (value_->type == ValueType::OneVector) {
+ /* Fill all indices with the same value. */
+ const GSpan vector = this->value_as<VariableValue_OneVector>()->data[0];
+ new_value->data.extend(full_mask, GVVectorArray_For_SingleGSpan{vector, array_size});
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ value_allocator.release_value(value_, data_type);
}
- value_allocator.release_value(value_, data_type);
value_ = new_value;
break;
}
@@ -466,6 +482,7 @@ class VariableState : NonCopyable, NonMovable {
BLI_assert(mask.size() <= tot_initialized_);
this->ensure_is_mutable(full_mask, data_type, value_allocator);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::Span: {
@@ -497,6 +514,7 @@ class VariableState : NonCopyable, NonMovable {
/* Sanity check to make sure that enough values are not initialized. */
BLI_assert(mask.size() <= full_mask.size() - tot_initialized_);
this->ensure_is_mutable(full_mask, data_type, value_allocator);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::Span: {
@@ -524,6 +542,7 @@ class VariableState : NonCopyable, NonMovable {
void add_as_input__one(MFParamsBuilder &params, const MFDataType &data_type) const
{
BLI_assert(this->is_one());
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::GVArray: {
@@ -556,7 +575,7 @@ class VariableState : NonCopyable, NonMovable {
void ensure_is_mutable__one(const MFDataType &data_type, ValueAllocator &value_allocator)
{
BLI_assert(this->is_one());
- if (ELEM(value_->type, ValueType::OneSingle, ValueType::OneVector)) {
+ if (value_ != nullptr && ELEM(value_->type, ValueType::OneSingle, ValueType::OneVector)) {
return;
}
@@ -564,38 +583,42 @@ class VariableState : NonCopyable, NonMovable {
case MFDataType::Single: {
const CPPType &type = data_type.single_type();
VariableValue_OneSingle *new_value = value_allocator.obtain_OneSingle(type);
- if (value_->type == ValueType::GVArray) {
- this->value_as<VariableValue_GVArray>()->data.get_internal_single_to_uninitialized(
- new_value->data);
- new_value->is_initialized = true;
- }
- else if (value_->type == ValueType::Span) {
- BLI_assert(tot_initialized_ == 0);
- /* Nothing to do, the single value is uninitialized already. */
- }
- else {
- BLI_assert_unreachable();
+ if (value_ != nullptr) {
+ if (value_->type == ValueType::GVArray) {
+ this->value_as<VariableValue_GVArray>()->data.get_internal_single_to_uninitialized(
+ new_value->data);
+ new_value->is_initialized = true;
+ }
+ else if (value_->type == ValueType::Span) {
+ BLI_assert(tot_initialized_ == 0);
+ /* Nothing to do, the single value is uninitialized already. */
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ value_allocator.release_value(value_, data_type);
}
- value_allocator.release_value(value_, data_type);
value_ = new_value;
break;
}
case MFDataType::Vector: {
const CPPType &type = data_type.vector_base_type();
VariableValue_OneVector *new_value = value_allocator.obtain_OneVector(type);
- if (value_->type == ValueType::GVVectorArray) {
- const GVVectorArray &old_vector_array =
- this->value_as<VariableValue_GVVectorArray>()->data;
- new_value->data.extend(IndexRange(1), old_vector_array);
- }
- else if (value_->type == ValueType::GVectorArray) {
- BLI_assert(tot_initialized_ == 0);
- /* Nothing to do. */
- }
- else {
- BLI_assert_unreachable();
+ if (value_ != nullptr) {
+ if (value_->type == ValueType::GVVectorArray) {
+ const GVVectorArray &old_vector_array =
+ this->value_as<VariableValue_GVVectorArray>()->data;
+ new_value->data.extend(IndexRange(1), old_vector_array);
+ }
+ else if (value_->type == ValueType::GVectorArray) {
+ BLI_assert(tot_initialized_ == 0);
+ /* Nothing to do. */
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ value_allocator.release_value(value_, data_type);
}
- value_allocator.release_value(value_, data_type);
value_ = new_value;
break;
}
@@ -608,6 +631,7 @@ class VariableState : NonCopyable, NonMovable {
{
BLI_assert(this->is_one());
this->ensure_is_mutable__one(data_type, value_allocator);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::OneSingle: {
@@ -637,6 +661,7 @@ class VariableState : NonCopyable, NonMovable {
{
BLI_assert(this->is_one());
this->ensure_is_mutable__one(data_type, value_allocator);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::OneSingle: {
@@ -676,6 +701,7 @@ class VariableState : NonCopyable, NonMovable {
const MFDataType &data_type,
ValueAllocator &value_allocator)
{
+ BLI_assert(value_ != nullptr);
int new_tot_initialized = tot_initialized_ - mask.size();
/* Sanity check to make sure that enough indices can be destructed. */
@@ -743,6 +769,7 @@ class VariableState : NonCopyable, NonMovable {
void indices_split(IndexMask mask, IndicesSplitVectors &r_indices)
{
BLI_assert(mask.size() <= tot_initialized_);
+ BLI_assert(value_ != nullptr);
switch (value_->type) {
case ValueType::GVArray: {
@@ -778,51 +805,47 @@ class VariableState : NonCopyable, NonMovable {
template<typename T> T *value_as()
{
+ BLI_assert(value_ != nullptr);
BLI_assert(value_->type == T::static_type);
return static_cast<T *>(value_);
}
template<typename T> const T *value_as() const
{
+ BLI_assert(value_ != nullptr);
BLI_assert(value_->type == T::static_type);
return static_cast<T *>(value_);
}
};
-template<typename... Args> VariableState *ValueAllocator::obtain_variable_state(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)
-{
- state->~VariableState();
- variable_state_free_list_.push(state);
-}
-
/** Keeps track of the states of all variables during evaluation. */
class VariableStates {
private:
ValueAllocator value_allocator_;
- Map<const MFVariable *, VariableState *> variable_states_;
+ const MFProcedure &procedure_;
+ /** The state of every variable, indexed by #MFVariable::index_in_procedure(). */
+ Array<VariableState> variable_states_;
IndexMask full_mask_;
public:
- VariableStates(LinearAllocator<> &linear_allocator, IndexMask full_mask)
- : value_allocator_(linear_allocator), full_mask_(full_mask)
+ VariableStates(LinearAllocator<> &linear_allocator,
+ const MFProcedure &procedure,
+ IndexMask full_mask)
+ : value_allocator_(linear_allocator),
+ procedure_(procedure),
+ variable_states_(procedure.variables().size()),
+ full_mask_(full_mask)
{
}
~VariableStates()
{
- for (auto &&item : variable_states_.items()) {
- const MFVariable *variable = item.key;
- VariableState *state = item.value;
- state->destruct_self(value_allocator_, variable->data_type());
+ for (const int variable_i : procedure_.variables().index_range()) {
+ VariableState &state = variable_states_[variable_i];
+ if (state.value_ != nullptr) {
+ const MFVariable *variable = procedure_.variables()[variable_i];
+ state.destruct_value(value_allocator_, variable->data_type());
+ }
}
}
@@ -848,9 +871,12 @@ class VariableStates {
bool input_is_initialized,
void *caller_provided_storage = nullptr) {
const int tot_initialized = input_is_initialized ? full_mask_.size() : 0;
- variable_states_.add_new(variable,
- value_allocator_.obtain_variable_state(
- *value, tot_initialized, caller_provided_storage));
+ const int variable_i = variable->index_in_procedure();
+ VariableState &variable_state = variable_states_[variable_i];
+ BLI_assert(variable_state.value_ == nullptr);
+ variable_state.value_ = value;
+ variable_state.tot_initialized_ = tot_initialized;
+ variable_state.caller_provided_storage_ = caller_provided_storage;
};
switch (param_type.category()) {
@@ -936,32 +962,15 @@ class VariableStates {
{
VariableState &variable_state = this->get_variable_state(variable);
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);
+ variable_state.destruct_value(value_allocator_, variable.data_type());
}
}
VariableState &get_variable_state(const MFVariable &variable)
{
- return *variable_states_.lookup_or_add_cb(
- &variable, [&]() { return this->create_new_state_for_variable(variable); });
- }
-
- VariableState *create_new_state_for_variable(const MFVariable &variable)
- {
- MFDataType data_type = variable.data_type();
- switch (data_type.category()) {
- case MFDataType::Single: {
- const CPPType &type = data_type.single_type();
- return value_allocator_.obtain_variable_state(*value_allocator_.obtain_OneSingle(type), 0);
- }
- case MFDataType::Vector: {
- const CPPType &type = data_type.vector_base_type();
- return value_allocator_.obtain_variable_state(*value_allocator_.obtain_OneVector(type), 0);
- }
- }
- BLI_assert_unreachable();
- return nullptr;
+ const int variable_i = variable.index_in_procedure();
+ VariableState &variable_state = variable_states_[variable_i];
+ return variable_state;
}
};
@@ -977,49 +986,82 @@ static bool evaluate_as_one(const MultiFunction &fn,
return false;
}
for (VariableState *state : param_variable_states) {
- if (state != nullptr && !state->is_one()) {
+ if (state != nullptr && state->value_ != nullptr && !state->is_one()) {
return false;
}
}
return true;
}
-static void execute_call_instruction(const MFCallInstruction &instruction,
- IndexMask mask,
- VariableStates &variable_states,
- const MFContext &context)
+static void gather_parameter_variable_states(const MultiFunction &fn,
+ const MFCallInstruction &instruction,
+ VariableStates &variable_states,
+ MutableSpan<VariableState *> r_param_variable_states)
{
- const MultiFunction &fn = instruction.fn();
-
- Vector<VariableState *> param_variable_states;
- param_variable_states.resize(fn.param_amount());
-
for (const int param_index : fn.param_indices()) {
const MFVariable *variable = instruction.params()[param_index];
if (variable == nullptr) {
- param_variable_states[param_index] = nullptr;
+ r_param_variable_states[param_index] = nullptr;
}
else {
VariableState &variable_state = variable_states.get_variable_state(*variable);
- param_variable_states[param_index] = &variable_state;
+ r_param_variable_states[param_index] = &variable_state;
}
}
+}
+
+static void fill_params__one(const MultiFunction &fn,
+ const IndexMask mask,
+ MFParamsBuilder &params,
+ VariableStates &variable_states,
+ const Span<VariableState *> param_variable_states)
+{
+ for (const int param_index : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(param_index);
+ VariableState *variable_state = param_variable_states[param_index];
+ if (variable_state == nullptr) {
+ params.add_ignored_single_output();
+ }
+ else {
+ variable_states.add_as_param__one(*variable_state, params, param_type, mask);
+ }
+ }
+}
+
+static void fill_params(const MultiFunction &fn,
+ const IndexMask mask,
+ MFParamsBuilder &params,
+ VariableStates &variable_states,
+ const Span<VariableState *> param_variable_states)
+{
+ for (const int param_index : fn.param_indices()) {
+ const MFParamType param_type = fn.param_type(param_index);
+ VariableState *variable_state = param_variable_states[param_index];
+ if (variable_state == nullptr) {
+ params.add_ignored_single_output();
+ }
+ else {
+ variable_states.add_as_param(*variable_state, params, param_type, mask);
+ }
+ }
+}
+
+static void execute_call_instruction(const MFCallInstruction &instruction,
+ const IndexMask mask,
+ VariableStates &variable_states,
+ const MFContext &context)
+{
+ const MultiFunction &fn = instruction.fn();
+
+ Vector<VariableState *> param_variable_states;
+ param_variable_states.resize(fn.param_amount());
+ gather_parameter_variable_states(fn, instruction, variable_states, param_variable_states);
/* If all inputs to the function are constant, it's enough to call the function only once instead
* of for every index. */
if (evaluate_as_one(fn, param_variable_states, mask, variable_states.full_mask())) {
MFParamsBuilder params(fn, 1);
-
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- VariableState *variable_state = param_variable_states[param_index];
- if (variable_state == nullptr) {
- params.add_ignored_single_output();
- }
- else {
- variable_states.add_as_param__one(*variable_state, params, param_type, mask);
- }
- }
+ fill_params__one(fn, mask, params, variable_states, param_variable_states);
try {
fn.call(IndexRange(1), params, context);
@@ -1031,17 +1073,7 @@ static void execute_call_instruction(const MFCallInstruction &instruction,
}
else {
MFParamsBuilder params(fn, &mask);
-
- for (const int param_index : fn.param_indices()) {
- const MFParamType param_type = fn.param_type(param_index);
- VariableState *variable_state = param_variable_states[param_index];
- if (variable_state == nullptr) {
- params.add_ignored_single_output();
- }
- else {
- variable_states.add_as_param(*variable_state, params, param_type, mask);
- }
- }
+ fill_params(fn, mask, params, variable_states, param_variable_states);
try {
fn.call_auto(mask, params, context);
@@ -1090,7 +1122,7 @@ struct NextInstructionInfo {
*/
class InstructionScheduler {
private:
- Map<const MFInstruction *, Vector<InstructionIndices>> indices_by_instruction_;
+ Stack<NextInstructionInfo> next_instructions_;
public:
InstructionScheduler() = default;
@@ -1103,7 +1135,7 @@ class InstructionScheduler {
InstructionIndices new_indices;
new_indices.is_owned = false;
new_indices.referenced_indices = mask;
- indices_by_instruction_.lookup_or_add_default(&instruction).append(std::move(new_indices));
+ next_instructions_.push({&instruction, std::move(new_indices)});
}
void add_owned_indices(const MFInstruction &instruction, Vector<int64_t> indices)
@@ -1116,43 +1148,28 @@ class InstructionScheduler {
InstructionIndices new_indices;
new_indices.is_owned = true;
new_indices.owned_indices = std::move(indices);
- indices_by_instruction_.lookup_or_add_default(&instruction).append(std::move(new_indices));
+ next_instructions_.push({&instruction, std::move(new_indices)});
}
- void add_previous_instruction_indices(const MFInstruction &instruction,
- NextInstructionInfo &instr_info)
+ bool is_done() const
{
- indices_by_instruction_.lookup_or_add_default(&instruction)
- .append(std::move(instr_info.indices));
+ return next_instructions_.is_empty();
}
- NextInstructionInfo pop_next()
+ const NextInstructionInfo &peek() const
{
- if (indices_by_instruction_.is_empty()) {
- return {};
- }
- /* TODO: Implement better mechanism to determine next instruction. */
- const MFInstruction *instruction = *indices_by_instruction_.keys().begin();
+ BLI_assert(!this->is_done());
+ return next_instructions_.peek();
+ }
- NextInstructionInfo next_instruction_info;
- next_instruction_info.instruction = instruction;
- next_instruction_info.indices = this->pop_indices_array(instruction);
- return next_instruction_info;
+ void update_instruction_pointer(const MFInstruction &instruction)
+ {
+ next_instructions_.peek().instruction = &instruction;
}
- private:
- InstructionIndices pop_indices_array(const MFInstruction *instruction)
+ NextInstructionInfo pop()
{
- Vector<InstructionIndices> *indices = indices_by_instruction_.lookup_ptr(instruction);
- if (indices == nullptr) {
- return {};
- }
- InstructionIndices r_indices = (*indices).pop_last();
- BLI_assert(!r_indices.mask().is_empty());
- if (indices->is_empty()) {
- indices_by_instruction_.remove_contained(instruction);
- }
- return r_indices;
+ return next_instructions_.pop();
}
};
@@ -1160,23 +1177,26 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
{
BLI_assert(procedure_.validate());
+ AlignedBuffer<512, 64> local_buffer;
LinearAllocator<> linear_allocator;
+ linear_allocator.provide_buffer(local_buffer);
- VariableStates variable_states{linear_allocator, full_mask};
+ VariableStates variable_states{linear_allocator, procedure_, full_mask};
variable_states.add_initial_variable_states(*this, procedure_, params);
InstructionScheduler scheduler;
scheduler.add_referenced_indices(*procedure_.entry(), full_mask);
/* Loop until all indices got to a return instruction. */
- while (NextInstructionInfo instr_info = scheduler.pop_next()) {
+ while (!scheduler.is_done()) {
+ const NextInstructionInfo &instr_info = scheduler.peek();
const MFInstruction &instruction = *instr_info.instruction;
switch (instruction.type()) {
case MFInstructionType::Call: {
const MFCallInstruction &call_instruction = static_cast<const MFCallInstruction &>(
instruction);
execute_call_instruction(call_instruction, instr_info.mask(), variable_states, context);
- scheduler.add_previous_instruction_indices(*call_instruction.next(), instr_info);
+ scheduler.update_instruction_pointer(*call_instruction.next());
break;
}
case MFInstructionType::Branch: {
@@ -1187,6 +1207,7 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
IndicesSplitVectors new_indices;
variable_state.indices_split(instr_info.mask(), new_indices);
+ scheduler.pop();
scheduler.add_owned_indices(*branch_instruction.branch_false(), new_indices[false]);
scheduler.add_owned_indices(*branch_instruction.branch_true(), new_indices[true]);
break;
@@ -1196,17 +1217,18 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
static_cast<const MFDestructInstruction &>(instruction);
const MFVariable *variable = destruct_instruction.variable();
variable_states.destruct(*variable, instr_info.mask());
- scheduler.add_previous_instruction_indices(*destruct_instruction.next(), instr_info);
+ scheduler.update_instruction_pointer(*destruct_instruction.next());
break;
}
case MFInstructionType::Dummy: {
const MFDummyInstruction &dummy_instruction = static_cast<const MFDummyInstruction &>(
instruction);
- scheduler.add_previous_instruction_indices(*dummy_instruction.next(), instr_info);
+ scheduler.update_instruction_pointer(*dummy_instruction.next());
break;
}
case MFInstructionType::Return: {
/* Don't insert the indices back into the scheduler. */
+ scheduler.pop();
break;
}
}
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index 010c327d482..da83d9e8957 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -15,20 +15,32 @@ set(INC
)
set(SRC
+ intern/add_curves_on_mesh.cc
+ intern/fillet_curves.cc
intern/mesh_merge_by_distance.cc
intern/mesh_primitive_cuboid.cc
intern/mesh_to_curve_convert.cc
+ intern/mesh_to_volume.cc
intern/point_merge_by_distance.cc
intern/realize_instances.cc
intern/resample_curves.cc
+ intern/reverse_uv_sampler.cc
+ intern/set_curve_type.cc
+ intern/subdivide_curves.cc
intern/uv_parametrizer.c
+ GEO_add_curves_on_mesh.hh
+ GEO_fillet_curves.hh
GEO_mesh_merge_by_distance.hh
GEO_mesh_primitive_cuboid.hh
GEO_mesh_to_curve.hh
+ GEO_mesh_to_volume.hh
GEO_point_merge_by_distance.hh
GEO_realize_instances.hh
GEO_resample_curves.hh
+ GEO_reverse_uv_sampler.hh
+ GEO_set_curve_type.hh
+ GEO_subdivide_curves.hh
GEO_uv_parametrizer.h
)
@@ -37,6 +49,20 @@ set(LIB
bf_blenlib
)
+if(WITH_OPENVDB)
+ list(APPEND INC
+ ../../../intern/openvdb
+ )
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ bf_intern_openvdb
+ ${OPENVDB_LIBRARIES}
+ )
+ add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
+endif()
+
if(WITH_TBB)
add_definitions(-DWITH_TBB)
diff --git a/source/blender/geometry/GEO_add_curves_on_mesh.hh b/source/blender/geometry/GEO_add_curves_on_mesh.hh
new file mode 100644
index 00000000000..cf60a8e8ace
--- /dev/null
+++ b/source/blender/geometry/GEO_add_curves_on_mesh.hh
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_float4x4.hh"
+#include "BLI_kdtree.h"
+#include "BLI_math_vector.hh"
+#include "BLI_span.hh"
+
+#include "BKE_bvhutils.h"
+#include "BKE_curves.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+namespace blender::geometry {
+
+struct AddCurvesOnMeshInputs {
+ /** Information about the root points where new curves should be generated. */
+ Span<float3> root_positions_cu;
+ Span<float3> bary_coords;
+ Span<int> looptri_indices;
+
+ /** Determines shape of new curves. */
+ bool interpolate_length = false;
+ bool interpolate_shape = false;
+ bool interpolate_point_count = false;
+ float fallback_curve_length = 0.0f;
+ int fallback_point_count = 0;
+
+ /** Information about the surface that the new curves are attached to. */
+ const Mesh *surface = nullptr;
+ BVHTreeFromMesh *surface_bvh = nullptr;
+ Span<MLoopTri> surface_looptris;
+ Span<float2> surface_uv_map;
+ Span<float3> corner_normals_su;
+
+ /** Transformation matrices. */
+ float4x4 curves_to_surface_mat;
+ float4x4 surface_to_curves_normal_mat;
+
+ /**
+ * KD-Tree that contains the root points of existing curves. This is only necessary when
+ * interpolation is used.
+ */
+ KDTree_3d *old_roots_kdtree = nullptr;
+};
+
+/**
+ * Generate new curves on a mesh surface with the given inputs. Existing curves stay intact.
+ */
+void add_curves_on_mesh(bke::CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_fillet_curves.hh b/source/blender/geometry/GEO_fillet_curves.hh
new file mode 100644
index 00000000000..1f832f8b6cc
--- /dev/null
+++ b/source/blender/geometry/GEO_fillet_curves.hh
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_function_ref.hh"
+#include "BLI_index_mask.hh"
+
+#include "BKE_curves.hh"
+
+namespace blender::geometry {
+
+bke::CurvesGeometry fillet_curves_poly(const bke::CurvesGeometry &src_curves,
+ IndexMask curve_selection,
+ const VArray<float> &radius,
+ const VArray<int> &counts,
+ bool limit_radius);
+
+bke::CurvesGeometry fillet_curves_bezier(const bke::CurvesGeometry &src_curves,
+ IndexMask curve_selection,
+ const VArray<float> &radius,
+ bool limit_radius);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_mesh_to_curve.hh b/source/blender/geometry/GEO_mesh_to_curve.hh
index c480e4178cf..f619aaff217 100644
--- a/source/blender/geometry/GEO_mesh_to_curve.hh
+++ b/source/blender/geometry/GEO_mesh_to_curve.hh
@@ -1,12 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#pragma once
+
#include "BLI_index_mask.hh"
-#pragma once
+#include "BKE_curves.hh"
struct Mesh;
-struct Curves;
-class MeshComponent;
/** \file
* \ingroup geo
@@ -15,10 +15,10 @@ class MeshComponent;
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
+ * Convert the mesh into one or many poly curves. Since curves cannot have branches,
+ * intersections of more than three edges will become breaks in curves. Attributes that
* are not built-in on meshes and not curves are transferred to the result curve.
*/
-Curves *mesh_to_curve_convert(const MeshComponent &mesh_component, const IndexMask selection);
+bke::CurvesGeometry mesh_to_curve_convert(const Mesh &mesh, const IndexMask selection);
} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_mesh_to_volume.hh b/source/blender/geometry/GEO_mesh_to_volume.hh
new file mode 100644
index 00000000000..c95b472936b
--- /dev/null
+++ b/source/blender/geometry/GEO_mesh_to_volume.hh
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_float4x4.hh"
+#include "BLI_function_ref.hh"
+#include "BLI_string_ref.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#pragma once
+
+struct Volume;
+struct VolumeGrid;
+struct Depsgraph;
+
+/** \file
+ * \ingroup geo
+ */
+
+namespace blender::geometry {
+
+struct MeshToVolumeResolution {
+ MeshToVolumeModifierResolutionMode mode;
+ union {
+ float voxel_size;
+ float voxel_amount;
+ } settings;
+};
+
+#ifdef WITH_OPENVDB
+
+/**
+ * \param bounds_fn: Return the bounds of the mesh positions,
+ * used for deciding the voxel size in "Amount" mode.
+ */
+float volume_compute_voxel_size(const Depsgraph *depsgraph,
+ FunctionRef<void(float3 &r_min, float3 &r_max)> bounds_fn,
+ const MeshToVolumeResolution resolution,
+ float exterior_band_width,
+ const float4x4 &transform);
+/**
+ * Add a new VolumeGrid to the Volume by converting the supplied mesh
+ */
+VolumeGrid *volume_grid_add_from_mesh(Volume *volume,
+ const StringRefNull name,
+ const Mesh *mesh,
+ const float4x4 &mesh_to_volume_space_transform,
+ float voxel_size,
+ bool fill_volume,
+ float exterior_band_width,
+ float interior_band_width,
+ float density);
+#endif
+} // 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
index 1e977cf3bdc..92d871c62ab 100644
--- a/source/blender/geometry/GEO_point_merge_by_distance.hh
+++ b/source/blender/geometry/GEO_point_merge_by_distance.hh
@@ -17,7 +17,7 @@ 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,
+PointCloud *point_merge_by_distance(const PointCloud &src_points,
const float merge_distance,
const IndexMask selection);
diff --git a/source/blender/geometry/GEO_reverse_uv_sampler.hh b/source/blender/geometry/GEO_reverse_uv_sampler.hh
new file mode 100644
index 00000000000..ee91e0b0731
--- /dev/null
+++ b/source/blender/geometry/GEO_reverse_uv_sampler.hh
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_math_vector.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_span.hh"
+
+#include "DNA_meshdata_types.h"
+
+namespace blender::geometry {
+
+/**
+ * Can find the polygon/triangle that maps to a specific uv coordinate.
+ *
+ * \note this uses a trivial implementation currently that has to be replaced.
+ */
+class ReverseUVSampler {
+ private:
+ const Span<float2> uv_map_;
+ const Span<MLoopTri> looptris_;
+ int resolution_;
+ MultiValueMap<int2, int> looptris_by_cell_;
+
+ public:
+ ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris);
+
+ enum class ResultType {
+ None,
+ Ok,
+ Multiple,
+ };
+
+ struct Result {
+ ResultType type = ResultType::None;
+ const MLoopTri *looptri = nullptr;
+ float3 bary_weights;
+ };
+
+ Result sample(const float2 &query_uv) const;
+ void sample_many(Span<float2> query_uvs, MutableSpan<Result> r_results) const;
+};
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_set_curve_type.hh b/source/blender/geometry/GEO_set_curve_type.hh
new file mode 100644
index 00000000000..f38e63b1fc8
--- /dev/null
+++ b/source/blender/geometry/GEO_set_curve_type.hh
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_function_ref.hh"
+#include "BLI_index_mask.hh"
+
+#include "BKE_curves.hh"
+
+namespace blender::geometry {
+
+/**
+ * Try the conversion to the #dst_type-- avoiding the majority of the work done in
+ * #convert_curves by modifying an existing object in place rather than creating a new one.
+ *
+ * \note This function is necessary because attributes do not have proper support for CoW.
+ *
+ * \param get_writable_curves_fn: Should return the write-able curves to change directly if
+ * possible. This is a function in order to avoid the cost of retrieval when unnecessary.
+ */
+bool try_curves_conversion_in_place(IndexMask selection,
+ CurveType dst_type,
+ FunctionRef<bke::CurvesGeometry &()> get_writable_curves_fn);
+
+/**
+ * Change the types of the selected curves, potentially changing the total point count.
+ */
+bke::CurvesGeometry convert_curves(const bke::CurvesGeometry &src_curves,
+ IndexMask selection,
+ CurveType dst_type);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_subdivide_curves.hh b/source/blender/geometry/GEO_subdivide_curves.hh
new file mode 100644
index 00000000000..ba55118baa4
--- /dev/null
+++ b/source/blender/geometry/GEO_subdivide_curves.hh
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_function_ref.hh"
+#include "BLI_index_mask.hh"
+#include "BLI_virtual_array.hh"
+
+#include "BKE_curves.hh"
+
+namespace blender::geometry {
+
+/**
+ * Add more points along each segment, with the amount of points to add in each segment described
+ * by the #cuts input. The new points are equidistant in parameter space, but not in the actual
+ * distances.
+ *
+ * \param selection: A selection of curves to consider when subdividing.
+ */
+bke::CurvesGeometry subdivide_curves(const bke::CurvesGeometry &src_curves,
+ IndexMask selection,
+ const VArray<int> &cuts);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_uv_parametrizer.h b/source/blender/geometry/GEO_uv_parametrizer.h
index 624b0695aa3..5285aefbd4c 100644
--- a/source/blender/geometry/GEO_uv_parametrizer.h
+++ b/source/blender/geometry/GEO_uv_parametrizer.h
@@ -14,10 +14,7 @@ extern "C" {
typedef struct ParamHandle ParamHandle; /* Handle to an array of charts. */
typedef intptr_t ParamKey; /* Key (hash) for identifying verts and faces. */
-typedef enum ParamBool {
- PARAM_TRUE = 1,
- PARAM_FALSE = 0,
-} ParamBool;
+#define PARAM_KEY_MAX INTPTR_MAX
/* -------------------------------------------------------------------- */
/** \name Chart Construction:
@@ -38,20 +35,24 @@ ParamHandle *GEO_uv_parametrizer_construct_begin(void);
void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy);
+void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
+
+ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
+
void GEO_uv_parametrizer_face_add(ParamHandle *handle,
- ParamKey key,
- int nverts,
- ParamKey *vkeys,
- float *co[4],
- float *uv[4],
- ParamBool *pin,
- ParamBool *select);
+ const ParamKey key,
+ const int nverts,
+ const ParamKey *vkeys,
+ const float **co,
+ float **uv, /* Output will eventually be written to `uv`. */
+ const bool *pin,
+ const bool *select);
void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys);
void GEO_uv_parametrizer_construct_end(ParamHandle *handle,
- ParamBool fill,
- ParamBool topology_from_uvs,
+ bool fill,
+ bool topology_from_uvs,
int *count_fail);
void GEO_uv_parametrizer_delete(ParamHandle *handle);
@@ -70,7 +71,7 @@ void GEO_uv_parametrizer_delete(ParamHandle *handle);
*
* \{ */
-void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf);
+void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, bool live, bool abf);
void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed);
void GEO_uv_parametrizer_lscm_end(ParamHandle *handle);
@@ -88,14 +89,6 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *handle);
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Area Smooth
- * \{ */
-
-void GEO_uv_parametrizer_smooth_area(ParamHandle *handle);
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Packing
* \{ */
@@ -110,7 +103,10 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
/** \name Average area for all charts
* \{ */
-void GEO_uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned);
+void GEO_uv_parametrizer_average(ParamHandle *handle,
+ bool ignore_pinned,
+ bool scale_uv,
+ bool shear);
/** \} */
diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc
new file mode 100644
index 00000000000..e54e2bdd3b0
--- /dev/null
+++ b/source/blender/geometry/intern/add_curves_on_mesh.cc
@@ -0,0 +1,370 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_length_parameterize.hh"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh_sample.hh"
+
+#include "GEO_add_curves_on_mesh.hh"
+
+/**
+ * The code below uses a suffix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * su: Local space of the surface object.
+ */
+
+namespace blender::geometry {
+
+using bke::CurvesGeometry;
+
+struct NeighborCurve {
+ /* Curve index of the neighbor. */
+ int index;
+ /* The weights of all neighbors of a new curve add up to 1. */
+ float weight;
+};
+
+static constexpr int max_neighbors = 5;
+using NeighborCurves = Vector<NeighborCurve, max_neighbors>;
+
+static float3 compute_surface_point_normal(const MLoopTri &looptri,
+ const float3 &bary_coord,
+ const Span<float3> corner_normals)
+{
+ const int l0 = looptri.tri[0];
+ const int l1 = looptri.tri[1];
+ const int l2 = looptri.tri[2];
+
+ const float3 &l0_normal = corner_normals[l0];
+ const float3 &l1_normal = corner_normals[l1];
+ const float3 &l2_normal = corner_normals[l2];
+
+ const float3 normal = math::normalize(
+ attribute_math::mix3(bary_coord, l0_normal, l1_normal, l2_normal));
+ return normal;
+}
+
+static void initialize_straight_curve_positions(const float3 &p1,
+ const float3 &p2,
+ MutableSpan<float3> r_positions)
+{
+ const float step = 1.0f / (float)(r_positions.size() - 1);
+ for (const int i : r_positions.index_range()) {
+ r_positions[i] = math::interpolate(p1, p2, i * step);
+ }
+}
+
+static Array<NeighborCurves> find_curve_neighbors(const Span<float3> root_positions,
+ const KDTree_3d &old_roots_kdtree)
+{
+ const int tot_added_curves = root_positions.size();
+ Array<NeighborCurves> neighbors_per_curve(tot_added_curves);
+ threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) {
+ for (const int i : range) {
+ const float3 root = root_positions[i];
+ std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
+ const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
+ &old_roots_kdtree, root, nearest_n.data(), max_neighbors);
+ float tot_weight = 0.0f;
+ for (const int neighbor_i : IndexRange(found_neighbors)) {
+ KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
+ const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
+ tot_weight += weight;
+ neighbors_per_curve[i].append({nearest.index, weight});
+ }
+ /* Normalize weights. */
+ for (NeighborCurve &neighbor : neighbors_per_curve[i]) {
+ neighbor.weight /= tot_weight;
+ }
+ }
+ });
+ return neighbors_per_curve;
+}
+
+template<typename T, typename GetValueF>
+void interpolate_from_neighbors(const Span<NeighborCurves> neighbors_per_curve,
+ const T &fallback,
+ const GetValueF &get_value_from_neighbor,
+ MutableSpan<T> r_interpolated_values)
+{
+ attribute_math::DefaultMixer<T> mixer{r_interpolated_values};
+ threading::parallel_for(r_interpolated_values.index_range(), 512, [&](const IndexRange range) {
+ for (const int i : range) {
+ const NeighborCurves &neighbors = neighbors_per_curve[i];
+ if (neighbors.is_empty()) {
+ mixer.mix_in(i, fallback, 1.0f);
+ }
+ else {
+ for (const NeighborCurve &neighbor : neighbors) {
+ const T neighbor_value = get_value_from_neighbor(neighbor.index);
+ mixer.mix_in(i, neighbor_value, neighbor.weight);
+ }
+ }
+ }
+ });
+ mixer.finalize();
+}
+
+static void interpolate_position_without_interpolation(
+ CurvesGeometry &curves,
+ const int old_curves_num,
+ const Span<float3> root_positions_cu,
+ const Span<float> new_lengths_cu,
+ const Span<float3> new_normals_su,
+ const float4x4 &surface_to_curves_normal_mat)
+{
+ const int added_curves_num = root_positions_cu.size();
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int curve_i = old_curves_num + i;
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const float3 &root_cu = root_positions_cu[i];
+ const float length = new_lengths_cu[i];
+ const float3 &normal_su = new_normals_su[i];
+ const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su);
+ const float3 tip_cu = root_cu + length * normal_cu;
+
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
+ }
+ });
+}
+
+static void interpolate_position_with_interpolation(CurvesGeometry &curves,
+ const Span<float3> root_positions_cu,
+ const Span<NeighborCurves> neighbors_per_curve,
+ const int old_curves_num,
+ const Span<float> new_lengths_cu,
+ const Span<float3> new_normals_su,
+ const float4x4 &surface_to_curves_normal_mat,
+ const float4x4 &curves_to_surface_mat,
+ const BVHTreeFromMesh &surface_bvh,
+ const Span<MLoopTri> surface_looptris,
+ const Mesh &surface,
+ const Span<float3> corner_normals_su)
+{
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ const int added_curves_num = root_positions_cu.size();
+
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int added_curve_i : range) {
+ const NeighborCurves &neighbors = neighbors_per_curve[added_curve_i];
+ const int curve_i = old_curves_num + added_curve_i;
+ const IndexRange points = curves.points_for_curve(curve_i);
+
+ const float length_cu = new_lengths_cu[added_curve_i];
+ const float3 &normal_su = new_normals_su[added_curve_i];
+ const float3 normal_cu = math::normalize(surface_to_curves_normal_mat * normal_su);
+
+ const float3 &root_cu = root_positions_cu[added_curve_i];
+
+ if (neighbors.is_empty()) {
+ /* If there are no neighbors, just make a straight line. */
+ const float3 tip_cu = root_cu + length_cu * normal_cu;
+ initialize_straight_curve_positions(root_cu, tip_cu, positions_cu.slice(points));
+ continue;
+ }
+
+ positions_cu.slice(points).fill(root_cu);
+
+ for (const NeighborCurve &neighbor : neighbors) {
+ const int neighbor_curve_i = neighbor.index;
+ const float3 &neighbor_first_pos_cu = positions_cu[curves.offsets()[neighbor_curve_i]];
+ const float3 neighbor_first_pos_su = curves_to_surface_mat * neighbor_first_pos_cu;
+
+ BVHTreeNearest nearest;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(surface_bvh.tree,
+ neighbor_first_pos_su,
+ &nearest,
+ surface_bvh.nearest_callback,
+ const_cast<BVHTreeFromMesh *>(&surface_bvh));
+ const int neighbor_looptri_index = nearest.index;
+ const MLoopTri &neighbor_looptri = surface_looptris[neighbor_looptri_index];
+
+ const float3 neighbor_bary_coord =
+ bke::mesh_surface_sample::compute_bary_coord_in_triangle(
+ surface, neighbor_looptri, nearest.co);
+
+ const float3 neighbor_normal_su = compute_surface_point_normal(
+ surface_looptris[neighbor_looptri_index], neighbor_bary_coord, corner_normals_su);
+ const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat *
+ neighbor_normal_su);
+
+ /* The rotation matrix used to transform relative coordinates of the neighbor curve
+ * to the new curve. */
+ float normal_rotation_cu[3][3];
+ rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
+
+ const IndexRange neighbor_points = curves.points_for_curve(neighbor_curve_i);
+ const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
+
+ /* Sample the positions on neighbors and mix them into the final positions of the curve.
+ * Resampling is necessary if the length of the new curve does not match the length of the
+ * neighbors or the number of handle points is different.
+ *
+ * TODO: The lengths can be cached so they aren't recomputed if a curve is a neighbor for
+ * multiple new curves. Also, allocations could be avoided by reusing some arrays. */
+
+ const Span<float3> neighbor_positions_cu = positions_cu.slice(neighbor_points);
+ if (neighbor_positions_cu.size() == 1) {
+ /* Skip interpolating positions from neighbors with only one point. */
+ continue;
+ }
+ Array<float, 32> lengths(length_parameterize::segments_num(neighbor_points.size(), false));
+ length_parameterize::accumulate_lengths<float3>(neighbor_positions_cu, false, lengths);
+ const float neighbor_length_cu = lengths.last();
+
+ Array<float, 32> sample_lengths(points.size());
+ const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
+ const float resample_factor = (1.0f / (points.size() - 1.0f)) * length_factor;
+ for (const int i : sample_lengths.index_range()) {
+ sample_lengths[i] = i * resample_factor * neighbor_length_cu;
+ }
+
+ Array<int, 32> indices(points.size());
+ Array<float, 32> factors(points.size());
+ length_parameterize::sample_at_lengths(lengths, sample_lengths, indices, factors);
+
+ for (const int i : IndexRange(points.size())) {
+ const float3 sample_cu = math::interpolate(neighbor_positions_cu[indices[i]],
+ neighbor_positions_cu[indices[i] + 1],
+ factors[i]);
+ const float3 relative_to_root_cu = sample_cu - neighbor_root_cu;
+ float3 rotated_relative_coord = relative_to_root_cu;
+ mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
+ positions_cu[points[i]] += neighbor.weight * rotated_relative_coord;
+ }
+ }
+ }
+ });
+}
+
+void add_curves_on_mesh(CurvesGeometry &curves, const AddCurvesOnMeshInputs &inputs)
+{
+ const bool use_interpolation = inputs.interpolate_length || inputs.interpolate_point_count ||
+ inputs.interpolate_shape;
+
+ Array<NeighborCurves> neighbors_per_curve;
+ if (use_interpolation) {
+ BLI_assert(inputs.old_roots_kdtree != nullptr);
+ neighbors_per_curve = find_curve_neighbors(inputs.root_positions_cu, *inputs.old_roots_kdtree);
+ }
+
+ const int added_curves_num = inputs.root_positions_cu.size();
+ const int old_points_num = curves.points_num();
+ const int old_curves_num = curves.curves_num();
+ const int new_curves_num = old_curves_num + added_curves_num;
+
+ /* Grow number of curves first, so that the offsets array can be filled. */
+ curves.resize(old_points_num, new_curves_num);
+
+ /* Compute new curve offsets. */
+ MutableSpan<int> curve_offsets = curves.offsets_for_write();
+ MutableSpan<int> new_point_counts_per_curve = curve_offsets.take_back(added_curves_num);
+ if (inputs.interpolate_point_count) {
+ interpolate_from_neighbors<int>(
+ neighbors_per_curve,
+ inputs.fallback_point_count,
+ [&](const int curve_i) { return curves.points_for_curve(curve_i).size(); },
+ new_point_counts_per_curve);
+ }
+ else {
+ new_point_counts_per_curve.fill(inputs.fallback_point_count);
+ }
+ for (const int i : IndexRange(added_curves_num)) {
+ curve_offsets[old_curves_num + i + 1] += curve_offsets[old_curves_num + i];
+ }
+
+ const int new_points_num = curves.offsets().last();
+ curves.resize(new_points_num, new_curves_num);
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+
+ /* Determine length of new curves. */
+ Array<float> new_lengths_cu(added_curves_num);
+ if (inputs.interpolate_length) {
+ interpolate_from_neighbors<float>(
+ neighbors_per_curve,
+ inputs.fallback_curve_length,
+ [&](const int curve_i) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ float length = 0.0f;
+ for (const int segment_i : points.drop_back(1)) {
+ const float3 &p1 = positions_cu[segment_i];
+ const float3 &p2 = positions_cu[segment_i + 1];
+ length += math::distance(p1, p2);
+ }
+ return length;
+ },
+ new_lengths_cu);
+ }
+ else {
+ new_lengths_cu.fill(inputs.fallback_curve_length);
+ }
+
+ /* Find surface normal at root points. */
+ Array<float3> new_normals_su(added_curves_num);
+ threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int looptri_index = inputs.looptri_indices[i];
+ const float3 &bary_coord = inputs.bary_coords[i];
+ new_normals_su[i] = compute_surface_point_normal(
+ inputs.surface_looptris[looptri_index], bary_coord, inputs.corner_normals_su);
+ }
+ });
+
+ /* Propagate attachment information. */
+ if (!inputs.surface_uv_map.is_empty()) {
+ MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
+ bke::mesh_surface_sample::sample_corner_attribute(
+ *inputs.surface,
+ inputs.looptri_indices,
+ inputs.bary_coords,
+ GVArray::ForSpan(inputs.surface_uv_map),
+ IndexRange(added_curves_num),
+ surface_uv_coords.take_back(added_curves_num));
+ }
+
+ /* Update selection arrays when available. */
+ const VArray<float> points_selection = curves.selection_point_float();
+ if (points_selection.is_span()) {
+ MutableSpan<float> points_selection_span = curves.selection_point_float_for_write();
+ points_selection_span.drop_front(old_points_num).fill(1.0f);
+ }
+ const VArray<float> curves_selection = curves.selection_curve_float();
+ if (curves_selection.is_span()) {
+ MutableSpan<float> curves_selection_span = curves.selection_curve_float_for_write();
+ curves_selection_span.drop_front(old_curves_num).fill(1.0f);
+ }
+
+ /* Initialize position attribute. */
+ if (inputs.interpolate_shape) {
+ interpolate_position_with_interpolation(curves,
+ inputs.root_positions_cu,
+ neighbors_per_curve,
+ old_curves_num,
+ new_lengths_cu,
+ new_normals_su,
+ inputs.surface_to_curves_normal_mat,
+ inputs.curves_to_surface_mat,
+ *inputs.surface_bvh,
+ inputs.surface_looptris,
+ *inputs.surface,
+ inputs.corner_normals_su);
+ }
+ else {
+ interpolate_position_without_interpolation(curves,
+ old_curves_num,
+ inputs.root_positions_cu,
+ new_lengths_cu,
+ new_normals_su,
+ inputs.surface_to_curves_normal_mat);
+ }
+
+ /* Set curve types. */
+ MutableSpan<int8_t> types_span = curves.curve_types_for_write();
+ types_span.drop_front(old_curves_num).fill(CURVE_TYPE_CATMULL_ROM);
+ curves.update_curve_types();
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/fillet_curves.cc b/source/blender/geometry/intern/fillet_curves.cc
new file mode 100644
index 00000000000..2cca91f40ae
--- /dev/null
+++ b/source/blender/geometry/intern/fillet_curves.cc
@@ -0,0 +1,561 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
+
+#include "BLI_devirtualize_parameters.hh"
+#include "BLI_math_geom.h"
+#include "BLI_math_rotation.hh"
+#include "BLI_task.hh"
+
+#include "GEO_fillet_curves.hh"
+
+namespace blender::geometry {
+
+/**
+ * Return a range used to retrieve values from an array of values stored per point, but with an
+ * extra element at the end of each curve. This is useful for offsets within curves, where it is
+ * convenient to store the first 0 and have the last offset be the total result curve size.
+ */
+static IndexRange curve_dst_offsets(const IndexRange points, const int curve_index)
+{
+ return {curve_index + points.start(), points.size() + 1};
+}
+
+template<typename T>
+static void threaded_slice_fill(const Span<T> src, const Span<int> offsets, MutableSpan<T> dst)
+{
+ threading::parallel_for(src.index_range(), 512, [&](IndexRange range) {
+ for (const int i : range) {
+ dst.slice(bke::offsets_to_range(offsets, i)).fill(src[i]);
+ }
+ });
+}
+
+template<typename T>
+static void duplicate_fillet_point_data(const bke::CurvesGeometry &src_curves,
+ const bke::CurvesGeometry &dst_curves,
+ const IndexMask curve_selection,
+ const Span<int> point_offsets,
+ const Span<T> src,
+ MutableSpan<T> dst)
+{
+ threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) {
+ for (const int curve_i : curve_selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+ const Span<int> offsets = point_offsets.slice(curve_dst_offsets(src_points, curve_i));
+ threaded_slice_fill(src.slice(src_points), offsets, dst.slice(dst_points));
+ }
+ });
+}
+
+static void duplicate_fillet_point_data(const bke::CurvesGeometry &src_curves,
+ const bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<int> point_offsets,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ duplicate_fillet_point_data(
+ src_curves, dst_curves, selection, point_offsets, src.typed<T>(), dst.typed<T>());
+ });
+}
+
+static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const Span<IndexRange> unselected_ranges,
+ const VArray<float> &radii,
+ const VArray<int> &counts,
+ const Span<bool> cyclic,
+ MutableSpan<int> dst_curve_offsets,
+ MutableSpan<int> dst_point_offsets)
+{
+ /* Fill the offsets array with the curve point counts, then accumulate them to form offsets. */
+ bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_curve_offsets);
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int curve_i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange offsets_range = curve_dst_offsets(src_points, curve_i);
+
+ MutableSpan<int> point_offsets = dst_point_offsets.slice(offsets_range);
+ MutableSpan<int> point_counts = point_offsets.drop_back(1);
+
+ counts.materialize_compressed(src_points, point_counts);
+ for (int &count : point_counts) {
+ /* Make sure the number of cuts is greater than zero and add one for the existing point. */
+ count = std::max(count, 0) + 1;
+ }
+ if (!cyclic[curve_i]) {
+ /* Endpoints on non-cyclic curves cannot be filleted. */
+ point_counts.first() = 1;
+ point_counts.last() = 1;
+ }
+ /* Implicitly "deselect" points with zero radius. */
+ devirtualize_varray(radii, [&](const auto radii) {
+ for (const int i : IndexRange(src_points.size())) {
+ if (radii[i] == 0.0f) {
+ point_counts[i] = 1;
+ }
+ }
+ });
+
+ bke::curves::accumulate_counts_to_offsets(point_offsets);
+
+ dst_curve_offsets[curve_i] = point_offsets.last();
+ }
+ });
+ bke::curves::accumulate_counts_to_offsets(dst_curve_offsets);
+}
+
+static void calculate_directions(const Span<float3> positions, MutableSpan<float3> directions)
+{
+ for (const int i : positions.index_range().drop_back(1)) {
+ directions[i] = math::normalize(positions[i + 1] - positions[i]);
+ }
+ directions.last() = math::normalize(positions.first() - positions.last());
+}
+
+static void calculate_angles(const Span<float3> directions, MutableSpan<float> angles)
+{
+ angles.first() = M_PI - angle_v3v3(-directions.last(), directions.first());
+ for (const int i : directions.index_range().drop_front(1)) {
+ angles[i] = M_PI - angle_v3v3(-directions[i - 1], directions[i]);
+ }
+}
+
+/**
+ * Find the portion of the previous and next segments used by the current and next point fillets.
+ * If more than the total length of the segment would be used, scale the current point's radius
+ * just enough to make the two points meet in the middle.
+ */
+static float limit_radius(const float3 &position_prev,
+ const float3 &position,
+ const float3 &position_next,
+ const float angle_prev,
+ const float angle,
+ const float angle_next,
+ const float radius_prev,
+ const float radius,
+ const float radius_next)
+{
+ const float displacement = radius * std::tan(angle / 2.0f);
+
+ const float displacement_prev = radius_prev * std::tan(angle_prev / 2.0f);
+ const float segment_length_prev = math::distance(position, position_prev);
+ const float total_displacement_prev = displacement_prev + displacement;
+ const float factor_prev = std::clamp(segment_length_prev / total_displacement_prev, 0.0f, 1.0f);
+
+ const float displacement_next = radius_next * std::tan(angle_next / 2.0f);
+ const float segment_length_next = math::distance(position, position_next);
+ const float total_displacement_next = displacement_next + displacement;
+ const float factor_next = std::clamp(segment_length_next / total_displacement_next, 0.0f, 1.0f);
+
+ return radius * std::min(factor_prev, factor_next);
+}
+
+static void limit_radii(const Span<float3> positions,
+ const Span<float> angles,
+ const Span<float> radii,
+ const bool cyclic,
+ MutableSpan<float> radii_clamped)
+{
+ if (cyclic) {
+ /* First point. */
+ radii_clamped.first() = limit_radius(positions.last(),
+ positions.first(),
+ positions[1],
+ angles.last(),
+ angles.first(),
+ angles[1],
+ radii.last(),
+ radii.first(),
+ radii[1]);
+ /* All middle points. */
+ for (const int i : positions.index_range().drop_back(1).drop_front(1)) {
+ const int i_prev = i - 1;
+ const int i_next = i + 1;
+ radii_clamped[i] = limit_radius(positions[i_prev],
+ positions[i],
+ positions[i_next],
+ angles[i_prev],
+ angles[i],
+ angles[i_next],
+ radii[i_prev],
+ radii[i],
+ radii[i_next]);
+ }
+ /* Last point. */
+ radii_clamped.last() = limit_radius(positions.last(1),
+ positions.last(),
+ positions.first(),
+ angles.last(1),
+ angles.last(),
+ angles.first(),
+ radii.last(1),
+ radii.last(),
+ radii.first());
+ }
+ else {
+ const int i_last = positions.index_range().last();
+ /* First point. */
+ radii_clamped.first() = 0.0f;
+ /* All middle points. */
+ for (const int i : positions.index_range().drop_back(1).drop_front(1)) {
+ const int i_prev = i - 1;
+ const int i_next = i + 1;
+ /* Use a zero radius for the first and last points, because they don't have fillets.
+ * This logic could potentially be unrolled, but it doesn't seem worth it. */
+ const float radius_prev = i_prev == 0 ? 0.0f : radii[i_prev];
+ const float radius_next = i_next == i_last ? 0.0f : radii[i_next];
+ radii_clamped[i] = limit_radius(positions[i_prev],
+ positions[i],
+ positions[i_next],
+ angles[i_prev],
+ angles[i],
+ angles[i_next],
+ radius_prev,
+ radii[i],
+ radius_next);
+ }
+ /* Last point. */
+ radii_clamped.last() = 0.0f;
+ }
+}
+
+static void calculate_fillet_positions(const Span<float3> src_positions,
+ const Span<float> angles,
+ const Span<float> radii,
+ const Span<float3> directions,
+ const Span<int> dst_offsets,
+ MutableSpan<float3> dst)
+{
+ const int i_src_last = src_positions.index_range().last();
+ threading::parallel_for(src_positions.index_range(), 512, [&](IndexRange range) {
+ for (const int i_src : range) {
+ const IndexRange arc = bke::offsets_to_range(dst_offsets, i_src);
+ const float3 &src = src_positions[i_src];
+ if (arc.size() == 1) {
+ dst[arc.first()] = src;
+ continue;
+ }
+
+ const int i_src_prev = i_src == 0 ? i_src_last : i_src - 1;
+ const float angle = angles[i_src];
+ const float radius = radii[i_src];
+ const float displacement = radius * std::tan(angle / 2.0f);
+ const float3 prev_dir = -directions[i_src_prev];
+ const float3 &next_dir = directions[i_src];
+ const float3 arc_start = src + prev_dir * displacement;
+ const float3 arc_end = src + next_dir * displacement;
+
+ dst[arc.first()] = arc_start;
+ dst[arc.last()] = arc_end;
+
+ const IndexRange middle = arc.drop_front(1).drop_back(1);
+ if (middle.is_empty()) {
+ continue;
+ }
+
+ const float3 axis = -math::normalize(math::cross(prev_dir, next_dir));
+ const float3 center_direction = math::normalize(math::midpoint(next_dir, prev_dir));
+ const float distance_to_center = std::sqrt(pow2f(radius) + pow2f(displacement));
+ const float3 center = src + center_direction * distance_to_center;
+
+ /* Rotate each middle fillet point around the center. */
+ const float segment_angle = angle / (middle.size() + 1);
+ for (const int i : IndexRange(middle.size())) {
+ const int point_i = middle[i];
+ dst[point_i] = math::rotate_around_axis(arc_start, center, axis, segment_angle * (i + 1));
+ }
+ }
+ });
+}
+
+/**
+ * Set handles for the "Bezier" mode where we rely on setting the inner handles to approximate a
+ * circular arc. The outer (previous and next) handles outside the result fillet segment are set
+ * to vector handles.
+ */
+static void calculate_bezier_handles_bezier_mode(const Span<float3> src_handles_l,
+ const Span<float3> src_handles_r,
+ const Span<int8_t> src_types_l,
+ const Span<int8_t> src_types_r,
+ const Span<float> angles,
+ const Span<float> radii,
+ const Span<float3> directions,
+ const Span<int> dst_offsets,
+ const Span<float3> dst_positions,
+ MutableSpan<float3> dst_handles_l,
+ MutableSpan<float3> dst_handles_r,
+ MutableSpan<int8_t> dst_types_l,
+ MutableSpan<int8_t> dst_types_r)
+{
+ const int i_src_last = src_handles_l.index_range().last();
+ const int i_dst_last = dst_positions.index_range().last();
+ threading::parallel_for(src_handles_l.index_range(), 512, [&](IndexRange range) {
+ for (const int i_src : range) {
+ const IndexRange arc = bke::offsets_to_range(dst_offsets, i_src);
+ if (arc.size() == 1) {
+ dst_handles_l[arc.first()] = src_handles_l[i_src];
+ dst_handles_r[arc.first()] = src_handles_r[i_src];
+ dst_types_l[arc.first()] = src_types_l[i_src];
+ dst_types_r[arc.first()] = src_types_r[i_src];
+ continue;
+ }
+ BLI_assert(arc.size() == 2);
+ const int i_dst_a = arc.first();
+ const int i_dst_b = arc.last();
+
+ const int i_src_prev = i_src == 0 ? i_src_last : i_src - 1;
+ const float angle = angles[i_src];
+ const float radius = radii[i_src];
+ const float3 prev_dir = -directions[i_src_prev];
+ const float3 &next_dir = directions[i_src];
+
+ const float3 &arc_start = dst_positions[arc.first()];
+ const float3 &arc_end = dst_positions[arc.last()];
+
+ /* Calculate the point's handles on the outside of the fillet segment,
+ * connecting to the next or previous result points. */
+ const int i_dst_prev = i_dst_a == 0 ? i_dst_last : i_dst_a - 1;
+ const int i_dst_next = i_dst_b == i_dst_last ? 0 : i_dst_b + 1;
+ dst_handles_l[i_dst_a] = bke::curves::bezier::calculate_vector_handle(
+ dst_positions[i_dst_a], dst_positions[i_dst_prev]);
+ dst_handles_r[i_dst_b] = bke::curves::bezier::calculate_vector_handle(
+ dst_positions[i_dst_b], dst_positions[i_dst_next]);
+ dst_types_l[i_dst_a] = BEZIER_HANDLE_VECTOR;
+ dst_types_r[i_dst_b] = BEZIER_HANDLE_VECTOR;
+
+ /* The inner handles are aligned with the aligned with the outer vector
+ * handles, but have a specific length to best approximate a circle. */
+ const float handle_length = (4.0f / 3.0f) * radius * std::tan(angle / 4.0f);
+ dst_handles_r[i_dst_a] = arc_start - prev_dir * handle_length;
+ dst_handles_l[i_dst_b] = arc_end - next_dir * handle_length;
+ dst_types_r[i_dst_a] = BEZIER_HANDLE_ALIGN;
+ dst_types_l[i_dst_b] = BEZIER_HANDLE_ALIGN;
+ }
+ });
+}
+
+/**
+ * In the poly fillet mode, all the inner handles are set to vector handles, along with the "outer"
+ * (previous and next) handles at each fillet.
+ */
+static void calculate_bezier_handles_poly_mode(const Span<float3> src_handles_l,
+ const Span<float3> src_handles_r,
+ const Span<int8_t> src_types_l,
+ const Span<int8_t> src_types_r,
+ const Span<int> dst_offsets,
+ const Span<float3> dst_positions,
+ MutableSpan<float3> dst_handles_l,
+ MutableSpan<float3> dst_handles_r,
+ MutableSpan<int8_t> dst_types_l,
+ MutableSpan<int8_t> dst_types_r)
+{
+ const int i_dst_last = dst_positions.index_range().last();
+ threading::parallel_for(src_handles_l.index_range(), 512, [&](IndexRange range) {
+ for (const int i_src : range) {
+ const IndexRange arc = bke::offsets_to_range(dst_offsets, i_src);
+ if (arc.size() == 1) {
+ dst_handles_l[arc.first()] = src_handles_l[i_src];
+ dst_handles_r[arc.first()] = src_handles_r[i_src];
+ dst_types_l[arc.first()] = src_types_l[i_src];
+ dst_types_r[arc.first()] = src_types_r[i_src];
+ continue;
+ }
+
+ /* The fillet's next and previous handles are vector handles, as are the inner handles. */
+ dst_types_l.slice(arc).fill(BEZIER_HANDLE_VECTOR);
+ dst_types_r.slice(arc).fill(BEZIER_HANDLE_VECTOR);
+
+ /* Calculate the point's handles on the outside of the fillet segment. This point
+ * won't be selected for a fillet if it is the first or last in a non-cyclic curve. */
+
+ const int i_dst_prev = arc.first() == 0 ? i_dst_last : arc.one_before_start();
+ const int i_dst_next = arc.last() == i_dst_last ? 0 : arc.one_after_last();
+ dst_handles_l[arc.first()] = bke::curves::bezier::calculate_vector_handle(
+ dst_positions[arc.first()], dst_positions[i_dst_prev]);
+ dst_handles_r[arc.last()] = bke::curves::bezier::calculate_vector_handle(
+ dst_positions[arc.last()], dst_positions[i_dst_next]);
+
+ /* Set the values for the inner handles. */
+ const IndexRange middle = arc.drop_front(1).drop_back(1);
+ for (const int i : middle) {
+ dst_handles_r[i] = bke::curves::bezier::calculate_vector_handle(dst_positions[i],
+ dst_positions[i - 1]);
+ dst_handles_l[i] = bke::curves::bezier::calculate_vector_handle(dst_positions[i],
+ dst_positions[i + 1]);
+ }
+ }
+ });
+}
+
+static bke::CurvesGeometry fillet_curves(const bke::CurvesGeometry &src_curves,
+ const IndexMask curve_selection,
+ const VArray<float> &radius_input,
+ const VArray<int> &counts,
+ const bool limit_radius,
+ const bool use_bezier_mode)
+{
+ const Vector<IndexRange> unselected_ranges = curve_selection.extract_ranges_invert(
+ src_curves.curves_range());
+
+ const Span<float3> positions = src_curves.positions();
+ const VArraySpan<bool> cyclic{src_curves.cyclic()};
+ const bke::AttributeAccessor src_attributes = src_curves.attributes();
+
+ bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
+ /* Stores the offset of every result point for every original point.
+ * The extra length is used in order to store an extra zero for every curve. */
+ Array<int> dst_point_offsets(src_curves.points_num() + src_curves.curves_num());
+ calculate_result_offsets(src_curves,
+ curve_selection,
+ unselected_ranges,
+ radius_input,
+ counts,
+ cyclic,
+ dst_curves.offsets_for_write(),
+ dst_point_offsets);
+ const Span<int> point_offsets = dst_point_offsets.as_span();
+
+ dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
+ bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ VArraySpan<int8_t> src_types_l;
+ VArraySpan<int8_t> src_types_r;
+ Span<float3> src_handles_l;
+ Span<float3> src_handles_r;
+ MutableSpan<int8_t> dst_types_l;
+ MutableSpan<int8_t> dst_types_r;
+ MutableSpan<float3> dst_handles_l;
+ MutableSpan<float3> dst_handles_r;
+ if (src_curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
+ src_types_l = src_curves.handle_types_left();
+ src_types_r = src_curves.handle_types_right();
+ src_handles_l = src_curves.handle_positions_left();
+ src_handles_r = src_curves.handle_positions_right();
+
+ dst_types_l = dst_curves.handle_types_left_for_write();
+ dst_types_r = dst_curves.handle_types_right_for_write();
+ dst_handles_l = dst_curves.handle_positions_left_for_write();
+ dst_handles_r = dst_curves.handle_positions_right_for_write();
+ }
+
+ threading::parallel_for(curve_selection.index_range(), 512, [&](IndexRange range) {
+ Array<float3> directions;
+ Array<float> angles;
+ Array<float> radii;
+ Array<float> input_radii_buffer;
+
+ for (const int curve_i : curve_selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const Span<int> offsets = point_offsets.slice(curve_dst_offsets(src_points, curve_i));
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+ const Span<float3> src_positions = positions.slice(src_points);
+
+ directions.reinitialize(src_points.size());
+ calculate_directions(src_positions, directions);
+
+ angles.reinitialize(src_points.size());
+ calculate_angles(directions, angles);
+
+ radii.reinitialize(src_points.size());
+ if (limit_radius) {
+ input_radii_buffer.reinitialize(src_points.size());
+ radius_input.materialize_compressed(src_points, input_radii_buffer);
+ limit_radii(src_positions, angles, input_radii_buffer, cyclic[curve_i], radii);
+ }
+ else {
+ radius_input.materialize_compressed(src_points, radii);
+ }
+
+ calculate_fillet_positions(positions.slice(src_points),
+ angles,
+ radii,
+ directions,
+ offsets,
+ dst_positions.slice(dst_points));
+
+ if (src_curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
+ if (use_bezier_mode) {
+ calculate_bezier_handles_bezier_mode(src_handles_l.slice(src_points),
+ src_handles_r.slice(src_points),
+ src_types_l.slice(src_points),
+ src_types_r.slice(src_points),
+ angles,
+ radii,
+ directions,
+ offsets,
+ dst_positions.slice(dst_points),
+ dst_handles_l.slice(dst_points),
+ dst_handles_r.slice(dst_points),
+ dst_types_l.slice(dst_points),
+ dst_types_r.slice(dst_points));
+ }
+ else {
+ calculate_bezier_handles_poly_mode(src_handles_l.slice(src_points),
+ src_handles_r.slice(src_points),
+ src_types_l.slice(src_points),
+ src_types_r.slice(src_points),
+ offsets,
+ dst_positions.slice(dst_points),
+ dst_handles_l.slice(dst_points),
+ dst_handles_r.slice(dst_points),
+ dst_types_l.slice(dst_points),
+ dst_types_r.slice(dst_points));
+ }
+ }
+ }
+ });
+
+ for (auto &attribute : bke::retrieve_attributes_for_transfer(
+ src_attributes,
+ dst_attributes,
+ ATTR_DOMAIN_MASK_POINT,
+ {"position", "handle_type_left", "handle_type_right", "handle_right", "handle_left"})) {
+ duplicate_fillet_point_data(
+ src_curves, dst_curves, curve_selection, point_offsets, attribute.src, attribute.dst.span);
+ attribute.dst.finish();
+ }
+
+ if (!unselected_ranges.is_empty()) {
+ for (auto &attribute : bke::retrieve_attributes_for_transfer(
+ src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT)) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span);
+ attribute.dst.finish();
+ }
+ }
+
+ return dst_curves;
+}
+
+bke::CurvesGeometry fillet_curves_poly(const bke::CurvesGeometry &src_curves,
+ const IndexMask curve_selection,
+ const VArray<float> &radius,
+ const VArray<int> &count,
+ const bool limit_radius)
+{
+ return fillet_curves(src_curves, curve_selection, radius, count, limit_radius, false);
+}
+
+bke::CurvesGeometry fillet_curves_bezier(const bke::CurvesGeometry &src_curves,
+ const IndexMask curve_selection,
+ const VArray<float> &radius,
+ const bool limit_radius)
+{
+ return fillet_curves(src_curves,
+ curve_selection,
+ radius,
+ VArray<int>::ForSingle(1, src_curves.points_num()),
+ limit_radius,
+ true);
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc
index 07ac2419ad9..486d8adbf39 100644
--- a/source/blender/geometry/intern/mesh_primitive_cuboid.cc
+++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc
@@ -7,7 +7,6 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
#include "BKE_mesh.h"
@@ -322,11 +321,10 @@ static void calculate_polys(const CuboidConfig &config,
static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::AttributeIDRef &uv_id)
{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- bke::OutputAttribute_Typed<float2> uv_attribute =
- mesh_component.attribute_try_get_for_output_only<float2>(uv_id, ATTR_DOMAIN_CORNER);
- MutableSpan<float2> uvs = uv_attribute.as_span();
+ bke::MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+ bke::SpanAttributeWriter<float2> uv_attribute =
+ attributes.lookup_or_add_for_write_only_span<float2>(uv_id, ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.span;
int loop_index = 0;
@@ -394,7 +392,7 @@ static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::Att
}
}
- uv_attribute.save();
+ uv_attribute.finish();
}
Mesh *create_cuboid_mesh(const float3 &size,
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 38f9da2a60c..fdacb174462 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -8,7 +8,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "BKE_attribute_access.hh"
+#include "BKE_attribute.hh"
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
@@ -30,13 +30,12 @@ static void copy_with_map(const VArray<T> &src, Span<int> map, MutableSpan<T> ds
});
}
-static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_component,
- const Span<int> vert_indices,
- const Span<int> curve_offsets,
- const IndexRange cyclic_curves)
+static bke::CurvesGeometry create_curve_from_vert_indices(const Mesh &mesh,
+ const Span<int> vert_indices,
+ const Span<int> curve_offsets,
+ const IndexRange cyclic_curves)
{
- Curves *curves_id = bke::curves_new_nomain(vert_indices.size(), curve_offsets.size());
- bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ bke::CurvesGeometry curves(vert_indices.size(), curve_offsets.size());
curves.offsets_for_write().drop_back(1).copy_from(curve_offsets);
curves.offsets_for_write().last() = vert_indices.size();
curves.fill_curve_types(CURVE_TYPE_POLY);
@@ -44,14 +43,13 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
curves.cyclic_for_write().fill(false);
curves.cyclic_for_write().slice(cyclic_curves).fill(true);
- Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
+ const bke::AttributeAccessor mesh_attributes = bke::mesh_attributes(mesh);
+ bke::MutableAttributeAccessor curves_attributes = curves.attributes_for_write();
- CurveComponent curves_component;
- curves_component.replace(curves_id, GeometryOwnershipType::Editable);
+ Set<bke::AttributeIDRef> source_attribute_ids = mesh_attributes.all_ids();
for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) {
- if (mesh_component.attribute_is_builtin(attribute_id) &&
- !curves_component.attribute_is_builtin(attribute_id)) {
+ if (mesh_attributes.is_builtin(attribute_id) && !curves_attributes.is_builtin(attribute_id)) {
/* Don't copy attributes that are built-in on meshes but not on curves. */
continue;
}
@@ -60,8 +58,7 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
continue;
}
- const GVArray mesh_attribute = mesh_component.attribute_try_get_for_read(attribute_id,
- ATTR_DOMAIN_POINT);
+ const GVArray mesh_attribute = mesh_attributes.lookup(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) {
@@ -71,14 +68,14 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
/* Copy attribute based on the map for this curve. */
attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
using T = decltype(dummy);
- bke::OutputAttribute_Typed<T> attribute =
- curves_component.attribute_try_get_for_output_only<T>(attribute_id, ATTR_DOMAIN_POINT);
- copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.as_span());
- attribute.save();
+ bke::SpanAttributeWriter<T> attribute =
+ curves_attributes.lookup_or_add_for_write_only_span<T>(attribute_id, ATTR_DOMAIN_POINT);
+ copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.span);
+ attribute.finish();
});
}
- return curves_id;
+ return curves;
}
struct CurveFromEdgesOutput {
@@ -222,16 +219,14 @@ static Vector<std::pair<int, int>> get_selected_edges(const Mesh &mesh, const In
return selected_edges;
}
-Curves *mesh_to_curve_convert(const MeshComponent &mesh_component, const IndexMask selection)
+bke::CurvesGeometry mesh_to_curve_convert(const Mesh &mesh, const IndexMask selection)
{
- const Mesh &mesh = *mesh_component.get_for_read();
- Vector<std::pair<int, int>> selected_edges = get_selected_edges(*mesh_component.get_for_read(),
- selection);
+ Vector<std::pair<int, int>> selected_edges = get_selected_edges(mesh, 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.curve_offsets, output.cyclic_curves);
+ mesh, output.vert_indices, output.curve_offsets, output.cyclic_curves);
}
} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/mesh_to_volume.cc b/source/blender/geometry/intern/mesh_to_volume.cc
new file mode 100644
index 00000000000..ae98b048a6c
--- /dev/null
+++ b/source/blender/geometry/intern/mesh_to_volume.cc
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_mesh_runtime.h"
+#include "BKE_volume.h"
+
+#include "GEO_mesh_to_volume.hh"
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/GridTransformer.h>
+# include <openvdb/tools/VolumeToMesh.h>
+
+namespace blender::geometry {
+
+/* This class follows the MeshDataAdapter interface from openvdb. */
+class OpenVDBMeshAdapter {
+ private:
+ Span<MVert> vertices_;
+ Span<MLoop> loops_;
+ Span<MLoopTri> looptris_;
+ float4x4 transform_;
+
+ public:
+ OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform);
+ size_t polygonCount() const;
+ size_t pointCount() const;
+ size_t vertexCount(size_t UNUSED(polygon_index)) const;
+ void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const;
+};
+
+OpenVDBMeshAdapter::OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform)
+ : vertices_(mesh.mvert, mesh.totvert), loops_(mesh.mloop, mesh.totloop), transform_(transform)
+{
+ /* This only updates a cache and can be considered to be logically const. */
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(&mesh);
+ const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
+ looptris_ = Span(looptris, looptris_len);
+}
+
+size_t OpenVDBMeshAdapter::polygonCount() const
+{
+ return static_cast<size_t>(looptris_.size());
+}
+
+size_t OpenVDBMeshAdapter::pointCount() const
+{
+ return static_cast<size_t>(vertices_.size());
+}
+
+size_t OpenVDBMeshAdapter::vertexCount(size_t UNUSED(polygon_index)) const
+{
+ /* All polygons are triangles. */
+ return 3;
+}
+
+void OpenVDBMeshAdapter::getIndexSpacePoint(size_t polygon_index,
+ size_t vertex_index,
+ openvdb::Vec3d &pos) const
+{
+ const MLoopTri &looptri = looptris_[polygon_index];
+ const MVert &vertex = vertices_[loops_[looptri.tri[vertex_index]].v];
+ const float3 transformed_co = transform_ * float3(vertex.co);
+ pos = &transformed_co.x;
+}
+
+float volume_compute_voxel_size(const Depsgraph *depsgraph,
+ FunctionRef<void(float3 &r_min, float3 &r_max)> bounds_fn,
+ const MeshToVolumeResolution res,
+ const float exterior_band_width,
+ const float4x4 &transform)
+{
+ const float volume_simplify = BKE_volume_simplify_factor(depsgraph);
+ if (volume_simplify == 0.0f) {
+ return 0.0f;
+ }
+
+ if (res.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
+ return res.settings.voxel_size / volume_simplify;
+ }
+ if (res.settings.voxel_amount <= 0) {
+ return 0;
+ }
+
+ float3 bb_min;
+ float3 bb_max;
+ bounds_fn(bb_min, bb_max);
+
+ /* Compute the voxel size based on the desired number of voxels and the approximated bounding
+ * box of the volume. */
+ const float diagonal = math::distance(transform * bb_max, transform * bb_min);
+ const float approximate_volume_side_length = diagonal + exterior_band_width * 2.0f;
+ const float voxel_size = approximate_volume_side_length / res.settings.voxel_amount /
+ volume_simplify;
+ return voxel_size;
+}
+
+static openvdb::FloatGrid::Ptr mesh_to_volume_grid(const Mesh *mesh,
+ const float4x4 &mesh_to_volume_space_transform,
+ const float voxel_size,
+ const bool fill_volume,
+ const float exterior_band_width,
+ const float interior_band_width,
+ const float density)
+{
+ if (voxel_size == 0.0f) {
+ return nullptr;
+ }
+
+ float4x4 mesh_to_index_space_transform;
+ scale_m4_fl(mesh_to_index_space_transform.values, 1.0f / voxel_size);
+ mul_m4_m4_post(mesh_to_index_space_transform.values, mesh_to_volume_space_transform.values);
+ /* Better align generated grid with the source mesh. */
+ add_v3_fl(mesh_to_index_space_transform.values[3], -0.5f);
+
+ OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform};
+
+ /* Convert the bandwidths from object in index space. */
+ const float exterior = MAX2(0.001f, exterior_band_width / voxel_size);
+ const float interior = MAX2(0.001f, interior_band_width / voxel_size);
+
+ openvdb::FloatGrid::Ptr new_grid;
+ if (fill_volume) {
+ /* Setting the interior bandwidth to FLT_MAX, will make it fill the entire volume. */
+ new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
+ mesh_adapter, {}, exterior, FLT_MAX);
+ }
+ else {
+ new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
+ mesh_adapter, {}, exterior, interior);
+ }
+
+ /* Give each grid cell a fixed density for now. */
+ openvdb::tools::foreach (
+ new_grid->beginValueOn(),
+ [density](const openvdb::FloatGrid::ValueOnIter &iter) { iter.setValue(density); });
+
+ return new_grid;
+}
+
+VolumeGrid *volume_grid_add_from_mesh(Volume *volume,
+ const StringRefNull name,
+ const Mesh *mesh,
+ const float4x4 &mesh_to_volume_space_transform,
+ const float voxel_size,
+ const bool fill_volume,
+ const float exterior_band_width,
+ const float interior_band_width,
+ const float density)
+{
+ VolumeGrid *c_grid = BKE_volume_grid_add(volume, name.c_str(), VOLUME_GRID_FLOAT);
+ openvdb::FloatGrid::Ptr grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
+ BKE_volume_grid_openvdb_for_write(volume, c_grid, false));
+
+ /* Generate grid from mesh */
+ openvdb::FloatGrid::Ptr mesh_grid = mesh_to_volume_grid(mesh,
+ mesh_to_volume_space_transform,
+ voxel_size,
+ fill_volume,
+ exterior_band_width,
+ interior_band_width,
+ density);
+
+ /* Merge the generated grid. Should be cheap because grid has just been created. */
+ grid->merge(*mesh_grid);
+ /* Set class to "Fog Volume". */
+ grid->setGridClass(openvdb::GRID_FOG_VOLUME);
+ /* Change transform so that the index space is correctly transformed to object space. */
+ grid->transform().postScale(voxel_size);
+ return c_grid;
+}
+} // namespace blender::geometry
+#endif
diff --git a/source/blender/geometry/intern/point_merge_by_distance.cc b/source/blender/geometry/intern/point_merge_by_distance.cc
index 6639ff650d3..42fac849667 100644
--- a/source/blender/geometry/intern/point_merge_by_distance.cc
+++ b/source/blender/geometry/intern/point_merge_by_distance.cc
@@ -13,13 +13,14 @@
namespace blender::geometry {
-PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
+PointCloud *point_merge_by_distance(const PointCloud &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};
+ const bke::AttributeAccessor src_attributes = bke::pointcloud_attributes(src_points);
+ VArraySpan<float3> positions = src_attributes.lookup_or_default<float3>(
+ "position", ATTR_DOMAIN_POINT, float3(0));
+ const int src_size = positions.size();
/* Create the KD tree based on only the selected points, to speed up merge detection and
* balancing. */
@@ -40,8 +41,8 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
/* 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);
+ bke::MutableAttributeAccessor dst_attributes = bke::pointcloud_attributes_for_write(
+ *dst_pointcloud);
/* 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
@@ -104,47 +105,44 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
point_merge_counts[dst_index]++;
}
- Set<bke::AttributeIDRef> attributes = src_points.attribute_ids();
+ Set<bke::AttributeIDRef> attribute_ids = src_attributes.all_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>(
+ if (attribute_ids.contains("id")) {
+ VArraySpan<int> src = src_attributes.lookup_or_default<int>("id", ATTR_DOMAIN_POINT, 0);
+ bke::SpanAttributeWriter<int> dst = dst_attributes.lookup_or_add_for_write_only_span<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 points(map_offsets[i_dst], map_offsets[i_dst + 1] - map_offsets[i_dst]);
- dst_ids[i_dst] = src_ids[points.first()];
+ dst.span[i_dst] = src[points.first()];
}
});
- dst.save();
- attributes.remove_contained("id");
+ dst.finish();
+ attribute_ids.remove_contained("id");
}
/* Transfer all other attributes. */
- for (const bke::AttributeIDRef &id : attributes) {
+ for (const bke::AttributeIDRef &id : attribute_ids) {
if (!id.should_be_kept()) {
continue;
}
- bke::ReadAttributeLookup src_attribute = src_points.attribute_try_get_for_read(id);
+ bke::GAttributeReader src_attribute = src_attributes.lookup(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();
+ bke::SpanAttributeWriter<T> dst_attribute =
+ dst_attributes.lookup_or_add_for_write_only_span<T>(id, ATTR_DOMAIN_POINT);
+ VArraySpan<T> src = src_attribute.varray.typed<T>();
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)};
+ attribute_math::DefaultMixer<T> mixer{dst_attribute.span.slice(i_dst, 1)};
const IndexRange points(map_offsets[i_dst],
map_offsets[i_dst + 1] - map_offsets[i_dst]);
@@ -157,7 +155,7 @@ PointCloud *point_merge_by_distance(const PointCloudComponent &src_points,
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
});
}
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index ae07e817c67..0544f304283 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -23,12 +23,13 @@
namespace blender::geometry {
using blender::bke::AttributeIDRef;
+using blender::bke::AttributeKind;
+using blender::bke::AttributeMetaData;
using blender::bke::custom_data_type_to_cpp_type;
using blender::bke::CustomDataAttributes;
+using blender::bke::GSpanAttributeWriter;
using blender::bke::object_get_evaluated_geometry_set;
-using blender::bke::OutputAttribute;
-using blender::bke::OutputAttribute_Typed;
-using blender::bke::ReadAttributeLookup;
+using blender::bke::SpanAttributeWriter;
/**
* An ordered set of attribute ids. Attributes are ordered to avoid name lookups in many places.
@@ -66,8 +67,9 @@ struct AttributeFallbacksArray {
struct PointCloudRealizeInfo {
const PointCloud *pointcloud = nullptr;
/** Matches the order stored in #AllPointCloudsInfo.attributes. */
- Array<std::optional<GVArray_GSpan>> attributes;
+ Array<std::optional<GVArraySpan>> attributes;
/** Id attribute on the point cloud. If there are no ids, this #Span is empty. */
+ Span<float3> positions;
Span<int> stored_ids;
};
@@ -96,7 +98,7 @@ struct MeshRealizeInfo {
/** 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;
+ Array<std::optional<GVArraySpan>> attributes;
/** Vertex ids stored on the mesh. If there are no ids, this #Span is empty. */
Span<int> stored_vertex_ids;
};
@@ -116,7 +118,7 @@ struct RealizeCurveInfo {
/**
* Matches the order in #AllCurvesInfo.attributes.
*/
- Array<std::optional<GVArray_GSpan>> attributes;
+ Array<std::optional<GVArraySpan>> attributes;
/** ID attribute on the curves. If there are no ids, this #Span is empty. */
Span<int> stored_ids;
@@ -134,6 +136,12 @@ struct RealizeCurveInfo {
* doesn't exist on some (but not all) of the input curves data-blocks.
*/
Span<float> radius;
+
+ /**
+ * The resolution attribute must be filled with the default value if it does not exist on some
+ * curves.
+ */
+ VArray<int> resolution;
};
/** Start indices in the final output curves data-block. */
@@ -185,6 +193,7 @@ struct AllCurvesInfo {
bool create_id_attribute = false;
bool create_handle_postion_attributes = false;
bool create_radius_attribute = false;
+ bool create_resolution_attribute = false;
};
/** Collects all tasks that need to be executed to realize all instances. */
@@ -276,30 +285,31 @@ static void threaded_fill(const GPointer value, GMutableSpan dst)
}
static void copy_generic_attributes_to_result(
- const Span<std::optional<GVArray_GSpan>> src_attributes,
+ const Span<std::optional<GVArraySpan>> src_attributes,
const AttributeFallbacksArray &attribute_fallbacks,
const OrderedAttributes &ordered_attributes,
- const FunctionRef<IndexRange(AttributeDomain)> &range_fn,
- MutableSpan<GMutableSpan> dst_attributes)
+ const FunctionRef<IndexRange(eAttrDomain)> &range_fn,
+ MutableSpan<GSpanAttributeWriter> dst_attribute_writers)
{
- threading::parallel_for(dst_attributes.index_range(), 10, [&](const IndexRange attribute_range) {
- for (const int attribute_index : attribute_range) {
- const AttributeDomain domain = ordered_attributes.kinds[attribute_index].domain;
- const IndexRange element_slice = range_fn(domain);
-
- GMutableSpan dst_span = dst_attributes[attribute_index].slice(element_slice);
- if (src_attributes[attribute_index].has_value()) {
- threaded_copy(*src_attributes[attribute_index], dst_span);
- }
- else {
- const CPPType &cpp_type = dst_span.type();
- const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ?
- cpp_type.default_value() :
- attribute_fallbacks.array[attribute_index];
- threaded_fill({cpp_type, fallback}, dst_span);
- }
- }
- });
+ threading::parallel_for(
+ dst_attribute_writers.index_range(), 10, [&](const IndexRange attribute_range) {
+ for (const int attribute_index : attribute_range) {
+ const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const IndexRange element_slice = range_fn(domain);
+
+ GMutableSpan dst_span = dst_attribute_writers[attribute_index].span.slice(element_slice);
+ if (src_attributes[attribute_index].has_value()) {
+ threaded_copy(*src_attributes[attribute_index], dst_span);
+ }
+ else {
+ const CPPType &cpp_type = dst_span.type();
+ const void *fallback = attribute_fallbacks.array[attribute_index] == nullptr ?
+ cpp_type.default_value() :
+ attribute_fallbacks.array[attribute_index];
+ threaded_fill({cpp_type, fallback}, dst_span);
+ }
+ }
+ });
}
static void create_result_ids(const RealizeInstancesOptions &options,
@@ -354,7 +364,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
const OrderedAttributes &ordered_attributes)
{
Vector<std::pair<int, GSpan>> attributes_to_override;
- const CustomDataAttributes &attributes = instances_component.attributes();
+ const CustomDataAttributes &attributes = instances_component.instance_attributes();
attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id);
@@ -363,7 +373,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
return true;
}
GSpan span = *attributes.get_for_read(attribute_id);
- const CustomDataType expected_type = ordered_attributes.kinds[attribute_index].data_type;
+ const eCustomDataType 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);
@@ -440,7 +450,7 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
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");
+ std::optional<GSpan> ids = instances_component.instance_attributes().get_for_read("id");
if (ids.has_value()) {
stored_instance_ids = ids->typed<int>();
}
@@ -639,43 +649,44 @@ static AllPointCloudsInfo preprocess_pointclouds(const GeometrySet &geometry_set
pointcloud_info.pointcloud = pointcloud;
/* Access attributes. */
- PointCloudComponent component;
- component.replace(const_cast<PointCloud *>(pointcloud), GeometryOwnershipType::ReadOnly);
+ bke::AttributeAccessor attributes = bke::pointcloud_attributes(*pointcloud);
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);
+ const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (attributes.contains(attribute_id)) {
+ GVArray attribute = attributes.lookup_or_default(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>();
+ bke::GAttributeReader ids_attribute = attributes.lookup("id");
+ if (ids_attribute) {
+ pointcloud_info.stored_ids = ids_attribute.varray.get_internal_span().typed<int>();
}
}
+ const VArray<float3> position_attribute = attributes.lookup_or_default<float3>(
+ "position", ATTR_DOMAIN_POINT, float3(0));
+ pointcloud_info.positions = position_attribute.get_internal_span();
}
return info;
}
-static void execute_realize_pointcloud_task(const RealizeInstancesOptions &options,
- const RealizePointCloudTask &task,
- const OrderedAttributes &ordered_attributes,
- PointCloud &dst_pointcloud,
- MutableSpan<GMutableSpan> dst_attribute_spans,
- MutableSpan<int> all_dst_ids)
+static void execute_realize_pointcloud_task(
+ const RealizeInstancesOptions &options,
+ const RealizePointCloudTask &task,
+ const OrderedAttributes &ordered_attributes,
+ MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
+ MutableSpan<int> all_dst_ids,
+ MutableSpan<float3> all_dst_positions)
{
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};
- copy_transformed_positions(src_positions, task.transform, dst_positions);
+ copy_transformed_positions(
+ pointcloud_info.positions, task.transform, all_dst_positions.slice(point_slice));
/* Create point ids. */
if (!all_dst_ids.is_empty()) {
@@ -687,12 +698,12 @@ static void execute_realize_pointcloud_task(const RealizeInstancesOptions &optio
pointcloud_info.attributes,
task.attribute_fallbacks,
ordered_attributes,
- [&](const AttributeDomain domain) {
+ [&](const eAttrDomain domain) {
BLI_assert(domain == ATTR_DOMAIN_POINT);
UNUSED_VARS_NDEBUG(domain);
return point_slice;
},
- dst_attribute_spans);
+ dst_attribute_writers);
}
static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &options,
@@ -714,42 +725,47 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
PointCloudComponent &dst_component =
r_realized_geometry.get_component_for_write<PointCloudComponent>();
dst_component.replace(dst_pointcloud);
+ bke::MutableAttributeAccessor dst_attributes = bke::pointcloud_attributes_for_write(
+ *dst_pointcloud);
+
+ SpanAttributeWriter<float3> positions = dst_attributes.lookup_or_add_for_write_only_span<float3>(
+ "position", ATTR_DOMAIN_POINT);
/* Prepare id attribute. */
- OutputAttribute_Typed<int> point_ids;
- MutableSpan<int> point_ids_span;
+ SpanAttributeWriter<int> point_ids;
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();
+ point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
}
/* Prepare generic output attributes. */
- Vector<OutputAttribute> dst_attributes;
- Vector<GMutableSpan> dst_attribute_spans;
+ Vector<GSpanAttributeWriter> dst_attribute_writers;
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));
+ const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ dst_attribute_writers.append(dst_attributes.lookup_or_add_for_write_only_span(
+ attribute_id, ATTR_DOMAIN_POINT, data_type));
}
/* 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, ordered_attributes, *dst_pointcloud, dst_attribute_spans, point_ids_span);
+ execute_realize_pointcloud_task(options,
+ task,
+ ordered_attributes,
+ dst_attribute_writers,
+ point_ids.span,
+ positions.span);
}
});
- /* Save modified attributes. */
- for (OutputAttribute &dst_attribute : dst_attributes) {
- dst_attribute.save();
+ /* Tag modified attributes. */
+ for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
+ dst_attribute.finish();
}
+ positions.finish();
if (point_ids) {
- point_ids.save();
+ point_ids.finish();
}
}
@@ -830,22 +846,21 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
}
/* Access attributes. */
- MeshComponent component;
- component.replace(const_cast<Mesh *>(mesh), GeometryOwnershipType::ReadOnly);
+ bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh);
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);
+ const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
+ if (attributes.contains(attribute_id)) {
+ GVArray attribute = attributes.lookup_or_default(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>();
+ bke::GAttributeReader ids_attribute = attributes.lookup("id");
+ if (ids_attribute) {
+ mesh_info.stored_vertex_ids = ids_attribute.varray.get_internal_span().typed<int>();
}
}
}
@@ -856,7 +871,7 @@ 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<GSpanAttributeWriter> dst_attribute_writers,
MutableSpan<int> all_dst_vertex_ids)
{
const MeshRealizeInfo &mesh_info = *task.mesh_info;
@@ -927,7 +942,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
mesh_info.attributes,
task.attribute_fallbacks,
ordered_attributes,
- [&](const AttributeDomain domain) {
+ [&](const eAttrDomain domain) {
switch (domain) {
case ATTR_DOMAIN_POINT:
return IndexRange(task.start_indices.vertex, mesh.totvert);
@@ -942,7 +957,7 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
return IndexRange();
}
},
- dst_attribute_spans);
+ dst_attribute_writers);
}
static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
@@ -966,6 +981,7 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
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);
+ bke::MutableAttributeAccessor dst_attributes = bke::mesh_attributes_for_write(*dst_mesh);
/* Copy settings from the first input geometry set with a mesh. */
const RealizeMeshTask &first_task = tasks.first();
@@ -979,24 +995,19 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
}
/* Prepare id attribute. */
- OutputAttribute_Typed<int> vertex_ids;
- MutableSpan<int> vertex_ids_span;
+ SpanAttributeWriter<int> vertex_ids;
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();
+ vertex_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
}
/* Prepare generic output attributes. */
- Vector<OutputAttribute> dst_attributes;
- Vector<GMutableSpan> dst_attribute_spans;
+ Vector<GSpanAttributeWriter> dst_attribute_writers;
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));
+ const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ dst_attribute_writers.append(
+ dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
}
/* Actually execute all tasks. */
@@ -1004,16 +1015,16 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
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);
+ options, task, ordered_attributes, *dst_mesh, dst_attribute_writers, vertex_ids.span);
}
});
- /* Save modified attributes. */
- for (OutputAttribute &dst_attribute : dst_attributes) {
- dst_attribute.save();
+ /* Tag modified attributes. */
+ for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
+ dst_attribute.finish();
}
if (vertex_ids) {
- vertex_ids.save();
+ vertex_ids.finish();
}
}
@@ -1037,6 +1048,7 @@ static OrderedAttributes gather_generic_curve_attributes_to_propagate(
src_component_types, GEO_COMPONENT_TYPE_CURVE, true, attributes_to_propagate);
attributes_to_propagate.remove("position");
attributes_to_propagate.remove("radius");
+ attributes_to_propagate.remove("resolution");
attributes_to_propagate.remove("handle_right");
attributes_to_propagate.remove("handle_left");
r_create_id = attributes_to_propagate.pop_try("id").has_value();
@@ -1075,47 +1087,48 @@ static AllCurvesInfo preprocess_curves(const GeometrySet &geometry_set,
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 Curves *curves = info.order[curve_index];
- curve_info.curves = curves;
+ const Curves *curves_id = info.order[curve_index];
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ curve_info.curves = curves_id;
/* Access attributes. */
- CurveComponent component;
- component.replace(const_cast<Curves *>(curves), GeometryOwnershipType::ReadOnly);
+ bke::AttributeAccessor attributes = curves.attributes();
curve_info.attributes.reinitialize(info.attributes.size());
for (const int attribute_index : info.attributes.index_range()) {
- const AttributeDomain domain = info.attributes.kinds[attribute_index].domain;
+ const eAttrDomain domain = info.attributes.kinds[attribute_index].domain;
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);
+ const eCustomDataType data_type = info.attributes.kinds[attribute_index].data_type;
+ if (attributes.contains(attribute_id)) {
+ GVArray attribute = attributes.lookup_or_default(attribute_id, domain, data_type);
curve_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) {
- curve_info.stored_ids = ids_lookup.varray.get_internal_span().typed<int>();
+ bke::GAttributeReader id_attribute = attributes.lookup("id");
+ if (id_attribute) {
+ curve_info.stored_ids = id_attribute.varray.get_internal_span().typed<int>();
}
}
/* Retrieve the radius attribute, if it exists. */
- if (component.attribute_exists("radius")) {
- curve_info.radius = component
- .attribute_get_for_read<float>("radius", ATTR_DOMAIN_POINT, 0.0f)
- .get_internal_span();
+ if (attributes.contains("radius")) {
+ curve_info.radius =
+ attributes.lookup<float>("radius", ATTR_DOMAIN_POINT).get_internal_span();
info.create_radius_attribute = true;
}
+ /* Retrieve the resolution attribute, if it exists. */
+ curve_info.resolution = curves.resolution();
+ if (attributes.contains("resolution")) {
+ info.create_resolution_attribute = true;
+ }
+
/* Retrieve handle position attributes, if they exist. */
- if (component.attribute_exists("handle_right")) {
- curve_info.handle_left = component
- .attribute_get_for_read<float3>(
- "handle_left", ATTR_DOMAIN_POINT, float3(0))
- .get_internal_span();
- curve_info.handle_right = component
- .attribute_get_for_read<float3>(
- "handle_right", ATTR_DOMAIN_POINT, float3(0))
- .get_internal_span();
+ if (attributes.contains("handle_right")) {
+ curve_info.handle_left =
+ attributes.lookup<float3>("handle_left", ATTR_DOMAIN_POINT).get_internal_span();
+ curve_info.handle_right =
+ attributes.lookup<float3>("handle_right", ATTR_DOMAIN_POINT).get_internal_span();
info.create_handle_postion_attributes = true;
}
}
@@ -1127,11 +1140,12 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
const RealizeCurveTask &task,
const OrderedAttributes &ordered_attributes,
bke::CurvesGeometry &dst_curves,
- MutableSpan<GMutableSpan> dst_attribute_spans,
+ MutableSpan<GSpanAttributeWriter> dst_attribute_writers,
MutableSpan<int> all_dst_ids,
MutableSpan<float3> all_handle_left,
MutableSpan<float3> all_handle_right,
- MutableSpan<float> all_radii)
+ MutableSpan<float> all_radii,
+ MutableSpan<int> all_resolutions)
{
const RealizeCurveInfo &curves_info = *task.curve_info;
const Curves &curves_id = *curves_info.curves;
@@ -1171,6 +1185,10 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
}
}
+ if (all_curves_info.create_resolution_attribute) {
+ curves_info.resolution.materialize(all_resolutions.slice(dst_curve_range));
+ }
+
/* Copy curve offsets. */
const Span<int> src_offsets = curves.offsets();
const MutableSpan<int> dst_offsets = dst_curves.offsets_for_write().slice(dst_curve_range);
@@ -1189,7 +1207,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
curves_info.attributes,
task.attribute_fallbacks,
ordered_attributes,
- [&](const AttributeDomain domain) {
+ [&](const eAttrDomain domain) {
switch (domain) {
case ATTR_DOMAIN_POINT:
return IndexRange(task.start_indices.point, curves.points_num());
@@ -1200,7 +1218,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
return IndexRange();
}
},
- dst_attribute_spans);
+ dst_attribute_writers);
}
static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
@@ -1224,48 +1242,50 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
dst_curves.offsets_for_write().last() = points_num;
CurveComponent &dst_component = r_realized_geometry.get_component_for_write<CurveComponent>();
dst_component.replace(dst_curves_id);
+ bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
+
+ /* Copy settings from the first input geometry set with curves. */
+ const RealizeCurveTask &first_task = tasks.first();
+ const Curves &first_curves_id = *first_task.curve_info->curves;
+ bke::curves_copy_parameters(first_curves_id, *dst_curves_id);
/* Prepare id attribute. */
- OutputAttribute_Typed<int> point_ids;
- MutableSpan<int> point_ids_span;
+ SpanAttributeWriter<int> point_ids;
if (all_curves_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();
+ point_ids = dst_attributes.lookup_or_add_for_write_only_span<int>("id", ATTR_DOMAIN_POINT);
}
/* Prepare generic output attributes. */
- Vector<OutputAttribute> dst_attributes;
- Vector<GMutableSpan> dst_attribute_spans;
+ Vector<GSpanAttributeWriter> dst_attribute_writers;
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));
+ const eAttrDomain domain = ordered_attributes.kinds[attribute_index].domain;
+ const eCustomDataType data_type = ordered_attributes.kinds[attribute_index].data_type;
+ dst_attribute_writers.append(
+ dst_attributes.lookup_or_add_for_write_only_span(attribute_id, domain, data_type));
}
/* Prepare handle position attributes if necessary. */
- OutputAttribute_Typed<float3> handle_left;
- OutputAttribute_Typed<float3> handle_right;
- MutableSpan<float3> handle_left_span;
- MutableSpan<float3> handle_right_span;
+ SpanAttributeWriter<float3> handle_left;
+ SpanAttributeWriter<float3> handle_right;
if (all_curves_info.create_handle_postion_attributes) {
- handle_left = dst_component.attribute_try_get_for_output_only<float3>("handle_left",
- ATTR_DOMAIN_POINT);
- handle_right = dst_component.attribute_try_get_for_output_only<float3>("handle_right",
+ handle_left = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_left",
ATTR_DOMAIN_POINT);
- handle_left_span = handle_left.as_span();
- handle_right_span = handle_right.as_span();
+ handle_right = dst_attributes.lookup_or_add_for_write_only_span<float3>("handle_right",
+ ATTR_DOMAIN_POINT);
}
/* Prepare radius attribute if necessary. */
- OutputAttribute_Typed<float> radius;
- MutableSpan<float> radius_span;
+ SpanAttributeWriter<float> radius;
if (all_curves_info.create_radius_attribute) {
- radius = dst_component.attribute_try_get_for_output_only<float>("radius", ATTR_DOMAIN_POINT);
- radius_span = radius.as_span();
+ radius = dst_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
+ }
+
+ /* Prepare resolution attribute if necessary. */
+ SpanAttributeWriter<int> resolution;
+ if (all_curves_info.create_resolution_attribute) {
+ resolution = dst_attributes.lookup_or_add_for_write_only_span<int>("resolution",
+ ATTR_DOMAIN_CURVE);
}
/* Actually execute all tasks. */
@@ -1277,27 +1297,40 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
task,
ordered_attributes,
dst_curves,
- dst_attribute_spans,
- point_ids_span,
- handle_left_span,
- handle_right_span,
- radius_span);
+ dst_attribute_writers,
+ point_ids.span,
+ handle_left.span,
+ handle_right.span,
+ radius.span,
+ resolution.span);
}
});
- /* Save modified attributes. */
- for (OutputAttribute &dst_attribute : dst_attributes) {
- dst_attribute.save();
+ /* Type counts have to be updated eagerly. */
+ dst_curves.runtime->type_counts.fill(0);
+ for (const RealizeCurveTask &task : tasks) {
+ for (const int i : IndexRange(CURVE_TYPES_NUM)) {
+ dst_curves.runtime->type_counts[i] +=
+ task.curve_info->curves->geometry.runtime->type_counts[i];
+ }
+ }
+
+ /* Tag modified attributes. */
+ for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
+ dst_attribute.finish();
}
if (point_ids) {
- point_ids.save();
+ point_ids.finish();
}
if (radius) {
- radius.save();
+ radius.finish();
+ }
+ if (resolution) {
+ resolution.finish();
}
if (all_curves_info.create_handle_postion_attributes) {
- handle_left.save();
- handle_right.save();
+ handle_left.finish();
+ handle_right.finish();
}
}
@@ -1312,7 +1345,7 @@ 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 = sub_geometry.get_component_for_write<InstancesComponent>();
- component.attributes().remove("id");
+ component.instance_attributes().remove("id");
}
});
}
diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc
index 7895225a189..2c3a6c6e0cf 100644
--- a/source/blender/geometry/intern/resample_curves.cc
+++ b/source/blender/geometry/intern/resample_curves.cc
@@ -77,8 +77,8 @@ static bool interpolate_attribute_to_poly_curve(const bke::AttributeIDRef &attri
static const Set<StringRef> no_interpolation{{
"handle_type_left",
"handle_type_right",
- "handle_position_right",
- "handle_position_left",
+ "handle_right",
+ "handle_left",
"nurbs_weight",
}};
return !(attribute_id.is_named() && no_interpolation.contains(attribute_id.name()));
@@ -92,17 +92,18 @@ static void retrieve_attribute_spans(const Span<bke::AttributeIDRef> ids,
CurveComponent &dst_component,
Vector<GSpan> &src,
Vector<GMutableSpan> &dst,
- Vector<bke::OutputAttribute> &dst_attributes)
+ Vector<bke::GSpanAttributeWriter> &dst_attributes)
{
for (const int i : ids.index_range()) {
- GVArray src_attribute = src_component.attribute_try_get_for_read(ids[i], ATTR_DOMAIN_POINT);
+ GVArray src_attribute = src_component.attributes()->lookup(ids[i], ATTR_DOMAIN_POINT);
BLI_assert(src_attribute);
src.append(src_attribute.get_internal_span());
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type());
- bke::OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- ids[i], ATTR_DOMAIN_POINT, data_type);
- dst.append(dst_attribute.as_span());
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(src_attribute.type());
+ bke::GSpanAttributeWriter dst_attribute =
+ dst_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ ids[i], ATTR_DOMAIN_POINT, data_type);
+ dst.append(dst_attribute.span);
dst_attributes.append(std::move(dst_attribute));
}
}
@@ -111,7 +112,7 @@ struct AttributesForInterpolation : NonCopyable, NonMovable {
Vector<GSpan> src;
Vector<GMutableSpan> dst;
- Vector<bke::OutputAttribute> dst_attributes;
+ Vector<bke::GSpanAttributeWriter> dst_attributes;
Vector<GSpan> src_no_interpolation;
Vector<GMutableSpan> dst_no_interpolation;
@@ -129,8 +130,8 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com
VectorSet<bke::AttributeIDRef> ids;
VectorSet<bke::AttributeIDRef> ids_no_interpolation;
- src_component.attribute_foreach(
- [&](const bke::AttributeIDRef &id, const AttributeMetaData meta_data) {
+ src_component.attributes()->for_all(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
if (meta_data.domain != ATTR_DOMAIN_POINT) {
return true;
}
@@ -161,40 +162,6 @@ static void gather_point_attributes_to_interpolate(const CurveComponent &src_com
result.src_no_interpolation,
result.dst_no_interpolation,
result.dst_attributes);
-
- dst_curves.update_customdata_pointers();
-}
-
-/**
- * Copy the provided point attribute values between all curves in the #curve_ranges index
- * ranges, assuming that all curves are the same size in #src_curves and #dst_curves.
- */
-template<typename T>
-static void copy_between_curves(const bke::CurvesGeometry &src_curves,
- const bke::CurvesGeometry &dst_curves,
- const Span<IndexRange> curve_ranges,
- const Span<T> src,
- const MutableSpan<T> dst)
-{
- threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
- for (const IndexRange range : curve_ranges.slice(range)) {
- const IndexRange src_points = src_curves.points_for_curves(range);
- const IndexRange dst_points = dst_curves.points_for_curves(range);
- /* The arrays might be large, so a threaded copy might make sense here too. */
- dst.slice(dst_points).copy_from(src.slice(src_points));
- }
- });
-}
-static void copy_between_curves(const bke::CurvesGeometry &src_curves,
- const bke::CurvesGeometry &dst_curves,
- const Span<IndexRange> unselected_ranges,
- const GSpan src,
- const GMutableSpan dst)
-{
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src.typed<T>(), dst.typed<T>());
- });
}
static Curves *resample_to_uniform(const CurveComponent &src_component,
@@ -266,11 +233,10 @@ static Curves *resample_to_uniform(const CurveComponent &src_component,
for (const int i_curve : sliced_selection) {
const bool cyclic = curves_cyclic[i_curve];
const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- length_parameterize::create_uniform_samples(
- src_curves.evaluated_lengths_for_curve(i_curve, cyclic),
- curves_cyclic[i_curve],
- sample_indices.as_mutable_span().slice(dst_points),
- sample_factors.as_mutable_span().slice(dst_points));
+ length_parameterize::sample_uniform(src_curves.evaluated_lengths_for_curve(i_curve, cyclic),
+ !curves_cyclic[i_curve],
+ sample_indices.as_mutable_span().slice(dst_points),
+ sample_factors.as_mutable_span().slice(dst_points));
}
/* For every attribute, evaluate attributes from every curve in the range in the original
@@ -328,23 +294,24 @@ static Curves *resample_to_uniform(const CurveComponent &src_component,
/* Any attribute data from unselected curve points can be directly copied. */
for (const int i : attributes.src.index_range()) {
- copy_between_curves(
+ bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
}
for (const int i : attributes.src_no_interpolation.index_range()) {
- copy_between_curves(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ unselected_ranges,
+ attributes.src_no_interpolation[i],
+ attributes.dst_no_interpolation[i]);
}
/* Copy positions for unselected curves. */
Span<float3> src_positions = src_curves.positions();
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
- for (bke::OutputAttribute &attribute : attributes.dst_attributes) {
- attribute.save();
+ for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
+ attribute.finish();
}
return dst_curves_id;
@@ -449,23 +416,24 @@ Curves *resample_to_evaluated(const CurveComponent &src_component,
/* Any attribute data from unselected curve points can be directly copied. */
for (const int i : attributes.src.index_range()) {
- copy_between_curves(
+ bke::curves::copy_point_data(
src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
}
for (const int i : attributes.src_no_interpolation.index_range()) {
- copy_between_curves(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ unselected_ranges,
+ attributes.src_no_interpolation[i],
+ attributes.dst_no_interpolation[i]);
}
/* Copy positions for unselected curves. */
Span<float3> src_positions = src_curves.positions();
- copy_between_curves(src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
- for (bke::OutputAttribute &attribute : attributes.dst_attributes) {
- attribute.save();
+ for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
+ attribute.finish();
}
return dst_curves_id;
diff --git a/source/blender/geometry/intern/reverse_uv_sampler.cc b/source/blender/geometry/intern/reverse_uv_sampler.cc
new file mode 100644
index 00000000000..54df43db4ea
--- /dev/null
+++ b/source/blender/geometry/intern/reverse_uv_sampler.cc
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "GEO_reverse_uv_sampler.hh"
+
+#include "BLI_math_geom.h"
+#include "BLI_math_vector.hh"
+#include "BLI_task.hh"
+#include "BLI_timeit.hh"
+
+namespace blender::geometry {
+
+static int2 uv_to_cell_key(const float2 &uv, const int resolution)
+{
+ return int2{uv * resolution};
+}
+
+ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris)
+ : uv_map_(uv_map), looptris_(looptris)
+{
+ resolution_ = std::max<int>(3, std::sqrt(looptris.size()) * 2);
+
+ for (const int looptri_index : looptris.index_range()) {
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float2 &uv_0 = uv_map_[looptri.tri[0]];
+ const float2 &uv_1 = uv_map_[looptri.tri[1]];
+ const float2 &uv_2 = uv_map_[looptri.tri[2]];
+
+ const int2 key_0 = uv_to_cell_key(uv_0, resolution_);
+ const int2 key_1 = uv_to_cell_key(uv_1, resolution_);
+ const int2 key_2 = uv_to_cell_key(uv_2, resolution_);
+
+ const int2 min_key = math::min(math::min(key_0, key_1), key_2);
+ const int2 max_key = math::max(math::max(key_0, key_1), key_2);
+
+ for (int key_x = min_key.x; key_x <= max_key.x; key_x++) {
+ for (int key_y = min_key.y; key_y <= max_key.y; key_y++) {
+ const int2 key{key_x, key_y};
+ looptris_by_cell_.add(key, looptri_index);
+ }
+ }
+ }
+}
+
+ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const
+{
+ const int2 cell_key = uv_to_cell_key(query_uv, resolution_);
+ const Span<int> looptri_indices = looptris_by_cell_.lookup(cell_key);
+
+ float best_dist = FLT_MAX;
+ float3 best_bary_weights;
+ const MLoopTri *best_looptri;
+
+ for (const int looptri_index : looptri_indices) {
+ const MLoopTri &looptri = looptris_[looptri_index];
+ const float2 &uv_0 = uv_map_[looptri.tri[0]];
+ const float2 &uv_1 = uv_map_[looptri.tri[1]];
+ const float2 &uv_2 = uv_map_[looptri.tri[2]];
+ float3 bary_weights;
+ if (!barycentric_coords_v2(uv_0, uv_1, uv_2, query_uv, bary_weights)) {
+ continue;
+ }
+
+ /* If #query_uv is in the triangle, the distance is <= 0. Otherwise, the larger the distance,
+ * the further away the uv is from the triangle. */
+ const float x_dist = std::max(-bary_weights.x, bary_weights.x - 1.0f);
+ const float y_dist = std::max(-bary_weights.y, bary_weights.y - 1.0f);
+ const float z_dist = std::max(-bary_weights.z, bary_weights.z - 1.0f);
+ const float dist = MAX3(x_dist, y_dist, z_dist);
+
+ if (dist <= 0.0f) {
+ /* Return early if the uv coordinate is in the triangle. */
+ return Result{ResultType::Ok, &looptri, bary_weights};
+ }
+
+ if (dist < best_dist) {
+ best_dist = dist;
+ best_bary_weights = bary_weights;
+ best_looptri = &looptri;
+ }
+ }
+
+ /* Allow for a small epsilon in case the uv is on th edge. */
+ if (best_dist < 0.00001f) {
+ return Result{ResultType::Ok, best_looptri, math::clamp(best_bary_weights, 0.0f, 1.0f)};
+ }
+
+ return Result{};
+}
+
+void ReverseUVSampler::sample_many(const Span<float2> query_uvs,
+ MutableSpan<Result> r_results) const
+{
+ BLI_assert(query_uvs.size() == r_results.size());
+ threading::parallel_for(query_uvs.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ r_results[i] = this->sample(query_uvs[i]);
+ }
+ });
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/set_curve_type.cc b/source/blender/geometry/intern/set_curve_type.cc
new file mode 100644
index 00000000000..40ee2488a4b
--- /dev/null
+++ b/source/blender/geometry/intern/set_curve_type.cc
@@ -0,0 +1,689 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_attribute.hh"
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+
+#include "BLI_task.hh"
+
+#include "GEO_set_curve_type.hh"
+
+namespace blender::geometry {
+
+/**
+ * This function answers the question about possible conversion method for NURBS-to-Bezier. In
+ * general for 3rd degree NURBS curves there is one-to-one relation with 3rd degree Bezier curves
+ * that can be exploit for conversion - Bezier handles sit on NURBS hull segments and in the middle
+ * between those handles are Bezier anchor points.
+ */
+static bool is_nurbs_to_bezier_one_to_one(const KnotsMode knots_mode)
+{
+ if (ELEM(knots_mode, NURBS_KNOT_MODE_NORMAL, NURBS_KNOT_MODE_ENDPOINT)) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * As an optimization, just change the types on a mutable curves data-block when the conversion is
+ * simple. This could be expanded to more cases where the number of points doesn't change in the
+ * future, though that might require properly initializing some attributes, or removing others.
+ */
+static bool conversion_can_change_point_num(const CurveType dst_type)
+{
+ if (ELEM(dst_type, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_POLY)) {
+ /* The conversion to Catmull Rom or Poly should never change the number of points, no matter
+ * the source type (Bezier to Catmull Rom conversion cannot maintain the same shape anyway). */
+ return false;
+ }
+ return true;
+}
+
+template<typename T>
+static void scale_input_assign(const Span<T> src,
+ const int scale,
+ const int offset,
+ MutableSpan<T> dst)
+{
+ for (const int i : dst.index_range()) {
+ dst[i] = src[i * scale + offset];
+ }
+}
+
+/**
+ * The Bezier control point and its handles become three control points on the NURBS curve,
+ * so each attribute value is duplicated three times.
+ */
+template<typename T> static void bezier_generic_to_nurbs(const Span<T> src, MutableSpan<T> dst)
+{
+ for (const int i : src.index_range()) {
+ dst[i * 3] = src[i];
+ dst[i * 3 + 1] = src[i];
+ dst[i * 3 + 2] = src[i];
+ }
+}
+
+static void bezier_generic_to_nurbs(const GSpan src, GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ bezier_generic_to_nurbs(src.typed<T>(), dst.typed<T>());
+ });
+}
+
+static void bezier_positions_to_nurbs(const Span<float3> src_positions,
+ const Span<float3> src_handles_l,
+ const Span<float3> src_handles_r,
+ MutableSpan<float3> dst_positions)
+{
+ for (const int i : src_positions.index_range()) {
+ dst_positions[i * 3] = src_handles_l[i];
+ dst_positions[i * 3 + 1] = src_positions[i];
+ dst_positions[i * 3 + 2] = src_handles_r[i];
+ }
+}
+
+static void catmull_rom_to_bezier_handles(const Span<float3> src_positions,
+ const bool cyclic,
+ MutableSpan<float3> dst_handles_l,
+ MutableSpan<float3> dst_handles_r)
+{
+ /* Catmull Rom curves are the same as Bezier curves with automatically defined handle positions.
+ * This constant defines the portion of the distance between the next/previous points to use for
+ * the length of the handles. */
+ constexpr float handle_scale = 1.0f / 6.0f;
+
+ if (src_positions.size() == 1) {
+ dst_handles_l.first() = src_positions.first();
+ dst_handles_r.first() = src_positions.first();
+ return;
+ }
+
+ const float3 first_offset = cyclic ? src_positions[1] - src_positions.last() :
+ src_positions[1] - src_positions[0];
+ dst_handles_r.first() = src_positions.first() + first_offset * handle_scale;
+ dst_handles_l.first() = src_positions.first() - first_offset * handle_scale;
+
+ const float3 last_offset = cyclic ? src_positions.first() - src_positions.last(1) :
+ src_positions.last() - src_positions.last(1);
+ dst_handles_l.last() = src_positions.last() - last_offset * handle_scale;
+ dst_handles_r.last() = src_positions.last() + last_offset * handle_scale;
+
+ for (const int i : src_positions.index_range().drop_front(1).drop_back(1)) {
+ const float3 left_offset = src_positions[i - 1] - src_positions[i + 1];
+ dst_handles_l[i] = src_positions[i] + left_offset * handle_scale;
+
+ const float3 right_offset = src_positions[i + 1] - src_positions[i - 1];
+ dst_handles_r[i] = src_positions[i] + right_offset * handle_scale;
+ }
+}
+
+static void catmull_rom_to_nurbs_positions(const Span<float3> src_positions,
+ const bool cyclic,
+ MutableSpan<float3> dst_positions)
+{
+ /* Convert the Catmull Rom position data to Bezier handles in order to reuse the Bezier to
+ * NURBS positions assignment. If this becomes a bottleneck, this step could be avoided. */
+ Array<float3, 32> bezier_handles_l(src_positions.size());
+ Array<float3, 32> bezier_handles_r(src_positions.size());
+ catmull_rom_to_bezier_handles(src_positions, cyclic, bezier_handles_l, bezier_handles_r);
+ bezier_positions_to_nurbs(src_positions, bezier_handles_l, bezier_handles_r, dst_positions);
+}
+
+template<typename T>
+static void nurbs_to_bezier_assign(const Span<T> src,
+ const MutableSpan<T> dst,
+ const KnotsMode knots_mode)
+{
+ switch (knots_mode) {
+ case NURBS_KNOT_MODE_NORMAL:
+ for (const int i : dst.index_range()) {
+ dst[i] = src[(i + 1) % src.size()];
+ }
+ break;
+ case NURBS_KNOT_MODE_ENDPOINT:
+ for (const int i : dst.index_range().drop_back(1).drop_front(1)) {
+ dst[i] = src[i + 1];
+ }
+ dst.first() = src.first();
+ dst.last() = src.last();
+ break;
+ default:
+ /* Every 3rd NURBS position (starting from index 1) should have its attributes transferred.
+ */
+ scale_input_assign<T>(src, 3, 1, dst);
+ }
+}
+
+static void nurbs_to_bezier_assign(const GSpan src, const KnotsMode knots_mode, 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);
+ });
+}
+
+static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_positions,
+ const KnotsMode knots_mode)
+{
+ const int nurbs_positions_num = nurbs_positions.size();
+ Vector<float3> handle_positions;
+
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ const bool is_periodic = knots_mode == NURBS_KNOT_MODE_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]);
+ }
+
+ /* Place Bezier handles on interior NURBS hull segments. Those handles can be either placed on
+ * endpoints, midpoints or 1/3 of the distance of a hull segment. */
+ const int segments_num = nurbs_positions_num - 1;
+ const bool ignore_interior_segment = segments_num == 3 && is_periodic == false;
+ if (ignore_interior_segment == false) {
+ const float mid_offset = (float)(segments_num - 1) / 2.0f;
+ for (const int i : IndexRange(1, segments_num - 2)) {
+ /* Divisor can have values: 1, 2 or 3. */
+ 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_num - 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]);
+ }
+ }
+ else {
+ for (const int i : IndexRange(nurbs_positions_num)) {
+ if (i % 3 == 1) {
+ continue;
+ }
+ handle_positions.append(nurbs_positions[i]);
+ }
+ if (nurbs_positions_num % 3 == 1) {
+ handle_positions.pop_last();
+ }
+ else if (nurbs_positions_num % 3 == 2) {
+ const int last_index = nurbs_positions_num - 1;
+ handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
+ }
+ }
+
+ return handle_positions;
+}
+
+static void create_nurbs_to_bezier_positions(const Span<float3> nurbs_positions,
+ const Span<float3> handle_positions,
+ const KnotsMode knots_mode,
+ MutableSpan<float3> bezier_positions)
+{
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ for (const int i : bezier_positions.index_range()) {
+ bezier_positions[i] = math::interpolate(
+ handle_positions[i * 2], handle_positions[i * 2 + 1], 0.5f);
+ }
+ }
+ else {
+ /* Every 3rd NURBS position (starting from index 1) should be converted to Bezier position. */
+ scale_input_assign(nurbs_positions, 3, 1, bezier_positions);
+ }
+}
+
+static int to_bezier_size(const CurveType src_type,
+ const bool cyclic,
+ const KnotsMode knots_mode,
+ const int src_size)
+{
+ switch (src_type) {
+ case CURVE_TYPE_NURBS: {
+ if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ return cyclic ? src_size : src_size - 2;
+ }
+ return (src_size + 1) / 3;
+ }
+ default:
+ return src_size;
+ }
+}
+
+static int to_nurbs_size(const CurveType src_type, const int src_size)
+{
+ switch (src_type) {
+ case CURVE_TYPE_BEZIER:
+ case CURVE_TYPE_CATMULL_ROM:
+ return src_size * 3;
+ default:
+ return src_size;
+ }
+}
+
+static void retrieve_curve_sizes(const bke::CurvesGeometry &curves, MutableSpan<int> sizes)
+{
+ threading::parallel_for(curves.curves_range(), 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ sizes[i] = curves.points_for_curve(i).size();
+ }
+ });
+}
+
+struct GenericAttributes : NonCopyable, NonMovable {
+ Vector<GSpan> src;
+ Vector<GMutableSpan> dst;
+
+ Vector<bke::GSpanAttributeWriter> attributes;
+};
+
+static void retrieve_generic_point_attributes(const bke::AttributeAccessor &src_attributes,
+ bke::MutableAttributeAccessor &dst_attributes,
+ GenericAttributes &attributes)
+{
+ src_attributes.for_all(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_POINT) {
+ /* Curve domain attributes are all copied directly to the result in one step. */
+ return true;
+ }
+ if (src_attributes.is_builtin(id)) {
+ if (!(id.is_named() && ELEM(id, "tilt", "radius"))) {
+ return true;
+ }
+ }
+
+ GVArray src_attribute = src_attributes.lookup(id, ATTR_DOMAIN_POINT);
+ BLI_assert(src_attribute);
+ attributes.src.append(src_attribute.get_internal_span());
+
+ bke::GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_span(
+ id, ATTR_DOMAIN_POINT, meta_data.data_type);
+ attributes.dst.append(dst_attribute.span);
+ attributes.attributes.append(std::move(dst_attribute));
+
+ return true;
+ });
+}
+
+static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection)
+{
+ const VArray<int8_t> src_knot_modes = src_curves.nurbs_knots_modes();
+ const VArray<int8_t> src_types = src_curves.curve_types();
+ const VArray<bool> src_cyclic = src_curves.cyclic();
+ const Span<float3> src_positions = src_curves.positions();
+
+ bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
+ dst_curves.fill_curve_types(selection, CURVE_TYPE_BEZIER);
+
+ MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
+ retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ dst_offsets[i] = to_bezier_size(
+ CurveType(src_types[i]), src_cyclic[i], KnotsMode(src_knot_modes[i]), dst_offsets[i]);
+ }
+ });
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
+ dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
+
+ const bke::AttributeAccessor src_attributes = src_curves.attributes();
+ bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
+
+ GenericAttributes attributes;
+ retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes);
+
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+ MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
+ MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
+ MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
+ MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
+ MutableSpan<float> dst_weights = dst_curves.nurbs_weights_for_write();
+
+ auto catmull_rom_to_bezier = [&](IndexMask selection) {
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ catmull_rom_to_bezier_handles(src_positions.slice(src_points),
+ src_cyclic[i],
+ dst_handles_l.slice(dst_points),
+ dst_handles_r.slice(dst_points));
+ }
+ });
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto poly_to_bezier = [&](IndexMask selection) {
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_VECTOR, dst_types_r);
+ dst_curves.calculate_bezier_auto_handles();
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto bezier_to_bezier = [&](IndexMask selection) {
+ const VArraySpan<int8_t> src_types_l = src_curves.handle_types_left();
+ const VArraySpan<int8_t> src_types_r = src_curves.handle_types_right();
+ const Span<float3> src_handles_l = src_curves.handle_positions_left();
+ const Span<float3> src_handles_r = src_curves.handle_positions_right();
+
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_l, dst_handles_l);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_handles_r, dst_handles_r);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_l, dst_types_l);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_types_r, dst_types_r);
+
+ dst_curves.calculate_bezier_auto_handles();
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, selection, attributes.src[i], attributes.dst[i]);
+ }
+ };
+
+ auto nurbs_to_bezier = [&](IndexMask selection) {
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_l);
+ bke::curves::fill_points<int8_t>(dst_curves, selection, BEZIER_HANDLE_ALIGN, dst_types_r);
+ bke::curves::fill_points<float>(dst_curves, selection, 0.0f, dst_weights);
+
+ threading::parallel_for(selection.index_range(), 64, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ const Span<float3> src_curve_positions = src_positions.slice(src_points);
+
+ KnotsMode knots_mode = KnotsMode(src_knot_modes[i]);
+ Span<float3> nurbs_positions = src_curve_positions;
+ Vector<float3> nurbs_positions_vector;
+ if (src_cyclic[i] && is_nurbs_to_bezier_one_to_one(knots_mode)) {
+ /* For conversion treat this as periodic closed curve. Extend NURBS hull to first and
+ * second point which will act as a skeleton for placing Bezier handles. */
+ nurbs_positions_vector.extend(src_curve_positions);
+ nurbs_positions_vector.append(src_curve_positions[0]);
+ nurbs_positions_vector.append(src_curve_positions[1]);
+ nurbs_positions = nurbs_positions_vector;
+ knots_mode = NURBS_KNOT_MODE_NORMAL;
+ }
+
+ const Vector<float3> handle_positions = create_nurbs_to_bezier_handles(nurbs_positions,
+ knots_mode);
+
+ scale_input_assign(handle_positions.as_span(), 2, 0, dst_handles_l.slice(dst_points));
+ scale_input_assign(handle_positions.as_span(), 2, 1, dst_handles_r.slice(dst_points));
+
+ create_nurbs_to_bezier_positions(
+ nurbs_positions, handle_positions, knots_mode, dst_positions.slice(dst_points));
+ }
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ nurbs_to_bezier_assign(attributes.src[i_attribute].slice(src_points),
+ KnotsMode(src_knot_modes[i]),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ bke::curves::foreach_curve_by_type(src_curves.curve_types(),
+ src_curves.curve_type_counts(),
+ selection,
+ catmull_rom_to_bezier,
+ poly_to_bezier,
+ bezier_to_bezier,
+ nurbs_to_bezier);
+
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range());
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
+ }
+
+ for (bke::GSpanAttributeWriter &attribute : attributes.attributes) {
+ attribute.finish();
+ }
+
+ return dst_curves;
+}
+
+static bke::CurvesGeometry convert_curves_to_nurbs(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection)
+{
+ const VArray<int8_t> src_types = src_curves.curve_types();
+ const VArray<bool> src_cyclic = src_curves.cyclic();
+ const Span<float3> src_positions = src_curves.positions();
+
+ bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
+ dst_curves.fill_curve_types(selection, CURVE_TYPE_NURBS);
+
+ MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
+ retrieve_curve_sizes(src_curves, dst_curves.offsets_for_write());
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ dst_offsets[i] = to_nurbs_size(CurveType(src_types[i]), dst_offsets[i]);
+ }
+ });
+ bke::curves::accumulate_counts_to_offsets(dst_offsets);
+ dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
+
+ const bke::AttributeAccessor src_attributes = src_curves.attributes();
+ bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
+
+ GenericAttributes attributes;
+ retrieve_generic_point_attributes(src_attributes, dst_attributes, attributes);
+
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ auto fill_weights_if_necessary = [&](const IndexMask selection) {
+ if (!src_curves.nurbs_weights().is_empty()) {
+ bke::curves::fill_points(dst_curves, selection, 1.0f, dst_curves.nurbs_weights_for_write());
+ }
+ };
+
+ auto catmull_rom_to_nurbs = [&](IndexMask selection) {
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
+ fill_weights_if_necessary(selection);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ catmull_rom_to_nurbs_positions(
+ src_positions.slice(src_points), src_cyclic[i], dst_positions.slice(dst_points));
+ }
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ auto poly_to_nurbs = [&](IndexMask selection) {
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+ fill_weights_if_necessary(selection);
+
+ /* Avoid using "Endpoint" knots modes for cyclic curves, since it adds a sharp point at the
+ * start/end. */
+ if (src_cyclic.is_single()) {
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(
+ selection,
+ src_cyclic.get_internal_single() ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT);
+ }
+ else {
+ VArraySpan<bool> cyclic{src_cyclic};
+ MutableSpan<int8_t> knots_modes = dst_curves.nurbs_knots_modes_for_write();
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ knots_modes[i] = cyclic[i] ? NURBS_KNOT_MODE_NORMAL : NURBS_KNOT_MODE_ENDPOINT;
+ }
+ });
+ }
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ attributes.src[i_attribute],
+ attributes.dst[i_attribute]);
+ }
+ };
+
+ auto bezier_to_nurbs = [&](IndexMask selection) {
+ const Span<float3> src_handles_l = src_curves.handle_positions_left();
+ const Span<float3> src_handles_r = src_curves.handle_positions_right();
+
+ dst_curves.nurbs_orders_for_write().fill_indices(selection, 4);
+ dst_curves.nurbs_knots_modes_for_write().fill_indices(selection, NURBS_KNOT_MODE_BEZIER);
+ fill_weights_if_necessary(selection);
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_positions_to_nurbs(src_positions.slice(src_points),
+ src_handles_l.slice(src_points),
+ src_handles_r.slice(src_points),
+ dst_positions.slice(dst_points));
+ }
+ });
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(i);
+ const IndexRange dst_points = dst_curves.points_for_curve(i);
+ bezier_generic_to_nurbs(attributes.src[i_attribute].slice(src_points),
+ attributes.dst[i_attribute].slice(dst_points));
+ }
+ });
+ }
+ };
+
+ auto nurbs_to_nurbs = [&](IndexMask selection) {
+ bke::curves::copy_point_data(src_curves, dst_curves, selection, src_positions, dst_positions);
+
+ if (!src_curves.nurbs_weights().is_empty()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ src_curves.nurbs_weights(),
+ dst_curves.nurbs_weights_for_write());
+ }
+
+ for (const int i_attribute : attributes.src.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ selection,
+ attributes.src[i_attribute],
+ attributes.dst[i_attribute]);
+ }
+ };
+
+ bke::curves::foreach_curve_by_type(src_curves.curve_types(),
+ src_curves.curve_type_counts(),
+ selection,
+ catmull_rom_to_nurbs,
+ poly_to_nurbs,
+ bezier_to_nurbs,
+ nurbs_to_nurbs);
+
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range());
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
+ }
+
+ for (bke::GSpanAttributeWriter &attribute : attributes.attributes) {
+ attribute.finish();
+ }
+
+ return dst_curves;
+}
+
+static bke::CurvesGeometry convert_curves_trivial(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const CurveType dst_type)
+{
+ bke::CurvesGeometry dst_curves(src_curves);
+ dst_curves.fill_curve_types(selection, dst_type);
+ dst_curves.remove_attributes_based_on_types();
+ return dst_curves;
+}
+
+bke::CurvesGeometry convert_curves(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const CurveType dst_type)
+{
+ switch (dst_type) {
+ case CURVE_TYPE_CATMULL_ROM:
+ case CURVE_TYPE_POLY:
+ return convert_curves_trivial(src_curves, selection, dst_type);
+ case CURVE_TYPE_BEZIER:
+ return convert_curves_to_bezier(src_curves, selection);
+ case CURVE_TYPE_NURBS:
+ return convert_curves_to_nurbs(src_curves, selection);
+ }
+ BLI_assert_unreachable();
+ return {};
+}
+
+bool try_curves_conversion_in_place(const IndexMask selection,
+ const CurveType dst_type,
+ FunctionRef<bke::CurvesGeometry &()> get_writable_curves_fn)
+{
+ if (conversion_can_change_point_num(dst_type)) {
+ return false;
+ }
+ bke::CurvesGeometry &curves = get_writable_curves_fn();
+ curves.fill_curve_types(selection, dst_type);
+ curves.remove_attributes_based_on_types();
+ return true;
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/subdivide_curves.cc b/source/blender/geometry/intern/subdivide_curves.cc
new file mode 100644
index 00000000000..8a6f3cbd5e3
--- /dev/null
+++ b/source/blender/geometry/intern/subdivide_curves.cc
@@ -0,0 +1,428 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
+
+#include "BLI_task.hh"
+
+#include "GEO_subdivide_curves.hh"
+
+namespace blender::geometry {
+
+/**
+ * Return a range used to retrieve values from an array of values stored per point, but with an
+ * extra element at the end of each curve. This is useful for offsets within curves, where it is
+ * convenient to store the first 0 and have the last offset be the total result curve size.
+ */
+static IndexRange curve_dst_offsets(const IndexRange points, const int curve_index)
+{
+ return {curve_index + points.start(), points.size() + 1};
+}
+
+static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const Span<IndexRange> unselected_ranges,
+ const VArray<int> &cuts,
+ const Span<bool> cyclic,
+ MutableSpan<int> dst_curve_offsets,
+ MutableSpan<int> dst_point_offsets)
+{
+ /* Fill the array with each curve's point count, then accumulate them to the offsets. */
+ bke::curves::fill_curve_counts(src_curves, unselected_ranges, dst_curve_offsets);
+ threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
+ for (const int curve_i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
+
+ MutableSpan<int> point_offsets = dst_point_offsets.slice(src_segments);
+
+ MutableSpan<int> point_counts = point_offsets.drop_back(1);
+ cuts.materialize_compressed(src_points, point_counts);
+ for (int &count : point_counts) {
+ /* Make sure the number of cuts is greater than zero and add one for the existing point. */
+ count = std::max(count, 0) + 1;
+ }
+ if (!cyclic[curve_i]) {
+ /* The last point only has a segment to be subdivided if the curve isn't cyclic. */
+ point_counts.last() = 1;
+ }
+
+ bke::curves::accumulate_counts_to_offsets(point_offsets);
+ dst_curve_offsets[curve_i] = point_offsets.last();
+ }
+ });
+ bke::curves::accumulate_counts_to_offsets(dst_curve_offsets);
+}
+
+template<typename T>
+static inline void linear_interpolation(const T &a, const T &b, MutableSpan<T> dst)
+{
+ dst.first() = a;
+ const float step = 1.0f / dst.size();
+ for (const int i : dst.index_range().drop_front(1)) {
+ dst[i] = attribute_math::mix2(i * step, a, b);
+ }
+}
+
+template<typename T>
+static void subdivide_attribute_linear(const bke::CurvesGeometry &src_curves,
+ const bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<int> point_offsets,
+ const Span<T> src,
+ MutableSpan<T> dst)
+{
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
+ for (const int curve_i : selection.slice(selection_range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
+ const Span<int> offsets = point_offsets.slice(src_segments);
+
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+ const Span<T> curve_src = src.slice(src_points);
+ MutableSpan<T> curve_dst = dst.slice(dst_points);
+
+ threading::parallel_for(curve_src.index_range().drop_back(1), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const IndexRange segment_points = bke::offsets_to_range(offsets, i);
+ linear_interpolation(curve_src[i], curve_src[i + 1], curve_dst.slice(segment_points));
+ }
+ });
+
+ const IndexRange dst_last_segment = bke::offsets_to_range(offsets, src_points.size() - 1);
+ linear_interpolation(curve_src.last(), curve_src.first(), dst.slice(dst_last_segment));
+ }
+ });
+}
+
+static void subdivide_attribute_linear(const bke::CurvesGeometry &src_curves,
+ const bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<int> point_offsets,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ subdivide_attribute_linear(
+ src_curves, dst_curves, selection, point_offsets, src.typed<T>(), dst.typed<T>());
+ });
+}
+
+template<typename T>
+static void subdivide_attribute_catmull_rom(const bke::CurvesGeometry &src_curves,
+ const bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<int> point_offsets,
+ const Span<bool> cyclic,
+ const Span<T> src,
+ MutableSpan<T> dst)
+{
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
+ for (const int curve_i : selection.slice(selection_range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+
+ bke::curves::catmull_rom::interpolate_to_evaluated(src.slice(src_points),
+ cyclic[curve_i],
+ point_offsets.slice(src_segments),
+ dst.slice(dst_points));
+ }
+ });
+}
+
+static void subdivide_attribute_catmull_rom(const bke::CurvesGeometry &src_curves,
+ const bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<int> point_offsets,
+ const Span<bool> cyclic,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ subdivide_attribute_catmull_rom(
+ src_curves, dst_curves, selection, point_offsets, cyclic, src.typed<T>(), dst.typed<T>());
+ });
+}
+
+static void subdivide_bezier_segment(const float3 &position_prev,
+ const float3 &handle_prev,
+ const float3 &handle_next,
+ const float3 &position_next,
+ const HandleType type_prev,
+ const HandleType type_next,
+ const IndexRange segment_points,
+ MutableSpan<float3> dst_positions,
+ MutableSpan<float3> dst_handles_l,
+ MutableSpan<float3> dst_handles_r,
+ MutableSpan<int8_t> dst_types_l,
+ MutableSpan<int8_t> dst_types_r,
+ const bool is_last_cyclic_segment)
+{
+ auto fill_segment_handle_types = [&](const HandleType type) {
+ /* Also change the left handle of the control point following the segment's points. And don't
+ * change the left handle of the first point, since that is part of the previous segment. */
+ dst_types_l.slice(segment_points.shift(1)).fill(type);
+ dst_types_r.slice(segment_points).fill(type);
+ };
+
+ if (bke::curves::bezier::segment_is_vector(type_prev, type_next)) {
+ linear_interpolation(position_prev, position_next, dst_positions.slice(segment_points));
+ fill_segment_handle_types(BEZIER_HANDLE_VECTOR);
+ }
+ else {
+ /* The first point in the segment is always copied. */
+ dst_positions[segment_points.first()] = position_prev;
+
+ /* Non-vector segments in the result curve 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. */
+ fill_segment_handle_types(BEZIER_HANDLE_FREE);
+
+ /* In order to generate a Bezier curve with the same shape as the input curve, 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. */
+ float3 segment_start = position_prev;
+ float3 segment_handle_prev = handle_prev;
+ float3 segment_handle_next = handle_next;
+ const float3 segment_end = position_next;
+
+ for (const int i : IndexRange(segment_points.size() - 1)) {
+ const float parameter = 1.0f / (segment_points.size() - i);
+ const int point_i = segment_points[i];
+ bke::curves::bezier::Insertion insert = bke::curves::bezier::insert(
+ segment_start, segment_handle_prev, segment_handle_next, segment_end, parameter);
+
+ /* Copy relevant temporary data to the result. */
+ dst_handles_r[point_i] = insert.handle_prev;
+ dst_handles_l[point_i + 1] = insert.left_handle;
+ dst_positions[point_i + 1] = insert.position;
+
+ /* Update the segment to prepare it for the next subdivision. */
+ segment_start = insert.position;
+ segment_handle_prev = insert.right_handle;
+ segment_handle_next = insert.handle_next;
+ }
+
+ /* Copy the handles for the last segment from the working variables. */
+ const int i_segment_last = is_last_cyclic_segment ? 0 : segment_points.one_after_last();
+ dst_handles_r[segment_points.last()] = segment_handle_prev;
+ dst_handles_l[i_segment_last] = segment_handle_next;
+ }
+}
+
+static void subdivide_bezier_positions(const Span<float3> src_positions,
+ const Span<int8_t> src_types_l,
+ const Span<int8_t> src_types_r,
+ const Span<float3> src_handles_l,
+ const Span<float3> src_handles_r,
+ const Span<int> evaluated_offsets,
+ const bool cyclic,
+ MutableSpan<float3> dst_positions,
+ MutableSpan<int8_t> dst_types_l,
+ MutableSpan<int8_t> dst_types_r,
+ MutableSpan<float3> dst_handles_l,
+ MutableSpan<float3> dst_handles_r)
+{
+ threading::parallel_for(src_positions.index_range().drop_back(1), 512, [&](IndexRange range) {
+ for (const int segment_i : range) {
+ const IndexRange segment = bke::offsets_to_range(evaluated_offsets, segment_i);
+ subdivide_bezier_segment(src_positions[segment_i],
+ src_handles_r[segment_i],
+ src_handles_l[segment_i + 1],
+ src_positions[segment_i + 1],
+ HandleType(src_types_r[segment_i]),
+ HandleType(src_types_l[segment_i + 1]),
+ segment,
+ dst_positions,
+ dst_handles_l,
+ dst_handles_r,
+ dst_types_l,
+ dst_types_r,
+ false);
+ }
+ });
+
+ if (cyclic) {
+ const int last_index = src_positions.index_range().last();
+ const IndexRange segment = bke::offsets_to_range(evaluated_offsets, last_index);
+ const HandleType type_prev = HandleType(src_types_r.last());
+ const HandleType type_next = HandleType(src_types_l.first());
+ subdivide_bezier_segment(src_positions.last(),
+ src_handles_r.last(),
+ src_handles_l.first(),
+ src_positions.first(),
+ type_prev,
+ type_next,
+ segment,
+ dst_positions,
+ dst_handles_l,
+ dst_handles_r,
+ dst_types_l,
+ dst_types_r,
+ true);
+
+ if (bke::curves::bezier::segment_is_vector(type_prev, type_next)) {
+ dst_types_l.first() = BEZIER_HANDLE_VECTOR;
+ dst_types_r.last() = BEZIER_HANDLE_VECTOR;
+ }
+ else {
+ dst_types_l.first() = BEZIER_HANDLE_FREE;
+ dst_types_r.last() = BEZIER_HANDLE_FREE;
+ }
+ }
+ else {
+ dst_positions.last() = src_positions.last();
+ dst_types_l.first() = src_types_l.first();
+ dst_types_r.last() = src_types_r.last();
+ dst_handles_l.first() = src_handles_l.first();
+ dst_handles_r.last() = src_handles_r.last();
+ }
+
+ /* TODO: It would be possible to avoid calling this for all segments besides vector segments. */
+ bke::curves::bezier::calculate_auto_handles(
+ cyclic, dst_types_l, dst_types_r, dst_positions, dst_handles_l, dst_handles_r);
+}
+
+bke::CurvesGeometry subdivide_curves(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const VArray<int> &cuts)
+{
+ const Vector<IndexRange> unselected_ranges = selection.extract_ranges_invert(
+ src_curves.curves_range());
+
+ /* Cyclic is accessed a lot, it's probably worth it to make sure it's a span. */
+ const VArraySpan<bool> cyclic{src_curves.cyclic()};
+
+ bke::CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
+
+ /* For each point, this contains the point offset in the corresponding result curve,
+ * starting at zero. For example for two curves with four points each, the values might
+ * look like this:
+ *
+ * | | Curve 0 | Curve 1 |
+ * | ------------------- |---|---|---|---|---|---|---|---|---|----|
+ * | Cuts | 0 | 3 | 0 | 0 | - | 2 | 0 | 0 | 4 | - |
+ * | New Point Count | 1 | 4 | 1 | 1 | - | 3 | 1 | 1 | 5 | - |
+ * | Accumulated Offsets | 0 | 1 | 5 | 6 | 7 | 0 | 3 | 4 | 5 | 10 |
+ *
+ * Storing the leading zero is unnecessary but makes the array a bit simpler to use by avoiding
+ * a check for the first segment, and because some existing utilities also use leading zeros. */
+ Array<int> dst_point_offsets(src_curves.points_num() + src_curves.curves_num());
+#ifdef DEBUG
+ dst_point_offsets.fill(-1);
+#endif
+ calculate_result_offsets(src_curves,
+ selection,
+ unselected_ranges,
+ cuts,
+ cyclic,
+ dst_curves.offsets_for_write(),
+ dst_point_offsets);
+ const Span<int> point_offsets = dst_point_offsets.as_span();
+
+ dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
+
+ const bke::AttributeAccessor src_attributes = src_curves.attributes();
+ bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
+
+ auto subdivide_catmull_rom = [&](IndexMask selection) {
+ for (auto &attribute : bke::retrieve_attributes_for_transfer(
+ src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT)) {
+ subdivide_attribute_catmull_rom(src_curves,
+ dst_curves,
+ selection,
+ point_offsets,
+ cyclic,
+ attribute.src,
+ attribute.dst.span);
+ attribute.dst.finish();
+ }
+ };
+
+ auto subdivide_poly = [&](IndexMask selection) {
+ for (auto &attribute : bke::retrieve_attributes_for_transfer(
+ src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT)) {
+ subdivide_attribute_linear(
+ src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span);
+ attribute.dst.finish();
+ }
+ };
+
+ auto subdivide_bezier = [&](IndexMask selection) {
+ const Span<float3> src_positions = src_curves.positions();
+ const VArraySpan<int8_t> src_types_l{src_curves.handle_types_left()};
+ const VArraySpan<int8_t> src_types_r{src_curves.handle_types_right()};
+ const Span<float3> src_handles_l = src_curves.handle_positions_left();
+ const Span<float3> src_handles_r = src_curves.handle_positions_right();
+
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+ MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
+ MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
+ MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
+ MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int curve_i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
+
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+ subdivide_bezier_positions(src_positions.slice(src_points),
+ src_types_l.slice(src_points),
+ src_types_r.slice(src_points),
+ src_handles_l.slice(src_points),
+ src_handles_r.slice(src_points),
+ point_offsets.slice(src_segments),
+ cyclic[curve_i],
+ dst_positions.slice(dst_points),
+ dst_types_l.slice(dst_points),
+ dst_types_r.slice(dst_points),
+ dst_handles_l.slice(dst_points),
+ dst_handles_r.slice(dst_points));
+ }
+ });
+
+ for (auto &attribute : bke::retrieve_attributes_for_transfer(src_attributes,
+ dst_attributes,
+ ATTR_DOMAIN_MASK_POINT,
+ {"position",
+ "handle_type_left",
+ "handle_type_right",
+ "handle_right",
+ "handle_left"})) {
+ subdivide_attribute_linear(
+ src_curves, dst_curves, selection, point_offsets, attribute.src, attribute.dst.span);
+ attribute.dst.finish();
+ }
+ };
+
+ /* NURBS curves are just treated as poly curves. NURBS subdivision that maintains
+ * their shape may be possible, but probably wouldn't work with the "cuts" input. */
+ auto subdivide_nurbs = subdivide_poly;
+
+ bke::curves::foreach_curve_by_type(src_curves.curve_types(),
+ src_curves.curve_type_counts(),
+ selection,
+ subdivide_catmull_rom,
+ subdivide_poly,
+ subdivide_bezier,
+ subdivide_nurbs);
+
+ if (!unselected_ranges.is_empty()) {
+ for (auto &attribute : bke::retrieve_attributes_for_transfer(
+ src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT)) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attribute.src, attribute.dst.span);
+ attribute.dst.finish();
+ }
+ }
+
+ return dst_curves;
+}
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/uv_parametrizer.c b/source/blender/geometry/intern/uv_parametrizer.c
index ad4b051a6c2..38924c718c3 100644
--- a/source/blender/geometry/intern/uv_parametrizer.c
+++ b/source/blender/geometry/intern/uv_parametrizer.c
@@ -4,26 +4,18 @@
* \ingroup eduv
*/
+#include "GEO_uv_parametrizer.h"
+
#include "MEM_guardedalloc.h"
#include "BLI_boxpack_2d.h"
#include "BLI_convexhull_2d.h"
+#include "BLI_ghash.h"
#include "BLI_heap.h"
-#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_polyfill_2d.h"
#include "BLI_polyfill_2d_beautify.h"
#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "GEO_uv_parametrizer.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "BLI_sys_types.h" /* for intptr_t support */
#include "eigen_capi.h"
@@ -36,11 +28,6 @@
#define param_warning(message) \
{/*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/}(void)0
-typedef enum PBool {
- P_TRUE = 1,
- P_FALSE = 0,
-} PBool;
-
/* Special Purpose Hash */
typedef intptr_t PHashKey;
@@ -56,11 +43,6 @@ typedef struct PHash {
int size, cursize, cursize_id;
} PHash;
-struct PChart;
-struct PEdge;
-struct PFace;
-struct PVert;
-
/* Simplices */
typedef struct PVert {
@@ -149,6 +131,7 @@ typedef struct PChart {
PEdge *edges;
PFace *faces;
int nverts, nedges, nfaces;
+ int nboundaries;
PVert *collapsed_verts;
PEdge *collapsed_edges;
@@ -165,7 +148,8 @@ typedef struct PChart {
} lscm;
struct PChartPack {
float rescale, area;
- float size[2] /* , trans[2] */;
+ float size[2];
+ float origin[2];
} pack;
} u;
@@ -195,6 +179,9 @@ typedef struct ParamHandle {
PHash *hash_edges;
PHash *hash_faces;
+ struct GHash *pin_hash;
+ int unique_pin_count;
+
PChart **charts;
int ncharts;
@@ -202,7 +189,6 @@ typedef struct ParamHandle {
RNG *rng;
float blend;
- bool do_aspect;
} ParamHandle;
/* PHash
@@ -319,54 +305,14 @@ static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link)
/* Geometry */
-static float p_vec_angle_cos(const float v1[3], const float v2[3], const float v3[3])
-{
- float d1[3], d2[3];
-
- d1[0] = v1[0] - v2[0];
- d1[1] = v1[1] - v2[1];
- d1[2] = v1[2] - v2[2];
-
- d2[0] = v3[0] - v2[0];
- d2[1] = v3[1] - v2[1];
- d2[2] = v3[2] - v2[2];
-
- normalize_v3(d1);
- normalize_v3(d2);
-
- return d1[0] * d2[0] + d1[1] * d2[1] + d1[2] * d2[2];
-}
-
static float p_vec_angle(const float v1[3], const float v2[3], const float v3[3])
{
- float dot = p_vec_angle_cos(v1, v2, v3);
-
- if (dot <= -1.0f) {
- return (float)M_PI;
- }
- if (dot >= 1.0f) {
- return 0.0f;
- }
- return acosf(dot);
+ return angle_v3v3v3(v1, v2, v3);
}
-
static float p_vec2_angle(const float v1[2], const float v2[2], const float v3[2])
{
- float u1[3], u2[3], u3[3];
-
- u1[0] = v1[0];
- u1[1] = v1[1];
- u1[2] = 0.0f;
- u2[0] = v2[0];
- u2[1] = v2[1];
- u2[2] = 0.0f;
- u3[0] = v3[0];
- u3[1] = v3[1];
- u3[2] = 0.0f;
-
- return p_vec_angle(u1, u2, u3);
+ return angle_v2v2v2(v1, v2, v3);
}
-
static void p_triangle_angles(
const float v1[3], const float v2[3], const float v3[3], float *r_a1, float *r_a2, float *r_a3)
{
@@ -407,25 +353,12 @@ static float p_face_uv_area_signed(PFace *f)
static float p_edge_length(PEdge *e)
{
- PVert *v1 = e->vert, *v2 = e->next->vert;
- float d[3];
-
- d[0] = v2->co[0] - v1->co[0];
- d[1] = v2->co[1] - v1->co[1];
- d[2] = v2->co[2] - v1->co[2];
-
- return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ return len_v3v3(e->vert->co, e->next->vert->co);
}
static float p_edge_uv_length(PEdge *e)
{
- PVert *v1 = e->vert, *v2 = e->next->vert;
- float d[3];
-
- d[0] = v2->uv[0] - v1->uv[0];
- d[1] = v2->uv[1] - v1->uv[1];
-
- return sqrtf(d[0] * d[0] + d[1] * d[1]);
+ return len_v2v2(e->vert->uv, e->next->vert->uv);
}
static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2])
@@ -499,64 +432,27 @@ static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
}
}
-static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2])
-{
- PVert *v;
- uint i = 0;
-
- for (v = chart->verts; v; v = v->nextlink) {
- copy_v2_v2(v->uv, points[i++]);
- }
-}
-
-static PBool p_intersect_line_2d_dir(const float v1[2],
- const float dir1[2],
- const float v2[2],
- const float dir2[2],
- float r_isect[2])
+static bool p_intersect_line_2d_dir(const float v1[2],
+ const float dir1[2],
+ const float v2[2],
+ const float dir2[2],
+ float r_isect[2])
{
float lmbda, div;
div = dir2[0] * dir1[1] - dir2[1] * dir1[0];
if (div == 0.0f) {
- return P_FALSE;
+ return false;
}
lmbda = ((v1[1] - v2[1]) * dir1[0] - (v1[0] - v2[0]) * dir1[1]) / div;
r_isect[0] = v1[0] + lmbda * dir2[0];
r_isect[1] = v1[1] + lmbda * dir2[1];
- return P_TRUE;
+ return true;
}
-#if 0
-static PBool p_intersect_line_2d(const float v1[2],
- const float v2[2],
- const float v3[2],
- const float v4[2],
- const float r_isect[2])
-{
- float dir1[2], dir2[2];
-
- dir1[0] = v4[0] - v3[0];
- dir1[1] = v4[1] - v3[1];
-
- dir2[0] = v2[0] - v1[0];
- dir2[1] = v2[1] - v1[1];
-
- if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) {
- /* parallel - should never happen in theory for polygon kernel, but
- * let's give a point nearby in case things go wrong */
- isect[0] = (v1[0] + v2[0]) * 0.5f;
- isect[1] = (v1[1] + v2[1]) * 0.5f;
- return P_FALSE;
- }
-
- return P_TRUE;
-}
-#endif
-
/* Topological Utilities */
static PEdge *p_wheel_edge_next(PEdge *e)
@@ -586,9 +482,9 @@ static PEdge *p_boundary_edge_prev(PEdge *e)
return last->next->next;
}
-static PBool p_vert_interior(PVert *v)
+static bool p_vert_interior(PVert *v)
{
- return (v->edge->pair != NULL);
+ return v->edge->pair;
}
static void p_face_flip(PFace *f)
@@ -807,7 +703,7 @@ static PEdge *p_edge_lookup(ParamHandle *handle, const PHashKey *vkeys)
return NULL;
}
-static int p_face_exists(ParamHandle *handle, ParamKey *pvkeys, int i1, int i2, int i3)
+static int p_face_exists(ParamHandle *handle, const ParamKey *pvkeys, int i1, int i2, int i3)
{
PHashKey *vkeys = (PHashKey *)pvkeys;
PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
@@ -816,19 +712,19 @@ static int p_face_exists(ParamHandle *handle, ParamKey *pvkeys, int i1, int i2,
while (e) {
if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) {
if (e->next->next->vert->u.key == vkeys[i3]) {
- return P_TRUE;
+ return true;
}
}
else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) {
if (e->next->next->vert->u.key == vkeys[i3]) {
- return P_TRUE;
+ return true;
}
}
e = (PEdge *)phash_next(handle->hash_edges, key, (PHashLink *)e);
}
- return P_FALSE;
+ return false;
}
static PChart *p_chart_new(ParamHandle *handle)
@@ -845,7 +741,7 @@ static void p_chart_delete(PChart *chart)
MEM_freeN(chart);
}
-static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
+static bool p_edge_implicit_seam(PEdge *e, PEdge *ep)
{
float *uv1, *uv2, *uvp1, *uvp2;
float limit[2];
@@ -868,21 +764,18 @@ static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
if ((fabsf(uv1[0] - uvp1[0]) > limit[0]) || (fabsf(uv1[1] - uvp1[1]) > limit[1])) {
e->flag |= PEDGE_SEAM;
ep->flag |= PEDGE_SEAM;
- return P_TRUE;
+ return true;
}
if ((fabsf(uv2[0] - uvp2[0]) > limit[0]) || (fabsf(uv2[1] - uvp2[1]) > limit[1])) {
e->flag |= PEDGE_SEAM;
ep->flag |= PEDGE_SEAM;
- return P_TRUE;
+ return true;
}
- return P_FALSE;
+ return false;
}
-static PBool p_edge_has_pair(ParamHandle *handle,
- PEdge *e,
- PBool topology_from_uvs,
- PEdge **r_pair)
+static bool p_edge_has_pair(ParamHandle *handle, PEdge *e, bool topology_from_uvs, PEdge **r_pair)
{
PHashKey key;
PEdge *pe;
@@ -891,7 +784,7 @@ static PBool p_edge_has_pair(ParamHandle *handle,
PHashKey key2 = e->next->vert->u.key;
if (e->flag & PEDGE_SEAM) {
- return P_FALSE;
+ return false;
}
key = PHASH_edge(key1, key2);
@@ -910,7 +803,7 @@ static PBool p_edge_has_pair(ParamHandle *handle,
if ((pe->flag & PEDGE_SEAM) || *r_pair ||
(topology_from_uvs && p_edge_implicit_seam(e, pe))) {
*r_pair = NULL;
- return P_FALSE;
+ return false;
}
*r_pair = pe;
@@ -924,17 +817,17 @@ static PBool p_edge_has_pair(ParamHandle *handle,
if ((*r_pair)->next->pair || (*r_pair)->next->next->pair) {
/* non unfoldable, maybe mobius ring or klein bottle */
*r_pair = NULL;
- return P_FALSE;
+ return false;
}
}
return (*r_pair != NULL);
}
-static PBool p_edge_connect_pair(ParamHandle *handle,
- PEdge *e,
- PBool topology_from_uvs,
- PEdge ***stack)
+static bool p_edge_connect_pair(ParamHandle *handle,
+ PEdge *e,
+ bool topology_from_uvs,
+ PEdge ***stack)
{
PEdge *pair = NULL;
@@ -955,7 +848,7 @@ static PBool p_edge_connect_pair(ParamHandle *handle,
return (e->pair != NULL);
}
-static int p_connect_pairs(ParamHandle *handle, PBool topology_from_uvs)
+static int p_connect_pairs(ParamHandle *handle, bool topology_from_uvs)
{
PEdge **stackbase = MEM_mallocN(sizeof(*stackbase) * phash_size(handle->hash_faces),
"Pstackbase");
@@ -1009,7 +902,7 @@ static void p_split_vert(PChart *chart, PEdge *e)
{
PEdge *we, *lastwe = NULL;
PVert *v = e->vert;
- PBool copy = P_TRUE;
+ bool copy = true;
if (e->flag & PEDGE_PIN) {
chart->flag |= PCHART_HAS_PINS;
@@ -1035,7 +928,7 @@ static void p_split_vert(PChart *chart, PEdge *e)
if (we == v->edge) {
/* found it, no need to copy */
- copy = P_FALSE;
+ copy = false;
v->nextlink = chart->verts;
chart->verts = v;
chart->nverts++;
@@ -1136,13 +1029,13 @@ static PFace *p_face_add(ParamHandle *handle)
static PFace *p_face_add_construct(ParamHandle *handle,
ParamKey key,
const ParamKey *vkeys,
- float *co[4],
- float *uv[4],
+ const float **co,
+ float **uv,
int i1,
int i2,
int i3,
- const ParamBool *pin,
- const ParamBool *select)
+ const bool *pin,
+ const bool *select)
{
PFace *f = p_face_add(handle);
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
@@ -1179,7 +1072,6 @@ static PFace *p_face_add_construct(ParamHandle *handle,
}
}
- /* insert into hash */
f->u.key = key;
phash_insert(handle->hash_faces, (PHashLink *)f);
@@ -1220,14 +1112,14 @@ static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3)
return f;
}
-static PBool p_quad_split_direction(ParamHandle *handle, float **co, PHashKey *vkeys)
+static bool p_quad_split_direction(ParamHandle *handle, const float **co, const ParamKey *vkeys)
{
/* Slight bias to prefer one edge over the other in case they are equal, so
* that in symmetric models we choose the same split direction instead of
* depending on floating point errors to decide. */
float bias = 1.0f + 1e-6f;
float fac = len_v3v3(co[0], co[2]) * bias - len_v3v3(co[1], co[3]);
- PBool dir = (fac <= 0.0f);
+ bool dir = (fac <= 0.0f);
/* The face exists check is there because of a special case:
* when two quads share three vertices, they can each be split into two triangles,
@@ -1248,14 +1140,12 @@ static PBool p_quad_split_direction(ParamHandle *handle, float **co, PHashKey *v
/* Construction: boundary filling */
-static void p_chart_boundaries(PChart *chart, int *r_nboundaries, PEdge **r_outer)
+static void p_chart_boundaries(PChart *chart, PEdge **r_outer)
{
PEdge *e, *be;
float len, maxlen = -1.0;
- if (r_nboundaries) {
- *r_nboundaries = 0;
- }
+ chart->nboundaries = 0;
if (r_outer) {
*r_outer = NULL;
}
@@ -1265,9 +1155,7 @@ static void p_chart_boundaries(PChart *chart, int *r_nboundaries, PEdge **r_oute
continue;
}
- if (r_nboundaries) {
- (*r_nboundaries)++;
- }
+ chart->nboundaries++;
len = 0.0f;
@@ -1566,22 +1454,22 @@ static float p_vert_cotan(const float v1[3], const float v2[3], const float v3[3
return dot_v3v3(a, b) / clen;
}
-static PBool p_vert_flipped_wheel_triangle(PVert *v)
+static bool p_vert_flipped_wheel_triangle(PVert *v)
{
PEdge *e = v->edge;
do {
if (p_face_uv_area_signed(e->face) < 0.0f) {
- return P_TRUE;
+ return true;
}
e = p_wheel_edge_next(e);
} while (e && (e != v->edge));
- return P_FALSE;
+ return false;
}
-static PBool p_vert_map_harmonic_weights(PVert *v)
+static bool p_vert_map_harmonic_weights(PVert *v)
{
float weightsum, positionsum[2], olduv[2];
@@ -1647,10 +1535,10 @@ static PBool p_vert_map_harmonic_weights(PVert *v)
v->uv[0] = olduv[0];
v->uv[1] = olduv[1];
- return P_FALSE;
+ return false;
}
- return P_TRUE;
+ return true;
}
static void p_vert_harmonic_insert(PVert *v)
@@ -1883,7 +1771,7 @@ static void p_split_vertex(PEdge *edge, PEdge *pair)
} while (e && (e != newv->edge));
}
-static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
+static bool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
{
PVert *oldv, *keepv;
@@ -1893,22 +1781,22 @@ static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
if (!edge || !pair) {
/* avoid collapsing chart into an edge */
if (edge && !edge->next->pair && !edge->next->next->pair) {
- return P_FALSE;
+ return false;
}
else if (pair && !pair->next->pair && !pair->next->next->pair) {
- return P_FALSE;
+ return false;
}
}
/* avoid merging two boundaries (oldv and keepv are on the 'other side' of
* the chart) */
else if (!p_vert_interior(oldv) && !p_vert_interior(keepv)) {
- return P_FALSE;
+ return false;
}
- return P_TRUE;
+ return true;
}
-static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew)
+static bool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew)
{
float nold[3], nnew[3], sub1[3], sub2[3];
@@ -1923,7 +1811,7 @@ static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float
return (dot_v3v3(nold, nnew) <= 0.0f);
}
-static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
+static bool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
{
PVert *oldv, *keepv;
PEdge *e;
@@ -1950,7 +1838,7 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
}
if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co)) {
- return P_FALSE;
+ return false;
}
a[0] = angle;
@@ -1967,10 +1855,10 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
for (i = 0; i < 3; i++) {
if ((b[i] < a[i]) && (b[i] < minangle)) {
- return P_FALSE;
+ return false;
}
else if ((b[i] > a[i]) && (b[i] > maxangle)) {
- return P_FALSE;
+ return false;
}
}
@@ -1980,7 +1868,7 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
if (p_vert_interior(oldv)) {
/* HLSCM criterion: angular defect smaller than threshold. */
if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0)) {
- return P_FALSE;
+ return false;
}
}
else {
@@ -1989,27 +1877,27 @@ static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
/* ABF++ criterion 2: avoid collapsing verts inwards. */
if (p_vert_interior(keepv)) {
- return P_FALSE;
+ return false;
}
/* Don't collapse significant boundary changes. */
angle = p_vec_angle(v1->co, oldv->co, v2->co);
if (angle < (M_PI * 160.0 / 180.0)) {
- return P_FALSE;
+ return false;
}
}
- return P_TRUE;
+ return true;
}
-static PBool p_collapse_allowed(PEdge *edge, PEdge *pair)
+static bool p_collapse_allowed(PEdge *edge, PEdge *pair)
{
PVert *oldv, *keepv;
p_collapsing_verts(edge, pair, &oldv, &keepv);
if (oldv->flag & PVERT_PIN) {
- return P_FALSE;
+ return false;
}
return (p_collapse_allowed_topologic(edge, pair) && p_collapse_allowed_geometric(edge, pair));
@@ -2572,21 +2460,17 @@ static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
return norm;
}
-static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
+static bool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
{
- PFace *f;
- PEdge *e;
- int i, j, ninterior = sys->ninterior, nvar = 2 * sys->ninterior;
- PBool success;
- LinearSolver *context;
+ int ninterior = sys->ninterior;
+ int nvar = 2 * ninterior;
+ LinearSolver *context = EIG_linear_solver_new(0, nvar, 1);
- context = EIG_linear_solver_new(0, nvar, 1);
-
- for (i = 0; i < nvar; i++) {
+ for (int i = 0; i < nvar; i++) {
EIG_linear_solver_right_hand_side_add(context, 0, i, sys->bInterior[i]);
}
- for (f = chart->faces; f; f = f->nextlink) {
+ for (PFace *f = chart->faces; f; f = f->nextlink) {
float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3];
float row1[6], row2[6], row3[6];
int vid[6];
@@ -2691,14 +2575,14 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
row3[5] = j2[0][2] * W[2][0] + j2[1][2] * W[2][1];
}
- for (i = 0; i < 3; i++) {
+ for (int i = 0; i < 3; i++) {
int r = vid[i];
if (r == -1) {
continue;
}
- for (j = 0; j < 6; j++) {
+ for (int j = 0; j < 6; j++) {
int c = vid[j];
if (c == -1) {
@@ -2729,10 +2613,10 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
}
}
- success = EIG_linear_solver_solve(context);
+ bool success = EIG_linear_solver_solve(context);
if (success) {
- for (f = chart->faces; f; f = f->nextlink) {
+ for (PFace *f = chart->faces; f; f = f->nextlink) {
float dlambda1, pre[3], dalpha;
PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
@@ -2778,7 +2662,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
sys->alpha[e3->u.id] += dalpha / sys->weight[e3->u.id] - pre[2];
/* clamp */
- e = f->edge;
+ PEdge *e = f->edge;
do {
if (sys->alpha[e->u.id] > (float)M_PI) {
sys->alpha[e->u.id] = (float)M_PI;
@@ -2789,7 +2673,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
} while (e != f->edge);
}
- for (i = 0; i < ninterior; i++) {
+ for (int i = 0; i < ninterior; i++) {
sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i);
sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i);
}
@@ -2800,7 +2684,7 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
return success;
}
-static PBool p_chart_abf_solve(PChart *chart)
+static bool p_chart_abf_solve(PChart *chart)
{
PVert *v;
PFace *f;
@@ -2911,7 +2795,7 @@ static PBool p_chart_abf_solve(PChart *chart)
if (!p_abf_matrix_invert(&sys, chart)) {
param_warning("ABF failed to invert matrix");
p_abf_free_system(&sys);
- return P_FALSE;
+ return false;
}
p_abf_compute_sines(&sys);
@@ -2920,14 +2804,14 @@ static PBool p_chart_abf_solve(PChart *chart)
if (i == ABF_MAX_ITER) {
param_warning("ABF maximum iterations reached");
p_abf_free_system(&sys);
- return P_FALSE;
+ return false;
}
}
chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha);
p_abf_free_system(&sys);
- return P_TRUE;
+ return true;
}
/* Least Squares Conformal Maps */
@@ -2983,7 +2867,7 @@ static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
}
}
-static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
+static bool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
{
PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2;
PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe;
@@ -3044,7 +2928,7 @@ static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PV
}
if (!maxe1 || !maxe2 || (maxlen < 0.5f * totlen)) {
- return P_FALSE;
+ return false;
}
/* find pin1 in the split vertices */
@@ -3144,10 +3028,10 @@ static void p_chart_lscm_load_solution(PChart *chart)
}
}
-static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
+static void p_chart_lscm_begin(PChart *chart, bool live, bool abf)
{
PVert *v, *pin1, *pin2;
- PBool select = P_FALSE, deselect = P_FALSE;
+ bool select = false, deselect = false;
int npins = 0, id = 0;
/* give vertices matrix indices and count pins */
@@ -3155,12 +3039,12 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
if (v->flag & PVERT_PIN) {
npins++;
if (v->flag & PVERT_SELECT) {
- select = P_TRUE;
+ select = true;
}
}
if (!(v->flag & PVERT_SELECT)) {
- deselect = P_TRUE;
+ deselect = true;
}
}
@@ -3193,7 +3077,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
/* No pins, let's find some ourself. */
PEdge *outer;
- p_chart_boundaries(chart, NULL, &outer);
+ p_chart_boundaries(chart, &outer);
/* Outer can be NULL with non-finite coords. */
if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) {
@@ -3213,7 +3097,7 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
}
}
-static PBool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
+static bool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
{
LinearSolver *context = chart->u.lscm.context;
PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
@@ -3350,7 +3234,7 @@ static PBool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
if (EIG_linear_solver_solve(context)) {
p_chart_lscm_load_solution(chart);
- return P_TRUE;
+ return true;
}
for (v = chart->verts; v; v = v->nextlink) {
@@ -3358,7 +3242,7 @@ static PBool p_chart_lscm_solve(ParamHandle *handle, PChart *chart)
v->uv[1] = 0.0f;
}
- return P_FALSE;
+ return false;
}
static void p_chart_lscm_transform_single_pin(PChart *chart)
@@ -3423,8 +3307,10 @@ static float p_face_stretch(PFace *f)
area = p_face_uv_area_signed(f);
- if (area <= 0.0f) { /* flipped face -> infinite stretch */
- return 1e10f;
+ if (area <= 0.0f) {
+ /* When a face is flipped, provide a large penalty.
+ * Add on a slight gradient to unflip the face, see also: T99781. */
+ return 1e8f * (1.0f + p_edge_uv_length(e1) + p_edge_uv_length(e2) + p_edge_uv_length(e3));
}
w = 1.0f / (2.0f * area);
@@ -3570,7 +3456,7 @@ static int p_compare_geometric_uv(const void *a, const void *b)
return 1;
}
-static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right)
+static bool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts, int *r_right)
{
/* Graham algorithm, taken from:
* http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */
@@ -3579,10 +3465,10 @@ static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts,
int npoints = 0, i, ulen, llen;
PVert **U, **L, **points, **p;
- p_chart_boundaries(chart, NULL, &be);
+ p_chart_boundaries(chart, &be);
if (!be) {
- return P_FALSE;
+ return false;
}
e = be;
@@ -3636,7 +3522,7 @@ static PBool p_chart_convex_hull(PChart *chart, PVert ***r_verts, int *r_nverts,
MEM_freeN(U);
MEM_freeN(L);
- return P_TRUE;
+ return true;
}
static float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4)
@@ -3819,545 +3705,6 @@ static void p_chart_rotate_fit_aabb(PChart *chart)
}
}
-/* Area Smoothing */
-
-/* 2d BSP tree for inverse mapping - that's a bit silly. */
-
-typedef struct SmoothTriangle {
- float co1[2], co2[2], co3[2];
- float oco1[2], oco2[2], oco3[2];
-} SmoothTriangle;
-
-typedef struct SmoothNode {
- struct SmoothNode *c1, *c2;
- SmoothTriangle **tri;
- float split;
- int axis, ntri;
-} SmoothNode;
-
-static void p_barycentric_2d(
- const float v1[2], const float v2[2], const float v3[2], const float p[2], float b[3])
-{
- float a[2], c[2], h[2], div;
-
- a[0] = v2[0] - v1[0];
- a[1] = v2[1] - v1[1];
- c[0] = v3[0] - v1[0];
- c[1] = v3[1] - v1[1];
-
- div = a[0] * c[1] - a[1] * c[0];
-
- if (div == 0.0f) {
- b[0] = 1.0f / 3.0f;
- b[1] = 1.0f / 3.0f;
- b[2] = 1.0f / 3.0f;
- }
- else {
- h[0] = p[0] - v1[0];
- h[1] = p[1] - v1[1];
-
- div = 1.0f / div;
-
- b[1] = (h[0] * c[1] - h[1] * c[0]) * div;
- b[2] = (a[0] * h[1] - a[1] * h[0]) * div;
- b[0] = 1.0f - b[1] - b[2];
- }
-}
-
-static PBool p_triangle_inside(SmoothTriangle *t, float co[2])
-{
- float b[3];
-
- p_barycentric_2d(t->co1, t->co2, t->co3, co, b);
-
- if ((b[0] >= 0.0f) && (b[1] >= 0.0f) && (b[2] >= 0.0f)) {
- co[0] = t->oco1[0] * b[0] + t->oco2[0] * b[1] + t->oco3[0] * b[2];
- co[1] = t->oco1[1] * b[0] + t->oco2[1] * b[1] + t->oco3[1] * b[2];
- return P_TRUE;
- }
-
- return P_FALSE;
-}
-
-static SmoothNode *p_node_new(
- MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
-{
- SmoothNode *node = BLI_memarena_alloc(arena, sizeof(*node));
- int axis, i, t1size = 0, t2size = 0;
- float split, /* mi, */ /* UNUSED */ mx;
- SmoothTriangle **t1, **t2, *t;
-
- node->tri = tri;
- node->ntri = ntri;
-
- if (ntri <= 10 || depth >= 15) {
- return node;
- }
-
- t1 = MEM_mallocN(sizeof(*t1) * ntri, "PNodeTri1");
- t2 = MEM_mallocN(sizeof(*t2) * ntri, "PNodeTri1");
-
- axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1]) ? 0 : 1;
- split = 0.5f * (bmin[axis] + bmax[axis]);
-
- for (i = 0; i < ntri; i++) {
- t = tri[i];
-
- if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) {
- t1[t1size] = t;
- t1size++;
- }
- if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) {
- t2[t2size] = t;
- t2size++;
- }
- }
-
- if ((t1size == t2size) && (t1size == ntri)) {
- MEM_freeN(t1);
- MEM_freeN(t2);
- return node;
- }
-
- node->tri = NULL;
- node->ntri = 0;
- MEM_freeN(tri);
-
- node->axis = axis;
- node->split = split;
-
- /* mi = bmin[axis]; */ /* UNUSED */
- mx = bmax[axis];
- bmax[axis] = split;
- node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth + 1);
-
- bmin[axis] = bmax[axis];
- bmax[axis] = mx;
- node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth + 1);
-
- return node;
-}
-
-static void p_node_delete(SmoothNode *node)
-{
- if (node->c1) {
- p_node_delete(node->c1);
- }
- if (node->c2) {
- p_node_delete(node->c2);
- }
- if (node->tri) {
- MEM_freeN(node->tri);
- }
-}
-
-static PBool p_node_intersect(SmoothNode *node, float co[2])
-{
- int i;
-
- if (node->tri) {
- for (i = 0; i < node->ntri; i++) {
- if (p_triangle_inside(node->tri[i], co)) {
- return P_TRUE;
- }
- }
-
- return P_FALSE;
- }
-
- if (co[node->axis] < node->split) {
- return p_node_intersect(node->c1, co);
- }
- return p_node_intersect(node->c2, co);
-}
-
-/* smoothing */
-
-static int p_compare_float(const void *a_, const void *b_)
-{
- const float a = *(const float *)a_;
- const float b = *(const float *)b_;
-
- if (a < b) {
- return -1;
- }
- if (a == b) {
- return 0;
- }
- return 1;
-}
-
-static float p_smooth_median_edge_length(PChart *chart)
-{
- PEdge *e;
- float *lengths = MEM_mallocN(sizeof(chart->edges) * chart->nedges, "PMedianLength");
- float median;
- int i;
-
- /* ok, so I'm lazy */
- for (i = 0, e = chart->edges; e; e = e->nextlink, i++) {
- lengths[i] = p_edge_length(e);
- }
-
- qsort(lengths, i, sizeof(float), p_compare_float);
-
- median = lengths[i / 2];
- MEM_freeN(lengths);
-
- return median;
-}
-
-static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d)
-{
- float len2d = p_edge_uv_length(e) * avg3d;
- float len3d = p_edge_length(e) * avg2d;
-
- return (len3d == 0.0f) ? 0.0f : len2d / len3d;
-}
-
-static void p_smooth(PChart *chart)
-{
- PEdge *e;
- PVert *v;
- PFace *f;
- int j, it2, maxiter2, it;
- int nedges = chart->nedges, nwheel, gridx, gridy;
- int edgesx, edgesy, nsize, esize, i, x, y, maxiter;
- float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d;
- float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy;
- float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding;
- SmoothTriangle *triangles, *t, *t2, **tri, **trip;
- SmoothNode *root;
- MemArena *arena;
-
- if (nedges == 0) {
- return;
- }
-
- p_chart_uv_bbox(chart, minv, maxv);
- median = p_smooth_median_edge_length(chart) * 0.10f;
-
- if (median == 0.0f) {
- return;
- }
-
- invmedian = 1.0f / median;
-
- /* compute edge distortion */
- avglen2d = avglen3d = 0.0;
-
- for (e = chart->edges; e; e = e->nextlink) {
- avglen2d += p_edge_uv_length(e);
- avglen3d += p_edge_length(e);
- }
-
- avglen2d /= nedges;
- avglen3d /= nedges;
-
- for (v = chart->verts; v; v = v->nextlink) {
- v->u.distortion = 0.0;
- nwheel = 0;
-
- e = v->edge;
- do {
- v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d);
- nwheel++;
-
- e = e->next->next->pair;
- } while (e && (e != v->edge));
-
- v->u.distortion /= nwheel;
- }
-
- /* need to do excessive grid size checking still */
- center[0] = 0.5f * (minv[0] + maxv[0]);
- center[1] = 0.5f * (minv[1] + maxv[1]);
-
- dx = 0.5f * (maxv[0] - minv[0]);
- dy = 0.5f * (maxv[1] - minv[1]);
-
- padding = 0.15f;
- dx += padding * dx + 2.0f * median;
- dy += padding * dy + 2.0f * median;
-
- gridx = (int)(dx * invmedian);
- gridy = (int)(dy * invmedian);
-
- minv[0] = center[0] - median * gridx;
- minv[1] = center[1] - median * gridy;
- maxv[0] = center[0] + median * gridx;
- maxv[1] = center[1] + median * gridy;
-
- /* create grid */
- gridx = gridx * 2 + 1;
- gridy = gridy * 2 + 1;
-
- if ((gridx <= 2) || (gridy <= 2)) {
- return;
- }
-
- edgesx = gridx - 1;
- edgesy = gridy - 1;
- nsize = gridx * gridy;
- esize = edgesx * edgesy;
-
- nodes = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodes");
- nodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesX");
- nodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothNodesY");
- oldnodesx = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesX");
- oldnodesy = MEM_mallocN(sizeof(float) * nsize, "PSmoothOldNodesY");
- hedges = MEM_mallocN(sizeof(float) * esize, "PSmoothHEdges");
- vedges = MEM_mallocN(sizeof(float) * esize, "PSmoothVEdges");
-
- if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) {
- if (nodes) {
- MEM_freeN(nodes);
- }
- if (nodesx) {
- MEM_freeN(nodesx);
- }
- if (nodesy) {
- MEM_freeN(nodesy);
- }
- if (oldnodesx) {
- MEM_freeN(oldnodesx);
- }
- if (oldnodesy) {
- MEM_freeN(oldnodesy);
- }
- if (hedges) {
- MEM_freeN(hedges);
- }
- if (vedges) {
- MEM_freeN(vedges);
- }
-
- // printf("Not enough memory for area smoothing grid");
- return;
- }
-
- for (x = 0; x < gridx; x++) {
- for (y = 0; y < gridy; y++) {
- i = x + y * gridx;
-
- nodesx[i] = minv[0] + median * x;
- nodesy[i] = minv[1] + median * y;
-
- nodes[i] = 1.0f;
- }
- }
-
- /* embed in grid */
- for (f = chart->faces; f; f = f->nextlink) {
- PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
- float fmin[2], fmax[2];
- int bx1, by1, bx2, by2;
-
- INIT_MINMAX2(fmin, fmax);
-
- minmax_v2v2_v2(fmin, fmax, e1->vert->uv);
- minmax_v2v2_v2(fmin, fmax, e2->vert->uv);
- minmax_v2v2_v2(fmin, fmax, e3->vert->uv);
-
- bx1 = (int)((fmin[0] - minv[0]) * invmedian);
- by1 = (int)((fmin[1] - minv[1]) * invmedian);
- bx2 = (int)((fmax[0] - minv[0]) * invmedian + 2);
- by2 = (int)((fmax[1] - minv[1]) * invmedian + 2);
-
- for (x = bx1; x < bx2; x++) {
- for (y = by1; y < by2; y++) {
- float p[2], b[3];
-
- i = x + y * gridx;
-
- p[0] = nodesx[i];
- p[1] = nodesy[i];
-
- p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b);
-
- if ((b[0] > 0.0f) && (b[1] > 0.0f) && (b[2] > 0.0f)) {
- nodes[i] = e1->vert->u.distortion * b[0];
- nodes[i] += e2->vert->u.distortion * b[1];
- nodes[i] += e3->vert->u.distortion * b[2];
- }
- }
- }
- }
-
- /* smooth the grid */
- maxiter = 10;
- climit = 0.00001f * nsize;
-
- for (it = 0; it < maxiter; it++) {
- moved = 0.0f;
-
- for (x = 0; x < edgesx; x++) {
- for (y = 0; y < edgesy; y++) {
- i = x + y * gridx;
- j = x + y * edgesx;
-
- hedges[j] = (nodes[i] + nodes[i + 1]) * 0.5f;
- vedges[j] = (nodes[i] + nodes[i + gridx]) * 0.5f;
-
- /* we do *inverse* mapping */
- hedges[j] = 1.0f / hedges[j];
- vedges[j] = 1.0f / vedges[j];
- }
- }
-
- maxiter2 = 50;
- dlimit = 0.0001f;
-
- for (it2 = 0; it2 < maxiter2; it2++) {
- d = 0.0f;
-
- memcpy(oldnodesx, nodesx, sizeof(float) * nsize);
- memcpy(oldnodesy, nodesy, sizeof(float) * nsize);
-
- for (x = 1; x < gridx - 1; x++) {
- for (y = 1; y < gridy - 1; y++) {
- float p[2], oldp[2], sum1, sum2, diff[2], length;
-
- i = x + gridx * y;
- j = x + edgesx * y;
-
- oldp[0] = oldnodesx[i];
- oldp[1] = oldnodesy[i];
-
- sum1 = hedges[j - 1] * oldnodesx[i - 1];
- sum1 += hedges[j] * oldnodesx[i + 1];
- sum1 += vedges[j - edgesx] * oldnodesx[i - gridx];
- sum1 += vedges[j] * oldnodesx[i + gridx];
-
- sum2 = hedges[j - 1];
- sum2 += hedges[j];
- sum2 += vedges[j - edgesx];
- sum2 += vedges[j];
-
- nodesx[i] = sum1 / sum2;
-
- sum1 = hedges[j - 1] * oldnodesy[i - 1];
- sum1 += hedges[j] * oldnodesy[i + 1];
- sum1 += vedges[j - edgesx] * oldnodesy[i - gridx];
- sum1 += vedges[j] * oldnodesy[i + gridx];
-
- nodesy[i] = sum1 / sum2;
-
- p[0] = nodesx[i];
- p[1] = nodesy[i];
-
- diff[0] = p[0] - oldp[0];
- diff[1] = p[1] - oldp[1];
-
- length = len_v2(diff);
- d = max_ff(d, length);
- moved += length;
- }
- }
-
- if (d < dlimit) {
- break;
- }
- }
-
- if (moved < climit) {
- break;
- }
- }
-
- MEM_freeN(oldnodesx);
- MEM_freeN(oldnodesy);
- MEM_freeN(hedges);
- MEM_freeN(vedges);
-
- /* Create BSP. */
- t = triangles = MEM_mallocN(sizeof(SmoothTriangle) * esize * 2, "PSmoothTris");
- trip = tri = MEM_mallocN(sizeof(SmoothTriangle *) * esize * 2, "PSmoothTriP");
-
- if (!triangles || !tri) {
- MEM_freeN(nodes);
- MEM_freeN(nodesx);
- MEM_freeN(nodesy);
-
- if (triangles) {
- MEM_freeN(triangles);
- }
- if (tri) {
- MEM_freeN(tri);
- }
-
- // printf("Not enough memory for area smoothing grid");
- return;
- }
-
- for (x = 0; x < edgesx; x++) {
- for (y = 0; y < edgesy; y++) {
- i = x + y * gridx;
-
- t->co1[0] = nodesx[i];
- t->co1[1] = nodesy[i];
-
- t->co2[0] = nodesx[i + 1];
- t->co2[1] = nodesy[i + 1];
-
- t->co3[0] = nodesx[i + gridx];
- t->co3[1] = nodesy[i + gridx];
-
- t->oco1[0] = minv[0] + x * median;
- t->oco1[1] = minv[1] + y * median;
-
- t->oco2[0] = minv[0] + (x + 1) * median;
- t->oco2[1] = minv[1] + y * median;
-
- t->oco3[0] = minv[0] + x * median;
- t->oco3[1] = minv[1] + (y + 1) * median;
-
- t2 = t + 1;
-
- t2->co1[0] = nodesx[i + gridx + 1];
- t2->co1[1] = nodesy[i + gridx + 1];
-
- t2->oco1[0] = minv[0] + (x + 1) * median;
- t2->oco1[1] = minv[1] + (y + 1) * median;
-
- t2->co2[0] = t->co2[0];
- t2->co2[1] = t->co2[1];
- t2->oco2[0] = t->oco2[0];
- t2->oco2[1] = t->oco2[1];
-
- t2->co3[0] = t->co3[0];
- t2->co3[1] = t->co3[1];
- t2->oco3[0] = t->oco3[0];
- t2->oco3[1] = t->oco3[1];
-
- *trip = t;
- trip++;
- t++;
- *trip = t;
- trip++;
- t++;
- }
- }
-
- MEM_freeN(nodes);
- MEM_freeN(nodesx);
- MEM_freeN(nodesy);
-
- arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "param smooth arena");
- root = p_node_new(arena, tri, esize * 2, minv, maxv, 0);
-
- for (v = chart->verts; v; v = v->nextlink) {
- if (!p_node_intersect(root, v->uv)) {
- param_warning("area smoothing error: couldn't find mapping triangle\n");
- }
- }
-
- p_node_delete(root);
- BLI_memarena_free(arena);
-
- MEM_freeN(triangles);
-}
-
/* Exported */
ParamHandle *GEO_uv_parametrizer_construct_begin(void)
@@ -4370,7 +3717,6 @@ ParamHandle *GEO_uv_parametrizer_construct_begin(void)
handle->polyfill_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
handle->aspx = 1.0f;
handle->aspy = 1.0f;
- handle->do_aspect = false;
handle->hash_verts = phash_new((PHashLink **)&handle->construction_chart->verts, 1);
handle->hash_edges = phash_new((PHashLink **)&handle->construction_chart->edges, 1);
@@ -4383,7 +3729,6 @@ void GEO_uv_parametrizer_aspect_ratio(ParamHandle *phandle, float aspx, float as
{
phandle->aspx = aspx;
phandle->aspy = aspy;
- phandle->do_aspect = true;
}
void GEO_uv_parametrizer_delete(ParamHandle *phandle)
@@ -4396,8 +3741,11 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle)
p_chart_delete(phandle->charts[i]);
}
- if (phandle->charts) {
- MEM_freeN(phandle->charts);
+ MEM_SAFE_FREE(phandle->charts);
+
+ if (phandle->pin_hash) {
+ BLI_ghash_free(phandle->pin_hash, NULL, NULL);
+ phandle->pin_hash = NULL;
}
if (phandle->construction_chart) {
@@ -4414,14 +3762,88 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle)
MEM_freeN(phandle);
}
+typedef struct GeoUVPinIndex {
+ struct GeoUVPinIndex *next;
+ float uv[2];
+ ParamKey reindex;
+} GeoUVPinIndex;
+
+/* Find a (mostly) unique ParamKey given a BMVert index and UV co-ordinates.
+ * For each unique pinned UVs, return a unique ParamKey, starting with
+ * a very large number, and decreasing steadily from there.
+ * For non-pinned UVs which share a BMVert with a pinned UV,
+ * return the index corresponding to the closest pinned UV.
+ * For everything else, just return the BMVert index.
+ * Note that ParamKeys will eventually be hashed, so they don't need to be contiguous.
+ */
+ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
+{
+ if (!handle->pin_hash) {
+ return bmvertindex; /* No verts pinned. */
+ }
+
+ GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex));
+ if (!pinuvlist) {
+ return bmvertindex; /* Vert not pinned. */
+ }
+
+ /* At least one of the UVs associated with bmvertindex is pinned. Find the best one. */
+ float bestdistsquared = len_squared_v2v2(pinuvlist->uv, uv);
+ ParamKey bestkey = pinuvlist->reindex;
+ pinuvlist = pinuvlist->next;
+ while (pinuvlist) {
+ const float distsquared = len_squared_v2v2(pinuvlist->uv, uv);
+ if (bestdistsquared > distsquared) {
+ bestdistsquared = distsquared;
+ bestkey = pinuvlist->reindex;
+ }
+ pinuvlist = pinuvlist->next;
+ }
+ return bestkey;
+}
+
+static GeoUVPinIndex *new_geo_uv_pinindex(ParamHandle *handle, const float uv[2])
+{
+ GeoUVPinIndex *pinuv = BLI_memarena_alloc(handle->arena, sizeof(*pinuv));
+ pinuv->next = NULL;
+ copy_v2_v2(pinuv->uv, uv);
+ pinuv->reindex = PARAM_KEY_MAX - (handle->unique_pin_count++);
+ return pinuv;
+}
+
+void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
+{
+ if (!handle->pin_hash) {
+ handle->pin_hash = BLI_ghash_int_new("uv pin reindex");
+ }
+
+ GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, POINTER_FROM_INT(bmvertindex));
+ if (!pinuvlist) {
+ BLI_ghash_insert(
+ handle->pin_hash, POINTER_FROM_INT(bmvertindex), new_geo_uv_pinindex(handle, uv));
+ return;
+ }
+
+ while (true) {
+ if (equals_v2v2(pinuvlist->uv, uv)) {
+ return;
+ }
+ if (!pinuvlist->next) {
+ pinuvlist->next = new_geo_uv_pinindex(handle, uv);
+ return;
+ }
+ pinuvlist = pinuvlist->next;
+ }
+}
+
static void p_add_ngon(ParamHandle *handle,
- ParamKey key,
- int nverts,
- ParamKey *vkeys,
- float **co,
- float **uv,
- ParamBool *pin,
- ParamBool *select)
+ const ParamKey key,
+ const int nverts,
+ const ParamKey *vkeys,
+ const float **co,
+ float **uv, /* Output will eventually be written to `uv`. */
+ const bool *pin,
+ const bool *select)
{
/* Allocate memory for polyfill. */
MemArena *arena = handle->polyfill_arena;
@@ -4463,11 +3885,11 @@ static void p_add_ngon(ParamHandle *handle,
uint v1 = tri[1];
uint v2 = tri[2];
- ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
- float *tri_co[3] = {co[v0], co[v1], co[v2]};
+ const ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
+ const float *tri_co[3] = {co[v0], co[v1], co[v2]};
float *tri_uv[3] = {uv[v0], uv[v1], uv[v2]};
- ParamBool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
- ParamBool tri_select[3] = {select[v0], select[v1], select[v2]};
+ bool tri_pin[3] = {pin[v0], pin[v1], pin[v2]};
+ bool tri_select[3] = {select[v0], select[v1], select[v2]};
GEO_uv_parametrizer_face_add(handle, key, 3, tri_vkeys, tri_co, tri_uv, tri_pin, tri_select);
}
@@ -4476,13 +3898,13 @@ static void p_add_ngon(ParamHandle *handle,
}
void GEO_uv_parametrizer_face_add(ParamHandle *phandle,
- ParamKey key,
- int nverts,
- ParamKey *vkeys,
- float *co[4],
- float *uv[4],
- ParamBool *pin,
- ParamBool *select)
+ const ParamKey key,
+ const int nverts,
+ const ParamKey *vkeys,
+ const float **co,
+ float **uv,
+ const bool *pin,
+ const bool *select)
{
param_assert(phash_lookup(phandle->hash_faces, key) == NULL);
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
@@ -4522,17 +3944,17 @@ void GEO_uv_parametrizer_edge_set_seam(ParamHandle *phandle, ParamKey *vkeys)
}
void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
- ParamBool fill,
- ParamBool topology_from_uvs,
+ bool fill,
+ bool topology_from_uvs,
int *count_fail)
{
PChart *chart = phandle->construction_chart;
- int i, j, nboundaries = 0;
+ int i, j;
PEdge *outer;
param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
- phandle->ncharts = p_connect_pairs(phandle, (PBool)topology_from_uvs);
+ phandle->ncharts = p_connect_pairs(phandle, topology_from_uvs);
phandle->charts = p_split_charts(phandle, chart, phandle->ncharts);
p_chart_delete(phandle->construction_chart);
@@ -4547,9 +3969,9 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
PVert *v;
chart = phandle->charts[i];
- p_chart_boundaries(chart, &nboundaries, &outer);
+ p_chart_boundaries(chart, &outer);
- if (!topology_from_uvs && nboundaries == 0) {
+ if (!topology_from_uvs && chart->nboundaries == 0) {
p_chart_delete(chart);
if (count_fail != NULL) {
*count_fail += 1;
@@ -4560,7 +3982,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
phandle->charts[j] = chart;
j++;
- if (fill && (nboundaries > 1)) {
+ if (fill && (chart->nboundaries > 1)) {
p_chart_fill_boundaries(chart, outer);
}
@@ -4574,7 +3996,7 @@ void GEO_uv_parametrizer_construct_end(ParamHandle *phandle,
phandle->state = PHANDLE_STATE_CONSTRUCTED;
}
-void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, ParamBool live, ParamBool abf)
+void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, bool live, bool abf)
{
PFace *f;
int i;
@@ -4586,7 +4008,7 @@ void GEO_uv_parametrizer_lscm_begin(ParamHandle *phandle, ParamBool live, ParamB
for (f = phandle->charts[i]->faces; f; f = f->nextlink) {
p_face_backup_uvs(f);
}
- p_chart_lscm_begin(phandle->charts[i], (PBool)live, (PBool)abf);
+ p_chart_lscm_begin(phandle->charts[i], live, abf);
}
}
@@ -4601,7 +4023,7 @@ void GEO_uv_parametrizer_lscm_solve(ParamHandle *phandle, int *count_changed, in
chart = phandle->charts[i];
if (chart->u.lscm.context) {
- const PBool result = p_chart_lscm_solve(phandle, chart);
+ const bool result = p_chart_lscm_solve(phandle, chart);
if (result && !(chart->flag & PCHART_HAS_PINS)) {
p_chart_rotate_minimum_area(chart);
@@ -4702,24 +4124,6 @@ void GEO_uv_parametrizer_stretch_end(ParamHandle *phandle)
phandle->rng = NULL;
}
-void GEO_uv_parametrizer_smooth_area(ParamHandle *phandle)
-{
- int i;
-
- param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
-
- for (i = 0; i < phandle->ncharts; i++) {
- PChart *chart = phandle->charts[i];
- PVert *v;
-
- for (v = chart->verts; v; v = v->nextlink) {
- v->flag &= ~PVERT_PIN;
- }
-
- p_smooth(chart);
- }
-}
-
/* don't pack, just rotate (used for better packing) */
static void GEO_uv_parametrizer_pack_rotate(ParamHandle *phandle, bool ignore_pinned)
{
@@ -4842,7 +4246,10 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
}
}
-void GEO_uv_parametrizer_average(ParamHandle *phandle, bool ignore_pinned)
+void GEO_uv_parametrizer_average(ParamHandle *phandle,
+ bool ignore_pinned,
+ bool scale_uv,
+ bool shear)
{
PChart *chart;
int i;
@@ -4855,17 +4262,93 @@ void GEO_uv_parametrizer_average(ParamHandle *phandle, bool ignore_pinned)
}
for (i = 0; i < phandle->ncharts; i++) {
- PFace *f;
chart = phandle->charts[i];
if (ignore_pinned && (chart->flag & PCHART_HAS_PINS)) {
continue;
}
+ p_chart_uv_bbox(chart, minv, maxv);
+ mid_v2_v2v2(chart->u.pack.origin, minv, maxv);
+
+ if (scale_uv || shear) {
+ /* It's possible that for some "bad" inputs, the following iteration will converge slowly or
+ * perhaps even diverge. Rather than infinite loop, we only iterate a maximum of `max_iter`
+ * times. (Also useful when making changes to the calculation.) */
+ int max_iter = 10;
+ for (int j = 0; j < max_iter; j++) {
+ /* An island could contain millions of polygons. When summing many small values, we need to
+ * use double precision in the accumulator to maintain accuracy. Note that the individual
+ * calculations only need to be at single precision.*/
+ double scale_cou = 0;
+ double scale_cov = 0;
+ double scale_cross = 0;
+ double weight_sum = 0;
+ for (PFace *f = chart->faces; f; f = f->nextlink) {
+ float m[2][2], s[2][2];
+ PVert *va = f->edge->vert;
+ PVert *vb = f->edge->next->vert;
+ PVert *vc = f->edge->next->next->vert;
+ s[0][0] = va->uv[0] - vc->uv[0];
+ s[0][1] = va->uv[1] - vc->uv[1];
+ s[1][0] = vb->uv[0] - vc->uv[0];
+ s[1][1] = vb->uv[1] - vc->uv[1];
+ /* Find the "U" axis and "V" axis in triangle co-ordinates. Normally this would require
+ * SVD, but in 2D we can use a cheaper matrix inversion instead.*/
+ if (!invert_m2_m2(m, s)) {
+ continue;
+ }
+ float cou[3], cov[3]; /* i.e. Texture "U" and texture "V" in 3D co-ordinates.*/
+ for (int k = 0; k < 3; k++) {
+ cou[k] = m[0][0] * (va->co[k] - vc->co[k]) + m[0][1] * (vb->co[k] - vc->co[k]);
+ cov[k] = m[1][0] * (va->co[k] - vc->co[k]) + m[1][1] * (vb->co[k] - vc->co[k]);
+ }
+ const float weight = p_face_area(f);
+ scale_cou += len_v3(cou) * weight;
+ scale_cov += len_v3(cov) * weight;
+ if (shear) {
+ normalize_v3(cov);
+ normalize_v3(cou);
+
+ /* Why is scale_cross called `cross` when we call `dot`? The next line calculates:
+ * `scale_cross += length(cross(cross(cou, face_normal), cov))`
+ * By construction, both `cou` and `cov` are orthogonal to the face normal.
+ * By definition, the normal vector has unit length. */
+ scale_cross += dot_v3v3(cou, cov) * weight;
+ }
+ weight_sum += weight;
+ }
+ if (scale_cou * scale_cov < 1e-10f) {
+ break;
+ }
+ const float scale_factor_u = scale_uv ? sqrtf(scale_cou / scale_cov) : 1.0f;
+
+ /* Compute correction transform. */
+ float t[2][2];
+ t[0][0] = scale_factor_u;
+ t[1][0] = clamp_f((float)(scale_cross / weight_sum), -0.5f, 0.5f);
+ t[0][1] = 0;
+ t[1][1] = 1.0f / scale_factor_u;
+
+ /* Apply the correction. */
+ p_chart_uv_transform(chart, t);
+
+ /* How far from the identity transform are we? [[1,0],[0,1]] */
+ const float err = fabsf(t[0][0] - 1.0f) + fabsf(t[1][0]) + fabsf(t[0][1]) +
+ fabsf(t[1][1] - 1.0f);
+
+ const float tolerance = 1e-6f; /* Trade accuracy for performance. */
+ if (err < tolerance) {
+ /* Too slow? Use Richardson Extrapolation to accelerate the convergence.*/
+ break;
+ }
+ }
+ }
+
chart->u.pack.area = 0.0f; /* 3d area */
chart->u.pack.rescale = 0.0f; /* UV area, abusing rescale for tmp storage, oh well :/ */
- for (f = chart->faces; f; f = f->nextlink) {
+ for (PFace *f = chart->faces; f; f = f->nextlink) {
chart->u.pack.area += p_face_area(f);
chart->u.pack.rescale += fabsf(p_face_uv_area_signed(f));
}
@@ -4891,18 +4374,16 @@ void GEO_uv_parametrizer_average(ParamHandle *phandle, bool ignore_pinned)
if (chart->u.pack.area != 0.0f && chart->u.pack.rescale != 0.0f) {
fac = chart->u.pack.area / chart->u.pack.rescale;
- /* Get the island center */
- p_chart_uv_bbox(chart, minv, maxv);
- trans[0] = (minv[0] + maxv[0]) / -2.0f;
- trans[1] = (minv[1] + maxv[1]) / -2.0f;
-
- /* Move center to 0,0 */
- p_chart_uv_translate(chart, trans);
+ /* Average scale. */
p_chart_uv_scale(chart, sqrtf(fac / tot_fac));
- /* Move to original center */
- trans[0] = -trans[0];
- trans[1] = -trans[1];
+ /* Get the current island center. */
+ p_chart_uv_bbox(chart, minv, maxv);
+
+ /* Move to original center. */
+ mid_v2_v2v2(trans, minv, maxv);
+ negate_v2(trans);
+ add_v2_v2(trans, chart->u.pack.origin);
p_chart_uv_translate(chart, trans);
}
}
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 69fc26c99e9..947fc32f8c0 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRC
intern/lineart/lineart_cpp_bridge.cc
intern/lineart/lineart_cpu.c
intern/lineart/lineart_ops.c
+ intern/lineart/lineart_shadow.c
intern/lineart/lineart_util.c
intern/lineart/MOD_lineart.h
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index 6cf7f6f11e5..bd8fd9f72ad 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -7,7 +7,7 @@
#include <stdio.h>
-#include "BLI_blenlib.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
@@ -182,7 +182,7 @@ void generic_bake_deform_stroke(
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
if (retime) {
- CFRA = gpf->framenum;
+ scene->r.cfra = gpf->framenum;
BKE_scene_graph_update_for_newframe(depsgraph);
}
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
@@ -193,7 +193,7 @@ void generic_bake_deform_stroke(
/* Return frame state and DB to original state. */
if (retime) {
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index e7301b4d910..73423d9a8ee 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -49,5 +49,5 @@ typedef void (*gpBakeCb)(struct GpencilModifierData *md_,
void generic_bake_deform_stroke(struct Depsgraph *depsgraph,
struct GpencilModifierData *md,
struct Object *ob,
- const bool retime,
+ bool retime,
gpBakeCb bake_cb);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
index f5ecce69129..092253dde79 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c
@@ -8,10 +8,9 @@
#include <stdio.h>
#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
index 38866bcd32a..407055c6165 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c
@@ -9,14 +9,11 @@
#include "MEM_guardedalloc.h"
-#include "BLI_utildefines.h"
-
#include "BLI_hash.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_rand.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
index 88515d849bc..cf390e8d3a0 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c
@@ -7,14 +7,15 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
-#include "BLI_utildefines.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vector.h"
#include "BLI_sort.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
index 792def30812..8ada66cfd55 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c
@@ -9,7 +9,6 @@
#include "BLI_utildefines.h"
-#include "BLI_blenlib.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index e57b9df03f5..41015c429fe 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -9,11 +9,9 @@
#include <string.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_string.h"
-#include "BLT_translation.h"
-
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
index e5604005240..0f1652a5620 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
@@ -8,8 +8,8 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_math_geom.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -22,7 +22,6 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
index bc0464cb4f9..652894af017 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c
@@ -6,12 +6,14 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_math_matrix.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BLI_math.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
index 96e649bf7a1..30f1a004338 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c
@@ -129,7 +129,7 @@ static void bakeModifier(Main *UNUSED(bmain),
/* Apply lattice effects on this frame
* NOTE: this assumes that we don't want lattice animation on non-keyframed frames.
*/
- CFRA = gpf->framenum;
+ scene->r.cfra = gpf->framenum;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Recalculate lattice data. */
@@ -153,7 +153,7 @@ static void bakeModifier(Main *UNUSED(bmain),
}
/* Return frame state and DB to original state. */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
index c92c062348c..5a358f5b3a1 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c
@@ -6,10 +6,11 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_hash.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_base.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
index a07ef2eb195..77616ae13b6 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c
@@ -7,9 +7,8 @@
#include <stdio.h>
-#include "BLI_utildefines.h"
-
#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -22,9 +21,6 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "MOD_gpencil_lineart.h"
-#include "lineart/MOD_lineart.h"
-
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -43,8 +39,10 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+#include "MOD_gpencil_lineart.h"
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_ui_common.h"
+#include "lineart/MOD_lineart.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -90,6 +88,8 @@ static void generate_strokes_actual(
lmd->intersection_mask,
lmd->thickness,
lmd->opacity,
+ lmd->shadow_selection,
+ lmd->silhouette_selection,
lmd->source_vertex_group,
lmd->vgname,
lmd->flags);
@@ -195,6 +195,7 @@ static void bakeModifier(Main *UNUSED(bmain),
* modifiers in the stack. */
lmd->edge_types_override = lmd->edge_types;
lmd->level_end_override = lmd->level_end;
+ lmd->shadow_selection_override = lmd->shadow_selection;
MOD_lineart_compute_feature_lines(
depsgraph, lmd, &gpd->runtime.lineart_cache, (!(ob->dtx & OB_DRAW_IN_FRONT)));
@@ -265,6 +266,10 @@ static void updateDepsgraph(GpencilModifierData *md,
DEG_add_object_relation(
ctx->node, ctx->scene->camera, DEG_OB_COMP_PARAMETERS, "Line Art Modifier");
}
+ if (lmd->light_contour_object) {
+ DEG_add_object_relation(
+ ctx->node, lmd->light_contour_object, DEG_OB_COMP_TRANSFORM, "Line Art Modifier");
+ }
}
static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
@@ -276,6 +281,7 @@ static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk,
walk(userData, ob, (ID **)&lmd->source_object, IDWALK_CB_NOP);
walk(userData, ob, (ID **)&lmd->source_camera, IDWALK_CB_NOP);
+ walk(userData, ob, (ID **)&lmd->light_contour_object, IDWALK_CB_NOP);
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -326,6 +332,10 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemPointerR(
row, ptr, "target_material", &obj_data_ptr, "materials", NULL, ICON_SHADING_TEXTURE);
+ uiLayout *col = uiLayoutColumn(layout, false);
+ uiItemR(col, ptr, "thickness", UI_ITEM_R_SLIDER, IFACE_("Line Thickness"), ICON_NONE);
+ uiItemR(col, ptr, "opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+
gpencil_modifier_panel_end(layout, ptr);
}
@@ -338,31 +348,107 @@ static void edge_types_panel_draw(const bContext *UNUSED(C), Panel *panel)
const bool is_baked = RNA_boolean_get(ptr, "is_baked");
const bool use_cache = RNA_boolean_get(ptr, "use_cache");
const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
+ const bool has_light = RNA_pointer_get(ptr, "light_contour_object").data != NULL;
uiLayoutSetEnabled(layout, !is_baked);
uiLayoutSetPropSep(layout, true);
+ uiLayout *sub = uiLayoutRow(layout, false);
+ uiLayoutSetActive(sub, has_light);
+ uiItemR(sub, ptr, "shadow_region_filtering", 0, IFACE_("Illumination Filtering"), ICON_NONE);
+
uiLayout *col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_contour", 0, IFACE_("Contour"), ICON_NONE);
- uiItemR(col, ptr, "use_loose", 0, IFACE_("Loose"), ICON_NONE);
+ sub = uiLayoutRowWithHeading(col, false, IFACE_("Create"));
+ uiItemR(sub, ptr, "use_contour", 0, "", ICON_NONE);
+
+ uiLayout *entry = uiLayoutRow(sub, true);
+ uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_contour"));
+ uiItemR(entry, ptr, "silhouette_filtering", 0, "", ICON_NONE);
+
+ const int silhouette_filtering = RNA_enum_get(ptr, "silhouette_filtering");
+ if (silhouette_filtering != LRT_SILHOUETTE_FILTER_NONE) {
+ uiItemR(entry, ptr, "use_invert_silhouette", 0, "", ICON_ARROW_LEFTRIGHT);
+ }
+
+ sub = uiLayoutRow(col, false);
+ uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
+ entry = uiLayoutColumn(sub, false);
+ uiItemL(entry, IFACE_("Crease"), ICON_NONE);
+ uiLayoutSetActive(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
+ if (use_cache && !is_first) {
+ uiItemL(entry, IFACE_("Crease Angle Cached"), ICON_INFO);
+ }
+ else {
+ uiItemR(entry,
+ ptr,
+ "crease_threshold",
+ UI_ITEM_R_SLIDER | UI_ITEM_R_FORCE_BLANK_DECORATE,
+ IFACE_("Default Angle"),
+ ICON_NONE);
+ }
+
+ uiItemR(col, ptr, "use_intersection", 0, IFACE_("Intersections"), ICON_NONE);
uiItemR(col, ptr, "use_material", 0, IFACE_("Material Borders"), ICON_NONE);
uiItemR(col, ptr, "use_edge_mark", 0, IFACE_("Edge Marks"), ICON_NONE);
- uiItemR(col, ptr, "use_intersection", 0, IFACE_("Intersections"), ICON_NONE);
+ uiItemR(col, ptr, "use_loose", 0, IFACE_("Loose"), ICON_NONE);
- uiLayout *sub = uiLayoutRowWithHeading(col, false, IFACE_("Crease"));
- uiItemR(sub, ptr, "use_crease", 0, "", ICON_NONE);
- uiLayout *entry = uiLayoutRow(sub, false);
- uiLayoutSetEnabled(entry, RNA_boolean_get(ptr, "use_crease") || is_first);
+ entry = uiLayoutColumn(col, false);
+ uiLayoutSetActive(entry, has_light);
+
+ sub = uiLayoutRow(entry, false);
+ uiItemR(sub, ptr, "use_light_contour", 0, IFACE_("Light Contour"), ICON_NONE);
+
+ uiItemR(entry, ptr, "use_shadow", 0, IFACE_("Cast Shadow"), ICON_NONE);
+
+ uiItemL(layout, IFACE_("Options"), ICON_NONE);
+
+ sub = uiLayoutColumn(layout, false);
if (use_cache && !is_first) {
- uiItemL(entry, IFACE_("Angle Cached"), ICON_INFO);
+ uiItemL(sub, IFACE_("Type overlapping cached"), ICON_INFO);
}
else {
- uiItemR(entry, ptr, "crease_threshold", UI_ITEM_R_SLIDER, " ", ICON_NONE);
+ uiItemR(sub,
+ ptr,
+ "use_overlap_edge_type_support",
+ 0,
+ IFACE_("Allow Overlapping Types"),
+ ICON_NONE);
+ }
+}
+
+static void options_light_reference_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+ 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_cache = RNA_boolean_get(ptr, "use_cache");
+ const bool has_light = RNA_pointer_get(ptr, "light_contour_object").data != NULL;
+ const bool is_first = BKE_gpencil_is_first_lineart_in_stack(ob_ptr.data, ptr->data);
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetEnabled(layout, !is_baked);
+
+ if (use_cache && !is_first) {
+ uiItemL(layout, "Cached from the first line art modifier.", ICON_INFO);
+ return;
}
- uiItemR(layout, ptr, "use_overlap_edge_type_support", 0, IFACE_("Allow Overlap"), ICON_NONE);
+ uiItemR(layout, ptr, "light_contour_object", 0, NULL, ICON_NONE);
+
+ uiLayout *remaining = uiLayoutColumn(layout, false);
+ uiLayoutSetActive(remaining, has_light);
+
+ uiItemR(remaining, ptr, "shadow_camera_size", 0, NULL, ICON_NONE);
+
+ uiLayout *col = uiLayoutColumn(remaining, true);
+ uiItemR(col, ptr, "shadow_camera_near", 0, "Near", ICON_NONE);
+ uiItemR(col, ptr, "shadow_camera_far", 0, "Far", ICON_NONE);
+
+ uiItemR(layout, ptr, "use_shadow_enclosed_shapes", 0, IFACE_("Enclosed Shapes"), ICON_NONE);
}
static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -400,21 +486,6 @@ static void options_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_back_face_culling", 0, IFACE_("Force Backface Culling"), ICON_NONE);
}
-static void style_panel_draw(const bContext *UNUSED(C), Panel *panel)
-{
- uiLayout *layout = panel->layout;
- PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
-
- const bool is_baked = RNA_boolean_get(ptr, "is_baked");
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetEnabled(layout, !is_baked);
-
- uiItemR(layout, ptr, "thickness", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-
- uiItemR(layout, ptr, "opacity", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
-}
-
static void occlusion_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -526,6 +597,7 @@ static void intersection_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "use_intersection_match", 0, IFACE_("Exact Match"), ICON_NONE);
}
+
static void face_mark_panel_draw_header(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
@@ -596,7 +668,7 @@ static void chaining_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "use_fuzzy_intersections", 0, NULL, ICON_NONE);
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_loose_as_contour", 0, IFACE_("Loose Edges As Contour"), 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);
@@ -707,10 +779,14 @@ static void panelRegister(ARegionType *region_type)
gpencil_modifier_subpanel_register(
region_type, "edge_types", "Edge Types", NULL, edge_types_panel_draw, panel_type);
+ gpencil_modifier_subpanel_register(region_type,
+ "light_reference",
+ "Light Reference",
+ NULL,
+ options_light_reference_draw,
+ panel_type);
gpencil_modifier_subpanel_register(
region_type, "geometry", "Geometry Processing", NULL, options_panel_draw, panel_type);
- gpencil_modifier_subpanel_register(
- region_type, "style", "Style", NULL, style_panel_draw, panel_type);
PanelType *occlusion_panel = gpencil_modifier_subpanel_register(
region_type, "occlusion", "Occlusion", NULL, occlusion_panel_draw, panel_type);
gpencil_modifier_subpanel_register(region_type,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
index 6460a69a6cc..1a8d1e75746 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c
@@ -10,7 +10,7 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLT_translation.h"
@@ -23,6 +23,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@@ -100,9 +101,11 @@ static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstro
}
}
-static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+static void generate_geometry(
+ GpencilModifierData *md, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, const bool update)
{
MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md;
+ bGPdata *gpd = ob->data;
bGPDstroke *gps, *gps_new = NULL;
int tot_strokes;
int i;
@@ -129,6 +132,9 @@ static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gp
mmd->flag & GP_MIRROR_INVERT_MATERIAL)) {
gps_new = BKE_gpencil_stroke_duplicate(gps, true, true);
update_position(ob, mmd, gps_new, xi);
+ if (update) {
+ BKE_gpencil_stroke_geometry_update(gpd, gps_new);
+ }
BLI_addtail(&gpf->strokes, gps_new);
}
}
@@ -147,7 +153,7 @@ static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Objec
if (gpf == NULL) {
continue;
}
- generate_geometry(md, ob, gpl, gpf);
+ generate_geometry(md, ob, gpl, gpf, false);
}
}
@@ -163,16 +169,16 @@ static void bakeModifier(Main *UNUSED(bmain),
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* apply mirror effects on this frame */
- CFRA = gpf->framenum;
+ scene->r.cfra = gpf->framenum;
BKE_scene_graph_update_for_newframe(depsgraph);
/* compute mirror effects on this frame */
- generate_geometry(md, ob, gpl, gpf);
+ generate_geometry(md, ob, gpl, gpf, true);
}
}
/* return frame state and DB to original state */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
index d80e32feb2e..fd4eb5da835 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c
@@ -16,8 +16,8 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
+#include "BLI_listbase.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
index 259e62a249c..253603aea67 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c
@@ -7,11 +7,10 @@
#include <stdio.h>
-#include "BLI_listbase.h"
-#include "BLI_utildefines.h"
-
#include "BLI_hash.h"
+#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
index f201a147082..ba88c83161f 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c
@@ -7,15 +7,14 @@
#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"
-#include "BLI_hash.h"
-#include "BLI_math.h"
-#include "BLI_rand.h"
-
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
index b964b143a0f..0bcbd71f029 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c
@@ -6,12 +6,10 @@
*/
#include <stdio.h>
+#include <string.h>
#include "BLI_utildefines.h"
-#include "BLI_blenlib.h"
-#include "BLI_math_vector.h"
-
#include "BLT_translation.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
index 7de1cc89a45..09c1005ecac 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c
@@ -9,7 +9,7 @@
#include <string.h> /* For #MEMCPY_STRUCT_AFTER. */
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -18,7 +18,6 @@
#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"
@@ -136,7 +135,7 @@ static void bakeModifier(Main *UNUSED(bmain),
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
/* Apply shrinkwrap effects on this frame. */
- CFRA = gpf->framenum;
+ scene->r.cfra = gpf->framenum;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Recalculate shrinkwrap data. */
@@ -145,7 +144,7 @@ static void bakeModifier(Main *UNUSED(bmain),
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);
+ Mesh *target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
mmd->cache_data = MEM_callocN(sizeof(ShrinkwrapTreeData), __func__);
if (BKE_shrinkwrap_init_tree(
mmd->cache_data, target, mmd->shrink_type, mmd->shrink_mode, false)) {
@@ -164,7 +163,7 @@ static void bakeModifier(Main *UNUSED(bmain),
}
/* Return frame state and DB to original state. */
- CFRA = oldframe;
+ scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
index e7dfdfee8d2..07350b73ce3 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c
@@ -16,7 +16,6 @@
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
-#include "DNA_vec_types.h"
#include "BKE_context.h"
#include "BKE_gpencil_geom.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
index 5c8c65b9f97..6ba7a934bff 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
index 3ddb508d58a..68fe15df898 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
index 8fa14496616..ad8804782e8 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c
@@ -10,7 +10,7 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
@@ -47,7 +47,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
static void initData(GpencilModifierData *md)
{
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
index e90408b1a94..f40e6ba0728 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
@@ -18,7 +18,6 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
-#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
@@ -29,7 +28,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
index d2c31591a98..1a6cadabf51 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c
@@ -8,7 +8,7 @@
#include <stdio.h>
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_defaults.h"
@@ -29,7 +29,6 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index ad3e1b5d7f2..5dd833fb12b 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -36,10 +36,16 @@ typedef struct LineartTriangle {
/* first culled in line list to use adjacent triangle info, then go through triangle list. */
double gn[3];
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
- unsigned char mat_occlusion;
- unsigned char flags; /* #eLineartTriangleFlags */
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
+ uint8_t mat_occlusion;
+ uint8_t flags; /* #eLineartTriangleFlags */
+
+ /* target_reference = (obi->obindex | triangle_index) */
+ /* higher 12 bits-------^ ^-----index in object, lower 20 bits */
+ uint32_t target_reference;
+
+ uint8_t intersection_priority;
/**
* Only use single link list, because we don't need to go back in order.
@@ -66,6 +72,7 @@ typedef enum eLineArtElementNodeFlag {
LRT_ELEMENT_IS_ADDITIONAL = (1 << 0),
LRT_ELEMENT_BORDER_ONLY = (1 << 1),
LRT_ELEMENT_NO_INTERSECTION = (1 << 2),
+ LRT_ELEMENT_INTERSECTION_DATA = (1 << 3),
} eLineArtElementNodeFlag;
typedef struct LineartElementLinkNode {
@@ -75,61 +82,99 @@ typedef struct LineartElementLinkNode {
void *object_ref;
eLineArtElementNodeFlag flags;
+ /* For edge element link nodes, used for shadow edge matching. */
+ int obindex;
+
/** Per object value, always set, if not enabled by #ObjectLineArt, then it's set to global. */
float crease_threshold;
} LineartElementLinkNode;
typedef struct LineartEdgeSegment {
struct LineartEdgeSegment *next, *prev;
- /** at==0: left at==1: right (this is in 2D projected space) */
- double at;
- /** Occlusion level after "at" point */
- unsigned char occlusion;
+ /** The point after which a property of the segment is changed, e.g. occlusion/material mask etc.
+ * ratio==0: v1 ratio==1: v2 (this is in 2D projected space), */
+ double ratio;
+ /** Occlusion level after "ratio" point */
+ uint8_t occlusion;
/* Used to filter line art occlusion edges */
- unsigned char material_mask_bits;
+ uint8_t material_mask_bits;
+
+ /* Lit/shaded flag for shadow is stored here.
+ * TODO(Yiming): Transfer material masks from shadow results
+ * onto here so then we can even filter transparent shadows. */
+ uint32_t shadow_mask_bits;
} LineartEdgeSegment;
+typedef struct LineartShadowEdge {
+ struct LineartShadowEdge *next, *prev;
+ /* Two end points in frame-buffer coordinates viewed from the light source. */
+ double fbc1[4], fbc2[4];
+ double g1[3], g2[3];
+ bool orig1, orig2;
+ struct LineartEdge *e_ref;
+ struct LineartEdge *e_ref_light_contour;
+ struct LineartEdgeSegment *es_ref; /* Only for 3rd stage casting. */
+ ListBase shadow_segments;
+} LineartShadowEdge;
+
+enum eLineartShadowSegmentFlag {
+ LRT_SHADOW_CASTED = 1,
+ LRT_SHADOW_FACING_LIGHT = 2,
+};
+
+/* Represents a cutting point on a #LineartShadowEdge */
+typedef struct LineartShadowSegment {
+ struct LineartShadowSegment *next, *prev;
+ /* eLineartShadowSegmentFlag */
+ int flag;
+ /* The point after which a property of the segment is changed. e.g. shadow mask/target_ref etc.
+ * Coordinates in NDC during shadow calculation but transformed to global linear before cutting
+ * onto edges during the loading stage of the "actual" rendering. */
+ double ratio;
+ /* Left and right pos, because when casting shadows at some point there will be
+ * non-continuous cuts, see #lineart_shadow_edge_cut for detailed explanation. */
+ double fbc1[4], fbc2[4];
+ /* Global position. */
+ double g1[4], g2[4];
+ uint32_t target_reference;
+ uint32_t shadow_mask_bits;
+} LineartShadowSegment;
+
typedef struct LineartVert {
double gloc[3];
double fbcoord[4];
/* Scene global index. */
int index;
-
- /**
- * Intersection data flag is here, when LRT_VERT_HAS_INTERSECTION_DATA is set,
- * size of the struct is extended to include intersection data.
- * See #eLineArtVertFlags.
- */
- char flag;
-
} LineartVert;
-typedef struct LineartVertIntersection {
- struct LineartVert base;
- /** Use vert index because we only use this to check vertex equal. This way we save 8 Bytes. */
- int isec1, isec2;
- struct LineartTriangle *intersecting_with;
-} LineartVertIntersection;
-
-typedef enum eLineArtVertFlags {
- LRT_VERT_HAS_INTERSECTION_DATA = (1 << 0),
- LRT_VERT_EDGE_USED = (1 << 1),
-} eLineArtVertFlags;
-
typedef struct LineartEdge {
- /** We only need link node kind of list here. */
- struct LineartEdge *next;
struct LineartVert *v1, *v2;
+ /** These two variables are also used to specify original edge and segment during 3rd stage
+ * reprojection, So we can easily find out the line which results come from. */
struct LineartTriangle *t1, *t2;
+
ListBase segments;
- char min_occ;
+ int8_t min_occ;
/** Also for line type determination on chaining. */
uint16_t flags;
- unsigned char intersection_mask;
+ uint8_t intersection_mask;
+
+ /** Matches the shadow result, used to determine whether a line is in the shadow or not.
+ * #edge_identifier usages:
+ * - Intersection lines:
+ * ((e->t1->target_reference << 32) | e->t2->target_reference);
+ * - Other lines: LRT_EDGE_IDENTIFIER(obi, e);
+ * - After shadow calculation: (search the shadow result and set reference to that);
+ */
+ uint64_t edge_identifier;
+
+ /** - Light contour: original_e->t1->target_reference | original_e->t2->target_reference.
+ * - Cast shadow: triangle_projected_onto->target_reference. */
+ uint64_t target_reference;
/**
* Still need this entry because culled lines will not add to object
@@ -149,17 +194,19 @@ typedef struct LineartEdgeChain {
float length;
/** Used when re-connecting and grease-pencil stroke generation. */
- char picked;
- char level;
+ uint8_t picked;
+ uint8_t level;
/** Chain now only contains one type of segments */
int type;
/** Will only connect chains that has the same loop id. */
int loop_id;
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
+ uint32_t shadow_mask_bits;
struct Object *object_ref;
+ struct Object *silhouette_backdrop;
} LineartEdgeChain;
typedef struct LineartEdgeChainItem {
@@ -170,9 +217,10 @@ typedef struct LineartEdgeChainItem {
float gpos[3];
float normal[3];
uint16_t line_type;
- char occlusion;
- unsigned char material_mask_bits;
- unsigned char intersection_mask;
+ uint8_t occlusion;
+ uint8_t material_mask_bits;
+ uint8_t intersection_mask;
+ uint32_t shadow_mask_bits;
size_t index;
} LineartEdgeChainItem;
@@ -180,17 +228,17 @@ typedef struct LineartChainRegisterEntry {
struct LineartChainRegisterEntry *next, *prev;
LineartEdgeChain *ec;
LineartEdgeChainItem *eci;
- char picked;
+ int8_t picked;
/* left/right mark.
* Because we revert list in chaining so we need the flag. */
- char is_left;
+ int8_t is_left;
} LineartChainRegisterEntry;
typedef struct LineartAdjacentEdge {
- unsigned int v1;
- unsigned int v2;
- unsigned int e;
+ uint32_t v1;
+ uint32_t v2;
+ uint32_t e;
} LineartAdjacentEdge;
enum eLineArtTileRecursiveLimit {
@@ -204,135 +252,175 @@ enum eLineArtTileRecursiveLimit {
#define LRT_TILE_SPLITTING_TRIANGLE_LIMIT 100
#define LRT_TILE_EDGE_COUNT_INITIAL 32
+enum eLineartShadowCameraType {
+ LRT_SHADOW_CAMERA_DIRECTIONAL = 1,
+ LRT_SHADOW_CAMERA_POINT = 2,
+};
+
typedef struct LineartPendingEdges {
LineartEdge **array;
int max;
int next;
} LineartPendingEdges;
-typedef struct LineartRenderBuffer {
- struct LineartRenderBuffer *prev, *next;
+typedef struct LineartData {
+ int w, h;
int thread_count;
+ int sizeof_triangle;
- int w, h;
- int tile_size_w, tile_size_h;
- int tile_count_x, tile_count_y;
- double width_per_tile, height_per_tile;
- double view_projection[4][4];
- double view[4][4];
+ LineartStaticMemPool render_data_pool;
+ /* A pointer to LineartCache::chain_data_pool, which acts as a cache for edge chains. */
+ LineartStaticMemPool *chain_data_pool;
+ /* Reference to LineartCache::shadow_data_pool, stay available until the final round of line art
+ * calculation is finished. */
+ LineartStaticMemPool *shadow_data_pool;
- float overscan;
+ /* Storing shadow edge eln, array, and cuts for shadow information, so it's available when line
+ * art runs the second time for occlusion. Either a reference to LineartCache::shadow_data_pool
+ * (shadow stage) or a reference to LineartData::render_data_pool (final stage). */
+ LineartStaticMemPool *edge_data_pool;
- struct LineartBoundingArea *initial_bounding_areas;
- unsigned int bounding_area_count;
+ struct _qtree {
- /* When splitting bounding areas, if there's an ortho camera placed at a straight angle, there
- * will be a lot of triangles aligned in line which can not be separated by continue subdividing
- * the tile. So we set a strict limit when using ortho camera. See eLineArtTileRecursiveLimit. */
- int tile_recursive_level;
+ int count_x, count_y;
+ double tile_width, tile_height;
- ListBase vertex_buffer_pointers;
- ListBase line_buffer_pointers;
- ListBase triangle_buffer_pointers;
+ /* When splitting bounding areas, if there's an ortho camera placed at a straight angle, there
+ * will be a lot of triangles aligned in line which can not be separated by continue
+ * subdividing the tile. So we set a strict limit when using ortho camera. See
+ * eLineArtTileRecursiveLimit. */
+ int recursive_level;
- /** This one's memory is not from main pool and is free()ed after culling stage. */
- ListBase triangle_adjacent_pointers;
+ struct LineartBoundingArea *initials;
- ListBase intersecting_vertex_buffer;
- /** Use the one comes with Line Art. */
- LineartStaticMemPool render_data_pool;
- ListBase wasted_cuts;
- SpinLock lock_cuts;
+ uint32_t initial_tile_count;
- /* This is just a pointer to LineartCache::chain_data_pool, which acts as a cache for line
- * chains. */
- LineartStaticMemPool *chain_data_pool;
+ } qtree;
+
+ struct _geom {
+
+ ListBase vertex_buffer_pointers;
+ ListBase line_buffer_pointers;
+ ListBase triangle_buffer_pointers;
+
+ /** This one's memory is not from main pool and is free()ed after culling stage. */
+ ListBase triangle_adjacent_pointers;
+
+ ListBase intersecting_vertex_buffer;
+
+ } geom;
- /* Render status */
- double view_vector[3];
+ struct _conf {
- int triangle_size;
+ double view_projection[4][4];
+ double view[4][4];
- /* Note: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
+ float overscan;
+
+ int max_occlusion_level;
+ double crease_angle;
+ double crease_cos;
+
+ int draw_material_preview;
+ double material_transparency;
+
+ bool use_contour;
+ bool use_crease;
+ bool use_material;
+ bool use_edge_marks;
+ bool use_intersections;
+ bool use_loose;
+ bool use_light_contour;
+ bool use_shadow;
+ bool use_contour_secondary; /* From viewing camera, during shadow calculation. */
+
+ int shadow_selection; /* Needs to be numeric because it's not just on/off. */
+ bool shadow_enclose_shapes;
+ bool shadow_use_silhouette;
+
+ bool fuzzy_intersections;
+ bool fuzzy_everything;
+ bool allow_boundaries;
+ bool allow_overlapping_edges;
+ bool allow_duplicated_types;
+ bool remove_doubles;
+ 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;
+
+ bool do_shadow_cast;
+ bool light_reference_available;
+
+ /* Keep an copy of these data so when line art is running it's self-contained. */
+ bool cam_is_persp;
+ bool cam_is_persp_secondary; /* "Secondary" ones are from viewing camera (as opposed to shadow
+ camera), during shadow calculation. */
+ float cam_obmat[4][4];
+ float cam_obmat_secondary[4][4];
+ double camera_pos[3];
+ double camera_pos_secondary[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;
+ float chaining_image_threshold;
+ float angle_splitting_threshold;
+
+ float chain_smooth_tolerance;
+
+ double view_vector[3];
+ double view_vector_secondary[3]; /* For shadow. */
+ } conf;
+
+ LineartElementLinkNode *isect_scheduled_up_to;
+ int isect_scheduled_up_to_index;
+
+ /* NOTE: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
struct LineartPendingEdges pending_edges;
int scheduled_count;
+ /* Intermediate shadow results, list of LineartShadowEdge */
+ LineartShadowEdge *shadow_edges;
+ int shadow_edges_count;
+
ListBase chains;
- /* For managing calculation tasks for multiple threads. */
+ ListBase wasted_cuts;
+ ListBase wasted_shadow_cuts;
+ SpinLock lock_cuts;
SpinLock lock_task;
- /* settings */
-
- int max_occlusion_level;
- double crease_angle;
- double crease_cos;
-
- int draw_material_preview;
- double material_transparency;
-
- bool use_contour;
- bool use_crease;
- bool use_material;
- bool use_edge_marks;
- bool use_intersections;
- bool use_loose;
- bool fuzzy_intersections;
- bool fuzzy_everything;
- bool allow_boundaries;
- bool allow_overlapping_edges;
- bool allow_duplicated_types;
- bool remove_doubles;
- 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;
- float chaining_image_threshold;
- float angle_splitting_threshold;
-
- float chain_smooth_tolerance;
-
- /* FIXME(Yiming): Temporary solution for speeding up calculation by not including lines that
- * are not in the selected source. This will not be needed after we have a proper scene-wise
- * cache running because multiple modifiers can then select results from that without further
- * calculation. */
- int _source_type;
- struct Collection *_source_collection;
- struct Object *_source_object;
-
-} LineartRenderBuffer;
+} LineartData;
typedef struct LineartCache {
- /** Separate memory pool for chain data, this goes to the cache, so when we free the main pool,
- * chains will still be available. */
+ /** Separate memory pool for chain data and shadow, this goes to the cache, so when we free the
+ * main pool, chains and shadows will still be available. */
LineartStaticMemPool chain_data_pool;
+ LineartStaticMemPool shadow_data_pool;
- /** A copy of rb->chains so we have that data available after rb has been destroyed. */
+ /** A copy of ld->chains so we have that data available after ld has been destroyed. */
ListBase chains;
+ /** Shadow-computed feature lines from original meshes to be matched with the second load of
+ * meshes thus providing lit/shade info in the second run of line art. */
+ ListBase shadow_elns;
+
/** Cache only contains edge types specified in this variable. */
- char rb_edge_types;
+ uint16_t all_enabled_edge_types;
} LineartCache;
#define DBL_TRIANGLE_LIM 1e-8
@@ -350,6 +438,14 @@ typedef enum eLineartTriangleFlags {
LRT_TRIANGLE_MAT_BACK_FACE_CULLING = (1 << 5),
} eLineartTriangleFlags;
+#define LRT_SHADOW_MASK_UNDEFINED 0
+#define LRT_SHADOW_MASK_LIT (1 << 0)
+#define LRT_SHADOW_MASK_SHADED (1 << 1)
+#define LRT_SHADOW_MASK_ENCLOSED_SHAPE (1 << 2)
+#define LRT_SHADOW_MASK_INHIBITED (1 << 3)
+#define LRT_SHADOW_SILHOUETTE_ERASED_GROUP (1 << 4)
+#define LRT_SHADOW_SILHOUETTE_ERASED_OBJECT (1 << 5)
+
/**
* Controls how many edges a worker thread is processing at one request.
* There's no significant performance impact on choosing different values.
@@ -358,18 +454,26 @@ typedef enum eLineartTriangleFlags {
#define LRT_THREAD_EDGE_COUNT 1000
typedef struct LineartRenderTaskInfo {
- struct LineartRenderBuffer *rb;
+ struct LineartData *ld;
int thread_id;
/**
* #pending_edges here only stores a reference to a portion in
- * LineartRenderbuffer::pending_edges, assigned by the occlusion scheduler.
+ * LineartData::pending_edges, assigned by the occlusion scheduler.
*/
struct LineartPendingEdges pending_edges;
} LineartRenderTaskInfo;
+#define LRT_OBINDEX_SHIFT 20
+#define LRT_OBINDEX_LOWER 0x0FFFFF /* Lower 20 bits. */
+#define LRT_OBINDEX_HIGHER 0xFFF00000 /* Higher 12 bits. */
+#define LRT_EDGE_IDENTIFIER(obi, e) \
+ (((uint64_t)(obi->obindex | (e->v1->index & LRT_OBINDEX_LOWER)) << 32) | \
+ (obi->obindex | (e->v2->index & LRT_OBINDEX_LOWER)))
+#define LRT_LIGHT_CONTOUR_TARGET 0xFFFFFFFF
+
typedef struct LineartObjectInfo {
struct LineartObjectInfo *next;
struct Object *original_ob;
@@ -380,22 +484,27 @@ typedef struct LineartObjectInfo {
LineartElementLinkNode *v_eln;
int usage;
uint8_t override_intersection_mask;
+ uint8_t intersection_priority;
int global_i_offset;
+ /* Shifted LRT_OBINDEX_SHIFT bits to be combined with object triangle index. */
+ int obindex;
+
bool free_use_mesh;
- /* Note: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
+ /** NOTE: Data inside #pending_edges are allocated with MEM_xxx call instead of in pool. */
struct LineartPendingEdges pending_edges;
} LineartObjectInfo;
typedef struct LineartObjectLoadTaskInfo {
- struct LineartRenderBuffer *rb;
+ struct LineartData *ld;
int thread_id;
/* LinkNode styled list */
LineartObjectInfo *pending;
/* Used to spread the load across several threads. This can not overflow. */
- long unsigned int total_faces;
+ uint64_t total_faces;
+ ListBase *shadow_elns;
} LineartObjectLoadTaskInfo;
/**
@@ -429,15 +538,18 @@ typedef struct LineartBoundingArea {
/** 1,2,3,4 quadrant */
struct LineartBoundingArea *child;
+ SpinLock lock;
+
ListBase lp;
ListBase rp;
ListBase up;
ListBase bp;
- uint16_t triangle_count;
- uint16_t max_triangle_count;
- uint16_t line_count;
- uint16_t max_line_count;
+ uint32_t triangle_count;
+ uint32_t max_triangle_count;
+ uint32_t line_count;
+ uint32_t max_line_count;
+ uint32_t insider_triangle_count;
/* Use array for speeding up multiple accesses. */
struct LineartTriangle **linked_triangles;
@@ -459,15 +571,16 @@ 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))
+#define LRT_CLOSE_LOOSER_v3(a, b) \
+ (LRT_DOUBLE_CLOSE_LOOSER(a[0], b[0]) && LRT_DOUBLE_CLOSE_LOOSER(a[1], b[1]) && \
+ LRT_DOUBLE_CLOSE_LOOSER(a[2], b[2]))
+
/* Notes on this function:
*
* r_ratio: The ratio on segment a1-a2. When r_ratio is very close to zero or one, it
@@ -480,10 +593,10 @@ typedef struct LineartBoundingArea {
* 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,
+BLI_INLINE int lineart_intersect_seg_seg(const double a1[2],
+ const double a2[2],
+ const double b1[2],
+ const double b2[2],
double *r_ratio,
bool *r_aligned)
{
@@ -624,32 +737,124 @@ BLI_INLINE int lineart_intersect_seg_seg(const double *a1,
#endif
}
+/* This is a special convenience function to lineart_intersect_seg_seg which will return true when
+ * the intersection point falls in the range of a1-a2 but not necessarily in the range of b1-b2. */
+BLI_INLINE int lineart_line_isec_2d_ignore_line2pos(const double a1[2],
+ const double a2[2],
+ const double b1[2],
+ const double b2[2],
+ double *r_a_ratio)
+{
+ /* The define here is used to check how vector or slope method handles boundary cases. The result
+ * of `lim(div->0)` and `lim(k->0)` could both produce some unwanted flickers in line art, the
+ * influence of which is still not fully understood, so keep the switch there for further
+ * investigations. */
+#define USE_VECTOR_LINE_INTERSECTION_IGN
+#ifdef USE_VECTOR_LINE_INTERSECTION_IGN
+
+ /* from isect_line_line_v2_point() */
+
+ double s10[2], s32[2];
+ double div;
+
+ sub_v2_v2v2_db(s10, a2, a1);
+ sub_v2_v2v2_db(s32, b2, b1);
+
+ div = cross_v2v2_db(s10, s32);
+ if (div != 0.0f) {
+ const double u = cross_v2v2_db(a2, a1);
+ const double v = cross_v2v2_db(b2, b1);
+
+ const double rx = ((s32[0] * u) - (s10[0] * v)) / div;
+ const double ry = ((s32[1] * u) - (s10[1] * v)) / div;
+
+ if (fabs(a2[0] - a1[0]) > fabs(a2[1] - a1[1])) {
+ *r_a_ratio = ratiod(a1[0], a2[0], rx);
+ if ((*r_a_ratio) >= -DBL_EDGE_LIM && (*r_a_ratio) <= 1 + DBL_EDGE_LIM) {
+ return 1;
+ }
+ return 0;
+ }
+
+ *r_a_ratio = ratiod(a1[1], a2[1], ry);
+ if ((*r_a_ratio) >= -DBL_EDGE_LIM && (*r_a_ratio) <= 1 + DBL_EDGE_LIM) {
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+
+#else
+ double k1, k2;
+ double x;
+ double y;
+ double ratio;
+ double x_diff = (a2[0] - a1[0]);
+ double x_diff2 = (b2[0] - b1[0]);
+
+ if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff, 0)) {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(x_diff2, 0)) {
+ *r_a_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);
+ *r_a_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);
+ *r_a_ratio = ratio;
+ }
+ else {
+ k1 = (a2[1] - a1[1]) / x_diff;
+ k2 = (b2[1] - b1[1]) / x_diff2;
+
+ if ((k1 == k2))
+ return 0;
+
+ x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1);
+
+ ratio = (x - a1[0]) / x_diff;
+
+ *r_a_ratio = ratio;
+ }
+ }
+
+ if (ratio <= 0 || ratio >= 1)
+ return 0;
+
+ return 1;
+#endif
+}
+
struct Depsgraph;
struct LineartGpencilModifierData;
-struct LineartRenderBuffer;
+struct LineartData;
struct Scene;
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);
+void MOD_lineart_chain_feature_lines(LineartData *ld);
+void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld);
/**
* 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, float threshold);
-void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb);
+void MOD_lineart_chain_connect(LineartData *ld);
+void MOD_lineart_chain_discard_unused(LineartData *ld, float threshold, uint8_t max_occlusion);
+void MOD_lineart_chain_clip_at_border(LineartData *ld);
/**
* 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);
+void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad);
+void MOD_lineart_smooth_chains(LineartData *ld, float tolerance);
+void MOD_lineart_chain_offset_towards_camera(LineartData *ld, float dist, bool use_custom_camera);
+void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld);
int MOD_lineart_chain_count(const LineartEdgeChain *ec);
void MOD_lineart_chain_clear_picked_flag(LineartCache *lc);
@@ -669,14 +874,12 @@ struct Scene;
/**
* This only gets initial "biggest" tile.
*/
-LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
- double x,
- double y);
+LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y);
/**
* Wrapper for more convenience.
*/
-LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y);
+LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y);
struct bGPDframe;
struct bGPDlayer;
@@ -689,17 +892,19 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
struct Object *ob,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
- char source_type,
+ int8_t source_type,
void *source_reference,
int level_start,
int level_end,
int mat_nr,
- short edge_types,
- unsigned char mask_switches,
- unsigned char material_mask_bits,
- unsigned char intersection_mask,
- short thickness,
+ int16_t edge_types,
+ uint8_t mask_switches,
+ uint8_t material_mask_bits,
+ uint8_t intersection_mask,
+ int16_t thickness,
float opacity,
+ uint8_t shadow_selection,
+ uint8_t silhouette_mode,
const char *source_vgname,
const char *vgname,
int modifier_flags);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
index 226b8f532b5..7c8e0c5a6f5 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_chain.c
@@ -17,13 +17,16 @@
#define LRT_OTHER_VERT(e, vt) ((vt) == (e)->v1 ? (e)->v2 : ((vt) == (e)->v2 ? (e)->v1 : NULL))
+struct Object;
+
/* Get a connected line, only for lines who has the exact given vert, or (in the case of
* intersection lines) who has a vert that has the exact same position. */
static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
LineartVert *vt,
LineartVert **new_vt,
int match_flag,
- unsigned char match_isec_mask)
+ uint8_t match_isec_mask,
+ struct Object *match_isec_object)
{
for (int i = 0; i < ba->line_count; i++) {
LineartEdge *n_e = ba->linked_lines[i];
@@ -46,6 +49,9 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
}
if (n_e->flags & LRT_EDGE_FLAG_INTERSECTION) {
+ if (n_e->object_ref != match_isec_object) {
+ continue;
+ }
if (vt->fbcoord[0] == n_e->v1->fbcoord[0] && vt->fbcoord[1] == n_e->v1->fbcoord[1]) {
*new_vt = LRT_OTHER_VERT(n_e, n_e->v1);
return n_e;
@@ -60,12 +66,12 @@ static LineartEdge *lineart_line_get_connected(LineartBoundingArea *ba,
return NULL;
}
-static LineartEdgeChain *lineart_chain_create(LineartRenderBuffer *rb)
+static LineartEdgeChain *lineart_chain_create(LineartData *ld)
{
LineartEdgeChain *ec;
- ec = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChain));
+ ec = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChain));
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
return ec;
}
@@ -85,14 +91,15 @@ static bool lineart_point_overlapping(LineartEdgeChainItem *eci,
return false;
}
-static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_append_point(LineartData *ld,
LineartEdgeChain *ec,
- float *fbcoord,
- float *gpos,
- float *normal,
- char type,
+ float fbcoord[4],
+ float gpos[3],
+ float normal[3],
+ uint8_t type,
int level,
- unsigned char material_mask_bits,
+ uint8_t material_mask_bits,
+ uint32_t shadow_mask_bits,
size_t index)
{
LineartEdgeChainItem *eci;
@@ -105,10 +112,11 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
old_eci->line_type = type;
old_eci->occlusion = level;
old_eci->material_mask_bits = material_mask_bits;
+ old_eci->shadow_mask_bits = shadow_mask_bits;
return old_eci;
}
- eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
+ eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem));
copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
@@ -117,19 +125,21 @@ static LineartEdgeChainItem *lineart_chain_append_point(LineartRenderBuffer *rb,
eci->line_type = type & LRT_EDGE_FLAG_ALL_TYPE;
eci->occlusion = level;
eci->material_mask_bits = material_mask_bits;
+ eci->shadow_mask_bits = shadow_mask_bits;
BLI_addtail(&ec->chain, eci);
return eci;
}
-static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_prepend_point(LineartData *ld,
LineartEdgeChain *ec,
- float *fbcoord,
- float *gpos,
- float *normal,
- char type,
+ float fbcoord[4],
+ float gpos[3],
+ float normal[3],
+ uint8_t type,
int level,
- unsigned char material_mask_bits,
+ uint8_t material_mask_bits,
+ uint32_t shadow_mask_bits,
size_t index)
{
LineartEdgeChainItem *eci;
@@ -138,7 +148,7 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
return ec->chain.first;
}
- eci = lineart_mem_acquire(rb->chain_data_pool, sizeof(LineartEdgeChainItem));
+ eci = lineart_mem_acquire(ld->chain_data_pool, sizeof(LineartEdgeChainItem));
copy_v4_v4(eci->pos, fbcoord);
copy_v3_v3(eci->gpos, gpos);
@@ -147,19 +157,21 @@ static LineartEdgeChainItem *lineart_chain_prepend_point(LineartRenderBuffer *rb
eci->line_type = type & LRT_EDGE_FLAG_ALL_TYPE;
eci->occlusion = level;
eci->material_mask_bits = material_mask_bits;
+ eci->shadow_mask_bits = shadow_mask_bits;
BLI_addhead(&ec->chain, eci);
return eci;
}
-void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
+void MOD_lineart_chain_feature_lines(LineartData *ld)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *eci;
LineartBoundingArea *ba;
LineartEdgeSegment *es;
int last_occlusion;
- unsigned char last_transparency;
+ uint8_t last_transparency;
+ uint32_t last_shadow;
/* Used when converting from double. */
float use_fbcoord[4];
float use_gpos[3];
@@ -181,7 +193,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
- ec = lineart_chain_create(rb);
+ ec = lineart_chain_create(ld);
/* One chain can only have one object_ref and intersection_mask,
* so we assign them based on the first segment we found. */
@@ -207,11 +219,11 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
}
/* Step 1: grow left. */
- ba = MOD_lineart_get_bounding_area(rb, e->v1->fbcoord[0], e->v1->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, e->v1->fbcoord[0], e->v1->fbcoord[1]);
new_vt = e->v1;
es = e->segments.first;
VERT_COORD_TO_FLOAT(new_vt);
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -219,9 +231,10 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags,
es->occlusion,
es->material_mask_bits,
+ es->shadow_mask_bits,
e->v1->index);
while (ba && (new_e = lineart_line_get_connected(
- ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
+ ba, new_vt, &new_vt, e->flags, ec->intersection_mask, ec->object_ref))) {
new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
if (new_e->t1 || new_e->t2) {
@@ -243,12 +256,12 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
for (es = new_e->segments.last; es; es = es->prev) {
double gpos[3], lpos[3];
double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
- 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);
+ double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
+ interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
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,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -256,25 +269,28 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
es->occlusion,
es->material_mask_bits,
+ es->shadow_mask_bits,
new_e->v1->index);
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
+ last_shadow = es->shadow_mask_bits;
}
}
else if (new_vt == new_e->v2) {
es = new_e->segments.first;
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
+ last_shadow = es->shadow_mask_bits;
es = es->next;
for (; es; es = es->next) {
double gpos[3], lpos[3];
double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
- 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);
+ double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
+ interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
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,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -282,12 +298,14 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
last_occlusion,
last_transparency,
+ last_shadow,
new_e->v2->index);
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
+ last_shadow = es->shadow_mask_bits;
}
VERT_COORD_TO_FLOAT(new_e->v2);
- lineart_chain_prepend_point(rb,
+ lineart_chain_prepend_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -295,9 +313,10 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
last_occlusion,
last_transparency,
+ last_shadow,
new_e->v2->index);
}
- ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
}
/* Restore normal value. */
@@ -318,17 +337,18 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
/* Step 2: Adding all cuts from the given line, so we can continue connecting the right side
* of the line. */
es = e->segments.first;
- last_occlusion = ((LineartEdgeSegment *)es)->occlusion;
- last_transparency = ((LineartEdgeSegment *)es)->material_mask_bits;
+ last_occlusion = es->occlusion;
+ last_transparency = es->material_mask_bits;
+ last_shadow = es->shadow_mask_bits;
for (es = es->next; es; es = es->next) {
double gpos[3], lpos[3];
double *lfb = e->v1->fbcoord, *rfb = e->v2->fbcoord;
- 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);
+ double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
+ interp_v3_v3v3_db(lpos, e->v1->fbcoord, e->v2->fbcoord, es->ratio);
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,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -336,12 +356,14 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags,
es->occlusion,
es->material_mask_bits,
+ es->shadow_mask_bits,
e->v1->index);
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
+ last_shadow = es->shadow_mask_bits;
}
VERT_COORD_TO_FLOAT(e->v2)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -349,13 +371,14 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
e->flags,
last_occlusion,
last_transparency,
+ last_shadow,
e->v2->index);
/* Step 3: grow right. */
- ba = MOD_lineart_get_bounding_area(rb, e->v2->fbcoord[0], e->v2->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, e->v2->fbcoord[0], e->v2->fbcoord[1]);
new_vt = e->v2;
while (ba && (new_e = lineart_line_get_connected(
- ba, new_vt, &new_vt, e->flags, e->intersection_mask))) {
+ ba, new_vt, &new_vt, e->flags, ec->intersection_mask, ec->object_ref))) {
new_e->flags |= LRT_EDGE_FLAG_CHAIN_PICKED;
if (new_e->t1 || new_e->t2) {
@@ -381,20 +404,23 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
es = new_e->segments.last;
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
+ last_shadow = es->shadow_mask_bits;
/* Fix leading vertex occlusion. */
eci->occlusion = last_occlusion;
eci->material_mask_bits = last_transparency;
+ eci->shadow_mask_bits = last_shadow;
for (es = new_e->segments.last; es; es = es->prev) {
double gpos[3], lpos[3];
double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
- 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);
+ double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
+ interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
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;
+ last_shadow = es->prev ? es->prev->shadow_mask_bits : last_shadow;
POS_TO_FLOAT(lpos, gpos)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -402,6 +428,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
last_occlusion,
last_transparency,
+ last_shadow,
new_e->v1->index);
}
}
@@ -409,18 +436,20 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
es = new_e->segments.first;
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
+ last_shadow = es->shadow_mask_bits;
eci->occlusion = last_occlusion;
eci->material_mask_bits = last_transparency;
+ eci->shadow_mask_bits = last_shadow;
es = es->next;
for (; es; es = es->next) {
double gpos[3], lpos[3];
double *lfb = new_e->v1->fbcoord, *rfb = new_e->v2->fbcoord;
- 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);
+ double global_at = lfb[3] * es->ratio / (es->ratio * lfb[3] + (1 - es->ratio) * rfb[3]);
+ interp_v3_v3v3_db(lpos, new_e->v1->fbcoord, new_e->v2->fbcoord, es->ratio);
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,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -428,12 +457,14 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
es->occlusion,
es->material_mask_bits,
+ es->shadow_mask_bits,
new_e->v2->index);
last_occlusion = es->occlusion;
last_transparency = es->material_mask_bits;
+ last_shadow = es->shadow_mask_bits;
}
VERT_COORD_TO_FLOAT(new_e->v2)
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
use_fbcoord,
use_gpos,
@@ -441,11 +472,12 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
new_e->flags,
last_occlusion,
last_transparency,
+ last_shadow,
new_e->v2->index);
}
- ba = MOD_lineart_get_bounding_area(rb, new_vt->fbcoord[0], new_vt->fbcoord[1]);
+ ba = MOD_lineart_get_bounding_area(ld, new_vt->fbcoord[0], new_vt->fbcoord[1]);
}
- if (rb->fuzzy_everything) {
+ if (ld->conf.fuzzy_everything) {
ec->type = LRT_EDGE_FLAG_CONTOUR;
}
else {
@@ -455,7 +487,7 @@ void MOD_lineart_chain_feature_lines(LineartRenderBuffer *rb)
LRT_ITER_ALL_LINES_END
}
-static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRenderBuffer *rb,
+static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartData *ld,
LineartBoundingArea *root,
LineartEdgeChainItem *eci)
{
@@ -468,32 +500,32 @@ static LineartBoundingArea *lineart_bounding_area_get_eci_recursive(LineartRende
ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1]
if (IN_BOUND(ch[0], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[0], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[0], eci);
}
if (IN_BOUND(ch[1], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[1], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[1], eci);
}
if (IN_BOUND(ch[2], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[2], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[2], eci);
}
if (IN_BOUND(ch[3], eci)) {
- return lineart_bounding_area_get_eci_recursive(rb, &ch[3], eci);
+ return lineart_bounding_area_get_eci_recursive(ld, &ch[3], eci);
}
#undef IN_BOUND
return NULL;
}
-static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuffer *rb,
+static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartData *ld,
LineartEdgeChainItem *eci)
{
if (!eci) {
return NULL;
}
- LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(rb, eci->pos[0], eci->pos[1]);
+ LineartBoundingArea *root = MOD_lineart_get_parent_bounding_area(ld, eci->pos[0], eci->pos[1]);
if (root == NULL) {
return NULL;
}
- return lineart_bounding_area_get_eci_recursive(rb, root, eci);
+ return lineart_bounding_area_get_eci_recursive(ld, root, eci);
}
/**
@@ -502,14 +534,14 @@ static LineartBoundingArea *lineart_bounding_area_get_end_point(LineartRenderBuf
* areas, this happens either when 1) the geometry is way too dense, or 2) the chaining threshold
* is too big that it covers multiple small bounding areas.
*/
-static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_point_recursive(LineartData *ld,
LineartBoundingArea *root,
LineartEdgeChain *ec,
LineartEdgeChainItem *eci)
{
if (root->child == NULL) {
LineartChainRegisterEntry *cre = lineart_list_append_pointer_pool_sized(
- &root->linked_chains, &rb->render_data_pool, ec, sizeof(LineartChainRegisterEntry));
+ &root->linked_chains, ld->chain_data_pool, ec, sizeof(LineartChainRegisterEntry));
cre->eci = eci;
@@ -524,34 +556,34 @@ static void lineart_bounding_area_link_point_recursive(LineartRenderBuffer *rb,
ba.l <= eci->pos[0] && ba.r >= eci->pos[0] && ba.b <= eci->pos[1] && ba.u >= eci->pos[1]
if (IN_BOUND(ch[0], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[0], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[0], ec, eci);
}
else if (IN_BOUND(ch[1], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[1], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[1], ec, eci);
}
else if (IN_BOUND(ch[2], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[2], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[2], ec, eci);
}
else if (IN_BOUND(ch[3], eci)) {
- lineart_bounding_area_link_point_recursive(rb, &ch[3], ec, eci);
+ lineart_bounding_area_link_point_recursive(ld, &ch[3], ec, eci);
}
#undef IN_BOUND
}
}
-static void lineart_bounding_area_link_chain(LineartRenderBuffer *rb, LineartEdgeChain *ec)
+static void lineart_bounding_area_link_chain(LineartData *ld, LineartEdgeChain *ec)
{
LineartEdgeChainItem *pl = ec->chain.first;
LineartEdgeChainItem *pr = ec->chain.last;
- LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(rb, pl->pos[0], pl->pos[1]);
- LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(rb, pr->pos[0], pr->pos[1]);
+ LineartBoundingArea *ba1 = MOD_lineart_get_parent_bounding_area(ld, pl->pos[0], pl->pos[1]);
+ LineartBoundingArea *ba2 = MOD_lineart_get_parent_bounding_area(ld, pr->pos[0], pr->pos[1]);
if (ba1) {
- lineart_bounding_area_link_point_recursive(rb, ba1, ec, pl);
+ lineart_bounding_area_link_point_recursive(ld, ba1, ec, pl);
}
if (ba2) {
- lineart_bounding_area_link_point_recursive(rb, ba2, ec, pr);
+ lineart_bounding_area_link_point_recursive(ld, ba2, ec, pr);
}
}
@@ -564,7 +596,8 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
float dist_accum = 0;
int fixed_occ = last_matching_eci->occlusion;
- unsigned char fixed_mask = last_matching_eci->material_mask_bits;
+ uint8_t fixed_mask = last_matching_eci->material_mask_bits;
+ uint32_t fixed_shadow = last_matching_eci->shadow_mask_bits;
LineartEdgeChainItem *can_skip_to = NULL;
LineartEdgeChainItem *last_eci = last_matching_eci;
@@ -579,7 +612,8 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
if (eci->occlusion < fixed_occ) {
break;
}
- if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ) {
+ if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ &&
+ eci->shadow_mask_bits == fixed_shadow) {
can_skip_to = eci;
}
}
@@ -589,12 +623,14 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
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) {
+ if (eci->material_mask_bits == fixed_mask && eci->occlusion == fixed_occ &&
+ eci->shadow_mask_bits == fixed_shadow) {
continue;
}
if (preserve_details) {
eci->material_mask_bits = fixed_mask;
eci->occlusion = fixed_occ;
+ eci->shadow_mask_bits = fixed_shadow;
}
else {
BLI_remlink(&ec->chain, eci);
@@ -606,41 +642,44 @@ static bool lineart_chain_fix_ambiguous_segments(LineartEdgeChain *ec,
return false;
}
-void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
+void MOD_lineart_chain_split_for_fixed_occlusion(LineartData *ld)
{
LineartEdgeChain *ec, *new_ec;
LineartEdgeChainItem *eci, *next_eci;
ListBase swap = {0};
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
int loop_id = 0;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
ec->loop_id = loop_id;
loop_id++;
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
int fixed_occ = first_eci->occlusion;
- unsigned char fixed_mask = first_eci->material_mask_bits;
+ uint8_t fixed_mask = first_eci->material_mask_bits;
+ uint32_t fixed_shadow = first_eci->shadow_mask_bits;
ec->level = fixed_occ;
ec->material_mask_bits = fixed_mask;
+ ec->shadow_mask_bits = fixed_shadow;
for (eci = first_eci->next; eci; eci = next_eci) {
next_eci = eci->next;
- if (eci->occlusion != fixed_occ || eci->material_mask_bits != fixed_mask) {
+ if (eci->occlusion != fixed_occ || eci->material_mask_bits != fixed_mask ||
+ eci->shadow_mask_bits != fixed_shadow) {
if (next_eci) {
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,
+ ld->conf.chaining_image_threshold,
+ ld->conf.chain_preserve_details,
&next_eci)) {
continue;
}
@@ -649,11 +688,12 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
/* Set the same occlusion level for the end vertex, so when further connection is needed
* the backwards occlusion info is also correct. */
eci->occlusion = fixed_occ;
+ eci->shadow_mask_bits = fixed_shadow;
eci->material_mask_bits = fixed_mask;
/* No need to split at the last point anyway. */
break;
}
- new_ec = lineart_chain_create(rb);
+ new_ec = lineart_chain_create(ld);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
new_ec->loop_id = loop_id;
@@ -662,7 +702,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
eci->prev = 0;
/* End the previous one. */
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
eci->pos,
eci->gpos,
@@ -670,6 +710,7 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
eci->line_type,
fixed_occ,
fixed_mask,
+ fixed_shadow,
eci->index);
new_ec->object_ref = ec->object_ref;
new_ec->type = ec->type;
@@ -677,22 +718,25 @@ void MOD_lineart_chain_split_for_fixed_occlusion(LineartRenderBuffer *rb)
ec = new_ec;
fixed_occ = eci->occlusion;
fixed_mask = eci->material_mask_bits;
+ fixed_shadow = eci->shadow_mask_bits;
ec->level = fixed_occ;
ec->material_mask_bits = fixed_mask;
+ ec->shadow_mask_bits = fixed_shadow;
}
}
}
- /* 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);
+
+ MOD_lineart_chain_discard_unused(ld, DBL_EDGE_LIM, ld->conf.max_occlusion_level);
+
+ LISTBASE_FOREACH (LineartEdgeChain *, iec, &ld->chains) {
+ lineart_bounding_area_link_chain(ld, iec);
}
}
/**
* NOTE: segment type (crease/material/contour...) is ambiguous after this.
*/
-static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb),
+static void lineart_chain_connect(LineartData *UNUSED(ld),
LineartEdgeChain *onto,
LineartEdgeChain *sub,
int reverse_1,
@@ -742,13 +786,14 @@ static void lineart_chain_connect(LineartRenderBuffer *UNUSED(rb),
}
}
-static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuffer *rb,
+static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartData *ld,
LineartBoundingArea *ba,
LineartEdgeChain *ec,
LineartEdgeChainItem *eci,
int occlusion,
- unsigned char material_mask_bits,
- unsigned char isec_mask,
+ uint8_t material_mask_bits,
+ uint8_t isec_mask,
+ uint32_t shadow_mask,
int loop_id,
float dist,
float *result_new_len,
@@ -761,8 +806,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
* next one. */
LISTBASE_FOREACH_MUTABLE (LineartChainRegisterEntry *, cre, &ba->linked_chains) {
if (cre->ec->object_ref != ec->object_ref) {
- if (!rb->fuzzy_everything) {
- if (rb->fuzzy_intersections) {
+ if (!ld->conf.fuzzy_everything) {
+ if (ld->conf.fuzzy_intersections) {
/* If none of those are intersection lines... */
if ((!(cre->ec->type & LRT_EDGE_FLAG_INTERSECTION)) &&
(!(ec->type & LRT_EDGE_FLAG_INTERSECTION))) {
@@ -779,12 +824,12 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
}
if (cre->ec == ec || (!cre->ec->chain.first) || (cre->ec->level != occlusion) ||
(cre->ec->material_mask_bits != material_mask_bits) ||
- (cre->ec->intersection_mask != isec_mask)) {
+ (cre->ec->intersection_mask != isec_mask) || (cre->ec->shadow_mask_bits != shadow_mask)) {
continue;
}
- if (!rb->fuzzy_everything) {
+ if (!ld->conf.fuzzy_everything) {
if (cre->ec->type != ec->type) {
- if (rb->fuzzy_intersections) {
+ if (ld->conf.fuzzy_intersections) {
if (!(cre->ec->type == LRT_EDGE_FLAG_INTERSECTION ||
ec->type == LRT_EDGE_FLAG_INTERSECTION)) {
continue; /* Fuzzy intersections but no intersection line found. */
@@ -796,8 +841,8 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
}
}
- float new_len = rb->use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) :
- len_v2v2(cre->eci->pos, eci->pos);
+ float new_len = ld->conf.use_geometry_space_chain ? len_v3v3(cre->eci->gpos, eci->gpos) :
+ len_v2v2(cre->eci->pos, eci->pos);
/* Even if the vertex is not from the same contour loop, we try to chain it still if the
* distance is small enough. This way we can better chain smaller loops and smooth them out
* later. */
@@ -817,15 +862,16 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
#define LRT_TEST_ADJACENT_AREAS(dist_to, list) \
if (dist_to < dist && dist_to > 0) { \
- LISTBASE_FOREACH (LinkData *, ld, list) { \
- LineartBoundingArea *sba = (LineartBoundingArea *)ld->data; \
- adjacent_closest = lineart_chain_get_closest_cre(rb, \
+ LISTBASE_FOREACH (LinkData *, link, list) { \
+ LineartBoundingArea *sba = (LineartBoundingArea *)link->data; \
+ adjacent_closest = lineart_chain_get_closest_cre(ld, \
sba, \
ec, \
eci, \
occlusion, \
material_mask_bits, \
isec_mask, \
+ shadow_mask, \
loop_id, \
dist, \
&adjacent_new_len, \
@@ -848,65 +894,69 @@ static LineartChainRegisterEntry *lineart_chain_get_closest_cre(LineartRenderBuf
return closest_cre;
}
-void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
+void MOD_lineart_chain_connect(LineartData *ld)
{
LineartEdgeChain *ec;
LineartEdgeChainItem *eci_l, *eci_r;
LineartBoundingArea *ba_l, *ba_r;
LineartChainRegisterEntry *closest_cre_l, *closest_cre_r, *closest_cre;
- float dist = rb->chaining_image_threshold;
+ float dist = ld->conf.chaining_image_threshold;
float dist_l, dist_r;
- int occlusion, reverse_main, loop_id;
- unsigned char material_mask_bits, isec_mask;
+ int reverse_main, loop_id;
+ uint8_t occlusion, material_mask_bits, isec_mask;
+ uint32_t shadow_mask;
ListBase swap = {0};
- if (rb->chaining_image_threshold < 0.0001) {
+ if (ld->conf.chaining_image_threshold < 0.0001) {
return;
}
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
- if (ec->picked) {
+ if (ec->picked || ec->chain.first == ec->chain.last) {
continue;
}
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
loop_id = ec->loop_id;
- if (ec->type == LRT_EDGE_FLAG_LOOSE && (!rb->use_loose_edge_chain)) {
+ if (ec->type == LRT_EDGE_FLAG_LOOSE && (!ld->conf.use_loose_edge_chain)) {
continue;
}
occlusion = ec->level;
material_mask_bits = ec->material_mask_bits;
isec_mask = ec->intersection_mask;
+ shadow_mask = ec->shadow_mask_bits;
eci_l = ec->chain.first;
eci_r = ec->chain.last;
- while ((ba_l = lineart_bounding_area_get_end_point(rb, eci_l)) &&
- (ba_r = lineart_bounding_area_get_end_point(rb, eci_r))) {
- closest_cre_l = lineart_chain_get_closest_cre(rb,
+ while ((ba_l = lineart_bounding_area_get_end_point(ld, eci_l)) &&
+ (ba_r = lineart_bounding_area_get_end_point(ld, eci_r))) {
+ closest_cre_l = lineart_chain_get_closest_cre(ld,
ba_l,
ec,
eci_l,
occlusion,
material_mask_bits,
isec_mask,
+ shadow_mask,
loop_id,
dist,
&dist_l,
NULL);
- closest_cre_r = lineart_chain_get_closest_cre(rb,
+ closest_cre_r = lineart_chain_get_closest_cre(ld,
ba_r,
ec,
eci_r,
occlusion,
material_mask_bits,
isec_mask,
+ shadow_mask,
loop_id,
dist,
&dist_r,
@@ -936,10 +986,10 @@ void MOD_lineart_chain_connect(LineartRenderBuffer *rb)
closest_cre->picked = 1;
closest_cre->ec->picked = 1;
if (closest_cre->is_left) {
- lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 0);
+ lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 0);
}
else {
- lineart_chain_connect(rb, ec, closest_cre->ec, reverse_main, 1);
+ lineart_chain_connect(ld, ec, closest_cre->ec, reverse_main, 1);
}
BLI_remlink(&swap, closest_cre->ec);
eci_l = ec->chain.first;
@@ -969,13 +1019,15 @@ float MOD_lineart_chain_compute_length(LineartEdgeChain *ec)
return offset_accum;
}
-void MOD_lineart_chain_discard_short(LineartRenderBuffer *rb, const float threshold)
+void MOD_lineart_chain_discard_unused(LineartData *ld,
+ const float threshold,
+ uint8_t max_occlusion)
{
LineartEdgeChain *ec, *next_ec;
- for (ec = rb->chains.first; ec; ec = next_ec) {
+ for (ec = ld->chains.first; ec; ec = next_ec) {
next_ec = ec->next;
- if (MOD_lineart_chain_compute_length(ec) < threshold) {
- BLI_remlink(&rb->chains, ec);
+ if (ec->level > max_occlusion || MOD_lineart_chain_compute_length(ec) < threshold) {
+ BLI_remlink(&ld->chains, ec);
}
}
}
@@ -999,9 +1051,9 @@ void MOD_lineart_chain_clear_picked_flag(LineartCache *lc)
}
}
-void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
+void MOD_lineart_smooth_chains(LineartData *ld, float tolerance)
{
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
/* Go through the chain two times, once from each direction. */
for (int times = 0; times < 2; times++) {
for (LineartEdgeChainItem *eci = ec->chain.first, *next_eci = eci->next; eci;
@@ -1067,25 +1119,27 @@ void MOD_lineart_smooth_chains(LineartRenderBuffer *rb, float tolerance)
}
}
-static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBuffer *rb,
+static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartData *ld,
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};
+ /* l: left, r: right, b: bottom, u: top. */
+ float ref_lu[2] = {-1.0f, 1.0f}, ref_lb[2] = {-1.0f, -1.0f}, ref_ru[2] = {1.0f, 1.0f},
+ ref_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);
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lu, ref_lb, isec) > 0);
}
if (!found && eci2->pos[0] > 1.0f) {
- found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, RU, RB, isec) > 0);
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_ru, ref_rb, isec) > 0);
}
if (!found && eci2->pos[1] < -1.0f) {
- found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LB, RB, isec) > 0);
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lb, ref_rb, isec) > 0);
}
if (!found && eci2->pos[1] > 1.0f) {
- found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, LU, RU, isec) > 0);
+ found = (isect_seg_seg_v2_point(eci1->pos, eci2->pos, ref_lu, ref_ru, isec) > 0);
}
if (UNLIKELY(!found)) {
@@ -1097,7 +1151,7 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu
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,
+ LineartEdgeChainItem *eci = lineart_mem_acquire(ld->chain_data_pool,
sizeof(LineartEdgeChainItem));
memcpy(eci, eci1, sizeof(LineartEdgeChainItem));
interp_v3_v3v3(eci->gpos, eci1->gpos, eci2->gpos, gratio);
@@ -1111,22 +1165,22 @@ static LineartEdgeChainItem *lineart_chain_create_crossing_point(LineartRenderBu
((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)
+void MOD_lineart_chain_clip_at_border(LineartData *ld)
{
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;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->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;
+ ec->picked = 1;
}
for (eci = first_eci->next; eci; eci = next_eci) {
next_eci = eci->next;
@@ -1137,9 +1191,9 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
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);
+ new_eci = lineart_chain_create_crossing_point(ld, prev_eci, eci);
- LineartEdgeChain *new_ec = lineart_mem_acquire(rb->chain_data_pool,
+ LineartEdgeChain *new_ec = lineart_mem_acquire(ld->chain_data_pool,
sizeof(LineartEdgeChain));
memcpy(new_ec, ec, sizeof(LineartEdgeChain));
new_ec->chain.first = next_eci;
@@ -1147,7 +1201,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
prev_eci->next = NULL;
ec->chain.last = prev_eci;
BLI_addtail(&ec->chain, new_eci);
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
ec_added = true;
ec = new_ec;
@@ -1156,7 +1210,7 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
continue;
}
/* Stroke comes in. */
- new_eci = lineart_chain_create_crossing_point(rb, eci, prev_eci);
+ new_eci = lineart_chain_create_crossing_point(ld, eci, prev_eci);
ec->chain.first = eci;
eci->prev = NULL;
@@ -1172,25 +1226,25 @@ void MOD_lineart_chain_clip_at_border(LineartRenderBuffer *rb)
}
if ((!ec_added) && is_inside) {
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
}
}
}
-void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshold_rad)
+void MOD_lineart_chain_split_angle(LineartData *ld, float angle_threshold_rad)
{
LineartEdgeChain *ec, *new_ec;
LineartEdgeChainItem *eci, *next_eci, *prev_eci;
ListBase swap = {0};
- swap.first = rb->chains.first;
- swap.last = rb->chains.last;
+ swap.first = ld->chains.first;
+ swap.last = ld->chains.last;
- rb->chains.last = rb->chains.first = NULL;
+ ld->chains.last = ld->chains.first = NULL;
while ((ec = BLI_pophead(&swap)) != NULL) {
ec->next = ec->prev = NULL;
- BLI_addtail(&rb->chains, ec);
+ BLI_addtail(&ld->chains, ec);
LineartEdgeChainItem *first_eci = (LineartEdgeChainItem *)ec->chain.first;
for (eci = first_eci->next; eci; eci = next_eci) {
next_eci = eci->next;
@@ -1203,7 +1257,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
break; /* No need to split at the last point anyway. */
}
if (angle < angle_threshold_rad) {
- new_ec = lineart_chain_create(rb);
+ new_ec = lineart_chain_create(ld);
new_ec->chain.first = eci;
new_ec->chain.last = ec->chain.last;
ec->chain.last = eci->prev;
@@ -1211,7 +1265,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
eci->prev = 0;
/* End the previous one. */
- lineart_chain_append_point(rb,
+ lineart_chain_append_point(ld,
ec,
eci->pos,
eci->gpos,
@@ -1219,6 +1273,7 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
eci->line_type,
ec->level,
eci->material_mask_bits,
+ eci->shadow_mask_bits,
eci->index);
new_ec->object_ref = ec->object_ref;
new_ec->type = ec->type;
@@ -1226,46 +1281,44 @@ void MOD_lineart_chain_split_angle(LineartRenderBuffer *rb, float angle_threshol
new_ec->loop_id = ec->loop_id;
new_ec->intersection_mask = ec->intersection_mask;
new_ec->material_mask_bits = ec->material_mask_bits;
+ new_ec->shadow_mask_bits = ec->shadow_mask_bits;
ec = new_ec;
}
}
}
}
-void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
- float dist,
- bool use_custom_camera)
+void MOD_lineart_chain_offset_towards_camera(LineartData *ld, 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);
+ copy_v3fl_v3db(cam, ld->conf.camera_pos);
}
else {
- copy_v3fl_v3db(cam, rb->active_camera_pos);
+ copy_v3fl_v3db(cam, ld->conf.active_camera_pos);
}
- if (rb->cam_is_persp) {
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ if (ld->conf.cam_is_persp) {
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->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));
+ mul_v3_fl(dir, MIN2(dist, orig_len - ld->conf.near_clip));
add_v3_v3(eci->gpos, dir);
}
}
}
else {
- LISTBASE_FOREACH (LineartEdgeChain *, ec, &rb->chains) {
+ copy_v3fl_v3db(view, ld->conf.view_vector);
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
LISTBASE_FOREACH (LineartEdgeChainItem *, eci, &ec->chain) {
sub_v3_v3v3(dir, cam, eci->gpos);
- float len_lim = dot_v3v3(view, dir) - rb->near_clip;
+ float len_lim = dot_v3v3(view, dir) - ld->conf.near_clip;
normalize_v3_v3(view_clamp, view);
mul_v3_fl(view_clamp, MIN2(dist, len_lim));
add_v3_v3(eci->gpos, view_clamp);
@@ -1273,3 +1326,19 @@ void MOD_lineart_chain_offset_towards_camera(LineartRenderBuffer *rb,
}
}
}
+
+void MOD_lineart_chain_find_silhouette_backdrop_objects(LineartData *ld)
+{
+ LISTBASE_FOREACH (LineartEdgeChain *, ec, &ld->chains) {
+ if (ec->type == LRT_EDGE_FLAG_CONTOUR &&
+ ec->shadow_mask_bits & LRT_SHADOW_SILHOUETTE_ERASED_GROUP) {
+ uint32_t target = ec->shadow_mask_bits & LRT_OBINDEX_HIGHER;
+ LineartElementLinkNode *eln = lineart_find_matching_eln(&ld->geom.line_buffer_pointers,
+ target);
+ if (!eln) {
+ continue;
+ }
+ ec->silhouette_backdrop = eln->object_ref;
+ }
+ }
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 016b70cedb0..874da3b88c9 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -39,6 +39,7 @@
#include "DNA_camera_types.h"
#include "DNA_collection_types.h"
#include "DNA_gpencil_types.h"
+#include "DNA_light_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -46,105 +47,117 @@
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
-#include "bmesh.h"
-#include "bmesh_class.h"
-#include "bmesh_tools.h"
-
#include "lineart_intern.h"
-static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
- LineartEdge *e);
-
-static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
+typedef struct LineartIsecSingle {
+ float v1[3], v2[3];
+ LineartTriangle *tri1, *tri2;
+} LineartIsecSingle;
+
+typedef struct LineartIsecThread {
+ int thread_id;
+
+ /* Scheduled work range. */
+ LineartElementLinkNode *pending_from;
+ LineartElementLinkNode *pending_to;
+ int index_from;
+ int index_to;
+
+ /* Thread intersection result data. */
+ LineartIsecSingle *array;
+ int current;
+ int max;
+ int count_test;
+
+ /* For individual thread reference.*/
+ LineartData *ld;
+} LineartIsecThread;
+
+typedef struct LineartIsecData {
+ LineartData *ld;
+ LineartIsecThread *threads;
+ int thread_count;
+} LineartIsecData;
+
+static void lineart_bounding_area_link_edge(LineartData *ld,
LineartBoundingArea *root_ba,
LineartEdge *e);
-static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this,
- LineartEdge *e,
- double x,
- double y,
- double k,
- int positive_x,
- int positive_y,
- double *next_x,
- double *next_y);
-
-static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
- LineartEdge *e,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend);
-
-static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
- LineartBoundingArea *root_ba,
- LineartTriangle *tri,
- double *LRUB,
- int recursive,
- int recursive_level,
- bool do_intersection);
+static bool lineart_get_edge_bounding_areas(
+ LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend);
-static bool lineart_triangle_edge_image_space_occlusion(SpinLock *spl,
- const LineartTriangle *tri,
+static bool lineart_triangle_edge_image_space_occlusion(const LineartTriangle *tri,
const LineartEdge *e,
const double *override_camera_loc,
const bool override_cam_is_persp,
const bool allow_overlapping_edges,
- const double vp[4][4],
- const double *camera_dir,
+ const double m_view_projection[4][4],
+ const double camera_dir[3],
const float cam_shift_x,
const float cam_shift_y,
double *from,
double *to);
-static void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e);
+static void lineart_bounding_area_link_triangle(LineartData *ld,
+ LineartBoundingArea *root_ba,
+ LineartTriangle *tri,
+ double l_r_u_b[4],
+ int recursive,
+ int recursive_level,
+ bool do_intersection,
+ struct LineartIsecThread *th);
+
+static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive);
+
+static void lineart_free_bounding_area_memories(LineartData *ld);
static LineartCache *lineart_init_cache(void);
-static void lineart_discard_segment(LineartRenderBuffer *rb, LineartEdgeSegment *es)
+static void lineart_discard_segment(LineartData *ld, LineartEdgeSegment *es)
{
- BLI_spin_lock(&rb->lock_cuts);
+ BLI_spin_lock(&ld->lock_cuts);
memset(es, 0, sizeof(LineartEdgeSegment));
/* Storing the node for potentially reuse the memory for new segment data.
* Line Art data is not freed after all calculations are done. */
- BLI_addtail(&rb->wasted_cuts, es);
+ BLI_addtail(&ld->wasted_cuts, es);
- BLI_spin_unlock(&rb->lock_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
}
-static LineartEdgeSegment *lineart_give_segment(LineartRenderBuffer *rb)
+static LineartEdgeSegment *lineart_give_segment(LineartData *ld)
{
- BLI_spin_lock(&rb->lock_cuts);
+ BLI_spin_lock(&ld->lock_cuts);
/* See if there is any already allocated memory we can reuse. */
- if (rb->wasted_cuts.first) {
- LineartEdgeSegment *es = (LineartEdgeSegment *)BLI_pophead(&rb->wasted_cuts);
- BLI_spin_unlock(&rb->lock_cuts);
+ if (ld->wasted_cuts.first) {
+ LineartEdgeSegment *es = (LineartEdgeSegment *)BLI_pophead(&ld->wasted_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
memset(es, 0, sizeof(LineartEdgeSegment));
return es;
}
- BLI_spin_unlock(&rb->lock_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
/* Otherwise allocate some new memory. */
- return (LineartEdgeSegment *)lineart_mem_acquire_thread(&rb->render_data_pool,
+ return (LineartEdgeSegment *)lineart_mem_acquire_thread(ld->edge_data_pool,
sizeof(LineartEdgeSegment));
}
/**
* Cuts the edge in image space and mark occlusion level for each segment.
*/
-static void lineart_edge_cut(LineartRenderBuffer *rb,
- LineartEdge *e,
- double start,
- double end,
- uchar material_mask_bits,
- uchar mat_occlusion)
+void lineart_edge_cut(LineartData *ld,
+ LineartEdge *e,
+ double start,
+ double end,
+ uchar material_mask_bits,
+ uchar mat_occlusion,
+ uint32_t shadow_bits)
{
- LineartEdgeSegment *es, *ies, *next_es, *prev_es;
+ LineartEdgeSegment *seg, *i_seg, *next_seg, *prev_seg;
LineartEdgeSegment *cut_start_before = 0, *cut_end_before = 0;
- LineartEdgeSegment *ns = 0, *ns2 = 0;
+ LineartEdgeSegment *new_seg1 = 0, *new_seg2 = 0;
int untouched = 0;
/* If for some reason the occlusion function may give a result that has zero length, or reversed
@@ -171,132 +184,159 @@ static void lineart_edge_cut(LineartRenderBuffer *rb,
/* Begin looking for starting position of the segment. */
/* Not using a list iteration macro because of it more clear when using for loops to iterate
* through the segments. */
- for (es = e->segments.first; es; es = es->next) {
- if (LRT_DOUBLE_CLOSE_ENOUGH(es->at, start)) {
- cut_start_before = es;
- ns = cut_start_before;
+ for (seg = e->segments.first; seg; seg = seg->next) {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, start)) {
+ cut_start_before = seg;
+ new_seg1 = cut_start_before;
break;
}
- if (es->next == NULL) {
+ if (seg->next == NULL) {
break;
}
- ies = es->next;
- if (ies->at > start + 1e-09 && start > es->at) {
- cut_start_before = ies;
- ns = lineart_give_segment(rb);
+ i_seg = seg->next;
+ if (i_seg->ratio > start + 1e-09 && start > seg->ratio) {
+ cut_start_before = i_seg;
+ new_seg1 = lineart_give_segment(ld);
break;
}
}
if (!cut_start_before && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
untouched = 1;
}
- for (es = cut_start_before; es; es = es->next) {
- /* We tried to cut at existing cutting point (e.g. where the line's occluded by a triangle
+ for (seg = cut_start_before; seg; seg = seg->next) {
+ /* We tried to cut ratio existing cutting point (e.g. where the line's occluded by a triangle
* strip). */
- if (LRT_DOUBLE_CLOSE_ENOUGH(es->at, end)) {
- cut_end_before = es;
- ns2 = cut_end_before;
+ if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, end)) {
+ cut_end_before = seg;
+ new_seg2 = cut_end_before;
break;
}
- /* This check is to prevent `es->at == 1.0` (where we don't need to cut because we are at the
- * end point). */
- if (!es->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
- cut_end_before = es;
- ns2 = cut_end_before;
+ /* This check is to prevent `es->ratio == 1.0` (where we don't need to cut because we are ratio
+ * the end point). */
+ if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
+ cut_end_before = seg;
+ new_seg2 = cut_end_before;
untouched = 1;
break;
}
/* When an actual cut is needed in the line. */
- if (es->at > end) {
- cut_end_before = es;
- ns2 = lineart_give_segment(rb);
+ if (seg->ratio > end) {
+ cut_end_before = seg;
+ new_seg2 = lineart_give_segment(ld);
break;
}
}
/* When we still can't find any existing cut in the line, we allocate new ones. */
- if (ns == NULL) {
- ns = lineart_give_segment(rb);
+ if (new_seg1 == NULL) {
+ new_seg1 = lineart_give_segment(ld);
}
- if (ns2 == NULL) {
+ if (new_seg2 == NULL) {
if (untouched) {
- ns2 = ns;
- cut_end_before = ns2;
+ new_seg2 = new_seg1;
+ cut_end_before = new_seg2;
}
else {
- ns2 = lineart_give_segment(rb);
+ new_seg2 = lineart_give_segment(ld);
}
}
if (cut_start_before) {
- if (cut_start_before != ns) {
+ if (cut_start_before != new_seg1) {
/* Insert cutting points for when a new cut is needed. */
- ies = cut_start_before->prev ? cut_start_before->prev : NULL;
- ns->occlusion = ies ? ies->occlusion : 0;
- ns->material_mask_bits = ies->material_mask_bits;
- BLI_insertlinkbefore(&e->segments, cut_start_before, ns);
+ i_seg = cut_start_before->prev ? cut_start_before->prev : NULL;
+ if (i_seg) {
+ new_seg1->occlusion = i_seg->occlusion;
+ new_seg1->material_mask_bits = i_seg->material_mask_bits;
+ new_seg1->shadow_mask_bits = i_seg->shadow_mask_bits;
+ }
+ BLI_insertlinkbefore(&e->segments, cut_start_before, new_seg1);
}
/* Otherwise we already found a existing cutting point, no need to insert a new one. */
}
else {
/* We have yet to reach a existing cutting point even after we searched the whole line, so we
* append the new cut to the end. */
- ies = e->segments.last;
- ns->occlusion = ies->occlusion;
- ns->material_mask_bits = ies->material_mask_bits;
- BLI_addtail(&e->segments, ns);
+ i_seg = e->segments.last;
+ new_seg1->occlusion = i_seg->occlusion;
+ new_seg1->material_mask_bits = i_seg->material_mask_bits;
+ new_seg1->shadow_mask_bits = i_seg->shadow_mask_bits;
+ BLI_addtail(&e->segments, new_seg1);
}
if (cut_end_before) {
/* The same manipulation as on "cut_start_before". */
- if (cut_end_before != ns2) {
- ies = cut_end_before->prev ? cut_end_before->prev : NULL;
- ns2->occlusion = ies ? ies->occlusion : 0;
- ns2->material_mask_bits = ies ? ies->material_mask_bits : 0;
- BLI_insertlinkbefore(&e->segments, cut_end_before, ns2);
+ if (cut_end_before != new_seg2) {
+ i_seg = cut_end_before->prev ? cut_end_before->prev : NULL;
+ if (i_seg) {
+ new_seg2->occlusion = i_seg->occlusion;
+ new_seg2->material_mask_bits = i_seg->material_mask_bits;
+ new_seg2->shadow_mask_bits = i_seg->shadow_mask_bits;
+ }
+ BLI_insertlinkbefore(&e->segments, cut_end_before, new_seg2);
}
}
else {
- ies = e->segments.last;
- ns2->occlusion = ies->occlusion;
- ns2->material_mask_bits = ies->material_mask_bits;
- BLI_addtail(&e->segments, ns2);
+ i_seg = e->segments.last;
+ new_seg2->occlusion = i_seg->occlusion;
+ new_seg2->material_mask_bits = i_seg->material_mask_bits;
+ new_seg2->shadow_mask_bits = i_seg->shadow_mask_bits;
+ if (!untouched) {
+ BLI_addtail(&e->segments, new_seg2);
+ }
}
/* If we touched the cut list, we assign the new cut position based on new cut position,
* this way we accommodate precision lost due to multiple cut inserts. */
- ns->at = start;
+ new_seg1->ratio = start;
if (!untouched) {
- ns2->at = end;
+ new_seg2->ratio = end;
}
else {
/* For the convenience of the loop below. */
- ns2 = ns2->next;
+ new_seg2 = new_seg2->next;
}
/* Register 1 level of occlusion for all touched segments. */
- for (es = ns; es && es != ns2; es = es->next) {
- es->occlusion += mat_occlusion;
- es->material_mask_bits |= material_mask_bits;
+ for (seg = new_seg1; seg && seg != new_seg2; seg = seg->next) {
+ seg->occlusion += mat_occlusion;
+ seg->material_mask_bits |= material_mask_bits;
+
+ /* The enclosed shape flag will override regular lit/shaded
+ * flags. See LineartEdgeSegment::shadow_mask_bits for details. */
+ if (shadow_bits == LRT_SHADOW_MASK_ENCLOSED_SHAPE) {
+ if (seg->shadow_mask_bits & LRT_SHADOW_MASK_LIT || e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
+ seg->shadow_mask_bits &= ~LRT_SHADOW_MASK_LIT;
+ seg->shadow_mask_bits |= LRT_SHADOW_MASK_INHIBITED;
+ }
+ else if (seg->shadow_mask_bits & LRT_SHADOW_MASK_SHADED) {
+ seg->shadow_mask_bits &= ~LRT_SHADOW_MASK_SHADED;
+ seg->shadow_mask_bits |= LRT_SHADOW_MASK_LIT;
+ }
+ }
+ else {
+ seg->shadow_mask_bits |= shadow_bits;
+ }
}
/* Reduce adjacent cutting points of the same level, which saves memory. */
- char min_occ = 127;
- prev_es = NULL;
- for (es = e->segments.first; es; es = next_es) {
- next_es = es->next;
-
- if (prev_es && prev_es->occlusion == es->occlusion &&
- prev_es->material_mask_bits == es->material_mask_bits) {
- BLI_remlink(&e->segments, es);
+ int8_t min_occ = 127;
+ prev_seg = NULL;
+ for (seg = e->segments.first; seg; seg = next_seg) {
+ next_seg = seg->next;
+
+ if (prev_seg && prev_seg->occlusion == seg->occlusion &&
+ prev_seg->material_mask_bits == seg->material_mask_bits &&
+ prev_seg->shadow_mask_bits == seg->shadow_mask_bits) {
+ BLI_remlink(&e->segments, seg);
/* This puts the node back to the render buffer, if more cut happens, these unused nodes get
* picked first. */
- lineart_discard_segment(rb, es);
+ lineart_discard_segment(ld, seg);
continue;
}
- min_occ = MIN2(min_occ, es->occlusion);
+ min_occ = MIN2(min_occ, seg->occlusion);
- prev_es = es;
+ prev_seg = seg;
}
e->min_occ = min_occ;
}
@@ -306,35 +346,18 @@ static void lineart_edge_cut(LineartRenderBuffer *rb,
*/
BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, LineartTriangle *tri)
{
- LineartVertIntersection *v1 = (void *)e->v1;
- LineartVertIntersection *v2 = (void *)e->v2;
- return ((v1->base.flag && v1->intersecting_with == tri) ||
- (v2->base.flag && v2->intersecting_with == tri));
+ return (((e->target_reference & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference) ||
+ (((e->target_reference >> 32) & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference));
}
-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);
- memcpy(new_array, ba->linked_triangles, sizeof(LineartTriangle *) * ba->max_triangle_count);
- ba->max_triangle_count *= 2;
- ba->linked_triangles = new_array;
- }
- ba->linked_triangles[ba->triangle_count] = tri;
- ba->triangle_count++;
+static void lineart_bounding_area_triangle_reallocate(LineartBoundingArea *ba)
+{
+ ba->max_triangle_count *= 2;
+ ba->linked_triangles = MEM_recallocN(ba->linked_triangles,
+ sizeof(LineartTriangle *) * ba->max_triangle_count);
}
-static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
- LineartBoundingArea *ba,
- LineartEdge *e)
+static void lineart_bounding_area_line_add(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
@@ -343,36 +366,23 @@ static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
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);
+ LineartEdge **new_array = MEM_mallocN(sizeof(LineartEdge *) * ba->max_line_count * 2,
+ "new ba_line_array");
memcpy(new_array, ba->linked_lines, sizeof(LineartEdge *) * ba->max_line_count);
ba->max_line_count *= 2;
+ MEM_freeN(ba->linked_lines);
ba->linked_lines = new_array;
}
ba->linked_lines[ba->line_count] = e;
ba->line_count++;
}
-static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *e, int thread_id)
+static void lineart_occlusion_single_line(LineartData *ld, LineartEdge *e, int thread_id)
{
- double x = e->v1->fbcoord[0], y = e->v1->fbcoord[1];
- LineartBoundingArea *ba = lineart_edge_first_bounding_area(rb, e);
- LineartBoundingArea *nba = ba;
LineartTriangleThread *tri;
-
- /* These values are used for marching along the line. */
double l, r;
- double k = (e->v2->fbcoord[1] - e->v1->fbcoord[1]) /
- (e->v2->fbcoord[0] - e->v1->fbcoord[0] + 1e-30);
- int positive_x = (e->v2->fbcoord[0] - e->v1->fbcoord[0]) > 0 ?
- 1 :
- (e->v2->fbcoord[0] == e->v1->fbcoord[0] ? 0 : -1);
- int positive_y = (e->v2->fbcoord[1] - e->v1->fbcoord[1]) > 0 ?
- 1 :
- (e->v2->fbcoord[1] == e->v1->fbcoord[1] ? 0 : -1);
-
- while (nba) {
-
+ LRT_EDGE_BA_MARCHING_BEGIN(e->v1->fbcoord, e->v2->fbcoord)
+ {
for (int i = 0; i < nba->triangle_count; i++) {
tri = (LineartTriangleThread *)nba->linked_triangles[i];
/* If we are already testing the line in this thread, then don't do it. */
@@ -385,49 +395,48 @@ static void lineart_occlusion_single_line(LineartRenderBuffer *rb, LineartEdge *
continue;
}
tri->testing_e[thread_id] = e;
- if (lineart_triangle_edge_image_space_occlusion(&rb->lock_task,
- (const LineartTriangle *)tri,
+ if (lineart_triangle_edge_image_space_occlusion((const LineartTriangle *)tri,
e,
- rb->camera_pos,
- rb->cam_is_persp,
- rb->allow_overlapping_edges,
- rb->view_projection,
- rb->view_vector,
- rb->shift_x,
- rb->shift_y,
+ ld->conf.camera_pos,
+ ld->conf.cam_is_persp,
+ ld->conf.allow_overlapping_edges,
+ ld->conf.view_projection,
+ ld->conf.view_vector,
+ ld->conf.shift_x,
+ ld->conf.shift_y,
&l,
&r)) {
- lineart_edge_cut(rb, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion);
- if (e->min_occ > rb->max_occlusion_level) {
+ lineart_edge_cut(ld, e, l, r, tri->base.material_mask_bits, tri->base.mat_occlusion, 0);
+ if (e->min_occ > ld->conf.max_occlusion_level) {
/* No need to calculate any longer on this line because no level more than set value is
* going to show up in the rendered result. */
return;
}
}
}
- /* Marching along `e->v1` to `e->v2`, searching each possible bounding areas it may touch. */
- nba = lineart_bounding_area_next(nba, e, x, y, k, positive_x, positive_y, &x, &y);
+ LRT_EDGE_BA_MARCHING_NEXT(e->v1->fbcoord, e->v2->fbcoord)
}
+ LRT_EDGE_BA_MARCHING_END
}
-static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRenderTaskInfo *rti)
+static int lineart_occlusion_make_task_info(LineartData *ld, LineartRenderTaskInfo *rti)
{
int res = 0;
int starting_index;
- BLI_spin_lock(&rb->lock_task);
+ BLI_spin_lock(&ld->lock_task);
- starting_index = rb->scheduled_count;
- rb->scheduled_count += LRT_THREAD_EDGE_COUNT;
+ starting_index = ld->scheduled_count;
+ ld->scheduled_count += LRT_THREAD_EDGE_COUNT;
- BLI_spin_unlock(&rb->lock_task);
+ BLI_spin_unlock(&ld->lock_task);
- if (starting_index >= rb->pending_edges.next) {
+ if (starting_index >= ld->pending_edges.next) {
res = 0;
}
else {
- rti->pending_edges.array = &rb->pending_edges.array[starting_index];
- int remaining = rb->pending_edges.next - starting_index;
+ rti->pending_edges.array = &ld->pending_edges.array[starting_index];
+ int remaining = ld->pending_edges.next - starting_index;
rti->pending_edges.max = MIN2(remaining, LRT_THREAD_EDGE_COUNT);
res = 1;
}
@@ -437,13 +446,13 @@ static int lineart_occlusion_make_task_info(LineartRenderBuffer *rb, LineartRend
static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartRenderTaskInfo *rti)
{
- LineartRenderBuffer *rb = rti->rb;
+ LineartData *ld = rti->ld;
LineartEdge *eip;
- while (lineart_occlusion_make_task_info(rb, rti)) {
+ while (lineart_occlusion_make_task_info(ld, rti)) {
for (int i = 0; i < rti->pending_edges.max; i++) {
eip = rti->pending_edges.array[i];
- lineart_occlusion_single_line(rb, eip, rti->thread_id);
+ lineart_occlusion_single_line(ld, eip, rti->thread_id);
}
}
}
@@ -453,9 +462,9 @@ static void lineart_occlusion_worker(TaskPool *__restrict UNUSED(pool), LineartR
* #MOD_lineart_compute_feature_lines function.
* This function handles all occlusion calculation.
*/
-static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
+void lineart_main_occlusion_begin(LineartData *ld)
{
- int thread_count = rb->thread_count;
+ int thread_count = ld->thread_count;
LineartRenderTaskInfo *rti = MEM_callocN(sizeof(LineartRenderTaskInfo) * thread_count,
"Task Pool");
int i;
@@ -464,7 +473,7 @@ static void lineart_main_occlusion_begin(LineartRenderBuffer *rb)
for (i = 0; i < thread_count; i++) {
rti[i].thread_id = i;
- rti[i].rb = rb;
+ rti[i].ld = ld;
BLI_task_pool_push(tp, (TaskRunFunction)lineart_occlusion_worker, &rti[i], 0, NULL);
}
BLI_task_pool_work_and_wait(tp);
@@ -485,10 +494,10 @@ static bool lineart_point_inside_triangle(const double v[2],
const double v1[2],
const double v2[2])
{
- double cl, c;
+ double cl, c, cl0;
cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
- c = cl;
+ c = cl0 = cl;
cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
if (c * cl <= 0) {
@@ -504,8 +513,7 @@ static bool lineart_point_inside_triangle(const double v[2],
c = cl;
- cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
- if (c * cl <= 0) {
+ if (c * cl0 <= 0) {
return false;
}
@@ -554,6 +562,12 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2]
return 0;
}
+enum LineartPointTri {
+ LRT_OUTSIDE_TRIANGLE = 0,
+ LRT_ON_TRIANGLE = 1,
+ LRT_INSIDE_TRIANGLE = 2,
+};
+
/**
* Same algorithm as lineart_point_inside_triangle(), but returns differently:
* 0-outside 1-on the edge 2-inside.
@@ -564,7 +578,7 @@ static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[
double r;
if (lineart_point_on_line_segment(v, v0, v1) || lineart_point_on_line_segment(v, v1, v2) ||
lineart_point_on_line_segment(v, v2, v0)) {
- return 1;
+ return LRT_ON_TRIANGLE;
}
cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
@@ -572,28 +586,28 @@ static int lineart_point_triangle_relation(double v[2], double v0[2], double v1[
cl = (v1[0] - v[0]) * (v2[1] - v[1]) - (v1[1] - v[1]) * (v2[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
c = cl;
cl = (v2[0] - v[0]) * (v0[1] - v[1]) - (v2[1] - v[1]) * (v0[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
c = cl;
cl = (v0[0] - v[0]) * (v1[1] - v[1]) - (v0[1] - v[1]) * (v1[0] - v[0]);
if ((r = c * cl) < 0) {
- return 0;
+ return LRT_OUTSIDE_TRIANGLE;
}
if (r == 0) {
- return 1;
+ return LRT_ON_TRIANGLE;
}
- return 2;
+ return LRT_INSIDE_TRIANGLE;
}
/**
@@ -641,17 +655,17 @@ static bool lineart_point_inside_triangle3d(double v[3], double v0[3], double v1
* The following `lineart_memory_get_XXX_space` functions are for allocating new memory for some
* modified geometries in the culling stage.
*/
-static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartData *ld)
{
LineartElementLinkNode *eln;
/* We don't need to allocate a whole bunch of triangles because the amount of clipped triangles
* are relatively small. */
- LineartTriangle *render_triangles = lineart_mem_acquire(&rb->render_data_pool,
- 64 * rb->triangle_size);
+ LineartTriangle *render_triangles = lineart_mem_acquire(&ld->render_data_pool,
+ 64 * ld->sizeof_triangle);
- eln = lineart_list_append_pointer_pool_sized(&rb->triangle_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.triangle_buffer_pointers,
+ &ld->render_data_pool,
render_triangles,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
@@ -660,15 +674,15 @@ static LineartElementLinkNode *lineart_memory_get_triangle_space(LineartRenderBu
return eln;
}
-static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_vert_space(LineartData *ld)
{
LineartElementLinkNode *eln;
- LineartVert *render_vertices = lineart_mem_acquire(&rb->render_data_pool,
+ LineartVert *render_vertices = lineart_mem_acquire(&ld->render_data_pool,
sizeof(LineartVert) * 64);
- eln = lineart_list_append_pointer_pool_sized(&rb->vertex_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.vertex_buffer_pointers,
+ &ld->render_data_pool,
render_vertices,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
@@ -677,18 +691,18 @@ static LineartElementLinkNode *lineart_memory_get_vert_space(LineartRenderBuffer
return eln;
}
-static LineartElementLinkNode *lineart_memory_get_edge_space(LineartRenderBuffer *rb)
+static LineartElementLinkNode *lineart_memory_get_edge_space(LineartData *ld)
{
LineartElementLinkNode *eln;
- LineartEdge *render_edges = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge) * 64);
+ LineartEdge *render_edges = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdge) * 64);
- eln = lineart_list_append_pointer_pool_sized(&rb->line_buffer_pointers,
- &rb->render_data_pool,
+ eln = lineart_list_append_pointer_pool_sized(&ld->geom.line_buffer_pointers,
+ ld->edge_data_pool,
render_edges,
sizeof(LineartElementLinkNode));
eln->element_count = 64;
- eln->crease_threshold = rb->crease_threshold;
+ eln->crease_threshold = ld->conf.crease_threshold;
eln->flags |= LRT_ELEMENT_IS_ADDITIONAL;
return eln;
@@ -699,8 +713,11 @@ static void lineart_triangle_post(LineartTriangle *tri, LineartTriangle *orig)
/* Just re-assign normal and set cull flag. */
copy_v3_v3_db(tri->gn, orig->gn);
tri->flags = LRT_CULL_GENERATED;
+ tri->intersection_mask = orig->intersection_mask;
tri->material_mask_bits = orig->material_mask_bits;
tri->mat_occlusion = orig->mat_occlusion;
+ tri->intersection_priority = orig->intersection_priority;
+ tri->target_reference = orig->target_reference;
}
static void lineart_triangle_set_cull_flag(LineartTriangle *tri, uchar flag)
@@ -729,15 +746,15 @@ static void lineart_discard_duplicated_edges(LineartEdge *old_e)
* Does near-plane cut on 1 triangle only. When cutting with far-plane, the camera vectors gets
* reversed by the caller so don't need to implement one in a different direction.
*/
-static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
+static void lineart_triangle_cull_single(LineartData *ld,
LineartTriangle *tri,
int in0,
int in1,
int in2,
- double *cam_pos,
- double *view_dir,
+ double cam_pos[3],
+ double view_dir[3],
bool allow_boundaries,
- double (*vp)[4],
+ double m_view_projection[4][4],
Object *ob,
int *r_v_count,
int *r_e_count,
@@ -746,7 +763,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
LineartElementLinkNode *e_eln,
LineartElementLinkNode *t_eln)
{
- double vv1[3], vv2[3], dot1, dot2;
+ double span_v1[3], span_v2[3], dot_v1, dot_v2;
double a;
int v_count = *r_v_count;
int e_count = *r_e_count;
@@ -755,7 +772,7 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
LineartEdge *new_e, *e, *old_e;
LineartEdgeSegment *es;
- LineartTriangleAdjacent *ta;
+ LineartTriangleAdjacent *tri_adj;
if (tri->flags & (LRT_CULL_USED | LRT_CULL_GENERATED | LRT_CULL_DISCARD)) {
return;
@@ -763,11 +780,12 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
/* See definition of tri->intersecting_verts and the usage in
* lineart_geometry_object_load() for details. */
- ta = (void *)tri->intersecting_verts;
+ tri_adj = (void *)tri->intersecting_verts;
LineartVert *vt = &((LineartVert *)v_eln->pointer)[v_count];
- LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + rb->triangle_size * t_count);
- LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) + rb->triangle_size * (t_count + 1));
+ LineartTriangle *tri1 = (void *)(((uchar *)t_eln->pointer) + ld->sizeof_triangle * t_count);
+ LineartTriangle *tri2 = (void *)(((uchar *)t_eln->pointer) +
+ ld->sizeof_triangle * (t_count + 1));
new_e = &((LineartEdge *)e_eln->pointer)[e_count];
/* Init `edge` to the last `edge` entry. */
@@ -777,12 +795,12 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
new_e = &((LineartEdge *)e_eln->pointer)[e_count]; \
e_count++; \
e = new_e; \
- es = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeSegment)); \
+ es = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartEdgeSegment)); \
BLI_addtail(&e->segments, es);
#define SELECT_EDGE(e_num, v1_link, v2_link, new_tri) \
- if (ta->e[e_num]) { \
- old_e = ta->e[e_num]; \
+ if (tri_adj->e[e_num]) { \
+ old_e = tri_adj->e[e_num]; \
new_flag = old_e->flags; \
old_e->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
lineart_discard_duplicated_edges(old_e); \
@@ -795,28 +813,28 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
e->object_ref = ob; \
e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \
e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \
- lineart_add_edge_to_array(&rb->pending_edges, e); \
+ lineart_add_edge_to_array(&ld->pending_edges, e); \
}
#define RELINK_EDGE(e_num, new_tri) \
- if (ta->e[e_num]) { \
- old_e = ta->e[e_num]; \
+ if (tri_adj->e[e_num]) { \
+ old_e = tri_adj->e[e_num]; \
old_e->t1 = ((old_e->t1 == tri) ? (new_tri) : (old_e->t1)); \
old_e->t2 = ((old_e->t2 == tri) ? (new_tri) : (old_e->t2)); \
}
#define REMOVE_TRIANGLE_EDGE \
- if (ta->e[0]) { \
- ta->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[0]); \
+ if (tri_adj->e[0]) { \
+ tri_adj->e[0]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[0]); \
} \
- if (ta->e[1]) { \
- ta->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[1]); \
+ if (tri_adj->e[1]) { \
+ tri_adj->e[1]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[1]); \
} \
- if (ta->e[2]) { \
- ta->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
- lineart_discard_duplicated_edges(ta->e[2]); \
+ if (tri_adj->e[2]) { \
+ tri_adj->e[2]->flags = LRT_EDGE_FLAG_CHAIN_PICKED; \
+ lineart_discard_duplicated_edges(tri_adj->e[2]); \
}
switch (in0 + in1 + in2) {
@@ -856,32 +874,32 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
if (!in0) {
/* Cut point for line 2---|-----0. */
- sub_v3_v3v3_db(vv1, tri->v[0]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
/* Assign it to a new point. */
interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a);
- mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
+ mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
vt[0].index = tri->v[2]->index;
/* Cut point for line 1---|-----0. */
- sub_v3_v3v3_db(vv1, tri->v[0]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[0]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
/* Assign it to another new point. */
interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a);
- mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
+ mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
vt[1].index = tri->v[1]->index;
/* New line connecting two new points. */
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
/* NOTE: inverting `e->v1/v2` (left/right point) doesn't matter as long as
* `tri->edge` and `tri->v` has the same sequence. and the winding direction
@@ -909,28 +927,28 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
t_count += 1;
}
else if (!in2) {
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a);
- mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
+ mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
vt[0].index = tri->v[0]->index;
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a);
- mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
+ mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
vt[1].index = tri->v[1]->index;
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[0];
e->v2 = &vt[1];
@@ -950,28 +968,28 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
t_count += 1;
}
else if (!in1) {
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a);
- mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
+ mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
vt[0].index = tri->v[2]->index;
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a);
- mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
+ mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
vt[1].index = tri->v[0]->index;
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1021,32 +1039,32 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
*/
if (in0) {
/* Cut point for line 0---|------1. */
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot2 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v2 / (dot_v1 + dot_v2);
/* Assign to a new point. */
interp_v3_v3v3_db(vt[0].gloc, tri->v[0]->gloc, tri->v[1]->gloc, a);
- mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
+ mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
vt[0].index = tri->v[0]->index;
/* Cut point for line 0---|------2. */
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot2 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v2 / (dot_v1 + dot_v2);
/* Assign to other new point. */
interp_v3_v3v3_db(vt[1].gloc, tri->v[0]->gloc, tri->v[2]->gloc, a);
- mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
+ mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
vt[1].index = tri->v[0]->index;
/* New line connects two new points. */
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1077,28 +1095,28 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
}
else if (in1) {
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[2]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[2]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[1]->gloc, tri->v[2]->gloc, a);
- mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
+ mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
vt[0].index = tri->v[1]->index;
- sub_v3_v3v3_db(vv1, tri->v[1]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[1]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[1]->gloc, tri->v[0]->gloc, a);
- mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
+ mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
vt[1].index = tri->v[1]->index;
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1126,28 +1144,28 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
}
else if (in2) {
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[0]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[0]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[0].gloc, tri->v[2]->gloc, tri->v[0]->gloc, a);
- mul_v4_m4v3_db(vt[0].fbcoord, vp, vt[0].gloc);
+ mul_v4_m4v3_db(vt[0].fbcoord, m_view_projection, vt[0].gloc);
vt[0].index = tri->v[2]->index;
- sub_v3_v3v3_db(vv1, tri->v[2]->gloc, cam_pos);
- sub_v3_v3v3_db(vv2, cam_pos, tri->v[1]->gloc);
- dot1 = dot_v3v3_db(vv1, view_dir);
- dot2 = dot_v3v3_db(vv2, view_dir);
- a = dot1 / (dot1 + dot2);
+ sub_v3_v3v3_db(span_v1, tri->v[2]->gloc, cam_pos);
+ sub_v3_v3v3_db(span_v2, cam_pos, tri->v[1]->gloc);
+ dot_v1 = dot_v3v3_db(span_v1, view_dir);
+ dot_v2 = dot_v3v3_db(span_v2, view_dir);
+ a = dot_v1 / (dot_v1 + dot_v2);
interp_v3_v3v3_db(vt[1].gloc, tri->v[2]->gloc, tri->v[1]->gloc, a);
- mul_v4_m4v3_db(vt[1].fbcoord, vp, vt[1].gloc);
+ mul_v4_m4v3_db(vt[1].fbcoord, m_view_projection, vt[1].gloc);
vt[1].index = tri->v[2]->index;
INCREASE_EDGE
if (allow_boundaries) {
e->flags = LRT_EDGE_FLAG_CONTOUR;
- lineart_add_edge_to_array(&rb->pending_edges, e);
+ lineart_add_edge_to_array(&ld->pending_edges, e);
}
e->v1 = &vt[1];
e->v2 = &vt[0];
@@ -1191,22 +1209,22 @@ static void lineart_triangle_cull_single(LineartRenderBuffer *rb,
* new topology that represents the trimmed triangle. (which then became a triangle or a square
* formed by two triangles)
*/
-static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
+void lineart_main_cull_triangles(LineartData *ld, bool clip_far)
{
LineartTriangle *tri;
LineartElementLinkNode *v_eln, *t_eln, *e_eln;
- double(*vp)[4] = rb->view_projection;
+ double(*m_view_projection)[4] = ld->conf.view_projection;
int i;
int v_count = 0, t_count = 0, e_count = 0;
Object *ob;
- bool allow_boundaries = rb->allow_boundaries;
+ bool allow_boundaries = ld->conf.allow_boundaries;
double cam_pos[3];
- double clip_start = rb->near_clip, clip_end = rb->far_clip;
+ double clip_start = ld->conf.near_clip, clip_end = ld->conf.far_clip;
double view_dir[3], clip_advance[3];
- copy_v3_v3_db(view_dir, rb->view_vector);
- copy_v3_v3_db(clip_advance, rb->view_vector);
- copy_v3_v3_db(cam_pos, rb->camera_pos);
+ copy_v3_v3_db(view_dir, ld->conf.view_vector);
+ copy_v3_v3_db(clip_advance, ld->conf.view_vector);
+ copy_v3_v3_db(cam_pos, ld->conf.camera_pos);
if (clip_far) {
/* Move starting point to end plane. */
@@ -1222,25 +1240,25 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
add_v3_v3_db(cam_pos, clip_advance);
}
- v_eln = lineart_memory_get_vert_space(rb);
- t_eln = lineart_memory_get_triangle_space(rb);
- e_eln = lineart_memory_get_edge_space(rb);
+ v_eln = lineart_memory_get_vert_space(ld);
+ t_eln = lineart_memory_get_triangle_space(ld);
+ e_eln = lineart_memory_get_edge_space(ld);
/* Additional memory space for storing generated points and triangles. */
#define LRT_CULL_ENSURE_MEMORY \
if (v_count > 60) { \
v_eln->element_count = v_count; \
- v_eln = lineart_memory_get_vert_space(rb); \
+ v_eln = lineart_memory_get_vert_space(ld); \
v_count = 0; \
} \
if (t_count > 60) { \
t_eln->element_count = t_count; \
- t_eln = lineart_memory_get_triangle_space(rb); \
+ t_eln = lineart_memory_get_triangle_space(ld); \
t_count = 0; \
} \
if (e_count > 60) { \
e_eln->element_count = e_count; \
- e_eln = lineart_memory_get_edge_space(rb); \
+ e_eln = lineart_memory_get_edge_space(ld); \
e_count = 0; \
}
@@ -1275,21 +1293,21 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
int use_w = 3;
int in0 = 0, in1 = 0, in2 = 0;
- if (!rb->cam_is_persp) {
+ if (!ld->conf.cam_is_persp) {
clip_start = -1;
clip_end = 1;
use_w = 2;
}
/* Then go through all the other triangles. */
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) {
if (eln->flags & LRT_ELEMENT_IS_ADDITIONAL) {
continue;
}
ob = eln->object_ref;
for (i = 0; i < eln->element_count; i++) {
/* Select the triangle in the array. */
- tri = (void *)(((uchar *)eln->pointer) + rb->triangle_size * i);
+ tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * i);
if (tri->flags & LRT_CULL_DISCARD) {
continue;
@@ -1297,7 +1315,7 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
LRT_CULL_DECIDE_INSIDE
LRT_CULL_ENSURE_MEMORY
- lineart_triangle_cull_single(rb,
+ lineart_triangle_cull_single(ld,
tri,
in0,
in1,
@@ -1305,7 +1323,7 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
cam_pos,
view_dir,
allow_boundaries,
- vp,
+ m_view_projection,
ob,
&v_count,
&e_count,
@@ -1326,33 +1344,33 @@ static void lineart_main_cull_triangles(LineartRenderBuffer *rb, bool clip_far)
* Adjacent data is only used during the initial stages of computing.
* So we can free it using this function when it is not needed anymore.
*/
-static void lineart_main_free_adjacent_data(LineartRenderBuffer *rb)
+void lineart_main_free_adjacent_data(LineartData *ld)
{
- LinkData *ld;
- while ((ld = BLI_pophead(&rb->triangle_adjacent_pointers)) != NULL) {
- MEM_freeN(ld->data);
+ LinkData *link;
+ while ((link = BLI_pophead(&ld->geom.triangle_adjacent_pointers)) != NULL) {
+ MEM_freeN(link->data);
}
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.triangle_buffer_pointers) {
LineartTriangle *tri = eln->pointer;
int i;
for (i = 0; i < eln->element_count; i++) {
/* See definition of tri->intersecting_verts and the usage in
* lineart_geometry_object_load() for detailed. */
tri->intersecting_verts = NULL;
- tri = (LineartTriangle *)(((uchar *)tri) + rb->triangle_size);
+ tri = (LineartTriangle *)(((uchar *)tri) + ld->sizeof_triangle);
}
}
}
-static void lineart_main_perspective_division(LineartRenderBuffer *rb)
+void lineart_main_perspective_division(LineartData *ld)
{
LineartVert *vt;
int i;
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->vertex_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.vertex_buffer_pointers) {
vt = eln->pointer;
for (i = 0; i < eln->element_count; i++) {
- if (rb->cam_is_persp) {
+ if (ld->conf.cam_is_persp) {
/* Do not divide Z, we use Z to back transform cut points in later chaining process. */
vt[i].fbcoord[0] /= vt[i].fbcoord[3];
vt[i].fbcoord[1] /= vt[i].fbcoord[3];
@@ -1363,13 +1381,13 @@ static void lineart_main_perspective_division(LineartRenderBuffer *rb)
// `vt[i].fbcoord[2] = -2 * vt[i].fbcoord[2] / (far - near) - (far + near) / (far - near);
}
/* Shifting is always needed. */
- vt[i].fbcoord[0] -= rb->shift_x * 2;
- vt[i].fbcoord[1] -= rb->shift_y * 2;
+ vt[i].fbcoord[0] -= ld->conf.shift_x * 2;
+ vt[i].fbcoord[1] -= ld->conf.shift_y * 2;
}
}
}
-static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
+void lineart_main_discard_out_of_frame_edges(LineartData *ld)
{
LineartEdge *e;
int i;
@@ -1377,7 +1395,7 @@ static void lineart_main_discard_out_of_frame_edges(LineartRenderBuffer *rb)
#define LRT_VERT_OUT_OF_BOUND(v) \
(v && (v->fbcoord[0] < -1 || v->fbcoord[0] > 1 || v->fbcoord[1] < -1 || v->fbcoord[1] > 1))
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->line_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.line_buffer_pointers) {
e = (LineartEdge *)eln->pointer;
for (i = 0; i < eln->element_count; i++) {
if ((LRT_VERT_OUT_OF_BOUND(e[i].v1) && LRT_VERT_OUT_OF_BOUND(e[i].v2))) {
@@ -1414,14 +1432,23 @@ static void lineart_mvert_transform_task(void *__restrict userdata,
v->index = i;
}
-#define LRT_EDGE_FLAG_TYPE_MAX_BITS 6
+static const int LRT_MESH_EDGE_TYPES[] = {
+ LRT_EDGE_FLAG_EDGE_MARK,
+ LRT_EDGE_FLAG_CONTOUR,
+ LRT_EDGE_FLAG_CREASE,
+ LRT_EDGE_FLAG_MATERIAL,
+ LRT_EDGE_FLAG_LOOSE,
+ LRT_EDGE_FLAG_CONTOUR_SECONDARY,
+};
-static int lineart_edge_type_duplication_count(char eflag)
+#define LRT_MESH_EDGE_TYPES_COUNT 6
+
+static int lineart_edge_type_duplication_count(int eflag)
{
int count = 0;
/* See eLineartEdgeFlag for details. */
- for (int i = 0; i < LRT_EDGE_FLAG_TYPE_MAX_BITS; i++) {
- if (eflag & (1 << i)) {
+ for (int i = 0; i < LRT_MESH_EDGE_TYPES_COUNT; i++) {
+ if (eflag & LRT_MESH_EDGE_TYPES[i]) {
count++;
}
}
@@ -1432,18 +1459,19 @@ static int lineart_edge_type_duplication_count(char eflag)
* Because we have a variable size for #LineartTriangle, we need an access helper.
* See #LineartTriangleThread for more info.
*/
-static LineartTriangle *lineart_triangle_from_index(LineartRenderBuffer *rb,
+static LineartTriangle *lineart_triangle_from_index(LineartData *ld,
LineartTriangle *rt_array,
int index)
{
- char *b = (char *)rt_array;
- b += (index * rb->triangle_size);
+ int8_t *b = (int8_t *)rt_array;
+ b += (index * ld->sizeof_triangle);
return (LineartTriangle *)b;
}
typedef struct EdgeFeatData {
- LineartRenderBuffer *rb;
+ LineartData *ld;
Mesh *me;
+ Object *ob;
const MLoopTri *mlooptri;
LineartTriangle *tri_array;
LineartVert *v_array;
@@ -1476,6 +1504,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
EdgeFeatData *e_feat_data = (EdgeFeatData *)userdata;
EdgeFeatReduceData *reduce_data = (EdgeFeatReduceData *)tls->userdata_chunk;
Mesh *me = e_feat_data->me;
+ Object *ob = e_feat_data->ob;
LineartEdgeNeighbor *edge_nabr = e_feat_data->edge_nabr;
const MLoopTri *mlooptri = e_feat_data->mlooptri;
@@ -1488,7 +1517,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
}
bool face_mark_filtered = false;
- bool enable_face_mark = (e_feat_data->use_freestyle_face && e_feat_data->rb->filter_face_mark);
+ bool enable_face_mark = (e_feat_data->use_freestyle_face &&
+ e_feat_data->ld->conf.filter_face_mark);
bool only_contour = false;
if (enable_face_mark) {
FreestyleFace *ff1, *ff2;
@@ -1505,7 +1535,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
* path is simper when it's assuming both ff1 and ff2 not NULL. */
ff2 = ff1;
}
- if (e_feat_data->rb->filter_face_mark_boundaries ^ e_feat_data->rb->filter_face_mark_invert) {
+ if (e_feat_data->ld->conf.filter_face_mark_boundaries ^
+ e_feat_data->ld->conf.filter_face_mark_invert) {
if ((ff1->flag & FREESTYLE_FACE_MARK) || (ff2->flag & FREESTYLE_FACE_MARK)) {
face_mark_filtered = true;
}
@@ -1515,12 +1546,12 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
face_mark_filtered = true;
}
}
- if (e_feat_data->rb->filter_face_mark_invert) {
+ if (e_feat_data->ld->conf.filter_face_mark_invert) {
face_mark_filtered = !face_mark_filtered;
}
if (!face_mark_filtered) {
edge_nabr[i].flags = LRT_EDGE_FLAG_INHIBIT;
- if (e_feat_data->rb->filter_face_mark_keep_contour) {
+ if (e_feat_data->ld->conf.filter_face_mark_keep_contour) {
only_contour = true;
}
}
@@ -1539,60 +1570,77 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
LineartTriangle *tri1, *tri2;
LineartVert *vert;
- LineartRenderBuffer *rb = e_feat_data->rb;
+ LineartData *ld = e_feat_data->ld;
int f1 = i / 3, f2 = edge_nabr[i].e / 3;
/* The mesh should already be triangulated now, so we can assume each face is a triangle. */
- tri1 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f1);
- tri2 = lineart_triangle_from_index(rb, e_feat_data->tri_array, f2);
+ tri1 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f1);
+ tri2 = lineart_triangle_from_index(ld, e_feat_data->tri_array, f2);
vert = &e_feat_data->v_array[edge_nabr[i].v1];
double view_vector_persp[3];
double *view_vector = view_vector_persp;
- double dot_1 = 0, dot_2 = 0;
+ double dot_v1 = 0, dot_v2 = 0;
double result;
bool material_back_face = ((tri1->flags | tri2->flags) & LRT_TRIANGLE_MAT_BACK_FACE_CULLING);
- if (rb->use_contour || rb->use_back_face_culling || material_back_face) {
- if (rb->cam_is_persp) {
- sub_v3_v3v3_db(view_vector, rb->camera_pos, vert->gloc);
+ if (ld->conf.use_contour || ld->conf.use_back_face_culling || material_back_face) {
+ if (ld->conf.cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, ld->conf.camera_pos, vert->gloc);
}
else {
- view_vector = rb->view_vector;
+ view_vector = ld->conf.view_vector;
}
- dot_1 = dot_v3v3_db(view_vector, tri1->gn);
- dot_2 = dot_v3v3_db(view_vector, tri2->gn);
+ dot_v1 = dot_v3v3_db(view_vector, tri1->gn);
+ dot_v2 = dot_v3v3_db(view_vector, tri2->gn);
- if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ if ((result = dot_v1 * dot_v2) <= 0 && (dot_v1 + dot_v2)) {
edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
}
- if (rb->use_back_face_culling) {
- if (dot_1 < 0) {
+ if (ld->conf.use_back_face_culling) {
+ if (dot_v1 < 0) {
tri1->flags |= LRT_CULL_DISCARD;
}
- if (dot_2 < 0) {
+ if (dot_v2 < 0) {
tri2->flags |= LRT_CULL_DISCARD;
}
}
if (material_back_face) {
- if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_1 < 0) {
+ if (tri1->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v1 < 0) {
tri1->flags |= LRT_CULL_DISCARD;
}
- if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_2 < 0) {
+ if (tri2->flags & LRT_TRIANGLE_MAT_BACK_FACE_CULLING && dot_v2 < 0) {
tri2->flags |= LRT_CULL_DISCARD;
}
}
}
+ if (ld->conf.use_contour_secondary) {
+ view_vector = view_vector_persp;
+ if (ld->conf.cam_is_persp_secondary) {
+ sub_v3_v3v3_db(view_vector, vert->gloc, ld->conf.camera_pos_secondary);
+ }
+ else {
+ view_vector = ld->conf.view_vector_secondary;
+ }
+
+ dot_v1 = dot_v3v3_db(view_vector, tri1->gn);
+ dot_v2 = dot_v3v3_db(view_vector, tri2->gn);
+
+ if ((result = dot_v1 * dot_v2) <= 0 && (dot_v1 + dot_v2)) {
+ edge_flag_result |= LRT_EDGE_FLAG_CONTOUR_SECONDARY;
+ }
+ }
+
if (!only_contour) {
- if (rb->use_crease) {
+ if (ld->conf.use_crease) {
bool do_crease = true;
- if (!rb->force_crease && !e_feat_data->use_auto_smooth &&
+ if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth &&
(me->mpoly[mlooptri[f1].poly].flag & ME_SMOOTH) &&
(me->mpoly[mlooptri[f2].poly].flag & ME_SMOOTH)) {
do_crease = false;
@@ -1605,8 +1653,19 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
int mat1 = me->mpoly[mlooptri[f1].poly].mat_nr;
int mat2 = me->mpoly[mlooptri[f2].poly].mat_nr;
- if (rb->use_material && mat1 != mat2) {
- edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
+ if (mat1 != mat2) {
+ Material *m1 = BKE_object_material_get(ob, mat1 + 1);
+ Material *m2 = BKE_object_material_get(ob, mat2 + 1);
+ if (m1 && m2 &&
+ ((m1->lineart.mat_occlusion == 0 && m2->lineart.mat_occlusion != 0) ||
+ (m2->lineart.mat_occlusion == 0 && m1->lineart.mat_occlusion != 0))) {
+ if (ld->conf.use_contour) {
+ edge_flag_result |= LRT_EDGE_FLAG_CONTOUR;
+ }
+ }
+ if (ld->conf.use_material) {
+ edge_flag_result |= LRT_EDGE_FLAG_MATERIAL;
+ }
}
}
else { /* only_contour */
@@ -1621,11 +1680,11 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
if (real_edges[i % 3] >= 0) {
MEdge *medge = &me->medge[real_edges[i % 3]];
- if (rb->use_crease && rb->sharp_as_crease && (medge->flag & ME_SHARP)) {
+ if (ld->conf.use_crease && ld->conf.sharp_as_crease && (medge->flag & ME_SHARP)) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
}
- if (rb->use_edge_marks && e_feat_data->use_freestyle_edge) {
+ if (ld->conf.use_edge_marks && e_feat_data->use_freestyle_edge) {
FreestyleEdge *fe;
int index = e_feat_data->freestyle_edge_index;
fe = &((FreestyleEdge *)me->edata.layers[index].data)[real_edges[i % 3]];
@@ -1641,7 +1700,7 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
/* Only allocate for feature edge (instead of all edges) to save memory.
* If allow duplicated edges, one edge gets added multiple times if it has multiple types.
*/
- reduce_data->feat_edges += e_feat_data->rb->allow_duplicated_types ?
+ reduce_data->feat_edges += e_feat_data->ld->conf.allow_duplicated_types ?
lineart_edge_type_duplication_count(edge_flag_result) :
1;
}
@@ -1679,6 +1738,7 @@ static void lineart_join_loose_edge_arr(LooseEdgeData *loose_data, LooseEdgeData
sizeof(MEdge *) * to_be_joined->loose_count);
loose_data->loose_count += to_be_joined->loose_count;
MEM_freeN(to_be_joined->loose_array);
+ to_be_joined->loose_array = NULL;
}
static void lineart_add_loose_edge(LooseEdgeData *loose_data, MEdge *e)
@@ -1712,7 +1772,7 @@ static void loose_data_sum_reduce(const void *__restrict UNUSED(userdata),
lineart_join_loose_edge_arr(final, loose_chunk);
}
-static void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e)
+void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e)
{
if (pe->next >= pe->max || !pe->max) {
if (!pe->max) {
@@ -1731,15 +1791,14 @@ static void lineart_add_edge_to_array(LineartPendingEdges *pe, LineartEdge *e)
pe->array[pe->next] = e;
pe->next++;
}
-
static void lineart_add_edge_to_array_thread(LineartObjectInfo *obi, LineartEdge *e)
{
lineart_add_edge_to_array(&obi->pending_edges, e);
}
-/* Note: For simplicity, this function doesn't actually do anything if you already have data in
+/* NOTE: For simplicity, this function doesn't actually do anything if you already have data in
* #pe. */
-static void lineart_finalize_object_edge_array_reserve(LineartPendingEdges *pe, int count)
+void lineart_finalize_object_edge_array_reserve(LineartPendingEdges *pe, int count)
{
if (pe->max || pe->array) {
return;
@@ -1766,17 +1825,17 @@ static void lineart_finalize_object_edge_array(LineartPendingEdges *pe, LineartO
}
static void lineart_triangle_adjacent_assign(LineartTriangle *tri,
- LineartTriangleAdjacent *ta,
+ LineartTriangleAdjacent *tri_adj,
LineartEdge *e)
{
if (lineart_edge_match(tri, e, 0, 1)) {
- ta->e[0] = e;
+ tri_adj->e[0] = e;
}
else if (lineart_edge_match(tri, e, 1, 2)) {
- ta->e[1] = e;
+ tri_adj->e[1] = e;
}
else if (lineart_edge_match(tri, e, 2, 0)) {
- ta->e[2] = e;
+ tri_adj->e[2] = e;
}
}
@@ -1817,12 +1876,18 @@ static void lineart_load_tri_task(void *__restrict userdata,
mat->lineart.material_mask_bits :
0);
tri->mat_occlusion |= (mat ? mat->lineart.mat_occlusion : 1);
+ tri->intersection_priority = ((mat && (mat->lineart.flags &
+ LRT_MATERIAL_CUSTOM_INTERSECTION_PRIORITY)) ?
+ mat->lineart.intersection_priority :
+ ob_info->intersection_priority);
tri->flags |= (mat && (mat->blend_flag & MA_BL_CULL_BACKFACE)) ?
LRT_TRIANGLE_MAT_BACK_FACE_CULLING :
0;
tri->intersection_mask = ob_info->override_intersection_mask;
+ tri->target_reference = (ob_info->obindex | (i & LRT_OBINDEX_LOWER));
+
double gn[3];
float no[3];
normal_tri_v3(no, me->mvert[v1].co, me->mvert[v2].co, me->mvert[v3].co);
@@ -1862,7 +1927,7 @@ static void lineart_edge_neighbor_init_task(void *__restrict userdata,
adj_e->v1 = mloop[looptri->tri[i % 3]].v;
adj_e->v2 = mloop[looptri->tri[(i + 1) % 3]].v;
if (adj_e->v1 > adj_e->v2) {
- SWAP(unsigned int, adj_e->v1, adj_e->v2);
+ SWAP(uint32_t, adj_e->v1, adj_e->v2);
}
edge_nabr->e = -1;
@@ -1908,7 +1973,9 @@ static LineartEdgeNeighbor *lineart_build_edge_neighbor(Mesh *me, int total_edge
return edge_nabr;
}
-static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRenderBuffer *re_buf)
+static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
+ LineartData *la_data,
+ ListBase *shadow_elns)
{
LineartElementLinkNode *elem_link_node;
LineartVert *la_v_arr;
@@ -1942,20 +2009,22 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
/* If we allow duplicated edges, one edge should get added multiple times if is has been
* classified as more than one edge type. This is so we can create multiple different line type
* chains containing the same edge. */
- la_v_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_v_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
sizeof(LineartVert) * me->totvert);
- la_tri_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
- tot_tri * re_buf->triangle_size);
+ la_tri_arr = lineart_mem_acquire_thread(&la_data->render_data_pool,
+ tot_tri * la_data->sizeof_triangle);
Object *orig_ob = ob_info->original_ob;
- BLI_spin_lock(&re_buf->lock_task);
- elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->vertex_buffer_pointers,
- &re_buf->render_data_pool,
- la_v_arr,
- sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.vertex_buffer_pointers,
+ &la_data->render_data_pool,
+ la_v_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
+ elem_link_node->obindex = ob_info->obindex;
elem_link_node->element_count = me->totvert;
elem_link_node->object_ref = orig_ob;
ob_info->v_eln = elem_link_node;
@@ -1970,7 +2039,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
use_auto_smooth = true;
}
else {
- crease_angle = re_buf->crease_threshold;
+ crease_angle = la_data->conf.crease_threshold;
}
/* FIXME(Yiming): Hack for getting clean 3D text, the seam that extruded text object creates
@@ -1979,12 +2048,13 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
elem_link_node->flags |= LRT_ELEMENT_BORDER_ONLY;
}
- BLI_spin_lock(&re_buf->lock_task);
- elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->triangle_buffer_pointers,
- &re_buf->render_data_pool,
- la_tri_arr,
- sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.triangle_buffer_pointers,
+ &la_data->render_data_pool,
+ la_tri_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
int usage = ob_info->usage;
@@ -1996,10 +2066,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
LineartTriangleAdjacent *tri_adj = MEM_callocN(sizeof(LineartTriangleAdjacent) * tot_tri,
"LineartTriangleAdjacent");
/* Link is minimal so we use pool anyway. */
- BLI_spin_lock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
lineart_list_append_pointer_pool_thread(
- &re_buf->triangle_adjacent_pointers, &re_buf->render_data_pool, tri_adj);
- BLI_spin_unlock(&re_buf->lock_task);
+ &la_data->geom.triangle_adjacent_pointers, &la_data->render_data_pool, tri_adj);
+ BLI_spin_unlock(&la_data->lock_task);
/* Convert all vertices to lineart verts. */
TaskParallelSettings vert_settings;
@@ -2028,10 +2098,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
tri_data.mlooptri = mlooptri;
tri_data.vert_arr = la_v_arr;
tri_data.tri_arr = la_tri_arr;
- tri_data.lineart_triangle_size = re_buf->triangle_size;
+ tri_data.lineart_triangle_size = la_data->sizeof_triangle;
tri_data.tri_adj = tri_adj;
- unsigned int total_edges = tot_tri * 3;
+ uint32_t total_edges = tot_tri * 3;
BLI_task_parallel_range(0, tot_tri, &tri_data, lineart_load_tri_task, &tri_settings);
@@ -2049,8 +2119,9 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
edge_feat_settings.func_reduce = feat_data_sum_reduce;
EdgeFeatData edge_feat_data = {0};
- edge_feat_data.rb = re_buf;
+ edge_feat_data.ld = la_data;
edge_feat_data.me = me;
+ edge_feat_data.ob = orig_ob;
edge_feat_data.mlooptri = mlooptri;
edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges);
edge_feat_data.tri_array = la_tri_arr;
@@ -2075,7 +2146,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
&edge_feat_settings);
LooseEdgeData loose_data = {0};
- if (re_buf->use_loose) {
+ if (la_data->conf.use_loose) {
/* Only identifying floating edges at this point because other edges has been taken care of
* inside #lineart_identify_mlooptri_feature_edges function. */
TaskParallelSettings edge_loose_settings;
@@ -2091,20 +2162,27 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
int allocate_la_e = edge_reduce.feat_edges + loose_data.loose_count;
- la_edge_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_edge_arr = lineart_mem_acquire_thread(la_data->edge_data_pool,
sizeof(LineartEdge) * allocate_la_e);
- la_seg_arr = lineart_mem_acquire_thread(&re_buf->render_data_pool,
+ la_seg_arr = lineart_mem_acquire_thread(la_data->edge_data_pool,
sizeof(LineartEdgeSegment) * allocate_la_e);
- BLI_spin_lock(&re_buf->lock_task);
- elem_link_node = lineart_list_append_pointer_pool_sized_thread(&re_buf->line_buffer_pointers,
- &re_buf->render_data_pool,
- la_edge_arr,
- sizeof(LineartElementLinkNode));
- BLI_spin_unlock(&re_buf->lock_task);
+ BLI_spin_lock(&la_data->lock_task);
+ elem_link_node = lineart_list_append_pointer_pool_sized_thread(
+ &la_data->geom.line_buffer_pointers,
+ la_data->edge_data_pool,
+ la_edge_arr,
+ sizeof(LineartElementLinkNode));
+ BLI_spin_unlock(&la_data->lock_task);
elem_link_node->element_count = allocate_la_e;
elem_link_node->object_ref = orig_ob;
+ elem_link_node->obindex = ob_info->obindex;
+
+ LineartElementLinkNode *shadow_eln = NULL;
+ if (shadow_elns) {
+ shadow_eln = lineart_find_matching_eln(shadow_elns, ob_info->obindex);
+ }
- // Start of the edge/seg arr
+ /* Start of the edge/seg arr */
LineartEdge *la_edge;
LineartEdgeSegment *la_seg;
la_edge = la_edge_arr;
@@ -2125,8 +2203,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
LineartEdge *edge_added = NULL;
/* See eLineartEdgeFlag for details. */
- for (int flag_bit = 0; flag_bit < LRT_EDGE_FLAG_TYPE_MAX_BITS; flag_bit++) {
- char use_type = 1 << flag_bit;
+ for (int flag_bit = 0; flag_bit < LRT_MESH_EDGE_TYPES_COUNT; flag_bit++) {
+ int use_type = LRT_MESH_EDGE_TYPES[flag_bit];
if (!(use_type & edge_nabr->flags)) {
continue;
}
@@ -2134,20 +2212,32 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
la_edge->v1 = &la_v_arr[edge_nabr->v1];
la_edge->v2 = &la_v_arr[edge_nabr->v2];
int findex = i / 3;
- la_edge->t1 = lineart_triangle_from_index(re_buf, la_tri_arr, findex);
+ la_edge->t1 = lineart_triangle_from_index(la_data, la_tri_arr, findex);
if (!edge_added) {
lineart_triangle_adjacent_assign(la_edge->t1, &tri_adj[findex], la_edge);
}
if (edge_nabr->e != -1) {
findex = edge_nabr->e / 3;
- la_edge->t2 = lineart_triangle_from_index(re_buf, la_tri_arr, findex);
+ la_edge->t2 = lineart_triangle_from_index(la_data, la_tri_arr, findex);
if (!edge_added) {
lineart_triangle_adjacent_assign(la_edge->t2, &tri_adj[findex], la_edge);
}
}
la_edge->flags = use_type;
la_edge->object_ref = orig_ob;
+ la_edge->edge_identifier = LRT_EDGE_IDENTIFIER(ob_info, la_edge);
BLI_addtail(&la_edge->segments, la_seg);
+
+ if (shadow_eln) {
+ /* TODO(Yiming): It's gonna be faster to do this operation after second stage occlusion if
+ * we only need visible segments to have shadow info, however that way we lose information
+ * on "shadow behind transparency window" type of region. */
+ LineartEdge *shadow_e = lineart_find_matching_edge(shadow_eln, la_edge->edge_identifier);
+ if (shadow_e) {
+ lineart_register_shadow_cuts(la_data, la_edge, shadow_e);
+ }
+ }
+
if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
usage == OBJECT_LRT_NO_INTERSECTION) {
lineart_add_edge_to_array_thread(ob_info, la_edge);
@@ -2162,7 +2252,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
la_edge++;
la_seg++;
- if (!re_buf->allow_duplicated_types) {
+ if (!la_data->conf.allow_duplicated_types) {
break;
}
}
@@ -2174,10 +2264,17 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, LineartRend
la_edge->v2 = &la_v_arr[loose_data.loose_array[i]->v2];
la_edge->flags = LRT_EDGE_FLAG_LOOSE;
la_edge->object_ref = orig_ob;
+ la_edge->edge_identifier = LRT_EDGE_IDENTIFIER(ob_info, la_edge);
BLI_addtail(&la_edge->segments, la_seg);
if (usage == OBJECT_LRT_INHERIT || usage == OBJECT_LRT_INCLUDE ||
usage == OBJECT_LRT_NO_INTERSECTION) {
lineart_add_edge_to_array_thread(ob_info, la_edge);
+ if (shadow_eln) {
+ LineartEdge *shadow_e = lineart_find_matching_edge(shadow_eln, la_edge->edge_identifier);
+ if (shadow_e) {
+ lineart_register_shadow_cuts(la_data, la_edge, shadow_e);
+ }
+ }
}
la_edge++;
la_seg++;
@@ -2196,10 +2293,7 @@ static void lineart_object_load_worker(TaskPool *__restrict UNUSED(pool),
LineartObjectLoadTaskInfo *olti)
{
for (LineartObjectInfo *obi = olti->pending; obi; obi = obi->next) {
- lineart_geometry_object_load(obi, olti->rb);
- if (G.debug_value == 4000) {
- printf("thread id: %d processed: %d\n", olti->thread_id, obi->original_me->totpoly);
- }
+ lineart_geometry_object_load(obi, olti->ld, olti->shadow_elns);
}
}
@@ -2221,6 +2315,26 @@ static uchar lineart_intersection_mask_check(Collection *c, Object *ob)
return 0;
}
+static uchar lineart_intersection_priority_check(Collection *c, Object *ob)
+{
+ if (ob->lineart.flags & OBJECT_LRT_OWN_INTERSECTION_PRIORITY) {
+ return ob->lineart.intersection_priority;
+ }
+
+ LISTBASE_FOREACH (CollectionChild *, cc, &c->children) {
+ uchar result = lineart_intersection_priority_check(cc->collection, ob);
+ if (result) {
+ return result;
+ }
+ }
+ if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
+ if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_PRIORITY) {
+ return c->lineart_intersection_priority;
+ }
+ }
+ return 0;
+}
+
/**
* See if this object in such collection is used for generating line art,
* Disabling a collection for line art will doable all objects inside.
@@ -2277,7 +2391,7 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_
int this_face_count)
{
LineartObjectLoadTaskInfo *use_olti = olti_list;
- long unsigned int min_face = use_olti->total_faces;
+ uint64_t min_face = use_olti->total_faces;
for (int i = 0; i < thread_count; i++) {
if (olti_list[i].total_faces < min_face) {
min_face = olti_list[i].total_faces;
@@ -2290,7 +2404,7 @@ static void lineart_geometry_load_assign_thread(LineartObjectLoadTaskInfo *olti_
use_olti->pending = obi;
}
-static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
+static bool lineart_geometry_check_visible(double model_view_proj[4][4],
double shift_x,
double shift_y,
Mesh *use_mesh)
@@ -2333,7 +2447,7 @@ static bool lineart_geometry_check_visible(double (*model_view_proj)[4],
return true;
}
-static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
+static void lineart_object_load_single_instance(LineartData *ld,
Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -2341,21 +2455,25 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
float use_mat[4][4],
bool is_render,
LineartObjectLoadTaskInfo *olti,
- int thread_count)
+ int thread_count,
+ int obindex)
{
- LineartObjectInfo *obi = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartObjectInfo));
+ LineartObjectInfo *obi = lineart_mem_acquire(&ld->render_data_pool, sizeof(LineartObjectInfo));
obi->usage = lineart_usage_check(scene->master_collection, ob, is_render);
obi->override_intersection_mask = lineart_intersection_mask_check(scene->master_collection, ob);
+ obi->intersection_priority = lineart_intersection_priority_check(scene->master_collection, ob);
Mesh *use_mesh;
if (obi->usage == OBJECT_LRT_EXCLUDE) {
return;
}
+ obi->obindex = obindex << LRT_OBINDEX_SHIFT;
+
/* Prepare the matrix used for transforming this specific object (instance). This has to be
* done before mesh boundbox check because the function needs that. */
- mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, rb->view_projection, use_mat);
- mul_m4db_m4db_m4fl_uniq(obi->model_view, rb->view, use_mat);
+ mul_m4db_m4db_m4fl_uniq(obi->model_view_proj, ld->conf.view_projection, use_mat);
+ mul_m4db_m4db_m4fl_uniq(obi->model_view, ld->conf.view, use_mat);
if (!ELEM(ob->type, OB_MESH, OB_MBALL, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) {
return;
@@ -2377,7 +2495,8 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
return;
}
- if (!lineart_geometry_check_visible(obi->model_view_proj, rb->shift_x, rb->shift_y, use_mesh)) {
+ if (!lineart_geometry_check_visible(
+ obi->model_view_proj, ld->conf.shift_x, ld->conf.shift_y, use_mesh)) {
return;
}
@@ -2396,89 +2515,105 @@ static void lineart_object_load_single_instance(LineartRenderBuffer *rb,
lineart_geometry_load_assign_thread(olti, obi, thread_count, use_mesh->totpoly);
}
-static void lineart_main_load_geometries(
- Depsgraph *depsgraph,
- Scene *scene,
- Object *camera /* Still use camera arg for convenience. */,
- LineartRenderBuffer *rb,
- bool allow_duplicates)
+void lineart_main_load_geometries(Depsgraph *depsgraph,
+ Scene *scene,
+ Object *camera /* Still use camera arg for convenience. */,
+ LineartData *ld,
+ bool allow_duplicates,
+ bool do_shadow_casting,
+ ListBase *shadow_elns)
{
double proj[4][4], view[4][4], result[4][4];
float inv[4][4];
- Camera *cam = camera->data;
- float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
- int fit = BKE_camera_sensor_fit(cam->sensor_fit, rb->w, rb->h);
- double asp = ((double)rb->w / (double)rb->h);
-
- int bound_box_discard_count = 0;
- if (cam->type == CAM_PERSP) {
- if (fit == CAMERA_SENSOR_FIT_VERT && asp > 1) {
- sensor *= asp;
+ if (!do_shadow_casting) {
+ Camera *cam = camera->data;
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ int fit = BKE_camera_sensor_fit(cam->sensor_fit, ld->w, ld->h);
+ double asp = ((double)ld->w / (double)ld->h);
+ if (cam->type == CAM_PERSP) {
+ if (fit == CAMERA_SENSOR_FIT_VERT && asp > 1) {
+ sensor *= asp;
+ }
+ if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) {
+ sensor /= asp;
+ }
+ const double fov = focallength_to_fov(cam->lens / (1 + ld->conf.overscan), sensor);
+ lineart_matrix_perspective_44d(proj, fov, asp, cam->clip_start, cam->clip_end);
}
- if (fit == CAMERA_SENSOR_FIT_HOR && asp < 1) {
- sensor /= asp;
+ else if (cam->type == CAM_ORTHO) {
+ const double w = cam->ortho_scale / 2;
+ lineart_matrix_ortho_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end);
}
- const double fov = focallength_to_fov(cam->lens / (1 + rb->overscan), sensor);
- lineart_matrix_perspective_44d(proj, fov, asp, cam->clip_start, cam->clip_end);
- }
- else if (cam->type == CAM_ORTHO) {
- const double w = cam->ortho_scale / 2;
- lineart_matrix_ortho_44d(proj, -w, w, -w / asp, w / asp, cam->clip_start, cam->clip_end);
+
+ invert_m4_m4(inv, ld->conf.cam_obmat);
+ mul_m4db_m4db_m4fl_uniq(result, proj, inv);
+ copy_m4_m4_db(proj, result);
+ copy_m4_m4_db(ld->conf.view_projection, proj);
+
+ unit_m4_db(view);
+ copy_m4_m4_db(ld->conf.view, view);
}
- double t_start;
+ BLI_listbase_clear(&ld->geom.triangle_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.vertex_buffer_pointers);
+ double t_start;
if (G.debug_value == 4000) {
t_start = PIL_check_seconds_timer();
}
- invert_m4_m4(inv, rb->cam_obmat);
- mul_m4db_m4db_m4fl_uniq(result, proj, inv);
- copy_m4_m4_db(proj, result);
- copy_m4_m4_db(rb->view_projection, proj);
-
- unit_m4_db(view);
- copy_m4_m4_db(rb->view, view);
-
- BLI_listbase_clear(&rb->triangle_buffer_pointers);
- BLI_listbase_clear(&rb->vertex_buffer_pointers);
-
- int thread_count = rb->thread_count;
+ int thread_count = ld->thread_count;
+ int bound_box_discard_count = 0;
+ int obindex = 0;
- /* 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);
+ &ld->render_data_pool, sizeof(LineartObjectLoadTaskInfo) * thread_count);
eEvaluationMode eval_mode = DEG_get_mode(depsgraph);
bool is_render = eval_mode == DAG_EVAL_RENDER;
- FOREACH_SCENE_OBJECT_BEGIN (scene, ob) {
+ int flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE;
+
+ /* Instance duplicated & particles. */
+ if (allow_duplicates) {
+ flags |= DEG_ITER_OBJECT_FLAG_DUPLI;
+ }
+
+ /* XXX(@Yiming): Temporary solution, this iterator is technically unsafe to use *during*
+ * depsgraph evaluation, see D14997 for detailed explanations. */
+ DEG_OBJECT_ITER_BEGIN (depsgraph, ob, flags) {
+
+ obindex++;
+
Object *eval_ob = DEG_get_evaluated_object(depsgraph, ob);
if (!eval_ob) {
continue;
}
+ /* DEG_OBJECT_ITER_BEGIN will include the instanced mesh of these curve object types, so don't
+ * load them twice. */
+ if (allow_duplicates && ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) {
+ continue;
+ }
+
if (BKE_object_visibility(eval_ob, eval_mode) & OB_VISIBLE_SELF) {
- lineart_object_load_single_instance(
- rb, depsgraph, scene, eval_ob, eval_ob, eval_ob->obmat, is_render, olti, thread_count);
- }
- if (allow_duplicates) {
- ListBase *dupli = object_duplilist(depsgraph, scene, eval_ob);
- LISTBASE_FOREACH (DupliObject *, dob, dupli) {
- if (BKE_object_visibility(eval_ob, eval_mode) &
- (OB_VISIBLE_PARTICLES | OB_VISIBLE_INSTANCES)) {
- Object *ob_ref = (dob->type & OB_DUPLIPARTS) ? eval_ob : dob->ob;
- lineart_object_load_single_instance(
- rb, depsgraph, scene, dob->ob, ob_ref, dob->mat, is_render, olti, thread_count);
- }
- }
- free_object_duplilist(dupli);
+ lineart_object_load_single_instance(ld,
+ depsgraph,
+ scene,
+ eval_ob,
+ eval_ob,
+ eval_ob->obmat,
+ is_render,
+ olti,
+ thread_count,
+ obindex);
}
}
- FOREACH_SCENE_OBJECT_END;
+ DEG_OBJECT_ITER_END;
TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
@@ -2486,7 +2621,8 @@ static void lineart_main_load_geometries(
printf("thread count: %d\n", thread_count);
}
for (int i = 0; i < thread_count; i++) {
- olti[i].rb = rb;
+ olti[i].ld = ld;
+ olti[i].shadow_elns = shadow_elns;
olti[i].thread_id = i;
BLI_task_pool_push(tp, (TaskRunFunction)lineart_object_load_worker, &olti[i], 0, NULL);
}
@@ -2506,7 +2642,7 @@ static void lineart_main_load_geometries(
edge_count += obi->pending_edges.next;
}
}
- lineart_finalize_object_edge_array_reserve(&rb->pending_edges, edge_count);
+ lineart_finalize_object_edge_array_reserve(&ld->pending_edges, edge_count);
for (int i = 0; i < thread_count; i++) {
for (LineartObjectInfo *obi = olti[i].pending; obi; obi = obi->next) {
@@ -2524,7 +2660,7 @@ static void lineart_main_load_geometries(
* same numeric index to come close together. */
obi->global_i_offset = global_i;
global_i += v_count;
- lineart_finalize_object_edge_array(&rb->pending_edges, obi);
+ lineart_finalize_object_edge_array(&ld->pending_edges, obi);
}
}
@@ -2562,14 +2698,25 @@ static bool lineart_triangle_get_other_verts(const LineartTriangle *tri,
return false;
}
-static bool lineart_edge_from_triangle(const LineartTriangle *tri,
- const LineartEdge *e,
- bool allow_overlapping_edges)
+bool lineart_edge_from_triangle(const LineartTriangle *tri,
+ const LineartEdge *e,
+ bool allow_overlapping_edges)
{
- /* Normally we just determine from the pointer address. */
- if (e->t1 == tri || e->t2 == tri) {
- return true;
+ const LineartEdge *use_e = e;
+ if (e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
+ if (((e->target_reference & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference) ||
+ (((e->target_reference >> 32) & LRT_LIGHT_CONTOUR_TARGET) == tri->target_reference)) {
+ return true;
+ }
}
+ else {
+ /* Normally we just determine from identifiers of adjacent triangles. */
+ if ((use_e->t1 && use_e->t1->target_reference == tri->target_reference) ||
+ (use_e->t2 && use_e->t2->target_reference == tri->target_reference)) {
+ return true;
+ }
+ }
+
/* If allows overlapping, then we compare the vertex coordinates one by one to determine if one
* edge is from specific triangle. This is slower but can handle edge split cases very well. */
if (allow_overlapping_edges) {
@@ -2618,6 +2765,9 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
(num > is[order[1]] ? order[1] : (num > is[order[0]] ? order[0] : -1))); \
}
+#define LRT_ISEC(index) (index == 0 ? isec_e1 : (index == 1 ? isec_e2 : isec_e3))
+#define LRT_PARALLEL(index) (index == 0 ? para_e1 : (index == 1 ? para_e2 : para_e3))
+
/**
* This is the main function to calculate
* the occlusion status between 1(one) triangle and 1(one) line.
@@ -2631,7 +2781,7 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* 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
+ * 2) Currently using discrete a/b/c/para_e1/para_e2/para_e3/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.
*
@@ -2640,31 +2790,32 @@ static bool lineart_edge_from_triangle(const LineartTriangle *tri,
* 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,
+static bool lineart_triangle_edge_image_space_occlusion(const LineartTriangle *tri,
const LineartEdge *e,
const double *override_camera_loc,
const bool override_cam_is_persp,
const bool allow_overlapping_edges,
- const double vp[4][4],
- const double *camera_dir,
+ const double m_view_projection[4][4],
+ const double camera_dir[3],
const float cam_shift_x,
const float cam_shift_y,
double *from,
double *to)
{
- double is[3] = {0};
- int order[3];
- int LCross = -1, RCross = -1;
- int a, b, c; /* Crossing info. */
- bool pa, pb, pc; /* Parallel info. */
- int st_l = 0, st_r = 0;
-
- double Lv[3];
- double Rv[3];
- double vd4[4];
- double Cv[3];
- double dot_l, dot_r, dot_la, dot_ra;
+ double cross_ratios[3] = {0};
+ int cross_order[3];
+ int cross_v1 = -1, cross_v2 = -1;
+ /* If the edge intersects with the triangle edges (including extensions). */
+ int isec_e1, isec_e2, isec_e3;
+ /* If edge is parallel to one of the edges in the triangle. */
+ bool para_e1, para_e2, para_e3;
+ enum LineartPointTri state_v1 = LRT_OUTSIDE_TRIANGLE, state_v2 = LRT_OUTSIDE_TRIANGLE;
+
+ double dir_v1[3];
+ double dir_v2[3];
+ double view_vector[4];
+ double dir_cam[3];
+ double dot_v1, dot_v2, dot_v1a, dot_v2a;
double dot_f;
double gloc[4], trans[4];
double cut = -1;
@@ -2687,31 +2838,37 @@ 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_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);
+ isec_e1 = lineart_intersect_seg_seg(LFBC, RFBC, FBC0, FBC1, &cross_ratios[0], &para_e1);
+ isec_e2 = lineart_intersect_seg_seg(LFBC, RFBC, FBC1, FBC2, &cross_ratios[1], &para_e2);
+ isec_e3 = lineart_intersect_seg_seg(LFBC, RFBC, FBC2, FBC0, &cross_ratios[2], &para_e3);
/* Sort the intersection distance. */
- INTERSECT_SORT_MIN_TO_MAX_3(is[0], is[1], is[2], order);
+ INTERSECT_SORT_MIN_TO_MAX_3(cross_ratios[0], cross_ratios[1], cross_ratios[2], cross_order);
- sub_v3_v3v3_db(Lv, e->v1->gloc, tri->v[0]->gloc);
- sub_v3_v3v3_db(Rv, e->v2->gloc, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v1, e->v1->gloc, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v2, e->v2->gloc, tri->v[0]->gloc);
- copy_v3_v3_db(Cv, camera_dir);
-
- if (override_cam_is_persp) {
- copy_v3_v3_db(vd4, override_camera_loc);
- }
- else {
- copy_v4_v4_db(vd4, override_camera_loc);
- }
+ copy_v3_v3_db(dir_cam, camera_dir);
+ copy_v3_v3_db(view_vector, override_camera_loc);
if (override_cam_is_persp) {
- sub_v3_v3v3_db(Cv, vd4, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_cam, view_vector, tri->v[0]->gloc);
}
- dot_l = dot_v3v3_db(Lv, tri->gn);
- dot_r = dot_v3v3_db(Rv, tri->gn);
- dot_f = dot_v3v3_db(Cv, tri->gn);
+ dot_v1 = dot_v3v3_db(dir_v1, tri->gn);
+ dot_v2 = dot_v3v3_db(dir_v2, tri->gn);
+ dot_f = dot_v3v3_db(dir_cam, tri->gn);
+
+ if ((e->flags & LRT_EDGE_FLAG_PROJECTED_SHADOW) &&
+ (e->target_reference == tri->target_reference)) {
+ if (((dot_f > 0) && (e->flags & LRT_EDGE_FLAG_SHADOW_FACING_LIGHT)) ||
+ ((dot_f < 0) && (!(e->flags & LRT_EDGE_FLAG_SHADOW_FACING_LIGHT)))) {
+ *from = 0.0f;
+ *to = 1.0f;
+ return true;
+ }
+
+ return false;
+ }
/* 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
@@ -2722,46 +2879,45 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
return false;
}
+ /* Whether two end points are inside/on_the_edge/outside of the triangle. */
+ state_v1 = lineart_point_triangle_relation(LFBC, FBC0, FBC1, FBC2);
+ state_v2 = lineart_point_triangle_relation(RFBC, FBC0, FBC1, FBC2);
+
/* If the edge doesn't visually cross any edge of the triangle... */
- if (!a && !b && !c) {
+ if (!isec_e1 && !isec_e2 && !isec_e3) {
/* 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))) {
+ if ((!state_v1) && (!state_v2)) {
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);
-
/* Determine the cut position. */
- dot_la = fabs(dot_l);
- if (dot_la < DBL_EPSILON) {
- dot_la = 0;
- dot_l = 0;
+ dot_v1a = fabs(dot_v1);
+ if (dot_v1a < DBL_EPSILON) {
+ dot_v1a = 0;
+ dot_v1 = 0;
}
- dot_ra = fabs(dot_r);
- if (dot_ra < DBL_EPSILON) {
- dot_ra = 0;
- dot_r = 0;
+ dot_v2a = fabs(dot_v2);
+ if (dot_v2a < DBL_EPSILON) {
+ dot_v2a = 0;
+ dot_v2 = 0;
}
- if (dot_l - dot_r == 0) {
+ if (dot_v1 - dot_v2 == 0) {
cut = 100000;
}
- else if (dot_l * dot_r <= 0) {
- cut = dot_la / fabs(dot_l - dot_r);
+ else if (dot_v1 * dot_v2 <= 0) {
+ cut = dot_v1a / fabs(dot_v1 - dot_v2);
}
else {
- cut = fabs(dot_r + dot_l) / fabs(dot_l - dot_r);
- cut = dot_ra > dot_la ? 1 - cut : cut;
+ cut = fabs(dot_v2 + dot_v1) / fabs(dot_v1 - dot_v2);
+ cut = dot_v2a > dot_v1a ? 1 - cut : cut;
}
/* Transform the cut from geometry space to image space. */
if (override_cam_is_persp) {
interp_v3_v3v3_db(gloc, e->v1->gloc, e->v2->gloc, cut);
- mul_v4_m4v3_db(trans, vp, gloc);
+ mul_v4_m4v3_db(trans, m_view_projection, gloc);
mul_v3db_db(trans, (1 / trans[3]));
trans[0] -= cam_shift_x * 2;
trans[1] -= cam_shift_y * 2;
@@ -2776,7 +2932,7 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
}
#define LRT_GUARD_NOT_FOUND \
- if (LCross < 0 || RCross < 0) { \
+ if (cross_v1 < 0 || cross_v2 < 0) { \
return false; \
}
@@ -2784,95 +2940,97 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
* indicates triangle boundary. DBL_TRIANGLE_LIM is needed to for floating point precision
* tolerance. */
- if (st_l == 2) {
+ if (state_v1 == LRT_INSIDE_TRIANGLE) {
/* Left side is in the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* | l---r | */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* | l------r| */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* | l-------|------r */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 0, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 0, cross_v2);
}
}
- else if (st_l == 1) {
+ else if (state_v1 == LRT_ON_TRIANGLE) {
/* Left side is on some edge of the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* |l------r | */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* |l---------r| */
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* |l----------|-------r (crossing the triangle) [OR]
* r---------|l | (not crossing the triangle) */
- INTERSECT_JUST_GREATER(is, order, DBL_TRIANGLE_LIM, RCross);
- if (RCross >= 0 && LRT_ABC(RCross) && is[RCross] > (DBL_TRIANGLE_LIM)) {
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, LCross);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2);
+ if (cross_v2 >= 0 && LRT_ISEC(cross_v2) && cross_ratios[cross_v2] > (DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v1);
}
else {
- INTERSECT_JUST_SMALLER(is, order, DBL_TRIANGLE_LIM, RCross);
- if (RCross > 0) {
- INTERSECT_JUST_SMALLER(is, order, is[RCross], LCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, DBL_TRIANGLE_LIM, cross_v2);
+ if (cross_v2 > 0) {
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, cross_ratios[cross_v2], cross_v1);
}
}
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))) {
+ if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) ||
+ (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) {
return false;
}
}
}
- else if (st_l == 0) {
+ else if (state_v1 == LRT_OUTSIDE_TRIANGLE) {
/* Left side is outside of the triangle. */
- if (st_r == 2) {
+ if (state_v2 == LRT_INSIDE_TRIANGLE) {
/* l---|---r | */
- INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
- else if (st_r == 1) {
+ else if (state_v2 == LRT_ON_TRIANGLE) {
/* |r----------|-------l (crossing the triangle) [OR]
* l---------|r | (not crossing the triangle) */
- INTERSECT_JUST_SMALLER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- if (LCross >= 0 && LRT_ABC(LCross) && is[LCross] < (1 - DBL_TRIANGLE_LIM)) {
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, RCross);
+ INTERSECT_JUST_SMALLER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 >= 0 && LRT_ISEC(cross_v1) && cross_ratios[cross_v1] < (1 - DBL_TRIANGLE_LIM)) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v2);
}
else {
- INTERSECT_JUST_GREATER(is, order, 1 - DBL_TRIANGLE_LIM, LCross);
- if (LCross > 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, 1 - DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 > 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
}
LRT_GUARD_NOT_FOUND
/* The same logic applies as above case. */
- if ((LRT_PABC(LCross) && !LRT_ABC(LCross)) || (LRT_PABC(RCross) && !LRT_ABC(RCross))) {
+ if ((LRT_PARALLEL(cross_v1) && !LRT_ISEC(cross_v1)) ||
+ (LRT_PARALLEL(cross_v2) && !LRT_ISEC(cross_v2))) {
return false;
}
}
- else if (st_r == 0) {
+ else if (state_v2 == LRT_OUTSIDE_TRIANGLE) {
/* 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);
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, -DBL_TRIANGLE_LIM, cross_v1);
+ if (cross_v1 >= 0 && LRT_ISEC(cross_v1)) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
else {
- if (LCross >= 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
- if (LCross >= 0) {
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ if (cross_v1 >= 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v1);
+ if (cross_v1 >= 0) {
+ INTERSECT_JUST_GREATER(cross_ratios, cross_order, cross_ratios[cross_v1], cross_v2);
}
}
}
@@ -2881,28 +3039,28 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
LRT_GUARD_NOT_FOUND
- double LF = dot_l * dot_f, RF = dot_r * dot_f;
+ double dot_1f = dot_v1 * dot_f, dot_2f = dot_v2 * dot_f;
/* Determine the start and end point of image space cut on a line. */
- if (LF <= 0 && RF <= 0 && (dot_l || dot_r)) {
- *from = MAX2(0, is[LCross]);
- *to = MIN2(1, is[RCross]);
+ if (dot_1f <= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(0, cross_ratios[cross_v1]);
+ *to = MIN2(1, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
return true;
}
- if (LF >= 0 && RF <= 0 && (dot_l || dot_r)) {
- *from = MAX2(cut, is[LCross]);
- *to = MIN2(1, is[RCross]);
+ if (dot_1f >= 0 && dot_2f <= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(cut, cross_ratios[cross_v1]);
+ *to = MIN2(1, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
return true;
}
- if (LF <= 0 && RF >= 0 && (dot_l || dot_r)) {
- *from = MAX2(0, is[LCross]);
- *to = MIN2(cut, is[RCross]);
+ if (dot_1f <= 0 && dot_2f >= 0 && (dot_v1 || dot_v2)) {
+ *from = MAX2(0, cross_ratios[cross_v1]);
+ *to = MIN2(cut, cross_ratios[cross_v2]);
if (*from >= *to) {
return false;
}
@@ -2916,6 +3074,8 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
#undef INTERSECT_SORT_MIN_TO_MAX_3
#undef INTERSECT_JUST_GREATER
#undef INTERSECT_JUST_SMALLER
+#undef LRT_ISEC
+#undef LRT_PARALLEL
/**
* At this stage of the computation we don't have triangle adjacent info anymore,
@@ -2997,272 +3157,242 @@ static LineartVert *lineart_triangle_share_point(const LineartTriangle *l,
return NULL;
}
-/**
- * To save time and prevent overlapping lines when computing intersection lines.
- */
-static bool lineart_vert_already_intersected_2v(LineartVertIntersection *vt,
- LineartVertIntersection *v1,
- LineartVertIntersection *v2)
-{
- return ((vt->isec1 == v1->base.index && vt->isec2 == v2->base.index) ||
- (vt->isec2 == v2->base.index && vt->isec1 == v1->base.index));
-}
-
-static void lineart_vert_set_intersection_2v(LineartVert *vt, LineartVert *v1, LineartVert *v2)
-{
- LineartVertIntersection *irv = (LineartVertIntersection *)vt;
- irv->isec1 = v1->index;
- irv->isec2 = v2->index;
-}
-
-/**
- * This tests a triangle against a virtual line represented by `v1---v2`.
- * The vertices returned after repeated calls to this function
- * is then used to create a triangle/triangle intersection line.
- */
-static LineartVert *lineart_triangle_2v_intersection_test(LineartRenderBuffer *rb,
- LineartVert *v1,
- LineartVert *v2,
- LineartTriangle *tri,
- LineartTriangle *testing,
- LineartVert *last)
+static bool lineart_triangle_2v_intersection_math(
+ LineartVert *v1, LineartVert *v2, LineartTriangle *tri, const double *last, double *rv)
{
- double Lv[3];
- double Rv[3];
- double dot_l, dot_r;
- LineartVert *result;
+ /* Direction vectors for the edge verts. We will check if the verts are on the same side of the
+ * triangle or not. */
+ double dir_v1[3], dir_v2[3];
+ double dot_v1, dot_v2;
double gloc[3];
- LineartVert *l = v1, *r = v2;
- for (LinkNode *ln = (void *)testing->intersecting_verts; ln; ln = ln->next) {
- LineartVertIntersection *vt = ln->link;
- if (vt->intersecting_with == tri &&
- lineart_vert_already_intersected_2v(
- vt, (LineartVertIntersection *)l, (LineartVertIntersection *)r)) {
- return (LineartVert *)vt;
- }
- }
-
- sub_v3_v3v3_db(Lv, l->gloc, testing->v[0]->gloc);
- sub_v3_v3v3_db(Rv, r->gloc, testing->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v1, v1->gloc, tri->v[0]->gloc);
+ sub_v3_v3v3_db(dir_v2, v2->gloc, tri->v[0]->gloc);
- dot_l = dot_v3v3_db(Lv, testing->gn);
- dot_r = dot_v3v3_db(Rv, testing->gn);
+ dot_v1 = dot_v3v3_db(dir_v1, tri->gn);
+ dot_v2 = dot_v3v3_db(dir_v2, tri->gn);
- if (dot_l * dot_r > 0 || (!dot_l && !dot_r)) {
- return 0;
+ if (dot_v1 * dot_v2 > 0 || (!dot_v1 && !dot_v2)) {
+ return false;
}
- dot_l = fabs(dot_l);
- dot_r = fabs(dot_r);
+ dot_v1 = fabs(dot_v1);
+ dot_v2 = fabs(dot_v2);
- interp_v3_v3v3_db(gloc, l->gloc, r->gloc, dot_l / (dot_l + dot_r));
+ interp_v3_v3v3_db(gloc, v1->gloc, v2->gloc, dot_v1 / (dot_v1 + dot_v2));
- /* Due to precision issue, we might end up with the same point as the one we already detected.
- */
- if (last && LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[0], gloc[0]) &&
- LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[1], gloc[1]) &&
- LRT_DOUBLE_CLOSE_ENOUGH(last->gloc[2], gloc[2])) {
- return NULL;
+ /* Due to precision issue, we might end up with the same point as the one we already detected. */
+ if (last && LRT_DOUBLE_CLOSE_ENOUGH(last[0], gloc[0]) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(last[1], gloc[1]) && LRT_DOUBLE_CLOSE_ENOUGH(last[2], gloc[2])) {
+ return false;
}
if (!(lineart_point_inside_triangle3d(
- gloc, testing->v[0]->gloc, testing->v[1]->gloc, testing->v[2]->gloc))) {
- return NULL;
+ gloc, tri->v[0]->gloc, tri->v[1]->gloc, tri->v[2]->gloc))) {
+ return false;
}
- /* This is an intersection vert, the size is bigger than LineartVert,
- * allocated separately. */
- result = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartVertIntersection));
-
- /* Indicate the data structure difference. */
- result->flag = LRT_VERT_HAS_INTERSECTION_DATA;
+ copy_v3_v3_db(rv, gloc);
- copy_v3_v3_db(result->gloc, gloc);
-
- lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, result);
-
- return result;
+ return true;
}
-/**
- * Test if two triangles intersect. Generates one intersection line if the check succeeds.
- */
-static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- LineartTriangle *testing)
+static bool lineart_triangle_intersect_math(LineartTriangle *tri,
+ LineartTriangle *t2,
+ double *v1,
+ double *v2)
{
- LineartVert *v1 = 0, *v2 = 0;
- LineartVert **next = &v1;
- LineartEdge *result;
- LineartVert *E0T = 0;
- LineartVert *E1T = 0;
- LineartVert *E2T = 0;
- LineartVert *TE0 = 0;
- LineartVert *TE1 = 0;
- LineartVert *TE2 = 0;
+ double *next = v1, *last = NULL;
LineartVert *sv1, *sv2;
- double cl[3];
- double ZMin, ZMax;
- ZMax = rb->far_clip;
- ZMin = rb->near_clip;
- copy_v3_v3_db(cl, rb->camera_pos);
- LineartVert *share = lineart_triangle_share_point(testing, tri);
+ LineartVert *share = lineart_triangle_share_point(t2, tri);
if (share) {
/* If triangles have sharing points like `abc` and `acd`, then we only need to detect `bc`
* against `acd` or `cd` against `abc`. */
- LineartVert *new_share;
lineart_triangle_get_other_verts(tri, share, &sv1, &sv2);
- v1 = new_share = lineart_mem_acquire(&rb->render_data_pool, (sizeof(LineartVertIntersection)));
-
- new_share->flag = LRT_VERT_HAS_INTERSECTION_DATA;
-
- copy_v3_v3_db(new_share->gloc, share->gloc);
+ copy_v3_v3_db(v1, share->gloc);
- v2 = lineart_triangle_2v_intersection_test(rb, sv1, sv2, tri, testing, 0);
-
- if (v2 == NULL) {
- lineart_triangle_get_other_verts(testing, share, &sv1, &sv2);
- v2 = lineart_triangle_2v_intersection_test(rb, sv1, sv2, testing, tri, 0);
- if (v2 == NULL) {
- return 0;
+ if (!lineart_triangle_2v_intersection_math(sv1, sv2, t2, 0, v2)) {
+ lineart_triangle_get_other_verts(t2, share, &sv1, &sv2);
+ if (lineart_triangle_2v_intersection_math(sv1, sv2, tri, 0, v2)) {
+ return true;
}
- lineart_prepend_pool(&testing->intersecting_verts, &rb->render_data_pool, new_share);
- }
- else {
- lineart_prepend_pool(&tri->intersecting_verts, &rb->render_data_pool, new_share);
}
}
else {
/* If not sharing any points, then we need to try all the possibilities. */
- E0T = lineart_triangle_2v_intersection_test(rb, tri->v[0], tri->v[1], tri, testing, 0);
- if (E0T && (!(*next))) {
- (*next) = E0T;
- lineart_vert_set_intersection_2v((*next), tri->v[0], tri->v[1]);
- next = &v2;
- }
- E1T = lineart_triangle_2v_intersection_test(rb, tri->v[1], tri->v[2], tri, testing, v1);
- if (E1T && (!(*next))) {
- (*next) = E1T;
- lineart_vert_set_intersection_2v((*next), tri->v[1], tri->v[2]);
- next = &v2;
- }
- if (!(*next)) {
- E2T = lineart_triangle_2v_intersection_test(rb, tri->v[2], tri->v[0], tri, testing, v1);
- }
- if (E2T && (!(*next))) {
- (*next) = E2T;
- lineart_vert_set_intersection_2v((*next), tri->v[2], tri->v[0]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(tri->v[0], tri->v[1], t2, 0, v1)) {
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE0 = lineart_triangle_2v_intersection_test(
- rb, testing->v[0], testing->v[1], testing, tri, v1);
- }
- if (TE0 && (!(*next))) {
- (*next) = TE0;
- lineart_vert_set_intersection_2v((*next), testing->v[0], testing->v[1]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(tri->v[1], tri->v[2], t2, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE1 = lineart_triangle_2v_intersection_test(
- rb, testing->v[1], testing->v[2], testing, tri, v1);
+ if (lineart_triangle_2v_intersection_math(tri->v[2], tri->v[0], t2, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (TE1 && (!(*next))) {
- (*next) = TE1;
- lineart_vert_set_intersection_2v((*next), testing->v[1], testing->v[2]);
- next = &v2;
+
+ if (lineart_triangle_2v_intersection_math(t2->v[0], t2->v[1], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (!(*next)) {
- TE2 = lineart_triangle_2v_intersection_test(
- rb, testing->v[2], testing->v[0], testing, tri, v1);
+ if (lineart_triangle_2v_intersection_math(t2->v[1], t2->v[2], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
- if (TE2 && (!(*next))) {
- (*next) = TE2;
- lineart_vert_set_intersection_2v((*next), testing->v[2], testing->v[0]);
- next = &v2;
+ if (lineart_triangle_2v_intersection_math(t2->v[2], t2->v[0], tri, last, next)) {
+ if (last) {
+ return true;
+ }
+ next = v2;
+ last = v1;
}
+ }
+ return false;
+}
- if (!(*next)) {
- return 0;
- }
+static void lineart_add_isec_thread(LineartIsecThread *th,
+ const double *v1,
+ const double *v2,
+ LineartTriangle *tri1,
+ LineartTriangle *tri2)
+{
+ if (th->current == th->max) {
+
+ LineartIsecSingle *new_array = MEM_mallocN(sizeof(LineartIsecSingle) * th->max * 2,
+ "LineartIsecSingle");
+ memcpy(new_array, th->array, sizeof(LineartIsecSingle) * th->max);
+ th->max *= 2;
+ MEM_freeN(th->array);
+ th->array = new_array;
+ }
+ LineartIsecSingle *isec_single = &th->array[th->current];
+ copy_v3fl_v3db(isec_single->v1, v1);
+ copy_v3fl_v3db(isec_single->v2, v2);
+ isec_single->tri1 = tri1;
+ isec_single->tri2 = tri2;
+ if (tri1->target_reference > tri2->target_reference) {
+ SWAP(LineartTriangle *, isec_single->tri1, isec_single->tri2);
+ }
+ th->current++;
+}
+
+#define LRT_ISECT_TRIANGLE_PER_THREAD 4096
+
+static bool lineart_schedule_new_triangle_task(LineartIsecThread *th)
+{
+ LineartData *ld = th->ld;
+ int remaining = LRT_ISECT_TRIANGLE_PER_THREAD;
+
+ BLI_spin_lock(&ld->lock_task);
+ LineartElementLinkNode *eln = ld->isect_scheduled_up_to;
+
+ if (!eln) {
+ BLI_spin_unlock(&ld->lock_task);
+ return false;
}
- /* The intersection line has been generated only in geometry space, so we need to transform
- * them as well. */
- mul_v4_m4v3_db(v1->fbcoord, rb->view_projection, v1->gloc);
- mul_v4_m4v3_db(v2->fbcoord, rb->view_projection, v2->gloc);
- if (rb->cam_is_persp) {
- mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3]));
- mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3]));
+ th->pending_from = eln;
+ th->index_from = ld->isect_scheduled_up_to_index;
+
+ while (remaining > 0 && eln) {
+ int remaining_this_eln = eln->element_count - ld->isect_scheduled_up_to_index;
+ int added_count = MIN2(remaining, remaining_this_eln);
+ remaining -= added_count;
+ if (remaining || added_count == remaining_this_eln) {
+ eln = eln->next;
+ ld->isect_scheduled_up_to = eln;
+ ld->isect_scheduled_up_to_index = 0;
+ }
+ else {
+ ld->isect_scheduled_up_to_index += added_count;
+ }
}
- v1->fbcoord[0] -= rb->shift_x * 2;
- v1->fbcoord[1] -= rb->shift_y * 2;
- v2->fbcoord[0] -= rb->shift_x * 2;
- v2->fbcoord[1] -= rb->shift_y * 2;
- /* This z transformation is not the same as the rest of the part, because the data don't go
- * through normal perspective division calls in the pipeline, but this way the 3D result and
- * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke
- * generation anyway. */
- v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin));
- v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin));
+ th->pending_to = eln ? eln : ld->geom.triangle_buffer_pointers.last;
+ th->index_to = ld->isect_scheduled_up_to_index;
- ((LineartVertIntersection *)v1)->intersecting_with = tri;
- ((LineartVertIntersection *)v2)->intersecting_with = testing;
+ BLI_spin_unlock(&ld->lock_task);
- result = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge));
- result->v1 = v1;
- result->v2 = v2;
- result->t1 = tri;
- result->t2 = testing;
+ return true;
+}
- LineartEdgeSegment *es = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdgeSegment));
- BLI_addtail(&result->segments, es);
- /* Don't need to OR flags right now, just a type mark. */
- result->flags = LRT_EDGE_FLAG_INTERSECTION;
- result->intersection_mask = (tri->intersection_mask | testing->intersection_mask);
+/* This function initializes two things:
+ * 1) Triangle array scheduling info, for each worker thread to get its chunk from the scheduler.
+ * 2) Per-thread intersection result array. Does not store actual #LineartEdge, these results will
+ * be finalized by #lineart_create_edges_from_isec_data
+ */
+static void lineart_init_isec_thread(LineartIsecData *d, LineartData *ld, int thread_count)
+{
+ d->threads = MEM_callocN(sizeof(LineartIsecThread) * thread_count, "LineartIsecThread arr");
+ d->ld = ld;
+ d->thread_count = thread_count;
- lineart_add_edge_to_array(&rb->pending_edges, result);
+ ld->isect_scheduled_up_to = ld->geom.triangle_buffer_pointers.first;
+ ld->isect_scheduled_up_to_index = 0;
- return result;
+ for (int i = 0; i < thread_count; i++) {
+ LineartIsecThread *it = &d->threads[i];
+ it->array = MEM_mallocN(sizeof(LineartIsecSingle) * 100, "LineartIsecSingle arr");
+ it->max = 100;
+ it->current = 0;
+ it->thread_id = i;
+ it->ld = ld;
+ }
}
-static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- LineartBoundingArea *ba)
+static void lineart_destroy_isec_thread(LineartIsecData *d)
{
- /* Testing_triangle->testing[0] is used to store pairing triangle reference.
- * See definition of LineartTriangleThread for more info. */
- LineartTriangle *testing_triangle;
- LineartTriangleThread *tt;
+ for (int i = 0; i < d->thread_count; i++) {
+ LineartIsecThread *it = &d->threads[i];
+ MEM_freeN(it->array);
+ }
+ MEM_freeN(d->threads);
+}
- double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
+static void lineart_triangle_intersect_in_bounding_area(LineartTriangle *tri,
+ LineartBoundingArea *ba,
+ LineartIsecThread *th,
+ int up_to)
+{
+ BLI_assert(th != NULL);
- /* If this is not the smallest subdiv bounding area. */
- if (ba->child) {
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[0]);
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[1]);
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[2]);
- lineart_triangle_intersect_in_bounding_area(rb, tri, &ba->child[3]);
+ if (!th) {
return;
}
- /* If this _is_ the smallest subdiv bounding area, then do the intersections there. */
- for (int i = 0; i < ba->triangle_count; i++) {
- testing_triangle = ba->linked_triangles[i];
- tt = (LineartTriangleThread *)testing_triangle;
+ double *G0 = tri->v[0]->gloc, *G1 = tri->v[1]->gloc, *G2 = tri->v[2]->gloc;
- if (testing_triangle == tri || tt->testing_e[0] == (LineartEdge *)tri) {
+ /* If this _is_ the smallest subdivision bounding area, then do the intersections there. */
+ for (int i = 0; i < up_to; i++) {
+ /* Testing_triangle->testing[0] is used to store pairing triangle reference.
+ * See definition of LineartTriangleThread for more info. */
+ LineartTriangle *testing_triangle = ba->linked_triangles[i];
+ LineartTriangleThread *tt = (LineartTriangleThread *)testing_triangle;
+
+ if (testing_triangle == tri || tt->testing_e[th->thread_id] == (LineartEdge *)tri) {
continue;
}
- tt->testing_e[0] = (LineartEdge *)tri;
+ tt->testing_e[th->thread_id] = (LineartEdge *)tri;
if ((testing_triangle->flags & LRT_TRIANGLE_NO_INTERSECTION) ||
((testing_triangle->flags & LRT_TRIANGLE_INTERSECTION_ONLY) &&
@@ -3285,65 +3415,106 @@ static void lineart_triangle_intersect_in_bounding_area(LineartRenderBuffer *rb,
}
/* If we do need to compute intersection, then finally do it. */
- lineart_triangle_intersect(rb, tri, testing_triangle);
+
+ double iv1[3], iv2[3];
+ if (lineart_triangle_intersect_math(tri, testing_triangle, iv1, iv2)) {
+ lineart_add_isec_thread(th, iv1, iv2, tri, testing_triangle);
+ }
}
}
/**
* The calculated view vector will point towards the far-plane from the camera position.
*/
-static void lineart_main_get_view_vector(LineartRenderBuffer *rb)
+void lineart_main_get_view_vector(LineartData *ld)
{
float direction[3] = {0, 0, 1};
float trans[3];
float inv[4][4];
float obmat_no_scale[4][4];
- copy_m4_m4(obmat_no_scale, rb->cam_obmat);
-
+ copy_m4_m4(obmat_no_scale, ld->conf.cam_obmat);
normalize_v3(obmat_no_scale[0]);
normalize_v3(obmat_no_scale[1]);
normalize_v3(obmat_no_scale[2]);
invert_m4_m4(inv, obmat_no_scale);
transpose_m4(inv);
mul_v3_mat3_m4v3(trans, inv, direction);
- copy_m4_m4(rb->cam_obmat, obmat_no_scale);
- copy_v3db_v3fl(rb->view_vector, trans);
+ copy_m4_m4(ld->conf.cam_obmat, obmat_no_scale);
+ copy_v3db_v3fl(ld->conf.view_vector, trans);
+
+ if (ld->conf.light_reference_available) {
+ copy_m4_m4(obmat_no_scale, ld->conf.cam_obmat_secondary);
+ normalize_v3(obmat_no_scale[0]);
+ normalize_v3(obmat_no_scale[1]);
+ normalize_v3(obmat_no_scale[2]);
+ invert_m4_m4(inv, obmat_no_scale);
+ transpose_m4(inv);
+ mul_v3_mat3_m4v3(trans, inv, direction);
+ copy_m4_m4(ld->conf.cam_obmat_secondary, obmat_no_scale);
+ copy_v3db_v3fl(ld->conf.view_vector_secondary, trans);
+ }
+}
+
+static void lineart_end_bounding_area_recursive(LineartBoundingArea *ba)
+{
+ BLI_spin_end(&ba->lock);
+ if (ba->child) {
+ for (int i = 0; i < 4; i++) {
+ lineart_end_bounding_area_recursive(&ba->child[i]);
+ }
+ }
}
-static void lineart_destroy_render_data(LineartRenderBuffer *rb)
+void lineart_destroy_render_data_keep_init(LineartData *ld)
{
- if (rb == NULL) {
+ if (ld == NULL) {
return;
}
- BLI_listbase_clear(&rb->chains);
- BLI_listbase_clear(&rb->wasted_cuts);
+ BLI_listbase_clear(&ld->chains);
+ BLI_listbase_clear(&ld->wasted_cuts);
+
+ BLI_listbase_clear(&ld->geom.vertex_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.line_buffer_pointers);
+ BLI_listbase_clear(&ld->geom.triangle_buffer_pointers);
+
+ if (ld->pending_edges.array) {
+ MEM_freeN(ld->pending_edges.array);
+ }
- BLI_listbase_clear(&rb->vertex_buffer_pointers);
- BLI_listbase_clear(&rb->line_buffer_pointers);
- BLI_listbase_clear(&rb->triangle_buffer_pointers);
+ for (int i = 0; i < ld->qtree.initial_tile_count; i++) {
+ lineart_end_bounding_area_recursive(&ld->qtree.initials[i]);
+ }
+ lineart_free_bounding_area_memories(ld);
- BLI_spin_end(&rb->lock_task);
- BLI_spin_end(&rb->lock_cuts);
- BLI_spin_end(&rb->render_data_pool.lock_mem);
+ lineart_mem_destroy(&ld->render_data_pool);
+}
- if (rb->pending_edges.array) {
- MEM_freeN(rb->pending_edges.array);
+static void lineart_destroy_render_data(LineartData *ld)
+{
+ if (ld == NULL) {
+ return;
}
- lineart_mem_destroy(&rb->render_data_pool);
+ BLI_spin_end(&ld->lock_task);
+ BLI_spin_end(&ld->lock_cuts);
+ BLI_spin_end(&ld->render_data_pool.lock_mem);
+
+ lineart_destroy_render_data_keep_init(ld);
+
+ lineart_mem_destroy(&ld->render_data_pool);
}
void MOD_lineart_destroy_render_data(LineartGpencilModifierData *lmd)
{
- LineartRenderBuffer *rb = lmd->render_buffer_ptr;
+ LineartData *ld = lmd->la_data_ptr;
- lineart_destroy_render_data(rb);
+ lineart_destroy_render_data(ld);
- if (rb) {
- MEM_freeN(rb);
- lmd->render_buffer_ptr = NULL;
+ if (ld) {
+ MEM_freeN(ld);
+ lmd->la_data_ptr = NULL;
}
if (G.debug_value == 4000) {
@@ -3367,17 +3538,17 @@ void MOD_lineart_clear_cache(struct LineartCache **lc)
(*lc) = NULL;
}
-static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
- LineartGpencilModifierData *lmd,
- Object *camera,
- Object *active_camera,
- LineartCache *lc)
+static LineartData *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");
+ LineartData *ld = MEM_callocN(sizeof(LineartData), "Line Art render buffer");
lmd->cache = lc;
- lmd->render_buffer_ptr = rb;
- lc->rb_edge_types = lmd->edge_types_override;
+ lmd->la_data_ptr = ld;
+ lc->all_enabled_edge_types = lmd->edge_types_override;
if (!scene || !camera || !lc) {
return NULL;
@@ -3390,98 +3561,120 @@ static LineartRenderBuffer *lineart_create_render_buffer(Scene *scene,
clipping_offset = 0.0001;
}
- copy_v3db_v3fl(rb->camera_pos, camera->obmat[3]);
+ copy_v3db_v3fl(ld->conf.camera_pos, camera->obmat[3]);
if (active_camera) {
- copy_v3db_v3fl(rb->active_camera_pos, active_camera->obmat[3]);
+ copy_v3db_v3fl(ld->conf.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;
- rb->w = scene->r.xsch;
- rb->h = scene->r.ysch;
+ copy_m4_m4(ld->conf.cam_obmat, camera->obmat);
+
+ ld->conf.cam_is_persp = (c->type == CAM_PERSP);
+ ld->conf.near_clip = c->clip_start + clipping_offset;
+ ld->conf.far_clip = c->clip_end - clipping_offset;
+ ld->w = scene->r.xsch;
+ ld->h = scene->r.ysch;
- if (rb->cam_is_persp) {
- rb->tile_recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE;
+ if (ld->conf.cam_is_persp) {
+ ld->qtree.recursive_level = LRT_TILE_RECURSIVE_PERSPECTIVE;
}
else {
- rb->tile_recursive_level = LRT_TILE_RECURSIVE_ORTHO;
+ ld->qtree.recursive_level = LRT_TILE_RECURSIVE_ORTHO;
}
- double asp = ((double)rb->w / (double)rb->h);
- int fit = BKE_camera_sensor_fit(c->sensor_fit, rb->w, rb->h);
- rb->shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp;
- rb->shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp;
+ double asp = ((double)ld->w / (double)ld->h);
+ int fit = BKE_camera_sensor_fit(c->sensor_fit, ld->w, ld->h);
+ ld->conf.shift_x = fit == CAMERA_SENSOR_FIT_HOR ? c->shiftx : c->shiftx / asp;
+ ld->conf.shift_y = fit == CAMERA_SENSOR_FIT_VERT ? c->shifty : c->shifty * asp;
- rb->overscan = lmd->overscan;
+ ld->conf.overscan = lmd->overscan;
- rb->shift_x /= (1 + rb->overscan);
- rb->shift_y /= (1 + rb->overscan);
+ ld->conf.shift_x /= (1 + ld->conf.overscan);
+ ld->conf.shift_y /= (1 + ld->conf.overscan);
- rb->crease_threshold = cos(M_PI - lmd->crease_threshold);
- rb->chaining_image_threshold = lmd->chaining_image_threshold;
- rb->angle_splitting_threshold = lmd->angle_splitting_threshold;
- rb->chain_smooth_tolerance = lmd->chain_smooth_tolerance;
+ if (lmd->light_contour_object) {
+ Object *light_obj = lmd->light_contour_object;
+ copy_v3db_v3fl(ld->conf.camera_pos_secondary, light_obj->obmat[3]);
+ copy_m4_m4(ld->conf.cam_obmat_secondary, light_obj->obmat);
+ ld->conf.light_reference_available = true;
+ if (light_obj->type == OB_LAMP) {
+ ld->conf.cam_is_persp_secondary = ((Light *)light_obj->data)->type != LA_SUN;
+ }
+ }
- rb->fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0;
- rb->fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0;
- rb->allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0;
- 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;
+ ld->conf.crease_threshold = cos(M_PI - lmd->crease_threshold);
+ ld->conf.chaining_image_threshold = lmd->chaining_image_threshold;
+ ld->conf.angle_splitting_threshold = lmd->angle_splitting_threshold;
+ ld->conf.chain_smooth_tolerance = lmd->chain_smooth_tolerance;
+
+ ld->conf.fuzzy_intersections = (lmd->calculation_flags & LRT_INTERSECTION_AS_CONTOUR) != 0;
+ ld->conf.fuzzy_everything = (lmd->calculation_flags & LRT_EVERYTHING_AS_CONTOUR) != 0;
+ ld->conf.allow_boundaries = (lmd->calculation_flags & LRT_ALLOW_CLIPPING_BOUNDARIES) != 0;
+ ld->conf.use_loose_as_contour = (lmd->calculation_flags & LRT_LOOSE_AS_CONTOUR) != 0;
+ ld->conf.use_loose_edge_chain = (lmd->calculation_flags & LRT_CHAIN_LOOSE_EDGES) != 0;
+ ld->conf.use_geometry_space_chain = (lmd->calculation_flags & LRT_CHAIN_GEOMETRY_SPACE) != 0;
+ ld->conf.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;
+ ld->conf.allow_overlapping_edges = (lmd->calculation_flags & LRT_ALLOW_OVERLAPPING_EDGES) != 0;
- rb->allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0;
+ ld->conf.allow_duplicated_types = (lmd->calculation_flags & LRT_ALLOW_OVERLAP_EDGE_TYPES) != 0;
- 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;
+ ld->conf.force_crease = (lmd->calculation_flags & LRT_USE_CREASE_ON_SMOOTH_SURFACES) != 0;
+ ld->conf.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;
+ ld->conf.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;
+ ld->conf.max_occlusion_level = lmd->level_end_override;
int16_t edge_types = lmd->edge_types_override;
- rb->use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
- rb->use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0;
- rb->use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
- rb->use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
- rb->use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
- rb->use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0;
+ /* lmd->edge_types_override contains all used flags in the modifier stack. */
+ ld->conf.use_contour = (edge_types & LRT_EDGE_FLAG_CONTOUR) != 0;
+ ld->conf.use_crease = (edge_types & LRT_EDGE_FLAG_CREASE) != 0;
+ ld->conf.use_material = (edge_types & LRT_EDGE_FLAG_MATERIAL) != 0;
+ ld->conf.use_edge_marks = (edge_types & LRT_EDGE_FLAG_EDGE_MARK) != 0;
+ ld->conf.use_intersections = (edge_types & LRT_EDGE_FLAG_INTERSECTION) != 0;
+ ld->conf.use_loose = (edge_types & LRT_EDGE_FLAG_LOOSE) != 0;
+ ld->conf.use_light_contour = ((edge_types & LRT_EDGE_FLAG_LIGHT_CONTOUR) != 0 &&
+ (lmd->light_contour_object != NULL));
+ ld->conf.use_shadow = ((edge_types & LRT_EDGE_FLAG_PROJECTED_SHADOW) != 0 &&
+ (lmd->light_contour_object != NULL));
+
+ ld->conf.shadow_selection = lmd->shadow_selection_override;
+ ld->conf.shadow_enclose_shapes = (lmd->calculation_flags & LRT_SHADOW_ENCLOSED_SHAPES) != 0;
+ ld->conf.shadow_use_silhouette = lmd->shadow_use_silhouette_override != 0;
+
+ ld->conf.use_back_face_culling = (lmd->calculation_flags & LRT_USE_BACK_FACE_CULLING) != 0;
+
+ ld->conf.filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0;
+ ld->conf.filter_face_mark = (lmd->calculation_flags & LRT_FILTER_FACE_MARK) != 0;
+ ld->conf.filter_face_mark_boundaries = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_BOUNDARIES) != 0;
+ ld->conf.filter_face_mark_keep_contour = (lmd->calculation_flags &
+ LRT_FILTER_FACE_MARK_KEEP_CONTOUR) != 0;
- rb->filter_face_mark_invert = (lmd->calculation_flags & LRT_FILTER_FACE_MARK_INVERT) != 0;
- 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;
+ ld->chain_data_pool = &lc->chain_data_pool;
- rb->chain_data_pool = &lc->chain_data_pool;
+ /* See #LineartData::edge_data_pool for explanation. */
+ ld->edge_data_pool = &ld->render_data_pool;
- BLI_spin_init(&rb->lock_task);
- BLI_spin_init(&rb->lock_cuts);
- BLI_spin_init(&rb->render_data_pool.lock_mem);
+ BLI_spin_init(&ld->lock_task);
+ BLI_spin_init(&ld->lock_cuts);
+ BLI_spin_init(&ld->render_data_pool.lock_mem);
- return rb;
+ ld->thread_count = BKE_render_num_threads(&scene->r);
+
+ return ld;
}
-static int lineart_triangle_size_get(const Scene *scene, LineartRenderBuffer *rb)
+static int lineart_triangle_size_get(LineartData *ld)
{
- if (rb->thread_count == 0) {
- rb->thread_count = BKE_render_num_threads(&scene->r);
- }
- return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (rb->thread_count));
+ return sizeof(LineartTriangle) + (sizeof(LineartEdge *) * (ld->thread_count));
}
-static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
+void lineart_main_bounding_area_make_initial(LineartData *ld)
{
/* Initial tile split is defined as 4 (subdivided as 4*4), increasing the value allows the
* algorithm to build the acceleration structure for bigger scenes a little faster but not as
@@ -3491,24 +3684,35 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
int row, col;
LineartBoundingArea *ba;
+ /* Always make sure the shortest side has at least LRT_BA_ROWS tiles. */
+ if (ld->w > ld->h) {
+ sp_w = sp_h * ld->w / ld->h;
+ }
+ else {
+ sp_h = sp_w * ld->h / ld->w;
+ }
+
/* Because NDC (Normalized Device Coordinates) range is (-1,1),
* so the span for each initial tile is double of that in the (0,1) range. */
double span_w = (double)1 / sp_w * 2.0;
double span_h = (double)1 / sp_h * 2.0;
- rb->tile_count_x = sp_w;
- rb->tile_count_y = sp_h;
- rb->width_per_tile = span_w;
- rb->height_per_tile = span_h;
+ ld->qtree.count_x = sp_w;
+ ld->qtree.count_y = sp_h;
+ ld->qtree.tile_width = span_w;
+ ld->qtree.tile_height = span_h;
- rb->bounding_area_count = sp_w * sp_h;
- rb->initial_bounding_areas = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartBoundingArea) * rb->bounding_area_count);
+ ld->qtree.initial_tile_count = sp_w * sp_h;
+ ld->qtree.initials = lineart_mem_acquire(
+ &ld->render_data_pool, sizeof(LineartBoundingArea) * ld->qtree.initial_tile_count);
+ for (int i = 0; i < ld->qtree.initial_tile_count; i++) {
+ BLI_spin_init(&ld->qtree.initials[i].lock);
+ }
/* Initialize tiles. */
for (row = 0; row < sp_h; row++) {
for (col = 0; col < sp_w; col++) {
- ba = &rb->initial_bounding_areas[row * LRT_BA_ROWS + col];
+ ba = &ld->qtree.initials[row * ld->qtree.count_x + col];
/* Set the four direction limits. */
ba->l = span_w * col - 1.0;
@@ -3522,34 +3726,12 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
/* Init linked_triangles array. */
ba->max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT;
ba->max_line_count = LRT_TILE_EDGE_COUNT_INITIAL;
- ba->linked_triangles = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count);
- ba->linked_lines = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartEdge *) * ba->max_line_count);
+ ba->linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba->max_triangle_count,
+ "ba_linked_triangles");
+ ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba->max_line_count,
+ "ba_linked_lines");
- /* Link adjacent ones. */
- if (row) {
- lineart_list_append_pointer_pool(
- &ba->up,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[(row - 1) * LRT_BA_ROWS + col]);
- }
- if (col) {
- lineart_list_append_pointer_pool(&ba->lp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[row * LRT_BA_ROWS + col - 1]);
- }
- if (row != sp_h - 1) {
- lineart_list_append_pointer_pool(
- &ba->bp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[(row + 1) * LRT_BA_ROWS + col]);
- }
- if (col != sp_w - 1) {
- lineart_list_append_pointer_pool(&ba->rp,
- &rb->render_data_pool,
- &rb->initial_bounding_areas[row * LRT_BA_ROWS + col + 1]);
- }
+ BLI_spin_init(&ba->lock);
}
}
}
@@ -3557,11 +3739,11 @@ static void lineart_main_bounding_area_make_initial(LineartRenderBuffer *rb)
/**
* Re-link adjacent tiles after one gets subdivided.
*/
-static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartBoundingArea *root)
+static void lineart_bounding_areas_connect_new(LineartData *ld, LineartBoundingArea *root)
{
LineartBoundingArea *ba = root->child, *tba;
LinkData *lip2, *next_lip;
- LineartStaticMemPool *mph = &rb->render_data_pool;
+ LineartStaticMemPool *mph = &ld->render_data_pool;
/* Inter-connection with newly created 4 child bounding areas. */
lineart_list_append_pointer_pool(&ba[1].rp, mph, &ba[0]);
@@ -3697,17 +3879,59 @@ static void lineart_bounding_areas_connect_new(LineartRenderBuffer *rb, LineartB
BLI_listbase_clear(&root->bp);
}
+static void lineart_bounding_areas_connect_recursive(LineartData *ld, LineartBoundingArea *root)
+{
+ if (root->child) {
+ lineart_bounding_areas_connect_new(ld, root);
+ for (int i = 0; i < 4; i++) {
+ lineart_bounding_areas_connect_recursive(ld, &root->child[i]);
+ }
+ }
+}
+
+void lineart_main_bounding_areas_connect_post(LineartData *ld)
+{
+ int total_tile_initial = ld->qtree.count_x * ld->qtree.count_y;
+ int tiles_per_row = ld->qtree.count_x;
+
+ for (int row = 0; row < ld->qtree.count_y; row++) {
+ for (int col = 0; col < ld->qtree.count_x; col++) {
+ LineartBoundingArea *ba = &ld->qtree.initials[row * tiles_per_row + col];
+ /* Link adjacent ones. */
+ if (row) {
+ lineart_list_append_pointer_pool(
+ &ba->up, &ld->render_data_pool, &ld->qtree.initials[(row - 1) * tiles_per_row + col]);
+ }
+ if (col) {
+ lineart_list_append_pointer_pool(
+ &ba->lp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col - 1]);
+ }
+ if (row != ld->qtree.count_y - 1) {
+ lineart_list_append_pointer_pool(
+ &ba->bp, &ld->render_data_pool, &ld->qtree.initials[(row + 1) * tiles_per_row + col]);
+ }
+ if (col != ld->qtree.count_x - 1) {
+ lineart_list_append_pointer_pool(
+ &ba->rp, &ld->render_data_pool, &ld->qtree.initials[row * tiles_per_row + col + 1]);
+ }
+ }
+ }
+ for (int i = 0; i < total_tile_initial; i++) {
+ lineart_bounding_areas_connect_recursive(ld, &ld->qtree.initials[i]);
+ }
+}
+
/**
- * Subdivide a tile after one tile contains too many triangles.
+ * Subdivide a tile after one tile contains too many triangles, then re-link triangles into all the
+ * child tiles.
*/
-static void lineart_bounding_area_split(LineartRenderBuffer *rb,
+static void lineart_bounding_area_split(LineartData *ld,
LineartBoundingArea *root,
int recursive_level)
{
- LineartBoundingArea *ba = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartBoundingArea) * 4);
- LineartTriangle *tri;
+ LineartBoundingArea *ba = lineart_mem_acquire_thread(&ld->render_data_pool,
+ sizeof(LineartBoundingArea) * 4);
ba[0].l = root->cx;
ba[0].r = root->r;
ba[0].u = root->u;
@@ -3736,80 +3960,80 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
ba[3].cx = (ba[3].l + ba[3].r) / 2;
ba[3].cy = (ba[3].u + ba[3].b) / 2;
- root->child = ba;
-
- lineart_bounding_areas_connect_new(rb, root);
-
- /* Init linked_triangles array. */
+ /* Init linked_triangles array and locks. */
for (int i = 0; i < 4; i++) {
ba[i].max_triangle_count = LRT_TILE_SPLITTING_TRIANGLE_LIMIT;
ba[i].max_line_count = LRT_TILE_EDGE_COUNT_INITIAL;
- ba[i].linked_triangles = lineart_mem_acquire(
- &rb->render_data_pool, sizeof(LineartTriangle *) * LRT_TILE_SPLITTING_TRIANGLE_LIMIT);
- ba[i].linked_lines = lineart_mem_acquire(&rb->render_data_pool,
- sizeof(LineartEdge *) * LRT_TILE_EDGE_COUNT_INITIAL);
+ ba[i].linked_triangles = MEM_callocN(sizeof(LineartTriangle *) * ba[i].max_triangle_count,
+ "ba_linked_triangles");
+ ba[i].linked_lines = MEM_callocN(sizeof(LineartEdge *) * ba[i].max_line_count,
+ "ba_linked_lines");
+ BLI_spin_init(&ba[i].lock);
}
- for (int i = 0; i < root->triangle_count; i++) {
- tri = root->linked_triangles[i];
- LineartBoundingArea *cba = root->child;
+ for (uint32_t i = 0; i < root->triangle_count; i++) {
+ LineartTriangle *tri = root->linked_triangles[i];
+
double b[4];
b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
- if (LRT_BOUND_AREA_CROSSES(b, &cba[0].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[0], tri, b, 0, recursive_level + 1, false);
+
+ /* Re-link triangles into child tiles, not doing intersection lines during this because this
+ * batch of triangles are all tested with each other for intersections. */
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[0].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[0], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[1].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[1], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[1].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[1], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[2].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[2], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[2].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[2], tri, b, 0, recursive_level + 1, false, NULL);
}
- if (LRT_BOUND_AREA_CROSSES(b, &cba[3].l)) {
- lineart_bounding_area_link_triangle(rb, &cba[3], tri, b, 0, recursive_level + 1, false);
+ if (LRT_BOUND_AREA_CROSSES(b, &ba[3].l)) {
+ lineart_bounding_area_link_triangle(ld, &ba[3], tri, b, 0, recursive_level + 1, false, NULL);
}
}
- rb->bounding_area_count += 3;
+ /* At this point the child tiles are fully initialized and it's safe for new triangles to be
+ * inserted, so assign root->child for #lineart_bounding_area_link_triangle to use. */
+ root->child = ba;
}
-static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb),
+static bool lineart_bounding_area_edge_intersect(LineartData *UNUSED(fb),
const double l[2],
const double r[2],
LineartBoundingArea *ba)
{
- double vx, vy;
+ double dx, dy;
double converted[4];
double c1, c;
- if (((converted[0] = (double)ba->l) > MAX2(l[0], r[0])) ||
- ((converted[1] = (double)ba->r) < MIN2(l[0], r[0])) ||
- ((converted[2] = (double)ba->b) > MAX2(l[1], r[1])) ||
- ((converted[3] = (double)ba->u) < MIN2(l[1], r[1]))) {
+ if (((converted[0] = ba->l) > MAX2(l[0], r[0])) || ((converted[1] = ba->r) < MIN2(l[0], r[0])) ||
+ ((converted[2] = ba->b) > MAX2(l[1], r[1])) || ((converted[3] = ba->u) < MIN2(l[1], r[1]))) {
return false;
}
- vx = l[0] - r[0];
- vy = l[1] - r[1];
+ dx = l[0] - r[0];
+ dy = l[1] - r[1];
- c1 = vx * (converted[2] - l[1]) - vy * (converted[0] - l[0]);
+ c1 = dx * (converted[2] - l[1]) - dy * (converted[0] - l[0]);
c = c1;
- c1 = vx * (converted[2] - l[1]) - vy * (converted[1] - l[0]);
+ c1 = dx * (converted[2] - l[1]) - dy * (converted[1] - l[0]);
if (c1 * c <= 0) {
return true;
}
c = c1;
- c1 = vx * (converted[3] - l[1]) - vy * (converted[0] - l[0]);
+ c1 = dx * (converted[3] - l[1]) - dy * (converted[0] - l[0]);
if (c1 * c <= 0) {
return true;
}
c = c1;
- c1 = vx * (converted[3] - l[1]) - vy * (converted[1] - l[0]);
+ c1 = dx * (converted[3] - l[1]) - dy * (converted[1] - l[0]);
if (c1 * c <= 0) {
return true;
}
@@ -3818,24 +4042,28 @@ static bool lineart_bounding_area_edge_intersect(LineartRenderBuffer *UNUSED(fb)
return false;
}
-static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
+static bool lineart_bounding_area_triangle_intersect(LineartData *fb,
LineartTriangle *tri,
- LineartBoundingArea *ba)
+ LineartBoundingArea *ba,
+ bool *r_triangle_vert_inside)
{
double p1[2], p2[2], p3[2], p4[2];
double *FBC1 = tri->v[0]->fbcoord, *FBC2 = tri->v[1]->fbcoord, *FBC3 = tri->v[2]->fbcoord;
- p3[0] = p1[0] = (double)ba->l;
- p2[1] = p1[1] = (double)ba->b;
- p2[0] = p4[0] = (double)ba->r;
- p3[1] = p4[1] = (double)ba->u;
+ p3[0] = p1[0] = ba->l;
+ p2[1] = p1[1] = ba->b;
+ p2[0] = p4[0] = ba->r;
+ p3[1] = p4[1] = ba->u;
if ((FBC1[0] >= p1[0] && FBC1[0] <= p2[0] && FBC1[1] >= p1[1] && FBC1[1] <= p3[1]) ||
(FBC2[0] >= p1[0] && FBC2[0] <= p2[0] && FBC2[1] >= p1[1] && FBC2[1] <= p3[1]) ||
(FBC3[0] >= p1[0] && FBC3[0] <= p2[0] && FBC3[1] >= p1[1] && FBC3[1] <= p3[1])) {
+ *r_triangle_vert_inside = true;
return true;
}
+ *r_triangle_vert_inside = false;
+
if (lineart_point_inside_triangle(p1, FBC1, FBC2, FBC3) ||
lineart_point_inside_triangle(p2, FBC1, FBC2, FBC3) ||
lineart_point_inside_triangle(p3, FBC1, FBC2, FBC3) ||
@@ -3853,87 +4081,180 @@ static bool lineart_bounding_area_triangle_intersect(LineartRenderBuffer *fb,
}
/**
- * 1) Link triangles with bounding areas for later occlusion test.
- * 2) Test triangles with existing(added previously) triangles for intersection lines.
+ * This function does two things:
+ *
+ * 1) Builds a quad-tree under ld->InitialBoundingAreas to achieve good geometry separation for
+ * fast overlapping test between triangles and lines. This acceleration structure makes the
+ * occlusion stage much faster.
+ *
+ * 2) Test triangles with other triangles that are previously linked into each tile
+ * (#LineartBoundingArea) for intersection lines. When splitting the tile into 4 children and
+ * re-linking triangles into the child tiles, intersections are inhibited so we don't get
+ * duplicated intersection lines.
+ *
*/
-static void lineart_bounding_area_link_triangle(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_triangle(LineartData *ld,
LineartBoundingArea *root_ba,
LineartTriangle *tri,
- double *LRUB,
+ double l_r_u_b[4],
int recursive,
int recursive_level,
- bool do_intersection)
+ bool do_intersection,
+ struct LineartIsecThread *th)
{
- if (!lineart_bounding_area_triangle_intersect(rb, tri, root_ba)) {
+ bool triangle_vert_inside;
+ if (!lineart_bounding_area_triangle_intersect(ld, tri, root_ba, &triangle_vert_inside)) {
return;
}
- if (root_ba->child == NULL) {
- lineart_bounding_area_triangle_add(rb, root_ba, tri);
- /* If splitting doesn't improve triangle separation, then shouldn't allow splitting anymore.
- * Here we use recursive limit. This is especially useful in orthographic render,
- * where a lot of faces could easily line up perfectly in image space,
- * which can not be separated by simply slicing the image tile. */
- if (root_ba->triangle_count >= LRT_TILE_SPLITTING_TRIANGLE_LIMIT && recursive &&
- recursive_level < rb->tile_recursive_level) {
- lineart_bounding_area_split(rb, root_ba, recursive_level);
- }
- if (recursive && do_intersection && rb->use_intersections) {
- lineart_triangle_intersect_in_bounding_area(rb, tri, root_ba);
- }
- }
- else {
- LineartBoundingArea *ba = root_ba->child;
- double *B1 = LRUB;
+
+ LineartBoundingArea *old_ba = root_ba;
+
+ if (old_ba->child) {
+ /* If old_ba->child is not NULL, then tile splitting is fully finished, safe to directly insert
+ * into child tiles. */
+ double *B1 = l_r_u_b;
double b[4];
- if (!LRUB) {
+ if (!l_r_u_b) {
b[0] = MIN3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
b[1] = MAX3(tri->v[0]->fbcoord[0], tri->v[1]->fbcoord[0], tri->v[2]->fbcoord[0]);
b[2] = MAX3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
b[3] = MIN3(tri->v[0]->fbcoord[1], tri->v[1]->fbcoord[1], tri->v[2]->fbcoord[1]);
B1 = b;
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[0].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[0], tri, B1, recursive, recursive_level + 1, do_intersection);
+ for (int iba = 0; iba < 4; iba++) {
+ if (LRT_BOUND_AREA_CROSSES(B1, &old_ba->child[iba].l)) {
+ lineart_bounding_area_link_triangle(
+ ld, &old_ba->child[iba], tri, B1, recursive, recursive_level + 1, do_intersection, th);
+ }
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[1].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[1], tri, B1, recursive, recursive_level + 1, do_intersection);
+ return;
+ }
+
+ /* When splitting tiles, triangles are relinked into new tiles by a single thread, #th is NULL
+ * in that situation. */
+ if (th) {
+ BLI_spin_lock(&old_ba->lock);
+ }
+
+ /* If there are still space left in this tile for insertion. */
+ if (old_ba->triangle_count < old_ba->max_triangle_count) {
+ const uint32_t old_tri_count = old_ba->triangle_count;
+
+ old_ba->linked_triangles[old_tri_count] = tri;
+
+ if (triangle_vert_inside) {
+ old_ba->insider_triangle_count++;
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[2].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[2], tri, B1, recursive, recursive_level + 1, do_intersection);
+ old_ba->triangle_count++;
+
+ /* Do intersections in place. */
+ if (do_intersection && ld->conf.use_intersections) {
+ lineart_triangle_intersect_in_bounding_area(tri, old_ba, th, old_tri_count);
+ }
+
+ if (th) {
+ BLI_spin_unlock(&old_ba->lock);
}
- if (LRT_BOUND_AREA_CROSSES(B1, &ba[3].l)) {
- lineart_bounding_area_link_triangle(
- rb, &ba[3], tri, B1, recursive, recursive_level + 1, do_intersection);
+ }
+ else { /* We need to wait for either splitting or array extension to be done. */
+
+ if (recursive_level < ld->qtree.recursive_level &&
+ old_ba->insider_triangle_count >= LRT_TILE_SPLITTING_TRIANGLE_LIMIT) {
+ if (!old_ba->child) {
+ /* old_ba->child==NULL, means we are the thread that's doing the splitting. */
+ lineart_bounding_area_split(ld, old_ba, recursive_level);
+ } /* Otherwise other thread has completed the splitting process. */
+ }
+ else {
+ if (old_ba->triangle_count == old_ba->max_triangle_count) {
+ /* Means we are the thread that's doing the extension. */
+ lineart_bounding_area_triangle_reallocate(old_ba);
+ } /* Otherwise other thread has completed the extending the array. */
+ }
+
+ /* Unlock before going into recursive call. */
+ if (th) {
+ BLI_spin_unlock(&old_ba->lock);
+ }
+
+ /* Of course we still have our own triangle needs to be added. */
+ lineart_bounding_area_link_triangle(
+ ld, root_ba, tri, l_r_u_b, recursive, recursive_level, do_intersection, th);
+ }
+}
+
+static void lineart_free_bounding_area_memory(LineartBoundingArea *ba, bool recursive)
+{
+ BLI_spin_end(&ba->lock);
+ if (ba->linked_lines) {
+ MEM_freeN(ba->linked_lines);
+ }
+ if (ba->linked_triangles) {
+ MEM_freeN(ba->linked_triangles);
+ }
+ if (recursive && ba->child) {
+ for (int i = 0; i < 4; i++) {
+ lineart_free_bounding_area_memory(&ba->child[i], recursive);
+ }
+ }
+}
+static void lineart_free_bounding_area_memories(LineartData *ld)
+{
+ for (int i = 0; i < ld->qtree.count_y; i++) {
+ for (int j = 0; j < ld->qtree.count_x; j++) {
+ lineart_free_bounding_area_memory(&ld->qtree.initials[i * ld->qtree.count_x + j], true);
}
}
}
-static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
+static void lineart_bounding_area_link_edge(LineartData *ld,
LineartBoundingArea *root_ba,
LineartEdge *e)
{
if (root_ba->child == NULL) {
- lineart_bounding_area_line_add(rb, root_ba, e);
+ lineart_bounding_area_line_add(root_ba, e);
}
else {
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[0], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[0])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[0], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[1], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[1])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[1], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[2], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[2])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[2], e);
}
if (lineart_bounding_area_edge_intersect(
- rb, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) {
- lineart_bounding_area_link_edge(rb, &root_ba->child[3], e);
+ ld, e->v1->fbcoord, e->v2->fbcoord, &root_ba->child[3])) {
+ lineart_bounding_area_link_edge(ld, &root_ba->child[3], e);
+ }
+ }
+}
+
+static void lineart_clear_linked_edges_recursive(LineartData *ld, LineartBoundingArea *root_ba)
+{
+ if (root_ba->child) {
+ for (int i = 0; i < 4; i++) {
+ lineart_clear_linked_edges_recursive(ld, &root_ba->child[i]);
+ }
+ }
+ if (root_ba->linked_lines) {
+ MEM_freeN(root_ba->linked_lines);
+ }
+ root_ba->line_count = 0;
+ root_ba->max_line_count = 128;
+ root_ba->linked_lines = MEM_callocN(sizeof(LineartEdge *) * root_ba->max_line_count,
+ "cleared lineart edges");
+}
+void lineart_main_clear_linked_edges(LineartData *ld)
+{
+ LineartBoundingArea *ba = ld->qtree.initials;
+ for (int i = 0; i < ld->qtree.count_y; i++) {
+ for (int j = 0; j < ld->qtree.count_x; j++) {
+ lineart_clear_linked_edges_recursive(ld, &ba[i * ld->qtree.count_x + j]);
}
}
}
@@ -3941,16 +4262,16 @@ static void lineart_bounding_area_link_edge(LineartRenderBuffer *rb,
/**
* Link lines to their respective bounding areas.
*/
-static void lineart_main_link_lines(LineartRenderBuffer *rb)
+void lineart_main_link_lines(LineartData *ld)
{
LRT_ITER_ALL_LINES_BEGIN
{
int r1, r2, c1, c2, row, col;
- if (lineart_get_edge_bounding_areas(rb, e, &r1, &r2, &c1, &c2)) {
+ if (lineart_get_edge_bounding_areas(ld, e, &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], e);
+ ld, &ld->qtree.initials[row * ld->qtree.count_x + col], e);
}
}
}
@@ -3958,14 +4279,66 @@ static void lineart_main_link_lines(LineartRenderBuffer *rb)
LRT_ITER_ALL_LINES_END
}
-static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
- LineartTriangle *tri,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend)
+static void lineart_main_remove_unused_lines_recursive(LineartBoundingArea *ba,
+ uint8_t max_occlusion)
+{
+ if (ba->child) {
+ for (int i = 0; i < 4; i++) {
+ lineart_main_remove_unused_lines_recursive(&ba->child[i], max_occlusion);
+ }
+ return;
+ }
+
+ if (!ba->line_count) {
+ return;
+ }
+
+ int usable_count = 0;
+ for (int i = 0; i < ba->line_count; i++) {
+ LineartEdge *e = ba->linked_lines[i];
+ if (e->min_occ > max_occlusion) {
+ continue;
+ }
+ usable_count++;
+ }
+
+ if (!usable_count) {
+ ba->line_count = 0;
+ return;
+ }
+
+ LineartEdge **new_array = MEM_callocN(sizeof(LineartEdge *) * usable_count,
+ "cleaned lineart edge array");
+
+ int new_i = 0;
+ for (int i = 0; i < ba->line_count; i++) {
+ LineartEdge *e = ba->linked_lines[i];
+ if (e->min_occ > max_occlusion) {
+ continue;
+ }
+ new_array[new_i] = e;
+ new_i++;
+ }
+
+ MEM_freeN(ba->linked_lines);
+ ba->linked_lines = new_array;
+ ba->max_line_count = ba->line_count = usable_count;
+}
+
+static void lineart_main_remove_unused_lines_from_tiles(LineartData *ld)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ for (int row = 0; row < ld->qtree.count_y; row++) {
+ for (int col = 0; col < ld->qtree.count_x; col++) {
+ lineart_main_remove_unused_lines_recursive(
+ &ld->qtree.initials[row * ld->qtree.count_x + col], ld->conf.max_occlusion_level);
+ }
+ }
+}
+
+static bool lineart_get_triangle_bounding_areas(
+ LineartData *ld, LineartTriangle *tri, int *rowbegin, int *rowend, int *colbegin, int *colend)
+{
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
double b[4];
if (!tri->v[0] || !tri->v[1] || !tri->v[2]) {
@@ -3983,14 +4356,14 @@ static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
(*colbegin) = (int)((b[0] + 1.0) / sp_w);
(*colend) = (int)((b[1] + 1.0) / sp_w);
- (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
- (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+ (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1;
- if ((*colend) >= rb->tile_count_x) {
- (*colend) = rb->tile_count_x - 1;
+ if ((*colend) >= ld->qtree.count_x) {
+ (*colend) = ld->qtree.count_x - 1;
}
- if ((*rowend) >= rb->tile_count_y) {
- (*rowend) = rb->tile_count_y - 1;
+ if ((*rowend) >= ld->qtree.count_y) {
+ (*rowend) = ld->qtree.count_y - 1;
}
if ((*colbegin) < 0) {
(*colbegin) = 0;
@@ -4002,14 +4375,10 @@ static bool lineart_get_triangle_bounding_areas(LineartRenderBuffer *rb,
return true;
}
-static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
- LineartEdge *e,
- int *rowbegin,
- int *rowend,
- int *colbegin,
- int *colend)
+static bool lineart_get_edge_bounding_areas(
+ LineartData *ld, LineartEdge *e, int *rowbegin, int *rowend, int *colbegin, int *colend)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
double b[4];
if (!e->v1 || !e->v2) {
@@ -4031,31 +4400,29 @@ static bool lineart_get_edge_bounding_areas(LineartRenderBuffer *rb,
(*colbegin) = (int)((b[0] + 1.0) / sp_w);
(*colend) = (int)((b[1] + 1.0) / sp_w);
- (*rowend) = rb->tile_count_y - (int)((b[2] + 1.0) / sp_h) - 1;
- (*rowbegin) = rb->tile_count_y - (int)((b[3] + 1.0) / sp_h) - 1;
+ (*rowend) = ld->qtree.count_y - (int)((b[2] + 1.0) / sp_h) - 1;
+ (*rowbegin) = ld->qtree.count_y - (int)((b[3] + 1.0) / sp_h) - 1;
/* It's possible that the line stretches too much out to the side, resulting negative value. */
if ((*rowend) < (*rowbegin)) {
- (*rowend) = rb->tile_count_y - 1;
+ (*rowend) = ld->qtree.count_y - 1;
}
if ((*colend) < (*colbegin)) {
- (*colend) = rb->tile_count_x - 1;
+ (*colend) = ld->qtree.count_x - 1;
}
- CLAMP((*colbegin), 0, rb->tile_count_x - 1);
- CLAMP((*rowbegin), 0, rb->tile_count_y - 1);
- CLAMP((*colend), 0, rb->tile_count_x - 1);
- CLAMP((*rowend), 0, rb->tile_count_y - 1);
+ CLAMP((*colbegin), 0, ld->qtree.count_x - 1);
+ CLAMP((*rowbegin), 0, ld->qtree.count_y - 1);
+ CLAMP((*colend), 0, ld->qtree.count_x - 1);
+ CLAMP((*rowend), 0, ld->qtree.count_y - 1);
return true;
}
-LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *rb,
- double x,
- double y)
+LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartData *ld, double x, double y)
{
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
int col, row;
if (x > 1 || x < -1 || y > 1 || y < -1) {
@@ -4063,13 +4430,13 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r
}
col = (int)((x + 1.0) / sp_w);
- row = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+ row = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1;
- if (col >= rb->tile_count_x) {
- col = rb->tile_count_x - 1;
+ if (col >= ld->qtree.count_x) {
+ col = ld->qtree.count_x - 1;
}
- if (row >= rb->tile_count_y) {
- row = rb->tile_count_y - 1;
+ if (row >= ld->qtree.count_y) {
+ row = ld->qtree.count_y - 1;
}
if (col < 0) {
col = 0;
@@ -4078,29 +4445,29 @@ LineartBoundingArea *MOD_lineart_get_parent_bounding_area(LineartRenderBuffer *r
row = 0;
}
- return &rb->initial_bounding_areas[row * LRT_BA_ROWS + col];
+ return &ld->qtree.initials[row * ld->qtree.count_x + col];
}
-static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
+static LineartBoundingArea *lineart_get_bounding_area(LineartData *ld, double x, double y)
{
LineartBoundingArea *iba;
- double sp_w = rb->width_per_tile, sp_h = rb->height_per_tile;
+ double sp_w = ld->qtree.tile_width, sp_h = ld->qtree.tile_height;
int c = (int)((x + 1.0) / sp_w);
- int r = rb->tile_count_y - (int)((y + 1.0) / sp_h) - 1;
+ int r = ld->qtree.count_y - (int)((y + 1.0) / sp_h) - 1;
if (r < 0) {
r = 0;
}
if (c < 0) {
c = 0;
}
- if (r >= rb->tile_count_y) {
- r = rb->tile_count_y - 1;
+ if (r >= ld->qtree.count_y) {
+ r = ld->qtree.count_y - 1;
}
- if (c >= rb->tile_count_x) {
- c = rb->tile_count_x - 1;
+ if (c >= ld->qtree.count_x) {
+ c = ld->qtree.count_x - 1;
}
- iba = &rb->initial_bounding_areas[r * LRT_BA_ROWS + c];
+ iba = &ld->qtree.initials[r * ld->qtree.count_x + c];
while (iba->child) {
if (x > iba->cx) {
if (y > iba->cy) {
@@ -4122,101 +4489,243 @@ static LineartBoundingArea *lineart_get_bounding_area(LineartRenderBuffer *rb, d
return iba;
}
-LineartBoundingArea *MOD_lineart_get_bounding_area(LineartRenderBuffer *rb, double x, double y)
+LineartBoundingArea *MOD_lineart_get_bounding_area(LineartData *ld, double x, double y)
{
LineartBoundingArea *ba;
- if ((ba = MOD_lineart_get_parent_bounding_area(rb, x, y)) != NULL) {
- return lineart_get_bounding_area(rb, x, y);
+ if ((ba = MOD_lineart_get_parent_bounding_area(ld, x, y)) != NULL) {
+ return lineart_get_bounding_area(ld, x, y);
}
return NULL;
}
-/**
- * Sequentially add triangles into render buffer. This also does intersection along the way.
- */
-static void lineart_main_add_triangles(LineartRenderBuffer *rb)
+static void lineart_add_triangles_worker(TaskPool *__restrict UNUSED(pool), LineartIsecThread *th)
{
- LineartTriangle *tri;
- int i, lim;
- int x1, x2, y1, y2;
- int r, co;
-
- LISTBASE_FOREACH (LineartElementLinkNode *, eln, &rb->triangle_buffer_pointers) {
- tri = eln->pointer;
- lim = eln->element_count;
- for (i = 0; i < lim; i++) {
- if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) {
- tri = (void *)(((uchar *)tri) + rb->triangle_size);
- continue;
- }
- if (lineart_get_triangle_bounding_areas(rb, tri, &y1, &y2, &x1, &x2)) {
- for (co = x1; co <= x2; co++) {
- for (r = y1; r <= y2; r++) {
- lineart_bounding_area_link_triangle(rb,
- &rb->initial_bounding_areas[r * LRT_BA_ROWS + co],
- tri,
- 0,
- 1,
- 0,
- (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION)));
+ LineartData *ld = th->ld;
+ int _dir_control = 0;
+ while (lineart_schedule_new_triangle_task(th)) {
+ for (LineartElementLinkNode *eln = th->pending_from; eln != th->pending_to->next;
+ eln = eln->next) {
+ int index_start = eln == th->pending_from ? th->index_from : 0;
+ int index_end = eln == th->pending_to ? th->index_to : eln->element_count;
+ LineartTriangle *tri = (void *)(((uchar *)eln->pointer) + ld->sizeof_triangle * index_start);
+ for (int ei = index_start; ei < index_end; ei++) {
+ int x1, x2, y1, y2;
+ int r, co;
+ if ((tri->flags & LRT_CULL_USED) || (tri->flags & LRT_CULL_DISCARD)) {
+ tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
+ continue;
+ }
+ if (lineart_get_triangle_bounding_areas(ld, tri, &y1, &y2, &x1, &x2)) {
+ _dir_control++;
+ for (co = x1; co <= x2; co++) {
+ for (r = y1; r <= y2; r++) {
+ lineart_bounding_area_link_triangle(ld,
+ &ld->qtree.initials[r * ld->qtree.count_x + co],
+ tri,
+ 0,
+ 1,
+ 0,
+ (!(tri->flags & LRT_TRIANGLE_NO_INTERSECTION)),
+ th);
+ }
}
+ } /* Else throw away. */
+ tri = (void *)(((uchar *)tri) + ld->sizeof_triangle);
+ }
+ }
+ }
+}
+
+static void lineart_create_edges_from_isec_data(LineartIsecData *d)
+{
+ LineartData *ld = d->ld;
+ double ZMax = ld->conf.far_clip;
+ double ZMin = ld->conf.near_clip;
+ int total_lines = 0;
+
+ for (int i = 0; i < d->thread_count; i++) {
+ LineartIsecThread *th = &d->threads[i];
+ if (G.debug_value == 4000) {
+ printf("Thread %d isec generated %d lines.\n", i, th->current);
+ }
+ if (!th->current) {
+ continue;
+ }
+ total_lines += th->current;
+ }
+
+ if (!total_lines) {
+ return;
+ }
+
+ /* We don't care about removing duplicated vert in this method, chaining can handle that,
+ * and it saves us from using locks and look up tables. */
+ LineartVert *v = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartVert) * total_lines * 2);
+ LineartEdge *e = lineart_mem_acquire(ld->edge_data_pool, sizeof(LineartEdge) * total_lines);
+ LineartEdgeSegment *es = lineart_mem_acquire(ld->edge_data_pool,
+ sizeof(LineartEdgeSegment) * total_lines);
+
+ LineartElementLinkNode *eln = lineart_mem_acquire(ld->edge_data_pool,
+ sizeof(LineartElementLinkNode));
+ eln->element_count = total_lines;
+ eln->pointer = e;
+ eln->flags |= LRT_ELEMENT_INTERSECTION_DATA;
+ BLI_addhead(&ld->geom.line_buffer_pointers, eln);
+
+ for (int i = 0; i < d->thread_count; i++) {
+ LineartIsecThread *th = &d->threads[i];
+ if (!th->current) {
+ continue;
+ }
+
+ for (int j = 0; j < th->current; j++) {
+ LineartIsecSingle *is = &th->array[j];
+ LineartVert *v1 = v;
+ LineartVert *v2 = v + 1;
+ copy_v3db_v3fl(v1->gloc, is->v1);
+ copy_v3db_v3fl(v2->gloc, is->v2);
+ /* The intersection line has been generated only in geometry space, so we need to transform
+ * them as well. */
+ mul_v4_m4v3_db(v1->fbcoord, ld->conf.view_projection, v1->gloc);
+ mul_v4_m4v3_db(v2->fbcoord, ld->conf.view_projection, v2->gloc);
+ mul_v3db_db(v1->fbcoord, (1 / v1->fbcoord[3]));
+ mul_v3db_db(v2->fbcoord, (1 / v2->fbcoord[3]));
+
+ v1->fbcoord[0] -= ld->conf.shift_x * 2;
+ v1->fbcoord[1] -= ld->conf.shift_y * 2;
+ v2->fbcoord[0] -= ld->conf.shift_x * 2;
+ v2->fbcoord[1] -= ld->conf.shift_y * 2;
+
+ /* This z transformation is not the same as the rest of the part, because the data don't go
+ * through normal perspective division calls in the pipeline, but this way the 3D result and
+ * occlusion on the generated line is correct, and we don't really use 2D for viewport stroke
+ * generation anyway. */
+ v1->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v1->fbcoord[2]) * (ZMax - ZMin));
+ v2->fbcoord[2] = ZMin * ZMax / (ZMax - fabs(v2->fbcoord[2]) * (ZMax - ZMin));
+ e->v1 = v1;
+ e->v2 = v2;
+ e->t1 = is->tri1;
+ e->t2 = is->tri2;
+ /* This is so we can also match intersection edges from shadow to later viewing stage. */
+ e->edge_identifier = (((uint64_t)e->t1->target_reference) << 32) | e->t2->target_reference;
+ e->flags = LRT_EDGE_FLAG_INTERSECTION;
+ e->intersection_mask = (is->tri1->intersection_mask | is->tri2->intersection_mask);
+ BLI_addtail(&e->segments, es);
+
+ int obi1 = (e->t1->target_reference & LRT_OBINDEX_HIGHER);
+ int obi2 = (e->t2->target_reference & LRT_OBINDEX_HIGHER);
+ LineartElementLinkNode *eln1 = lineart_find_matching_eln(&ld->geom.line_buffer_pointers,
+ obi1);
+ LineartElementLinkNode *eln2 = obi1 == obi2 ? eln1 :
+ lineart_find_matching_eln(
+ &ld->geom.line_buffer_pointers, obi2);
+ Object *ob1 = eln1 ? eln1->object_ref : NULL;
+ Object *ob2 = eln2 ? eln2->object_ref : NULL;
+ if (e->t1->intersection_priority > e->t2->intersection_priority) {
+ e->object_ref = ob1;
+ }
+ else if (e->t1->intersection_priority < e->t2->intersection_priority) {
+ e->object_ref = ob2;
+ }
+ else { /* equal priority */
+ if (ob1 == ob2) {
+ /* object_ref should be ambiguous if intersection lines comes from different objects. */
+ e->object_ref = ob1;
}
- } /* Else throw away. */
- tri = (void *)(((uchar *)tri) + rb->triangle_size);
+ }
+
+ lineart_add_edge_to_array(&ld->pending_edges, e);
+
+ v += 2;
+ e++;
+ es++;
}
}
}
/**
+ * Sequentially add triangles into render buffer, intersection lines between those triangles will
+ * also be computed at the same time.
+ */
+void lineart_main_add_triangles(LineartData *ld)
+{
+ double t_start;
+ if (G.debug_value == 4000) {
+ t_start = PIL_check_seconds_timer();
+ }
+
+ /* Initialize per-thread data for thread task scheduling information and storing intersection
+ * results. */
+ LineartIsecData d = {0};
+ lineart_init_isec_thread(&d, ld, ld->thread_count);
+
+ TaskPool *tp = BLI_task_pool_create(NULL, TASK_PRIORITY_HIGH);
+ for (int i = 0; i < ld->thread_count; i++) {
+ BLI_task_pool_push(tp, (TaskRunFunction)lineart_add_triangles_worker, &d.threads[i], 0, NULL);
+ }
+ BLI_task_pool_work_and_wait(tp);
+ BLI_task_pool_free(tp);
+
+ if (ld->conf.use_intersections) {
+ lineart_create_edges_from_isec_data(&d);
+ }
+
+ lineart_destroy_isec_thread(&d);
+
+ if (G.debug_value == 4000) {
+ double t_elapsed = PIL_check_seconds_timer() - t_start;
+ printf("Line art intersection time: %f\n", t_elapsed);
+ }
+}
+
+/**
* This function gets the tile for the point `e->v1`, and later use #lineart_bounding_area_next()
* to get next along the way.
*/
-static LineartBoundingArea *lineart_edge_first_bounding_area(LineartRenderBuffer *rb,
- LineartEdge *e)
+LineartBoundingArea *lineart_edge_first_bounding_area(LineartData *ld,
+ double *fbcoord1,
+ double *fbcoord2)
{
- double data[2] = {e->v1->fbcoord[0], e->v1->fbcoord[1]};
+ double data[2] = {fbcoord1[0], fbcoord1[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]);
+ return lineart_get_bounding_area(ld, data[0], data[1]);
}
- if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LU, RU, &sr, &p_unused) &&
- sr < r && sr > 0) {
+ if (lineart_intersect_seg_seg(fbcoord1, fbcoord2, LU, RU, &sr, &p_unused) && sr < r && sr > 0) {
r = sr;
}
- if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LB, RB, &sr, &p_unused) &&
- sr < r && sr > 0) {
+ if (lineart_intersect_seg_seg(fbcoord1, fbcoord2, LB, RB, &sr, &p_unused) && sr < r && sr > 0) {
r = sr;
}
- if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, LB, LU, &sr, &p_unused) &&
- sr < r && sr > 0) {
+ if (lineart_intersect_seg_seg(fbcoord1, fbcoord2, LB, LU, &sr, &p_unused) && sr < r && sr > 0) {
r = sr;
}
- if (lineart_intersect_seg_seg(e->v1->fbcoord, e->v2->fbcoord, RB, RU, &sr, &p_unused) &&
- sr < r && sr > 0) {
+ if (lineart_intersect_seg_seg(fbcoord1, fbcoord2, RB, RU, &sr, &p_unused) && sr < r && sr > 0) {
r = sr;
}
- interp_v2_v2v2_db(data, e->v1->fbcoord, e->v2->fbcoord, r);
+ interp_v2_v2v2_db(data, fbcoord1, fbcoord2, r);
- return lineart_get_bounding_area(rb, data[0], data[1]);
+ return lineart_get_bounding_area(ld, data[0], data[1]);
}
/**
* This march along one render line in image space and
* get the next bounding area the line is crossing.
*/
-static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this,
- LineartEdge *e,
- double x,
- double y,
- double k,
- int positive_x,
- int positive_y,
- double *next_x,
- double *next_y)
+LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this,
+ double *fbcoord1,
+ double *fbcoord2,
+ double x,
+ double y,
+ double k,
+ int positive_x,
+ int positive_y,
+ double *next_x,
+ double *next_y)
{
double rx, ry, ux, uy, lx, ly, bx, by;
double r1, r2;
@@ -4231,8 +4740,8 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
if (positive_y > 0) {
uy = this->u;
ux = x + (uy - y) / k;
- r1 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], rx);
- r2 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], ux);
+ r1 = ratiod(fbcoord1[0], fbcoord2[0], rx);
+ r2 = ratiod(fbcoord1[0], fbcoord2[0], ux);
if (MIN2(r1, r2) > 1) {
return 0;
}
@@ -4264,8 +4773,8 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
else if (positive_y < 0) {
by = this->b;
bx = x + (by - y) / k;
- r1 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], rx);
- r2 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], bx);
+ r1 = ratiod(fbcoord1[0], fbcoord2[0], rx);
+ r2 = ratiod(fbcoord1[0], fbcoord2[0], bx);
if (MIN2(r1, r2) > 1) {
return 0;
}
@@ -4292,7 +4801,7 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
}
/* If the line is completely horizontal, in which Y difference == 0. */
else {
- r1 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], this->r);
+ r1 = ratiod(fbcoord1[0], fbcoord2[0], this->r);
if (r1 > 1) {
return 0;
}
@@ -4316,8 +4825,8 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
if (positive_y > 0) {
uy = this->u;
ux = x + (uy - y) / k;
- r1 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], lx);
- r2 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], ux);
+ r1 = ratiod(fbcoord1[0], fbcoord2[0], lx);
+ r2 = ratiod(fbcoord1[0], fbcoord2[0], ux);
if (MIN2(r1, r2) > 1) {
return 0;
}
@@ -4347,8 +4856,8 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
else if (positive_y < 0) {
by = this->b;
bx = x + (by - y) / k;
- r1 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], lx);
- r2 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], bx);
+ r1 = ratiod(fbcoord1[0], fbcoord2[0], lx);
+ r2 = ratiod(fbcoord1[0], fbcoord2[0], bx);
if (MIN2(r1, r2) > 1) {
return 0;
}
@@ -4375,7 +4884,7 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
}
/* Again, horizontal. */
else {
- r1 = ratiod(e->v1->fbcoord[0], e->v2->fbcoord[0], this->l);
+ r1 = ratiod(fbcoord1[0], fbcoord2[0], this->l);
if (r1 > 1) {
return 0;
}
@@ -4392,7 +4901,7 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
/* If the line is completely vertical, hence X difference == 0. */
else {
if (positive_y > 0) {
- r1 = ratiod(e->v1->fbcoord[1], e->v2->fbcoord[1], this->u);
+ r1 = ratiod(fbcoord1[1], fbcoord2[1], this->u);
if (r1 > 1) {
return 0;
}
@@ -4406,7 +4915,7 @@ static LineartBoundingArea *lineart_bounding_area_next(LineartBoundingArea *this
}
}
else if (positive_y < 0) {
- r1 = ratiod(e->v1->fbcoord[1], e->v2->fbcoord[1], this->b);
+ r1 = ratiod(fbcoord1[1], fbcoord2[1], this->b);
if (r1 > 1) {
return 0;
}
@@ -4427,24 +4936,26 @@ 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,
bool enable_stroke_depth_offset)
{
- LineartRenderBuffer *rb;
+ LineartData *ld;
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;
-
if (G.debug_value == 4000) {
t_start = PIL_check_seconds_timer();
}
- BKE_scene_camera_switch_update(scene);
-
if (lmd->calculation_flags & LRT_USE_CUSTOM_CAMERA) {
if (!lmd->source_camera ||
(use_camera = DEG_get_evaluated_object(depsgraph, lmd->source_camera))->type !=
@@ -4453,6 +4964,9 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
}
}
else {
+
+ BKE_scene_camera_switch_update(scene);
+
if (!scene->camera) {
return false;
}
@@ -4462,54 +4976,79 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
LineartCache *lc = lineart_init_cache();
*cached_result = lc;
- rb = lineart_create_render_buffer(scene, lmd, use_camera, scene->camera, lc);
+ ld = 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);
-
- /* FIXME(Yiming): See definition of int #LineartRenderBuffer::_source_type for detailed. */
- rb->_source_type = lmd->source_type;
- rb->_source_collection = lmd->source_collection;
- rb->_source_object = lmd->source_object;
+ ld->sizeof_triangle = lineart_triangle_size_get(ld);
+
+ LineartData *shadow_rb = NULL;
+ LineartElementLinkNode *shadow_veln, *shadow_eeln;
+ ListBase *shadow_elns = ld->conf.shadow_selection ? &lc->shadow_elns : NULL;
+ bool shadow_generated = lineart_main_try_generate_shadow(depsgraph,
+ scene,
+ ld,
+ lmd,
+ &lc->shadow_data_pool,
+ &shadow_veln,
+ &shadow_eeln,
+ shadow_elns,
+ &shadow_rb);
/* Get view vector before loading geometries, because we detect feature lines there. */
- lineart_main_get_view_vector(rb);
- lineart_main_load_geometries(
- depsgraph, scene, use_camera, rb, lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS);
+ lineart_main_get_view_vector(ld);
+
+ lineart_main_load_geometries(depsgraph,
+ scene,
+ use_camera,
+ ld,
+ lmd->calculation_flags & LRT_ALLOW_DUPLI_OBJECTS,
+ false,
+ shadow_elns);
- if (!rb->vertex_buffer_pointers.first) {
+ if (shadow_generated) {
+ lineart_main_transform_and_add_shadow(ld, shadow_veln, shadow_eeln);
+ }
+
+ if (!ld->geom.vertex_buffer_pointers.first) {
/* No geometry loaded, return early. */
return true;
}
/* Initialize the bounding box acceleration structure, it's a lot like BVH in 3D. */
- lineart_main_bounding_area_make_initial(rb);
+ lineart_main_bounding_area_make_initial(ld);
/* We need to get cut into triangles that are crossing near/far plans, only this way can we get
* correct coordinates of those clipped lines. Done in two steps,
* setting clip_far==false for near plane. */
- lineart_main_cull_triangles(rb, false);
+ lineart_main_cull_triangles(ld, false);
/* `clip_far == true` for far plane. */
- lineart_main_cull_triangles(rb, true);
+ lineart_main_cull_triangles(ld, true);
/* At this point triangle adjacent info pointers is no longer needed, free them. */
- lineart_main_free_adjacent_data(rb);
+ lineart_main_free_adjacent_data(ld);
/* Do the perspective division after clipping is done. */
- lineart_main_perspective_division(rb);
+ lineart_main_perspective_division(ld);
- lineart_main_discard_out_of_frame_edges(rb);
+ lineart_main_discard_out_of_frame_edges(ld);
/* Triangle intersections are done here during sequential adding of them. Only after this,
* triangles and lines are all linked with acceleration structure, and the 2D occlusion stage
* can do its job. */
- lineart_main_add_triangles(rb);
+ lineart_main_add_triangles(ld);
+
+ /* Add shadow cuts to intersection lines as well. */
+ lineart_register_intersection_shadow_cuts(ld, shadow_elns);
+
+ /* Re-link bounding areas because they have been subdivided by worker threads and we need
+ * adjacent info. */
+ lineart_main_bounding_areas_connect_post(ld);
/* Link lines to acceleration structure, this can only be done after perspective division, if
* we do it after triangles being added, the acceleration structure has already been
* subdivided, this way we do less list manipulations. */
- lineart_main_link_lines(rb);
+ lineart_main_link_lines(ld);
/* "intersection_only" is preserved for being called in a standalone fashion.
* If so the data will already be available at the stage. Otherwise we do the occlusion and
@@ -4518,54 +5057,65 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
if (!intersections_only) {
/* Occlusion is work-and-wait. This call will not return before work is completed. */
- lineart_main_occlusion_begin(rb);
+ lineart_main_occlusion_begin(ld);
+
+ lineart_main_make_enclosed_shapes(ld, shadow_rb);
+
+ lineart_main_remove_unused_lines_from_tiles(ld);
/* Chaining is all single threaded. See lineart_chain.c
* In this particular call, only lines that are geometrically connected (share the _exact_
* same end point) will be chained together. */
- MOD_lineart_chain_feature_lines(rb);
+ MOD_lineart_chain_feature_lines(ld);
/* We are unable to take care of occlusion if we only connect end points, so here we do a
* spit, where the splitting point could be any cut in e->segments. */
- MOD_lineart_chain_split_for_fixed_occlusion(rb);
+ MOD_lineart_chain_split_for_fixed_occlusion(ld);
/* Then we connect chains based on the _proximity_ of their end points in image space, here's
* the place threshold value gets involved. */
- MOD_lineart_chain_connect(rb);
-
- float *t_image = &lmd->chaining_image_threshold;
- /* This configuration ensures there won't be accidental lost of short unchained segments. */
- MOD_lineart_chain_discard_short(rb, MIN2(*t_image, 0.001f) - FLT_EPSILON);
+ MOD_lineart_chain_connect(ld);
- if (rb->chain_smooth_tolerance > FLT_EPSILON) {
+ if (ld->conf.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. */
- MOD_lineart_smooth_chains(rb, rb->chain_smooth_tolerance / 50);
+ MOD_lineart_smooth_chains(ld, ld->conf.chain_smooth_tolerance / 50);
}
- if (rb->use_image_boundary_trimming) {
- MOD_lineart_chain_clip_at_border(rb);
+ if (ld->conf.use_image_boundary_trimming) {
+ MOD_lineart_chain_clip_at_border(ld);
}
- if (rb->angle_splitting_threshold > FLT_EPSILON) {
- MOD_lineart_chain_split_angle(rb, rb->angle_splitting_threshold);
+ if (ld->conf.angle_splitting_threshold > FLT_EPSILON) {
+ MOD_lineart_chain_split_angle(ld, ld->conf.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);
+ ld, lmd->stroke_depth_offset, lmd->flags & LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA);
+ }
+
+ if (ld->conf.shadow_use_silhouette) {
+ MOD_lineart_chain_find_silhouette_backdrop_objects(ld);
}
/* Finally transfer the result list into cache. */
- memcpy(&lc->chains, &rb->chains, sizeof(ListBase));
+ memcpy(&lc->chains, &ld->chains, sizeof(ListBase));
/* At last, we need to clear flags so we don't confuse GPencil generation calls. */
MOD_lineart_chain_clear_picked_flag(lc);
}
+ lineart_mem_destroy(&lc->shadow_data_pool);
+
+ if (ld->conf.shadow_enclose_shapes && shadow_rb) {
+ lineart_destroy_render_data_keep_init(shadow_rb);
+ MEM_freeN(shadow_rb);
+ }
+
if (G.debug_value == 4000) {
- lineart_count_and_print_render_buffer_memory(rb);
+ lineart_count_and_print_render_buffer_memory(ld);
double t_elapsed = PIL_check_seconds_timer() - t_start;
printf("Line art total time: %lf\n", t_elapsed);
@@ -4574,18 +5124,6 @@ bool MOD_lineart_compute_feature_lines(Depsgraph *depsgraph,
return true;
}
-static int UNUSED_FUNCTION(lineart_rb_edge_types)(LineartRenderBuffer *rb)
-{
- int types = 0;
- types |= rb->use_contour ? LRT_EDGE_FLAG_CONTOUR : 0;
- types |= rb->use_crease ? LRT_EDGE_FLAG_CREASE : 0;
- types |= rb->use_material ? LRT_EDGE_FLAG_MATERIAL : 0;
- types |= rb->use_edge_marks ? LRT_EDGE_FLAG_EDGE_MARK : 0;
- types |= rb->use_intersections ? LRT_EDGE_FLAG_INTERSECTION : 0;
- types |= rb->use_loose ? LRT_EDGE_FLAG_LOOSE : 0;
- return types;
-}
-
static void lineart_gpencil_generate(LineartCache *cache,
Depsgraph *depsgraph,
Object *gpencil_object,
@@ -4601,8 +5139,10 @@ static void lineart_gpencil_generate(LineartCache *cache,
uchar mask_switches,
uchar material_mask_bits,
uchar intersection_mask,
- short thickness,
+ int16_t thickness,
float opacity,
+ uchar shaodow_selection,
+ uchar silhouette_mode,
const char *source_vgname,
const char *vgname,
int modifier_flags)
@@ -4630,9 +5170,10 @@ static void lineart_gpencil_generate(LineartCache *cache,
/* (!orig_col && !orig_ob) means the whole scene is selected. */
- int enabled_types = cache->rb_edge_types;
+ int enabled_types = cache->all_enabled_edge_types;
bool invert_input = modifier_flags & LRT_GPENCIL_INVERT_SOURCE_VGROUP;
bool match_output = modifier_flags & LRT_GPENCIL_MATCH_OUTPUT_VGROUP;
+ bool inverse_silhouette = modifier_flags & LRT_GPENCIL_INVERT_SILHOUETTE_FILTER;
LISTBASE_FOREACH (LineartEdgeChain *, ec, &cache->chains) {
@@ -4684,11 +5225,55 @@ static void lineart_gpencil_generate(LineartCache *cache,
}
}
}
+ if (shaodow_selection) {
+ if (ec->shadow_mask_bits != LRT_SHADOW_MASK_UNDEFINED) {
+ /* TODO(@Yiming): Give a behavior option for how to display undefined shadow info. */
+ if ((shaodow_selection == LRT_SHADOW_FILTER_LIT &&
+ (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_LIT))) ||
+ (shaodow_selection == LRT_SHADOW_FILTER_SHADED &&
+ (!(ec->shadow_mask_bits & LRT_SHADOW_MASK_SHADED)))) {
+ continue;
+ }
+ }
+ }
+ if (silhouette_mode && (ec->type & (LRT_EDGE_FLAG_CONTOUR))) {
+ bool is_silhouette = false;
+ if (orig_col) {
+ if (!ec->silhouette_backdrop) {
+ is_silhouette = true;
+ }
+ else if (!BKE_collection_has_object_recursive_instanced(orig_col,
+ ec->silhouette_backdrop)) {
+ is_silhouette = true;
+ }
+ }
+ else {
+ if ((!orig_ob) && (!ec->silhouette_backdrop)) {
+ is_silhouette = true;
+ }
+ }
+
+ if ((silhouette_mode == LRT_SILHOUETTE_FILTER_INDIVIDUAL || orig_ob) &&
+ ec->silhouette_backdrop != ec->object_ref) {
+ is_silhouette = true;
+ }
+
+ if (inverse_silhouette) {
+ is_silhouette = !is_silhouette;
+ }
+ if (!is_silhouette) {
+ continue;
+ }
+ }
/* Preserved: If we ever do asynchronous generation, this picked flag should be set here. */
// ec->picked = 1;
const int count = MOD_lineart_chain_count(ec);
+ if (count < 2) {
+ continue;
+ }
+
bGPDstroke *gps = BKE_gpencil_stroke_add(gpf, color_idx, count, thickness, false);
int i;
@@ -4760,17 +5345,19 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
Object *ob,
bGPDlayer *gpl,
bGPDframe *gpf,
- char source_type,
+ int8_t source_type,
void *source_reference,
int level_start,
int level_end,
int mat_nr,
- short edge_types,
+ int16_t edge_types,
uchar mask_switches,
uchar material_mask_bits,
uchar intersection_mask,
- short thickness,
+ int16_t thickness,
float opacity,
+ uchar shadow_selection,
+ uchar silhouette_mode,
const char *source_vgname,
const char *vgname,
int modifier_flags)
@@ -4782,26 +5369,20 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
Object *source_object = NULL;
Collection *source_collection = NULL;
- short use_types = 0;
+ int16_t use_types = edge_types;
if (source_type == LRT_SOURCE_OBJECT) {
if (!source_reference) {
return;
}
source_object = (Object *)source_reference;
- /* Note that intersection lines will only be in collection. */
- use_types = edge_types & (~LRT_EDGE_FLAG_INTERSECTION);
}
else if (source_type == LRT_SOURCE_COLLECTION) {
if (!source_reference) {
return;
}
source_collection = (Collection *)source_reference;
- use_types = edge_types;
- }
- else {
- /* Whole scene. */
- use_types = edge_types;
}
+
float gp_obmat_inverse[4][4];
invert_m4_m4(gp_obmat_inverse, ob->obmat);
lineart_gpencil_generate(cache,
@@ -4821,6 +5402,8 @@ void MOD_lineart_gpencil_generate(LineartCache *cache,
intersection_mask,
thickness,
opacity,
+ shadow_selection,
+ silhouette_mode,
source_vgname,
vgname,
modifier_flags);
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
index 1a197c8b4b7..3668f1dc6d7 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_intern.h
@@ -18,7 +18,7 @@
#include <string.h>
struct LineartEdge;
-struct LineartRenderBuffer;
+struct LineartData;
struct LineartStaticMemPool;
struct LineartStaticMemPoolNode;
@@ -49,7 +49,6 @@ void *lineart_mem_acquire(struct LineartStaticMemPool *smp, size_t size);
void *lineart_mem_acquire_thread(struct LineartStaticMemPool *smp, size_t size);
void lineart_mem_destroy(struct LineartStaticMemPool *smp);
-void lineart_prepend_edge_direct(void **list_head, void *node);
void lineart_prepend_pool(LinkNode **first, struct LineartStaticMemPool *smp, void *link);
void lineart_matrix_ortho_44d(double (*mProjection)[4],
@@ -62,33 +61,118 @@ void lineart_matrix_ortho_44d(double (*mProjection)[4],
void lineart_matrix_perspective_44d(
double (*mProjection)[4], double fFov_rad, double fAspect, double zMin, double zMax);
-int lineart_count_intersection_segment_count(struct LineartRenderBuffer *rb);
+int lineart_count_intersection_segment_count(struct LineartData *ld);
-void lineart_count_and_print_render_buffer_memory(struct LineartRenderBuffer *rb);
+void lineart_count_and_print_render_buffer_memory(struct LineartData *ld);
#define LRT_ITER_ALL_LINES_BEGIN \
- LineartEdge *e; \
- for (int i = 0; i < rb->pending_edges.next; i++) { \
- e = rb->pending_edges.array[i];
+ { \
+ LineartEdge *e; \
+ for (int __i = 0; __i < ld->pending_edges.next; __i++) { \
+ e = ld->pending_edges.array[__i];
#define LRT_ITER_ALL_LINES_NEXT ; /* Doesn't do anything now with new array setup. */
#define LRT_ITER_ALL_LINES_END \
LRT_ITER_ALL_LINES_NEXT \
+ } \
}
#define LRT_BOUND_AREA_CROSSES(b1, b2) \
((b1)[0] < (b2)[1] && (b1)[1] > (b2)[0] && (b1)[3] < (b2)[2] && (b1)[2] > (b2)[3])
-/* Initial bounding area row/column count, setting 4 is the simplest way algorithm could function
- * efficiently. */
-#define LRT_BA_ROWS 4
+/* Initial bounding area row/column count, setting 10 is tested to be relatively optimal for the
+ * performance under current algorithm. */
+#define LRT_BA_ROWS 10
+
+#define LRT_EDGE_BA_MARCHING_BEGIN(fb1, fb2) \
+ double x = fb1[0], y = fb1[1]; \
+ LineartBoundingArea *ba = lineart_edge_first_bounding_area(ld, fb1, fb2); \
+ LineartBoundingArea *nba = ba; \
+ double k = (fb2[1] - fb1[1]) / (fb2[0] - fb1[0] + 1e-30); \
+ int positive_x = (fb2[0] - fb1[0]) > 0 ? 1 : (fb2[0] == fb1[0] ? 0 : -1); \
+ int positive_y = (fb2[1] - fb1[1]) > 0 ? 1 : (fb2[1] == fb1[1] ? 0 : -1); \
+ while (nba)
+
+#define LRT_EDGE_BA_MARCHING_NEXT(fb1, fb2) \
+ /* Marching along `e->v1` to `e->v2`, searching each possible bounding areas it may touch. */ \
+ nba = lineart_bounding_area_next(nba, fb1, fb2, x, y, k, positive_x, positive_y, &x, &y);
+
+#define LRT_EDGE_BA_MARCHING_END
+
+void lineart_main_occlusion_begin(struct LineartData *ld);
+void lineart_main_cull_triangles(struct LineartData *ld, bool clip_far);
+void lineart_main_free_adjacent_data(struct LineartData *ld);
+void lineart_main_perspective_division(struct LineartData *ld);
+void lineart_main_discard_out_of_frame_edges(struct LineartData *ld);
+void lineart_main_load_geometries(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *camera,
+ struct LineartData *ld,
+ bool allow_duplicates,
+ bool do_shadow_casting,
+ struct ListBase *shadow_elns);
+void lineart_main_get_view_vector(struct LineartData *ld);
+void lineart_main_bounding_area_make_initial(struct LineartData *ld);
+void lineart_main_bounding_areas_connect_post(struct LineartData *ld);
+void lineart_main_clear_linked_edges(struct LineartData *ld);
+void lineart_main_link_lines(struct LineartData *ld);
+void lineart_main_add_triangles(struct LineartData *ld);
+bool lineart_main_try_generate_shadow(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct LineartData *original_ld,
+ struct LineartGpencilModifierData *lmd,
+ struct LineartStaticMemPool *shadow_data_pool,
+ struct LineartElementLinkNode **r_veln,
+ struct LineartElementLinkNode **r_eeln,
+ struct ListBase *r_calculated_edges_eln_list,
+ struct LineartData **r_shadow_ld_if_reproject);
+void lineart_main_make_enclosed_shapes(struct LineartData *ld, struct LineartData *shadow_ld);
+void lineart_main_transform_and_add_shadow(struct LineartData *ld,
+ struct LineartElementLinkNode *veln,
+ struct LineartElementLinkNode *eeln);
+
+LineartElementLinkNode *lineart_find_matching_eln(struct ListBase *shadow_elns, int obindex);
+LineartEdge *lineart_find_matching_edge(struct LineartElementLinkNode *shadow_eln,
+ uint64_t edge_identifier);
+void lineart_register_shadow_cuts(struct LineartData *ld,
+ struct LineartEdge *e,
+ struct LineartEdge *shadow_edge);
+void lineart_register_intersection_shadow_cuts(struct LineartData *ld,
+ struct ListBase *shadow_elns);
+
+bool lineart_edge_from_triangle(const struct LineartTriangle *tri,
+ const struct LineartEdge *e,
+ bool allow_overlapping_edges);
+LineartBoundingArea *lineart_edge_first_bounding_area(struct LineartData *ld,
+ double *fbcoord1,
+ double *fbcoord2);
+LineartBoundingArea *lineart_bounding_area_next(struct LineartBoundingArea *_this,
+ double *fbcoord1,
+ double *fbcoord2,
+ double x,
+ double y,
+ double k,
+ int positive_x,
+ int positive_y,
+ double *next_x,
+ double *next_y);
+void lineart_edge_cut(struct LineartData *ld,
+ struct LineartEdge *e,
+ double start,
+ double end,
+ uchar material_mask_bits,
+ uchar mat_occlusion,
+ uint32_t shadow_bits);
+void lineart_add_edge_to_array(struct LineartPendingEdges *pe, struct LineartEdge *e);
+void lineart_finalize_object_edge_array_reserve(struct LineartPendingEdges *pe, int count);
+void lineart_destroy_render_data_keep_init(struct LineartData *ld);
#ifdef __cplusplus
extern "C" {
#endif
-void lineart_sort_adjacent_items(LineartAdjacentEdge *ai, int length);
+void lineart_sort_adjacent_items(struct LineartAdjacentEdge *ai, int length);
#ifdef __cplusplus
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
index 2b60fc45800..138c016e2e2 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c
@@ -132,6 +132,8 @@ static bool bake_strokes(Object *ob,
lmd->intersection_mask,
lmd->thickness,
lmd->opacity,
+ lmd->shadow_selection,
+ lmd->silhouette_selection,
lmd->source_vertex_group,
lmd->vgname,
lmd->flags);
@@ -141,8 +143,8 @@ static bool bake_strokes(Object *ob,
if (!is_first) {
MOD_lineart_clear_cache(&local_lc);
}
- /* Restore the original cache pointer so the modifiers below still have access to the
- * "global" cache. */
+ /* Restore the original cache pointer so the modifiers below still have access to the "global"
+ * cache. */
lmd->cache = gpd->runtime.lineart_cache;
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c
new file mode 100644
index 00000000000..ad0137fe0f0
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c
@@ -0,0 +1,1418 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include "MOD_gpencil_lineart.h"
+#include "MOD_lineart.h"
+
+#include "lineart_intern.h"
+
+#include "BKE_global.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_id.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "DEG_depsgraph_query.h"
+#include "DNA_collection_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_light_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+#include "MEM_guardedalloc.h"
+
+#include "BLI_task.h"
+#include "PIL_time.h"
+
+/* Shadow loading etc. ================== */
+
+LineartElementLinkNode *lineart_find_matching_eln(ListBase *shadow_elns, int obindex)
+{
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, shadow_elns) {
+ if (eln->obindex == obindex) {
+ return eln;
+ }
+ }
+ return NULL;
+}
+
+LineartEdge *lineart_find_matching_edge(LineartElementLinkNode *shadow_eln,
+ uint64_t edge_identifier)
+{
+ LineartEdge *elist = (LineartEdge *)shadow_eln->pointer;
+ for (int i = 0; i < shadow_eln->element_count; i++) {
+ if (elist[i].edge_identifier == edge_identifier) {
+ return &elist[i];
+ }
+ }
+ return NULL;
+}
+
+static bool lineart_contour_viewed_from_dark_side(LineartData *ld, LineartEdge *e)
+{
+
+ if (!(e->flags & (LRT_EDGE_FLAG_CONTOUR | LRT_EDGE_FLAG_CONTOUR_SECONDARY))) {
+ return false;
+ }
+ double view_vector[3];
+ double light_vector[3];
+ bool side_1_facing_light = false;
+ bool side_2_facing_light = false;
+ bool side_1_facing_camera = false;
+ if (ld->conf.cam_is_persp_secondary) {
+ sub_v3_v3v3_db(light_vector, ld->conf.camera_pos_secondary, e->v1->gloc);
+ }
+ else {
+ copy_v3_v3_db(light_vector, ld->conf.view_vector_secondary);
+ }
+ double dot_light_1 = dot_v3v3_db(light_vector, e->t1->gn);
+ side_1_facing_light = (dot_light_1 > 0);
+ if (e->t2) {
+ double dot_light_2 = dot_v3v3_db(light_vector, e->t2->gn);
+ side_2_facing_light = (dot_light_2 > 0);
+ }
+ else {
+ side_2_facing_light = !side_1_facing_light;
+ }
+
+ if (ld->conf.cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, ld->conf.camera_pos, e->v1->gloc);
+ }
+ else {
+ copy_v3_v3_db(view_vector, ld->conf.view_vector);
+ }
+ double dot_view_1 = dot_v3v3_db(view_vector, e->t1->gn);
+ side_1_facing_camera = (dot_view_1 > 0);
+
+ if ((side_1_facing_camera && (!side_1_facing_light) && side_2_facing_light) ||
+ ((!side_1_facing_camera) && side_1_facing_light && (!side_2_facing_light))) {
+ return true;
+ }
+ return false;
+}
+
+/* Cuts the original edge based on the occlusion results under light-camera, if segment
+ * is occluded in light-camera, then that segment on the original edge must be shaded. */
+void lineart_register_shadow_cuts(LineartData *ld, LineartEdge *e, LineartEdge *shadow_edge)
+{
+ LISTBASE_FOREACH (LineartEdgeSegment *, es, &shadow_edge->segments) {
+ /* Convert to view space cutting points. */
+ double la1 = es->ratio;
+ double la2 = es->next ? es->next->ratio : 1.0f;
+ la1 = la1 * e->v2->fbcoord[3] /
+ (e->v1->fbcoord[3] - la1 * (e->v1->fbcoord[3] - e->v2->fbcoord[3]));
+ la2 = la2 * e->v2->fbcoord[3] /
+ (e->v1->fbcoord[3] - la2 * (e->v1->fbcoord[3] - e->v2->fbcoord[3]));
+ unsigned char shadow_bits = (es->occlusion != 0) ? LRT_SHADOW_MASK_SHADED :
+ LRT_SHADOW_MASK_LIT;
+
+ if (lineart_contour_viewed_from_dark_side(ld, e) && shadow_bits == LRT_SHADOW_MASK_LIT) {
+ shadow_bits = LRT_SHADOW_MASK_SHADED;
+ }
+
+ lineart_edge_cut(ld, e, la1, la2, 0, 0, shadow_bits);
+ }
+}
+
+void lineart_register_intersection_shadow_cuts(LineartData *ld, ListBase *shadow_elns)
+{
+ if (!shadow_elns) {
+ return;
+ }
+
+ LineartElementLinkNode *eln_isect_shadow = NULL;
+ LineartElementLinkNode *eln_isect_original = NULL;
+
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, shadow_elns) {
+ if (eln->flags & LRT_ELEMENT_INTERSECTION_DATA) {
+ eln_isect_shadow = eln;
+ break;
+ }
+ }
+ LISTBASE_FOREACH (LineartElementLinkNode *, eln, &ld->geom.line_buffer_pointers) {
+ if (eln->flags & LRT_ELEMENT_INTERSECTION_DATA) {
+ eln_isect_original = eln;
+ break;
+ }
+ }
+ if (!eln_isect_shadow || !eln_isect_original) {
+ return;
+ }
+
+ /* Keeping it single threaded for now because a simple parallel_for could end up getting the same
+ * #shadow_e in different threads. */
+ for (int i = 0; i < eln_isect_original->element_count; i++) {
+ LineartEdge *e = &((LineartEdge *)eln_isect_original->pointer)[i];
+ LineartEdge *shadow_e = lineart_find_matching_edge(eln_isect_shadow,
+ (uint64_t)e->edge_identifier);
+ if (shadow_e) {
+ lineart_register_shadow_cuts(ld, e, shadow_e);
+ }
+ }
+}
+
+/* Shadow computation part ================== */
+
+static LineartShadowSegment *lineart_give_shadow_segment(LineartData *ld)
+{
+ BLI_spin_lock(&ld->lock_cuts);
+
+ /* See if there is any already allocated memory we can reuse. */
+ if (ld->wasted_shadow_cuts.first) {
+ LineartShadowSegment *es = (LineartShadowSegment *)BLI_pophead(&ld->wasted_shadow_cuts);
+ BLI_spin_unlock(&ld->lock_cuts);
+ memset(es, 0, sizeof(LineartShadowSegment));
+ return (LineartShadowSegment *)es;
+ }
+ BLI_spin_unlock(&ld->lock_cuts);
+
+ /* Otherwise allocate some new memory. */
+ return (LineartShadowSegment *)lineart_mem_acquire_thread(&ld->render_data_pool,
+ sizeof(LineartShadowSegment));
+}
+
+static void lineart_shadow_segment_slice_get(double *fb_co_1,
+ double *fb_co_2,
+ double *gloc_1,
+ double *gloc_2,
+ double ratio,
+ double at_1,
+ double at_2,
+ double *r_fb_co,
+ double *r_gloc)
+{
+ double real_at = ((at_2 - at_1) == 0) ? 0 : ((ratio - at_1) / (at_2 - at_1));
+ double ga = fb_co_1[3] * real_at / (fb_co_2[3] * (1.0f - real_at) + fb_co_1[3] * real_at);
+ interp_v3_v3v3_db(r_fb_co, fb_co_1, fb_co_2, real_at);
+ r_fb_co[3] = interpd(fb_co_2[3], fb_co_1[3], ga);
+ interp_v3_v3v3_db(r_gloc, gloc_1, gloc_2, ga);
+}
+
+/**
+ * This function tries to get the closest projected segments along two end points.
+ * The x,y of s1, s2 are aligned in frame-buffer coordinates, only z,w are different.
+ * We will get the closest z/w as well as the corresponding global coordinates.
+ *
+ * \code{.unparsed}
+ * (far side)
+ * l-------r [s1] ^
+ * _-r [s2] | In this situation it will essentially return the coordinates of s2.
+ * _-` |
+ * l-` |
+ *
+ * (far side)
+ * _-r [s2] ^
+ * _-` | In this case the return coordinates would be `s2l` and `s1r`,
+ * l-----_c`-----r [s1] | and `r_new` will be assigned coordinates of `c`.
+ * _-` |
+ * l-` |
+ * \endcode
+ *
+ * Returns true when a new cut (`c`) is needed in the middle, otherwise returns false, and
+ * `*r_new_xxx` are not touched.
+ */
+static bool lineart_do_closest_segment(bool is_persp,
+ double *s1_fb_co_1,
+ double *s1_fb_co_2,
+ double *s2_fb_co_1,
+ double *s2_fb_co_2,
+ double *s1_gloc_1,
+ double *s1_gloc_2,
+ double *s2_gloc_1,
+ double *s2_gloc_2,
+ double *r_fb_co_1,
+ double *r_fb_co_2,
+ double *r_gloc_1,
+ double *r_gloc_2,
+ double *r_new_in_the_middle,
+ double *r_new_in_the_middle_global,
+ double *r_new_at,
+ bool *is_side_2r,
+ bool *use_new_ref)
+{
+ int side = 0;
+ int z_index = is_persp ? 3 : 2;
+ /* Always use the closest point to the light camera. */
+ if (s1_fb_co_1[z_index] >= s2_fb_co_1[z_index]) {
+ copy_v4_v4_db(r_fb_co_1, s2_fb_co_1);
+ copy_v3_v3_db(r_gloc_1, s2_gloc_1);
+ side++;
+ }
+ if (s1_fb_co_2[z_index] >= s2_fb_co_2[z_index]) {
+ copy_v4_v4_db(r_fb_co_2, s2_fb_co_2);
+ copy_v3_v3_db(r_gloc_2, s2_gloc_2);
+ *is_side_2r = true;
+ side++;
+ }
+ if (s1_fb_co_1[z_index] <= s2_fb_co_1[z_index]) {
+ copy_v4_v4_db(r_fb_co_1, s1_fb_co_1);
+ copy_v3_v3_db(r_gloc_1, s1_gloc_1);
+ side--;
+ }
+ if (s1_fb_co_2[z_index] <= s2_fb_co_2[z_index]) {
+ copy_v4_v4_db(r_fb_co_2, s1_fb_co_2);
+ copy_v3_v3_db(r_gloc_2, s1_gloc_2);
+ *is_side_2r = false;
+ side--;
+ }
+
+ /* No need to cut in the middle, because one segment completely overlaps the other. */
+ if (side) {
+ if (side > 0) {
+ *is_side_2r = true;
+ *use_new_ref = true;
+ }
+ else if (side < 0) {
+ *is_side_2r = false;
+ *use_new_ref = false;
+ }
+ return false;
+ }
+
+ /* Else there must be an intersection point in the middle. Use "w" value to linearly plot the
+ * position and get image space "ratio" position. */
+ double dl = s1_fb_co_1[z_index] - s2_fb_co_1[z_index];
+ double dr = s1_fb_co_2[z_index] - s2_fb_co_2[z_index];
+ double ga = ratiod(dl, dr, 0);
+ *r_new_at = is_persp ? s2_fb_co_2[3] * ga / (s2_fb_co_1[3] * (1.0f - ga) + s2_fb_co_2[3] * ga) :
+ ga;
+ interp_v3_v3v3_db(r_new_in_the_middle, s2_fb_co_1, s2_fb_co_2, *r_new_at);
+ r_new_in_the_middle[3] = interpd(s2_fb_co_2[3], s2_fb_co_1[3], ga);
+ interp_v3_v3v3_db(r_new_in_the_middle_global, s1_gloc_1, s1_gloc_2, ga);
+ *use_new_ref = true;
+
+ return true;
+}
+
+/* For each visible [segment] of the edge, create 1 shadow edge. Note if the original edge has
+ * multiple visible cuts, multiple shadow edges should be generated. */
+static void lineart_shadow_create_shadow_edge_array(LineartData *ld,
+ bool transform_edge_cuts,
+ bool do_light_contour)
+{
+ /* If the segment is short enough, we ignore them because it's not prominently visible anyway. */
+#define DISCARD_NONSENSE_SEGMENTS \
+ if (es->occlusion != 0 || \
+ (es->next && \
+ LRT_DOUBLE_CLOSE_ENOUGH(es->ratio, ((LineartEdgeSegment *)es->next)->ratio))) { \
+ LRT_ITER_ALL_LINES_NEXT; \
+ continue; \
+ }
+
+ /* Count and allocate at once to save time. */
+ int segment_count = 0;
+ uint16_t accept_types = (LRT_EDGE_FLAG_CONTOUR | LRT_EDGE_FLAG_LOOSE);
+ if (do_light_contour) {
+ accept_types |= LRT_EDGE_FLAG_LIGHT_CONTOUR;
+ }
+ LRT_ITER_ALL_LINES_BEGIN
+ {
+ /* Only contour and loose edges can actually cast shadows. We allow light contour here because
+ * we want to see if it also doubles as a view contour, in that case we also need to project
+ * them. */
+ if (!(e->flags & accept_types)) {
+ continue;
+ }
+ if (e->flags == LRT_EDGE_FLAG_LIGHT_CONTOUR) {
+ /* Check if the light contour also doubles as a view contour. */
+ LineartEdge *orig_e = (LineartEdge *)e->t1;
+ if (!orig_e->t2) {
+ e->flags |= LRT_EDGE_FLAG_CONTOUR;
+ }
+ else {
+ double vv[3];
+ double *view_vector = vv;
+ double dot_1 = 0, dot_2 = 0;
+ double result;
+ if (ld->conf.cam_is_persp) {
+ sub_v3_v3v3_db(view_vector, orig_e->v1->gloc, ld->conf.camera_pos);
+ }
+ else {
+ view_vector = ld->conf.view_vector;
+ }
+
+ dot_1 = dot_v3v3_db(view_vector, orig_e->t1->gn);
+ dot_2 = dot_v3v3_db(view_vector, orig_e->t2->gn);
+
+ if ((result = dot_1 * dot_2) <= 0 && (dot_1 + dot_2)) {
+ /* If this edge is both a light contour and a view contour, mark it for the convenience
+ * of generating it in the next iteration. */
+ e->flags |= LRT_EDGE_FLAG_CONTOUR;
+ }
+ }
+ if (!(e->flags & LRT_EDGE_FLAG_CONTOUR)) {
+ continue;
+ }
+ }
+ LISTBASE_FOREACH (LineartEdgeSegment *, es, &e->segments) {
+ DISCARD_NONSENSE_SEGMENTS
+ segment_count++;
+ }
+ }
+ LRT_ITER_ALL_LINES_END
+
+ LineartShadowEdge *sedge = lineart_mem_acquire(&ld->render_data_pool,
+ sizeof(LineartShadowEdge) * segment_count);
+ LineartShadowSegment *sseg = lineart_mem_acquire(
+ &ld->render_data_pool, sizeof(LineartShadowSegment) * segment_count * 2);
+
+ ld->shadow_edges = sedge;
+ ld->shadow_edges_count = segment_count;
+
+ int i = 0;
+ LRT_ITER_ALL_LINES_BEGIN
+ {
+ if (!(e->flags & (LRT_EDGE_FLAG_CONTOUR | LRT_EDGE_FLAG_LOOSE))) {
+ continue;
+ }
+ LISTBASE_FOREACH (LineartEdgeSegment *, es, &e->segments) {
+ DISCARD_NONSENSE_SEGMENTS
+
+ double next_at = es->next ? ((LineartEdgeSegment *)es->next)->ratio : 1.0f;
+ /* Get correct XYZ and W coordinates. */
+ interp_v3_v3v3_db(sedge[i].fbc1, e->v1->fbcoord, e->v2->fbcoord, es->ratio);
+ interp_v3_v3v3_db(sedge[i].fbc2, e->v1->fbcoord, e->v2->fbcoord, next_at);
+
+ /* Global coord for light-shadow separation line (occlusion-corrected light contour). */
+ double ga1 = e->v1->fbcoord[3] * es->ratio /
+ (es->ratio * e->v1->fbcoord[3] + (1 - es->ratio) * e->v2->fbcoord[3]);
+ double ga2 = e->v1->fbcoord[3] * next_at /
+ (next_at * e->v1->fbcoord[3] + (1 - next_at) * e->v2->fbcoord[3]);
+ interp_v3_v3v3_db(sedge[i].g1, e->v1->gloc, e->v2->gloc, ga1);
+ interp_v3_v3v3_db(sedge[i].g2, e->v1->gloc, e->v2->gloc, ga2);
+
+ /* Assign an absurdly big W for initial distance so when triangles show up to catch the
+ * shadow, their w must certainly be smaller than this value so the shadow catches
+ * successfully. */
+ sedge[i].fbc1[3] = 1e30;
+ sedge[i].fbc2[3] = 1e30;
+ sedge[i].fbc1[2] = 1e30;
+ sedge[i].fbc2[2] = 1e30;
+
+ /* Assign to the first segment's right and the last segment's left position */
+ copy_v4_v4_db(sseg[i * 2].fbc2, sedge[i].fbc1);
+ copy_v4_v4_db(sseg[i * 2 + 1].fbc1, sedge[i].fbc2);
+ sseg[i * 2].ratio = 0.0f;
+ sseg[i * 2 + 1].ratio = 1.0f;
+ BLI_addtail(&sedge[i].shadow_segments, &sseg[i * 2]);
+ BLI_addtail(&sedge[i].shadow_segments, &sseg[i * 2 + 1]);
+
+ if (e->flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
+ sedge[i].e_ref = (LineartEdge *)e->t1;
+ sedge[i].e_ref_light_contour = e;
+ /* Restore original edge flag for edges "who is both view and light contour" so we still
+ * have correct edge flags. */
+ e->flags &= (~LRT_EDGE_FLAG_CONTOUR);
+ }
+ else {
+ sedge[i].e_ref = e;
+ }
+
+ sedge[i].es_ref = es;
+
+ i++;
+ }
+ }
+ LRT_ITER_ALL_LINES_END
+
+ /* Transform the cutting position to global space for regular feature lines. This is for
+ * convenience of reusing the shadow cast function for both shadow line generation and silhouette
+ * registration, which the latter one needs view-space coordinates, while cast shadow needs
+ * global-space coordinates. */
+ if (transform_edge_cuts) {
+ LRT_ITER_ALL_LINES_BEGIN
+ {
+ LISTBASE_FOREACH (LineartEdgeSegment *, es, &e->segments) {
+ es->ratio = e->v1->fbcoord[3] * es->ratio /
+ (es->ratio * e->v1->fbcoord[3] + (1 - es->ratio) * e->v2->fbcoord[3]);
+ }
+ }
+ LRT_ITER_ALL_LINES_END
+ }
+
+ if (G.debug_value == 4000) {
+ printf("Shadow: Added %d raw shadow_edges\n", segment_count);
+ }
+}
+
+/* This function does the actual cutting on a given "shadow edge".
+ * #start / #end determines the view(from light camera) space cutting ratio.
+ * #start/end_gloc/fbc are the respective start/end coordinates.
+ * #facing_light is set from the caller which determines if this edge landed on a triangle's light
+ * facing side or not.
+ *
+ * Visually this function does this: (Top is the far side of the camera)
+ * _-end
+ * _-`
+ * l[-------------_-`--------------]r [e] 1) Calls for cut on top of #e.
+ * _-`
+ * _-`
+ * start-`
+ *
+ * _-end
+ * _-`
+ * l[-----][------_-`----][--------]r [e] 2) Add cutting points on #e at #start/#end.
+ * _-`
+ * _-`
+ * start-`
+ *
+ * _-end
+ * _-`
+ * [------_-`----] 3) Call lineart_shadow_segment_slice_get() to
+ * _-` get coordinates of a visually aligned segment on
+ * _-` #e with the incoming segment.
+ * start-`
+ *
+ * _c-----] 4) Call lineart_do_closest_segment() to find out the
+ * _-` actual geometry after cut, add a new cut if needed.
+ * _-`
+ * [`
+ *
+ * l[-----] _][----][--------]r [e] 5) Write coordinates on cuts.
+ * _-`
+ * _-`
+ * [`
+ *
+ * This process is repeated on each existing segments of the shadow edge (#e), which ensures they
+ * all have been tested for closest segments after cutting. And in the diagram it's clear that the
+ * left/right side of cuts are likely to be discontinuous, each cut's left side designates the
+ * right side of the last segment, and vise versa. */
+static void lineart_shadow_edge_cut(LineartData *ld,
+ LineartShadowEdge *e,
+ double start,
+ double end,
+ double *start_gloc,
+ double *end_gloc,
+ double *start_fb_co,
+ double *end_fb_co,
+ bool facing_light,
+ uint32_t target_reference)
+{
+ LineartShadowSegment *seg, *i_seg;
+ LineartShadowSegment *cut_start_after = e->shadow_segments.first,
+ *cut_end_before = e->shadow_segments.last;
+ LineartShadowSegment *new_seg_1 = NULL, *new_seg_2 = NULL, *seg_1 = NULL, *seg_2 = NULL;
+ int untouched = 0;
+
+ /* If for some reason the occlusion function may give a result that has zero length, or
+ * reversed in direction, or NAN, we take care of them here. */
+ if (LRT_DOUBLE_CLOSE_ENOUGH(start, end)) {
+ return;
+ }
+ if (LRT_DOUBLE_CLOSE_ENOUGH(start, 1) || LRT_DOUBLE_CLOSE_ENOUGH(end, 0)) {
+ return;
+ }
+ if (UNLIKELY(start != start)) {
+ start = 0;
+ }
+ if (UNLIKELY(end != end)) {
+ end = 0;
+ }
+
+ if (start > end) {
+ double t = start;
+ start = end;
+ end = t;
+ }
+
+ /* Begin looking for starting position of the segment. */
+ /* Not using a list iteration macro because of it more clear when using for loops to iterate
+ * through the segments. */
+ for (seg = e->shadow_segments.first; seg; seg = seg->next) {
+ if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, start)) {
+ cut_start_after = seg;
+ new_seg_1 = cut_start_after;
+ break;
+ }
+ if (seg->next == NULL) {
+ break;
+ }
+ i_seg = seg->next;
+ if (i_seg->ratio > start + 1e-09 && start > seg->ratio) {
+ cut_start_after = seg;
+ new_seg_1 = lineart_give_shadow_segment(ld);
+ break;
+ }
+ }
+ if (!cut_start_after && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
+ untouched = 1;
+ }
+ for (seg = cut_start_after->next; seg; seg = seg->next) {
+ /* We tried to cut at existing cutting point (e.g. where the line's occluded by a triangle
+ * strip). */
+ if (LRT_DOUBLE_CLOSE_ENOUGH(seg->ratio, end)) {
+ cut_end_before = seg;
+ new_seg_2 = cut_end_before;
+ break;
+ }
+ /* This check is to prevent `es->ratio == 1.0` (where we don't need to cut because we are ratio
+ * the end point). */
+ if (!seg->next && LRT_DOUBLE_CLOSE_ENOUGH(1, end)) {
+ cut_end_before = seg;
+ new_seg_2 = cut_end_before;
+ untouched = 1;
+ break;
+ }
+ /* When an actual cut is needed in the line. */
+ if (seg->ratio > end) {
+ cut_end_before = seg;
+ new_seg_2 = lineart_give_shadow_segment(ld);
+ break;
+ }
+ }
+
+ /* When we still can't find any existing cut in the line, we allocate new ones. */
+ if (new_seg_1 == NULL) {
+ new_seg_1 = lineart_give_shadow_segment(ld);
+ }
+ if (new_seg_2 == NULL) {
+ if (untouched) {
+ new_seg_2 = new_seg_1;
+ cut_end_before = new_seg_2;
+ }
+ else {
+ new_seg_2 = lineart_give_shadow_segment(ld);
+ }
+ }
+
+ /* If we touched the cut list, we assign the new cut position based on new cut position,
+ * this way we accommodate precision lost due to multiple cut inserts. */
+ new_seg_1->ratio = start;
+ if (!untouched) {
+ new_seg_2->ratio = end;
+ }
+
+ double r_fb_co_1[4], r_fb_co_2[4], r_gloc_1[3], r_gloc_2[3];
+ double r_new_in_the_middle[4], r_new_in_the_middle_global[3], r_new_at;
+ double *s1_fb_co_1, *s1_fb_co_2, *s1_gloc_1, *s1_gloc_2;
+
+ /* Temporary coordinate records and "middle" records. */
+ double t_g1[3], t_g2[3], t_fbc1[4], t_fbc2[4], m_g1[3], m_fbc1[4], m_g2[3], m_fbc2[4];
+ bool is_side_2r, has_middle = false, use_new_ref;
+ copy_v4_v4_db(t_fbc1, start_fb_co);
+ copy_v3_v3_db(t_g1, start_gloc);
+
+ /* Do max stuff before insert. */
+ LineartShadowSegment *nes;
+ for (seg = cut_start_after; seg != cut_end_before; seg = nes) {
+ nes = seg->next;
+
+ s1_fb_co_1 = seg->fbc2, s1_fb_co_2 = nes->fbc1;
+ s1_gloc_1 = seg->g2, s1_gloc_2 = nes->g1;
+ seg_1 = seg, seg_2 = nes;
+ if (seg == cut_start_after) {
+ lineart_shadow_segment_slice_get(seg->fbc2,
+ nes->fbc1,
+ seg->g2,
+ nes->g1,
+ new_seg_1->ratio,
+ seg->ratio,
+ nes->ratio,
+ m_fbc1,
+ m_g1);
+ s1_fb_co_1 = m_fbc1, s1_gloc_1 = m_g1;
+ seg_1 = new_seg_1;
+ if (cut_start_after != new_seg_1) {
+ BLI_insertlinkafter(&e->shadow_segments, cut_start_after, new_seg_1);
+ copy_v4_v4_db(new_seg_1->fbc1, m_fbc1);
+ copy_v3_v3_db(new_seg_1->g1, m_g1);
+ }
+ }
+ if (nes == cut_end_before) {
+ lineart_shadow_segment_slice_get(seg->fbc2,
+ nes->fbc1,
+ seg->g2,
+ nes->g1,
+ new_seg_2->ratio,
+ seg->ratio,
+ nes->ratio,
+ m_fbc2,
+ m_g2);
+ s1_fb_co_2 = m_fbc2, s1_gloc_2 = m_g2;
+ seg_2 = new_seg_2;
+ if (cut_end_before != new_seg_2) {
+ BLI_insertlinkbefore(&e->shadow_segments, cut_end_before, new_seg_2);
+ copy_v4_v4_db(new_seg_2->fbc2, m_fbc2);
+ copy_v3_v3_db(new_seg_2->g2, m_g2);
+ /* Need to restore the flag for next segment's reference. */
+ seg_2->flag = seg->flag;
+ seg_2->target_reference = seg->target_reference;
+ }
+ }
+
+ lineart_shadow_segment_slice_get(
+ start_fb_co, end_fb_co, start_gloc, end_gloc, seg_2->ratio, start, end, t_fbc2, t_g2);
+
+ if ((has_middle = lineart_do_closest_segment(ld->conf.cam_is_persp,
+ s1_fb_co_1,
+ s1_fb_co_2,
+ t_fbc1,
+ t_fbc2,
+ s1_gloc_1,
+ s1_gloc_2,
+ t_g1,
+ t_g2,
+ r_fb_co_1,
+ r_fb_co_2,
+ r_gloc_1,
+ r_gloc_2,
+ r_new_in_the_middle,
+ r_new_in_the_middle_global,
+ &r_new_at,
+ &is_side_2r,
+ &use_new_ref))) {
+ LineartShadowSegment *ss_middle = lineart_give_shadow_segment(ld);
+ ss_middle->ratio = interpf(seg_2->ratio, seg_1->ratio, r_new_at);
+ ss_middle->flag = LRT_SHADOW_CASTED |
+ (use_new_ref ? (facing_light ? LRT_SHADOW_FACING_LIGHT : 0) : seg_1->flag);
+ ss_middle->target_reference = (use_new_ref ? (target_reference) : seg_1->target_reference);
+ copy_v3_v3_db(ss_middle->g1, r_new_in_the_middle_global);
+ copy_v3_v3_db(ss_middle->g2, r_new_in_the_middle_global);
+ copy_v4_v4_db(ss_middle->fbc1, r_new_in_the_middle);
+ copy_v4_v4_db(ss_middle->fbc2, r_new_in_the_middle);
+ BLI_insertlinkafter(&e->shadow_segments, seg_1, ss_middle);
+ }
+ /* Always assign the "closest" value to the segment. */
+ copy_v4_v4_db(seg_1->fbc2, r_fb_co_1);
+ copy_v3_v3_db(seg_1->g2, r_gloc_1);
+ copy_v4_v4_db(seg_2->fbc1, r_fb_co_2);
+ copy_v3_v3_db(seg_2->g1, r_gloc_2);
+
+ if (has_middle) {
+ seg_1->flag = LRT_SHADOW_CASTED |
+ (is_side_2r ? seg->flag : (facing_light ? LRT_SHADOW_FACING_LIGHT : 0));
+ seg_1->target_reference = is_side_2r ? seg->target_reference : target_reference;
+ }
+ else {
+ seg_1->flag = LRT_SHADOW_CASTED |
+ (use_new_ref ? (facing_light ? LRT_SHADOW_FACING_LIGHT : 0) : seg->flag);
+ seg_1->target_reference = use_new_ref ? target_reference : seg->target_reference;
+ }
+
+ copy_v4_v4_db(t_fbc1, t_fbc2);
+ copy_v3_v3_db(t_g1, t_g2);
+ }
+}
+
+static bool lineart_shadow_cast_onto_triangle(LineartData *ld,
+ LineartTriangle *tri,
+ LineartShadowEdge *sedge,
+ double *r_at_1,
+ double *r_at_2,
+ double *r_fb_co_1,
+ double *r_fb_co_2,
+ double *r_gloc_1,
+ double *r_gloc_2,
+ bool *r_facing_light)
+{
+
+ double *LFBC = sedge->fbc1, *RFBC = sedge->fbc2, *FBC0 = tri->v[0]->fbcoord,
+ *FBC1 = tri->v[1]->fbcoord, *FBC2 = tri->v[2]->fbcoord;
+
+ /* Bound box check. Because we have already done occlusion in the shadow camera, so any visual
+ * intersection found in this function must mean that the triangle is behind the given line so it
+ * will always project a shadow, hence no need to do depth bound-box check. */
+ if ((MAX3(FBC0[0], FBC1[0], FBC2[0]) < MIN2(LFBC[0], RFBC[0])) ||
+ (MIN3(FBC0[0], FBC1[0], FBC2[0]) > MAX2(LFBC[0], RFBC[0])) ||
+ (MAX3(FBC0[1], FBC1[1], FBC2[1]) < MIN2(LFBC[1], RFBC[1])) ||
+ (MIN3(FBC0[1], FBC1[1], FBC2[1]) > MAX2(LFBC[1], RFBC[1]))) {
+ return false;
+ }
+
+ bool is_persp = ld->conf.cam_is_persp;
+ double ratio[2];
+ int trie[2];
+ int pi = 0;
+ if (lineart_line_isec_2d_ignore_line2pos(FBC0, FBC1, LFBC, RFBC, &ratio[pi])) {
+ trie[pi] = 0;
+ pi++;
+ }
+ if (lineart_line_isec_2d_ignore_line2pos(FBC1, FBC2, LFBC, RFBC, &ratio[pi])) {
+ /* ratio[0] == 1 && ratio[1] == 0 means we found a intersection at the same point of the
+ * edge (FBC1), ignore this one and try get the intersection point from the other side of
+ * the edge
+ */
+ if (!(pi && LRT_DOUBLE_CLOSE_ENOUGH(ratio[0], 1.0f) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(ratio[1], 0.0f))) {
+ trie[pi] = 1;
+ pi++;
+ }
+ }
+ if (!pi) {
+ return false;
+ }
+ if (pi == 1 && lineart_line_isec_2d_ignore_line2pos(FBC2, FBC0, LFBC, RFBC, &ratio[pi])) {
+
+ if ((trie[0] == 0 && LRT_DOUBLE_CLOSE_ENOUGH(ratio[0], 0.0f) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(ratio[1], 1.0f)) ||
+ (trie[0] == 1 && LRT_DOUBLE_CLOSE_ENOUGH(ratio[0], 1.0f) &&
+ LRT_DOUBLE_CLOSE_ENOUGH(ratio[1], 0.0f))) {
+ return false;
+ }
+ trie[pi] = 2;
+ pi++;
+ }
+
+ if (pi != 2) {
+ return false;
+ }
+
+ /* Get projected global position. */
+
+ double gpos1[3], gpos2[3];
+ double *v1 = (trie[0] == 0 ? FBC0 : (trie[0] == 1 ? FBC1 : FBC2));
+ double *v2 = (trie[0] == 0 ? FBC1 : (trie[0] == 1 ? FBC2 : FBC0));
+ double *v3 = (trie[1] == 0 ? FBC0 : (trie[1] == 1 ? FBC1 : FBC2));
+ double *v4 = (trie[1] == 0 ? FBC1 : (trie[1] == 1 ? FBC2 : FBC0));
+ double *gv1 = (trie[0] == 0 ? tri->v[0]->gloc :
+ (trie[0] == 1 ? tri->v[1]->gloc : tri->v[2]->gloc));
+ double *gv2 = (trie[0] == 0 ? tri->v[1]->gloc :
+ (trie[0] == 1 ? tri->v[2]->gloc : tri->v[0]->gloc));
+ double *gv3 = (trie[1] == 0 ? tri->v[0]->gloc :
+ (trie[1] == 1 ? tri->v[1]->gloc : tri->v[2]->gloc));
+ double *gv4 = (trie[1] == 0 ? tri->v[1]->gloc :
+ (trie[1] == 1 ? tri->v[2]->gloc : tri->v[0]->gloc));
+ double gr1 = is_persp ? v1[3] * ratio[0] / (ratio[0] * v1[3] + (1 - ratio[0]) * v2[3]) :
+ ratio[0];
+ double gr2 = is_persp ? v3[3] * ratio[1] / (ratio[1] * v3[3] + (1 - ratio[1]) * v4[3]) :
+ ratio[1];
+ interp_v3_v3v3_db(gpos1, gv1, gv2, gr1);
+ interp_v3_v3v3_db(gpos2, gv3, gv4, gr2);
+
+ double fbc1[4], fbc2[4];
+
+ mul_v4_m4v3_db(fbc1, ld->conf.view_projection, gpos1);
+ mul_v4_m4v3_db(fbc2, ld->conf.view_projection, gpos2);
+ if (is_persp) {
+ mul_v3db_db(fbc1, 1.0f / fbc1[3]);
+ mul_v3db_db(fbc2, 1.0f / fbc2[3]);
+ }
+
+ int use = (fabs(LFBC[0] - RFBC[0]) > fabs(LFBC[1] - RFBC[1])) ? 0 : 1;
+ double at1 = ratiod(LFBC[use], RFBC[use], fbc1[use]);
+ double at2 = ratiod(LFBC[use], RFBC[use], fbc2[use]);
+ if (at1 > at2) {
+ swap_v3_v3_db(gpos1, gpos2);
+ swap_v4_v4_db(fbc1, fbc2);
+ SWAP(double, at1, at2);
+ }
+
+ /* If not effectively projecting anything. */
+ if (at1 > (1.0f - FLT_EPSILON) || at2 < FLT_EPSILON) {
+ return false;
+ }
+
+ /* Trim to edge's end points. */
+
+ double t_fbc1[4], t_fbc2[4], t_gpos1[3], t_gpos2[3];
+ bool trimmed1 = false, trimmed2 = false;
+ if (at1 < 0 || at2 > 1) {
+ double rat1 = (-at1) / (at2 - at1);
+ double rat2 = (1.0f - at1) / (at2 - at1);
+ double gat1 = is_persp ? fbc1[3] * rat1 / (rat1 * fbc1[3] + (1 - rat1) * fbc2[3]) : rat1;
+ double gat2 = is_persp ? fbc1[3] * rat2 / (rat2 * fbc1[3] + (1 - rat2) * fbc2[3]) : rat2;
+ if (at1 < 0) {
+ interp_v3_v3v3_db(t_gpos1, gpos1, gpos2, gat1);
+ interp_v3_v3v3_db(t_fbc1, fbc1, fbc2, rat1);
+ t_fbc1[3] = interpd(fbc2[3], fbc1[3], gat1);
+ at1 = 0, trimmed1 = true;
+ }
+ if (at2 > 1) {
+ interp_v3_v3v3_db(t_gpos2, gpos1, gpos2, gat2);
+ interp_v3_v3v3_db(t_fbc2, fbc1, fbc2, rat2);
+ t_fbc2[3] = interpd(fbc2[3], fbc1[3], gat2);
+ at2 = 1, trimmed2 = true;
+ }
+ }
+ if (trimmed1) {
+ copy_v4_v4_db(fbc1, t_fbc1);
+ copy_v3_v3_db(gpos1, t_gpos1);
+ }
+ if (trimmed2) {
+ copy_v4_v4_db(fbc2, t_fbc2);
+ copy_v3_v3_db(gpos2, t_gpos2);
+ }
+
+ *r_at_1 = at1;
+ *r_at_2 = at2;
+ copy_v4_v4_db(r_fb_co_1, fbc1);
+ copy_v4_v4_db(r_fb_co_2, fbc2);
+ copy_v3_v3_db(r_gloc_1, gpos1);
+ copy_v3_v3_db(r_gloc_2, gpos2);
+
+ double camera_vector[3];
+
+ if (is_persp) {
+ sub_v3_v3v3_db(camera_vector, ld->conf.camera_pos, tri->v[0]->gloc);
+ }
+ else {
+ copy_v3_v3_db(camera_vector, ld->conf.view_vector);
+ }
+
+ double dot_f = dot_v3v3_db(camera_vector, tri->gn);
+ *r_facing_light = (dot_f < 0);
+
+ return true;
+}
+
+/* The one step all to cast all visible edges in light camera back to other geometries behind them,
+ * the result of this step can then be generated as actual LineartEdge's for occlusion test in view
+ * camera. */
+static void lineart_shadow_cast(LineartData *ld, bool transform_edge_cuts, bool do_light_contour)
+{
+
+ lineart_shadow_create_shadow_edge_array(ld, transform_edge_cuts, do_light_contour);
+
+ /* Keep it single threaded for now because the loop will write "done" pointers to triangles. */
+ for (int edge_i = 0; edge_i < ld->shadow_edges_count; edge_i++) {
+ LineartShadowEdge *sedge = &ld->shadow_edges[edge_i];
+
+ LineartTriangleThread *tri;
+ double at_1, at_2;
+ double fb_co_1[4], fb_co_2[4];
+ double global_1[3], global_2[3];
+ bool facing_light;
+
+ LRT_EDGE_BA_MARCHING_BEGIN(sedge->fbc1, sedge->fbc2)
+ {
+ for (int i = 0; i < nba->triangle_count; i++) {
+ tri = (LineartTriangleThread *)nba->linked_triangles[i];
+ if (tri->testing_e[0] == (LineartEdge *)sedge || tri->base.mat_occlusion == 0 ||
+ lineart_edge_from_triangle(
+ (LineartTriangle *)tri, sedge->e_ref, ld->conf.allow_overlapping_edges)) {
+ continue;
+ }
+ tri->testing_e[0] = (LineartEdge *)sedge;
+
+ if (lineart_shadow_cast_onto_triangle(ld,
+ (LineartTriangle *)tri,
+ sedge,
+ &at_1,
+ &at_2,
+ fb_co_1,
+ fb_co_2,
+ global_1,
+ global_2,
+ &facing_light)) {
+ lineart_shadow_edge_cut(ld,
+ sedge,
+ at_1,
+ at_2,
+ global_1,
+ global_2,
+ fb_co_1,
+ fb_co_2,
+ facing_light,
+ tri->base.target_reference);
+ }
+ }
+ LRT_EDGE_BA_MARCHING_NEXT(sedge->fbc1, sedge->fbc2);
+ }
+ LRT_EDGE_BA_MARCHING_END;
+ }
+}
+
+/* For each [segment] on a shadow shadow_edge, 1 LineartEdge will be generated with a cast shadow
+ * edge flag (if that segment failed to cast onto anything then it's not generated). The original
+ * shadow shadow_edge is optionally generated as a light contour. */
+static bool lineart_shadow_cast_generate_edges(LineartData *ld,
+ bool do_original_edges,
+ LineartElementLinkNode **r_veln,
+ LineartElementLinkNode **r_eeln)
+{
+ int tot_edges = 0;
+ int tot_orig_edges = 0;
+ for (int i = 0; i < ld->shadow_edges_count; i++) {
+ LineartShadowEdge *sedge = &ld->shadow_edges[i];
+ LISTBASE_FOREACH (LineartShadowSegment *, sseg, &sedge->shadow_segments) {
+ if (!(sseg->flag & LRT_SHADOW_CASTED)) {
+ continue;
+ }
+ if (!sseg->next) {
+ break;
+ }
+ tot_edges++;
+ }
+ tot_orig_edges++;
+ }
+
+ int edge_alloc = tot_edges + (do_original_edges ? tot_orig_edges : 0);
+
+ if (G.debug_value == 4000) {
+ printf("Line art shadow segments total: %d\n", tot_edges);
+ }
+
+ if (!edge_alloc) {
+ return false;
+ }
+ LineartElementLinkNode *veln = lineart_mem_acquire(ld->shadow_data_pool,
+ sizeof(LineartElementLinkNode));
+ LineartElementLinkNode *eeln = lineart_mem_acquire(ld->shadow_data_pool,
+ sizeof(LineartElementLinkNode));
+ veln->pointer = lineart_mem_acquire(ld->shadow_data_pool, sizeof(LineartVert) * edge_alloc * 2);
+ eeln->pointer = lineart_mem_acquire(ld->shadow_data_pool, sizeof(LineartEdge) * edge_alloc);
+ LineartEdgeSegment *es = lineart_mem_acquire(ld->shadow_data_pool,
+ sizeof(LineartEdgeSegment) * edge_alloc);
+ *r_veln = veln;
+ *r_eeln = eeln;
+
+ veln->element_count = edge_alloc * 2;
+ eeln->element_count = edge_alloc;
+
+ LineartVert *vlist = veln->pointer;
+ LineartEdge *elist = eeln->pointer;
+
+ int ei = 0;
+ for (int i = 0; i < ld->shadow_edges_count; i++) {
+ LineartShadowEdge *sedge = &ld->shadow_edges[i];
+ LISTBASE_FOREACH (LineartShadowSegment *, sseg, &sedge->shadow_segments) {
+ if (!(sseg->flag & LRT_SHADOW_CASTED)) {
+ continue;
+ }
+ if (!sseg->next) {
+ break;
+ }
+ LineartEdge *e = &elist[ei];
+ BLI_addtail(&e->segments, &es[ei]);
+ LineartVert *v1 = &vlist[ei * 2], *v2 = &vlist[ei * 2 + 1];
+ copy_v3_v3_db(v1->gloc, sseg->g2);
+ copy_v3_v3_db(v2->gloc, ((LineartShadowSegment *)sseg->next)->g1);
+ e->v1 = v1;
+ e->v2 = v2;
+ e->t1 = (LineartTriangle *)sedge->e_ref; /* See LineartEdge::t1 for usage. */
+ e->t2 = (LineartTriangle *)(sedge->e_ref_light_contour ? sedge->e_ref_light_contour :
+ sedge->e_ref);
+ e->target_reference = sseg->target_reference;
+ e->edge_identifier = sedge->e_ref->edge_identifier;
+ e->flags = (LRT_EDGE_FLAG_PROJECTED_SHADOW |
+ ((sseg->flag & LRT_SHADOW_FACING_LIGHT) ? LRT_EDGE_FLAG_SHADOW_FACING_LIGHT :
+ 0));
+ ei++;
+ }
+ if (do_original_edges) {
+ /* Occlusion-corrected light contour. */
+ LineartEdge *e = &elist[ei];
+ BLI_addtail(&e->segments, &es[ei]);
+ LineartVert *v1 = &vlist[ei * 2], *v2 = &vlist[ei * 2 + 1];
+ v1->index = sedge->e_ref->v1->index;
+ v2->index = sedge->e_ref->v2->index;
+ copy_v3_v3_db(v1->gloc, sedge->g1);
+ copy_v3_v3_db(v2->gloc, sedge->g2);
+ uint64_t ref_1 = sedge->e_ref->t1 ? sedge->e_ref->t1->target_reference : 0;
+ uint64_t ref_2 = sedge->e_ref->t2 ? sedge->e_ref->t2->target_reference : 0;
+ e->edge_identifier = sedge->e_ref->edge_identifier;
+ e->target_reference = ((ref_1 << 32) | ref_2);
+ e->v1 = v1;
+ e->v2 = v2;
+ e->t1 = e->t2 = (LineartTriangle *)sedge->e_ref;
+ e->flags = LRT_EDGE_FLAG_LIGHT_CONTOUR;
+ if (lineart_contour_viewed_from_dark_side(ld, sedge->e_ref)) {
+ lineart_edge_cut(ld, e, 0.0f, 1.0f, 0, 0, LRT_SHADOW_MASK_SHADED);
+ }
+ ei++;
+ }
+ }
+ return true;
+}
+
+static void lineart_shadow_register_silhouette(LineartData *ld)
+{
+ /* Keeping it single threaded for now because a simple parallel_for could end up getting the same
+ * #sedge->e_ref in different threads. */
+ for (int i = 0; i < ld->shadow_edges_count; i++) {
+ LineartShadowEdge *sedge = &ld->shadow_edges[i];
+
+ LineartEdge *e = sedge->e_ref;
+ LineartEdgeSegment *es = sedge->es_ref;
+ double es_start = es->ratio, es_end = es->next ? es->next->ratio : 1.0f;
+ LISTBASE_FOREACH (LineartShadowSegment *, sseg, &sedge->shadow_segments) {
+ if (!(sseg->flag & LRT_SHADOW_CASTED)) {
+ continue;
+ }
+ if (!sseg->next) {
+ break;
+ }
+
+ uint32_t silhouette_flags = (sseg->target_reference & LRT_OBINDEX_HIGHER) |
+ LRT_SHADOW_SILHOUETTE_ERASED_GROUP;
+
+ double at_start = interpd(es_end, es_start, sseg->ratio);
+ double at_end = interpd(es_end, es_start, sseg->next->ratio);
+ lineart_edge_cut(ld, e, at_start, at_end, 0, 0, silhouette_flags);
+ }
+ }
+}
+
+/* To achieve enclosed shape effect, we need to:
+ * 1) Show shaded segments against lit background.
+ * 2) Erase lit segments against lit background. */
+static void lineart_shadow_register_enclosed_shapes(LineartData *ld, LineartData *shadow_ld)
+{
+ LineartEdge *e;
+ LineartEdgeSegment *es;
+ for (int i = 0; i < shadow_ld->pending_edges.next; i++) {
+ e = shadow_ld->pending_edges.array[i];
+
+ /* Only care about shade-on-light and light-on-light situations, hence we only need
+ * non-occluded segments in shadow buffer. */
+ if (e->min_occ > 0) {
+ continue;
+ }
+ for (es = e->segments.first; es; es = es->next) {
+ if (es->occlusion > 0) {
+ continue;
+ }
+ double next_at = es->next ? ((LineartEdgeSegment *)es->next)->ratio : 1.0f;
+ LineartEdge *orig_e = (LineartEdge *)e->t2;
+
+ /* Shadow view space to global. */
+ double ga1 = e->v1->fbcoord[3] * es->ratio /
+ (es->ratio * e->v1->fbcoord[3] + (1 - es->ratio) * e->v2->fbcoord[3]);
+ double ga2 = e->v1->fbcoord[3] * next_at /
+ (next_at * e->v1->fbcoord[3] + (1 - next_at) * e->v2->fbcoord[3]);
+ double g1[3], g2[3], g1v[4], g2v[4];
+ interp_v3_v3v3_db(g1, e->v1->gloc, e->v2->gloc, ga1);
+ interp_v3_v3v3_db(g2, e->v1->gloc, e->v2->gloc, ga2);
+ mul_v4_m4v3_db(g1v, ld->conf.view_projection, g1);
+ mul_v4_m4v3_db(g2v, ld->conf.view_projection, g2);
+
+ if (ld->conf.cam_is_persp) {
+ mul_v3db_db(g1v, (1 / g1v[3]));
+ mul_v3db_db(g2v, (1 / g2v[3]));
+ }
+
+ g1v[0] -= ld->conf.shift_x * 2;
+ g1v[1] -= ld->conf.shift_y * 2;
+ g2v[0] -= ld->conf.shift_x * 2;
+ g2v[1] -= ld->conf.shift_y * 2;
+
+#define GET_RATIO(n) \
+ (fabs(orig_e->v2->fbcoord[0] - orig_e->v1->fbcoord[0]) > \
+ fabs(orig_e->v2->fbcoord[1] - orig_e->v1->fbcoord[1])) ? \
+ ((g##n##v[0] - orig_e->v1->fbcoord[0]) / \
+ (orig_e->v2->fbcoord[0] - orig_e->v1->fbcoord[0])) : \
+ ((g##n##v[1] - orig_e->v1->fbcoord[1]) / (orig_e->v2->fbcoord[1] - orig_e->v1->fbcoord[1]))
+ double la1, la2;
+ la1 = GET_RATIO(1);
+ la2 = GET_RATIO(2);
+#undef GET_RATIO
+
+ lineart_edge_cut(ld, orig_e, la1, la2, 0, 0, LRT_SHADOW_MASK_ENCLOSED_SHAPE);
+ }
+ }
+}
+
+/* This call would internally duplicate #original_ld, override necessary configurations for shadow
+ * computations. It will return:
+ *
+ * 1) Generated shadow edges in format of `LineartElementLinkNode` which can be directly loaded
+ * into later main view camera occlusion stage.
+ * 2) Shadow render buffer if 3rd stage reprojection is need for silhouette/lit/shaded region
+ * selection. Otherwise the shadow render buffer is deleted before this function returns.
+ */
+bool lineart_main_try_generate_shadow(Depsgraph *depsgraph,
+ Scene *scene,
+ LineartData *original_ld,
+ LineartGpencilModifierData *lmd,
+ LineartStaticMemPool *shadow_data_pool,
+ LineartElementLinkNode **r_veln,
+ LineartElementLinkNode **r_eeln,
+ ListBase *r_calculated_edges_eln_list,
+ LineartData **r_shadow_ld_if_reproject)
+{
+ if ((!original_ld->conf.use_shadow && !original_ld->conf.use_light_contour &&
+ !original_ld->conf.shadow_selection) ||
+ (!lmd->light_contour_object)) {
+ return false;
+ }
+
+ double t_start;
+ if (G.debug_value == 4000) {
+ t_start = PIL_check_seconds_timer();
+ }
+
+ bool is_persp = true;
+
+ if (lmd->light_contour_object->type == OB_LAMP) {
+ Light *la = (Light *)lmd->light_contour_object->data;
+ if (la->type == LA_SUN) {
+ is_persp = false;
+ }
+ }
+
+ LineartData *ld = MEM_callocN(sizeof(LineartData), "LineArt render buffer copied");
+ memcpy(ld, original_ld, sizeof(LineartData));
+
+ BLI_spin_init(&ld->lock_task);
+ BLI_spin_init(&ld->lock_cuts);
+ BLI_spin_init(&ld->render_data_pool.lock_mem);
+
+ ld->conf.do_shadow_cast = true;
+ ld->shadow_data_pool = shadow_data_pool;
+
+ /* See LineartData::edge_data_pool for explanation. */
+ if (ld->conf.shadow_selection) {
+ ld->edge_data_pool = shadow_data_pool;
+ }
+ else {
+ ld->edge_data_pool = &ld->render_data_pool;
+ }
+
+ copy_v3_v3_db(ld->conf.camera_pos_secondary, ld->conf.camera_pos);
+ copy_m4_m4(ld->conf.cam_obmat_secondary, ld->conf.cam_obmat);
+
+ copy_m4_m4(ld->conf.cam_obmat, lmd->light_contour_object->obmat);
+ copy_v3db_v3fl(ld->conf.camera_pos, ld->conf.cam_obmat[3]);
+ ld->conf.cam_is_persp_secondary = ld->conf.cam_is_persp;
+ ld->conf.cam_is_persp = is_persp;
+ ld->conf.near_clip = is_persp ? lmd->shadow_camera_near : -lmd->shadow_camera_far;
+ ld->conf.far_clip = lmd->shadow_camera_far;
+ ld->w = lmd->shadow_camera_size;
+ ld->h = lmd->shadow_camera_size;
+ /* Need to prevent wrong camera configuration so that shadow computation won't stall. */
+ if (!ld->w || !ld->h) {
+ ld->w = ld->h = 200;
+ }
+ if (!ld->conf.near_clip || !ld->conf.far_clip) {
+ ld->conf.near_clip = 0.1f;
+ ld->conf.far_clip = 200.0f;
+ }
+ ld->qtree.recursive_level = is_persp ? LRT_TILE_RECURSIVE_PERSPECTIVE : LRT_TILE_RECURSIVE_ORTHO;
+
+ /* Contour and loose edge from light viewing direction will be cast as shadow, so only
+ * force them on. If we need lit/shaded information for other line types, they are then
+ * enabled as-is so that cutting positions can also be calculated through shadow projection.
+ */
+ if (!ld->conf.shadow_selection) {
+ ld->conf.use_crease = ld->conf.use_material = ld->conf.use_edge_marks =
+ ld->conf.use_intersections = ld->conf.use_light_contour = false;
+ }
+ else {
+ ld->conf.use_contour_secondary = true;
+ ld->conf.allow_duplicated_types = true;
+ }
+ ld->conf.use_loose = true;
+ ld->conf.use_contour = true;
+
+ ld->conf.max_occlusion_level = 0; /* No point getting see-through projections there. */
+ ld->conf.use_back_face_culling = false;
+
+ /* Override matrices to light "camera". */
+ double proj[4][4], view[4][4], result[4][4];
+ float inv[4][4];
+ if (is_persp) {
+ lineart_matrix_perspective_44d(proj, DEG2RAD(160), 1, ld->conf.near_clip, ld->conf.far_clip);
+ }
+ else {
+ lineart_matrix_ortho_44d(
+ proj, -ld->w, ld->w, -ld->h, ld->h, ld->conf.near_clip, ld->conf.far_clip);
+ }
+ invert_m4_m4(inv, ld->conf.cam_obmat);
+ mul_m4db_m4db_m4fl_uniq(result, proj, inv);
+ copy_m4_m4_db(proj, result);
+ copy_m4_m4_db(ld->conf.view_projection, proj);
+ unit_m4_db(view);
+ copy_m4_m4_db(ld->conf.view, view);
+
+ lineart_main_get_view_vector(ld);
+
+ lineart_main_load_geometries(
+ depsgraph, scene, NULL, ld, lmd->flags & LRT_ALLOW_DUPLI_OBJECTS, true, NULL);
+
+ if (!ld->geom.vertex_buffer_pointers.first) {
+ /* No geometry loaded, return early. */
+ lineart_destroy_render_data_keep_init(ld);
+ MEM_freeN(ld);
+ return false;
+ }
+
+ /* The exact same process as in MOD_lineart_compute_feature_lines() until occlusion finishes.
+ */
+
+ lineart_main_bounding_area_make_initial(ld);
+ lineart_main_cull_triangles(ld, false);
+ lineart_main_cull_triangles(ld, true);
+ lineart_main_free_adjacent_data(ld);
+ lineart_main_perspective_division(ld);
+ lineart_main_discard_out_of_frame_edges(ld);
+ lineart_main_add_triangles(ld);
+ lineart_main_bounding_areas_connect_post(ld);
+ lineart_main_link_lines(ld);
+ lineart_main_occlusion_begin(ld);
+
+ /* Do shadow cast stuff then get generated vert/edge data. */
+ lineart_shadow_cast(ld, true, false);
+ bool any_generated = lineart_shadow_cast_generate_edges(ld, true, r_veln, r_eeln);
+
+ if (ld->conf.shadow_selection) {
+ memcpy(r_calculated_edges_eln_list, &ld->geom.line_buffer_pointers, sizeof(ListBase));
+ }
+
+ if (ld->conf.shadow_enclose_shapes) {
+ /* Need loaded data for re-projecting the 3rd time to get shape boundary against lit/shaded
+ * region. */
+ (*r_shadow_ld_if_reproject) = ld;
+ }
+ else {
+ lineart_destroy_render_data_keep_init(ld);
+ MEM_freeN(ld);
+ }
+
+ if (G.debug_value == 4000) {
+ double t_elapsed = PIL_check_seconds_timer() - t_start;
+ printf("Line art shadow stage 1 time: %f\n", t_elapsed);
+ }
+
+ return any_generated;
+}
+
+typedef struct LineartShadowFinalizeData {
+ LineartData *ld;
+ LineartVert *v;
+ LineartEdge *e;
+} LineartShadowFinalizeData;
+
+static void lineart_shadow_transform_task(void *__restrict userdata,
+ const int element_index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ LineartShadowFinalizeData *data = (LineartShadowFinalizeData *)userdata;
+ LineartData *ld = data->ld;
+ LineartVert *v = &data->v[element_index];
+ mul_v4_m4v3_db(v->fbcoord, ld->conf.view_projection, v->gloc);
+}
+
+static void lineart_shadow_finalize_shadow_edges_task(
+ void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ LineartShadowFinalizeData *data = (LineartShadowFinalizeData *)userdata;
+ LineartData *ld = data->ld;
+ LineartEdge *e = data->e;
+
+ if (e[i].flags & LRT_EDGE_FLAG_LIGHT_CONTOUR) {
+ LineartElementLinkNode *eln = lineart_find_matching_eln(
+ &ld->geom.vertex_buffer_pointers, e[i].edge_identifier & LRT_OBINDEX_HIGHER);
+ if (eln) {
+ int v1i = (((e[i].edge_identifier) >> 32) & LRT_OBINDEX_LOWER);
+ int v2i = (e[i].edge_identifier & LRT_OBINDEX_LOWER);
+ LineartVert *v = (LineartVert *)eln->pointer;
+ /* If the global position is close enough, use the original vertex to prevent flickering
+ * caused by very slim boundary condition in point_triangle_relation().*/
+ if (LRT_CLOSE_LOOSER_v3(e[i].v1->gloc, v[v1i].gloc)) {
+ e[i].v1 = &v[v1i];
+ }
+ if (LRT_CLOSE_LOOSER_v3(e[i].v2->gloc, v[v2i].gloc)) {
+ e[i].v2 = &v[v2i];
+ }
+ }
+ }
+}
+
+/* Shadow segments needs to be transformed to view-camera space, just like any other objects.
+ */
+void lineart_main_transform_and_add_shadow(LineartData *ld,
+ LineartElementLinkNode *veln,
+ LineartElementLinkNode *eeln)
+{
+
+ TaskParallelSettings transform_settings;
+ BLI_parallel_range_settings_defaults(&transform_settings);
+ /* Set the minimum amount of edges a thread has to process. */
+ transform_settings.min_iter_per_thread = 8192;
+
+ LineartShadowFinalizeData data = {0};
+ data.ld = ld;
+ data.v = (LineartVert *)veln->pointer;
+ data.e = (LineartEdge *)eeln->pointer;
+
+ BLI_task_parallel_range(
+ 0, veln->element_count, &data, lineart_shadow_transform_task, &transform_settings);
+ BLI_task_parallel_range(0,
+ eeln->element_count,
+ &data,
+ lineart_shadow_finalize_shadow_edges_task,
+ &transform_settings);
+ for (int i = 0; i < eeln->element_count; i++) {
+ lineart_add_edge_to_array(&ld->pending_edges, &data.e[i]);
+ }
+
+ BLI_addtail(&ld->geom.vertex_buffer_pointers, veln);
+ BLI_addtail(&ld->geom.line_buffer_pointers, eeln);
+}
+
+/* Does the 3rd stage reprojection, will not re-load objects because #shadow_ld is not deleted.
+ * Only re-projects view camera edges and check visibility in light camera, then we can determine
+ * whether an edge landed on a lit or shaded area. */
+void lineart_main_make_enclosed_shapes(LineartData *ld, LineartData *shadow_ld)
+{
+ double t_start;
+ if (G.debug_value == 4000) {
+ t_start = PIL_check_seconds_timer();
+ }
+
+ if (shadow_ld || ld->conf.shadow_use_silhouette) {
+ lineart_shadow_cast(ld, false, shadow_ld ? true : false);
+ if (ld->conf.shadow_use_silhouette) {
+ lineart_shadow_register_silhouette(ld);
+ }
+ }
+
+ if (G.debug_value == 4000) {
+ double t_elapsed = PIL_check_seconds_timer() - t_start;
+ printf("Line art shadow stage 2 cast and silhouette time: %f\n", t_elapsed);
+ }
+
+ if (!shadow_ld) {
+ return;
+ }
+
+ ld->shadow_data_pool = &ld->render_data_pool;
+
+ if (shadow_ld->pending_edges.array) {
+ MEM_freeN(shadow_ld->pending_edges.array);
+ shadow_ld->pending_edges.array = NULL;
+ shadow_ld->pending_edges.next = shadow_ld->pending_edges.max = 0;
+ }
+
+ LineartElementLinkNode *shadow_veln, *shadow_eeln;
+
+ bool any_generated = lineart_shadow_cast_generate_edges(ld, false, &shadow_veln, &shadow_eeln);
+
+ if (!any_generated) {
+ return;
+ }
+
+ LineartVert *v = shadow_veln->pointer;
+ for (int i = 0; i < shadow_veln->element_count; i++) {
+ mul_v4_m4v3_db(v[i].fbcoord, shadow_ld->conf.view_projection, v[i].gloc);
+ if (shadow_ld->conf.cam_is_persp) {
+ mul_v3db_db(v[i].fbcoord, (1 / v[i].fbcoord[3]));
+ }
+ }
+
+ lineart_finalize_object_edge_array_reserve(&shadow_ld->pending_edges,
+ shadow_eeln->element_count);
+
+ LineartEdge *se = shadow_eeln->pointer;
+ for (int i = 0; i < shadow_eeln->element_count; i++) {
+ lineart_add_edge_to_array(&shadow_ld->pending_edges, &se[i]);
+ }
+
+ shadow_ld->scheduled_count = 0;
+
+ lineart_main_clear_linked_edges(shadow_ld);
+ lineart_main_link_lines(shadow_ld);
+ lineart_main_occlusion_begin(shadow_ld);
+
+ lineart_shadow_register_enclosed_shapes(ld, shadow_ld);
+
+ if (G.debug_value == 4000) {
+ double t_elapsed = PIL_check_seconds_timer() - t_start;
+ printf("Line art shadow stage 2 total time: %f\n", t_elapsed);
+ }
+}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
index 4ea17b25995..95647f2dd75 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
@@ -144,13 +144,6 @@ void lineart_mem_destroy(LineartStaticMemPool *smp)
}
}
-void lineart_prepend_edge_direct(void **list_head, void *node)
-{
- LineartEdge *e_n = (LineartEdge *)node;
- e_n->next = (*list_head);
- (*list_head) = e_n;
-}
-
void lineart_prepend_pool(LinkNode **first, LineartStaticMemPool *smp, void *link)
{
LinkNode *ln = lineart_mem_acquire_thread(smp, sizeof(LinkNode));
@@ -212,13 +205,13 @@ void lineart_matrix_ortho_44d(double (*mProjection)[4],
mProjection[3][3] = 1.0f;
}
-void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
+void lineart_count_and_print_render_buffer_memory(LineartData *ld)
{
size_t total = 0;
size_t sum_this = 0;
size_t count_this = 0;
- LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &rb->render_data_pool.pools) {
+ LISTBASE_FOREACH (LineartStaticMemPoolNode *, smpn, &ld->render_data_pool.pools) {
count_this++;
sum_this += LRT_MEMORY_POOL_1MB;
}
@@ -227,7 +220,7 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
sum_this = 0;
count_this = 0;
- LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->line_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &ld->geom.line_buffer_pointers) {
count_this++;
sum_this += reln->element_count * sizeof(LineartEdge);
}
@@ -236,9 +229,9 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
sum_this = 0;
count_this = 0;
- LISTBASE_FOREACH (LineartElementLinkNode *, reln, &rb->triangle_buffer_pointers) {
+ LISTBASE_FOREACH (LineartElementLinkNode *, reln, &ld->geom.triangle_buffer_pointers) {
count_this++;
- sum_this += reln->element_count * rb->triangle_size;
+ sum_this += reln->element_count * ld->sizeof_triangle;
}
printf(" allocated %zu triangle blocks, total %zu Bytes.\n", count_this, sum_this);
total += sum_this;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index e78c86ae196..5e97909a2b8 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -5,7 +5,7 @@
# to more easily highlight code-paths in other libraries that need to be refactored,
# bf_gpu is allowed to have opengl regardless of this option.
-if(NOT WITH_OPENGL AND NOT WITH_METAL_BACKEND)
+if(NOT WITH_OPENGL AND NOT WITH_METAL_BACKEND AND NOT WITH_HEADLESS)
add_definitions(-DWITH_OPENGL)
endif()
@@ -21,13 +21,15 @@ set(INC
../imbuf
../makesdna
../makesrna
- ../windowmanager
+ # For theme color access.
../editors/include
- # For node muting stuff...
+ # For *_info.hh includes.
+ ../draw/engines/eevee_next
+
+ # For node muting stuff.
../nodes
- ../nodes/intern
../../../intern/atomic
../../../intern/clog
@@ -189,18 +191,27 @@ set(OPENGL_SRC
set(METAL_SRC
metal/mtl_backend.mm
metal/mtl_context.mm
+ metal/mtl_command_buffer.mm
metal/mtl_debug.mm
+ metal/mtl_framebuffer.mm
+ metal/mtl_memory.mm
+ metal/mtl_query.mm
metal/mtl_state.mm
metal/mtl_texture.mm
metal/mtl_texture_util.mm
+ metal/mtl_uniform_buffer.mm
metal/mtl_backend.hh
metal/mtl_capabilities.hh
metal/mtl_common.hh
metal/mtl_context.hh
metal/mtl_debug.hh
+ metal/mtl_framebuffer.hh
+ metal/mtl_memory.hh
+ metal/mtl_query.hh
metal/mtl_state.hh
metal/mtl_texture.hh
+ metal/mtl_uniform_buffer.hh
)
# Select Backend source based on availability
@@ -443,22 +454,24 @@ list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
set(SRC_SHADER_CREATE_INFOS
../draw/engines/basic/shaders/infos/basic_depth_info.hh
+ ../draw/engines/eevee_next/shaders/infos/eevee_film_info.hh
../draw/engines/eevee_next/shaders/infos/eevee_material_info.hh
../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh
../draw/engines/gpencil/shaders/infos/gpencil_info.hh
../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh
- ../draw/engines/overlay/shaders/infos/antialiasing_info.hh
- ../draw/engines/overlay/shaders/infos/armature_info.hh
- ../draw/engines/overlay/shaders/infos/background_info.hh
- ../draw/engines/overlay/shaders/infos/edit_mode_info.hh
- ../draw/engines/overlay/shaders/infos/extra_info.hh
- ../draw/engines/overlay/shaders/infos/facing_info.hh
- ../draw/engines/overlay/shaders/infos/grid_info.hh
- ../draw/engines/overlay/shaders/infos/outline_info.hh
- ../draw/engines/overlay/shaders/infos/paint_info.hh
- ../draw/engines/overlay/shaders/infos/sculpt_info.hh
- ../draw/engines/overlay/shaders/infos/volume_info.hh
- ../draw/engines/overlay/shaders/infos/wireframe_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_antialiasing_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_armature_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_background_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_edit_mode_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_extra_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_facing_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_grid_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_outline_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_paint_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_sculpt_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_sculpt_curves_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_volume_info.hh
+ ../draw/engines/overlay/shaders/infos/overlay_wireframe_info.hh
../draw/engines/select/shaders/infos/select_id_info.hh
../draw/engines/workbench/shaders/infos/workbench_composite_info.hh
../draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
@@ -552,7 +565,7 @@ endif()
-if(WITH_GPU_SHADER_BUILDER)
+if(WITH_GPU_BUILDTIME_SHADER_BUILDER)
# TODO(@fclem) Fix this mess.
if(APPLE)
add_executable(shader_builder
@@ -561,11 +574,7 @@ if(WITH_GPU_SHADER_BUILDER)
)
setup_platform_linker_flags(shader_builder)
-
- target_link_libraries(shader_builder PUBLIC
- bf_blenkernel
- buildinfoobj
- )
+ target_link_libraries(shader_builder PUBLIC buildinfoobj)
else()
if(WIN32)
# We can re-use the manifest from tests.exe here since it's
@@ -580,12 +589,14 @@ if(WITH_GPU_SHADER_BUILDER)
${MANIFEST}
)
- target_link_libraries(shader_builder PUBLIC
- bf_blenkernel
- ${PLATFORM_LINKLIBS}
- )
endif()
-
+ target_link_libraries(shader_builder PUBLIC
+ bf_gpu
+ bf_intern_clog
+ bf_blenlib
+ bf_intern_ghost
+ ${PLATFORM_LINKLIBS}
+ )
target_include_directories(shader_builder PRIVATE ${INC} ${CMAKE_CURRENT_BINARY_DIR})
set(SRC_BAKED_CREATE_INFOS_FILE ${CMAKE_CURRENT_BINARY_DIR}/shader_baked.hh)
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 1af0080baef..89473ac0fe0 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -10,6 +10,7 @@
#include <stddef.h>
#include "BKE_attribute.h"
+#include "BKE_pbvh.h"
#ifdef __cplusplus
extern "C" {
@@ -20,6 +21,7 @@ struct CCGElem;
struct CCGKey;
struct DMFlagMat;
struct GSet;
+struct TableGSet;
struct MLoop;
struct MLoopCol;
struct MLoopTri;
@@ -29,6 +31,9 @@ struct MVert;
struct Mesh;
struct PBVH;
struct SubdivCCG;
+struct CustomData;
+
+typedef struct PBVHGPUFormat PBVHGPUFormat;
/**
* Buffers for drawing from PBVH grids.
@@ -53,7 +58,9 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const struct MPoly *mpoly,
/**
* Threaded: do not call any functions that use OpenGL calls!
*/
-GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, unsigned int **grid_hidden);
+GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid,
+ unsigned int **grid_hidden,
+ bool smooth);
/**
* Threaded: do not call any functions that use OpenGL calls!
@@ -78,36 +85,46 @@ enum {
};
/**
+ * 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_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
- const float (*vert_normals)[3],
+ const CustomData *vdata,
+ const CustomData *ldata,
const float *vmask,
- const void *vcol_data,
- int vcol_type,
- AttributeDomain vcol_domain,
const int *sculpt_face_sets,
- int face_sets_color_seed,
- int face_sets_color_default,
- int update_flags);
+ const int face_sets_color_seed,
+ const int face_sets_color_default,
+ const int update_flags,
+ const float (*vert_normals)[3]);
+
+bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
+ PBVHGPUFormat *vbo_id,
+ const struct CustomData *vdata,
+ const struct CustomData *ldata,
+ bool active_attrs_only);
/**
* 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,
+void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id,
+ struct GPU_PBVH_Buffers *buffers,
struct BMesh *bm,
struct GSet *bm_faces,
struct GSet *bm_unique_verts,
struct GSet *bm_other_verts,
- int update_flags);
+ const int update_flags);
/**
* Threaded: do not call any functions that use OpenGL calls!
*/
-void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
struct SubdivCCG *subdiv_ccg,
struct CCGElem **grids,
const struct DMFlagMat *grid_flag_mats,
@@ -120,7 +137,8 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
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);
@@ -133,9 +151,11 @@ void GPU_pbvh_buffers_free(GPU_PBVH_Buffers *buffers);
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);
-
bool GPU_pbvh_buffers_has_overlays(GPU_PBVH_Buffers *buffers);
+PBVHGPUFormat *GPU_pbvh_make_format(void);
+void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_common_types.h b/source/blender/gpu/GPU_common_types.h
index 8c91d60812f..13535a4fb3b 100644
--- a/source/blender/gpu/GPU_common_types.h
+++ b/source/blender/gpu/GPU_common_types.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
/** \file
* \ingroup gpu
*/
@@ -8,6 +10,14 @@
extern "C" {
#endif
+typedef enum eGPULoadOp {
+ GPU_LOADACTION_CLEAR = 0,
+ GPU_LOADACTION_LOAD,
+ GPU_LOADACTION_DONT_CARE
+} eGPULoadOp;
+
+typedef enum eGPUStoreOp { GPU_STOREACTION_STORE = 0, GPU_STOREACTION_DONT_CARE } eGPUStoreOp;
+
typedef enum eGPUFrontFace {
GPU_CLOCKWISE,
GPU_COUNTERCLOCKWISE,
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index f3b7f8c29bf..9d92ea2cad9 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -17,10 +17,10 @@
extern "C" {
#endif
-void GPU_backend_init(eGPUBackendType backend);
-void GPU_backend_exit(void);
-bool GPU_backend_supported(eGPUBackendType type);
-
+/* GPU backends abstract the differences between different APIs. GPU_context_create
+ * automatically initializes the backend, and GPU_context_discard frees it when there
+ * are no more contexts. */
+bool GPU_backend_supported(void);
eGPUBackendType GPU_backend_get_type(void);
/** Opaque type hiding blender::gpu::Context. */
@@ -38,6 +38,13 @@ void GPU_context_discard(GPUContext *);
void GPU_context_active_set(GPUContext *);
GPUContext *GPU_context_active_get(void);
+/* Begin and end frame are used to mark the singular boundary representing the lifetime of a whole
+ * frame. This also acts as a divisor for ensuring workload submission and flushing, especially for
+ * background rendering when there is no call to present.
+ * This is required by explicit-API's where there is no implicit workload flushing. */
+void GPU_context_begin_frame(GPUContext *ctx);
+void GPU_context_end_frame(GPUContext *ctx);
+
/* Legacy GPU (Intel HD4000 series) do not support sharing GPU objects between GPU
* contexts. EEVEE/Workbench can create different contexts for image/preview rendering, baking or
* compiling. When a legacy GPU is detected (`GPU_use_main_context_workaround()`) any worker
diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h
index 4436f7a5a7b..70ec7c19e7c 100644
--- a/source/blender/gpu/GPU_framebuffer.h
+++ b/source/blender/gpu/GPU_framebuffer.h
@@ -14,6 +14,7 @@
#pragma once
+#include "GPU_common_types.h"
#include "GPU_texture.h"
typedef enum eGPUFrameBufferBits {
@@ -52,6 +53,44 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb);
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *fb);
void GPU_framebuffer_restore(void);
+/* Advanced binding control. */
+typedef struct GPULoadStore {
+ eGPULoadOp load_action;
+ eGPUStoreOp store_action;
+} GPULoadStore;
+#define NULL_LOAD_STORE \
+ { \
+ GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_DONT_CARE \
+ }
+
+/* Load store config array (load_store_actions) matches attachment structure of
+ * GPU_framebuffer_config_array. This allows us to explicitly specify whether attachment data needs
+ * to be loaded and stored on a per-attachment basis. This enables a number of bandwidth
+ * optimizations:
+ * - No need to load contents if subsequent work is over-writing every pixel.
+ * - No need to store attachments whose contents are not used beyond this pass e.g. depth buffer.
+ * - State can be customized at bind-time rather than applying to the frame-buffer object as a
+ * whole.
+ *
+ * Example:
+ * \code{.c}
+ * GPU_framebuffer_bind_loadstore(&fb, {
+ * {GPU_LOADACTION_LOAD, GPU_STOREACTION_DONT_CARE} // must be depth buffer
+ * {GPU_LOADACTION_LOAD, GPU_STOREACTION_STORE}, // Color attachment 0
+ * {GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_STORE}, // Color attachment 1
+ * {GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_STORE} // Color attachment 2
+ * })
+ * \encode
+ */
+void GPU_framebuffer_bind_loadstore(GPUFrameBuffer *fb,
+ const GPULoadStore *load_store_actions,
+ uint actions_len);
+#define GPU_framebuffer_bind_ex(_fb, ...) \
+ { \
+ GPULoadStore actions[] = __VA_ARGS__; \
+ GPU_framebuffer_bind_loadstore(_fb, actions, (sizeof(actions) / sizeof(GPULoadStore))); \
+ }
+
bool GPU_framebuffer_bound(GPUFrameBuffer *fb);
bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]);
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index fff90e6f8ff..c0633f0323d 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -7,7 +7,7 @@
#pragma once
-#include "DNA_customdata_types.h" /* for CustomDataType */
+#include "DNA_customdata_types.h" /* for eCustomDataType */
#include "DNA_image_types.h"
#include "DNA_listBase.h"
@@ -130,9 +130,9 @@ typedef void (*GPUCodegenCallbackFn)(void *thunk, GPUMaterial *mat, GPUCodegenOu
GPUNodeLink *GPU_constant(const float *num);
GPUNodeLink *GPU_uniform(const float *num);
-GPUNodeLink *GPU_attribute(GPUMaterial *mat, CustomDataType type, const char *name);
+GPUNodeLink *GPU_attribute(GPUMaterial *mat, eCustomDataType type, const char *name);
GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
- CustomDataType type,
+ eCustomDataType type,
const char *name,
eGPUDefaultValue default_value);
GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli);
@@ -259,7 +259,7 @@ void GPU_pass_cache_free(void);
typedef struct GPUMaterialAttribute {
struct GPUMaterialAttribute *next, *prev;
- int type; /* CustomDataType */
+ int type; /* eCustomDataType */
char name[64]; /* MAX_CUSTOMDATA_LAYER_NAME */
char input_name[12 + 1]; /* GPU_MAX_SAFE_ATTR_NAME + 1 */
eGPUType gputype;
diff --git a/source/blender/gpu/GPU_shader_shared_utils.h b/source/blender/gpu/GPU_shader_shared_utils.h
index 474549d1f42..88bdad2bf76 100644
--- a/source/blender/gpu/GPU_shader_shared_utils.h
+++ b/source/blender/gpu/GPU_shader_shared_utils.h
@@ -41,6 +41,7 @@
# define floorf floor
# define ceilf ceil
# define sqrtf sqrt
+# define expf exp
# define float2 vec2
# define float3 vec3
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index b045d908438..5bd20b7be98 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -113,7 +113,7 @@ typedef enum eGPUTextureFormat {
GPU_R16F,
GPU_R16, /* Max texture buffer format. */
- /* Special formats texture & renderbuffer */
+ /* Special formats texture & render-buffer. */
GPU_RGB10_A2,
GPU_R11F_G11F_B10F,
GPU_DEPTH32F_STENCIL8,
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index 6e07e6c3229..d2890efee72 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -30,6 +30,7 @@ class VertBuf;
class GPUBackend {
public:
virtual ~GPUBackend() = default;
+ virtual void delete_resources() = 0;
static GPUBackend *get();
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index 32b117dac12..1b34b6e6c69 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -14,7 +14,6 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
-#include "GPU_matrix.h"
#include "GPU_platform.h"
#include "GPU_shader.h"
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
index ab5e23a846c..4dff35c3633 100644
--- a/source/blender/gpu/intern/gpu_batch_presets.c
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -11,15 +11,8 @@
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
-#include "DNA_userdef_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
#include "GPU_batch.h"
-#include "GPU_batch_presets.h" /* own include */
-#include "GPU_batch_utils.h"
-#include "GPU_context.h"
+#include "GPU_batch_presets.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name Local Structures
@@ -139,7 +132,7 @@ GPUBatch *GPU_batch_preset_sphere_wire(int lod)
/** \name Create Sphere (3D)
* \{ */
-GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
+static GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
{
const float lon_inc = 2 * M_PI / lon_res;
const float lat_inc = M_PI / lat_res;
diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c
index 43a47aab945..10a05fe90b9 100644
--- a/source/blender/gpu/intern/gpu_batch_utils.c
+++ b/source/blender/gpu/intern/gpu_batch_utils.c
@@ -8,7 +8,6 @@
#include "BLI_math.h"
#include "BLI_polyfill_2d.h"
-#include "BLI_rect.h"
#include "BLI_sort_utils.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index fed998bb33e..14bbd82c282 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -9,20 +9,18 @@
#include <limits.h>
#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
-#include "BLI_hash.h"
-#include "BLI_math.h"
#include "BLI_math_color.h"
-#include "BLI_math_color_blend.h"
#include "BLI_utildefines.h"
+#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_userdef_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_attribute.h"
@@ -36,17 +34,12 @@
#include "GPU_batch.h"
#include "GPU_buffers.h"
+#include "DRW_engine.h"
+
#include "gpu_private.h"
#include "bmesh.h"
-/* 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;
@@ -88,10 +81,52 @@ struct GPU_PBVH_Buffers {
bool show_overlay;
};
-static struct {
+typedef struct GPUAttrRef {
+ uchar domain, type;
+ ushort cd_offset;
+ int layer_idx;
+} GPUAttrRef;
+
+#define MAX_GPU_ATTR 256
+
+typedef struct PBVHGPUFormat {
GPUVertFormat format;
- uint pos, nor, msk, col, fset;
-} g_vbo_id = {{0}};
+ uint pos, nor, msk, fset;
+ uint col[MAX_GPU_ATTR];
+ uint uv[MAX_GPU_ATTR];
+ int totcol, totuv;
+
+ /* Upload only the active color and UV attributes,
+ * used for workbench mode. */
+ bool active_attrs_only;
+} PBVHGPUFormat;
+
+PBVHGPUFormat *GPU_pbvh_make_format(void)
+{
+ PBVHGPUFormat *vbo_id = MEM_callocN(sizeof(PBVHGPUFormat), "PBVHGPUFormat");
+
+ GPU_pbvh_attribute_names_update(PBVH_FACES, vbo_id, NULL, NULL, false);
+
+ return vbo_id;
+}
+
+void GPU_pbvh_free_format(PBVHGPUFormat *vbo_id)
+{
+ MEM_SAFE_FREE(vbo_id);
+}
+
+static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
+ eCustomDataMask type_mask,
+ const CustomData *vdata,
+ const CustomData *edata,
+ const CustomData *ldata,
+ const CustomData *pdata,
+ GPUAttrRef r_cd_attrs[MAX_GPU_ATTR],
+ bool active_only,
+ int active_type,
+ int active_domain,
+ const CustomDataLayer *active_layer,
+ const CustomDataLayer *render_layer);
/** \} */
@@ -101,20 +136,6 @@ static struct {
void gpu_pbvh_init()
{
- /* Initialize vertex buffer (match 'VertexBufferFormat'). */
- if (g_vbo_id.format.attr_len == 0) {
- g_vbo_id.pos = GPU_vertformat_attr_add(
- &g_vbo_id.format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- g_vbo_id.nor = GPU_vertformat_attr_add(
- &g_vbo_id.format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
- g_vbo_id.msk = GPU_vertformat_attr_add(
- &g_vbo_id.format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.col = GPU_vertformat_attr_add(
- &g_vbo_id.format, "ac", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- g_vbo_id.fset = GPU_vertformat_attr_add(
- &g_vbo_id.format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
- }
}
void gpu_pbvh_exit()
@@ -122,33 +143,37 @@ void gpu_pbvh_exit()
/* Nothing to do. */
}
+static CustomDataLayer *get_active_layer(const CustomData *cdata, int type)
+{
+ int idx = CustomData_get_active_layer_index(cdata, type);
+ return idx != -1 ? cdata->layers + idx : NULL;
+}
+
+static CustomDataLayer *get_render_layer(const CustomData *cdata, int type)
+{
+ int idx = CustomData_get_render_layer_index(cdata, type);
+ return idx != -1 ? cdata->layers + idx : NULL;
+}
+
/* Allocates a non-initialized buffer to be sent to GPU.
* Return is false it indicates that the memory map failed. */
-static bool gpu_pbvh_vert_buf_data_set(GPU_PBVH_Buffers *buffers, uint vert_len)
+static bool gpu_pbvh_vert_buf_data_set(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
+ uint vert_len)
{
/* Keep so we can test #GPU_USAGE_DYNAMIC buffer use.
* Not that format initialization match in both blocks.
* Do this to keep braces balanced - otherwise indentation breaks. */
-#if 0
- if (buffers->vert_buf == NULL) {
- /* Initialize vertex buffer (match 'VertexBufferFormat'). */
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_DYNAMIC);
- GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
- }
- else if (vert_len != buffers->vert_buf->vertex_len) {
- GPU_vertbuf_data_resize(buffers->vert_buf, vert_len);
- }
-#else
+
if (buffers->vert_buf == NULL) {
/* Initialize vertex buffer (match 'VertexBufferFormat'). */
- buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&g_vbo_id.format, GPU_USAGE_STATIC);
+ buffers->vert_buf = GPU_vertbuf_create_with_format_ex(&vbo_id->format, GPU_USAGE_STATIC);
}
if (GPU_vertbuf_get_data(buffers->vert_buf) == NULL ||
GPU_vertbuf_get_vertex_len(buffers->vert_buf) != vert_len) {
/* Allocate buffer if not allocated yet or size changed. */
GPU_vertbuf_data_alloc(buffers->vert_buf, vert_len);
}
-#endif
return GPU_vertbuf_get_data(buffers->vert_buf) != NULL;
}
@@ -194,25 +219,62 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE);
}
-void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
const MVert *mvert,
- const float (*vert_normals)[3],
+ const CustomData *vdata,
+ const CustomData *ldata,
const float *vmask,
- const void *vcol_data,
- int vcol_type,
- AttributeDomain vcol_domain,
const int *sculpt_face_sets,
int face_sets_color_seed,
int face_sets_color_default,
- int update_flags)
+ int update_flags,
+ const float (*vert_normals)[3])
{
- const MPropCol *vtcol = vcol_type == CD_PROP_COLOR ? vcol_data : NULL;
- const MLoopCol *vcol = vcol_type == CD_PROP_BYTE_COLOR ? vcol_data : NULL;
- const float(*f3col)[3] = vcol_type == CD_PROP_FLOAT3 ? vcol_data : NULL;
+ GPUAttrRef vcol_refs[MAX_GPU_ATTR];
+ GPUAttrRef cd_uvs[MAX_GPU_ATTR];
+
+ Mesh me_query;
+ BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id);
+
+ CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&me_query.id);
+ eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&me_query.id, actcol) :
+ ATTR_DOMAIN_AUTO;
+
+ CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&me_query.id);
+
+ int totcol;
+
+ if (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) {
+ totcol = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR,
+ CD_MASK_COLOR_ALL,
+ vdata,
+ NULL,
+ ldata,
+ NULL,
+ vcol_refs,
+ vbo_id->active_attrs_only,
+ actcol ? actcol->type : 0,
+ actcol_domain,
+ actcol,
+ rendercol);
+ }
+ else {
+ totcol = 0;
+ }
- const bool color_loops = vcol_domain == ATTR_DOMAIN_CORNER;
- const bool show_vcol = (vtcol || vcol || f3col) &&
- (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) != 0;
+ int totuv = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER,
+ CD_MASK_MLOOPUV,
+ NULL,
+ NULL,
+ ldata,
+ NULL,
+ cd_uvs,
+ vbo_id->active_attrs_only,
+ CD_MLOOPUV,
+ ATTR_DOMAIN_CORNER,
+ get_active_layer(ldata, CD_MLOOPUV),
+ get_render_layer(ldata, CD_MLOOPUV));
const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_face_sets = sculpt_face_sets &&
@@ -224,25 +286,106 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int totelem = buffers->tot_tri * 3;
/* Build VBO */
- if (gpu_pbvh_vert_buf_data_set(buffers, totelem)) {
+ if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totelem)) {
GPUVertBufRaw pos_step = {0};
GPUVertBufRaw nor_step = {0};
GPUVertBufRaw msk_step = {0};
GPUVertBufRaw fset_step = {0};
GPUVertBufRaw col_step = {0};
+ GPUVertBufRaw uv_step = {0};
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.pos, &pos_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.nor, &nor_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.msk, &msk_step);
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.fset, &fset_step);
- if (show_vcol) {
- GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, g_vbo_id.col, &col_step);
- }
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->pos, &pos_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->nor, &nor_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->msk, &msk_step);
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->fset, &fset_step);
/* calculate normal for each polygon only once */
uint mpoly_prev = UINT_MAX;
short no[3] = {0, 0, 0};
+ if (totuv > 0) {
+ for (int uv_i = 0; uv_i < totuv; uv_i++) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->uv[uv_i], &uv_step);
+
+ GPUAttrRef *ref = cd_uvs + uv_i;
+ CustomDataLayer *layer = ldata->layers + ref->layer_idx;
+ MLoopUV *muv = layer->data;
+
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
+ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
+
+ if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ continue;
+ }
+
+ for (uint j = 0; j < 3; j++) {
+ MLoopUV *muv2 = muv + lt->tri[j];
+
+ memcpy(GPU_vertbuf_raw_step(&uv_step), muv2->uv, sizeof(muv2->uv));
+ }
+ }
+ }
+ }
+
+ for (int col_i = 0; col_i < totcol; col_i++) {
+ GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->col[col_i], &col_step);
+
+ MPropCol *pcol = NULL;
+ MLoopCol *mcol = NULL;
+
+ GPUAttrRef *ref = vcol_refs + col_i;
+ const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+ CustomDataLayer *layer = cdata->layers + ref->layer_idx;
+
+ bool color_loops = ref->domain == ATTR_DOMAIN_CORNER;
+
+ if (layer->type == CD_PROP_COLOR) {
+ pcol = (MPropCol *)layer->data;
+ }
+ else {
+ mcol = (MLoopCol *)layer->data;
+ }
+
+ for (uint i = 0; i < buffers->face_indices_len; i++) {
+ const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
+ const uint vtri[3] = {
+ buffers->mloop[lt->tri[0]].v,
+ buffers->mloop[lt->tri[1]].v,
+ buffers->mloop[lt->tri[2]].v,
+ };
+
+ if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ continue;
+ }
+
+ for (uint j = 0; j < 3; j++) {
+ /* Vertex Colors. */
+ const uint loop_index = lt->tri[j];
+
+ ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
+
+ if (pcol) {
+ MPropCol *pcol2 = pcol + (color_loops ? loop_index : vtri[j]);
+
+ scol[0] = unit_float_to_ushort_clamp(pcol2->color[0]);
+ scol[1] = unit_float_to_ushort_clamp(pcol2->color[1]);
+ scol[2] = unit_float_to_ushort_clamp(pcol2->color[2]);
+ scol[3] = unit_float_to_ushort_clamp(pcol2->color[3]);
+ }
+ else {
+ const MLoopCol *mcol2 = mcol + (color_loops ? loop_index : vtri[j]);
+
+ scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->r]);
+ scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->g]);
+ scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol2->b]);
+ scol[3] = unit_float_to_ushort_clamp(mcol2->a * (1.0f / 255.0f));
+ }
+
+ memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
+ }
+ }
+ }
+
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
const uint vtri[3] = {
@@ -296,50 +439,6 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
*(uchar *)GPU_vertbuf_raw_step(&msk_step) = cmask;
empty_mask = empty_mask && (cmask == 0);
- /* Vertex Colors. */
- if (show_vcol) {
- ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- if (vtcol) {
- if (color_loops) {
- scol[0] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[0]);
- scol[1] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[1]);
- scol[2] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[2]);
- scol[3] = unit_float_to_ushort_clamp(vtcol[lt->tri[j]].color[3]);
- }
- else {
- scol[0] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[0]);
- scol[1] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[1]);
- scol[2] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[2]);
- scol[3] = unit_float_to_ushort_clamp(vtcol[vtri[j]].color[3]);
- }
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- else if (f3col) {
- if (color_loops) {
- scol[0] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][0]);
- scol[1] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][1]);
- scol[2] = unit_float_to_ushort_clamp(f3col[lt->tri[j]][2]);
- scol[3] = USHRT_MAX;
- }
- else {
- scol[0] = unit_float_to_ushort_clamp(f3col[vtri[j]][0]);
- scol[1] = unit_float_to_ushort_clamp(f3col[vtri[j]][1]);
- scol[2] = unit_float_to_ushort_clamp(f3col[vtri[j]][2]);
- scol[3] = USHRT_MAX;
- }
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- else if (vcol) {
- const uint loop_index = lt->tri[j];
- const MLoopCol *mcol = vcol + (color_loops ? loop_index : vtri[j]);
-
- scol[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->r]);
- scol[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->g]);
- scol[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mcol->b]);
- scol[3] = unit_float_to_ushort_clamp(mcol->a * (1.0f / 255.0f));
- memcpy(GPU_vertbuf_raw_step(&col_step), scol, sizeof(scol));
- }
- }
/* Face Sets. */
memcpy(GPU_vertbuf_raw_step(&fset_step), face_set_color, sizeof(uchar[3]));
}
@@ -604,7 +703,8 @@ void GPU_pbvh_grid_buffers_update_free(GPU_PBVH_Buffers *buffers,
}
}
-void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
SubdivCCG *subdiv_ccg,
CCGElem **grids,
const struct DMFlagMat *grid_flag_mats,
@@ -628,8 +728,6 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
/* Build VBO */
const int has_mask = key->has_mask;
- buffers->smooth = grid_flag_mats[grid_indices[0]].flag & ME_SMOOTH;
-
uint vert_per_grid = (buffers->smooth) ? key->grid_area : (square_i(key->grid_size - 1) * 4);
uint vert_count = totgrid * vert_per_grid;
@@ -653,7 +751,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
uint vbo_index_offset = 0;
/* Build VBO */
- if (gpu_pbvh_vert_buf_data_set(buffers, vert_count)) {
+ if (gpu_pbvh_vert_buf_data_set(vbo_id, buffers, vert_count)) {
GPUIndexBufBuilder elb_lines;
if (buffers->index_lines_buf == NULL) {
@@ -683,25 +781,25 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
for (x = 0; x < key->grid_size; x++) {
CCGElem *elem = CCG_grid_elem(key, grid, x, y);
GPU_vertbuf_attr_set(
- buffers->vert_buf, g_vbo_id.pos, vbo_index, CCG_elem_co(key, elem));
+ buffers->vert_buf, vbo_id->pos, vbo_index, CCG_elem_co(key, elem));
short no_short[3];
normal_float_to_short_v3(no_short, CCG_elem_no(key, elem));
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index, no_short);
if (has_mask && show_mask) {
float fmask = *CCG_elem_mask(key, elem);
uchar cmask = (uchar)(fmask * 255);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index, &cmask);
empty_mask = empty_mask && (cmask == 0);
}
if (show_vcol) {
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index, &vcol);
}
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index, &face_set_color);
vbo_index += 1;
}
@@ -730,37 +828,37 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
normal_quad_v3(fno, co[3], co[2], co[1], co[0]);
normal_float_to_short_v3(no_short, fno);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 0, co[0]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 0, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 1, co[1]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 1, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 2, co[2]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 2, no_short);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.pos, vbo_index + 3, co[3]);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.nor, vbo_index + 3, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 0, co[0]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 0, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 1, co[1]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 1, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 2, co[2]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 2, no_short);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->pos, vbo_index + 3, co[3]);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->nor, vbo_index + 3, no_short);
if (has_mask && show_mask) {
float fmask = (*CCG_elem_mask(key, elems[0]) + *CCG_elem_mask(key, elems[1]) +
*CCG_elem_mask(key, elems[2]) + *CCG_elem_mask(key, elems[3])) *
0.25f;
uchar cmask = (uchar)(fmask * 255);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 0, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 1, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 2, &cmask);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.msk, vbo_index + 3, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 0, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 1, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 2, &cmask);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->msk, vbo_index + 3, &cmask);
empty_mask = empty_mask && (cmask == 0);
}
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 0, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 1, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 2, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col, vbo_index + 3, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 0, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 1, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 2, &vcol);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->col[0], vbo_index + 3, &vcol);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 0, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 1, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 2, &face_set_color);
- GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, vbo_index + 3, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 0, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 1, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 2, &face_set_color);
+ GPU_vertbuf_attr_set(buffers->vert_buf, vbo_id->fset, vbo_index + 3, &face_set_color);
vbo_index += 4;
}
@@ -783,13 +881,14 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->show_overlay = !empty_mask || !default_face_set;
}
-GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden)
+GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden, bool smooth)
{
GPU_PBVH_Buffers *buffers;
buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers");
buffers->grid_hidden = grid_hidden;
buffers->totgrid = totgrid;
+ buffers->smooth = smooth;
buffers->show_overlay = false;
@@ -805,7 +904,8 @@ GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hid
* \{ */
/* Output a BMVert into a VertexBufferFormat array at v_index. */
-static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
+static void gpu_bmesh_vert_to_buffer_copy(PBVHGPUFormat *vbo_id,
+ BMVert *v,
GPUVertBuf *vert_buf,
int v_index,
const float fno[3],
@@ -819,27 +919,27 @@ static void gpu_bmesh_vert_to_buffer_copy(BMVert *v,
BLI_assert(!BM_elem_flag_test(v, BM_ELEM_HIDDEN));
/* Set coord, normal, and mask */
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->pos, v_index, v->co);
short no_short[3];
normal_float_to_short_v3(no_short, fno ? fno : v->no);
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.nor, v_index, no_short);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->nor, v_index, no_short);
if (show_mask) {
float effective_mask = fmask ? *fmask : BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
uchar cmask = (uchar)(effective_mask * 255);
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.msk, v_index, &cmask);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->msk, v_index, &cmask);
*empty_mask = *empty_mask && (cmask == 0);
}
if (show_vcol) {
const ushort vcol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.col, v_index, &vcol);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->col[0], v_index, &vcol);
}
/* Add default face sets color to avoid artifacts. */
const uchar face_set[3] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
- GPU_vertbuf_attr_set(vert_buf, g_vbo_id.fset, v_index, &face_set);
+ GPU_vertbuf_attr_set(vert_buf, vbo_id->fset, v_index, &face_set);
}
/* Return the total number of vertices that don't have BM_ELEM_HIDDEN set */
@@ -896,7 +996,8 @@ void GPU_pbvh_bmesh_buffers_update_free(GPU_PBVH_Buffers *buffers)
}
}
-void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
+void GPU_pbvh_bmesh_buffers_update(PBVHGPUFormat *vbo_id,
+ GPU_PBVH_Buffers *buffers,
BMesh *bm,
GSet *bm_faces,
GSet *bm_unique_verts,
@@ -935,7 +1036,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
/* Fill vertex buffer */
- if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
+ if (!gpu_pbvh_vert_buf_data_set(vbo_id, buffers, totvert)) {
/* Memory map failed */
return;
}
@@ -965,7 +1066,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
/* Add vertex to the vertex buffer each time a new one is encountered */
*idx_p = POINTER_FROM_UINT(v_index);
- gpu_bmesh_vert_to_buffer_copy(v[i],
+ gpu_bmesh_vert_to_buffer_copy(vbo_id,
+ v[i],
buffers->vert_buf,
v_index,
NULL,
@@ -1032,7 +1134,8 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
for (i = 0; i < 3; i++) {
- gpu_bmesh_vert_to_buffer_copy(v[i],
+ gpu_bmesh_vert_to_buffer_copy(vbo_id,
+ v[i],
buffers->vert_buf,
v_index++,
f->no,
@@ -1075,6 +1178,250 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
return buffers;
}
+/**
+ * Builds a list of attributes from a set of domains and a set of
+ * customdata types.
+ *
+ * \param active_only: Returns only one item, a #GPUAttrRef to active_layer.
+ * \param active_layer: #CustomDataLayer to use for the active layer.
+ * \param active_layer: #CustomDataLayer to use for the render layer.
+ */
+static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
+ eCustomDataMask type_mask,
+ const CustomData *vdata,
+ const CustomData *edata,
+ const CustomData *ldata,
+ const CustomData *pdata,
+ GPUAttrRef r_cd_attrs[MAX_GPU_ATTR],
+ bool active_only,
+ int active_type,
+ int active_domain,
+ const CustomDataLayer *active_layer,
+ const CustomDataLayer *render_layer)
+{
+ const CustomData *cdata_active = active_domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+
+ if (!cdata_active) {
+ return 0;
+ }
+
+ if (active_only) {
+ int idx = active_layer ? active_layer - cdata_active->layers : -1;
+
+ if (idx >= 0 && idx < cdata_active->totlayer) {
+ r_cd_attrs[0].cd_offset = cdata_active->layers[idx].offset;
+ r_cd_attrs[0].domain = active_domain;
+ r_cd_attrs[0].type = active_type;
+ r_cd_attrs[0].layer_idx = idx;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ const CustomData *datas[4] = {vdata, edata, pdata, ldata};
+
+ int count = 0;
+ for (eAttrDomain domain = 0; domain < 4; domain++) {
+ const CustomData *cdata = datas[domain];
+
+ if (!cdata || !((1 << domain) & domain_mask)) {
+ continue;
+ }
+
+ CustomDataLayer *cl = cdata->layers;
+
+ for (int i = 0; count < MAX_GPU_ATTR && i < cdata->totlayer; i++, cl++) {
+ if ((CD_TYPE_AS_MASK(cl->type) & type_mask) && !(cl->flag & CD_FLAG_TEMPORARY)) {
+ GPUAttrRef *ref = r_cd_attrs + count;
+
+ ref->cd_offset = cl->offset;
+ ref->type = cl->type;
+ ref->layer_idx = i;
+ ref->domain = domain;
+
+ count++;
+ }
+ }
+ }
+
+ /* ensure render layer is last
+ draw cache code seems to need this
+ */
+
+ for (int i = 0; i < count; i++) {
+ GPUAttrRef *ref = r_cd_attrs + i;
+ const CustomData *cdata = datas[ref->domain];
+
+ if (cdata->layers + ref->layer_idx == render_layer) {
+ SWAP(GPUAttrRef, r_cd_attrs[i], r_cd_attrs[count - 1]);
+ break;
+ }
+ }
+
+ return count;
+}
+
+static bool gpu_pbvh_format_equals(PBVHGPUFormat *a, PBVHGPUFormat *b)
+{
+ bool bad = false;
+
+ bad |= a->active_attrs_only != b->active_attrs_only;
+
+ bad |= a->pos != b->pos;
+ bad |= a->fset != b->fset;
+ bad |= a->msk != b->msk;
+ bad |= a->nor != b->nor;
+
+ for (int i = 0; i < MIN2(a->totuv, b->totuv); i++) {
+ bad |= a->uv[i] != b->uv[i];
+ }
+
+ for (int i = 0; i < MIN2(a->totcol, b->totcol); i++) {
+ bad |= a->col[i] != b->col[i];
+ }
+
+ bad |= a->totuv != b->totuv;
+ bad |= a->totcol != b->totcol;
+
+ return !bad;
+}
+
+bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
+ PBVHGPUFormat *vbo_id,
+ const CustomData *vdata,
+ const CustomData *ldata,
+ bool active_attrs_only)
+{
+ const bool active_only = active_attrs_only;
+ PBVHGPUFormat old_format = *vbo_id;
+
+ GPU_vertformat_clear(&vbo_id->format);
+
+ vbo_id->active_attrs_only = active_attrs_only;
+
+ if (vbo_id->format.attr_len == 0) {
+ vbo_id->pos = GPU_vertformat_attr_add(
+ &vbo_id->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ vbo_id->nor = GPU_vertformat_attr_add(
+ &vbo_id->format, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ /* TODO: Do not allocate these `.msk` and `.col` when they are not used. */
+ vbo_id->msk = GPU_vertformat_attr_add(
+ &vbo_id->format, "msk", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ vbo_id->totcol = 0;
+ if (pbvh_type == PBVH_FACES) {
+ int ci = 0;
+
+ Mesh me_query;
+
+ BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id);
+
+ CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me_query.id);
+ CustomDataLayer *render_color_layer = BKE_id_attributes_render_color_get(&me_query.id);
+ eAttrDomain active_color_domain = active_color_layer ?
+ BKE_id_attribute_domain(&me_query.id,
+ active_color_layer) :
+ ATTR_DOMAIN_NUM;
+
+ GPUAttrRef vcol_layers[MAX_GPU_ATTR];
+ int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR,
+ CD_MASK_COLOR_ALL,
+ vdata,
+ NULL,
+ ldata,
+ NULL,
+ vcol_layers,
+ active_only,
+ active_color_layer ? active_color_layer->type : -1,
+ active_color_domain,
+ active_color_layer,
+ render_color_layer);
+
+ for (int i = 0; i < totlayer; i++) {
+ GPUAttrRef *ref = vcol_layers + i;
+ const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
+
+ const CustomDataLayer *layer = cdata->layers + ref->layer_idx;
+
+ if (vbo_id->totcol < MAX_GPU_ATTR) {
+ vbo_id->col[ci++] = GPU_vertformat_attr_add(
+ &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ vbo_id->totcol++;
+
+ bool is_render = render_color_layer == layer;
+ bool is_active = active_color_layer == layer;
+
+ DRW_cdlayer_attr_aliases_add(&vbo_id->format, "c", cdata, layer, is_render, is_active);
+ }
+ }
+ }
+
+ /* ensure at least one vertex color layer */
+ if (vbo_id->totcol == 0) {
+ vbo_id->col[0] = GPU_vertformat_attr_add(
+ &vbo_id->format, "c", GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ vbo_id->totcol = 1;
+
+ GPU_vertformat_alias_add(&vbo_id->format, "ac");
+ }
+
+ vbo_id->fset = GPU_vertformat_attr_add(
+ &vbo_id->format, "fset", GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ vbo_id->totuv = 0;
+ if (pbvh_type == PBVH_FACES && ldata && CustomData_has_layer(ldata, CD_MLOOPUV)) {
+ GPUAttrRef uv_layers[MAX_GPU_ATTR];
+ CustomDataLayer *active = NULL, *render = NULL;
+
+ active = get_active_layer(ldata, CD_MLOOPUV);
+ render = get_render_layer(ldata, CD_MLOOPUV);
+
+ int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_CORNER,
+ CD_MASK_MLOOPUV,
+ NULL,
+ NULL,
+ ldata,
+ NULL,
+ uv_layers,
+ active_only,
+ CD_MLOOPUV,
+ ATTR_DOMAIN_CORNER,
+ active,
+ render);
+
+ vbo_id->totuv = totlayer;
+
+ for (int i = 0; i < totlayer; i++) {
+ GPUAttrRef *ref = uv_layers + i;
+
+ vbo_id->uv[i] = GPU_vertformat_attr_add(
+ &vbo_id->format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ CustomDataLayer *cl = ldata->layers + ref->layer_idx;
+ bool is_active = ref->layer_idx == CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
+
+ DRW_cdlayer_attr_aliases_add(&vbo_id->format, "u", ldata, cl, cl == render, is_active);
+
+ /* Apparently the render attribute is 'a' while active is 'au',
+ * at least going by the draw cache extractor code.
+ */
+ if (cl == render) {
+ GPU_vertformat_alias_add(&vbo_id->format, "a");
+ }
+ }
+ }
+ }
+
+ if (!gpu_pbvh_format_equals(&old_format, vbo_id)) {
+ return true;
+ }
+
+ return false;
+}
+
GPUBatch *GPU_pbvh_buffers_batch_get(GPU_PBVH_Buffers *buffers, bool fast, bool wires)
{
if (wires) {
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index eb69a1d2635..18748627b83 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -8,7 +8,7 @@
* with checks for drivers and GPU support.
*/
-#include "DNA_userdef_types.h"
+#include "DNA_userdef_types.h" /* For `U.glreslimit`. */
#include "GPU_capabilities.h"
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index f1b46f8bf86..82441c3c89c 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -12,8 +12,6 @@
#include "DNA_customdata_types.h"
#include "DNA_image_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
#include "BLI_ghash.h"
#include "BLI_hash_mm2a.h"
#include "BLI_link_utils.h"
@@ -23,7 +21,6 @@
#include "PIL_time.h"
#include "BKE_material.h"
-#include "BKE_world.h"
#include "GPU_capabilities.h"
#include "GPU_material.h"
@@ -35,13 +32,12 @@
#include "BLI_vector.hh"
#include "gpu_codegen.h"
-#include "gpu_material_library.h"
#include "gpu_node_graph.h"
#include "gpu_shader_create_info.hh"
#include "gpu_shader_dependency_private.h"
-#include <stdarg.h>
-#include <string.h>
+#include <cstdarg>
+#include <cstring>
#include <sstream>
#include <string>
@@ -56,16 +52,19 @@ using namespace blender::gpu::shader;
*/
struct GPUCodegenCreateInfo : ShaderCreateInfo {
struct NameBuffer {
+ using NameEntry = std::array<char, 32>;
+
/** Duplicate attribute names to avoid reference the GPUNodeGraph directly. */
char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1];
char var_names[16][8];
- blender::Vector<std::array<char, 32>, 16> sampler_names;
+ blender::Vector<std::unique_ptr<NameEntry>, 16> sampler_names;
/* Returns the appended name memory location */
const char *append_sampler_name(const char name[32])
{
- auto index = sampler_names.append_and_get_index(std::array<char, 32>());
- char *name_buffer = sampler_names[index].data();
+ auto index = sampler_names.size();
+ sampler_names.append(std::make_unique<NameEntry>());
+ char *name_buffer = sampler_names[index]->data();
memcpy(name_buffer, name, 32);
return name_buffer;
}
@@ -303,7 +302,7 @@ void GPUCodegen::generate_attribs()
info.vertex_out(iface);
/* Input declaration, loading / assignment to interface and geometry shader passthrough. */
- std::stringstream decl_ss, iface_ss, load_ss;
+ std::stringstream load_ss;
int slot = 15;
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) {
diff --git a/source/blender/gpu/intern/gpu_compute.cc b/source/blender/gpu/intern/gpu_compute.cc
index b45cf8211cb..277f6d22280 100644
--- a/source/blender/gpu/intern/gpu_compute.cc
+++ b/source/blender/gpu/intern/gpu_compute.cc
@@ -7,7 +7,6 @@
#include "GPU_compute.h"
#include "gpu_backend.hh"
-#include "gpu_storage_buffer_private.hh"
void GPU_compute_dispatch(GPUShader *shader,
uint groups_x_len,
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index c6eaf7defdc..e29b0d5801d 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -23,12 +23,11 @@
#include "GPU_context.h"
#include "GPU_framebuffer.h"
-#include "GHOST_C-api.h"
-
#include "gpu_backend.hh"
#include "gpu_batch_private.hh"
#include "gpu_context_private.hh"
#include "gpu_matrix_private.h"
+#include "gpu_private.h"
#ifdef WITH_OPENGL_BACKEND
# include "gl_backend.hh"
@@ -45,6 +44,12 @@ using namespace blender::gpu;
static thread_local Context *active_ctx = nullptr;
+static std::mutex backend_users_mutex;
+static int num_backend_users = 0;
+
+static void gpu_backend_create();
+static void gpu_backend_discard();
+
/* -------------------------------------------------------------------- */
/** \name gpu::Context methods
* \{ */
@@ -87,9 +92,13 @@ Context *Context::get()
GPUContext *GPU_context_create(void *ghost_window)
{
- if (GPUBackend::get() == nullptr) {
- /* TODO: move where it make sense. */
- GPU_backend_init(GPU_BACKEND_OPENGL);
+ {
+ std::scoped_lock lock(backend_users_mutex);
+ if (num_backend_users == 0) {
+ /* Automatically create backend when first context is created. */
+ gpu_backend_create();
+ }
+ num_backend_users++;
}
Context *ctx = GPUBackend::get()->context_alloc(ghost_window);
@@ -103,6 +112,16 @@ void GPU_context_discard(GPUContext *ctx_)
Context *ctx = unwrap(ctx_);
delete ctx;
active_ctx = nullptr;
+
+ {
+ std::scoped_lock lock(backend_users_mutex);
+ num_backend_users--;
+ BLI_assert(num_backend_users >= 0);
+ if (num_backend_users == 0) {
+ /* Discard backend when last context is discarded. */
+ gpu_backend_discard();
+ }
+ }
}
void GPU_context_active_set(GPUContext *ctx_)
@@ -125,6 +144,22 @@ GPUContext *GPU_context_active_get()
return wrap(Context::get());
}
+void GPU_context_begin_frame(GPUContext *ctx)
+{
+ blender::gpu::Context *_ctx = unwrap(ctx);
+ if (_ctx) {
+ _ctx->begin_frame();
+ }
+}
+
+void GPU_context_end_frame(GPUContext *ctx)
+{
+ blender::gpu::Context *_ctx = unwrap(ctx);
+ if (_ctx) {
+ _ctx->end_frame();
+ }
+}
+
/* -------------------------------------------------------------------- */
/** \name Main context global mutex
*
@@ -177,11 +212,12 @@ void GPU_render_step()
/** \name Backend selection
* \{ */
-static GPUBackend *g_backend;
+static const eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
+static GPUBackend *g_backend = nullptr;
-bool GPU_backend_supported(eGPUBackendType type)
+bool GPU_backend_supported(void)
{
- switch (type) {
+ switch (g_backend_type) {
case GPU_BACKEND_OPENGL:
#ifdef WITH_OPENGL_BACKEND
return true;
@@ -200,12 +236,12 @@ bool GPU_backend_supported(eGPUBackendType type)
}
}
-void GPU_backend_init(eGPUBackendType backend_type)
+static void gpu_backend_create()
{
BLI_assert(g_backend == nullptr);
- BLI_assert(GPU_backend_supported(backend_type));
+ BLI_assert(GPU_backend_supported());
- switch (backend_type) {
+ switch (g_backend_type) {
#ifdef WITH_OPENGL_BACKEND
case GPU_BACKEND_OPENGL:
g_backend = new GLBackend;
@@ -222,10 +258,15 @@ void GPU_backend_init(eGPUBackendType backend_type)
}
}
-void GPU_backend_exit()
+void gpu_backend_delete_resources()
+{
+ BLI_assert(g_backend);
+ g_backend->delete_resources();
+}
+
+void gpu_backend_discard()
{
- /* TODO: assert no resource left. Currently UI textures are still not freed in their context
- * correctly. */
+ /* TODO: assert no resource left. */
delete g_backend;
g_backend = nullptr;
}
diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh
index af9791fde88..f823a92893c 100644
--- a/source/blender/gpu/intern/gpu_context_private.hh
+++ b/source/blender/gpu/intern/gpu_context_private.hh
@@ -28,11 +28,11 @@ namespace blender::gpu {
class Context {
public:
/** State management */
- Shader *shader = NULL;
- FrameBuffer *active_fb = NULL;
- GPUMatrixState *matrix_state = NULL;
- StateManager *state_manager = NULL;
- Immediate *imm = NULL;
+ Shader *shader = nullptr;
+ FrameBuffer *active_fb = nullptr;
+ GPUMatrixState *matrix_state = nullptr;
+ StateManager *state_manager = nullptr;
+ Immediate *imm = nullptr;
/**
* All 4 window frame-buffers.
@@ -41,10 +41,10 @@ class Context {
* Front frame-buffers contains (in principle, but not always) the last frame color.
* Default frame-buffer is back_left.
*/
- FrameBuffer *back_left = NULL;
- FrameBuffer *front_left = NULL;
- FrameBuffer *back_right = NULL;
- FrameBuffer *front_right = NULL;
+ FrameBuffer *back_left = nullptr;
+ FrameBuffer *front_left = nullptr;
+ FrameBuffer *back_right = nullptr;
+ FrameBuffer *front_right = nullptr;
DebugStack debug_stack;
@@ -52,7 +52,7 @@ class Context {
/** Thread on which this context is active. */
pthread_t thread_;
bool is_active_;
- /** Avoid including GHOST headers. Can be NULL for off-screen contexts. */
+ /** Avoid including GHOST headers. Can be nullptr for off-screen contexts. */
void *ghost_window_;
public:
@@ -63,6 +63,8 @@ class Context {
virtual void activate() = 0;
virtual void deactivate() = 0;
+ virtual void begin_frame() = 0;
+ virtual void end_frame() = 0;
/* Will push all pending commands to the GPU. */
virtual void flush() = 0;
diff --git a/source/blender/gpu/intern/gpu_drawlist.cc b/source/blender/gpu/intern/gpu_drawlist.cc
index b5b8d2f90bc..e1699bd0036 100644
--- a/source/blender/gpu/intern/gpu_drawlist.cc
+++ b/source/blender/gpu/intern/gpu_drawlist.cc
@@ -7,9 +7,6 @@
* Implementation of Multi Draw Indirect.
*/
-#include "MEM_guardedalloc.h"
-
-#include "GPU_batch.h"
#include "GPU_drawlist.h"
#include "gpu_backend.hh"
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index fb3c9549f18..8d93e49d588 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -7,7 +7,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
@@ -18,7 +17,6 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
-#include "gpu_private.h"
#include "gpu_texture_private.hh"
#include "gpu_framebuffer_private.hh"
@@ -126,6 +124,43 @@ void FrameBuffer::attachment_remove(GPUAttachmentType type)
dirty_attachments_ = true;
}
+void FrameBuffer::load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len)
+{
+ /* Follows attachment structure of GPU_framebuffer_config_array/GPU_framebuffer_ensure_config */
+ const GPULoadStore &depth_action = load_store_actions[0];
+ Span<GPULoadStore> color_attachments(load_store_actions + 1, actions_len - 1);
+
+ if (this->attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex) {
+ this->attachment_set_loadstore_op(
+ GPU_FB_DEPTH_STENCIL_ATTACHMENT, depth_action.load_action, depth_action.store_action);
+ }
+ if (this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) {
+ this->attachment_set_loadstore_op(
+ GPU_FB_DEPTH_ATTACHMENT, depth_action.load_action, depth_action.store_action);
+ }
+
+ GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0;
+ for (const GPULoadStore &actions : color_attachments) {
+ if (this->attachments_[type].tex) {
+ this->attachment_set_loadstore_op(type, actions.load_action, actions.store_action);
+ }
+ ++type;
+ }
+}
+
+unsigned int FrameBuffer::get_bits_per_pixel()
+{
+ unsigned int total_bits = 0;
+ for (GPUAttachment &attachment : attachments_) {
+ Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
+ if (tex != nullptr) {
+ int bits = to_bytesize(tex->format_get()) * to_component_len(tex->format_get());
+ total_bits += bits;
+ }
+ }
+ return total_bits;
+}
+
void FrameBuffer::recursive_downsample(int max_lvl,
void (*callback)(void *userData, int level),
void *userData)
@@ -151,10 +186,21 @@ void FrameBuffer::recursive_downsample(int max_lvl,
attachment.mip = mip_lvl;
}
}
+
/* Update the internal attachments and viewport size. */
dirty_attachments_ = true;
this->bind(true);
+ /* Optimize load-store state. */
+ GPUAttachmentType type = GPU_FB_DEPTH_ATTACHMENT;
+ for (GPUAttachment &attachment : attachments_) {
+ Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
+ if (tex != nullptr) {
+ this->attachment_set_loadstore_op(type, GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_STORE);
+ }
+ ++type;
+ }
+
callback(userData, mip_lvl);
}
@@ -200,6 +246,18 @@ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
unwrap(gpu_fb)->bind(enable_srgb);
}
+void GPU_framebuffer_bind_loadstore(GPUFrameBuffer *gpu_fb,
+ const GPULoadStore *load_store_actions,
+ uint actions_len)
+{
+ /* Bind */
+ GPU_framebuffer_bind(gpu_fb);
+
+ /* Update load store */
+ FrameBuffer *fb = unwrap(gpu_fb);
+ fb->load_store_config_array(load_store_actions, actions_len);
+}
+
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
{
const bool enable_srgb = false;
diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh
index d218662d17f..8cecc6b8b15 100644
--- a/source/blender/gpu/intern/gpu_framebuffer_private.hh
+++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh
@@ -114,6 +114,10 @@ class FrameBuffer {
eGPUDataFormat data_format,
const void *clear_value) = 0;
+ virtual void attachment_set_loadstore_op(GPUAttachmentType type,
+ eGPULoadOp load_action,
+ eGPUStoreOp store_action) = 0;
+
virtual void read(eGPUFrameBufferBits planes,
eGPUDataFormat format,
const int area[4],
@@ -128,12 +132,15 @@ class FrameBuffer {
int dst_offset_x,
int dst_offset_y) = 0;
+ void load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len);
+
void attachment_set(GPUAttachmentType type, const GPUAttachment &new_attachment);
void attachment_remove(GPUAttachmentType type);
void recursive_downsample(int max_lvl,
void (*callback)(void *userData, int level),
void *userData);
+ uint get_bits_per_pixel();
inline void size_set(int width, int height)
{
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index 69467e5b28a..8f04b1c2dfe 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -18,7 +18,6 @@
#include "gpu_context_private.hh"
#include "gpu_immediate_private.hh"
#include "gpu_shader_private.hh"
-#include "gpu_vertex_buffer_private.hh"
#include "gpu_vertex_format_private.h"
using namespace blender::gpu;
diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh
index 6c50fa01071..74ebbdc7ae3 100644
--- a/source/blender/gpu/intern/gpu_immediate_private.hh
+++ b/source/blender/gpu/intern/gpu_immediate_private.hh
@@ -19,7 +19,7 @@ namespace blender::gpu {
class Immediate {
public:
/** Pointer to the mapped buffer data for the current vertex. */
- uchar *vertex_data = NULL;
+ uchar *vertex_data = nullptr;
/** Current vertex index. */
uint vertex_idx = 0;
/** Length of the buffer in vertices. */
@@ -32,12 +32,12 @@ class Immediate {
/** Current draw call specification. */
GPUPrimType prim_type = GPU_PRIM_NONE;
GPUVertFormat vertex_format = {};
- GPUShader *shader = NULL;
+ GPUShader *shader = nullptr;
/** Enforce strict vertex count (disabled when using #immBeginAtMost). */
bool strict_vertex_len = true;
/** Batch in construction when using #immBeginBatch. */
- GPUBatch *batch = NULL;
+ GPUBatch *batch = nullptr;
/** Wide Line workaround. */
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index 67035853594..5233ff2dbf6 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -13,7 +13,6 @@
#include "BLI_utildefines.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "UI_resources.h"
@@ -143,7 +142,7 @@ static void imm_draw_circle(GPUPrimType prim_type,
int nsegments)
{
if (prim_type == GPU_PRIM_LINE_LOOP) {
- /* Note(Metal/AMD): For small primitives, line list more efficient than line strip.. */
+ /* NOTE(Metal/AMD): For small primitives, line list more efficient than line strip.. */
immBegin(GPU_PRIM_LINES, nsegments * 2);
immVertex2f(shdr_pos, x + (radius_x * cosf(0.0f)), y + (radius_y * sinf(0.0f)));
@@ -334,16 +333,30 @@ static void imm_draw_circle_3D(
GPUPrimType prim_type, uint pos, float x, float y, float radius, int nsegments)
{
if (prim_type == GPU_PRIM_LINE_LOOP) {
- /* Note(Metal/AMD): For small primitives, line list more efficient than line strip. */
+ /* NOTE(Metal/AMD): For small primitives, line list more efficient than line strip. */
immBegin(GPU_PRIM_LINES, nsegments * 2);
- immVertex3f(pos, x + radius * cosf(0.0f), y + radius * sinf(0.0f), 0.0f);
- for (int i = 1; i < nsegments; i++) {
- float angle = (float)(2 * M_PI) * ((float)i / (float)nsegments);
- immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
- immVertex3f(pos, x + radius * cosf(angle), y + radius * sinf(angle), 0.0f);
+ const float angle = (float)(2 * M_PI) / (float)nsegments;
+ float xprev = cosf(-angle) * radius;
+ float yprev = sinf(-angle) * radius;
+ const float alpha = 2.0f * cosf(angle);
+
+ float xr = radius;
+ float yr = 0;
+
+ for (int i = 0; i < nsegments; i++) {
+ immVertex3f(pos, x + xr, y + yr, 0.0f);
+ if (i) {
+ immVertex3f(pos, x + xr, y + yr, 0.0f);
+ }
+ const float xnext = alpha * xr - xprev;
+ const float ynext = alpha * yr - yprev;
+ xprev = xr;
+ yprev = yr;
+ xr = xnext;
+ yr = ynext;
}
- immVertex3f(pos, x + radius * cosf(0.0f), y + radius * sinf(0.0f), 0.0f);
+ immVertex3f(pos, x + radius, y, 0.0f);
immEnd();
}
else {
@@ -373,7 +386,7 @@ void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegm
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
{
- /* Note(Metal/AMD): For small primitives, line list more efficient than line-strip. */
+ /* NOTE(Metal/AMD): For small primitives, line list more efficient than line-strip. */
immBegin(GPU_PRIM_LINES, 8);
immVertex2f(pos, x1, y1);
immVertex2f(pos, x1, y2);
@@ -392,7 +405,7 @@ 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)
{
/* use this version when GPUVertFormat has a vec3 position */
- /* Note(Metal/AMD): For small primitives, line list more efficient than line-strip. */
+ /* NOTE(Metal/AMD): For small primitives, line list more efficient than line-strip. */
immBegin(GPU_PRIM_LINES, 8);
immVertex3f(pos, x1, y1, 0.0f);
immVertex3f(pos, x1, y2, 0.0f);
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index e97c9e9c829..34b355eefaf 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -6,15 +6,10 @@
*/
#include "GPU_init_exit.h" /* interface */
-#include "BKE_global.h"
#include "BLI_sys_types.h"
#include "GPU_batch.h"
-#include "GPU_buffers.h"
-#include "GPU_context.h"
-#include "GPU_immediate.h"
#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"
@@ -60,6 +55,8 @@ void GPU_exit(void)
gpu_shader_dependency_exit();
gpu_shader_create_info_exit();
+ gpu_backend_delete_resources();
+
initialized = false;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 23028f58059..4d3ea3e0c99 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -19,14 +19,11 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
-#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
-#include "BKE_scene.h"
-#include "BKE_world.h"
#include "NOD_shader.h"
@@ -669,7 +666,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries");
mat->refcount = 1;
#ifndef NDEBUG
- BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
+ STRNCPY(mat->name, name);
#else
UNUSED_VARS(name);
#endif
@@ -750,6 +747,9 @@ void GPU_material_compile(GPUMaterial *mat)
mat->status = GPU_MAT_SUCCESS;
gpu_node_graph_free_nodes(&mat->graph);
}
+ else {
+ mat->status = GPU_MAT_FAILED;
+ }
}
else {
mat->status = GPU_MAT_FAILED;
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index ffc2228a49b..b071ab85f3a 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -30,7 +30,7 @@ typedef struct GPUFunction {
eGPUType paramtype[MAX_PARAMETER];
GPUFunctionQual paramqual[MAX_PARAMETER];
int totparam;
- /* TOOD(@fclem): Clean that void pointer. */
+ /* TODO(@fclem): Clean that void pointer. */
void *source; /* GPUSource */
} GPUFunction;
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 91fb0544cf6..1338c5312c2 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -328,7 +328,7 @@ void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph)
/* Attributes and Textures */
-static char attr_prefix_get(CustomDataType type)
+static char attr_prefix_get(eCustomDataType type)
{
switch (type) {
case CD_TANGENT:
@@ -347,7 +347,7 @@ static char attr_prefix_get(CustomDataType type)
static void attr_input_name(GPUMaterialAttribute *attr)
{
- /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
+ /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.cc */
if (attr->type == CD_ORCO) {
/* OPTI: orco is computed from local positions, but only if no modifier is present. */
STRNCPY(attr->input_name, "orco");
@@ -364,7 +364,7 @@ static void attr_input_name(GPUMaterialAttribute *attr)
/** Add a new varying attribute of given type and name. Returns NULL if out of slots. */
static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph,
- CustomDataType type,
+ eCustomDataType type,
const char *name)
{
/* Find existing attribute. */
@@ -378,7 +378,7 @@ static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph,
}
/* Add new requested attribute if it's within GPU limits. */
- if (attr == NULL && num_attributes < GPU_MAX_ATTR) {
+ if (attr == NULL) {
attr = MEM_callocN(sizeof(*attr), __func__);
attr->type = type;
STRNCPY(attr->name, name);
@@ -468,7 +468,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
/* Creating Inputs */
-GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const char *name)
+GPUNodeLink *GPU_attribute(GPUMaterial *mat, const eCustomDataType type, const char *name)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name);
@@ -491,7 +491,7 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const ch
}
GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
- const CustomDataType type,
+ const eCustomDataType type,
const char *name,
eGPUDefaultValue default_value)
{
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index a8ee5187d98..0e293302086 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -10,6 +10,10 @@
extern "C" {
#endif
+/* gpu_backend.cc */
+
+void gpu_backend_delete_resources(void);
+
/* gpu_pbvh.c */
void gpu_pbvh_init(void);
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index ac33c5d5ca8..7afba20c2d9 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -12,12 +12,8 @@
#include "GPU_select.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_rect.h"
-#include "DNA_userdef_types.h"
-
#include "BLI_utildefines.h"
#include "gpu_select_private.h"
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 840201c8c97..b5b2d7fa1a5 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -13,7 +13,6 @@
#include "GPU_debug.h"
#include "GPU_framebuffer.h"
-#include "GPU_immediate.h"
#include "GPU_select.h"
#include "GPU_state.h"
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc
index 26c9ed79d6c..7393dfd0d81 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.cc
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -19,7 +19,6 @@
#include "BLI_rect.h"
-#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
index 515f65adb73..d8af2fc584d 100644
--- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
+++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
@@ -12,6 +12,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_material.h"
@@ -101,6 +102,38 @@ void UI_GetThemeColorShadeAlpha4ubv(int UNUSED(colorid),
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_attribute.h
+ * \{ */
+
+void BKE_id_attribute_copy_domains_temp(short UNUSED(id_type),
+ const struct CustomData *UNUSED(vdata),
+ const struct CustomData *UNUSED(edata),
+ const struct CustomData *UNUSED(ldata),
+ const struct CustomData *UNUSED(pdata),
+ const struct CustomData *UNUSED(cdata),
+ struct ID *UNUSED(i_id))
+{
+}
+
+struct CustomDataLayer *BKE_id_attributes_active_color_get(const struct ID *UNUSED(id))
+{
+ return nullptr;
+}
+
+struct CustomDataLayer *BKE_id_attributes_render_color_get(const struct ID *UNUSED(id))
+{
+ return nullptr;
+}
+
+eAttrDomain BKE_id_attribute_domain(const struct ID *UNUSED(id),
+ const struct CustomDataLayer *UNUSED(layer))
+{
+ return ATTR_DOMAIN_AUTO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Stubs of BKE_paint.h
* \{ */
bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt),
@@ -170,6 +203,28 @@ int CustomData_get_offset(const struct CustomData *UNUSED(data), int UNUSED(type
return 0;
}
+int CustomData_get_named_layer_index(const struct CustomData *UNUSED(data),
+ int UNUSED(type),
+ const char *UNUSED(name))
+{
+ return -1;
+}
+
+int CustomData_get_active_layer_index(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ return -1;
+}
+
+int CustomData_get_render_layer_index(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ return -1;
+}
+
+bool CustomData_has_layer(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ return false;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -237,5 +292,14 @@ void DRW_deferred_shader_remove(struct GPUMaterial *UNUSED(mat))
BLI_assert_unreachable();
}
+void DRW_cdlayer_attr_aliases_add(struct GPUVertFormat *UNUSED(format),
+ const char *UNUSED(base_name),
+ const struct CustomData *UNUSED(data),
+ const struct CustomDataLayer *UNUSED(cl),
+ bool UNUSED(is_active_render),
+ bool UNUSED(is_active_layer))
+{
+}
+
/** \} */
}
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index b92fae4a89b..c3a1236e814 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -5,25 +5,9 @@
* \ingroup gpu
*/
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math_base.h"
-#include "BLI_math_vector.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
-#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
-#include "BKE_appdir.h"
-#include "BKE_global.h"
-
-#include "DNA_space_types.h"
-
-#include "GPU_matrix.h"
-#include "GPU_platform.h"
#include "GPU_shader.h"
-#include "GPU_texture.h"
-#include "GPU_uniform_buffer.h"
/* Adjust these constants as needed. */
#define MAX_DEFINE_LENGTH 256
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc
index f5b90989481..bc0731862cb 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.cc
+++ b/source/blender/gpu/intern/gpu_shader_create_info.cc
@@ -19,7 +19,6 @@
#include "gpu_shader_create_info.hh"
#include "gpu_shader_create_info_private.hh"
#include "gpu_shader_dependency_private.h"
-#include "gpu_shader_private.hh"
#undef GPU_SHADER_INTERFACE_INFO
#undef GPU_SHADER_CREATE_INFO
@@ -155,13 +154,13 @@ std::string ShaderCreateInfo::check_error() const
}
else {
if (!this->vertex_source_.is_empty()) {
- error += "Compute shader has vertex_source_ shader attached in" + this->name_ + ".\n";
+ error += "Compute shader has vertex_source_ shader attached in " + this->name_ + ".\n";
}
if (!this->geometry_source_.is_empty()) {
- error += "Compute shader has geometry_source_ shader attached in" + this->name_ + ".\n";
+ error += "Compute shader has geometry_source_ shader attached in " + this->name_ + ".\n";
}
if (!this->fragment_source_.is_empty()) {
- error += "Compute shader has fragment_source_ shader attached in" + this->name_ + ".\n";
+ error += "Compute shader has fragment_source_ shader attached in " + this->name_ + ".\n";
}
}
@@ -334,8 +333,11 @@ bool gpu_shader_create_info_compile_all()
int skipped = 0;
int total = 0;
for (ShaderCreateInfo *info : g_create_infos->values()) {
+ info->finalize();
if (info->do_static_compilation_) {
- if (GPU_compute_shader_support() == false && info->compute_source_ != nullptr) {
+ if ((GPU_compute_shader_support() == false && info->compute_source_ != nullptr) ||
+ (GPU_shader_image_load_store_support() == false && info->has_resource_image()) ||
+ (GPU_shader_storage_buffer_objects_support() == false && info->has_resource_storage())) {
skipped++;
continue;
}
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
index 4927ef75a75..8e05412d0ee 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.hh
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -872,6 +872,31 @@ struct ShaderCreateInfo {
return stream;
}
+ bool has_resource_type(Resource::BindType bind_type) const
+ {
+ for (auto &res : batch_resources_) {
+ if (res.bind_type == bind_type) {
+ return true;
+ }
+ }
+ for (auto &res : pass_resources_) {
+ if (res.bind_type == bind_type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool has_resource_image() const
+ {
+ return has_resource_type(Resource::BindType::IMAGE);
+ }
+
+ bool has_resource_storage() const
+ {
+ return has_resource_type(Resource::BindType::STORAGE_BUFFER);
+ }
+
/** \} */
#undef TEST_EQUAL
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 842914f5bed..d91e15243f3 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -15,7 +15,6 @@
#include "BLI_ghash.h"
#include "BLI_map.hh"
-#include "BLI_set.hh"
#include "BLI_string_ref.hh"
#include "gpu_material_library.h"
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index ea138973c74..6f43b379d31 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -38,7 +38,7 @@ static void sort_input_list(MutableSpan<ShaderInput> dst)
/* Simple sorting by going through the array and selecting the biggest element each time. */
for (uint i = 0; i < dst.size(); i++) {
- ShaderInput *input_src = &src[0];
+ ShaderInput *input_src = src.data();
for (uint j = 1; j < src.size(); j++) {
if (src[j].name_hash > input_src->name_hash) {
input_src = &src[j];
diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh
index ac78af38fcc..60344757b43 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.hh
+++ b/source/blender/gpu/intern/gpu_shader_interface.hh
@@ -39,9 +39,9 @@ class ShaderInterface {
/* TODO(fclem): should be protected. */
public:
/** Flat array. In this order: Attributes, Ubos, Uniforms. */
- ShaderInput *inputs_ = NULL;
+ ShaderInput *inputs_ = nullptr;
/** Buffer containing all inputs names separated by '\0'. */
- char *name_buffer_ = NULL;
+ char *name_buffer_ = nullptr;
/** Input counts inside input array. */
uint attr_len_ = 0;
uint ubo_len_ = 0;
@@ -187,7 +187,7 @@ inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u)
return "srgbTarget";
default:
- return NULL;
+ return nullptr;
}
}
@@ -208,7 +208,7 @@ inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBu
case GPU_UNIFORM_BLOCK_DRW_INFOS:
return "drw_infos";
default:
- return NULL;
+ return nullptr;
}
}
@@ -258,7 +258,7 @@ inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const
return inputs + i; /* not found */
}
}
- return NULL; /* not found */
+ return nullptr; /* not found */
}
/* This is a bit dangerous since we could have a hash collision.
@@ -268,7 +268,7 @@ inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const
return inputs + i;
}
}
- return NULL; /* not found */
+ return nullptr; /* not found */
}
inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs,
@@ -281,7 +281,7 @@ inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const
return inputs + i;
}
}
- return NULL; /* not found */
+ return nullptr; /* not found */
}
} // namespace blender::gpu
diff --git a/source/blender/gpu/intern/gpu_shader_log.cc b/source/blender/gpu/intern/gpu_shader_log.cc
index 83fc34a3278..572727fa515 100644
--- a/source/blender/gpu/intern/gpu_shader_log.cc
+++ b/source/blender/gpu/intern/gpu_shader_log.cc
@@ -15,8 +15,6 @@
#include "gpu_shader_dependency_private.h"
#include "gpu_shader_private.hh"
-#include "GPU_platform.h"
-
#include "CLG_log.h"
static CLG_LogRef LOG = {"gpu.shader"};
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index f74d500340d..a1e0b8867a0 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -14,8 +14,6 @@
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BKE_global.h"
-
#include "GPU_state.h"
#include "gpu_context_private.hh"
diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc
index 68020ec66f4..afa27da9c85 100644
--- a/source/blender/gpu/intern/gpu_storage_buffer.cc
+++ b/source/blender/gpu/intern/gpu_storage_buffer.cc
@@ -12,7 +12,6 @@
#include "BLI_math_base.h"
#include "gpu_backend.hh"
-#include "gpu_node_graph.h"
#include "GPU_material.h"
#include "GPU_vertex_buffer.h" /* For GPUUsageType. */
diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh
index 091e6c2d386..9baec0c2a77 100644
--- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh
@@ -29,7 +29,7 @@ class StorageBuf {
/** Data size in bytes. */
size_t size_in_bytes_;
/** Continuous memory block to copy to GPU. This data is owned by the StorageBuf. */
- void *data_ = NULL;
+ void *data_ = nullptr;
/** Debugging name */
char name_[DEBUG_NAME_LEN];
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index d78dc845074..218d22ddf53 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -13,7 +13,6 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
#include "gpu_framebuffer_private.hh"
-#include "gpu_vertex_buffer_private.hh"
#include "gpu_texture_private.hh"
@@ -702,7 +701,11 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size)
void GPU_samplers_update()
{
- GPUBackend::get()->samplers_update();
+ /* Backend may not exist when we are updating preferences from background mode. */
+ GPUBackend *backend = GPUBackend::get();
+ if (backend) {
+ backend->samplers_update();
+ }
}
/** \} */
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
index 6e3285b6fef..e3d70634ce1 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
@@ -29,7 +29,7 @@ class UniformBuf {
/** Data size in bytes. */
size_t size_in_bytes_;
/** Continuous memory block to copy to GPU. This data is owned by the UniformBuf. */
- void *data_ = NULL;
+ void *data_ = nullptr;
/** Debugging name */
char name_[DEBUG_NAME_LEN];
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index f47970d48d1..0dbd565291b 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -12,7 +12,6 @@
#include "gpu_backend.hh"
#include "gpu_vertex_format_private.h"
-#include "gl_vertex_buffer.hh" /* TODO: remove. */
#include "gpu_context_private.hh" /* TODO: remove. */
#include "gpu_vertex_buffer_private.hh"
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
index 7a0b53cf958..a7920bacaec 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
@@ -29,7 +29,7 @@ class VertBuf {
/** Status flag. */
GPUVertBufStatus flag = GPU_VERTBUF_INVALID;
/** NULL indicates data in VRAM (unmapped) */
- uchar *data = NULL;
+ uchar *data = nullptr;
protected:
/** Usage hint for GL optimization. */
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index c3118ca320c..71bdf9e336b 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -9,16 +9,13 @@
#include <string.h>
-#include "BLI_listbase.h"
#include "BLI_math_vector.h"
-#include "BLI_memblock.h"
#include "BLI_rect.h"
#include "BKE_colortools.h"
#include "IMB_colormanagement.h"
-#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
#include "GPU_capabilities.h"
diff --git a/source/blender/gpu/metal/mtl_backend.hh b/source/blender/gpu/metal/mtl_backend.hh
index 9044d8517ab..3e09408e43e 100644
--- a/source/blender/gpu/metal/mtl_backend.hh
+++ b/source/blender/gpu/metal/mtl_backend.hh
@@ -35,19 +35,24 @@ class MTLBackend : public GPUBackend {
return MTLBackend::capabilities;
}
- inline ~MTLBackend()
+ ~MTLBackend()
{
MTLBackend::platform_exit();
}
+ void delete_resources()
+ {
+ /* Delete any resources with context active. */
+ }
+
static bool metal_is_supported();
- inline static MTLBackend *get()
+ static MTLBackend *get()
{
return static_cast<MTLBackend *>(GPUBackend::get());
}
void samplers_update() override;
- inline void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override
+ void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override
{
/* Placeholder */
}
diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm
index 8bdec962af0..3328855bbf8 100644
--- a/source/blender/gpu/metal/mtl_backend.mm
+++ b/source/blender/gpu/metal/mtl_backend.mm
@@ -9,6 +9,9 @@
#include "gpu_backend.hh"
#include "mtl_backend.hh"
#include "mtl_context.hh"
+#include "mtl_framebuffer.hh"
+#include "mtl_uniform_buffer.hh"
+#include "mtl_query.hh"
#include "gpu_capabilities_private.hh"
#include "gpu_platform_private.hh"
@@ -50,8 +53,9 @@ DrawList *MTLBackend::drawlist_alloc(int list_length)
FrameBuffer *MTLBackend::framebuffer_alloc(const char *name)
{
- /* TODO(Metal): Implement MTLFrameBuffer. */
- return nullptr;
+ MTLContext *mtl_context = static_cast<MTLContext *>(
+ reinterpret_cast<Context *>(GPU_context_active_get()));
+ return new MTLFrameBuffer(mtl_context, name);
};
IndexBuf *MTLBackend::indexbuf_alloc()
@@ -62,8 +66,7 @@ IndexBuf *MTLBackend::indexbuf_alloc()
QueryPool *MTLBackend::querypool_alloc()
{
- /* TODO(Metal): Implement MTLQueryPool. */
- return nullptr;
+ return new MTLQueryPool();
};
Shader *MTLBackend::shader_alloc(const char *name)
@@ -79,8 +82,7 @@ Texture *MTLBackend::texture_alloc(const char *name)
UniformBuf *MTLBackend::uniformbuf_alloc(int size, const char *name)
{
- /* TODO(Metal): Implement MTLUniformBuf. */
- return nullptr;
+ return new MTLUniformBuf(size, name);
};
StorageBuf *MTLBackend::storagebuf_alloc(int size, GPUUsageType usage, const char *name)
@@ -125,7 +127,21 @@ void MTLBackend::render_end()
void MTLBackend::render_step()
{
- /* Placeholder */
+ /* NOTE(Metal): Primarily called from main thread, but below data-structures
+ * and operations are thread-safe, and GPUContext rendering coordination
+ * is also thread-safe. */
+
+ /* Flush any MTLSafeFreeLists which have previously been released by any MTLContext. */
+ MTLContext::get_global_memory_manager().update_memory_pools();
+
+ /* End existing MTLSafeFreeList and begin new list --
+ * Buffers wont `free` until all associated in-flight command buffers have completed.
+ * Decrement final reference count for ensuring the previous list is certainly
+ * released. */
+ MTLSafeFreeList *cmd_free_buffer_list =
+ MTLContext::get_global_memory_manager().get_current_safe_list();
+ MTLContext::get_global_memory_manager().begin_new_safe_list();
+ cmd_free_buffer_list->decrement_reference();
}
bool MTLBackend::is_inside_render_boundary()
@@ -256,7 +272,7 @@ bool MTLBackend::metal_is_supported()
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
- /* Metal Viewport requires macOS Version 10.15 onwards. */
+ /* Metal Viewport requires macOS Version 10.15 onward. */
bool supported_os_version = version.majorVersion >= 11 ||
(version.majorVersion == 10 ? version.minorVersion >= 15 : false);
if (!supported_os_version) {
@@ -380,11 +396,10 @@ void MTLBackend::capabilities_init(MTLContext *ctx)
/* In Metal, total_thread_count is 512 or 1024, such that
* threadgroup `width*height*depth <= total_thread_count` */
- unsigned int max_threads_per_threadgroup_per_dim =
- ([device supportsFamily:MTLGPUFamilyApple4] ||
- MTLBackend::capabilities.supports_family_mac1) ?
- 1024 :
- 512;
+ uint max_threads_per_threadgroup_per_dim = ([device supportsFamily:MTLGPUFamilyApple4] ||
+ MTLBackend::capabilities.supports_family_mac1) ?
+ 1024 :
+ 512;
GCaps.max_work_group_size[0] = max_threads_per_threadgroup_per_dim;
GCaps.max_work_group_size[1] = max_threads_per_threadgroup_per_dim;
GCaps.max_work_group_size[2] = max_threads_per_threadgroup_per_dim;
diff --git a/source/blender/gpu/metal/mtl_capabilities.hh b/source/blender/gpu/metal/mtl_capabilities.hh
index 3afa6e31ccb..d56f796e60f 100644
--- a/source/blender/gpu/metal/mtl_capabilities.hh
+++ b/source/blender/gpu/metal/mtl_capabilities.hh
@@ -19,7 +19,7 @@ namespace gpu {
#define MTL_MAX_UNIFORMS_PER_BLOCK 64
/* Context-specific limits -- populated in 'MTLBackend::platform_init' */
-typedef struct MTLCapabilities {
+struct MTLCapabilities {
/* Variable Limits & feature sets. */
int max_color_render_targets = 4; /* Minimum = 4 */
@@ -40,8 +40,7 @@ typedef struct MTLCapabilities {
bool supports_family_mac2 = false;
bool supports_family_mac_catalyst1 = false;
bool supports_family_mac_catalyst2 = false;
-
-} MTLCapabilities;
+};
} // namespace gpu
} // namespace blender
diff --git a/source/blender/gpu/metal/mtl_command_buffer.mm b/source/blender/gpu/metal/mtl_command_buffer.mm
new file mode 100644
index 00000000000..9a9a2d55103
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_command_buffer.mm
@@ -0,0 +1,652 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "DNA_userdef_types.h"
+
+#include "mtl_backend.hh"
+#include "mtl_common.hh"
+#include "mtl_context.hh"
+#include "mtl_debug.hh"
+#include "mtl_framebuffer.hh"
+
+#include <fstream>
+
+using namespace blender;
+using namespace blender::gpu;
+
+namespace blender::gpu {
+
+/* Global sync event used across MTLContext's.
+ * This resolves flickering artifacts from command buffer
+ * dependencies not being honored for work submitted between
+ * different GPUContext's. */
+id<MTLEvent> MTLCommandBufferManager::sync_event = nil;
+uint64_t MTLCommandBufferManager::event_signal_val = 0;
+
+/* Counter for active command buffers. */
+int MTLCommandBufferManager::num_active_cmd_bufs = 0;
+
+/* -------------------------------------------------------------------- */
+/** \name MTLCommandBuffer initialization and render coordination.
+ * \{ */
+
+void MTLCommandBufferManager::prepare(bool supports_render)
+{
+ render_pass_state_.reset_state();
+}
+
+void MTLCommandBufferManager::register_encoder_counters()
+{
+ encoder_count_++;
+ empty_ = false;
+}
+
+id<MTLCommandBuffer> MTLCommandBufferManager::ensure_begin()
+{
+ if (active_command_buffer_ == nil) {
+
+ /* Verify number of active command buffers is below limit.
+ * Exceeding this limit will mean we either have a leak/GPU hang
+ * or we should increase the command buffer limit during MTLQueue creation */
+ BLI_assert(MTLCommandBufferManager::num_active_cmd_bufs < MTL_MAX_COMMAND_BUFFERS);
+
+ if (G.debug & G_DEBUG_GPU) {
+ /* Debug: Enable Advanced Errors for GPU work execution. */
+ MTLCommandBufferDescriptor *desc = [[MTLCommandBufferDescriptor alloc] init];
+ desc.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
+ desc.retainedReferences = YES;
+ active_command_buffer_ = [context_.queue commandBufferWithDescriptor:desc];
+ }
+ else {
+ active_command_buffer_ = [context_.queue commandBuffer];
+ }
+ [active_command_buffer_ retain];
+ MTLCommandBufferManager::num_active_cmd_bufs++;
+
+ /* Ensure command buffers execute in submission order across multiple MTLContext's. */
+ if (this->sync_event != nil) {
+ [active_command_buffer_ encodeWaitForEvent:this->sync_event value:this->event_signal_val];
+ }
+
+ /* Ensure we begin new Scratch Buffer if we are on a new frame. */
+ MTLScratchBufferManager &mem = context_.memory_manager;
+ mem.ensure_increment_scratch_buffer();
+
+ /* Reset Command buffer heuristics. */
+ this->reset_counters();
+ }
+ BLI_assert(active_command_buffer_ != nil);
+ return active_command_buffer_;
+}
+
+/* If wait is true, CPU will stall until GPU work has completed. */
+bool MTLCommandBufferManager::submit(bool wait)
+{
+ /* Skip submission if command buffer is empty. */
+ if (empty_ || active_command_buffer_ == nil) {
+ return false;
+ }
+
+ /* Ensure current encoders are finished. */
+ this->end_active_command_encoder();
+ BLI_assert(active_command_encoder_type_ == MTL_NO_COMMAND_ENCODER);
+
+ /* Flush active ScratchBuffer associated with parent MTLContext. */
+ context_.memory_manager.flush_active_scratch_buffer();
+
+ /*** Submit Command Buffer. ***/
+ /* Strict ordering ensures command buffers are guaranteed to execute after a previous
+ * one has completed. Resolves flickering when command buffers are submitted from
+ * different MTLContext's. */
+ if (MTLCommandBufferManager::sync_event == nil) {
+ MTLCommandBufferManager::sync_event = [context_.device newEvent];
+ BLI_assert(MTLCommandBufferManager::sync_event);
+ [MTLCommandBufferManager::sync_event retain];
+ }
+ BLI_assert(MTLCommandBufferManager::sync_event != nil);
+ MTLCommandBufferManager::event_signal_val++;
+
+ [active_command_buffer_ encodeSignalEvent:MTLCommandBufferManager::sync_event
+ value:MTLCommandBufferManager::event_signal_val];
+
+ /* Command buffer lifetime tracking. */
+ /* Increment current MTLSafeFreeList reference counter to flag MTLBuffers freed within
+ * the current command buffer lifetime as used.
+ * This ensures that in-use resources are not prematurely de-referenced and returned to the
+ * available buffer pool while they are in-use by the GPU. */
+ MTLSafeFreeList *cmd_free_buffer_list =
+ MTLContext::get_global_memory_manager().get_current_safe_list();
+ BLI_assert(cmd_free_buffer_list);
+ cmd_free_buffer_list->increment_reference();
+
+ id<MTLCommandBuffer> cmd_buffer_ref = active_command_buffer_;
+ [cmd_buffer_ref retain];
+
+ [cmd_buffer_ref addCompletedHandler:^(id<MTLCommandBuffer> cb) {
+ /* Upon command buffer completion, decrement MTLSafeFreeList reference count
+ * to allow buffers no longer in use by this CommandBuffer to be freed. */
+ cmd_free_buffer_list->decrement_reference();
+
+ /* Release command buffer after completion callback handled. */
+ [cmd_buffer_ref release];
+
+ /* Decrement count. */
+ MTLCommandBufferManager::num_active_cmd_bufs--;
+ }];
+
+ /* Submit command buffer to GPU. */
+ [active_command_buffer_ commit];
+
+ if (wait || (G.debug & G_DEBUG_GPU)) {
+ /* Wait until current GPU work has finished executing. */
+ [active_command_buffer_ waitUntilCompleted];
+
+ /* Command buffer execution debugging can return an error message if
+ * execution has failed or encountered GPU-side errors. */
+ if (G.debug & G_DEBUG_GPU) {
+
+ NSError *error = [active_command_buffer_ error];
+ if (error != nil) {
+ NSLog(@"%@", error);
+ BLI_assert(false);
+
+ @autoreleasepool {
+ const char *stringAsChar = [[NSString stringWithFormat:@"%@", error] UTF8String];
+
+ std::ofstream outfile;
+ outfile.open("command_buffer_error.txt", std::fstream::out | std::fstream::app);
+ outfile << stringAsChar;
+ outfile.close();
+ }
+ }
+ }
+ }
+
+ /* Release previous frames command buffer and reset active cmd buffer. */
+ if (last_submitted_command_buffer_ != nil) {
+
+ BLI_assert(MTLBackend::get()->is_inside_render_boundary());
+ [last_submitted_command_buffer_ autorelease];
+ last_submitted_command_buffer_ = nil;
+ }
+ last_submitted_command_buffer_ = active_command_buffer_;
+ active_command_buffer_ = nil;
+
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Render Command Encoder Utility and management functions.
+ * \{ */
+
+/* Fetch/query current encoder. */
+bool MTLCommandBufferManager::is_inside_render_pass()
+{
+ return (active_command_encoder_type_ == MTL_RENDER_COMMAND_ENCODER);
+}
+
+bool MTLCommandBufferManager::is_inside_blit()
+{
+ return (active_command_encoder_type_ == MTL_BLIT_COMMAND_ENCODER);
+}
+
+bool MTLCommandBufferManager::is_inside_compute()
+{
+ return (active_command_encoder_type_ == MTL_COMPUTE_COMMAND_ENCODER);
+}
+
+id<MTLRenderCommandEncoder> MTLCommandBufferManager::get_active_render_command_encoder()
+{
+ /* Calling code should check if inside render pass. Otherwise nil. */
+ return active_render_command_encoder_;
+}
+
+id<MTLBlitCommandEncoder> MTLCommandBufferManager::get_active_blit_command_encoder()
+{
+ /* Calling code should check if inside render pass. Otherwise nil. */
+ return active_blit_command_encoder_;
+}
+
+id<MTLComputeCommandEncoder> MTLCommandBufferManager::get_active_compute_command_encoder()
+{
+ /* Calling code should check if inside render pass. Otherwise nil. */
+ return active_compute_command_encoder_;
+}
+
+MTLFrameBuffer *MTLCommandBufferManager::get_active_framebuffer()
+{
+ /* If outside of RenderPass, nullptr will be returned. */
+ if (this->is_inside_render_pass()) {
+ return active_frame_buffer_;
+ }
+ return nullptr;
+}
+
+/* Encoder and Pass management. */
+/* End currently active MTLCommandEncoder. */
+bool MTLCommandBufferManager::end_active_command_encoder()
+{
+
+ /* End active encoder if one is active. */
+ if (active_command_encoder_type_ != MTL_NO_COMMAND_ENCODER) {
+
+ switch (active_command_encoder_type_) {
+ case MTL_RENDER_COMMAND_ENCODER: {
+ /* Verify a RenderCommandEncoder is active and end. */
+ BLI_assert(active_render_command_encoder_ != nil);
+
+ /* Complete Encoding. */
+ [active_render_command_encoder_ endEncoding];
+ [active_render_command_encoder_ release];
+ active_render_command_encoder_ = nil;
+ active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
+
+ /* Reset associated framebuffer flag. */
+ active_frame_buffer_ = nullptr;
+ active_pass_descriptor_ = nullptr;
+ return true;
+ }
+
+ case MTL_BLIT_COMMAND_ENCODER: {
+ /* Verify a RenderCommandEncoder is active and end. */
+ BLI_assert(active_blit_command_encoder_ != nil);
+ [active_blit_command_encoder_ endEncoding];
+ [active_blit_command_encoder_ release];
+ active_blit_command_encoder_ = nil;
+ active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
+ return true;
+ }
+
+ case MTL_COMPUTE_COMMAND_ENCODER: {
+ /* Verify a RenderCommandEncoder is active and end. */
+ BLI_assert(active_compute_command_encoder_ != nil);
+ [active_compute_command_encoder_ endEncoding];
+ [active_compute_command_encoder_ release];
+ active_compute_command_encoder_ = nil;
+ active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
+ return true;
+ }
+
+ default: {
+ BLI_assert(false && "Invalid command encoder type");
+ return false;
+ }
+ };
+ }
+ else {
+ /* MTL_NO_COMMAND_ENCODER. */
+ BLI_assert(active_render_command_encoder_ == nil);
+ BLI_assert(active_blit_command_encoder_ == nil);
+ BLI_assert(active_compute_command_encoder_ == nil);
+ return false;
+ }
+}
+
+id<MTLRenderCommandEncoder> MTLCommandBufferManager::ensure_begin_render_command_encoder(
+ MTLFrameBuffer *ctx_framebuffer, bool force_begin, bool *new_pass)
+{
+ /* Ensure valid framebuffer. */
+ BLI_assert(ctx_framebuffer != nullptr);
+
+ /* Ensure active command buffer. */
+ id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
+ BLI_assert(cmd_buf);
+
+ /* Begin new command encoder if the currently active one is
+ * incompatible or requires updating. */
+ if (active_command_encoder_type_ != MTL_RENDER_COMMAND_ENCODER ||
+ active_frame_buffer_ != ctx_framebuffer || force_begin) {
+ this->end_active_command_encoder();
+
+ /* Determine if this is a re-bind of the same framebuffer. */
+ bool is_rebind = (active_frame_buffer_ == ctx_framebuffer);
+
+ /* Generate RenderPassDescriptor from bound framebuffer. */
+ BLI_assert(ctx_framebuffer);
+ active_frame_buffer_ = ctx_framebuffer;
+ active_pass_descriptor_ = active_frame_buffer_->bake_render_pass_descriptor(
+ is_rebind && (!active_frame_buffer_->get_pending_clear()));
+
+ /* Determine if there is a visibility buffer assigned to the context. */
+ gpu::MTLBuffer *visibility_buffer = context_.get_visibility_buffer();
+ this->active_pass_descriptor_.visibilityResultBuffer =
+ (visibility_buffer) ? visibility_buffer->get_metal_buffer() : nil;
+ context_.clear_visibility_dirty();
+
+ /* Ensure we have already cleaned up our previous render command encoder. */
+ BLI_assert(active_render_command_encoder_ == nil);
+
+ /* Create new RenderCommandEncoder based on descriptor (and begin encoding). */
+ active_render_command_encoder_ = [cmd_buf
+ renderCommandEncoderWithDescriptor:active_pass_descriptor_];
+ [active_render_command_encoder_ retain];
+ active_command_encoder_type_ = MTL_RENDER_COMMAND_ENCODER;
+
+ /* Update command buffer encoder heuristics. */
+ this->register_encoder_counters();
+
+ /* Apply initial state. */
+ /* Update Viewport and Scissor State */
+ active_frame_buffer_->apply_state();
+
+ /* FLAG FRAMEBUFFER AS CLEARED -- A clear only lasts as long as one has been specified.
+ * After this, resets to Load attachments to parallel GL behavior. */
+ active_frame_buffer_->mark_cleared();
+
+ /* Reset RenderPassState to ensure resource bindings are re-applied. */
+ render_pass_state_.reset_state();
+
+ /* Return true as new pass started. */
+ *new_pass = true;
+ }
+ else {
+ /* No new pass. */
+ *new_pass = false;
+ }
+
+ BLI_assert(active_render_command_encoder_ != nil);
+ return active_render_command_encoder_;
+}
+
+id<MTLBlitCommandEncoder> MTLCommandBufferManager::ensure_begin_blit_encoder()
+{
+ /* Ensure active command buffer. */
+ id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
+ BLI_assert(cmd_buf);
+
+ /* Ensure no existing command encoder of a different type is active. */
+ if (active_command_encoder_type_ != MTL_BLIT_COMMAND_ENCODER) {
+ this->end_active_command_encoder();
+ }
+
+ /* Begin new Blit Encoder. */
+ if (active_blit_command_encoder_ == nil) {
+ active_blit_command_encoder_ = [cmd_buf blitCommandEncoder];
+ BLI_assert(active_blit_command_encoder_ != nil);
+ [active_blit_command_encoder_ retain];
+ active_command_encoder_type_ = MTL_BLIT_COMMAND_ENCODER;
+
+ /* Update command buffer encoder heuristics. */
+ this->register_encoder_counters();
+ }
+ BLI_assert(active_blit_command_encoder_ != nil);
+ return active_blit_command_encoder_;
+}
+
+id<MTLComputeCommandEncoder> MTLCommandBufferManager::ensure_begin_compute_encoder()
+{
+ /* Ensure active command buffer. */
+ id<MTLCommandBuffer> cmd_buf = this->ensure_begin();
+ BLI_assert(cmd_buf);
+
+ /* Ensure no existing command encoder of a different type is active. */
+ if (active_command_encoder_type_ != MTL_COMPUTE_COMMAND_ENCODER) {
+ this->end_active_command_encoder();
+ }
+
+ /* Begin new Compute Encoder. */
+ if (active_compute_command_encoder_ == nil) {
+ active_compute_command_encoder_ = [cmd_buf computeCommandEncoder];
+ BLI_assert(active_compute_command_encoder_ != nil);
+ [active_compute_command_encoder_ retain];
+ active_command_encoder_type_ = MTL_COMPUTE_COMMAND_ENCODER;
+
+ /* Update command buffer encoder heuristics. */
+ this->register_encoder_counters();
+ }
+ BLI_assert(active_compute_command_encoder_ != nil);
+ return active_compute_command_encoder_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Command buffer heuristics.
+ * \{ */
+
+/* Rendering Heuristics. */
+void MTLCommandBufferManager::register_draw_counters(int vertex_submission)
+{
+ current_draw_call_count_++;
+ vertex_submitted_count_ += vertex_submission;
+ empty_ = false;
+}
+
+/* Reset workload counters. */
+void MTLCommandBufferManager::reset_counters()
+{
+ empty_ = true;
+ current_draw_call_count_ = 0;
+ encoder_count_ = 0;
+ vertex_submitted_count_ = 0;
+}
+
+/* Workload evaluation. */
+bool MTLCommandBufferManager::do_break_submission()
+{
+ /* Skip if no active command buffer. */
+ if (active_command_buffer_ == nil) {
+ return false;
+ }
+
+ /* Use optimized heuristic to split heavy command buffer submissions to better saturate the
+ * hardware and also reduce stalling from individual large submissions. */
+ if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY) ||
+ GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ return ((current_draw_call_count_ > 30000) || (vertex_submitted_count_ > 100000000) ||
+ (encoder_count_ > 25));
+ }
+ else {
+ /* Apple Silicon is less efficient if splitting submissions. */
+ return false;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Command buffer debugging.
+ * \{ */
+
+/* Debug. */
+void MTLCommandBufferManager::push_debug_group(const char *name, int index)
+{
+ id<MTLCommandBuffer> cmd = this->ensure_begin();
+ if (cmd != nil) {
+ [cmd pushDebugGroup:[NSString stringWithFormat:@"%s_%d", name, index]];
+ }
+}
+
+void MTLCommandBufferManager::pop_debug_group()
+{
+ id<MTLCommandBuffer> cmd = this->ensure_begin();
+ if (cmd != nil) {
+ [cmd popDebugGroup];
+ }
+}
+
+/* Workload Synchronization. */
+bool MTLCommandBufferManager::insert_memory_barrier(eGPUBarrier barrier_bits,
+ eGPUStageBarrierBits before_stages,
+ eGPUStageBarrierBits after_stages)
+{
+ /* Only supporting Metal on 10.14 onward anyway - Check required for warnings. */
+ if (@available(macOS 10.14, *)) {
+
+ /* Resolve scope. */
+ MTLBarrierScope scope = 0;
+ if (barrier_bits & GPU_BARRIER_SHADER_IMAGE_ACCESS ||
+ barrier_bits & GPU_BARRIER_TEXTURE_FETCH) {
+ scope = scope | MTLBarrierScopeTextures | MTLBarrierScopeRenderTargets;
+ }
+ if (barrier_bits & GPU_BARRIER_SHADER_STORAGE ||
+ barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY ||
+ barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) {
+ scope = scope | MTLBarrierScopeBuffers;
+ }
+
+ if (scope != 0) {
+ /* Issue barrier based on encoder. */
+ switch (active_command_encoder_type_) {
+ case MTL_NO_COMMAND_ENCODER:
+ case MTL_BLIT_COMMAND_ENCODER: {
+ /* No barrier to be inserted. */
+ return false;
+ }
+
+ /* Rendering. */
+ case MTL_RENDER_COMMAND_ENCODER: {
+ /* Currently flagging both stages -- can use bits above to filter on stage type --
+ * though full barrier is safe for now*/
+ MTLRenderStages before_stage_flags = 0;
+ MTLRenderStages after_stage_flags = 0;
+ if (before_stages & GPU_BARRIER_STAGE_VERTEX &&
+ !(before_stages & GPU_BARRIER_STAGE_FRAGMENT)) {
+ before_stage_flags = before_stage_flags | MTLRenderStageVertex;
+ }
+ if (before_stages & GPU_BARRIER_STAGE_FRAGMENT) {
+ before_stage_flags = before_stage_flags | MTLRenderStageFragment;
+ }
+ if (after_stages & GPU_BARRIER_STAGE_VERTEX) {
+ after_stage_flags = after_stage_flags | MTLRenderStageVertex;
+ }
+ if (after_stages & GPU_BARRIER_STAGE_FRAGMENT) {
+ after_stage_flags = MTLRenderStageFragment;
+ }
+
+ id<MTLRenderCommandEncoder> rec = this->get_active_render_command_encoder();
+ BLI_assert(rec != nil);
+ [rec memoryBarrierWithScope:scope
+ afterStages:after_stage_flags
+ beforeStages:before_stage_flags];
+ return true;
+ }
+
+ /* Compute. */
+ case MTL_COMPUTE_COMMAND_ENCODER: {
+ id<MTLComputeCommandEncoder> rec = this->get_active_compute_command_encoder();
+ BLI_assert(rec != nil);
+ [rec memoryBarrierWithScope:scope];
+ return true;
+ }
+ }
+ }
+ }
+ /* No barrier support. */
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Render Pass State for active RenderCommandEncoder
+ * \{ */
+/* Reset binding state when a new RenderCommandEncoder is bound, to ensure
+ * pipeline resources are re-applied to the new Encoder.
+ * NOTE: In Metal, state is only persistent within an MTLCommandEncoder,
+ * not globally. */
+void MTLRenderPassState::reset_state()
+{
+ /* Reset Cached pipeline state. */
+ this->bound_pso = nil;
+ this->bound_ds_state = nil;
+
+ /* Clear shader binding. */
+ this->last_bound_shader_state.set(nullptr, 0);
+
+ /* Other states. */
+ MTLFrameBuffer *fb = this->cmd.get_active_framebuffer();
+ this->last_used_stencil_ref_value = 0;
+ this->last_scissor_rect = {0,
+ 0,
+ (uint)((fb != nullptr) ? fb->get_width() : 0),
+ (uint)((fb != nullptr) ? fb->get_height() : 0)};
+
+ /* Reset cached resource binding state */
+ for (int ubo = 0; ubo < MTL_MAX_UNIFORM_BUFFER_BINDINGS; ubo++) {
+ this->cached_vertex_buffer_bindings[ubo].is_bytes = false;
+ this->cached_vertex_buffer_bindings[ubo].metal_buffer = nil;
+ this->cached_vertex_buffer_bindings[ubo].offset = -1;
+
+ this->cached_fragment_buffer_bindings[ubo].is_bytes = false;
+ this->cached_fragment_buffer_bindings[ubo].metal_buffer = nil;
+ this->cached_fragment_buffer_bindings[ubo].offset = -1;
+ }
+
+ /* Reset cached texture and sampler state binding state. */
+ for (int tex = 0; tex < MTL_MAX_TEXTURE_SLOTS; tex++) {
+ this->cached_vertex_texture_bindings[tex].metal_texture = nil;
+ this->cached_vertex_sampler_state_bindings[tex].sampler_state = nil;
+ this->cached_vertex_sampler_state_bindings[tex].is_arg_buffer_binding = false;
+
+ this->cached_fragment_texture_bindings[tex].metal_texture = nil;
+ this->cached_fragment_sampler_state_bindings[tex].sampler_state = nil;
+ this->cached_fragment_sampler_state_bindings[tex].is_arg_buffer_binding = false;
+ }
+}
+
+/* Bind Texture to current RenderCommandEncoder. */
+void MTLRenderPassState::bind_vertex_texture(id<MTLTexture> tex, uint slot)
+{
+ if (this->cached_vertex_texture_bindings[slot].metal_texture != tex) {
+ id<MTLRenderCommandEncoder> rec = this->cmd.get_active_render_command_encoder();
+ BLI_assert(rec != nil);
+ [rec setVertexTexture:tex atIndex:slot];
+ this->cached_vertex_texture_bindings[slot].metal_texture = tex;
+ }
+}
+
+void MTLRenderPassState::bind_fragment_texture(id<MTLTexture> tex, uint slot)
+{
+ if (this->cached_fragment_texture_bindings[slot].metal_texture != tex) {
+ id<MTLRenderCommandEncoder> rec = this->cmd.get_active_render_command_encoder();
+ BLI_assert(rec != nil);
+ [rec setFragmentTexture:tex atIndex:slot];
+ this->cached_fragment_texture_bindings[slot].metal_texture = tex;
+ }
+}
+
+void MTLRenderPassState::bind_vertex_sampler(MTLSamplerBinding &sampler_binding,
+ bool use_argument_buffer_for_samplers,
+ uint slot)
+{
+ /* TODO(Metal): Implement RenderCommandEncoder vertex sampler binding utility. This will be
+ * implemented alongside MTLShader. */
+}
+
+void MTLRenderPassState::bind_fragment_sampler(MTLSamplerBinding &sampler_binding,
+ bool use_argument_buffer_for_samplers,
+ uint slot)
+{
+ /* TODO(Metal): Implement RenderCommandEncoder fragment sampler binding utility. This will be
+ * implemented alongside MTLShader. */
+}
+
+void MTLRenderPassState::bind_vertex_buffer(id<MTLBuffer> buffer, uint buffer_offset, uint index)
+{
+ /* TODO(Metal): Implement RenderCommandEncoder vertex buffer binding utility. This will be
+ * implemented alongside the full MTLMemoryManager. */
+}
+
+void MTLRenderPassState::bind_fragment_buffer(id<MTLBuffer> buffer, uint buffer_offset, uint index)
+{
+ /* TODO(Metal): Implement RenderCommandEncoder fragment buffer binding utility. This will be
+ * implemented alongside the full MTLMemoryManager. */
+}
+
+void MTLRenderPassState::bind_vertex_bytes(void *bytes, uint length, uint index)
+{
+ /* TODO(Metal): Implement RenderCommandEncoder vertex bytes binding utility. This will be
+ * implemented alongside the full MTLMemoryManager. */
+}
+
+void MTLRenderPassState::bind_fragment_bytes(void *bytes, uint length, uint index)
+{
+ /* TODO(Metal): Implement RenderCommandEncoder fragment bytes binding utility. This will be
+ * implemented alongside the full MTLMemoryManager. */
+}
+
+/** \} */
+
+} // blender::gpu
diff --git a/source/blender/gpu/metal/mtl_common.hh b/source/blender/gpu/metal/mtl_common.hh
index aa60d3aff61..44ba786f90f 100644
--- a/source/blender/gpu/metal/mtl_common.hh
+++ b/source/blender/gpu/metal/mtl_common.hh
@@ -4,7 +4,13 @@
#define __MTL_COMMON
// -- Renderer Options --
+#define MTL_MAX_DRAWABLES 3
#define MTL_MAX_SET_BYTES_SIZE 4096
#define MTL_FORCE_WAIT_IDLE 0
+#define MTL_MAX_COMMAND_BUFFERS 64
+
+/* Number of frames for which we retain in-flight resources such as scratch buffers.
+ * Set as number of GPU frames in flight, plus an additional value for extra possible CPU frame. */
+#define MTL_NUM_SAFE_FRAMES (MTL_MAX_DRAWABLES + 1)
#endif
diff --git a/source/blender/gpu/metal/mtl_context.hh b/source/blender/gpu/metal/mtl_context.hh
index 1849a04ea48..0db87bf5da5 100644
--- a/source/blender/gpu/metal/mtl_context.hh
+++ b/source/blender/gpu/metal/mtl_context.hh
@@ -3,6 +3,9 @@
/** \file
* \ingroup gpu
*/
+
+#pragma once
+
#include "MEM_guardedalloc.h"
#include "gpu_context_private.hh"
@@ -10,7 +13,11 @@
#include "GPU_common_types.h"
#include "GPU_context.h"
+#include "mtl_backend.hh"
#include "mtl_capabilities.hh"
+#include "mtl_common.hh"
+#include "mtl_framebuffer.hh"
+#include "mtl_memory.hh"
#include "mtl_texture.hh"
#include <Cocoa/Cocoa.h>
@@ -23,12 +30,117 @@
namespace blender::gpu {
+/* Forward Declarations */
+class MTLContext;
+class MTLCommandBufferManager;
class MTLShader;
class MTLUniformBuf;
-class MTLBuffer;
+
+/* Structs containing information on current binding state for textures and samplers. */
+struct MTLTextureBinding {
+ bool used;
+
+ /* Same value as index in bindings array. */
+ uint texture_slot_index;
+ gpu::MTLTexture *texture_resource;
+};
+
+struct MTLSamplerBinding {
+ bool used;
+ MTLSamplerState state;
+
+ bool operator==(MTLSamplerBinding const &other) const
+ {
+ return (used == other.used && state == other.state);
+ }
+};
+
+/* Metal Context Render Pass State -- Used to track active RenderCommandEncoder state based on
+ * bound MTLFrameBuffer's.Owned by MTLContext. */
+struct MTLRenderPassState {
+ friend class MTLContext;
+
+ MTLRenderPassState(MTLContext &context, MTLCommandBufferManager &command_buffer_manager)
+ : ctx(context), cmd(command_buffer_manager){};
+
+ /* Given a RenderPassState is associated with a live RenderCommandEncoder,
+ * this state sits within the MTLCommandBufferManager. */
+ MTLContext &ctx;
+ MTLCommandBufferManager &cmd;
+
+ /* Caching of resource bindings for active MTLRenderCommandEncoder.
+ * In Metal, resource bindings are local to the MTLCommandEncoder,
+ * not globally to the whole pipeline/cmd buffer. */
+ struct MTLBoundShaderState {
+ MTLShader *shader_ = nullptr;
+ uint pso_index_;
+ void set(MTLShader *shader, uint pso_index)
+ {
+ shader_ = shader;
+ pso_index_ = pso_index;
+ }
+ };
+
+ MTLBoundShaderState last_bound_shader_state;
+ id<MTLRenderPipelineState> bound_pso = nil;
+ id<MTLDepthStencilState> bound_ds_state = nil;
+ uint last_used_stencil_ref_value = 0;
+ MTLScissorRect last_scissor_rect;
+
+ /* Caching of CommandEncoder Vertex/Fragment buffer bindings. */
+ struct BufferBindingCached {
+ /* Whether the given binding slot uses byte data (Push Constant equivalent)
+ * or an MTLBuffer. */
+ bool is_bytes;
+ id<MTLBuffer> metal_buffer;
+ int offset;
+ };
+
+ BufferBindingCached cached_vertex_buffer_bindings[MTL_MAX_UNIFORM_BUFFER_BINDINGS];
+ BufferBindingCached cached_fragment_buffer_bindings[MTL_MAX_UNIFORM_BUFFER_BINDINGS];
+
+ /* Caching of CommandEncoder textures bindings. */
+ struct TextureBindingCached {
+ id<MTLTexture> metal_texture;
+ };
+
+ TextureBindingCached cached_vertex_texture_bindings[MTL_MAX_TEXTURE_SLOTS];
+ TextureBindingCached cached_fragment_texture_bindings[MTL_MAX_TEXTURE_SLOTS];
+
+ /* Cached of CommandEncoder sampler states. */
+ struct SamplerStateBindingCached {
+ MTLSamplerState binding_state;
+ id<MTLSamplerState> sampler_state;
+ bool is_arg_buffer_binding;
+ };
+
+ SamplerStateBindingCached cached_vertex_sampler_state_bindings[MTL_MAX_TEXTURE_SLOTS];
+ SamplerStateBindingCached cached_fragment_sampler_state_bindings[MTL_MAX_TEXTURE_SLOTS];
+
+ /* Reset RenderCommandEncoder binding state. */
+ void reset_state();
+
+ /* Texture Binding (RenderCommandEncoder). */
+ void bind_vertex_texture(id<MTLTexture> tex, uint slot);
+ void bind_fragment_texture(id<MTLTexture> tex, uint slot);
+
+ /* Sampler Binding (RenderCommandEncoder). */
+ void bind_vertex_sampler(MTLSamplerBinding &sampler_binding,
+ bool use_argument_buffer_for_samplers,
+ uint slot);
+ void bind_fragment_sampler(MTLSamplerBinding &sampler_binding,
+ bool use_argument_buffer_for_samplers,
+ uint slot);
+
+ /* Buffer binding (RenderCommandEncoder). */
+ void bind_vertex_buffer(id<MTLBuffer> buffer, uint buffer_offset, uint index);
+ void bind_fragment_buffer(id<MTLBuffer> buffer, uint buffer_offset, uint index);
+ void bind_vertex_bytes(void *bytes, uint length, uint index);
+ void bind_fragment_bytes(void *bytes, uint length, uint index);
+};
/* Depth Stencil State */
-typedef struct MTLContextDepthStencilState {
+struct MTLContextDepthStencilState {
/* Depth State. */
bool depth_write_enable;
@@ -44,9 +156,9 @@ typedef struct MTLContextDepthStencilState {
/* Stencil State. */
bool stencil_test_enabled;
- unsigned int stencil_read_mask;
- unsigned int stencil_write_mask;
- unsigned int stencil_ref;
+ uint stencil_read_mask;
+ uint stencil_write_mask;
+ uint stencil_ref;
MTLCompareFunction stencil_func;
MTLStencilOperation stencil_op_front_stencil_fail;
@@ -65,7 +177,7 @@ typedef struct MTLContextDepthStencilState {
/* TODO(Metal): Consider optimizing this function using memcmp.
* Un-used, but differing, stencil state leads to over-generation
* of state objects when doing trivial compare. */
- inline bool operator==(const MTLContextDepthStencilState &other) const
+ bool operator==(const MTLContextDepthStencilState &other) const
{
bool depth_state_equality = (has_depth_target == other.has_depth_target &&
depth_write_enable == other.depth_write_enable &&
@@ -98,7 +210,7 @@ typedef struct MTLContextDepthStencilState {
* - setStencilReferenceValue:
* - setDepthBias:slopeScale:clamp:
*/
- inline std::size_t hash() const
+ std::size_t hash() const
{
std::size_t boolean_bitmask = (this->depth_write_enable ? 1 : 0) |
((this->depth_test_enabled ? 1 : 0) << 1) |
@@ -127,9 +239,9 @@ typedef struct MTLContextDepthStencilState {
std::size_t final_hash = (main_hash << 8) | boolean_bitmask;
return final_hash;
}
-} MTLContextDepthStencilState;
+};
-typedef struct MTLContextTextureUtils {
+struct MTLContextTextureUtils {
/* Depth Update Utilities */
/* Depth texture updates are not directly supported with Blit operations, similarly, we cannot
@@ -174,8 +286,7 @@ typedef struct MTLContextTextureUtils {
blender::Map<TextureUpdateRoutineSpecialisation, id<MTLComputePipelineState>>
texture_buffer_update_compute_psos;
- template<typename T>
- inline void free_cached_pso_map(blender::Map<T, id<MTLComputePipelineState>> &map)
+ template<typename T> void free_cached_pso_map(blender::Map<T, id<MTLComputePipelineState>> &map)
{
for (typename blender::Map<T, id<MTLComputePipelineState>>::MutableItem item : map.items()) {
[item.value release];
@@ -183,12 +294,12 @@ typedef struct MTLContextTextureUtils {
map.clear();
}
- inline void init()
+ void init()
{
fullscreen_blit_shader = nullptr;
}
- inline void cleanup()
+ void cleanup()
{
if (fullscreen_blit_shader) {
GPU_shader_free(fullscreen_blit_shader);
@@ -213,37 +324,16 @@ typedef struct MTLContextTextureUtils {
free_cached_pso_map(texture_cube_array_update_compute_psos);
free_cached_pso_map(texture_buffer_update_compute_psos);
}
-
-} MTLContextTextureUtils;
-
-/* Structs containing information on current binding state for textures and samplers. */
-typedef struct MTLTextureBinding {
- bool used;
-
- /* Same value as index in bindings array. */
- unsigned int texture_slot_index;
- gpu::MTLTexture *texture_resource;
-
-} MTLTextureBinding;
-
-typedef struct MTLSamplerBinding {
- bool used;
- MTLSamplerState state;
-
- bool operator==(MTLSamplerBinding const &other) const
- {
- return (used == other.used && state == other.state);
- }
-} MTLSamplerBinding;
+};
/* Combined sampler state configuration for Argument Buffer caching. */
struct MTLSamplerArray {
- unsigned int num_samplers;
+ uint num_samplers;
/* MTLSamplerState permutations between 0..256 - slightly more than a byte. */
MTLSamplerState mtl_sampler_flags[MTL_MAX_TEXTURE_SLOTS];
id<MTLSamplerState> mtl_sampler[MTL_MAX_TEXTURE_SLOTS];
- inline bool operator==(const MTLSamplerArray &other) const
+ bool operator==(const MTLSamplerArray &other) const
{
if (this->num_samplers != other.num_samplers) {
return false;
@@ -253,7 +343,7 @@ struct MTLSamplerArray {
sizeof(MTLSamplerState) * this->num_samplers) == 0);
}
- inline uint32_t hash() const
+ uint32_t hash() const
{
uint32_t hash = this->num_samplers;
for (int i = 0; i < this->num_samplers; i++) {
@@ -287,12 +377,12 @@ typedef enum MTLPipelineStateDirtyFlag {
/* Ignore full flag bit-mask `MTL_PIPELINE_STATE_ALL_FLAG`. */
ENUM_OPERATORS(MTLPipelineStateDirtyFlag, MTL_PIPELINE_STATE_CULLMODE_FLAG);
-typedef struct MTLUniformBufferBinding {
+struct MTLUniformBufferBinding {
bool bound;
MTLUniformBuf *ubo;
-} MTLUniformBufferBinding;
+};
-typedef struct MTLContextGlobalShaderPipelineState {
+struct MTLContextGlobalShaderPipelineState {
bool initialised;
/* Whether the pipeline state has been modified since application.
@@ -358,20 +448,120 @@ typedef struct MTLContextGlobalShaderPipelineState {
/* Render parameters. */
float point_size = 1.0f;
float line_width = 1.0f;
+};
-} MTLContextGlobalShaderPipelineState;
+/* Command Buffer Manager - Owned by MTLContext.
+ * The MTLCommandBufferManager represents all work associated with
+ * a command buffer of a given identity. This manager is a fixed-state
+ * on the context, which coordinates the lifetime of command buffers
+ * for particular categories of work.
+ *
+ * This ensures operations on command buffers, and the state associated,
+ * is correctly tracked and managed. Workload submission and MTLCommandEncoder
+ * coordination is managed from here.
+ *
+ * There is currently only one MTLCommandBufferManager for managing submission
+ * of the "main" rendering commands. A secondary upload command buffer track,
+ * or asynchronous compute command buffer track may be added in the future. */
+class MTLCommandBufferManager {
+ friend class MTLContext;
-/* Metal Buffer */
-typedef struct MTLTemporaryBufferRange {
- id<MTLBuffer> metal_buffer;
- void *host_ptr;
- unsigned long long buffer_offset;
- unsigned long long size;
- MTLResourceOptions options;
+ public:
+ /* Event to coordinate sequential execution across all "main" command buffers. */
+ static id<MTLEvent> sync_event;
+ static uint64_t event_signal_val;
+
+ /* Counter for active command buffers. */
+ static int num_active_cmd_bufs;
+
+ private:
+ /* Associated Context and properties. */
+ MTLContext &context_;
+ bool supports_render_ = false;
+
+ /* CommandBuffer tracking. */
+ id<MTLCommandBuffer> active_command_buffer_ = nil;
+ id<MTLCommandBuffer> last_submitted_command_buffer_ = nil;
+
+ /* Active MTLCommandEncoders. */
+ enum {
+ MTL_NO_COMMAND_ENCODER = 0,
+ MTL_RENDER_COMMAND_ENCODER = 1,
+ MTL_BLIT_COMMAND_ENCODER = 2,
+ MTL_COMPUTE_COMMAND_ENCODER = 3
+ } active_command_encoder_type_ = MTL_NO_COMMAND_ENCODER;
+
+ id<MTLRenderCommandEncoder> active_render_command_encoder_ = nil;
+ id<MTLBlitCommandEncoder> active_blit_command_encoder_ = nil;
+ id<MTLComputeCommandEncoder> active_compute_command_encoder_ = nil;
+
+ /* State associated with active RenderCommandEncoder. */
+ MTLRenderPassState render_pass_state_;
+ MTLFrameBuffer *active_frame_buffer_ = nullptr;
+ MTLRenderPassDescriptor *active_pass_descriptor_ = nullptr;
+
+ /* Workload heuristics - We may need to split command buffers to optimize workload and balancing.
+ */
+ int current_draw_call_count_ = 0;
+ int encoder_count_ = 0;
+ int vertex_submitted_count_ = 0;
+ bool empty_ = true;
- void flush();
- bool requires_flush();
-} MTLTemporaryBufferRange;
+ public:
+ MTLCommandBufferManager(MTLContext &context)
+ : context_(context), render_pass_state_(context, *this){};
+ void prepare(bool supports_render = true);
+
+ /* If wait is true, CPU will stall until GPU work has completed. */
+ bool submit(bool wait);
+
+ /* Fetch/query current encoder. */
+ bool is_inside_render_pass();
+ bool is_inside_blit();
+ bool is_inside_compute();
+ id<MTLRenderCommandEncoder> get_active_render_command_encoder();
+ id<MTLBlitCommandEncoder> get_active_blit_command_encoder();
+ id<MTLComputeCommandEncoder> get_active_compute_command_encoder();
+ MTLFrameBuffer *get_active_framebuffer();
+
+ /* RenderPassState for RenderCommandEncoder. */
+ MTLRenderPassState &get_render_pass_state()
+ {
+ /* Render pass state should only be valid if we are inside a render pass. */
+ BLI_assert(this->is_inside_render_pass());
+ return render_pass_state_;
+ }
+
+ /* Rendering Heuristics. */
+ void register_draw_counters(int vertex_submission);
+ void reset_counters();
+ bool do_break_submission();
+
+ /* Encoder and Pass management. */
+ /* End currently active MTLCommandEncoder. */
+ bool end_active_command_encoder();
+ id<MTLRenderCommandEncoder> ensure_begin_render_command_encoder(MTLFrameBuffer *ctx_framebuffer,
+ bool force_begin,
+ bool *new_pass);
+ id<MTLBlitCommandEncoder> ensure_begin_blit_encoder();
+ id<MTLComputeCommandEncoder> ensure_begin_compute_encoder();
+
+ /* Workload Synchronization. */
+ bool insert_memory_barrier(eGPUBarrier barrier_bits,
+ eGPUStageBarrierBits before_stages,
+ eGPUStageBarrierBits after_stages);
+ /* TODO(Metal): Support fences in command buffer class. */
+
+ /* Debug. */
+ void push_debug_group(const char *name, int index);
+ void pop_debug_group();
+
+ private:
+ /* Begin new command buffer. */
+ id<MTLCommandBuffer> ensure_begin();
+
+ void register_encoder_counters();
+};
/** MTLContext -- Core render loop and state management. **/
/* NOTE(Metal): Partial MTLContext stub to provide wrapper functionality
@@ -386,7 +576,7 @@ class MTLContext : public Context {
/* Texture Samplers. */
/* Cache of generated MTLSamplerState objects based on permutations of `eGPUSamplerState`. */
- id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_MAX] = {0};
+ id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_MAX];
id<MTLSamplerState> default_sampler_state_ = nil;
/* When texture sampler count exceeds the resource bind limit, an
@@ -397,6 +587,14 @@ class MTLContext : public Context {
MTLSamplerArray samplers_;
blender::Map<MTLSamplerArray, gpu::MTLBuffer *> cached_sampler_buffers_;
+ /* Frame. */
+ bool is_inside_frame_ = false;
+ uint current_frame_index_;
+
+ /* Visibility buffer for MTLQuery results. */
+ gpu::MTLBuffer *visibility_buffer_ = nullptr;
+ bool visibility_is_dirty_ = false;
+
public:
/* Shaders and Pipeline state. */
MTLContextGlobalShaderPipelineState pipeline_state;
@@ -405,22 +603,36 @@ class MTLContext : public Context {
id<MTLCommandQueue> queue = nil;
id<MTLDevice> device = nil;
+ /* Memory Management */
+ MTLScratchBufferManager memory_manager;
+ static MTLBufferPool global_memory_manager;
+
+ /* CommandBuffer managers. */
+ MTLCommandBufferManager main_command_buffer;
+
/* GPUContext interface. */
MTLContext(void *ghost_window);
~MTLContext();
static void check_error(const char *info);
- void activate(void) override;
- void deactivate(void) override;
+ void activate() override;
+ void deactivate() override;
+ void begin_frame() override;
+ void end_frame() 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;
+ static MTLContext *get()
+ {
+ return static_cast<MTLContext *>(Context::get());
+ }
+
void debug_group_begin(const char *name, int index) override;
- void debug_group_end(void) override;
+ void debug_group_end() override;
/*** MTLContext Utility functions. */
/*
@@ -428,37 +640,79 @@ class MTLContext : public Context {
* rendering, binding resources, setting global state, resource management etc;
*/
- /* Metal Context Core functions. */
- /* Command Buffer Management. */
- id<MTLCommandBuffer> get_active_command_buffer();
+ /** Metal Context Core functions. **/
+
+ /* Bind frame-buffer to context. */
+ void framebuffer_bind(MTLFrameBuffer *framebuffer);
- /* Render Pass State and Management. */
- void begin_render_pass();
- void end_render_pass();
- bool is_render_pass_active();
+ /* Restore frame-buffer used by active context to default back-buffer. */
+ void framebuffer_restore();
- /* Texture Binding. */
- void texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture_unit);
- void sampler_bind(MTLSamplerState, unsigned int sampler_unit);
+ /* Ensure a render-pass using the Context frame-buffer (active_fb_) is in progress. */
+ id<MTLRenderCommandEncoder> ensure_begin_render_pass();
+
+ MTLFrameBuffer *get_current_framebuffer();
+ MTLFrameBuffer *get_default_framebuffer();
+
+ /* Context Global-State Texture Binding. */
+ void texture_bind(gpu::MTLTexture *mtl_texture, uint texture_unit);
+ void sampler_bind(MTLSamplerState, uint sampler_unit);
void texture_unbind(gpu::MTLTexture *mtl_texture);
- void texture_unbind_all(void);
+ void texture_unbind_all();
id<MTLSamplerState> get_sampler_from_state(MTLSamplerState state);
id<MTLSamplerState> generate_sampler_from_state(MTLSamplerState state);
id<MTLSamplerState> get_default_sampler_state();
/* Metal Context pipeline state. */
- void pipeline_state_init(void);
- MTLShader *get_active_shader(void);
+ void pipeline_state_init();
+ MTLShader *get_active_shader();
/* State assignment. */
void set_viewport(int origin_x, int origin_y, int width, int height);
void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height);
void set_scissor_enabled(bool scissor_enabled);
+ /* Visibility buffer control. */
+ void set_visibility_buffer(gpu::MTLBuffer *buffer);
+ gpu::MTLBuffer *get_visibility_buffer() const;
+
+ /* Flag whether the visibility buffer for query results
+ * has changed. This requires a new RenderPass in order
+ * to update.*/
+ bool is_visibility_dirty() const;
+
+ /* Reset dirty flag state for visibility buffer. */
+ void clear_visibility_dirty();
+
/* Texture utilities. */
MTLContextTextureUtils &get_texture_utils()
{
- return this->texture_utils_;
+ return texture_utils_;
+ }
+
+ bool get_active()
+ {
+ return is_active_;
+ }
+
+ bool get_inside_frame()
+ {
+ return is_inside_frame_;
+ }
+
+ uint get_current_frame_index()
+ {
+ return current_frame_index_;
+ }
+
+ MTLScratchBufferManager &get_scratchbuffer_manager()
+ {
+ return this->memory_manager;
+ }
+
+ static MTLBufferPool &get_global_memory_manager()
+ {
+ return MTLContext::global_memory_manager;
}
};
diff --git a/source/blender/gpu/metal/mtl_context.mm b/source/blender/gpu/metal/mtl_context.mm
index 94f5682b11b..26cfe6632ef 100644
--- a/source/blender/gpu/metal/mtl_context.mm
+++ b/source/blender/gpu/metal/mtl_context.mm
@@ -16,48 +16,105 @@ using namespace blender::gpu;
namespace blender::gpu {
-/* -------------------------------------------------------------------- */
-/** \name Memory Management
- * \{ */
-
-bool MTLTemporaryBufferRange::requires_flush()
-{
- /* We do not need to flush shared memory */
- return this->options & MTLResourceStorageModeManaged;
-}
-
-void MTLTemporaryBufferRange::flush()
-{
- if (this->requires_flush()) {
- BLI_assert(this->metal_buffer);
- BLI_assert((this->buffer_offset + this->size) <= [this->metal_buffer length]);
- BLI_assert(this->buffer_offset >= 0);
- [this->metal_buffer
- didModifyRange:NSMakeRange(this->buffer_offset, this->size - this->buffer_offset)];
- }
-}
-
-/** \} */
+/* Global memory manager. */
+MTLBufferPool MTLContext::global_memory_manager;
/* -------------------------------------------------------------------- */
/** \name MTLContext
* \{ */
/* Placeholder functions */
-MTLContext::MTLContext(void *ghost_window)
+MTLContext::MTLContext(void *ghost_window) : memory_manager(*this), main_command_buffer(*this)
{
/* Init debug. */
debug::mtl_debug_init();
+ /* Initialize command buffer state. */
+ this->main_command_buffer.prepare();
+
+ /* Frame management. */
+ is_inside_frame_ = false;
+ current_frame_index_ = 0;
+
+ /* Create FrameBuffer handles. */
+ MTLFrameBuffer *mtl_front_left = new MTLFrameBuffer(this, "front_left");
+ MTLFrameBuffer *mtl_back_left = new MTLFrameBuffer(this, "back_left");
+ this->front_left = mtl_front_left;
+ this->back_left = mtl_back_left;
+ this->active_fb = this->back_left;
+ /* Prepare platform and capabilities. (NOTE: With METAL, this needs to be done after CTX
+ * initialization). */
+ MTLBackend::platform_init(this);
+ MTLBackend::capabilities_init(this);
+
/* Initialize Metal modules. */
+ this->memory_manager.init();
this->state_manager = new MTLStateManager(this);
- /* TODO(Metal): Implement. */
+ /* Ensure global memory manager is initialized. */
+ MTLContext::global_memory_manager.init(this->device);
+
+ /* Initialize texture read/update structures. */
+ this->get_texture_utils().init();
+
+ /* Bound Samplers struct. */
+ for (int i = 0; i < MTL_MAX_TEXTURE_SLOTS; i++) {
+ samplers_.mtl_sampler[i] = nil;
+ samplers_.mtl_sampler_flags[i] = DEFAULT_SAMPLER_STATE;
+ }
+
+ /* Initialize samplers. */
+ for (uint i = 0; i < GPU_SAMPLER_MAX; i++) {
+ MTLSamplerState state;
+ state.state = static_cast<eGPUSamplerState>(i);
+ sampler_state_cache_[i] = this->generate_sampler_from_state(state);
+ }
}
MTLContext::~MTLContext()
{
- /* TODO(Metal): Implement. */
+ BLI_assert(this == reinterpret_cast<MTLContext *>(GPU_context_active_get()));
+ /* Ensure rendering is complete command encoders/command buffers are freed. */
+ if (MTLBackend::get()->is_inside_render_boundary()) {
+ this->finish();
+
+ /* End frame. */
+ if (this->get_inside_frame()) {
+ this->end_frame();
+ }
+ }
+ /* Release update/blit shaders. */
+ this->get_texture_utils().cleanup();
+
+ /* Release Sampler States. */
+ for (int i = 0; i < GPU_SAMPLER_MAX; i++) {
+ if (sampler_state_cache_[i] != nil) {
+ [sampler_state_cache_[i] release];
+ sampler_state_cache_[i] = nil;
+ }
+ }
+}
+
+void MTLContext::begin_frame()
+{
+ BLI_assert(MTLBackend::get()->is_inside_render_boundary());
+ if (this->get_inside_frame()) {
+ return;
+ }
+
+ /* Begin Command buffer for next frame. */
+ is_inside_frame_ = true;
+}
+
+void MTLContext::end_frame()
+{
+ BLI_assert(this->get_inside_frame());
+
+ /* Ensure pre-present work is committed. */
+ this->flush();
+
+ /* Increment frame counter. */
+ is_inside_frame_ = false;
}
void MTLContext::check_error(const char *info)
@@ -65,20 +122,20 @@ void MTLContext::check_error(const char *info)
/* TODO(Metal): Implement. */
}
-void MTLContext::activate(void)
+void MTLContext::activate()
{
/* TODO(Metal): Implement. */
}
-void MTLContext::deactivate(void)
+void MTLContext::deactivate()
{
/* TODO(Metal): Implement. */
}
-void MTLContext::flush(void)
+void MTLContext::flush()
{
/* TODO(Metal): Implement. */
}
-void MTLContext::finish(void)
+void MTLContext::finish()
{
/* TODO(Metal): Implement. */
}
@@ -90,26 +147,84 @@ void MTLContext::memory_statistics_get(int *total_mem, int *free_mem)
*free_mem = 0;
}
-id<MTLCommandBuffer> MTLContext::get_active_command_buffer()
+void MTLContext::framebuffer_bind(MTLFrameBuffer *framebuffer)
{
- /* TODO(Metal): Implement. */
- return nil;
+ /* We do not yet begin the pass -- We defer beginning the pass until a draw is requested. */
+ BLI_assert(framebuffer);
+ this->active_fb = framebuffer;
}
-/* Render Pass State and Management */
-void MTLContext::begin_render_pass()
+void MTLContext::framebuffer_restore()
{
- /* TODO(Metal): Implement. */
+ /* Bind default framebuffer from context --
+ * We defer beginning the pass until a draw is requested. */
+ this->active_fb = this->back_left;
}
-void MTLContext::end_render_pass()
+
+id<MTLRenderCommandEncoder> MTLContext::ensure_begin_render_pass()
{
- /* TODO(Metal): Implement. */
+ BLI_assert(this);
+
+ /* Ensure the rendering frame has started. */
+ if (!this->get_inside_frame()) {
+ this->begin_frame();
+ }
+
+ /* Check whether a framebuffer is bound. */
+ if (!this->active_fb) {
+ BLI_assert(false && "No framebuffer is bound!");
+ return this->main_command_buffer.get_active_render_command_encoder();
+ }
+
+ /* Ensure command buffer workload submissions are optimal --
+ * Though do not split a batch mid-IMM recording */
+ /* TODO(Metal): Add IMM Check once MTLImmediate has been implemented. */
+ if (this->main_command_buffer.do_break_submission()/*&&
+ !((MTLImmediate *)(this->imm))->imm_is_recording()*/) {
+ this->flush();
+ }
+
+ /* Begin pass or perform a pass switch if the active framebuffer has been changed, or if the
+ * framebuffer state has been modified (is_dirty). */
+ if (!this->main_command_buffer.is_inside_render_pass() ||
+ this->active_fb != this->main_command_buffer.get_active_framebuffer() ||
+ this->main_command_buffer.get_active_framebuffer()->get_dirty() ||
+ this->is_visibility_dirty()) {
+
+ /* Validate bound framebuffer before beginning render pass. */
+ if (!static_cast<MTLFrameBuffer *>(this->active_fb)->validate_render_pass()) {
+ MTL_LOG_WARNING("Framebuffer validation failed, falling back to default framebuffer\n");
+ this->framebuffer_restore();
+
+ if (!static_cast<MTLFrameBuffer *>(this->active_fb)->validate_render_pass()) {
+ MTL_LOG_ERROR("CRITICAL: DEFAULT FRAMEBUFFER FAIL VALIDATION!!\n");
+ }
+ }
+
+ /* Begin RenderCommandEncoder on main CommandBuffer. */
+ bool new_render_pass = false;
+ id<MTLRenderCommandEncoder> new_enc =
+ this->main_command_buffer.ensure_begin_render_command_encoder(
+ static_cast<MTLFrameBuffer *>(this->active_fb), true, &new_render_pass);
+ if (new_render_pass) {
+ /* Flag context pipeline state as dirty - dynamic pipeline state need re-applying. */
+ this->pipeline_state.dirty_flags = MTL_PIPELINE_STATE_ALL_FLAG;
+ }
+ return new_enc;
+ }
+ BLI_assert(!this->main_command_buffer.get_active_framebuffer()->get_dirty());
+ return this->main_command_buffer.get_active_render_command_encoder();
}
-bool MTLContext::is_render_pass_active()
+MTLFrameBuffer *MTLContext::get_current_framebuffer()
{
- /* TODO(Metal): Implement. */
- return false;
+ MTLFrameBuffer *last_bound = static_cast<MTLFrameBuffer *>(this->active_fb);
+ return last_bound ? last_bound : this->get_default_framebuffer();
+}
+
+MTLFrameBuffer *MTLContext::get_default_framebuffer()
+{
+ return static_cast<MTLFrameBuffer *>(this->back_left);
}
/** \} */
@@ -200,13 +315,107 @@ void MTLContext::pipeline_state_init()
MTLStencilOperationKeep;
}
+void MTLContext::set_viewport(int origin_x, int origin_y, int width, int height)
+{
+ BLI_assert(this);
+ BLI_assert(width > 0);
+ BLI_assert(height > 0);
+ BLI_assert(origin_x >= 0);
+ BLI_assert(origin_y >= 0);
+ bool changed = (this->pipeline_state.viewport_offset_x != origin_x) ||
+ (this->pipeline_state.viewport_offset_y != origin_y) ||
+ (this->pipeline_state.viewport_width != width) ||
+ (this->pipeline_state.viewport_height != height);
+ this->pipeline_state.viewport_offset_x = origin_x;
+ this->pipeline_state.viewport_offset_y = origin_y;
+ this->pipeline_state.viewport_width = width;
+ this->pipeline_state.viewport_height = height;
+ if (changed) {
+ this->pipeline_state.dirty_flags = (this->pipeline_state.dirty_flags |
+ MTL_PIPELINE_STATE_VIEWPORT_FLAG);
+ }
+}
+
+void MTLContext::set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height)
+{
+ BLI_assert(this);
+ bool changed = (this->pipeline_state.scissor_x != scissor_x) ||
+ (this->pipeline_state.scissor_y != scissor_y) ||
+ (this->pipeline_state.scissor_width != scissor_width) ||
+ (this->pipeline_state.scissor_height != scissor_height) ||
+ (this->pipeline_state.scissor_enabled != true);
+ this->pipeline_state.scissor_x = scissor_x;
+ this->pipeline_state.scissor_y = scissor_y;
+ this->pipeline_state.scissor_width = scissor_width;
+ this->pipeline_state.scissor_height = scissor_height;
+ this->pipeline_state.scissor_enabled = (scissor_width > 0 && scissor_height > 0);
+
+ if (changed) {
+ this->pipeline_state.dirty_flags = (this->pipeline_state.dirty_flags |
+ MTL_PIPELINE_STATE_SCISSOR_FLAG);
+ }
+}
+
+void MTLContext::set_scissor_enabled(bool scissor_enabled)
+{
+ /* Only turn on Scissor if requested scissor region is valid */
+ scissor_enabled = scissor_enabled && (this->pipeline_state.scissor_width > 0 &&
+ this->pipeline_state.scissor_height > 0);
+
+ bool changed = (this->pipeline_state.scissor_enabled != scissor_enabled);
+ this->pipeline_state.scissor_enabled = scissor_enabled;
+ if (changed) {
+ this->pipeline_state.dirty_flags = (this->pipeline_state.dirty_flags |
+ MTL_PIPELINE_STATE_SCISSOR_FLAG);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Visibility buffer control for MTLQueryPool.
+ * \{ */
+
+void MTLContext::set_visibility_buffer(gpu::MTLBuffer *buffer)
+{
+ /* Flag visibility buffer as dirty if the buffer being used for visibility has changed --
+ * This is required by the render pass, and we will break the pass if the results destination
+ * buffer is modified. */
+ if (buffer) {
+ visibility_is_dirty_ = (buffer != visibility_buffer_) || visibility_is_dirty_;
+ visibility_buffer_ = buffer;
+ visibility_buffer_->debug_ensure_used();
+ }
+ else {
+ /* If buffer is null, reset visibility state, mark dirty to break render pass if results are no
+ * longer needed. */
+ visibility_is_dirty_ = (visibility_buffer_ != nullptr) || visibility_is_dirty_;
+ visibility_buffer_ = nullptr;
+ }
+}
+
+gpu::MTLBuffer *MTLContext::get_visibility_buffer() const
+{
+ return visibility_buffer_;
+}
+
+void MTLContext::clear_visibility_dirty()
+{
+ visibility_is_dirty_ = false;
+}
+
+bool MTLContext::is_visibility_dirty() const
+{
+ return visibility_is_dirty_;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Texture State Management
* \{ */
-void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture_unit)
+void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, uint texture_unit)
{
BLI_assert(this);
BLI_assert(mtl_texture);
@@ -226,7 +435,7 @@ void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture
mtl_texture->is_bound_ = true;
}
-void MTLContext::sampler_bind(MTLSamplerState sampler_state, unsigned int sampler_unit)
+void MTLContext::sampler_bind(MTLSamplerState sampler_state, uint sampler_unit)
{
BLI_assert(this);
if (sampler_unit < 0 || sampler_unit >= GPU_max_textures() ||
@@ -271,14 +480,14 @@ void MTLContext::texture_unbind_all()
id<MTLSamplerState> MTLContext::get_sampler_from_state(MTLSamplerState sampler_state)
{
- BLI_assert((unsigned int)sampler_state >= 0 && ((unsigned int)sampler_state) < GPU_SAMPLER_MAX);
- return this->sampler_state_cache_[(unsigned int)sampler_state];
+ BLI_assert((uint)sampler_state >= 0 && ((uint)sampler_state) < GPU_SAMPLER_MAX);
+ return sampler_state_cache_[(uint)sampler_state];
}
id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState sampler_state)
{
/* Check if sampler already exists for given state. */
- id<MTLSamplerState> st = this->sampler_state_cache_[(unsigned int)sampler_state];
+ id<MTLSamplerState> st = sampler_state_cache_[(uint)sampler_state];
if (st != nil) {
return st;
}
@@ -318,7 +527,7 @@ id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState samp
descriptor.supportArgumentBuffers = true;
id<MTLSamplerState> state = [this->device newSamplerStateWithDescriptor:descriptor];
- this->sampler_state_cache_[(unsigned int)sampler_state] = state;
+ sampler_state_cache_[(uint)sampler_state] = state;
BLI_assert(state != nil);
[descriptor autorelease];
@@ -328,10 +537,10 @@ id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState samp
id<MTLSamplerState> MTLContext::get_default_sampler_state()
{
- if (this->default_sampler_state_ == nil) {
- this->default_sampler_state_ = this->get_sampler_from_state(DEFAULT_SAMPLER_STATE);
+ if (default_sampler_state_ == nil) {
+ default_sampler_state_ = this->get_sampler_from_state(DEFAULT_SAMPLER_STATE);
}
- return this->default_sampler_state_;
+ return default_sampler_state_;
}
/** \} */
diff --git a/source/blender/gpu/metal/mtl_debug.mm b/source/blender/gpu/metal/mtl_debug.mm
index 9d67a1f4f04..8ca4a0cc6e3 100644
--- a/source/blender/gpu/metal/mtl_debug.mm
+++ b/source/blender/gpu/metal/mtl_debug.mm
@@ -46,20 +46,14 @@ namespace blender::gpu {
void MTLContext::debug_group_begin(const char *name, int index)
{
if (G.debug & G_DEBUG_GPU) {
- id<MTLCommandBuffer> cmd = this->get_active_command_buffer();
- if (cmd != nil) {
- [cmd pushDebugGroup:[NSString stringWithFormat:@"%s_%d", name, index]];
- }
+ this->main_command_buffer.push_debug_group(name, index);
}
}
void MTLContext::debug_group_end()
{
if (G.debug & G_DEBUG_GPU) {
- id<MTLCommandBuffer> cmd = this->get_active_command_buffer();
- if (cmd != nil) {
- [cmd popDebugGroup];
- }
+ this->main_command_buffer.pop_debug_group();
}
}
diff --git a/source/blender/gpu/metal/mtl_framebuffer.hh b/source/blender/gpu/metal/mtl_framebuffer.hh
new file mode 100644
index 00000000000..d6e9fa76b70
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_framebuffer.hh
@@ -0,0 +1,233 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Encapsulation of Frame-buffer states (attached textures, viewport, scissors).
+ */
+
+#pragma once
+
+#include "GPU_common_types.h"
+#include "MEM_guardedalloc.h"
+
+#include "gpu_framebuffer_private.hh"
+#include "mtl_texture.hh"
+#include <Metal/Metal.h>
+
+namespace blender::gpu {
+
+class MTLContext;
+
+struct MTLAttachment {
+ bool used;
+ gpu::MTLTexture *texture;
+ union {
+ float color[4];
+ float depth;
+ uint stencil;
+ } clear_value;
+
+ eGPULoadOp load_action;
+ eGPUStoreOp store_action;
+ uint mip;
+ uint slice;
+ uint depth_plane;
+
+ /* If Array Length is larger than zero, use multilayered rendering. */
+ uint render_target_array_length;
+};
+
+/**
+ * Implementation of FrameBuffer object using Metal.
+ **/
+class MTLFrameBuffer : public FrameBuffer {
+ private:
+ /* Context Handle. */
+ MTLContext *context_;
+
+ /* Metal Attachment properties. */
+ uint colour_attachment_count_;
+ MTLAttachment mtl_color_attachments_[GPU_FB_MAX_COLOR_ATTACHMENT];
+ MTLAttachment mtl_depth_attachment_;
+ MTLAttachment mtl_stencil_attachment_;
+ bool use_multilayered_rendering_ = false;
+
+ /* State. */
+ /* Whether global framebuffer properties have changed and require
+ * re-generation of MTLRenderPassDescriptor/RenderCommandEncoders. */
+ bool is_dirty_;
+
+ /* Whether loadstore properties have changed (only affects certain cached configs). */
+ bool is_loadstore_dirty_;
+
+ /* Context that the latest modified state was last applied to.
+ * If this does not match current ctx, re-apply state. */
+ MTLContext *dirty_state_ctx_;
+
+ /* Whether a clear is pending -- Used to toggle between clear and load FB configurations
+ * (without dirtying the state) - Frame-buffer load config is used if no `GPU_clear_*` command
+ * was issued after binding the FrameBuffer. */
+ bool has_pending_clear_;
+
+ /* Render Pass Descriptors:
+ * There are 3 MTLRenderPassDescriptors for different ways in which a frame-buffer
+ * can be configured:
+ * [0] = CLEAR CONFIG -- Used when a GPU_framebuffer_clear_* command has been issued.
+ * [1] = LOAD CONFIG -- Used if bound, but no clear is required.
+ * [2] = CUSTOM CONFIG -- When using GPU_framebuffer_bind_ex to manually specify
+ * load-store configuration for optimal bandwidth utilization.
+ * -- We cache these different configs to avoid re-generation --
+ */
+ typedef enum {
+ MTL_FB_CONFIG_CLEAR = 0,
+ MTL_FB_CONFIG_LOAD = 1,
+ MTL_FB_CONFIG_CUSTOM = 2
+ } MTL_FB_CONFIG;
+#define MTL_FB_CONFIG_MAX (MTL_FB_CONFIG_CUSTOM + 1)
+
+ MTLRenderPassDescriptor *framebuffer_descriptor_[MTL_FB_CONFIG_MAX];
+ MTLRenderPassColorAttachmentDescriptor
+ *colour_attachment_descriptors_[GPU_FB_MAX_COLOR_ATTACHMENT];
+ /* Whether MTLRenderPassDescriptor[N] requires updating with latest state. */
+ bool descriptor_dirty_[MTL_FB_CONFIG_MAX];
+ /* Whether SRGB is enabled for this framebuffer configuration. */
+ bool srgb_enabled_;
+ /* Whether the primary Frame-buffer attachment is an SRGB target or not. */
+ bool is_srgb_;
+
+ public:
+ /**
+ * Create a conventional framebuffer to attach texture to.
+ **/
+ MTLFrameBuffer(MTLContext *ctx, const char *name);
+
+ ~MTLFrameBuffer();
+
+ void bind(bool enabled_srgb) override;
+
+ bool check(char err_out[256]) override;
+
+ void clear(eGPUFrameBufferBits buffers,
+ const float clear_col[4],
+ float clear_depth,
+ uint clear_stencil) override;
+ void clear_multi(const float (*clear_cols)[4]) override;
+ void clear_attachment(GPUAttachmentType type,
+ eGPUDataFormat data_format,
+ const void *clear_value) override;
+
+ void attachment_set_loadstore_op(GPUAttachmentType type,
+ eGPULoadOp load_action,
+ eGPUStoreOp store_action) override;
+
+ void read(eGPUFrameBufferBits planes,
+ eGPUDataFormat format,
+ const int area[4],
+ int channel_len,
+ int slot,
+ void *r_data) override;
+
+ void blit_to(eGPUFrameBufferBits planes,
+ int src_slot,
+ FrameBuffer *dst,
+ int dst_slot,
+ int dst_offset_x,
+ int dst_offset_y) override;
+
+ void apply_state();
+
+ /* State. */
+ /* Flag MTLFramebuffer configuration as having changed. */
+ void mark_dirty();
+ void mark_loadstore_dirty();
+ /* Mark that a pending clear has been performed. */
+ void mark_cleared();
+ /* Mark that we have a pending clear. */
+ void mark_do_clear();
+
+ /* Attachment management. */
+ /* When dirty_attachments_ is true, we need to reprocess attachments to extract Metal
+ * information. */
+ void update_attachments(bool update_viewport);
+ bool add_color_attachment(gpu::MTLTexture *texture, uint slot, int miplevel, int layer);
+ bool add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer);
+ bool add_stencil_attachment(gpu::MTLTexture *texture, int miplevel, int layer);
+ bool remove_color_attachment(uint slot);
+ bool remove_depth_attachment();
+ bool remove_stencil_attachment();
+ void remove_all_attachments();
+ void ensure_render_target_size();
+
+ /* Clear values -> Load/store actions. */
+ bool set_color_attachment_clear_color(uint slot, const float clear_color[4]);
+ bool set_depth_attachment_clear_value(float depth_clear);
+ bool set_stencil_attachment_clear_value(uint stencil_clear);
+ bool set_color_loadstore_op(uint slot, eGPULoadOp load_action, eGPUStoreOp store_action);
+ bool set_depth_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action);
+ bool set_stencil_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action);
+
+ /* Remove any pending clears - Ensure "load" configuration is used. */
+ bool reset_clear_state();
+
+ /* Fetch values */
+ bool has_attachment_at_slot(uint slot);
+ bool has_color_attachment_with_texture(gpu::MTLTexture *texture);
+ bool has_depth_attachment();
+ bool has_stencil_attachment();
+ int get_color_attachment_slot_from_texture(gpu::MTLTexture *texture);
+ uint get_attachment_count();
+ uint get_attachment_limit()
+ {
+ return GPU_FB_MAX_COLOR_ATTACHMENT;
+ };
+ MTLAttachment get_color_attachment(uint slot);
+ MTLAttachment get_depth_attachment();
+ MTLAttachment get_stencil_attachment();
+
+ /* Metal API resources and validation. */
+ bool validate_render_pass();
+ MTLRenderPassDescriptor *bake_render_pass_descriptor(bool load_contents);
+
+ /* Blitting. */
+ void blit(uint read_slot,
+ uint src_x_offset,
+ uint src_y_offset,
+ MTLFrameBuffer *metal_fb_write,
+ uint write_slot,
+ uint dst_x_offset,
+ uint dst_y_offset,
+ uint width,
+ uint height,
+ eGPUFrameBufferBits blit_buffers);
+
+ int get_width();
+ int get_height();
+ bool get_dirty()
+ {
+ return is_dirty_ || is_loadstore_dirty_;
+ }
+
+ bool get_pending_clear()
+ {
+ return has_pending_clear_;
+ }
+
+ bool get_srgb_enabled()
+ {
+ return srgb_enabled_;
+ }
+
+ bool get_is_srgb()
+ {
+ return is_srgb_;
+ }
+
+ private:
+ /* Clears a render target by force-opening a render pass. */
+ void force_clear();
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("MTLFrameBuffer");
+};
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_framebuffer.mm b/source/blender/gpu/metal/mtl_framebuffer.mm
new file mode 100644
index 00000000000..515dd70e5de
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_framebuffer.mm
@@ -0,0 +1,1899 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "BKE_global.h"
+
+#include "mtl_context.hh"
+#include "mtl_debug.hh"
+#include "mtl_framebuffer.hh"
+#include "mtl_texture.hh"
+#import <Availability.h>
+
+namespace blender::gpu {
+
+/* -------------------------------------------------------------------- */
+/** \name Creation & Deletion
+ * \{ */
+
+MTLFrameBuffer::MTLFrameBuffer(MTLContext *ctx, const char *name) : FrameBuffer(name)
+{
+
+ context_ = ctx;
+ is_dirty_ = true;
+ is_loadstore_dirty_ = true;
+ dirty_state_ctx_ = nullptr;
+ has_pending_clear_ = false;
+ colour_attachment_count_ = 0;
+ srgb_enabled_ = false;
+ is_srgb_ = false;
+
+ for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
+ mtl_color_attachments_[i].used = false;
+ }
+ mtl_depth_attachment_.used = false;
+ mtl_stencil_attachment_.used = false;
+
+ for (int i = 0; i < MTL_FB_CONFIG_MAX; i++) {
+ framebuffer_descriptor_[i] = [[MTLRenderPassDescriptor alloc] init];
+ descriptor_dirty_[i] = true;
+ }
+
+ for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
+ colour_attachment_descriptors_[i] = [[MTLRenderPassColorAttachmentDescriptor alloc] init];
+ }
+
+ /* Initial state. */
+ this->size_set(0, 0);
+ this->viewport_reset();
+ this->scissor_reset();
+}
+
+MTLFrameBuffer::~MTLFrameBuffer()
+{
+ /* If FrameBuffer is associated with a currently open RenderPass, end. */
+ if (context_->main_command_buffer.get_active_framebuffer() == this) {
+ context_->main_command_buffer.end_active_command_encoder();
+ }
+
+ /* Restore default frame-buffer if this frame-buffer was bound. */
+ if (context_->active_fb == this && context_->back_left != this) {
+ /* If this assert triggers it means the frame-buffer is being freed while in use by another
+ * context which, by the way, is TOTALLY UNSAFE!!! (Copy from GL behavior). */
+ BLI_assert(context_ == static_cast<MTLContext *>(unwrap(GPU_context_active_get())));
+ GPU_framebuffer_restore();
+ }
+
+ /* Free Render Pass Descriptors. */
+ for (int config = 0; config < MTL_FB_CONFIG_MAX; config++) {
+ if (framebuffer_descriptor_[config] != nil) {
+ [framebuffer_descriptor_[config] release];
+ framebuffer_descriptor_[config] = nil;
+ }
+ }
+
+ /* Free colour attachment descriptors. */
+ for (int i = 0; i < GPU_FB_MAX_COLOR_ATTACHMENT; i++) {
+ if (colour_attachment_descriptors_[i] != nil) {
+ [colour_attachment_descriptors_[i] release];
+ colour_attachment_descriptors_[i] = nil;
+ }
+ }
+
+ /* Remove attachments - release FB texture references. */
+ this->remove_all_attachments();
+
+ if (context_ == nullptr) {
+ return;
+ }
+}
+
+void MTLFrameBuffer::bind(bool enabled_srgb)
+{
+
+ /* Verify Context is valid. */
+ if (context_ != static_cast<MTLContext *>(unwrap(GPU_context_active_get()))) {
+ BLI_assert(false && "Trying to use the same frame-buffer in multiple context's.");
+ return;
+ }
+
+ /* Ensure SRGB state is up-to-date and valid. */
+ bool srgb_state_changed = srgb_enabled_ != enabled_srgb;
+ if (context_->active_fb != this || srgb_state_changed) {
+ if (srgb_state_changed) {
+ this->mark_dirty();
+ }
+ srgb_enabled_ = enabled_srgb;
+ GPU_shader_set_framebuffer_srgb_target(srgb_enabled_ && is_srgb_);
+ }
+
+ /* Ensure local MTLAttachment data is up to date. */
+ this->update_attachments(true);
+
+ /* Reset clear state on bind -- Clears and load/store ops are set after binding. */
+ this->reset_clear_state();
+
+ /* Bind to active context. */
+ MTLContext *mtl_context = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+ if (mtl_context) {
+ mtl_context->framebuffer_bind(this);
+ dirty_state_ = true;
+ }
+ else {
+ MTL_LOG_WARNING("Attempting to bind FrameBuffer, but no context is active\n");
+ }
+}
+
+bool MTLFrameBuffer::check(char err_out[256])
+{
+ /* Ensure local MTLAttachment data is up to date. */
+ this->update_attachments(true);
+
+ /* Ensure there is at least one attachment. */
+ bool valid = (this->get_attachment_count() > 0 ||
+ this->has_depth_attachment() | this->has_stencil_attachment());
+ if (!valid) {
+ const char *format = "Framebuffer %s does not have any attachments.\n";
+ if (err_out) {
+ BLI_snprintf(err_out, 256, format, name_);
+ }
+ else {
+ MTL_LOG_ERROR(format, name_);
+ }
+ return false;
+ }
+
+ /* Ensure all attachments have identical dimensions. */
+ /* Ensure all attachments are render-targets. */
+ bool first = true;
+ uint dim_x = 0;
+ uint dim_y = 0;
+ for (int col_att = 0; col_att < this->get_attachment_count(); col_att++) {
+ MTLAttachment att = this->get_color_attachment(col_att);
+ if (att.used) {
+ if (att.texture->gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATTACHMENT) {
+ if (first) {
+ dim_x = att.texture->width_get();
+ dim_y = att.texture->height_get();
+ first = false;
+ }
+ else {
+ if (dim_x != att.texture->width_get() || dim_y != att.texture->height_get()) {
+ const char *format =
+ "Framebuffer %s: Color attachment dimensions do not match those of previous "
+ "attachment\n";
+ if (err_out) {
+ BLI_snprintf(err_out, 256, format, name_);
+ }
+ else {
+ fprintf(stderr, format, name_);
+ MTL_LOG_ERROR(format, name_);
+ }
+ return false;
+ }
+ }
+ }
+ else {
+ const char *format =
+ "Framebuffer %s: Color attachment texture does not have usage flag "
+ "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
+ if (err_out) {
+ BLI_snprintf(err_out, 256, format, name_);
+ }
+ else {
+ fprintf(stderr, format, name_);
+ MTL_LOG_ERROR(format, name_);
+ }
+ return false;
+ }
+ }
+ }
+ MTLAttachment depth_att = this->get_depth_attachment();
+ MTLAttachment stencil_att = this->get_stencil_attachment();
+ if (depth_att.used) {
+ if (first) {
+ dim_x = depth_att.texture->width_get();
+ dim_y = depth_att.texture->height_get();
+ first = false;
+ valid = (depth_att.texture->gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATTACHMENT);
+
+ if (!valid) {
+ const char *format =
+ "Framebuffer %n: Depth attachment does not have usage "
+ "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
+ if (err_out) {
+ BLI_snprintf(err_out, 256, format, name_);
+ }
+ else {
+ fprintf(stderr, format, name_);
+ MTL_LOG_ERROR(format, name_);
+ }
+ return false;
+ }
+ }
+ else {
+ if (dim_x != depth_att.texture->width_get() || dim_y != depth_att.texture->height_get()) {
+ const char *format =
+ "Framebuffer %n: Depth attachment dimensions do not match that of previous "
+ "attachment\n";
+ if (err_out) {
+ BLI_snprintf(err_out, 256, format, name_);
+ }
+ else {
+ fprintf(stderr, format, name_);
+ MTL_LOG_ERROR(format, name_);
+ }
+ return false;
+ }
+ }
+ }
+ if (stencil_att.used) {
+ if (first) {
+ dim_x = stencil_att.texture->width_get();
+ dim_y = stencil_att.texture->height_get();
+ first = false;
+ valid = (stencil_att.texture->gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_ATTACHMENT);
+ if (!valid) {
+ const char *format =
+ "Framebuffer %s: Stencil attachment does not have usage "
+ "'GPU_TEXTURE_USAGE_ATTACHMENT'\n";
+ if (err_out) {
+ BLI_snprintf(err_out, 256, format, name_);
+ }
+ else {
+ fprintf(stderr, format, name_);
+ MTL_LOG_ERROR(format, name_);
+ }
+ return false;
+ }
+ }
+ else {
+ if (dim_x != stencil_att.texture->width_get() ||
+ dim_y != stencil_att.texture->height_get()) {
+ const char *format =
+ "Framebuffer %s: Stencil attachment dimensions do not match that of previous "
+ "attachment";
+ if (err_out) {
+ BLI_snprintf(err_out, 256, format, name_);
+ }
+ else {
+ fprintf(stderr, format, name_);
+ MTL_LOG_ERROR(format, name_);
+ }
+ return false;
+ }
+ }
+ }
+
+ BLI_assert(valid);
+ return valid;
+}
+
+void MTLFrameBuffer::force_clear()
+{
+ /* Perform clear by ending current and starting a new render pass. */
+ MTLContext *mtl_context = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
+ MTLFrameBuffer *current_framebuffer = mtl_context->get_current_framebuffer();
+ if (current_framebuffer) {
+ BLI_assert(current_framebuffer == this);
+ /* End current render-pass. */
+ if (mtl_context->main_command_buffer.is_inside_render_pass()) {
+ mtl_context->main_command_buffer.end_active_command_encoder();
+ }
+ mtl_context->ensure_begin_render_pass();
+ BLI_assert(has_pending_clear_ == false);
+ }
+}
+
+void MTLFrameBuffer::clear(eGPUFrameBufferBits buffers,
+ const float clear_col[4],
+ float clear_depth,
+ uint clear_stencil)
+{
+
+ BLI_assert(unwrap(GPU_context_active_get()) == context_);
+ BLI_assert(context_->active_fb == this);
+
+ /* Ensure attachments are up to date. */
+ this->update_attachments(true);
+
+ /* If we had no previous clear pending, reset clear state. */
+ if (!has_pending_clear_) {
+ this->reset_clear_state();
+ }
+
+ /* Ensure we only clear if attachments exist for given buffer bits. */
+ bool do_clear = false;
+ if (buffers & GPU_COLOR_BIT) {
+ for (int i = 0; i < colour_attachment_count_; i++) {
+ this->set_color_attachment_clear_color(i, clear_col);
+ do_clear = true;
+ }
+ }
+
+ if (buffers & GPU_DEPTH_BIT) {
+ this->set_depth_attachment_clear_value(clear_depth);
+ do_clear = do_clear || this->has_depth_attachment();
+ }
+ if (buffers & GPU_STENCIL_BIT) {
+ this->set_stencil_attachment_clear_value(clear_stencil);
+ do_clear = do_clear || this->has_stencil_attachment();
+ }
+
+ if (do_clear) {
+ has_pending_clear_ = true;
+
+ /* Apply state before clear. */
+ this->apply_state();
+
+ /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
+ * MTLTexture instead. */
+ /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
+ * between clears where no draws occur. Can optimize at the high-level by using explicit
+ * load-store flags. */
+ this->force_clear();
+ }
+}
+
+void MTLFrameBuffer::clear_multi(const float (*clear_cols)[4])
+{
+ /* If we had no previous clear pending, reset clear state. */
+ if (!has_pending_clear_) {
+ this->reset_clear_state();
+ }
+
+ bool do_clear = false;
+ for (int i = 0; i < this->get_attachment_limit(); i++) {
+ if (this->has_attachment_at_slot(i)) {
+ this->set_color_attachment_clear_color(i, clear_cols[i]);
+ do_clear = true;
+ }
+ }
+
+ if (do_clear) {
+ has_pending_clear_ = true;
+
+ /* Apply state before clear. */
+ this->apply_state();
+
+ /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
+ * MTLTexture instead. */
+ /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
+ * between clears where no draws occur. Can optimize at the high-level by using explicit
+ * load-store flags. */
+ this->force_clear();
+ }
+}
+
+void MTLFrameBuffer::clear_attachment(GPUAttachmentType type,
+ eGPUDataFormat data_format,
+ const void *clear_value)
+{
+ BLI_assert(static_cast<MTLContext *>(unwrap(GPU_context_active_get())) == context_);
+ BLI_assert(context_->active_fb == this);
+
+ /* If we had no previous clear pending, reset clear state. */
+ if (!has_pending_clear_) {
+ this->reset_clear_state();
+ }
+
+ bool do_clear = false;
+
+ if (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) {
+ if (this->has_depth_attachment() || this->has_stencil_attachment()) {
+ BLI_assert(data_format == GPU_DATA_UINT_24_8);
+ float depth = ((*(uint32_t *)clear_value) & 0x00FFFFFFu) / (float)0x00FFFFFFu;
+ int stencil = ((*(uint32_t *)clear_value) >> 24);
+ this->set_depth_attachment_clear_value(depth);
+ this->set_stencil_attachment_clear_value(stencil);
+ do_clear = true;
+ }
+ }
+ else if (type == GPU_FB_DEPTH_ATTACHMENT) {
+ if (this->has_depth_attachment()) {
+ if (data_format == GPU_DATA_FLOAT) {
+ this->set_depth_attachment_clear_value(*(float *)clear_value);
+ }
+ else {
+ float depth = *(uint32_t *)clear_value / (float)0xFFFFFFFFu;
+ this->set_depth_attachment_clear_value(depth);
+ }
+ do_clear = true;
+ }
+ }
+ else {
+ int slot = type - GPU_FB_COLOR_ATTACHMENT0;
+ if (this->has_attachment_at_slot(slot)) {
+ float col_clear_val[4] = {0.0};
+ switch (data_format) {
+ case GPU_DATA_FLOAT: {
+ const float *vals = (float *)clear_value;
+ col_clear_val[0] = vals[0];
+ col_clear_val[1] = vals[1];
+ col_clear_val[2] = vals[2];
+ col_clear_val[3] = vals[3];
+ } break;
+ case GPU_DATA_UINT: {
+ const uint *vals = (uint *)clear_value;
+ col_clear_val[0] = (float)(vals[0]);
+ col_clear_val[1] = (float)(vals[1]);
+ col_clear_val[2] = (float)(vals[2]);
+ col_clear_val[3] = (float)(vals[3]);
+ } break;
+ case GPU_DATA_INT: {
+ const int *vals = (int *)clear_value;
+ col_clear_val[0] = (float)(vals[0]);
+ col_clear_val[1] = (float)(vals[1]);
+ col_clear_val[2] = (float)(vals[2]);
+ col_clear_val[3] = (float)(vals[3]);
+ } break;
+ default:
+ BLI_assert_msg(0, "Unhandled data format");
+ break;
+ }
+ this->set_color_attachment_clear_color(slot, col_clear_val);
+ do_clear = true;
+ }
+ }
+
+ if (do_clear) {
+ has_pending_clear_ = true;
+
+ /* Apply state before clear. */
+ this->apply_state();
+
+ /* TODO(Metal): Optimize - Currently force-clear always used. Consider moving clear state to
+ * MTLTexture instead. */
+ /* Force clear if RP is not yet active -- not the most efficient, but there is no distinction
+ * between clears where no draws occur. Can optimize at the high-level by using explicit
+ * load-store flags. */
+ this->force_clear();
+ }
+}
+
+void MTLFrameBuffer::read(eGPUFrameBufferBits planes,
+ eGPUDataFormat format,
+ const int area[4],
+ int channel_len,
+ int slot,
+ void *r_data)
+{
+
+ BLI_assert((planes & GPU_STENCIL_BIT) == 0);
+ BLI_assert(area[2] > 0);
+ BLI_assert(area[3] > 0);
+
+ switch (planes) {
+ case GPU_DEPTH_BIT: {
+ if (this->has_depth_attachment()) {
+ MTLAttachment depth = this->get_depth_attachment();
+ gpu::MTLTexture *tex = depth.texture;
+ if (tex) {
+ size_t sample_len = area[2] * area[3];
+ size_t sample_size = to_bytesize(tex->format_, format);
+ int debug_data_size = sample_len * sample_size;
+ tex->read_internal(0,
+ area[0],
+ area[1],
+ 0,
+ area[2],
+ area[3],
+ 1,
+ format,
+ channel_len,
+ debug_data_size,
+ r_data);
+ }
+ }
+ else {
+ MTL_LOG_ERROR(
+ "Attempting to read depth from a framebuffer which does not have a depth "
+ "attachment!\n");
+ }
+ }
+ return;
+
+ case GPU_COLOR_BIT: {
+ if (this->has_attachment_at_slot(slot)) {
+ MTLAttachment color = this->get_color_attachment(slot);
+ gpu::MTLTexture *tex = color.texture;
+ if (tex) {
+ size_t sample_len = area[2] * area[3];
+ size_t sample_size = to_bytesize(tex->format_, format);
+ int debug_data_size = sample_len * sample_size * channel_len;
+ tex->read_internal(0,
+ area[0],
+ area[1],
+ 0,
+ area[2],
+ area[3],
+ 1,
+ format,
+ channel_len,
+ debug_data_size,
+ r_data);
+ }
+ }
+ }
+ return;
+
+ case GPU_STENCIL_BIT:
+ MTL_LOG_ERROR("GPUFramebuffer: Error: Trying to read stencil bit. Unsupported.\n");
+ return;
+ }
+}
+
+void MTLFrameBuffer::blit_to(eGPUFrameBufferBits planes,
+ int src_slot,
+ FrameBuffer *dst,
+ int dst_slot,
+ int dst_offset_x,
+ int dst_offset_y)
+{
+ this->update_attachments(true);
+ static_cast<MTLFrameBuffer *>(dst)->update_attachments(true);
+
+ BLI_assert(planes != 0);
+
+ MTLFrameBuffer *metal_fb_write = static_cast<MTLFrameBuffer *>(dst);
+
+ BLI_assert(this);
+ BLI_assert(metal_fb_write);
+
+ /* Get width/height from attachment. */
+ MTLAttachment src_attachment;
+ const bool do_color = (planes & GPU_COLOR_BIT);
+ const bool do_depth = (planes & GPU_DEPTH_BIT);
+ const bool do_stencil = (planes & GPU_STENCIL_BIT);
+
+ if (do_color) {
+ BLI_assert(!do_depth && !do_stencil);
+ src_attachment = this->get_color_attachment(src_slot);
+ }
+ else if (do_depth) {
+ BLI_assert(!do_color && !do_stencil);
+ src_attachment = this->get_depth_attachment();
+ }
+ else if (do_stencil) {
+ BLI_assert(!do_color && !do_depth);
+ src_attachment = this->get_stencil_attachment();
+ }
+
+ BLI_assert(src_attachment.used);
+ this->blit(src_slot,
+ 0,
+ 0,
+ metal_fb_write,
+ dst_slot,
+ dst_offset_x,
+ dst_offset_y,
+ src_attachment.texture->width_get(),
+ src_attachment.texture->height_get(),
+ planes);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \ Private METAL implementation functions
+ * \{ */
+
+void MTLFrameBuffer::mark_dirty()
+{
+ is_dirty_ = true;
+ is_loadstore_dirty_ = true;
+}
+
+void MTLFrameBuffer::mark_loadstore_dirty()
+{
+ is_loadstore_dirty_ = true;
+}
+
+void MTLFrameBuffer::mark_cleared()
+{
+ has_pending_clear_ = false;
+}
+
+void MTLFrameBuffer::mark_do_clear()
+{
+ has_pending_clear_ = true;
+}
+
+void MTLFrameBuffer::update_attachments(bool update_viewport)
+{
+ if (!dirty_attachments_) {
+ return;
+ }
+
+ /* Cache viewport and scissor (If we have existing attachments). */
+ int t_viewport[4], t_scissor[4];
+ update_viewport = update_viewport &&
+ (this->get_attachment_count() > 0 && this->has_depth_attachment() &&
+ this->has_stencil_attachment());
+ if (update_viewport) {
+ this->viewport_get(t_viewport);
+ this->scissor_get(t_scissor);
+ }
+
+ /* Clear current attachments state. */
+ this->remove_all_attachments();
+
+ /* Reset framebuffer options. */
+ use_multilayered_rendering_ = false;
+
+ /* Track first attachment for SRGB property extraction. */
+ GPUAttachmentType first_attachment = GPU_FB_MAX_ATTACHMENT;
+ MTLAttachment first_attachment_mtl;
+
+ /* Scan through changes to attachments and populate local structures. */
+ bool depth_added = false;
+ for (GPUAttachmentType type = GPU_FB_MAX_ATTACHMENT - 1; type >= 0; --type) {
+ GPUAttachment &attach = attachments_[type];
+
+ switch (type) {
+ case GPU_FB_DEPTH_ATTACHMENT:
+ case GPU_FB_DEPTH_STENCIL_ATTACHMENT: {
+ /* If one of the DEPTH types has added a texture, we avoid running this again, as it would
+ * only remove the target. */
+ if (depth_added) {
+ break;
+ }
+ if (attach.tex) {
+ /* If we already had a depth attachment, preserve load/clear-state parameters,
+ * but remove existing and add new attachment. */
+ if (this->has_depth_attachment()) {
+ MTLAttachment depth_attachment_prev = this->get_depth_attachment();
+ this->remove_depth_attachment();
+ this->add_depth_attachment(
+ static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
+ this->set_depth_attachment_clear_value(depth_attachment_prev.clear_value.depth);
+ this->set_depth_loadstore_op(depth_attachment_prev.load_action,
+ depth_attachment_prev.store_action);
+ }
+ else {
+ this->add_depth_attachment(
+ static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
+ }
+
+ /* Check stencil component -- if supplied texture format supports stencil. */
+ eGPUTextureFormat format = GPU_texture_format(attach.tex);
+ bool use_stencil = (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) &&
+ (format == GPU_DEPTH32F_STENCIL8 || format == GPU_DEPTH24_STENCIL8);
+ if (use_stencil) {
+ if (this->has_stencil_attachment()) {
+ MTLAttachment stencil_attachment_prev = this->get_stencil_attachment();
+ this->remove_stencil_attachment();
+ this->add_stencil_attachment(
+ static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
+ this->set_stencil_attachment_clear_value(
+ stencil_attachment_prev.clear_value.stencil);
+ this->set_stencil_loadstore_op(stencil_attachment_prev.load_action,
+ stencil_attachment_prev.store_action);
+ }
+ else {
+ this->add_stencil_attachment(
+ static_cast<gpu::MTLTexture *>(unwrap(attach.tex)), attach.mip, attach.layer);
+ }
+ }
+
+ /* Flag depth as added -- mirrors the behavior in gl_framebuffer.cc to exit the for-loop
+ * after GPU_FB_DEPTH_STENCIL_ATTACHMENT has executed. */
+ depth_added = true;
+
+ if (first_attachment == GPU_FB_MAX_ATTACHMENT) {
+ /* Only use depth texture to get information if there is no color attachment. */
+ first_attachment = type;
+ first_attachment_mtl = this->get_depth_attachment();
+ }
+ }
+ else {
+ this->remove_depth_attachment();
+ if (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT && this->has_stencil_attachment()) {
+ this->remove_stencil_attachment();
+ }
+ }
+ } break;
+ case GPU_FB_COLOR_ATTACHMENT0:
+ case GPU_FB_COLOR_ATTACHMENT1:
+ case GPU_FB_COLOR_ATTACHMENT2:
+ case GPU_FB_COLOR_ATTACHMENT3:
+ case GPU_FB_COLOR_ATTACHMENT4:
+ case GPU_FB_COLOR_ATTACHMENT5: {
+ int color_slot_ind = type - GPU_FB_COLOR_ATTACHMENT0;
+ if (attach.tex) {
+ /* If we already had a colour attachment, preserve load/clear-state parameters,
+ * but remove existing and add new attachment. */
+ if (this->has_attachment_at_slot(color_slot_ind)) {
+ MTLAttachment color_attachment_prev = this->get_color_attachment(color_slot_ind);
+
+ this->remove_color_attachment(color_slot_ind);
+ this->add_color_attachment(static_cast<gpu::MTLTexture *>(unwrap(attach.tex)),
+ color_slot_ind,
+ attach.mip,
+ attach.layer);
+ this->set_color_attachment_clear_color(color_slot_ind,
+ color_attachment_prev.clear_value.color);
+ this->set_color_loadstore_op(color_slot_ind,
+ color_attachment_prev.load_action,
+ color_attachment_prev.store_action);
+ }
+ else {
+ this->add_color_attachment(static_cast<gpu::MTLTexture *>(unwrap(attach.tex)),
+ color_slot_ind,
+ attach.mip,
+ attach.layer);
+ }
+ first_attachment = type;
+ first_attachment_mtl = this->get_color_attachment(color_slot_ind);
+ }
+ else {
+ this->remove_color_attachment(color_slot_ind);
+ }
+ } break;
+ default:
+ /* Non-attachment parameters. */
+ break;
+ }
+ }
+
+ /* Check whether the first attachment is SRGB. */
+ if (first_attachment != GPU_FB_MAX_ATTACHMENT) {
+ is_srgb_ = (first_attachment_mtl.texture->format_get() == GPU_SRGB8_A8);
+ }
+
+ /* Reset viewport and Scissor (If viewport is smaller or equal to the framebuffer size). */
+ if (update_viewport && t_viewport[2] <= width_ && t_viewport[3] <= height_) {
+
+ this->viewport_set(t_viewport);
+ this->scissor_set(t_viewport);
+ }
+ else {
+ this->viewport_reset();
+ this->scissor_reset();
+ }
+
+ /* We have now updated our internal structures. */
+ dirty_attachments_ = false;
+}
+
+void MTLFrameBuffer::apply_state()
+{
+ MTLContext *mtl_ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
+ BLI_assert(mtl_ctx);
+ if (mtl_ctx->active_fb == this) {
+ if (dirty_state_ == false && dirty_state_ctx_ == mtl_ctx) {
+ return;
+ }
+
+ /* Ensure viewport has been set. NOTE: This should no longer happen, but kept for safety to
+ * track bugs. */
+ if (viewport_[2] == 0 || viewport_[3] == 0) {
+ MTL_LOG_WARNING(
+ "Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check\n");
+ viewport_reset();
+ }
+
+ /* Update Context State. */
+ mtl_ctx->set_viewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]);
+ mtl_ctx->set_scissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]);
+ mtl_ctx->set_scissor_enabled(scissor_test_);
+
+ dirty_state_ = false;
+ dirty_state_ctx_ = mtl_ctx;
+ }
+ else {
+ MTL_LOG_ERROR(
+ "Attempting to set FrameBuffer State (VIEWPORT, SCISSOR), But FrameBuffer is not bound to "
+ "current Context.\n");
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \ Adding and Removing attachments
+ * \{ */
+
+bool MTLFrameBuffer::add_color_attachment(gpu::MTLTexture *texture,
+ uint slot,
+ int miplevel,
+ int layer)
+{
+ BLI_assert(this);
+ BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
+
+ if (texture) {
+ if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
+ MTL_LOG_WARNING("Attachment specified with invalid mip level %u\n", miplevel);
+ miplevel = 0;
+ }
+
+ /* Check if slot is in-use. */
+ /* Assume attachment load by default. */
+ colour_attachment_count_ += (!mtl_color_attachments_[slot].used) ? 1 : 0;
+ mtl_color_attachments_[slot].used = true;
+ mtl_color_attachments_[slot].texture = texture;
+ mtl_color_attachments_[slot].mip = miplevel;
+ mtl_color_attachments_[slot].load_action = GPU_LOADACTION_LOAD;
+ mtl_color_attachments_[slot].store_action = GPU_STOREACTION_STORE;
+ mtl_color_attachments_[slot].render_target_array_length = 0;
+
+ /* Determine whether array slice or depth plane based on texture type. */
+ switch (texture->type_) {
+ case GPU_TEXTURE_1D:
+ case GPU_TEXTURE_2D:
+ BLI_assert(layer <= 0);
+ mtl_color_attachments_[slot].slice = 0;
+ mtl_color_attachments_[slot].depth_plane = 0;
+ break;
+ case GPU_TEXTURE_1D_ARRAY:
+ if (layer < 0) {
+ layer = 0;
+ MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed.\n");
+ }
+ BLI_assert(layer < texture->h_);
+ mtl_color_attachments_[slot].slice = layer;
+ mtl_color_attachments_[slot].depth_plane = 0;
+ break;
+ case GPU_TEXTURE_2D_ARRAY:
+ BLI_assert(layer < texture->d_);
+ mtl_color_attachments_[slot].slice = layer;
+ mtl_color_attachments_[slot].depth_plane = 0;
+ if (layer == -1) {
+ mtl_color_attachments_[slot].slice = 0;
+ mtl_color_attachments_[slot].render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_3D:
+ BLI_assert(layer < texture->d_);
+ mtl_color_attachments_[slot].slice = 0;
+ mtl_color_attachments_[slot].depth_plane = layer;
+ if (layer == -1) {
+ mtl_color_attachments_[slot].depth_plane = 0;
+ mtl_color_attachments_[slot].render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_CUBE:
+ BLI_assert(layer < 6);
+ mtl_color_attachments_[slot].slice = layer;
+ mtl_color_attachments_[slot].depth_plane = 0;
+ if (layer == -1) {
+ mtl_color_attachments_[slot].slice = 0;
+ mtl_color_attachments_[slot].depth_plane = 0;
+ mtl_color_attachments_[slot].render_target_array_length = 6;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_CUBE_ARRAY:
+ BLI_assert(layer < 6 * texture->d_);
+ /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
+ mtl_color_attachments_[slot].slice = layer;
+ mtl_color_attachments_[slot].depth_plane = 0;
+ if (layer == -1) {
+ mtl_color_attachments_[slot].slice = 0;
+ mtl_color_attachments_[slot].depth_plane = 0;
+ mtl_color_attachments_[slot].render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_BUFFER:
+ mtl_color_attachments_[slot].slice = 0;
+ mtl_color_attachments_[slot].depth_plane = 0;
+ break;
+ default:
+ MTL_LOG_ERROR("MTLFrameBuffer::add_color_attachment Unrecognised texture type %u\n",
+ texture->type_);
+ break;
+ }
+
+ /* Update Framebuffer Resolution. */
+ int width_of_miplayer, height_of_miplayer;
+ if (miplevel <= 0) {
+ width_of_miplayer = texture->width_get();
+ height_of_miplayer = texture->height_get();
+ }
+ else {
+ width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
+ height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
+ }
+
+ if (width_ == 0 || height_ == 0) {
+ this->size_set(width_of_miplayer, height_of_miplayer);
+ this->scissor_reset();
+ this->viewport_reset();
+ BLI_assert(width_ > 0);
+ BLI_assert(height_ > 0);
+ }
+ else {
+ BLI_assert(width_ == width_of_miplayer);
+ BLI_assert(height_ == height_of_miplayer);
+ }
+
+ /* Flag as dirty. */
+ this->mark_dirty();
+ }
+ else {
+ MTL_LOG_ERROR(
+ "Passing in null texture to MTLFrameBuffer::addColourAttachment (This could be due to not "
+ "all texture types being supported).\n");
+ }
+ return true;
+}
+
+bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
+{
+ BLI_assert(this);
+
+ if (texture) {
+ if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
+ MTL_LOG_WARNING("Attachment specified with invalid mip level %u\n", miplevel);
+ miplevel = 0;
+ }
+
+ /* Assume attachment load by default. */
+ mtl_depth_attachment_.used = true;
+ mtl_depth_attachment_.texture = texture;
+ mtl_depth_attachment_.mip = miplevel;
+ mtl_depth_attachment_.load_action = GPU_LOADACTION_LOAD;
+ mtl_depth_attachment_.store_action = GPU_STOREACTION_STORE;
+ mtl_depth_attachment_.render_target_array_length = 0;
+
+ /* Determine whether array slice or depth plane based on texture type. */
+ switch (texture->type_) {
+ case GPU_TEXTURE_1D:
+ case GPU_TEXTURE_2D:
+ BLI_assert(layer <= 0);
+ mtl_depth_attachment_.slice = 0;
+ mtl_depth_attachment_.depth_plane = 0;
+ break;
+ case GPU_TEXTURE_1D_ARRAY:
+ if (layer < 0) {
+ layer = 0;
+ MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed\n");
+ }
+ BLI_assert(layer < texture->h_);
+ mtl_depth_attachment_.slice = layer;
+ mtl_depth_attachment_.depth_plane = 0;
+ break;
+ case GPU_TEXTURE_2D_ARRAY:
+ BLI_assert(layer < texture->d_);
+ mtl_depth_attachment_.slice = layer;
+ mtl_depth_attachment_.depth_plane = 0;
+ if (layer == -1) {
+ mtl_depth_attachment_.slice = 0;
+ mtl_depth_attachment_.render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_3D:
+ BLI_assert(layer < texture->d_);
+ mtl_depth_attachment_.slice = 0;
+ mtl_depth_attachment_.depth_plane = layer;
+ if (layer == -1) {
+ mtl_depth_attachment_.depth_plane = 0;
+ mtl_depth_attachment_.render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_CUBE:
+ BLI_assert(layer < 6);
+ mtl_depth_attachment_.slice = layer;
+ mtl_depth_attachment_.depth_plane = 0;
+ if (layer == -1) {
+ mtl_depth_attachment_.slice = 0;
+ mtl_depth_attachment_.depth_plane = 0;
+ mtl_depth_attachment_.render_target_array_length = 1;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_CUBE_ARRAY:
+ /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
+ BLI_assert(layer < 6 * texture->d_);
+ mtl_depth_attachment_.slice = layer;
+ mtl_depth_attachment_.depth_plane = 0;
+ if (layer == -1) {
+ mtl_depth_attachment_.slice = 0;
+ mtl_depth_attachment_.depth_plane = 0;
+ mtl_depth_attachment_.render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_BUFFER:
+ mtl_depth_attachment_.slice = 0;
+ mtl_depth_attachment_.depth_plane = 0;
+ break;
+ default:
+ BLI_assert(false && "Unrecognised texture type");
+ break;
+ }
+
+ /* Update Framebuffer Resolution. */
+ int width_of_miplayer, height_of_miplayer;
+ if (miplevel <= 0) {
+ width_of_miplayer = texture->width_get();
+ height_of_miplayer = texture->height_get();
+ }
+ else {
+ width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
+ height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
+ }
+
+ /* Update Framebuffer Resolution. */
+ if (width_ == 0 || height_ == 0) {
+ this->size_set(width_of_miplayer, height_of_miplayer);
+ this->scissor_reset();
+ this->viewport_reset();
+ BLI_assert(width_ > 0);
+ BLI_assert(height_ > 0);
+ }
+ else {
+ BLI_assert(width_ == texture->width_get());
+ BLI_assert(height_ == texture->height_get());
+ }
+
+ /* Flag as dirty after attachments changed. */
+ this->mark_dirty();
+ }
+ else {
+ MTL_LOG_ERROR(
+ "Passing in null texture to MTLFrameBuffer::addDepthAttachment (This could be due to not "
+ "all texture types being supported).");
+ }
+ return true;
+}
+
+bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplevel, int layer)
+{
+ BLI_assert(this);
+
+ if (texture) {
+ if (miplevel < 0 || miplevel >= MTL_MAX_MIPMAP_COUNT) {
+ MTL_LOG_WARNING("Attachment specified with invalid mip level %u\n", miplevel);
+ miplevel = 0;
+ }
+
+ /* Assume attachment load by default. */
+ mtl_stencil_attachment_.used = true;
+ mtl_stencil_attachment_.texture = texture;
+ mtl_stencil_attachment_.mip = miplevel;
+ mtl_stencil_attachment_.load_action = GPU_LOADACTION_LOAD;
+ mtl_stencil_attachment_.store_action = GPU_STOREACTION_STORE;
+ mtl_stencil_attachment_.render_target_array_length = 0;
+
+ /* Determine whether array slice or depth plane based on texture type. */
+ switch (texture->type_) {
+ case GPU_TEXTURE_1D:
+ case GPU_TEXTURE_2D:
+ BLI_assert(layer <= 0);
+ mtl_stencil_attachment_.slice = 0;
+ mtl_stencil_attachment_.depth_plane = 0;
+ break;
+ case GPU_TEXTURE_1D_ARRAY:
+ if (layer < 0) {
+ layer = 0;
+ MTL_LOG_WARNING("TODO: Support layered rendering for 1D array textures, if needed\n");
+ }
+ BLI_assert(layer < texture->h_);
+ mtl_stencil_attachment_.slice = layer;
+ mtl_stencil_attachment_.depth_plane = 0;
+ break;
+ case GPU_TEXTURE_2D_ARRAY:
+ BLI_assert(layer < texture->d_);
+ mtl_stencil_attachment_.slice = layer;
+ mtl_stencil_attachment_.depth_plane = 0;
+ if (layer == -1) {
+ mtl_stencil_attachment_.slice = 0;
+ mtl_stencil_attachment_.render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_3D:
+ BLI_assert(layer < texture->d_);
+ mtl_stencil_attachment_.slice = 0;
+ mtl_stencil_attachment_.depth_plane = layer;
+ if (layer == -1) {
+ mtl_stencil_attachment_.depth_plane = 0;
+ mtl_stencil_attachment_.render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_CUBE:
+ BLI_assert(layer < 6);
+ mtl_stencil_attachment_.slice = layer;
+ mtl_stencil_attachment_.depth_plane = 0;
+ if (layer == -1) {
+ mtl_stencil_attachment_.slice = 0;
+ mtl_stencil_attachment_.depth_plane = 0;
+ mtl_stencil_attachment_.render_target_array_length = 1;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_CUBE_ARRAY:
+ /* TODO(Metal): Verify multilayered rendering for Cube arrays. */
+ BLI_assert(layer < 6 * texture->d_);
+ mtl_stencil_attachment_.slice = layer;
+ mtl_stencil_attachment_.depth_plane = 0;
+ if (layer == -1) {
+ mtl_stencil_attachment_.slice = 0;
+ mtl_stencil_attachment_.depth_plane = 0;
+ mtl_stencil_attachment_.render_target_array_length = texture->d_;
+ use_multilayered_rendering_ = true;
+ }
+ break;
+ case GPU_TEXTURE_BUFFER:
+ mtl_stencil_attachment_.slice = 0;
+ mtl_stencil_attachment_.depth_plane = 0;
+ break;
+ default:
+ BLI_assert(false && "Unrecognised texture type");
+ break;
+ }
+
+ /* Update Framebuffer Resolution. */
+ int width_of_miplayer, height_of_miplayer;
+ if (miplevel <= 0) {
+ width_of_miplayer = texture->width_get();
+ height_of_miplayer = texture->height_get();
+ }
+ else {
+ width_of_miplayer = max_ii(texture->width_get() >> miplevel, 1);
+ height_of_miplayer = max_ii(texture->height_get() >> miplevel, 1);
+ }
+
+ /* Update Framebuffer Resolution. */
+ if (width_ == 0 || height_ == 0) {
+ this->size_set(width_of_miplayer, height_of_miplayer);
+ this->scissor_reset();
+ this->viewport_reset();
+ BLI_assert(width_ > 0);
+ BLI_assert(height_ > 0);
+ }
+ else {
+ BLI_assert(width_ == texture->width_get());
+ BLI_assert(height_ == texture->height_get());
+ }
+
+ /* Flag as dirty after attachments changed. */
+ this->mark_dirty();
+ }
+ else {
+ MTL_LOG_ERROR(
+ "Passing in null texture to MTLFrameBuffer::addStencilAttachment (This could be due to "
+ "not all texture types being supported).");
+ }
+ return true;
+}
+
+bool MTLFrameBuffer::remove_color_attachment(uint slot)
+{
+ BLI_assert(this);
+ BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
+
+ if (this->has_attachment_at_slot(slot)) {
+ colour_attachment_count_ -= (mtl_color_attachments_[slot].used) ? 1 : 0;
+ mtl_color_attachments_[slot].used = false;
+ this->ensure_render_target_size();
+ this->mark_dirty();
+ return true;
+ }
+
+ return false;
+}
+
+bool MTLFrameBuffer::remove_depth_attachment()
+{
+ BLI_assert(this);
+
+ mtl_depth_attachment_.used = false;
+ mtl_depth_attachment_.texture = nullptr;
+ this->ensure_render_target_size();
+ this->mark_dirty();
+
+ return true;
+}
+
+bool MTLFrameBuffer::remove_stencil_attachment()
+{
+ BLI_assert(this);
+
+ mtl_stencil_attachment_.used = false;
+ mtl_stencil_attachment_.texture = nullptr;
+ this->ensure_render_target_size();
+ this->mark_dirty();
+
+ return true;
+}
+
+void MTLFrameBuffer::remove_all_attachments()
+{
+ BLI_assert(this);
+
+ for (int attachment = 0; attachment < GPU_FB_MAX_COLOR_ATTACHMENT; attachment++) {
+ this->remove_color_attachment(attachment);
+ }
+ this->remove_depth_attachment();
+ this->remove_stencil_attachment();
+ colour_attachment_count_ = 0;
+ this->mark_dirty();
+
+ /* Verify height. */
+ this->ensure_render_target_size();
+
+ /* Flag attachments as no longer being dirty. */
+ dirty_attachments_ = false;
+}
+
+void MTLFrameBuffer::ensure_render_target_size()
+{
+ /* If we have no attachments, reset width and height to zero. */
+ if (colour_attachment_count_ == 0 && !this->has_depth_attachment() &&
+ !this->has_stencil_attachment()) {
+
+ /* Reset Viewport and Scissor for NULL framebuffer. */
+ this->size_set(0, 0);
+ this->scissor_reset();
+ this->viewport_reset();
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \ Clear values and Load-store actions
+ * \{ */
+
+void MTLFrameBuffer::attachment_set_loadstore_op(GPUAttachmentType type,
+ eGPULoadOp load_action,
+ eGPUStoreOp store_action)
+{
+ if (type >= GPU_FB_COLOR_ATTACHMENT0) {
+ int slot = type - GPU_FB_COLOR_ATTACHMENT0;
+ this->set_color_loadstore_op(slot, load_action, store_action);
+ }
+ else if (type == GPU_FB_DEPTH_STENCIL_ATTACHMENT) {
+ this->set_depth_loadstore_op(load_action, store_action);
+ this->set_stencil_loadstore_op(load_action, store_action);
+ }
+ else if (type == GPU_FB_DEPTH_ATTACHMENT) {
+ this->set_depth_loadstore_op(load_action, store_action);
+ }
+}
+
+bool MTLFrameBuffer::set_color_attachment_clear_color(uint slot, const float clear_color[4])
+{
+ BLI_assert(this);
+ BLI_assert(slot >= 0 && slot < this->get_attachment_limit());
+
+ /* Only mark as dirty if values have changed. */
+ bool changed = mtl_color_attachments_[slot].load_action != GPU_LOADACTION_CLEAR;
+ changed = changed || (memcmp(mtl_color_attachments_[slot].clear_value.color,
+ clear_color,
+ sizeof(float) * 4) != 0);
+ if (changed) {
+ memcpy(mtl_color_attachments_[slot].clear_value.color, clear_color, sizeof(float) * 4);
+ }
+ mtl_color_attachments_[slot].load_action = GPU_LOADACTION_CLEAR;
+
+ if (changed) {
+ this->mark_loadstore_dirty();
+ }
+ return true;
+}
+
+bool MTLFrameBuffer::set_depth_attachment_clear_value(float depth_clear)
+{
+ BLI_assert(this);
+
+ if (mtl_depth_attachment_.clear_value.depth != depth_clear ||
+ mtl_depth_attachment_.load_action != GPU_LOADACTION_CLEAR) {
+ mtl_depth_attachment_.clear_value.depth = depth_clear;
+ mtl_depth_attachment_.load_action = GPU_LOADACTION_CLEAR;
+ this->mark_loadstore_dirty();
+ }
+ return true;
+}
+
+bool MTLFrameBuffer::set_stencil_attachment_clear_value(uint stencil_clear)
+{
+ BLI_assert(this);
+
+ if (mtl_stencil_attachment_.clear_value.stencil != stencil_clear ||
+ mtl_stencil_attachment_.load_action != GPU_LOADACTION_CLEAR) {
+ mtl_stencil_attachment_.clear_value.stencil = stencil_clear;
+ mtl_stencil_attachment_.load_action = GPU_LOADACTION_CLEAR;
+ this->mark_loadstore_dirty();
+ }
+ return true;
+}
+
+bool MTLFrameBuffer::set_color_loadstore_op(uint slot,
+ eGPULoadOp load_action,
+ eGPUStoreOp store_action)
+{
+ BLI_assert(this);
+ eGPULoadOp prev_load_action = mtl_color_attachments_[slot].load_action;
+ eGPUStoreOp prev_store_action = mtl_color_attachments_[slot].store_action;
+ mtl_color_attachments_[slot].load_action = load_action;
+ mtl_color_attachments_[slot].store_action = store_action;
+
+ bool changed = (mtl_color_attachments_[slot].load_action != prev_load_action ||
+ mtl_color_attachments_[slot].store_action != prev_store_action);
+ if (changed) {
+ this->mark_loadstore_dirty();
+ }
+
+ return changed;
+}
+
+bool MTLFrameBuffer::set_depth_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action)
+{
+ BLI_assert(this);
+ eGPULoadOp prev_load_action = mtl_depth_attachment_.load_action;
+ eGPUStoreOp prev_store_action = mtl_depth_attachment_.store_action;
+ mtl_depth_attachment_.load_action = load_action;
+ mtl_depth_attachment_.store_action = store_action;
+
+ bool changed = (mtl_depth_attachment_.load_action != prev_load_action ||
+ mtl_depth_attachment_.store_action != prev_store_action);
+ if (changed) {
+ this->mark_loadstore_dirty();
+ }
+
+ return changed;
+}
+
+bool MTLFrameBuffer::set_stencil_loadstore_op(eGPULoadOp load_action, eGPUStoreOp store_action)
+{
+ BLI_assert(this);
+ eGPULoadOp prev_load_action = mtl_stencil_attachment_.load_action;
+ eGPUStoreOp prev_store_action = mtl_stencil_attachment_.store_action;
+ mtl_stencil_attachment_.load_action = load_action;
+ mtl_stencil_attachment_.store_action = store_action;
+
+ bool changed = (mtl_stencil_attachment_.load_action != prev_load_action ||
+ mtl_stencil_attachment_.store_action != prev_store_action);
+ if (changed) {
+ this->mark_loadstore_dirty();
+ }
+
+ return changed;
+}
+
+bool MTLFrameBuffer::reset_clear_state()
+{
+ for (int slot = 0; slot < colour_attachment_count_; slot++) {
+ this->set_color_loadstore_op(slot, GPU_LOADACTION_LOAD, GPU_STOREACTION_STORE);
+ }
+ this->set_depth_loadstore_op(GPU_LOADACTION_LOAD, GPU_STOREACTION_STORE);
+ this->set_stencil_loadstore_op(GPU_LOADACTION_LOAD, GPU_STOREACTION_STORE);
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \ Fetch values and Framebuffer status
+ * \{ */
+
+bool MTLFrameBuffer::has_attachment_at_slot(uint slot)
+{
+ BLI_assert(this);
+
+ if (slot >= 0 && slot < this->get_attachment_limit()) {
+ return mtl_color_attachments_[slot].used;
+ }
+ return false;
+}
+
+bool MTLFrameBuffer::has_color_attachment_with_texture(gpu::MTLTexture *texture)
+{
+ BLI_assert(this);
+
+ for (int attachment = 0; attachment < this->get_attachment_limit(); attachment++) {
+ if (mtl_color_attachments_[attachment].used &&
+ mtl_color_attachments_[attachment].texture == texture) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool MTLFrameBuffer::has_depth_attachment()
+{
+ BLI_assert(this);
+ return mtl_depth_attachment_.used;
+}
+
+bool MTLFrameBuffer::has_stencil_attachment()
+{
+ BLI_assert(this);
+ return mtl_stencil_attachment_.used;
+}
+
+int MTLFrameBuffer::get_color_attachment_slot_from_texture(gpu::MTLTexture *texture)
+{
+ BLI_assert(this);
+ BLI_assert(texture);
+
+ for (int attachment = 0; attachment < this->get_attachment_limit(); attachment++) {
+ if (mtl_color_attachments_[attachment].used &&
+ (mtl_color_attachments_[attachment].texture == texture)) {
+ return attachment;
+ }
+ }
+ return -1;
+}
+
+uint MTLFrameBuffer::get_attachment_count()
+{
+ BLI_assert(this);
+ return colour_attachment_count_;
+}
+
+MTLAttachment MTLFrameBuffer::get_color_attachment(uint slot)
+{
+ BLI_assert(this);
+ if (slot >= 0 && slot < GPU_FB_MAX_COLOR_ATTACHMENT) {
+ return mtl_color_attachments_[slot];
+ }
+ MTLAttachment null_attachment;
+ null_attachment.used = false;
+ return null_attachment;
+}
+
+MTLAttachment MTLFrameBuffer::get_depth_attachment()
+{
+ BLI_assert(this);
+ return mtl_depth_attachment_;
+}
+
+MTLAttachment MTLFrameBuffer::get_stencil_attachment()
+{
+ BLI_assert(this);
+ return mtl_stencil_attachment_;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \ METAL API Resources and Validation
+ * \{ */
+bool MTLFrameBuffer::validate_render_pass()
+{
+ BLI_assert(this);
+
+ /* First update attachments if dirty. */
+ this->update_attachments(true);
+
+ /* Verify attachment count. */
+ int used_attachments = 0;
+ for (int attachment = 0; attachment < GPU_FB_MAX_COLOR_ATTACHMENT; attachment++) {
+ if (mtl_color_attachments_[attachment].used) {
+ used_attachments++;
+ }
+ }
+ used_attachments += (mtl_depth_attachment_.used) ? 1 : 0;
+ used_attachments += (mtl_stencil_attachment_.used) ? 1 : 0;
+ return (used_attachments > 0);
+}
+
+MTLLoadAction mtl_load_action_from_gpu(eGPULoadOp action)
+{
+ return (action == GPU_LOADACTION_LOAD) ?
+ MTLLoadActionLoad :
+ ((action == GPU_LOADACTION_CLEAR) ? MTLLoadActionClear : MTLLoadActionDontCare);
+}
+
+MTLStoreAction mtl_store_action_from_gpu(eGPUStoreOp action)
+{
+ return (action == GPU_STOREACTION_STORE) ? MTLStoreActionStore : MTLStoreActionDontCare;
+}
+
+MTLRenderPassDescriptor *MTLFrameBuffer::bake_render_pass_descriptor(bool load_contents)
+{
+ BLI_assert(this);
+ if (load_contents) {
+ /* Only force-load contents if there is no clear pending. */
+ BLI_assert(!has_pending_clear_);
+ }
+
+ /* Ensure we are inside a frame boundary. */
+ MTLContext *metal_ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
+ BLI_assert(metal_ctx && metal_ctx->get_inside_frame());
+ UNUSED_VARS_NDEBUG(metal_ctx);
+
+ /* If Framebuffer has been modified, regenerate descriptor. */
+ if (is_dirty_) {
+ /* Clear all configs. */
+ for (int config = 0; config < 3; config++) {
+ descriptor_dirty_[config] = true;
+ }
+ }
+ else if (is_loadstore_dirty_) {
+ /* Load config always has load ops, so we only need to re-generate custom and clear state. */
+ descriptor_dirty_[MTL_FB_CONFIG_CLEAR] = true;
+ descriptor_dirty_[MTL_FB_CONFIG_CUSTOM] = true;
+ }
+
+ /* If we need to populate descriptor" */
+ /* Select config based on FrameBuffer state:
+ * [0] {MTL_FB_CONFIG_CLEAR} = Clear config -- we have a pending clear so should perform our
+ * configured clear.
+ * [1] {MTL_FB_CONFIG_LOAD} = Load config -- We need to re-load ALL attachments,
+ * used for re-binding/pass-breaks.
+ * [2] {MTL_FB_CONFIG_CUSTOM} = Custom config -- Use this when a custom binding config is
+ * specified.
+ */
+ uint descriptor_config = (load_contents) ? MTL_FB_CONFIG_LOAD :
+ ((this->get_pending_clear()) ? MTL_FB_CONFIG_CLEAR :
+ MTL_FB_CONFIG_CUSTOM);
+ if (descriptor_dirty_[descriptor_config] || framebuffer_descriptor_[descriptor_config] == nil) {
+
+ /* Create descriptor if it does not exist. */
+ if (framebuffer_descriptor_[descriptor_config] == nil) {
+ framebuffer_descriptor_[descriptor_config] = [[MTLRenderPassDescriptor alloc] init];
+ }
+
+#if defined(MAC_OS_X_VERSION_11_0) && __MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_11_0
+ if (@available(macOS 11.00, *)) {
+ /* Optimization: Use smaller tile size on Apple Silicon if exceeding a certain bpp limit. */
+ bool is_tile_based_gpu = [metal_ctx->device hasUnifiedMemory];
+ if (is_tile_based_gpu) {
+ uint framebuffer_bpp = this->get_bits_per_pixel();
+ bool use_small_tiles = (framebuffer_bpp > 64);
+
+ if (use_small_tiles) {
+ framebuffer_descriptor_[descriptor_config].tileWidth = 16;
+ framebuffer_descriptor_[descriptor_config].tileHeight = 16;
+ }
+ }
+ }
+#endif
+
+ /* Configure multilayered rendering. */
+ if (use_multilayered_rendering_) {
+ /* Ensure all targets have the same length. */
+ int len = 0;
+ bool valid = true;
+
+ for (int attachment_ind = 0; attachment_ind < GPU_FB_MAX_COLOR_ATTACHMENT;
+ attachment_ind++) {
+ if (mtl_color_attachments_[attachment_ind].used) {
+ if (len == 0) {
+ len = mtl_color_attachments_[attachment_ind].render_target_array_length;
+ }
+ else {
+ valid = valid &&
+ (len == mtl_color_attachments_[attachment_ind].render_target_array_length);
+ }
+ }
+ }
+
+ if (mtl_depth_attachment_.used) {
+ if (len == 0) {
+ len = mtl_depth_attachment_.render_target_array_length;
+ }
+ else {
+ valid = valid && (len == mtl_depth_attachment_.render_target_array_length);
+ }
+ }
+
+ if (mtl_stencil_attachment_.used) {
+ if (len == 0) {
+ len = mtl_stencil_attachment_.render_target_array_length;
+ }
+ else {
+ valid = valid && (len == mtl_stencil_attachment_.render_target_array_length);
+ }
+ }
+
+ BLI_assert(len > 0);
+ BLI_assert(valid);
+ framebuffer_descriptor_[descriptor_config].renderTargetArrayLength = len;
+ }
+ else {
+ framebuffer_descriptor_[descriptor_config].renderTargetArrayLength = 0;
+ }
+
+ /* Color attachments. */
+ int colour_attachments = 0;
+ for (int attachment_ind = 0; attachment_ind < GPU_FB_MAX_COLOR_ATTACHMENT; attachment_ind++) {
+
+ if (mtl_color_attachments_[attachment_ind].used) {
+
+ /* Create attachment descriptor. */
+ MTLRenderPassColorAttachmentDescriptor *attachment =
+ colour_attachment_descriptors_[attachment_ind];
+ BLI_assert(attachment != nil);
+
+ id<MTLTexture> texture =
+ mtl_color_attachments_[attachment_ind].texture->get_metal_handle_base();
+ if (texture == nil) {
+ MTL_LOG_ERROR("Attempting to assign invalid texture as attachment\n");
+ }
+
+ /* IF SRGB is enabled, but we are rendering with SRGB disabled, sample texture view. */
+ /* TODO(Metal): Consider caching SRGB texture view. */
+ id<MTLTexture> source_color_texture = texture;
+ if (this->get_is_srgb() && !this->get_srgb_enabled()) {
+ source_color_texture = [texture newTextureViewWithPixelFormat:MTLPixelFormatRGBA8Unorm];
+ }
+
+ /* Resolve appropriate load action -- IF force load, perform load.
+ * If clear but framebuffer has no pending clear, also load. */
+ eGPULoadOp load_action = mtl_color_attachments_[attachment_ind].load_action;
+ if (descriptor_config == MTL_FB_CONFIG_LOAD) {
+ /* MTL_FB_CONFIG_LOAD must always load. */
+ load_action = GPU_LOADACTION_LOAD;
+ }
+ else if (descriptor_config == MTL_FB_CONFIG_CUSTOM &&
+ load_action == GPU_LOADACTION_CLEAR) {
+ /* Custom config should be LOAD or DONT_CARE only. */
+ load_action = GPU_LOADACTION_LOAD;
+ }
+ attachment.texture = source_color_texture;
+ attachment.loadAction = mtl_load_action_from_gpu(load_action);
+ attachment.clearColor =
+ (load_action == GPU_LOADACTION_CLEAR) ?
+ MTLClearColorMake(mtl_color_attachments_[attachment_ind].clear_value.color[0],
+ mtl_color_attachments_[attachment_ind].clear_value.color[1],
+ mtl_color_attachments_[attachment_ind].clear_value.color[2],
+ mtl_color_attachments_[attachment_ind].clear_value.color[3]) :
+ MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
+ attachment.storeAction = mtl_store_action_from_gpu(
+ mtl_color_attachments_[attachment_ind].store_action);
+ attachment.level = mtl_color_attachments_[attachment_ind].mip;
+ attachment.slice = mtl_color_attachments_[attachment_ind].slice;
+ attachment.depthPlane = mtl_color_attachments_[attachment_ind].depth_plane;
+ colour_attachments++;
+
+ /* Copy attachment info back in. */
+ [framebuffer_descriptor_[descriptor_config].colorAttachments setObject:attachment
+ atIndexedSubscript:attachment_ind];
+ }
+ else {
+ /* Disable colour attachment. */
+ [framebuffer_descriptor_[descriptor_config].colorAttachments setObject:nil
+ atIndexedSubscript:attachment_ind];
+ }
+ }
+ BLI_assert(colour_attachments == colour_attachment_count_);
+
+ /* Depth attachment. */
+ if (mtl_depth_attachment_.used) {
+ framebuffer_descriptor_[descriptor_config].depthAttachment.texture =
+ (id<MTLTexture>)mtl_depth_attachment_.texture->get_metal_handle_base();
+
+ /* Resolve appropriate load action -- IF force load, perform load.
+ * If clear but framebuffer has no pending clear, also load. */
+ eGPULoadOp load_action = mtl_depth_attachment_.load_action;
+ if (descriptor_config == MTL_FB_CONFIG_LOAD) {
+ /* MTL_FB_CONFIG_LOAD must always load. */
+ load_action = GPU_LOADACTION_LOAD;
+ }
+ else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
+ /* Custom config should be LOAD or DONT_CARE only. */
+ load_action = GPU_LOADACTION_LOAD;
+ }
+ framebuffer_descriptor_[descriptor_config].depthAttachment.loadAction =
+ mtl_load_action_from_gpu(load_action);
+ framebuffer_descriptor_[descriptor_config].depthAttachment.clearDepth =
+ (load_action == GPU_LOADACTION_CLEAR) ? mtl_depth_attachment_.clear_value.depth : 0;
+ framebuffer_descriptor_[descriptor_config].depthAttachment.storeAction =
+ mtl_store_action_from_gpu(mtl_depth_attachment_.store_action);
+ framebuffer_descriptor_[descriptor_config].depthAttachment.level = mtl_depth_attachment_.mip;
+ framebuffer_descriptor_[descriptor_config].depthAttachment.slice =
+ mtl_depth_attachment_.slice;
+ framebuffer_descriptor_[descriptor_config].depthAttachment.depthPlane =
+ mtl_depth_attachment_.depth_plane;
+ }
+ else {
+ framebuffer_descriptor_[descriptor_config].depthAttachment.texture = nil;
+ }
+
+ /* Stencil attachment. */
+ if (mtl_stencil_attachment_.used) {
+ framebuffer_descriptor_[descriptor_config].stencilAttachment.texture =
+ (id<MTLTexture>)mtl_stencil_attachment_.texture->get_metal_handle_base();
+
+ /* Resolve appropriate load action -- IF force load, perform load.
+ * If clear but framebuffer has no pending clear, also load. */
+ eGPULoadOp load_action = mtl_stencil_attachment_.load_action;
+ if (descriptor_config == MTL_FB_CONFIG_LOAD) {
+ /* MTL_FB_CONFIG_LOAD must always load. */
+ load_action = GPU_LOADACTION_LOAD;
+ }
+ else if (descriptor_config == MTL_FB_CONFIG_CUSTOM && load_action == GPU_LOADACTION_CLEAR) {
+ /* Custom config should be LOAD or DONT_CARE only. */
+ load_action = GPU_LOADACTION_LOAD;
+ }
+ framebuffer_descriptor_[descriptor_config].stencilAttachment.loadAction =
+ mtl_load_action_from_gpu(load_action);
+ framebuffer_descriptor_[descriptor_config].stencilAttachment.clearStencil =
+ (load_action == GPU_LOADACTION_CLEAR) ? mtl_stencil_attachment_.clear_value.stencil : 0;
+ framebuffer_descriptor_[descriptor_config].stencilAttachment.storeAction =
+ mtl_store_action_from_gpu(mtl_stencil_attachment_.store_action);
+ framebuffer_descriptor_[descriptor_config].stencilAttachment.level =
+ mtl_stencil_attachment_.mip;
+ framebuffer_descriptor_[descriptor_config].stencilAttachment.slice =
+ mtl_stencil_attachment_.slice;
+ framebuffer_descriptor_[descriptor_config].stencilAttachment.depthPlane =
+ mtl_stencil_attachment_.depth_plane;
+ }
+ else {
+ framebuffer_descriptor_[descriptor_config].stencilAttachment.texture = nil;
+ }
+ descriptor_dirty_[descriptor_config] = false;
+ }
+ is_dirty_ = false;
+ is_loadstore_dirty_ = false;
+ return framebuffer_descriptor_[descriptor_config];
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \ Blitting
+ * \{ */
+
+void MTLFrameBuffer::blit(uint read_slot,
+ uint src_x_offset,
+ uint src_y_offset,
+ MTLFrameBuffer *metal_fb_write,
+ uint write_slot,
+ uint dst_x_offset,
+ uint dst_y_offset,
+ uint width,
+ uint height,
+ eGPUFrameBufferBits blit_buffers)
+{
+ BLI_assert(this);
+ BLI_assert(metal_fb_write);
+ if (!(this && metal_fb_write)) {
+ return;
+ }
+ MTLContext *mtl_context = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+
+ const bool do_color = (blit_buffers & GPU_COLOR_BIT);
+ const bool do_depth = (blit_buffers & GPU_DEPTH_BIT);
+ const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT);
+
+ /* Early exit if there is no blit to do. */
+ if (!(do_color || do_depth || do_stencil)) {
+ MTL_LOG_WARNING(
+ " MTLFrameBuffer: requested blit but no color, depth or stencil flag was set\n");
+ return;
+ }
+
+ id<MTLBlitCommandEncoder> blit_encoder = nil;
+
+ /* If the color format is not the same, we cannot use the BlitCommandEncoder, and instead use
+ * a Graphics-based blit. */
+ if (do_color && (this->get_color_attachment(read_slot).texture->format_get() !=
+ metal_fb_write->get_color_attachment(read_slot).texture->format_get())) {
+
+ MTLAttachment src_attachment = this->get_color_attachment(read_slot);
+ MTLAttachment dst_attachment = metal_fb_write->get_color_attachment(write_slot);
+ assert(src_attachment.slice == 0 &&
+ "currently only supporting slice 0 for graphics framebuffer blit");
+
+ src_attachment.texture->blit(dst_attachment.texture,
+ src_x_offset,
+ src_y_offset,
+ dst_x_offset,
+ dst_y_offset,
+ src_attachment.mip,
+ dst_attachment.mip,
+ dst_attachment.slice,
+ width,
+ height);
+ }
+ else {
+
+ /* Setup blit encoder. */
+ blit_encoder = mtl_context->main_command_buffer.ensure_begin_blit_encoder();
+
+ if (do_color) {
+ MTLAttachment src_attachment = this->get_color_attachment(read_slot);
+ MTLAttachment dst_attachment = metal_fb_write->get_color_attachment(write_slot);
+
+ if (src_attachment.used && dst_attachment.used) {
+
+ /* TODO(Metal): Support depth(z) offset in blit if needed. */
+ src_attachment.texture->blit(blit_encoder,
+ src_x_offset,
+ src_y_offset,
+ 0,
+ src_attachment.slice,
+ src_attachment.mip,
+ dst_attachment.texture,
+ dst_x_offset,
+ dst_y_offset,
+ 0,
+ dst_attachment.slice,
+ dst_attachment.mip,
+ width,
+ height,
+ 1);
+ }
+ else {
+ MTL_LOG_ERROR("Failed performing colour blit\n");
+ }
+ }
+ }
+ if ((do_depth || do_stencil) && blit_encoder == nil) {
+ blit_encoder = mtl_context->main_command_buffer.ensure_begin_blit_encoder();
+ }
+
+ if (do_depth) {
+ MTLAttachment src_attachment = this->get_depth_attachment();
+ MTLAttachment dst_attachment = metal_fb_write->get_depth_attachment();
+
+ if (src_attachment.used && dst_attachment.used) {
+
+ /* TODO(Metal): Support depth(z) offset in blit if needed. */
+ src_attachment.texture->blit(blit_encoder,
+ src_x_offset,
+ src_y_offset,
+ 0,
+ src_attachment.slice,
+ src_attachment.mip,
+ dst_attachment.texture,
+ dst_x_offset,
+ dst_y_offset,
+ 0,
+ dst_attachment.slice,
+ dst_attachment.mip,
+ width,
+ height,
+ 1);
+ }
+ else {
+ MTL_LOG_ERROR("Failed performing depth blit\n");
+ }
+ }
+
+ /* Stencil attachment blit. */
+ if (do_stencil) {
+ MTLAttachment src_attachment = this->get_stencil_attachment();
+ MTLAttachment dst_attachment = metal_fb_write->get_stencil_attachment();
+
+ if (src_attachment.used && dst_attachment.used) {
+
+ /* TODO(Metal): Support depth(z) offset in blit if needed. */
+ src_attachment.texture->blit(blit_encoder,
+ src_x_offset,
+ src_y_offset,
+ 0,
+ src_attachment.slice,
+ src_attachment.mip,
+ dst_attachment.texture,
+ dst_x_offset,
+ dst_y_offset,
+ 0,
+ dst_attachment.slice,
+ dst_attachment.mip,
+ width,
+ height,
+ 1);
+ }
+ else {
+ MTL_LOG_ERROR("Failed performing Stencil blit\n");
+ }
+ }
+}
+
+int MTLFrameBuffer::get_width()
+{
+ return width_;
+}
+int MTLFrameBuffer::get_height()
+{
+ return height_;
+}
+
+} // blender::gpu
diff --git a/source/blender/gpu/metal/mtl_memory.hh b/source/blender/gpu/metal/mtl_memory.hh
new file mode 100644
index 00000000000..dc5417dc11a
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_memory.hh
@@ -0,0 +1,482 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <atomic>
+#include <functional>
+#include <map>
+#include <mutex>
+#include <set>
+#include <unordered_map>
+
+#include "mtl_common.hh"
+
+#include <Cocoa/Cocoa.h>
+#include <Metal/Metal.h>
+#include <QuartzCore/QuartzCore.h>
+
+@class CAMetalLayer;
+@class MTLCommandQueue;
+@class MTLRenderPipelineState;
+
+/* Metal Memory Manager Overview. */
+/*
+ * The Metal Backend Memory manager is designed to provide an interface
+ * for all other MTL_* modules where memory allocation is required.
+ *
+ * Different allocation strategies and data-structures are used depending
+ * on how the data is used by the backend. These aim to optimally handle
+ * system memory and abstract away any complexity from the MTL_* modules
+ * themselves.
+ *
+ * There are two primary allocation modes which can be used:
+ *
+ * ** MTLScratchBufferManager **
+ *
+ * Each MTLContext owns a ScratchBufferManager which is implemented
+ * as a pool of circular buffers, designed to handle temporary
+ * memory allocations which occur on a per-frame basis. The scratch
+ * buffers allow flushing of host memory to the GPU to be batched.
+ *
+ * Each frame, the next scratch buffer is reset, then later flushed upon
+ * command buffer submission.
+ *
+ * Note: This is allocated per-context due to allocations being tied
+ * to workload submissions and context-specific submissions.
+ *
+ * Examples of scratch buffer usage are:
+ * - Immediate-mode temporary vertex buffers.
+ * - Shader uniform data updates
+ * - Staging of data for resource copies, or, data reads/writes.
+ *
+ * Usage:
+ *
+ * MTLContext::get_scratchbuffer_manager() - to fetch active manager.
+ *
+ * MTLTemporaryBuffer scratch_buffer_allocate_range(size)
+ * MTLTemporaryBuffer scratch_buffer_allocate_range_aligned(size, align)
+ *
+ * ---------------------------------------------------------------------------------
+ * ** MTLBufferPool **
+ *
+ * For static and longer-lasting memory allocations, such as those for UBOs,
+ * Vertex buffers, index buffers, etc; We want an optimal abstraction for
+ * fetching a MTLBuffer of the desired size and resource options.
+ *
+ * Memory allocations can be expensive so the MTLBufferPool provides
+ * functionality to track usage of these buffers and once a buffer
+ * is no longer in use, it is returned to the buffer pool for use
+ * by another backend resource.
+ *
+ * The MTLBufferPool provides functionality for safe tracking of resources,
+ * as buffers freed on the host side must have their usage by the GPU tracked,
+ * to ensure they are not prematurely re-used before they have finished being
+ * used by the GPU.
+ *
+ * Note: The MTLBufferPool is a global construct which can be fetched from anywhere.
+ *
+ * Usage:
+ * MTLContext::get_global_memory_manager(); - static routine to fetch global memory manager.
+ *
+ * gpu::MTLBuffer *allocate(size, is_cpu_visibile)
+ * gpu::MTLBuffer *allocate_aligned(size, alignment, is_cpu_visibile)
+ * gpu::MTLBuffer *allocate_with_data(size, is_cpu_visibile, data_ptr)
+ * gpu::MTLBuffer *allocate_aligned_with_data(size, alignment, is_cpu_visibile, data_ptr)
+ */
+
+/* Debug memory statistics: Disabled by Macro rather than guarded for
+ * performance considerations. */
+#define MTL_DEBUG_MEMORY_STATISTICS 0
+
+/* Allows a scratch buffer to temporarily grow beyond its maximum, which allows submission
+ * of one-time-use data packets which are too large. */
+#define MTL_SCRATCH_BUFFER_ALLOW_TEMPORARY_EXPANSION 1
+
+namespace blender::gpu {
+
+/* Forward Declarations. */
+class MTLContext;
+class MTLCommandBufferManager;
+class MTLUniformBuf;
+
+/* -------------------------------------------------------------------- */
+/** \name Memory Management.
+ * \{ */
+
+/* MTLBuffer allocation wrapper. */
+class MTLBuffer {
+
+ private:
+ /* Metal resource. */
+ id<MTLBuffer> metal_buffer_;
+
+ /* Host-visible mapped-memory pointer. Behavior depends on buffer type:
+ * - Shared buffers: pointer represents base address of #MTLBuffer whose data
+ * access has shared access by both the CPU and GPU on
+ * Unified Memory Architectures (UMA).
+ * - Managed buffer: Host-side mapped buffer region for CPU (Host) access. Managed buffers
+ * must be manually flushed to transfer data to GPU-resident buffer.
+ * - Private buffer: Host access is invalid, `data` will be nullptr. */
+ void *data_;
+
+ /* Whether buffer is allocated from an external source. */
+ bool is_external_ = false;
+
+ /* Allocation info. */
+ MTLResourceOptions options_;
+ id<MTLDevice> device_;
+ uint64_t alignment_;
+ uint64_t size_;
+
+ /* Allocated size may be larger than actual size. */
+ uint64_t usage_size_;
+
+ /* Lifetime info - whether the current buffer is actively in use. A buffer
+ * should be in use after it has been allocated. De-allocating the buffer, and
+ * returning it to the free buffer pool will set in_use to false. Using a buffer
+ * while it is not in-use should not be allowed and result in an error. */
+ std::atomic<bool> in_use_;
+
+ public:
+ MTLBuffer(id<MTLDevice> device, uint64_t size, MTLResourceOptions options, uint alignment = 1);
+ MTLBuffer(id<MTLBuffer> external_buffer);
+ ~MTLBuffer();
+
+ /* Fetch information about backing MTLBuffer. */
+ id<MTLBuffer> get_metal_buffer() const;
+ void *get_host_ptr() const;
+ uint64_t get_size_used() const;
+ uint64_t get_size() const;
+
+ /* Flush data to GPU. */
+ void flush();
+ void flush_range(uint64_t offset, uint64_t length);
+ bool requires_flush();
+
+ /* Buffer usage tracking. */
+ void flag_in_use(bool used);
+ bool get_in_use();
+ void set_usage_size(uint64_t size_used);
+
+ /* Debug. */
+ void set_label(NSString *str);
+
+ /* Read properties. */
+ MTLResourceOptions get_resource_options();
+ uint64_t get_alignment();
+
+ /* Resource-local free: For buffers allocated via memory manager,
+ * this will call the context `free_buffer` method to return the buffer to the context memory
+ * pool.
+ *
+ * Otherwise, free will release the associated metal resource.
+ * As a note, calling the destructor will also destroy the buffer and associated metal
+ * resource. */
+ void free();
+
+ /* Safety check to ensure buffers are not used after free. */
+ void debug_ensure_used();
+};
+
+/* View into part of an MTLBuffer. */
+struct MTLBufferRange {
+ id<MTLBuffer> metal_buffer;
+ void *data;
+ uint64_t buffer_offset;
+ uint64_t size;
+ MTLResourceOptions options;
+
+ void flush();
+ bool requires_flush();
+};
+
+/* Circular scratch buffer allocations should be seen as temporary and only used within the
+ * lifetime of the frame. */
+using MTLTemporaryBuffer = MTLBufferRange;
+
+/* Round-Robin Circular-buffer. */
+class MTLCircularBuffer {
+ friend class MTLScratchBufferManager;
+
+ private:
+ MTLContext &own_context_;
+
+ /* Wrapped MTLBuffer allocation handled. */
+ gpu::MTLBuffer *cbuffer_;
+
+ /* Current offset where next allocation will begin. */
+ uint64_t current_offset_;
+
+ /* Whether the Circular Buffer can grow during re-allocation if
+ * the size is exceeded. */
+ bool can_resize_;
+
+ /* Usage information. */
+ uint64_t used_frame_index_;
+ uint64_t last_flush_base_offset_;
+
+ public:
+ MTLCircularBuffer(MTLContext &ctx, uint64_t initial_size, bool allow_grow);
+ ~MTLCircularBuffer();
+ MTLTemporaryBuffer allocate_range(uint64_t alloc_size);
+ MTLTemporaryBuffer allocate_range_aligned(uint64_t alloc_size, uint alignment);
+ void flush();
+
+ /* Reset pointer back to start of circular buffer. */
+ void reset();
+};
+
+/* Wrapper struct used by Memory Manager to sort and compare gpu::MTLBuffer resources inside the
+ * memory pools. */
+struct MTLBufferHandle {
+ gpu::MTLBuffer *buffer;
+ uint64_t buffer_size;
+
+ inline MTLBufferHandle(gpu::MTLBuffer *buf)
+ {
+ this->buffer = buf;
+ this->buffer_size = this->buffer->get_size();
+ }
+
+ inline MTLBufferHandle(uint64_t compare_size)
+ {
+ this->buffer = nullptr;
+ this->buffer_size = compare_size;
+ }
+};
+
+struct CompareMTLBuffer {
+ bool operator()(const MTLBufferHandle &lhs, const MTLBufferHandle &rhs) const
+ {
+ return lhs.buffer_size < rhs.buffer_size;
+ }
+};
+
+/* An MTLSafeFreeList is a temporary list of gpu::MTLBuffers which have
+ * been freed by the high level backend, but are pending GPU work execution before
+ * the gpu::MTLBuffers can be returned to the Memory manager pools.
+ * This list is implemented as a chunked linked-list.
+ *
+ * Only a single MTLSafeFreeList is active at one time and is associated with current command
+ * buffer submissions. If an MTLBuffer is freed during the lifetime of a command buffer, it could
+ * still possibly be in-use and as such, the MTLSafeFreeList will increment its reference count for
+ * each command buffer submitted while the current pool is active.
+ *
+ * -- Reference count is incremented upon MTLCommandBuffer commit.
+ * -- Reference count is decremented in the MTLCommandBuffer completion callback handler.
+ *
+ * A new MTLSafeFreeList will begin each render step (frame). This pooling of buffers, rather than
+ * individual buffer resource tracking reduces performance overhead.
+ *
+ * * The reference count starts at 1 to ensure that the reference count cannot prematurely reach
+ * zero until any command buffers have been submitted. This additional decrement happens
+ * when the next MTLSafeFreeList is created, to allow the existing pool to be released once
+ * the reference count hits zero after submitted command buffers complete.
+ *
+ * Note: the Metal API independently tracks resources used by command buffers for the purpose of
+ * keeping resources alive while in-use by the driver and CPU, however, this differs from the
+ * MTLSafeFreeList mechanism in the Metal backend, which exists for the purpose of allowing
+ * previously allocated MTLBuffer resources to be re-used. This allows us to save on the expensive
+ * cost of memory allocation.
+ */
+class MTLSafeFreeList {
+ friend class MTLBufferPool;
+
+ private:
+ std::atomic<int> reference_count_;
+ std::atomic<bool> in_free_queue_;
+ std::recursive_mutex lock_;
+
+ /* Linked list of next MTLSafeFreeList chunk if current chunk is full. */
+ std::atomic<int> has_next_pool_;
+ std::atomic<MTLSafeFreeList *> next_;
+
+ /* Lockless list. MAX_NUM_BUFFERS_ within a chunk based on considerations
+ * for performance and memory. */
+ static const int MAX_NUM_BUFFERS_ = 1024;
+ std::atomic<int> current_list_index_;
+ gpu::MTLBuffer *safe_free_pool_[MAX_NUM_BUFFERS_];
+
+ public:
+ MTLSafeFreeList();
+
+ /* Add buffer to Safe Free List, can be called from secondary threads.
+ * Performs a lockless list insert. */
+ void insert_buffer(gpu::MTLBuffer *buffer);
+
+ /* Increments command buffer reference count. */
+ void increment_reference();
+
+ /* Decrement and return of buffers to pool occur on MTLCommandBuffer completion callback thread.
+ */
+ void decrement_reference();
+
+ void flag_in_queue()
+ {
+ in_free_queue_ = true;
+ if (has_next_pool_) {
+ MTLSafeFreeList *next_pool = next_.load();
+ BLI_assert(next_pool != nullptr);
+ next_pool->flag_in_queue();
+ }
+ }
+};
+
+/* MTLBuffer pools. */
+/* Allocating Metal buffers is expensive, so we cache all allocated buffers,
+ * and when requesting a new buffer, find one which fits the required dimensions
+ * from an existing pool of buffers.
+ *
+ * When freeing MTLBuffers, we insert them into the current MTLSafeFreeList, which defers
+ * release of the buffer until the associated command buffers have finished executing.
+ * This prevents a buffer from being re-used while it is still in-use by the GPU.
+ *
+ * * Once command buffers complete, MTLSafeFreeList's associated with the current
+ * command buffer submission are added to the `completed_safelist_queue_`.
+ *
+ * * At a set point in time, all MTLSafeFreeList's in `completed_safelist_queue_` have their
+ * MTLBuffers re-inserted into the Memory Manager's pools. */
+class MTLBufferPool {
+
+ private:
+ /* Memory statistics. */
+ long long int total_allocation_bytes_ = 0;
+
+#if MTL_DEBUG_MEMORY_STATISTICS == 1
+ /* Debug statistics. */
+ std::atomic<int> per_frame_allocation_count_;
+ std::atomic<long long int> allocations_in_pool_;
+ std::atomic<long long int> buffers_in_pool_;
+#endif
+
+ /* Metal resources. */
+ bool ensure_initialised_ = false;
+ id<MTLDevice> device_ = nil;
+
+ /* The buffer selection aims to pick a buffer which meets the minimum size requirements.
+ * To do this, we keep an ordered set of all available buffers. If the buffer is larger than the
+ * desired allocation size, we check it against `mtl_buffer_size_threshold_factor_`,
+ * which defines what % larger than the original allocation the buffer can be.
+ * - A higher value results in greater re-use of previously allocated buffers of similar sizes.
+ * - A lower value may result in more dynamic allocations, but minimized memory usage for a given
+ * scenario.
+ * The current value of 1.26 is calibrated for optimal performance and memory utilization. */
+ static constexpr float mtl_buffer_size_threshold_factor_ = 1.26;
+
+ /* Buffer pools using MTLResourceOptions as key for allocation type.
+ * Aliased as 'uint64_t' for map type compatibility.
+ * - A size-ordered list (MultiSet) of allocated buffers is kept per MTLResourceOptions
+ * permutation. This allows efficient lookup for buffers of a given requested size.
+ * - MTLBufferHandle wraps a gpu::MTLBuffer pointer to achieve easy size-based sorting
+ * via CompareMTLBuffer. */
+ using MTLBufferPoolOrderedList = std::multiset<MTLBufferHandle, CompareMTLBuffer>;
+ using MTLBufferResourceOptions = uint64_t;
+
+ blender::Map<MTLBufferResourceOptions, MTLBufferPoolOrderedList *> buffer_pools_;
+ blender::Vector<gpu::MTLBuffer *> allocations_;
+
+ /* Maintain a queue of all MTLSafeFreeList's that have been released
+ * by the GPU and are ready to have their buffers re-inserted into the
+ * MemoryManager pools.
+ * Access to this queue is made thread-safe through safelist_lock_. */
+ std::mutex safelist_lock_;
+ blender::Vector<MTLSafeFreeList *> completed_safelist_queue_;
+
+ /* Current free list, associated with active MTLCommandBuffer submission. */
+ /* MTLBuffer::free() can be called from separate threads, due to usage within animation
+ * system/worker threads. */
+ std::atomic<MTLSafeFreeList *> current_free_list_;
+
+ public:
+ void init(id<MTLDevice> device);
+ ~MTLBufferPool();
+
+ gpu::MTLBuffer *allocate(uint64_t size, bool cpu_visible);
+ gpu::MTLBuffer *allocate_aligned(uint64_t size, uint alignment, bool cpu_visible);
+ gpu::MTLBuffer *allocate_with_data(uint64_t size, bool cpu_visible, const void *data = nullptr);
+ gpu::MTLBuffer *allocate_aligned_with_data(uint64_t size,
+ uint alignment,
+ bool cpu_visible,
+ const void *data = nullptr);
+ bool free_buffer(gpu::MTLBuffer *buffer);
+
+ /* Flush MTLSafeFreeList buffers, for completed lists in `completed_safelist_queue_`,
+ * back to memory pools. */
+ void update_memory_pools();
+
+ /* Access and control over active MTLSafeFreeList. */
+ MTLSafeFreeList *get_current_safe_list();
+ void begin_new_safe_list();
+
+ /* Add a completed MTLSafeFreeList to completed_safelist_queue_. */
+ void push_completed_safe_list(MTLSafeFreeList *list);
+
+ private:
+ void ensure_buffer_pool(MTLResourceOptions options);
+ void insert_buffer_into_pool(MTLResourceOptions options, gpu::MTLBuffer *buffer);
+ void free();
+};
+
+/* Scratch buffers are circular-buffers used for temporary data within the current frame.
+ * In order to preserve integrity of contents when having multiple-frames-in-flight,
+ * we cycle through a collection of scratch buffers which are reset upon next use.
+ *
+ * Below are a series of properties, declared to manage scratch buffers. If a scratch buffer
+ * overflows, then the original buffer will be flushed and submitted, with retained references
+ * by usage within the command buffer, and a new buffer will be created.
+ * - The new buffer will grow in size to account for increased demand in temporary memory.
+ */
+class MTLScratchBufferManager {
+
+ private:
+ /* Maximum number of scratch buffers to allocate. This should be the maximum number of
+ * simultaneous frames in flight. */
+ static constexpr uint mtl_max_scratch_buffers_ = MTL_NUM_SAFE_FRAMES;
+
+ public:
+ /* Maximum size of single scratch buffer allocation. When re-sizing, this is the maximum size the
+ * newly allocated buffers will grow to. Larger allocations are possible if
+ * `MTL_SCRATCH_BUFFER_ALLOW_TEMPORARY_EXPANSION` is enabled, but these will instead allocate new
+ * buffers from the memory pools on the fly. */
+ static constexpr uint mtl_scratch_buffer_max_size_ = 128 * 1024 * 1024;
+
+ /* Initial size of circular scratch buffers prior to growth. */
+ static constexpr uint mtl_scratch_buffer_initial_size_ = 16 * 1024 * 1024;
+
+ private:
+ /* Parent MTLContext. */
+ MTLContext &context_;
+ bool initialised_ = false;
+
+ /* Scratch buffer currently in-use. */
+ uint current_scratch_buffer_ = 0;
+
+ /* Scratch buffer pool. */
+ MTLCircularBuffer *scratch_buffers_[mtl_max_scratch_buffers_];
+
+ public:
+ MTLScratchBufferManager(MTLContext &context) : context_(context){};
+ ~MTLScratchBufferManager();
+
+ /* Explicit initialization and freeing of resources.
+ * Initialization must occur after device creation. */
+ void init();
+ void free();
+
+ /* Allocation functions for creating temporary allocations from active circular buffer. */
+ MTLTemporaryBuffer scratch_buffer_allocate_range(uint64_t alloc_size);
+ MTLTemporaryBuffer scratch_buffer_allocate_range_aligned(uint64_t alloc_size, uint alignment);
+
+ /* Ensure a new scratch buffer is started if we move onto a new frame.
+ * Called when a new command buffer begins. */
+ void ensure_increment_scratch_buffer();
+
+ /* Flush memory for active scratch buffer to GPU.
+ * This call will perform a partial flush of the buffer starting from
+ * the last offset the data was flushed from, to the current offset. */
+ void flush_active_scratch_buffer();
+};
+
+/** \} */
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_memory.mm b/source/blender/gpu/metal/mtl_memory.mm
new file mode 100644
index 00000000000..48e27dd2bb6
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_memory.mm
@@ -0,0 +1,895 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_global.h"
+
+#include "DNA_userdef_types.h"
+
+#include "mtl_context.hh"
+#include "mtl_debug.hh"
+#include "mtl_memory.hh"
+
+using namespace blender;
+using namespace blender::gpu;
+
+namespace blender::gpu {
+
+/* -------------------------------------------------------------------- */
+/** \name Memory Management - MTLBufferPool and MTLSafeFreeList implementations. */
+
+void MTLBufferPool::init(id<MTLDevice> mtl_device)
+{
+ if (!ensure_initialised_) {
+ BLI_assert(mtl_device);
+ ensure_initialised_ = true;
+ device_ = mtl_device;
+
+#if MTL_DEBUG_MEMORY_STATISTICS == 1
+ /* Debug statistics. */
+ per_frame_allocation_count_ = 0;
+ allocations_in_pool_ = 0;
+ buffers_in_pool_ = 0;
+#endif
+
+ /* Free pools -- Create initial safe free pool */
+ BLI_assert(current_free_list_ == nullptr);
+ this->begin_new_safe_list();
+ }
+}
+
+MTLBufferPool::~MTLBufferPool()
+{
+ this->free();
+}
+
+void MTLBufferPool::free()
+{
+
+ for (auto buffer : allocations_) {
+ BLI_assert(buffer);
+ delete buffer;
+ }
+ allocations_.clear();
+
+ for (std::multiset<blender::gpu::MTLBufferHandle, blender::gpu::CompareMTLBuffer> *buffer_pool :
+ buffer_pools_.values()) {
+ delete buffer_pool;
+ }
+ buffer_pools_.clear();
+}
+
+gpu::MTLBuffer *MTLBufferPool::allocate(uint64_t size, bool cpu_visible)
+{
+ /* Allocate buffer with default HW-compatible alignment of 256 bytes.
+ * See https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf for more. */
+ return this->allocate_aligned(size, 256, cpu_visible);
+}
+
+gpu::MTLBuffer *MTLBufferPool::allocate_with_data(uint64_t size,
+ bool cpu_visible,
+ const void *data)
+{
+ /* Allocate buffer with default HW-compatible alignemnt of 256 bytes.
+ * See https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf for more. */
+ return this->allocate_aligned_with_data(size, 256, cpu_visible, data);
+}
+
+gpu::MTLBuffer *MTLBufferPool::allocate_aligned(uint64_t size, uint alignment, bool cpu_visible)
+{
+ /* Check not required. Main GPU module usage considered thread-safe. */
+ // BLI_assert(BLI_thread_is_main());
+
+ /* Calculate aligned size */
+ BLI_assert(alignment > 0);
+ uint64_t aligned_alloc_size = ceil_to_multiple_ul(size, alignment);
+
+ /* Allocate new MTL Buffer */
+ MTLResourceOptions options;
+ if (cpu_visible) {
+ options = ([device_ hasUnifiedMemory]) ? MTLResourceStorageModeShared :
+ MTLResourceStorageModeManaged;
+ }
+ else {
+ options = MTLResourceStorageModePrivate;
+ }
+
+ /* Check if we have a suitable buffer */
+ gpu::MTLBuffer *new_buffer = nullptr;
+ std::multiset<MTLBufferHandle, CompareMTLBuffer> **pool_search = buffer_pools_.lookup_ptr(
+ (uint64_t)options);
+
+ if (pool_search != nullptr) {
+ std::multiset<MTLBufferHandle, CompareMTLBuffer> *pool = *pool_search;
+ MTLBufferHandle size_compare(aligned_alloc_size);
+ auto result = pool->lower_bound(size_compare);
+ if (result != pool->end()) {
+ /* Potential buffer found, check if within size threshold requirements. */
+ gpu::MTLBuffer *found_buffer = result->buffer;
+ BLI_assert(found_buffer);
+ BLI_assert(found_buffer->get_metal_buffer());
+
+ uint64_t found_size = found_buffer->get_size();
+
+ if (found_size >= aligned_alloc_size &&
+ found_size <= (aligned_alloc_size * mtl_buffer_size_threshold_factor_)) {
+ MTL_LOG_INFO(
+ "[MemoryAllocator] Suitable Buffer of size %lld found, for requested size: %lld\n",
+ found_size,
+ aligned_alloc_size);
+
+ new_buffer = found_buffer;
+ BLI_assert(!new_buffer->get_in_use());
+
+ /* Remove buffer from free set. */
+ pool->erase(result);
+ }
+ else {
+ MTL_LOG_INFO(
+ "[MemoryAllocator] Buffer of size %lld found, but was incompatible with requested "
+ "size: "
+ "%lld\n",
+ found_size,
+ aligned_alloc_size);
+ new_buffer = nullptr;
+ }
+ }
+ }
+
+ /* Allocate new buffer. */
+ if (new_buffer == nullptr) {
+ new_buffer = new gpu::MTLBuffer(device_, size, options, alignment);
+
+ /* Track allocation in context. */
+ allocations_.append(new_buffer);
+ total_allocation_bytes_ += aligned_alloc_size;
+ }
+ else {
+ /* Re-use suitable buffer. */
+ new_buffer->set_usage_size(aligned_alloc_size);
+
+#if MTL_DEBUG_MEMORY_STATISTICS == 1
+ /* Debug. */
+ allocations_in_pool_ -= new_buffer->get_size();
+ buffers_in_pool_--;
+ BLI_assert(allocations_in_pool_ >= 0);
+#endif
+
+ /* Ensure buffer memory is correctly backed. */
+ BLI_assert(new_buffer->get_metal_buffer());
+ }
+ /* Flag buffer as actively in-use. */
+ new_buffer->flag_in_use(true);
+
+#if MTL_DEBUG_MEMORY_STATISTICS == 1
+ this->per_frame_allocation_count++;
+#endif
+
+ return new_buffer;
+}
+
+gpu::MTLBuffer *MTLBufferPool::allocate_aligned_with_data(uint64_t size,
+ uint alignment,
+ bool cpu_visible,
+ const void *data)
+{
+ gpu::MTLBuffer *buf = this->allocate_aligned(size, 256, cpu_visible);
+
+ /* Upload initial data. */
+ BLI_assert(data != nullptr);
+ BLI_assert(!(buf->get_resource_options() & MTLResourceStorageModePrivate));
+ BLI_assert(size <= buf->get_size());
+ BLI_assert(size <= [buf->get_metal_buffer() length]);
+ memcpy(buf->get_host_ptr(), data, size);
+ buf->flush_range(0, size);
+ return buf;
+}
+
+bool MTLBufferPool::free_buffer(gpu::MTLBuffer *buffer)
+{
+ /* Ensure buffer is flagged as in-use. I.e. has not already been returned to memory pools. */
+ bool buffer_in_use = buffer->get_in_use();
+ BLI_assert(buffer_in_use);
+ if (buffer_in_use) {
+
+ /* Fetch active safe pool from atomic ptr. */
+ MTLSafeFreeList *current_pool = this->get_current_safe_list();
+
+ /* Place buffer in safe_free_pool before returning to MemoryManager buffer pools. */
+ BLI_assert(current_pool);
+ current_pool->insert_buffer(buffer);
+ buffer->flag_in_use(false);
+
+ return true;
+ }
+ return false;
+}
+
+void MTLBufferPool::update_memory_pools()
+{
+ /* Ensure thread-safe access to `completed_safelist_queue_`, which contains
+ * the list of MTLSafeFreeList's whose buffers are ready to be
+ * re-inserted into the Memory Manager pools. */
+ safelist_lock_.lock();
+
+#if MTL_DEBUG_MEMORY_STATISTICS == 1
+ int num_buffers_added = 0;
+#endif
+
+ /* Always free oldest MTLSafeFreeList first. */
+ for (int safe_pool_free_index = 0; safe_pool_free_index < completed_safelist_queue_.size();
+ safe_pool_free_index++) {
+ MTLSafeFreeList *current_pool = completed_safelist_queue_[safe_pool_free_index];
+
+ /* Iterate through all MTLSafeFreeList linked-chunks. */
+ while (current_pool != nullptr) {
+ current_pool->lock_.lock();
+ BLI_assert(current_pool);
+ BLI_assert(current_pool->in_free_queue_);
+ int counter = 0;
+ int size = min_ii(current_pool->current_list_index_, MTLSafeFreeList::MAX_NUM_BUFFERS_);
+
+ /* Re-add all buffers within frame index to MemoryManager pools. */
+ while (counter < size) {
+
+ gpu::MTLBuffer *buf = current_pool->safe_free_pool_[counter];
+
+ /* Insert buffer back into open pools. */
+ BLI_assert(buf->get_in_use() == false);
+ this->insert_buffer_into_pool(buf->get_resource_options(), buf);
+ counter++;
+
+#if MTL_DEBUG_MEMORY_STATISTICS == 1
+ num_buffers_added++;
+#endif
+ }
+
+ /* Fetch next MTLSafeFreeList chunk, if any. */
+ MTLSafeFreeList *next_list = nullptr;
+ if (current_pool->has_next_pool_ > 0) {
+ next_list = current_pool->next_.load();
+ }
+
+ /* Delete current MTLSafeFreeList */
+ current_pool->lock_.unlock();
+ delete current_pool;
+ current_pool = nullptr;
+
+ /* Move onto next chunk. */
+ if (next_list != nullptr) {
+ current_pool = next_list;
+ }
+ }
+ }
+
+#if MTL_DEBUG_MEMORY_STATISTICS == 1
+ printf("--- Allocation Stats ---\n");
+ printf(" Num buffers processed in pool (this frame): %u\n", num_buffers_added);
+
+ uint framealloc = (uint)this->per_frame_allocation_count;
+ printf(" Allocations in frame: %u\n", framealloc);
+ printf(" Total Buffers allocated: %u\n", (uint)allocations_.size());
+ printf(" Total Memory allocated: %u MB\n", (uint)total_allocation_bytes_ / (1024 * 1024));
+
+ uint allocs = (uint)(allocations_in_pool_) / 1024 / 2024;
+ printf(" Free memory in pools: %u MB\n", allocs);
+
+ uint buffs = (uint)buffers_in_pool_;
+ printf(" Buffers in pools: %u\n", buffs);
+
+ printf(" Pools %u:\n", (uint)buffer_pools_.size());
+ auto key_iterator = buffer_pools_.keys().begin();
+ auto value_iterator = buffer_pools_.values().begin();
+ while (key_iterator != buffer_pools_.keys().end()) {
+ uint64_t mem_in_pool = 0;
+ uint64_t iters = 0;
+ for (auto it = (*value_iterator)->begin(); it != (*value_iterator)->end(); it++) {
+ mem_in_pool += it->buffer_size;
+ iters++;
+ }
+
+ printf(" Buffers in pool (%u)(%llu): %u (%u MB)\n",
+ (uint)*key_iterator,
+ iters,
+ (uint)((*value_iterator)->size()),
+ (uint)mem_in_pool / 1024 / 1024);
+ ++key_iterator;
+ ++value_iterator;
+ }
+
+ this->per_frame_allocation_count = 0;
+#endif
+
+ /* Clear safe pools list */
+ completed_safelist_queue_.clear();
+ safelist_lock_.unlock();
+}
+
+void MTLBufferPool::push_completed_safe_list(MTLSafeFreeList *safe_list)
+{
+ /* When an MTLSafeFreeList has been released by the GPU, and buffers are ready to
+ * be re-inserted into the MemoryManager pools for future use, add the MTLSafeFreeList
+ * to the `completed_safelist_queue_` for flushing at a controlled point in time. */
+ safe_list->lock_.lock();
+ BLI_assert(safe_list);
+ BLI_assert(safe_list->reference_count_ == 0 &&
+ "Pool must be fully dereferenced by all in-use cmd buffers before returning.\n");
+ BLI_assert(safe_list->in_free_queue_ == false && "Pool must not already be in queue");
+
+ /* Flag MTLSafeFreeList as having been added, and insert into SafeFreePool queue. */
+ safe_list->flag_in_queue();
+ safelist_lock_.lock();
+ completed_safelist_queue_.append(safe_list);
+ safelist_lock_.unlock();
+ safe_list->lock_.unlock();
+}
+
+MTLSafeFreeList *MTLBufferPool::get_current_safe_list()
+{
+ /* Thread-safe access via atomic ptr. */
+ return current_free_list_;
+}
+
+void MTLBufferPool::begin_new_safe_list()
+{
+ safelist_lock_.lock();
+ current_free_list_ = new MTLSafeFreeList();
+ safelist_lock_.unlock();
+}
+
+void MTLBufferPool::ensure_buffer_pool(MTLResourceOptions options)
+{
+ std::multiset<MTLBufferHandle, CompareMTLBuffer> **pool_search = buffer_pools_.lookup_ptr(
+ (uint64_t)options);
+ if (pool_search == nullptr) {
+ std::multiset<MTLBufferHandle, CompareMTLBuffer> *pool =
+ new std::multiset<MTLBufferHandle, CompareMTLBuffer>();
+ buffer_pools_.add_new((uint64_t)options, pool);
+ }
+}
+
+void MTLBufferPool::insert_buffer_into_pool(MTLResourceOptions options, gpu::MTLBuffer *buffer)
+{
+ /* Ensure `safelist_lock_` is locked in calling code before modifying. */
+ BLI_assert(buffer);
+
+ /* Reset usage size to actual size of allocation. */
+ buffer->set_usage_size(buffer->get_size());
+
+ /* Ensure pool exists. */
+ this->ensure_buffer_pool(options);
+
+ /* TODO(Metal): Support purgeability - Allow buffer in pool to have its memory taken back by the
+ * OS if needed. As we keep allocations around, they may not actually be in use, but we can
+ * ensure they do not block other apps from using memory. Upon a buffer being needed again, we
+ * can reset this state.
+ * TODO(Metal): Purgeability state does not update instantly, so this requires a deferral. */
+ BLI_assert(buffer->get_metal_buffer());
+ /* buffer->metal_buffer); [buffer->metal_buffer setPurgeableState:MTLPurgeableStateVolatile]; */
+
+ std::multiset<MTLBufferHandle, CompareMTLBuffer> *pool = buffer_pools_.lookup(options);
+ pool->insert(MTLBufferHandle(buffer));
+
+#if MTL_DEBUG_MEMORY_STATISTICS == 1
+ /* Debug statistics. */
+ allocations_in_pool_ += buffer->get_size();
+ buffers_in_pool_++;
+#endif
+}
+
+MTLSafeFreeList::MTLSafeFreeList()
+{
+ reference_count_ = 1;
+ in_free_queue_ = false;
+ current_list_index_ = 0;
+ next_ = nullptr;
+ has_next_pool_ = 0;
+}
+
+void MTLSafeFreeList::insert_buffer(gpu::MTLBuffer *buffer)
+{
+ BLI_assert(in_free_queue_ == false);
+
+ /* Lockless list insert. */
+ uint insert_index = current_list_index_++;
+
+ /* If the current MTLSafeFreeList size is exceeded, we ripple down the linked-list chain and
+ * insert the buffer into the next available chunk. */
+ if (insert_index >= MTLSafeFreeList::MAX_NUM_BUFFERS_) {
+
+ /* Check if first caller to generate next pool. */
+ int has_next = has_next_pool_++;
+ if (has_next == 0) {
+ next_ = new MTLSafeFreeList();
+ }
+ MTLSafeFreeList *next_list = next_.load();
+ BLI_assert(next_list);
+ next_list->insert_buffer(buffer);
+
+ /* Clamp index to chunk limit if overflowing. */
+ current_list_index_ = MTLSafeFreeList::MAX_NUM_BUFFERS_;
+ return;
+ }
+
+ safe_free_pool_[insert_index] = buffer;
+}
+
+/* Increments from active GPUContext thread. */
+void MTLSafeFreeList::increment_reference()
+{
+ lock_.lock();
+ BLI_assert(in_free_queue_ == false);
+ reference_count_++;
+ lock_.unlock();
+}
+
+/* Reference decrements and addition to completed list queue can occur from MTLCommandBuffer
+ * completion callback thread. */
+void MTLSafeFreeList::decrement_reference()
+{
+ lock_.lock();
+ BLI_assert(in_free_queue_ == false);
+ int ref_count = --reference_count_;
+
+ if (ref_count == 0) {
+ MTLContext::get_global_memory_manager().push_completed_safe_list(this);
+ }
+ lock_.unlock();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name MTLBuffer wrapper class implementation.
+ * \{ */
+
+/* Construct a gpu::MTLBuffer wrapper around a newly created metal::MTLBuffer. */
+MTLBuffer::MTLBuffer(id<MTLDevice> mtl_device,
+ uint64_t size,
+ MTLResourceOptions options,
+ uint alignment)
+{
+ /* Calculate aligned allocation size. */
+ BLI_assert(alignment > 0);
+ uint64_t aligned_alloc_size = ceil_to_multiple_ul(size, alignment);
+
+ alignment_ = alignment;
+ device_ = mtl_device;
+ is_external_ = false;
+
+ options_ = options;
+ this->flag_in_use(false);
+
+ metal_buffer_ = [device_ newBufferWithLength:aligned_alloc_size options:options];
+ BLI_assert(metal_buffer_);
+ [metal_buffer_ retain];
+
+ size_ = aligned_alloc_size;
+ this->set_usage_size(size_);
+ if (!(options_ & MTLResourceStorageModePrivate)) {
+ data_ = [metal_buffer_ contents];
+ }
+ else {
+ data_ = nullptr;
+ }
+}
+
+MTLBuffer::MTLBuffer(id<MTLBuffer> external_buffer)
+{
+ BLI_assert(external_buffer != nil);
+
+ /* Ensure external_buffer remains referenced while in-use. */
+ metal_buffer_ = external_buffer;
+ [metal_buffer_ retain];
+
+ /* Extract properties. */
+ is_external_ = true;
+ device_ = nil;
+ alignment_ = 1;
+ options_ = [metal_buffer_ resourceOptions];
+ size_ = [metal_buffer_ allocatedSize];
+ this->set_usage_size(size_);
+ data_ = [metal_buffer_ contents];
+ in_use_ = true;
+}
+
+gpu::MTLBuffer::~MTLBuffer()
+{
+ if (metal_buffer_ != nil) {
+ [metal_buffer_ release];
+ metal_buffer_ = nil;
+ }
+}
+
+void gpu::MTLBuffer::free()
+{
+ if (!is_external_) {
+ MTLContext::get_global_memory_manager().free_buffer(this);
+ }
+ else {
+ if (metal_buffer_ != nil) {
+ [metal_buffer_ release];
+ metal_buffer_ = nil;
+ }
+ }
+}
+
+id<MTLBuffer> gpu::MTLBuffer::get_metal_buffer() const
+{
+ return metal_buffer_;
+}
+
+void *gpu::MTLBuffer::get_host_ptr() const
+{
+ BLI_assert(!(options_ & MTLResourceStorageModePrivate));
+ BLI_assert(data_);
+ return data_;
+}
+
+uint64_t gpu::MTLBuffer::get_size() const
+{
+ return size_;
+}
+
+uint64_t gpu::MTLBuffer::get_size_used() const
+{
+ return usage_size_;
+}
+
+bool gpu::MTLBuffer::requires_flush()
+{
+ /* We do not need to flush shared memory, as addressable buffer is shared. */
+ return options_ & MTLResourceStorageModeManaged;
+}
+
+void gpu::MTLBuffer::set_label(NSString *str)
+{
+ metal_buffer_.label = str;
+}
+
+void gpu::MTLBuffer::debug_ensure_used()
+{
+ /* Debug: If buffer is not flagged as in-use, this is a problem. */
+ BLI_assert(in_use_ &&
+ "Buffer should be marked as 'in-use' if being actively used by an instance. Buffer "
+ "has likely already been freed.");
+}
+
+void gpu::MTLBuffer::flush()
+{
+ this->debug_ensure_used();
+ if (this->requires_flush()) {
+ [metal_buffer_ didModifyRange:NSMakeRange(0, size_)];
+ }
+}
+
+void gpu::MTLBuffer::flush_range(uint64_t offset, uint64_t length)
+{
+ this->debug_ensure_used();
+ if (this->requires_flush()) {
+ BLI_assert((offset + length) <= size_);
+ [metal_buffer_ didModifyRange:NSMakeRange(offset, length)];
+ }
+}
+
+void gpu::MTLBuffer::flag_in_use(bool used)
+{
+ in_use_ = used;
+}
+
+bool gpu::MTLBuffer::get_in_use()
+{
+ return in_use_;
+}
+
+void gpu::MTLBuffer::set_usage_size(uint64_t size_used)
+{
+ BLI_assert(size_used > 0 && size_used <= size_);
+ usage_size_ = size_used;
+}
+
+MTLResourceOptions gpu::MTLBuffer::get_resource_options()
+{
+ return options_;
+}
+
+uint64_t gpu::MTLBuffer::get_alignment()
+{
+ return alignment_;
+}
+
+bool MTLBufferRange::requires_flush()
+{
+ /* We do not need to flush shared memory. */
+ return this->options & MTLResourceStorageModeManaged;
+}
+
+void MTLBufferRange::flush()
+{
+ if (this->requires_flush()) {
+ BLI_assert(this->metal_buffer);
+ BLI_assert((this->buffer_offset + this->size) <= [this->metal_buffer length]);
+ BLI_assert(this->buffer_offset >= 0);
+ [this->metal_buffer
+ didModifyRange:NSMakeRange(this->buffer_offset, this->size - this->buffer_offset)];
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name MTLScratchBufferManager and MTLCircularBuffer implementation.
+ * \{ */
+
+MTLScratchBufferManager::~MTLScratchBufferManager()
+{
+ this->free();
+}
+
+void MTLScratchBufferManager::init()
+{
+
+ if (!this->initialised_) {
+ BLI_assert(context_.device);
+
+ /* Initialize Scratch buffers. */
+ for (int sb = 0; sb < mtl_max_scratch_buffers_; sb++) {
+ scratch_buffers_[sb] = new MTLCircularBuffer(
+ context_, mtl_scratch_buffer_initial_size_, true);
+ BLI_assert(scratch_buffers_[sb]);
+ BLI_assert(&(scratch_buffers_[sb]->own_context_) == &context_);
+ }
+ current_scratch_buffer_ = 0;
+ initialised_ = true;
+ }
+}
+
+void MTLScratchBufferManager::free()
+{
+ initialised_ = false;
+
+ /* Release Scratch buffers */
+ for (int sb = 0; sb < mtl_max_scratch_buffers_; sb++) {
+ delete scratch_buffers_[sb];
+ scratch_buffers_[sb] = nullptr;
+ }
+ current_scratch_buffer_ = 0;
+}
+
+MTLTemporaryBuffer MTLScratchBufferManager::scratch_buffer_allocate_range(uint64_t alloc_size)
+{
+ return this->scratch_buffer_allocate_range_aligned(alloc_size, 1);
+}
+
+MTLTemporaryBuffer MTLScratchBufferManager::scratch_buffer_allocate_range_aligned(
+ uint64_t alloc_size, uint alignment)
+{
+ /* Ensure scratch buffer allocation alignment adheres to offset alignment requirements. */
+ alignment = max_uu(alignment, 256);
+
+ BLI_assert(current_scratch_buffer_ >= 0 && "Scratch Buffer index not set");
+ MTLCircularBuffer *current_scratch_buff = this->scratch_buffers_[current_scratch_buffer_];
+ BLI_assert(current_scratch_buff != nullptr && "Scratch Buffer does not exist");
+ MTLTemporaryBuffer allocated_range = current_scratch_buff->allocate_range_aligned(alloc_size,
+ alignment);
+ BLI_assert(allocated_range.size >= alloc_size && allocated_range.size <= alloc_size + alignment);
+ BLI_assert(allocated_range.metal_buffer != nil);
+ return allocated_range;
+}
+
+void MTLScratchBufferManager::ensure_increment_scratch_buffer()
+{
+ /* Fetch active scratch buffer. */
+ MTLCircularBuffer *active_scratch_buf = scratch_buffers_[current_scratch_buffer_];
+ BLI_assert(&active_scratch_buf->own_context_ == &context_);
+
+ /* Ensure existing scratch buffer is no longer in use. MTL_MAX_SCRATCH_BUFFERS specifies
+ * the number of allocated scratch buffers. This value should be equal to the number of
+ * simultaneous frames in-flight. I.e. the maximal number of scratch buffers which are
+ * simultaneously in-use. */
+ if (active_scratch_buf->used_frame_index_ < context_.get_current_frame_index()) {
+ current_scratch_buffer_ = (current_scratch_buffer_ + 1) % mtl_max_scratch_buffers_;
+ active_scratch_buf = scratch_buffers_[current_scratch_buffer_];
+ active_scratch_buf->reset();
+ BLI_assert(&active_scratch_buf->own_context_ == &context_);
+ MTL_LOG_INFO("Scratch buffer %d reset - (ctx %p)(Frame index: %d)\n",
+ current_scratch_buffer_,
+ &context_,
+ context_.get_current_frame_index());
+ }
+}
+
+void MTLScratchBufferManager::flush_active_scratch_buffer()
+{
+ /* Fetch active scratch buffer and verify context. */
+ MTLCircularBuffer *active_scratch_buf = scratch_buffers_[current_scratch_buffer_];
+ BLI_assert(&active_scratch_buf->own_context_ == &context_);
+ active_scratch_buf->flush();
+}
+
+/* MTLCircularBuffer implementation. */
+MTLCircularBuffer::MTLCircularBuffer(MTLContext &ctx, uint64_t initial_size, bool allow_grow)
+ : own_context_(ctx)
+{
+ BLI_assert(this);
+ MTLResourceOptions options = ([own_context_.device hasUnifiedMemory]) ?
+ MTLResourceStorageModeShared :
+ MTLResourceStorageModeManaged;
+ cbuffer_ = new gpu::MTLBuffer(own_context_.device, initial_size, options, 256);
+ current_offset_ = 0;
+ can_resize_ = allow_grow;
+ cbuffer_->flag_in_use(true);
+
+ used_frame_index_ = ctx.get_current_frame_index();
+ last_flush_base_offset_ = 0;
+
+ /* Debug label. */
+ if (G.debug & G_DEBUG_GPU) {
+ cbuffer_->set_label(@"Circular Scratch Buffer");
+ }
+}
+
+MTLCircularBuffer::~MTLCircularBuffer()
+{
+ delete cbuffer_;
+}
+
+MTLTemporaryBuffer MTLCircularBuffer::allocate_range(uint64_t alloc_size)
+{
+ return this->allocate_range_aligned(alloc_size, 1);
+}
+
+MTLTemporaryBuffer MTLCircularBuffer::allocate_range_aligned(uint64_t alloc_size, uint alignment)
+{
+ BLI_assert(this);
+
+ /* Ensure alignment of an allocation is aligned to compatible offset boundaries. */
+ BLI_assert(alignment > 0);
+ alignment = max_ulul(alignment, 256);
+
+ /* Align current offset and allocation size to desired alignment */
+ uint64_t aligned_current_offset = ceil_to_multiple_ul(current_offset_, alignment);
+ uint64_t aligned_alloc_size = ceil_to_multiple_ul(alloc_size, alignment);
+ bool can_allocate = (aligned_current_offset + aligned_alloc_size) < cbuffer_->get_size();
+
+ BLI_assert(aligned_current_offset >= current_offset_);
+ BLI_assert(aligned_alloc_size >= alloc_size);
+
+ BLI_assert(aligned_current_offset % alignment == 0);
+ BLI_assert(aligned_alloc_size % alignment == 0);
+
+ /* Recreate Buffer */
+ if (!can_allocate) {
+ uint64_t new_size = cbuffer_->get_size();
+ if (can_resize_) {
+ /* Resize to the maximum of basic resize heuristic OR the size of the current offset +
+ * requested allocation -- we want the buffer to grow to a large enough size such that it
+ * does not need to resize mid-frame. */
+ new_size = max_ulul(
+ min_ulul(MTLScratchBufferManager::mtl_scratch_buffer_max_size_, new_size * 1.2),
+ aligned_current_offset + aligned_alloc_size);
+
+#if MTL_SCRATCH_BUFFER_ALLOW_TEMPORARY_EXPANSION == 1
+ /* IF a requested allocation EXCEEDS the maximum supported size, temporarily allocate up to
+ * this, but shrink down ASAP. */
+ if (new_size > MTLScratchBufferManager::mtl_scratch_buffer_max_size_) {
+
+ /* If new requested allocation is bigger than maximum allowed size, temporarily resize to
+ * maximum allocation size -- Otherwise, clamp the buffer size back down to the defined
+ * maximum */
+ if (aligned_alloc_size > MTLScratchBufferManager::mtl_scratch_buffer_max_size_) {
+ new_size = aligned_alloc_size;
+ MTL_LOG_INFO("Temporarily growing Scratch buffer to %d MB\n",
+ (int)new_size / 1024 / 1024);
+ }
+ else {
+ new_size = MTLScratchBufferManager::mtl_scratch_buffer_max_size_;
+ MTL_LOG_INFO("Shrinking Scratch buffer back to %d MB\n", (int)new_size / 1024 / 1024);
+ }
+ }
+ BLI_assert(aligned_alloc_size <= new_size);
+#else
+ new_size = min_ulul(MTLScratchBufferManager::mtl_scratch_buffer_max_size_, new_size);
+
+ if (aligned_alloc_size > new_size) {
+ BLI_assert(false);
+
+ /* Cannot allocate */
+ MTLTemporaryBuffer alloc_range;
+ alloc_range.metal_buffer = nil;
+ alloc_range.data = nullptr;
+ alloc_range.buffer_offset = 0;
+ alloc_range.size = 0;
+ alloc_range.options = cbuffer_->options;
+ }
+#endif
+ }
+ else {
+ MTL_LOG_WARNING(
+ "Performance Warning: Reached the end of circular buffer of size: %llu, but cannot "
+ "resize. Starting new buffer\n",
+ cbuffer_->get_size());
+ BLI_assert(aligned_alloc_size <= new_size);
+
+ /* Cannot allocate. */
+ MTLTemporaryBuffer alloc_range;
+ alloc_range.metal_buffer = nil;
+ alloc_range.data = nullptr;
+ alloc_range.buffer_offset = 0;
+ alloc_range.size = 0;
+ alloc_range.options = cbuffer_->get_resource_options();
+ }
+
+ /* Flush current buffer to ensure changes are visible on the GPU. */
+ this->flush();
+
+ /* Discard old buffer and create a new one - Relying on Metal reference counting to track
+ * in-use buffers */
+ MTLResourceOptions prev_options = cbuffer_->get_resource_options();
+ uint prev_alignment = cbuffer_->get_alignment();
+ delete cbuffer_;
+ cbuffer_ = new gpu::MTLBuffer(own_context_.device, new_size, prev_options, prev_alignment);
+ cbuffer_->flag_in_use(true);
+ current_offset_ = 0;
+ last_flush_base_offset_ = 0;
+
+ /* Debug label. */
+ if (G.debug & G_DEBUG_GPU) {
+ cbuffer_->set_label(@"Circular Scratch Buffer");
+ }
+ MTL_LOG_INFO("Resized Metal circular buffer to %llu bytes\n", new_size);
+
+ /* Reset allocation Status. */
+ aligned_current_offset = 0;
+ BLI_assert((aligned_current_offset + aligned_alloc_size) <= cbuffer_->get_size());
+ }
+
+ /* Allocate chunk. */
+ MTLTemporaryBuffer alloc_range;
+ alloc_range.metal_buffer = cbuffer_->get_metal_buffer();
+ alloc_range.data = (void *)((uint8_t *)([alloc_range.metal_buffer contents]) +
+ aligned_current_offset);
+ alloc_range.buffer_offset = aligned_current_offset;
+ alloc_range.size = aligned_alloc_size;
+ alloc_range.options = cbuffer_->get_resource_options();
+ BLI_assert(alloc_range.data);
+
+ /* Shift offset to match alignment. */
+ current_offset_ = aligned_current_offset + aligned_alloc_size;
+ BLI_assert(current_offset_ <= cbuffer_->get_size());
+ return alloc_range;
+}
+
+void MTLCircularBuffer::flush()
+{
+ BLI_assert(this);
+
+ uint64_t len = current_offset_ - last_flush_base_offset_;
+ if (len > 0) {
+ cbuffer_->flush_range(last_flush_base_offset_, len);
+ last_flush_base_offset_ = current_offset_;
+ }
+}
+
+void MTLCircularBuffer::reset()
+{
+ BLI_assert(this);
+
+ /* If circular buffer has data written to it, offset will be greater than zero. */
+ if (current_offset_ > 0) {
+
+ /* Ensure the circular buffer is no longer being used by an in-flight frame. */
+ BLI_assert((own_context_.get_current_frame_index() >=
+ (used_frame_index_ + MTL_NUM_SAFE_FRAMES - 1)) &&
+ "Trying to reset Circular scratch buffer's while its data is still being used by "
+ "an in-flight frame");
+
+ current_offset_ = 0;
+ last_flush_base_offset_ = 0;
+ }
+
+ /* Update used frame index to current. */
+ used_frame_index_ = own_context_.get_current_frame_index();
+}
+
+/** \} */
+
+} // blender::gpu
diff --git a/source/blender/gpu/metal/mtl_query.hh b/source/blender/gpu/metal/mtl_query.hh
new file mode 100644
index 00000000000..c1ec9a2a0f5
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_query.hh
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "BLI_vector.hh"
+
+#include "gpu_query.hh"
+#include "mtl_context.hh"
+
+namespace blender::gpu {
+
+class MTLQueryPool : public QueryPool {
+ private:
+ /** Number of queries that have been issued since last initialization.
+ * Should be equal to query_ids_.size(). */
+ uint32_t query_issued_;
+ /** Type of this query pool. */
+ GPUQueryType type_;
+ /** Can only be initialized once. */
+ bool initialized_ = false;
+ MTLVisibilityResultMode mtl_type_;
+ Vector<gpu::MTLBuffer *> buffer_;
+
+ void allocate_buffer();
+
+ public:
+ MTLQueryPool();
+ ~MTLQueryPool();
+
+ void init(GPUQueryType type) override;
+
+ void begin_query() override;
+ void end_query() override;
+
+ void get_occlusion_result(MutableSpan<uint32_t> r_values) override;
+};
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_query.mm b/source/blender/gpu/metal/mtl_query.mm
new file mode 100644
index 00000000000..33ae8f554c3
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_query.mm
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "mtl_query.hh"
+
+namespace blender::gpu {
+
+static const size_t VISIBILITY_COUNT_PER_BUFFER = 512;
+/* defined in the documentation but not queryable programmatically:
+ * https://developer.apple.com/documentation/metal/mtlvisibilityresultmode/mtlvisibilityresultmodeboolean?language=objc
+ */
+static const size_t VISIBILITY_RESULT_SIZE_IN_BYTES = 8;
+
+MTLQueryPool::MTLQueryPool()
+{
+ allocate_buffer();
+}
+MTLQueryPool::~MTLQueryPool()
+{
+ for (gpu::MTLBuffer *buf : buffer_) {
+ BLI_assert(buf);
+ buf->free();
+ }
+}
+
+void MTLQueryPool::allocate_buffer()
+{
+ /* Allocate Metal buffer for visibility results. */
+ size_t buffer_size_in_bytes = VISIBILITY_COUNT_PER_BUFFER * VISIBILITY_RESULT_SIZE_IN_BYTES;
+ gpu::MTLBuffer *buffer = MTLContext::get_global_memory_manager().allocate_buffer(
+ buffer_size_in_bytes, true);
+ BLI_assert(buffer);
+ buffer_.append(buffer);
+}
+
+static inline MTLVisibilityResultMode to_mtl_type(GPUQueryType type)
+{
+ if (type == GPU_QUERY_OCCLUSION) {
+ return MTLVisibilityResultModeBoolean;
+ }
+ BLI_assert(0);
+ return MTLVisibilityResultModeBoolean;
+}
+
+void MTLQueryPool::init(GPUQueryType type)
+{
+ BLI_assert(initialized_ == false);
+ initialized_ = true;
+ type_ = type;
+ mtl_type_ = to_mtl_type(type);
+ query_issued_ = 0;
+}
+
+void MTLQueryPool::begin_query()
+{
+ MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+
+ /* Ensure our allocated buffer pool has enough space for the current queries. */
+ int query_id = query_issued_;
+ int requested_buffer = query_id / VISIBILITY_COUNT_PER_BUFFER;
+ if (requested_buffer >= buffer_.size()) {
+ allocate_buffer();
+ }
+
+ BLI_assert(requested_buffer < buffer_.size());
+ gpu::MTLBuffer *buffer = buffer_[requested_buffer];
+
+ /* Ensure visibility buffer is set on the context. If visibility buffer changes,
+ * we need to begin a new render pass with an updated reference in the
+ * MTLRenderPassDescriptor. */
+ ctx->set_visibility_buffer(buffer);
+
+ ctx->ensure_begin_render_pass();
+ id<MTLRenderCommandEncoder> rec = ctx->main_command_buffer.get_active_render_command_encoder();
+ [rec setVisibilityResultMode:mtl_type_
+ offset:(query_id % VISIBILITY_COUNT_PER_BUFFER) *
+ VISIBILITY_RESULT_SIZE_IN_BYTES];
+ query_issued_ += 1;
+}
+
+void MTLQueryPool::end_query()
+{
+ MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+
+ id<MTLRenderCommandEncoder> rec = ctx->main_command_buffer.get_active_render_command_encoder();
+ [rec setVisibilityResultMode:MTLVisibilityResultModeDisabled offset:0];
+}
+
+void MTLQueryPool::get_occlusion_result(MutableSpan<uint32_t> r_values)
+{
+ MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
+
+ /* Create a blit encoder to synchronize the query buffer results between
+ * GPU and CPU when not using shared-memory. */
+ if ([ctx->device hasUnifiedMemory] == false) {
+ id<MTLBlitCommandEncoder> blit_encoder = ctx->main_command_buffer.ensure_begin_blit_encoder();
+ BLI_assert(blit_encoder);
+ for (gpu::MTLBuffer *buf : buffer_) {
+ [blit_encoder synchronizeResource:buf->get_metal_buffer()];
+ }
+ BLI_assert(ctx->get_inside_frame());
+ }
+
+ /* Wait for GPU operatiosn to complete and for query buffer contents
+ * to be synchronised back to host memory. */
+ GPU_finish();
+
+ /* Iterate through all possible visibility buffers and copy results into provided
+ * container. */
+ for (const int i : IndexRange(query_issued_)) {
+ int requested_buffer = i / VISIBILITY_COUNT_PER_BUFFER;
+ const uint64_t *queries = static_cast<const uint64_t *>(
+ buffer_[requested_buffer]->get_host_ptr());
+ r_values[i] = static_cast<uint32_t>(queries[i % VISIBILITY_COUNT_PER_BUFFER]);
+ }
+ ctx->set_visibility_buffer(nullptr);
+}
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_state.hh b/source/blender/gpu/metal/mtl_state.hh
index f2d85f9648b..e6472491b35 100644
--- a/source/blender/gpu/metal/mtl_state.hh
+++ b/source/blender/gpu/metal/mtl_state.hh
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
/** \file
* \ingroup gpu
*/
@@ -30,18 +32,18 @@ class MTLStateManager : public StateManager {
public:
MTLStateManager(MTLContext *ctx);
- void apply_state(void) override;
- void force_state(void) override;
+ void apply_state() override;
+ void force_state() override;
void issue_barrier(eGPUBarrier barrier_bits) override;
void texture_bind(Texture *tex, eGPUSamplerState sampler, int unit) override;
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;
@@ -62,10 +64,10 @@ class MTLStateManager : public StateManager {
void set_mutable_state(const GPUStateMutable &state);
/* METAL State utility functions. */
- void mtl_state_init(void);
+ void mtl_state_init();
void mtl_depth_range(float near, float far);
- void mtl_stencil_mask(unsigned int mask);
- void mtl_stencil_set_func(eGPUStencilTest stencil_func, int ref, unsigned int mask);
+ void mtl_stencil_mask(uint mask);
+ void mtl_stencil_set_func(eGPUStencilTest stencil_func, int ref, uint mask);
MEM_CXX_CLASS_ALLOC_FUNCS("MTLStateManager")
};
diff --git a/source/blender/gpu/metal/mtl_state.mm b/source/blender/gpu/metal/mtl_state.mm
index 5f52bc55f72..0f2d4d7dc48 100644
--- a/source/blender/gpu/metal/mtl_state.mm
+++ b/source/blender/gpu/metal/mtl_state.mm
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
/** \file
* \ingroup gpu
*/
@@ -8,6 +10,7 @@
#include "GPU_framebuffer.h"
#include "mtl_context.hh"
+#include "mtl_framebuffer.hh"
#include "mtl_state.hh"
namespace blender::gpu {
@@ -16,16 +19,16 @@ namespace blender::gpu {
/** \name MTLStateManager
* \{ */
-void MTLStateManager::mtl_state_init(void)
+void MTLStateManager::mtl_state_init()
{
- BLI_assert(this->context_);
- this->context_->pipeline_state_init();
+ BLI_assert(context_);
+ context_->pipeline_state_init();
}
MTLStateManager::MTLStateManager(MTLContext *ctx) : StateManager()
{
/* Initialize State. */
- this->context_ = ctx;
+ context_ = ctx;
mtl_state_init();
/* Force update using default state. */
@@ -35,15 +38,16 @@ MTLStateManager::MTLStateManager(MTLContext *ctx) : StateManager()
set_mutable_state(mutable_state);
}
-void MTLStateManager::apply_state(void)
+void MTLStateManager::apply_state()
{
this->set_state(this->state);
this->set_mutable_state(this->mutable_state);
- /* TODO(Metal): Enable after integration of MTLFrameBuffer. */
- /* static_cast<MTLFrameBuffer *>(this->context_->active_fb)->apply_state(); */
+
+ /* Apply active FrameBuffer state. */
+ static_cast<MTLFrameBuffer *>(context_->active_fb)->apply_state();
};
-void MTLStateManager::force_state(void)
+void MTLStateManager::force_state()
{
/* Little exception for clip distances since they need to keep the old count correct. */
uint32_t clip_distances = current_.clip_distances;
@@ -103,10 +107,10 @@ void MTLStateManager::set_state(const GPUState &state)
void MTLStateManager::mtl_depth_range(float near, float far)
{
- BLI_assert(this->context_);
+ BLI_assert(context_);
BLI_assert(near >= 0.0 && near < 1.0);
BLI_assert(far > 0.0 && far <= 1.0);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
ds_state.depth_range_near = near;
@@ -117,7 +121,7 @@ void MTLStateManager::mtl_depth_range(float near, float far)
void MTLStateManager::set_mutable_state(const GPUStateMutable &state)
{
GPUStateMutable changed = state ^ current_mutable_;
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
if (float_as_uint(changed.point_size) != 0) {
pipeline_state.point_size = state.point_size;
@@ -150,8 +154,8 @@ void MTLStateManager::set_mutable_state(const GPUStateMutable &state)
void MTLStateManager::set_write_mask(const eGPUWriteMask value)
{
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
pipeline_state.depth_stencil_state.depth_write_enable = ((value & GPU_WRITE_DEPTH) != 0);
pipeline_state.color_write_mask =
(((value & GPU_WRITE_RED) != 0) ? MTLColorWriteMaskRed : MTLColorWriteMaskNone) |
@@ -205,8 +209,8 @@ static MTLCompareFunction gpu_stencil_func_to_metal(eGPUStencilTest stencil_func
void MTLStateManager::set_depth_test(const eGPUDepthTest value)
{
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
ds_state.depth_test_enabled = (value != GPU_DEPTH_NONE);
@@ -214,20 +218,18 @@ void MTLStateManager::set_depth_test(const eGPUDepthTest value)
pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
}
-void MTLStateManager::mtl_stencil_mask(unsigned int mask)
+void MTLStateManager::mtl_stencil_mask(uint mask)
{
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
pipeline_state.depth_stencil_state.stencil_write_mask = mask;
pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
}
-void MTLStateManager::mtl_stencil_set_func(eGPUStencilTest stencil_func,
- int ref,
- unsigned int mask)
+void MTLStateManager::mtl_stencil_set_func(eGPUStencilTest stencil_func, int ref, uint mask)
{
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
ds_state.stencil_func = gpu_stencil_func_to_metal(stencil_func);
@@ -275,19 +277,17 @@ void MTLStateManager::set_stencil_test(const eGPUStencilTest test, const eGPUSte
{
switch (operation) {
case GPU_STENCIL_OP_REPLACE:
- mtl_stencil_set_op(this->context_,
- MTLStencilOperationKeep,
- MTLStencilOperationKeep,
- MTLStencilOperationReplace);
+ mtl_stencil_set_op(
+ context_, MTLStencilOperationKeep, MTLStencilOperationKeep, MTLStencilOperationReplace);
break;
case GPU_STENCIL_OP_COUNT_DEPTH_PASS:
/* Winding inversed due to flipped Y coordinate system in Metal. */
- mtl_stencil_set_op_separate(this->context_,
+ mtl_stencil_set_op_separate(context_,
GPU_CULL_FRONT,
MTLStencilOperationKeep,
MTLStencilOperationKeep,
MTLStencilOperationIncrementWrap);
- mtl_stencil_set_op_separate(this->context_,
+ mtl_stencil_set_op_separate(context_,
GPU_CULL_BACK,
MTLStencilOperationKeep,
MTLStencilOperationKeep,
@@ -295,12 +295,12 @@ void MTLStateManager::set_stencil_test(const eGPUStencilTest test, const eGPUSte
break;
case GPU_STENCIL_OP_COUNT_DEPTH_FAIL:
/* Winding inversed due to flipped Y coordinate system in Metal. */
- mtl_stencil_set_op_separate(this->context_,
+ mtl_stencil_set_op_separate(context_,
GPU_CULL_FRONT,
MTLStencilOperationKeep,
MTLStencilOperationDecrementWrap,
MTLStencilOperationKeep);
- mtl_stencil_set_op_separate(this->context_,
+ mtl_stencil_set_op_separate(context_,
GPU_CULL_BACK,
MTLStencilOperationKeep,
MTLStencilOperationIncrementWrap,
@@ -308,14 +308,12 @@ void MTLStateManager::set_stencil_test(const eGPUStencilTest test, const eGPUSte
break;
case GPU_STENCIL_OP_NONE:
default:
- mtl_stencil_set_op(this->context_,
- MTLStencilOperationKeep,
- MTLStencilOperationKeep,
- MTLStencilOperationKeep);
+ mtl_stencil_set_op(
+ context_, MTLStencilOperationKeep, MTLStencilOperationKeep, MTLStencilOperationKeep);
}
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
pipeline_state.depth_stencil_state.stencil_test_enabled = (test != GPU_STENCIL_NONE);
pipeline_state.dirty_flags |= MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG;
}
@@ -347,8 +345,8 @@ void MTLStateManager::set_logic_op(const bool enable)
void MTLStateManager::set_facing(const bool invert)
{
/* Check Current Context. */
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
/* Apply State -- opposite of GL, as METAL default is GPU_CLOCKWISE, GL default is
* COUNTERCLOCKWISE. This needs to be the inverse of the default. */
@@ -362,8 +360,8 @@ void MTLStateManager::set_facing(const bool invert)
void MTLStateManager::set_backface_culling(const eGPUFaceCullTest test)
{
/* Check Current Context. */
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
/* Apply State. */
pipeline_state.culling_enabled = (test != GPU_CULL_NONE);
@@ -386,8 +384,8 @@ void MTLStateManager::set_provoking_vert(const eGPUProvokingVertex vert)
void MTLStateManager::set_shadow_bias(const bool enable)
{
/* Check Current Context. */
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
MTLContextDepthStencilState &ds_state = pipeline_state.depth_stencil_state;
/* Apply State. */
@@ -500,8 +498,8 @@ void MTLStateManager::set_blend(const eGPUBlend value)
}
/* Check Current Context. */
- BLI_assert(this->context_);
- MTLContextGlobalShaderPipelineState &pipeline_state = this->context_->pipeline_state;
+ BLI_assert(context_);
+ MTLContextGlobalShaderPipelineState &pipeline_state = context_->pipeline_state;
if (value == GPU_BLEND_SUBTRACT) {
pipeline_state.rgb_blend_op = MTLBlendOperationReverseSubtract;
@@ -532,9 +530,11 @@ void MTLStateManager::set_blend(const eGPUBlend value)
/* NOTE(Metal): Granular option for specifying before/after stages for a barrier
* Would be a useful feature. */
-/*void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits,
+#if 0
+void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits,
eGPUStageBarrierBits before_stages,
- eGPUStageBarrierBits after_stages) */
+ eGPUStageBarrierBits after_stages)
+#endif
void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits)
{
/* NOTE(Metal): The Metal API implicitly tracks dependencies between resources.
@@ -547,58 +547,18 @@ void MTLStateManager::issue_barrier(eGPUBarrier barrier_bits)
MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
BLI_assert(ctx);
- if (ctx->is_render_pass_active()) {
-
- /* Apple Silicon does not support memory barriers.
- * We do not currently need these due to implicit API guarantees.
- * NOTE(Metal): MTLFence/MTLEvent may be required to synchronize work if
- * untracked resources are ever used. */
- if ([ctx->device hasUnifiedMemory]) {
- return;
- }
- /* Issue barrier. */
- /* TODO(Metal): To be completed pending implementation of RenderCommandEncoder management. */
- id<MTLRenderCommandEncoder> rec = nil; // ctx->get_active_render_command_encoder();
- BLI_assert(rec);
-
- /* Only supporting Metal on 10.15 onward anyway - Check required for warnings. */
- if (@available(macOS 10.14, *)) {
- MTLBarrierScope scope = 0;
- if (barrier_bits & GPU_BARRIER_SHADER_IMAGE_ACCESS ||
- barrier_bits & GPU_BARRIER_TEXTURE_FETCH) {
- scope = scope | MTLBarrierScopeTextures | MTLBarrierScopeRenderTargets;
- }
- if (barrier_bits & GPU_BARRIER_SHADER_STORAGE ||
- barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY ||
- barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) {
- scope = scope | MTLBarrierScopeBuffers;
- }
-
- MTLRenderStages before_stage_flags = 0;
- MTLRenderStages after_stage_flags = 0;
- if (before_stages & GPU_BARRIER_STAGE_VERTEX &&
- !(before_stages & GPU_BARRIER_STAGE_FRAGMENT)) {
- before_stage_flags = before_stage_flags | MTLRenderStageVertex;
- }
- if (before_stages & GPU_BARRIER_STAGE_FRAGMENT) {
- before_stage_flags = before_stage_flags | MTLRenderStageFragment;
- }
- if (after_stages & GPU_BARRIER_STAGE_VERTEX) {
- after_stage_flags = after_stage_flags | MTLRenderStageVertex;
- }
- if (after_stages & GPU_BARRIER_STAGE_FRAGMENT) {
- after_stage_flags = MTLRenderStageFragment;
- }
-
- if (scope != 0) {
- [rec memoryBarrierWithScope:scope
- afterStages:after_stage_flags
- beforeStages:before_stage_flags];
- }
- }
+ /* Apple Silicon does not support memory barriers.
+ * We do not currently need these due to implicit API guarantees.
+ * NOTE(Metal): MTLFence/MTLEvent may be required to synchronize work if
+ * untracked resources are ever used. */
+ if ([ctx->device hasUnifiedMemory]) {
+ return;
}
+
+ ctx->main_command_buffer.insert_memory_barrier(barrier_bits, before_stages, after_stages);
}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -642,7 +602,7 @@ void MTLStateManager::texture_unbind(Texture *tex_)
ctx->texture_unbind(mtl_tex);
}
-void MTLStateManager::texture_unbind_all(void)
+void MTLStateManager::texture_unbind_all()
{
MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
BLI_assert(ctx);
@@ -665,7 +625,7 @@ void MTLStateManager::image_unbind(Texture *tex_)
this->texture_unbind(tex_);
}
-void MTLStateManager::image_unbind_all(void)
+void MTLStateManager::image_unbind_all()
{
this->texture_unbind_all();
}
diff --git a/source/blender/gpu/metal/mtl_texture.hh b/source/blender/gpu/metal/mtl_texture.hh
index b820256ec36..82a7a20a310 100644
--- a/source/blender/gpu/metal/mtl_texture.hh
+++ b/source/blender/gpu/metal/mtl_texture.hh
@@ -40,7 +40,7 @@ struct TextureUpdateRoutineSpecialisation {
/* Number of channels the destination texture has (min=1, max=4). */
int component_count_output;
- inline bool operator==(const TextureUpdateRoutineSpecialisation &other) const
+ bool operator==(const TextureUpdateRoutineSpecialisation &other) const
{
return ((input_data_type == other.input_data_type) &&
(output_data_type == other.output_data_type) &&
@@ -48,7 +48,7 @@ struct TextureUpdateRoutineSpecialisation {
(component_count_output == other.component_count_output));
}
- inline uint64_t hash() const
+ uint64_t hash() const
{
blender::DefaultHash<std::string> string_hasher;
return (uint64_t)string_hasher(
@@ -71,12 +71,12 @@ typedef enum {
struct DepthTextureUpdateRoutineSpecialisation {
DepthTextureUpdateMode data_mode;
- inline bool operator==(const DepthTextureUpdateRoutineSpecialisation &other) const
+ bool operator==(const DepthTextureUpdateRoutineSpecialisation &other) const
{
return ((data_mode == other.data_mode));
}
- inline uint64_t hash() const
+ uint64_t hash() const
{
return (uint64_t)(this->data_mode);
}
@@ -93,10 +93,10 @@ struct TextureReadRoutineSpecialisation {
* 0 = Not a Depth format,
* 1 = FLOAT DEPTH,
* 2 = 24Bit Integer Depth,
- * 4 = 32bit unsigned Integer Depth. */
+ * 4 = 32bit Unsigned-Integer Depth. */
int depth_format_mode;
- inline bool operator==(const TextureReadRoutineSpecialisation &other) const
+ bool operator==(const TextureReadRoutineSpecialisation &other) const
{
return ((input_data_type == other.input_data_type) &&
(output_data_type == other.output_data_type) &&
@@ -105,7 +105,7 @@ struct TextureReadRoutineSpecialisation {
(depth_format_mode == other.depth_format_mode));
}
- inline uint64_t hash() const
+ uint64_t hash() const
{
blender::DefaultHash<std::string> string_hasher;
return (uint64_t)string_hasher(this->input_data_type + this->output_data_type +
@@ -125,28 +125,27 @@ static const int MTL_MAX_MIPMAP_COUNT = 15; /* Max: 16384x16384 */
static const int MTL_MAX_FBO_ATTACHED = 16;
/* Samplers */
-typedef struct MTLSamplerState {
+struct MTLSamplerState {
eGPUSamplerState state;
/* Mip min and mip max on sampler state always the same.
* Level range now controlled with textureView to be consistent with GL baseLevel. */
- inline bool operator==(const MTLSamplerState &other) const
+ bool operator==(const MTLSamplerState &other) const
{
/* Add other parameters as needed. */
return (this->state == other.state);
}
- operator unsigned int() const
+ operator uint() const
{
- return (unsigned int)state;
+ return (uint)state;
}
operator uint64_t() const
{
return (uint64_t)state;
}
-
-} MTLSamplerState;
+};
const MTLSamplerState DEFAULT_SAMPLER_STATE = {GPU_SAMPLER_DEFAULT /*, 0, 9999*/};
@@ -174,12 +173,12 @@ class MTLTexture : public Texture {
/* Texture Storage. */
id<MTLBuffer> texture_buffer_;
- unsigned int aligned_w_ = 0;
+ uint aligned_w_ = 0;
/* Blit Frame-buffer. */
GPUFrameBuffer *blit_fb_ = nullptr;
- unsigned int blit_fb_slice_ = 0;
- unsigned int blit_fb_mip_ = 0;
+ uint blit_fb_slice_ = 0;
+ uint blit_fb_mip_ = 0;
/* Texture view properties */
/* In Metal, we use texture views to either limit mipmap ranges,
@@ -238,7 +237,7 @@ class MTLTexture : public Texture {
void update_sub(
int mip, int offset[3], int extent[3], eGPUDataFormat type, const void *data) override;
- void generate_mipmap(void) override;
+ 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;
@@ -249,16 +248,16 @@ class MTLTexture : public Texture {
void *read(int mip, eGPUDataFormat type) override;
/* Remove once no longer required -- will just return 0 for now in MTL path*/
- uint gl_bindcode_get(void) const override;
+ uint gl_bindcode_get() const override;
bool texture_is_baked();
- inline const char *get_name()
+ const char *get_name()
{
return name_;
}
protected:
- bool init_internal(void) override;
+ bool init_internal() override;
bool init_internal(GPUVertBuf *vbo) override;
bool init_internal(const GPUTexture *src,
int mip_offset,
@@ -280,7 +279,7 @@ class MTLTexture : public Texture {
void ensure_mipmaps(int miplvl);
/* Flags a given mip level as being used. */
- void add_subresource(unsigned int level);
+ void add_subresource(uint level);
void read_internal(int mip,
int x_off,
@@ -299,31 +298,31 @@ class MTLTexture : public Texture {
id<MTLTexture> get_metal_handle_base();
MTLSamplerState get_sampler_state();
void blit(id<MTLBlitCommandEncoder> blit_encoder,
- unsigned int src_x_offset,
- unsigned int src_y_offset,
- unsigned int src_z_offset,
- unsigned int src_slice,
- unsigned int src_mip,
+ uint src_x_offset,
+ uint src_y_offset,
+ uint src_z_offset,
+ uint src_slice,
+ uint src_mip,
gpu::MTLTexture *dest,
- unsigned int dst_x_offset,
- unsigned int dst_y_offset,
- unsigned int dst_z_offset,
- unsigned int dst_slice,
- unsigned int dst_mip,
- unsigned int width,
- unsigned int height,
- unsigned int depth);
+ uint dst_x_offset,
+ uint dst_y_offset,
+ uint dst_z_offset,
+ uint dst_slice,
+ uint dst_mip,
+ uint width,
+ uint height,
+ uint depth);
void blit(gpu::MTLTexture *dest,
- unsigned int src_x_offset,
- unsigned int src_y_offset,
- unsigned int dst_x_offset,
- unsigned int dst_y_offset,
- unsigned int src_mip,
- unsigned int dst_mip,
- unsigned int dst_slice,
+ uint src_x_offset,
+ uint src_y_offset,
+ uint dst_x_offset,
+ uint dst_y_offset,
+ uint src_mip,
+ uint dst_mip,
+ uint dst_slice,
int width,
int height);
- GPUFrameBuffer *get_blit_framebuffer(unsigned int dst_slice, unsigned int dst_mip);
+ GPUFrameBuffer *get_blit_framebuffer(uint dst_slice, uint dst_mip);
MEM_CXX_CLASS_ALLOC_FUNCS("gpu::MTLTexture")
@@ -349,7 +348,7 @@ class MTLTexture : public Texture {
* - Per-component size matches (e.g. GPU_DATA_UBYTE)
* OR GPU_DATA_10_11_11_REV && GPU_R11G11B10 (equiv)
* OR D24S8 and GPU_DATA_UINT_24_8
- * We can Use BLIT ENCODER.
+ * We can use BLIT ENCODER.
*
* OTHERWISE TRIGGER COMPUTE:
* - Compute sizes will vary. Threads per grid WILL match 'extent'.
diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm
index ca19d1f9e4b..0cb38a3a2b7 100644
--- a/source/blender/gpu/metal/mtl_texture.mm
+++ b/source/blender/gpu/metal/mtl_texture.mm
@@ -23,13 +23,6 @@
#include "GHOST_C-api.h"
-/* Debug assistance. */
-/* Capture texture update routine for analysis in XCode GPU Frame Debugger. */
-#define DEBUG_TEXTURE_UPDATE_CAPTURE false
-
-/* Capture texture read routine for analysis in XCode GPU Frame Debugger. */
-#define DEBUG_TEXTURE_READ_CAPTURE false
-
namespace blender::gpu {
/* -------------------------------------------------------------------- */
@@ -41,34 +34,34 @@ void gpu::MTLTexture::mtl_texture_init()
BLI_assert(MTLContext::get() != nullptr);
/* Status. */
- this->is_baked_ = false;
- this->is_dirty_ = false;
- this->resource_mode_ = MTL_TEXTURE_MODE_DEFAULT;
- this->mtl_max_mips_ = 1;
+ is_baked_ = false;
+ is_dirty_ = false;
+ resource_mode_ = MTL_TEXTURE_MODE_DEFAULT;
+ mtl_max_mips_ = 1;
/* Metal properties. */
- this->texture_ = nil;
- this->texture_buffer_ = nil;
- this->mip_swizzle_view_ = nil;
+ texture_ = nil;
+ texture_buffer_ = nil;
+ mip_swizzle_view_ = nil;
/* Binding information. */
- this->is_bound_ = false;
+ is_bound_ = false;
/* VBO. */
- this->vert_buffer_ = nullptr;
- this->vert_buffer_mtl_ = nil;
- this->vert_buffer_offset_ = -1;
+ vert_buffer_ = nullptr;
+ vert_buffer_mtl_ = nil;
+ vert_buffer_offset_ = -1;
/* Default Swizzle. */
- this->tex_swizzle_mask_[0] = 'r';
- this->tex_swizzle_mask_[1] = 'g';
- this->tex_swizzle_mask_[2] = 'b';
- this->tex_swizzle_mask_[3] = 'a';
- this->mtl_swizzle_mask_ = MTLTextureSwizzleChannelsMake(
+ tex_swizzle_mask_[0] = 'r';
+ tex_swizzle_mask_[1] = 'g';
+ tex_swizzle_mask_[2] = 'b';
+ tex_swizzle_mask_[3] = 'a';
+ mtl_swizzle_mask_ = MTLTextureSwizzleChannelsMake(
MTLTextureSwizzleRed, MTLTextureSwizzleGreen, MTLTextureSwizzleBlue, MTLTextureSwizzleAlpha);
/* TODO(Metal): Find a way of specifying texture usage externally. */
- this->gpu_image_usage_flags_ = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
+ gpu_image_usage_flags_ = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
}
gpu::MTLTexture::MTLTexture(const char *name) : Texture(name)
@@ -89,23 +82,23 @@ gpu::MTLTexture::MTLTexture(const char *name,
/* Prep texture from METAL handle. */
BLI_assert(metal_texture != nil);
BLI_assert(type == GPU_TEXTURE_2D);
- this->type_ = type;
+ type_ = type;
init_2D(metal_texture.width, metal_texture.height, 0, 1, format);
/* Assign MTLTexture. */
- this->texture_ = metal_texture;
- [this->texture_ retain];
+ texture_ = metal_texture;
+ [texture_ retain];
/* Flag as Baked. */
- this->is_baked_ = true;
- this->is_dirty_ = false;
- this->resource_mode_ = MTL_TEXTURE_MODE_EXTERNAL;
+ is_baked_ = true;
+ is_dirty_ = false;
+ resource_mode_ = MTL_TEXTURE_MODE_EXTERNAL;
}
gpu::MTLTexture::~MTLTexture()
{
/* Unbind if bound. */
- if (this->is_bound_) {
+ if (is_bound_) {
MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
if (ctx != nullptr) {
ctx->state_manager->texture_unbind(this);
@@ -123,49 +116,49 @@ void gpu::MTLTexture::bake_mip_swizzle_view()
{
if (texture_view_dirty_flags_) {
/* if a texture view was previously created we release it. */
- if (this->mip_swizzle_view_ != nil) {
- [this->mip_swizzle_view_ release];
+ if (mip_swizzle_view_ != nil) {
+ [mip_swizzle_view_ release];
+ mip_swizzle_view_ = nil;
}
/* Determine num slices */
int num_slices = 1;
- switch (this->type_) {
+ switch (type_) {
case GPU_TEXTURE_1D_ARRAY:
- num_slices = this->h_;
+ num_slices = h_;
break;
case GPU_TEXTURE_2D_ARRAY:
- num_slices = this->d_;
+ num_slices = d_;
break;
case GPU_TEXTURE_CUBE:
num_slices = 6;
break;
case GPU_TEXTURE_CUBE_ARRAY:
/* d_ is equal to array levels * 6, including face count. */
- num_slices = this->d_;
+ num_slices = d_;
break;
default:
num_slices = 1;
break;
}
- int range_len = min_ii((this->mip_texture_max_level_ - this->mip_texture_base_level_) + 1,
- this->texture_.mipmapLevelCount);
+ int range_len = min_ii((mip_texture_max_level_ - mip_texture_base_level_) + 1,
+ texture_.mipmapLevelCount);
BLI_assert(range_len > 0);
- BLI_assert(mip_texture_base_level_ < this->texture_.mipmapLevelCount);
- BLI_assert(this->mip_texture_base_layer_ < num_slices);
- this->mip_swizzle_view_ = [this->texture_
- newTextureViewWithPixelFormat:this->texture_.pixelFormat
- textureType:this->texture_.textureType
- levels:NSMakeRange(this->mip_texture_base_level_, range_len)
- slices:NSMakeRange(this->mip_texture_base_layer_, num_slices)
- swizzle:this->mtl_swizzle_mask_];
+ BLI_assert(mip_texture_base_level_ < texture_.mipmapLevelCount);
+ BLI_assert(mip_texture_base_layer_ < num_slices);
+ mip_swizzle_view_ = [texture_
+ newTextureViewWithPixelFormat:texture_.pixelFormat
+ textureType:texture_.textureType
+ levels:NSMakeRange(mip_texture_base_level_, range_len)
+ slices:NSMakeRange(mip_texture_base_layer_, num_slices)
+ swizzle:mtl_swizzle_mask_];
MTL_LOG_INFO(
"Updating texture view - MIP TEXTURE BASE LEVEL: %d, MAX LEVEL: %d (Range len: %d)\n",
- this->mip_texture_base_level_,
- min_ii(this->mip_texture_max_level_, this->texture_.mipmapLevelCount),
+ mip_texture_base_level_,
+ min_ii(mip_texture_max_level_, texture_.mipmapLevelCount),
range_len);
- [this->mip_swizzle_view_ retain];
- this->mip_swizzle_view_.label = [this->texture_ label];
+ mip_swizzle_view_.label = [texture_ label];
texture_view_dirty_flags_ = TEXTURE_VIEW_NOT_DIRTY;
}
}
@@ -180,29 +173,29 @@ id<MTLTexture> gpu::MTLTexture::get_metal_handle()
this->ensure_baked();
/* Verify VBO texture shares same buffer. */
- if (this->resource_mode_ == MTL_TEXTURE_MODE_VBO) {
+ if (resource_mode_ == MTL_TEXTURE_MODE_VBO) {
int r_offset = -1;
/* TODO(Metal): Fetch buffer from MTLVertBuf when implemented. */
id<MTLBuffer> buf = nil; /*vert_buffer_->get_metal_buffer(&r_offset);*/
- BLI_assert(this->vert_buffer_mtl_ != nil);
- BLI_assert(buf == this->vert_buffer_mtl_ && r_offset == this->vert_buffer_offset_);
+ BLI_assert(vert_buffer_mtl_ != nil);
+ BLI_assert(buf == vert_buffer_mtl_ && r_offset == vert_buffer_offset_);
UNUSED_VARS(buf);
UNUSED_VARS_NDEBUG(r_offset);
}
- if (this->is_baked_) {
+ if (is_baked_) {
/* For explicit texture views, ensure we always return the texture view. */
- if (this->resource_mode_ == MTL_TEXTURE_MODE_TEXTURE_VIEW) {
- BLI_assert(this->mip_swizzle_view_ && "Texture view should always have a valid handle.");
+ if (resource_mode_ == MTL_TEXTURE_MODE_TEXTURE_VIEW) {
+ BLI_assert(mip_swizzle_view_ && "Texture view should always have a valid handle.");
}
- if (this->mip_swizzle_view_ != nil || texture_view_dirty_flags_) {
+ if (mip_swizzle_view_ != nil || texture_view_dirty_flags_) {
bake_mip_swizzle_view();
- return this->mip_swizzle_view_;
+ return mip_swizzle_view_;
}
- return this->texture_;
+ return texture_;
}
return nil;
}
@@ -214,36 +207,36 @@ id<MTLTexture> gpu::MTLTexture::get_metal_handle_base()
this->ensure_baked();
/* For explicit texture views, always return the texture view. */
- if (this->resource_mode_ == MTL_TEXTURE_MODE_TEXTURE_VIEW) {
- BLI_assert(this->mip_swizzle_view_ && "Texture view should always have a valid handle.");
- if (this->mip_swizzle_view_ != nil || texture_view_dirty_flags_) {
+ if (resource_mode_ == MTL_TEXTURE_MODE_TEXTURE_VIEW) {
+ BLI_assert(mip_swizzle_view_ && "Texture view should always have a valid handle.");
+ if (mip_swizzle_view_ != nil || texture_view_dirty_flags_) {
bake_mip_swizzle_view();
}
- return this->mip_swizzle_view_;
+ return mip_swizzle_view_;
}
/* Return base handle. */
- if (this->is_baked_) {
- return this->texture_;
+ if (is_baked_) {
+ return texture_;
}
return nil;
}
void gpu::MTLTexture::blit(id<MTLBlitCommandEncoder> blit_encoder,
- unsigned int src_x_offset,
- unsigned int src_y_offset,
- unsigned int src_z_offset,
- unsigned int src_slice,
- unsigned int src_mip,
+ uint src_x_offset,
+ uint src_y_offset,
+ uint src_z_offset,
+ uint src_slice,
+ uint src_mip,
gpu::MTLTexture *dest,
- unsigned int dst_x_offset,
- unsigned int dst_y_offset,
- unsigned int dst_z_offset,
- unsigned int dst_slice,
- unsigned int dst_mip,
- unsigned int width,
- unsigned int height,
- unsigned int depth)
+ uint dst_x_offset,
+ uint dst_y_offset,
+ uint dst_z_offset,
+ uint dst_slice,
+ uint dst_mip,
+ uint width,
+ uint height,
+ uint depth)
{
BLI_assert(this && dest);
@@ -273,13 +266,13 @@ void gpu::MTLTexture::blit(id<MTLBlitCommandEncoder> blit_encoder,
}
void gpu::MTLTexture::blit(gpu::MTLTexture *dst,
- unsigned int src_x_offset,
- unsigned int src_y_offset,
- unsigned int dst_x_offset,
- unsigned int dst_y_offset,
- unsigned int src_mip,
- unsigned int dst_mip,
- unsigned int dst_slice,
+ uint src_x_offset,
+ uint src_y_offset,
+ uint dst_x_offset,
+ uint dst_y_offset,
+ uint src_mip,
+ uint dst_mip,
+ uint dst_slice,
int width,
int height)
{
@@ -348,19 +341,19 @@ void gpu::MTLTexture::blit(gpu::MTLTexture *dst,
}
}
-GPUFrameBuffer *gpu::MTLTexture::get_blit_framebuffer(unsigned int dst_slice, unsigned int dst_mip)
+GPUFrameBuffer *gpu::MTLTexture::get_blit_framebuffer(uint dst_slice, uint dst_mip)
{
/* Check if layer has changed. */
bool update_attachments = false;
- if (!this->blit_fb_) {
- this->blit_fb_ = GPU_framebuffer_create("gpu_blit");
+ if (!blit_fb_) {
+ blit_fb_ = GPU_framebuffer_create("gpu_blit");
update_attachments = true;
}
/* Check if current blit FB has the correct attachment properties. */
- if (this->blit_fb_) {
- if (this->blit_fb_slice_ != dst_slice || this->blit_fb_mip_ != dst_mip) {
+ if (blit_fb_) {
+ if (blit_fb_slice_ != dst_slice || blit_fb_mip_ != dst_mip) {
update_attachments = true;
}
}
@@ -369,7 +362,7 @@ GPUFrameBuffer *gpu::MTLTexture::get_blit_framebuffer(unsigned int dst_slice, un
if (format_flag_ & GPU_FORMAT_DEPTH || format_flag_ & GPU_FORMAT_STENCIL) {
/* DEPTH TEX */
GPU_framebuffer_ensure_config(
- &this->blit_fb_,
+ &blit_fb_,
{GPU_ATTACHMENT_TEXTURE_LAYER_MIP(wrap(static_cast<Texture *>(this)),
static_cast<int>(dst_slice),
static_cast<int>(dst_mip)),
@@ -378,18 +371,18 @@ GPUFrameBuffer *gpu::MTLTexture::get_blit_framebuffer(unsigned int dst_slice, un
else {
/* COLOR TEX */
GPU_framebuffer_ensure_config(
- &this->blit_fb_,
+ &blit_fb_,
{GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE_LAYER_MIP(wrap(static_cast<Texture *>(this)),
static_cast<int>(dst_slice),
static_cast<int>(dst_mip))});
}
- this->blit_fb_slice_ = dst_slice;
- this->blit_fb_mip_ = dst_mip;
+ blit_fb_slice_ = dst_slice;
+ blit_fb_mip_ = dst_mip;
}
- BLI_assert(this->blit_fb_);
- return this->blit_fb_;
+ BLI_assert(blit_fb_);
+ return blit_fb_;
}
MTLSamplerState gpu::MTLTexture::get_sampler_state()
@@ -408,7 +401,7 @@ void gpu::MTLTexture::update_sub(
BLI_assert(ctx);
/* Do not update texture view. */
- BLI_assert(this->resource_mode_ != MTL_TEXTURE_MODE_TEXTURE_VIEW);
+ BLI_assert(resource_mode_ != MTL_TEXTURE_MODE_TEXTURE_VIEW);
/* Ensure mipmaps. */
this->ensure_mipmaps(mip);
@@ -418,16 +411,16 @@ void gpu::MTLTexture::update_sub(
/* Safety checks. */
#if TRUST_NO_ONE
- BLI_assert(mip >= this->mip_min_ && mip <= this->mip_max_);
- BLI_assert(mip < this->texture_.mipmapLevelCount);
- BLI_assert(this->texture_.mipmapLevelCount >= this->mip_max_);
+ BLI_assert(mip >= mip_min_ && mip <= mip_max_);
+ BLI_assert(mip < texture_.mipmapLevelCount);
+ BLI_assert(texture_.mipmapLevelCount >= mip_max_);
#endif
/* DEPTH FLAG - Depth formats cannot use direct BLIT - pass off to their own routine which will
* do a depth-only render. */
- bool is_depth_format = (this->format_flag_ & GPU_FORMAT_DEPTH);
+ bool is_depth_format = (format_flag_ & GPU_FORMAT_DEPTH);
if (is_depth_format) {
- switch (this->type_) {
+ switch (type_) {
case GPU_TEXTURE_2D: {
update_sub_depth_2d(mip, offset, extent, type, data);
@@ -444,7 +437,7 @@ void gpu::MTLTexture::update_sub(
@autoreleasepool {
/* Determine totalsize of INPUT Data. */
- int num_channels = to_component_len(this->format_);
+ int num_channels = to_component_len(format_);
int input_bytes_per_pixel = num_channels * to_bytesize(type);
int totalsize = 0;
@@ -482,26 +475,9 @@ void gpu::MTLTexture::update_sub(
BLI_assert(totalsize > 0);
/* Determine expected destination data size. */
- MTLPixelFormat destination_format = gpu_texture_format_to_metal(this->format_);
+ MTLPixelFormat destination_format = gpu_texture_format_to_metal(format_);
int expected_dst_bytes_per_pixel = get_mtl_format_bytesize(destination_format);
int destination_num_channels = get_mtl_format_num_components(destination_format);
- int destination_totalsize = 0;
- switch (this->dimensions_count()) {
- case 1:
- destination_totalsize = expected_dst_bytes_per_pixel * max_ii(expected_update_w, 1);
- break;
- case 2:
- destination_totalsize = expected_dst_bytes_per_pixel * max_ii(expected_update_w, 1) *
- max_ii(extent[1], 1);
- break;
- case 3:
- destination_totalsize = expected_dst_bytes_per_pixel * max_ii(expected_update_w, 1) *
- max_ii(extent[1], 1) * max_ii(extent[2], 1);
- break;
- default:
- BLI_assert(false);
- break;
- }
/* Prepare specialisation struct (For texture update routine). */
TextureUpdateRoutineSpecialisation compute_specialisation_kernel = {
@@ -517,21 +493,21 @@ void gpu::MTLTexture::update_sub(
can_use_direct_blit = false;
}
-#if MTL_VALIDATION_CRASH_DEPTH_1_1_1_WA
- if (this->type_ == GPU_TEXTURE_2D || this->type_ == GPU_TEXTURE_2D_ARRAY) {
- /* Workaround for crash in validation layer when blitting to depth2D target with
- * dimensions (1, 1, 1); */
- if (extent[0] == 1 && extent[1] == 1 && extent[2] == 1 && totalsize == 4) {
- can_use_direct_blit = false;
+ if (is_depth_format) {
+ if (type_ == GPU_TEXTURE_2D || type_ == GPU_TEXTURE_2D_ARRAY) {
+ /* Workaround for crash in validation layer when blitting to depth2D target with
+ * dimensions (1, 1, 1); */
+ if (extent[0] == 1 && extent[1] == 1 && extent[2] == 1 && totalsize == 4) {
+ can_use_direct_blit = false;
+ }
}
}
-#endif
- if (this->format_ == GPU_SRGB8_A8 && !can_use_direct_blit) {
+ if (format_ == GPU_SRGB8_A8 && !can_use_direct_blit) {
MTL_LOG_WARNING(
"SRGB data upload does not work correctly using compute upload. "
"texname '%s'\n",
- this->name_);
+ name_);
}
/* Safety Checks. */
@@ -573,49 +549,15 @@ void gpu::MTLTexture::update_sub(
}
}
- /* Debug hook for performing GPU capture of routine. */
- bool DO_CAPTURE = false;
-#if DEBUG_TEXTURE_UPDATE_CAPTURE == 1
- DO_CAPTURE = true;
- if (DO_CAPTURE) {
- MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
- MTLCaptureDescriptor *capture_descriptor = [[MTLCaptureDescriptor alloc] init];
- capture_descriptor.captureObject = ctx->device;
- NSError *error;
- if (![capture_manager startCaptureWithDescriptor:capture_descriptor error:&error]) {
- NSString *error_str = [NSString stringWithFormat:@"%@", error];
- const char *error_c_str = [error_str UTF8String];
- MTL_LOG_ERROR("Failed to start capture. Error: %s\n", error_c_str);
- }
- }
-#endif
-
- /* Fetch or Create command buffer. */
- id<MTLCommandBuffer> cmd_buffer = ctx->get_active_command_buffer();
- bool own_command_buffer = false;
- if (cmd_buffer == nil || DO_CAPTURE) {
- cmd_buffer = [ctx->queue commandBuffer];
- own_command_buffer = true;
- }
- else {
- /* Finish graphics work. */
- ctx->end_render_pass();
- }
-
/* Prepare staging buffer for data. */
id<MTLBuffer> staging_buffer = nil;
- unsigned long long staging_buffer_offset = 0;
+ uint64_t staging_buffer_offset = 0;
/* Fetch allocation from scratch buffer. */
- MTLTemporaryBufferRange allocation; /* TODO(Metal): Metal Memory manager. */
- /* = ctx->get_memory_manager().scratch_buffer_allocate_range_aligned(totalsize, 256);*/
- memcpy(allocation.host_ptr, data, totalsize);
+ MTLTemporaryBuffer allocation =
+ ctx->get_scratchbuffer_manager().scratch_buffer_allocate_range_aligned(totalsize, 256);
+ memcpy(allocation.data, data, totalsize);
staging_buffer = allocation.metal_buffer;
- if (own_command_buffer) {
- if (allocation.requires_flush()) {
- [staging_buffer didModifyRange:NSMakeRange(allocation.buffer_offset, allocation.size)];
- }
- }
staging_buffer_offset = allocation.buffer_offset;
/* Common Properties. */
@@ -629,23 +571,23 @@ void gpu::MTLTexture::update_sub(
return;
}
id<MTLTexture> texture_handle = ((compatible_write_format == destination_format)) ?
- this->texture_ :
- [this->texture_
+ texture_ :
+ [texture_
newTextureViewWithPixelFormat:compatible_write_format];
- /* Prepare encoders */
+ /* Prepare command encoders. */
id<MTLBlitCommandEncoder> blit_encoder = nil;
id<MTLComputeCommandEncoder> compute_encoder = nil;
if (can_use_direct_blit) {
- blit_encoder = [cmd_buffer blitCommandEncoder];
+ blit_encoder = ctx->main_command_buffer.ensure_begin_blit_encoder();
BLI_assert(blit_encoder != nil);
}
else {
- compute_encoder = [cmd_buffer computeCommandEncoder];
+ compute_encoder = ctx->main_command_buffer.ensure_begin_compute_encoder();
BLI_assert(compute_encoder != nil);
}
- switch (this->type_) {
+ switch (type_) {
/* 1D */
case GPU_TEXTURE_1D:
@@ -657,26 +599,26 @@ void gpu::MTLTexture::update_sub(
extent[0] :
ctx->pipeline_state.unpack_row_length);
int bytes_per_image = bytes_per_row;
- int max_array_index = ((this->type_ == GPU_TEXTURE_1D_ARRAY) ? extent[1] : 1);
+ int max_array_index = ((type_ == GPU_TEXTURE_1D_ARRAY) ? extent[1] : 1);
for (int array_index = 0; array_index < max_array_index; array_index++) {
int buffer_array_offset = staging_buffer_offset + (bytes_per_image * array_index);
- [blit_encoder copyFromBuffer:staging_buffer
- sourceOffset:buffer_array_offset
- sourceBytesPerRow:bytes_per_row
- sourceBytesPerImage:bytes_per_image
- sourceSize:MTLSizeMake(extent[0], 1, 1)
- toTexture:texture_handle
- destinationSlice:((this->type_ == GPU_TEXTURE_1D_ARRAY) ?
- (array_index + offset[1]) :
- 0)
- destinationLevel:mip
- destinationOrigin:MTLOriginMake(offset[0], 0, 0)];
+ [blit_encoder
+ copyFromBuffer:staging_buffer
+ sourceOffset:buffer_array_offset
+ sourceBytesPerRow:bytes_per_row
+ sourceBytesPerImage:bytes_per_image
+ sourceSize:MTLSizeMake(extent[0], 1, 1)
+ toTexture:texture_handle
+ destinationSlice:((type_ == GPU_TEXTURE_1D_ARRAY) ? (array_index + offset[1]) :
+ 0)
+ destinationLevel:mip
+ destinationOrigin:MTLOriginMake(offset[0], 0, 0)];
}
}
else {
/* Use Compute Based update. */
- if (this->type_ == GPU_TEXTURE_1D) {
+ if (type_ == GPU_TEXTURE_1D) {
id<MTLComputePipelineState> pso = texture_update_1d_get_kernel(
compute_specialisation_kernel);
TextureUpdateParams params = {mip,
@@ -693,7 +635,7 @@ void gpu::MTLTexture::update_sub(
dispatchThreads:MTLSizeMake(extent[0], 1, 1) /* Width, Height, Layer */
threadsPerThreadgroup:MTLSizeMake(64, 1, 1)];
}
- else if (this->type_ == GPU_TEXTURE_1D_ARRAY) {
+ else if (type_ == GPU_TEXTURE_1D_ARRAY) {
id<MTLComputePipelineState> pso = texture_update_1d_array_get_kernel(
compute_specialisation_kernel);
TextureUpdateParams params = {mip,
@@ -725,14 +667,14 @@ void gpu::MTLTexture::update_sub(
int bytes_per_image = bytes_per_row * extent[1];
int texture_array_relative_offset = 0;
- int base_slice = (this->type_ == GPU_TEXTURE_2D_ARRAY) ? offset[2] : 0;
- int final_slice = base_slice + ((this->type_ == GPU_TEXTURE_2D_ARRAY) ? extent[2] : 1);
+ int base_slice = (type_ == GPU_TEXTURE_2D_ARRAY) ? offset[2] : 0;
+ int final_slice = base_slice + ((type_ == GPU_TEXTURE_2D_ARRAY) ? extent[2] : 1);
for (int array_slice = base_slice; array_slice < final_slice; array_slice++) {
if (array_slice > 0) {
- BLI_assert(this->type_ == GPU_TEXTURE_2D_ARRAY);
- BLI_assert(array_slice < this->d_);
+ BLI_assert(type_ == GPU_TEXTURE_2D_ARRAY);
+ BLI_assert(array_slice < d_);
}
[blit_encoder copyFromBuffer:staging_buffer
@@ -750,7 +692,7 @@ void gpu::MTLTexture::update_sub(
}
else {
/* Use Compute texture update. */
- if (this->type_ == GPU_TEXTURE_2D) {
+ if (type_ == GPU_TEXTURE_2D) {
id<MTLComputePipelineState> pso = texture_update_2d_get_kernel(
compute_specialisation_kernel);
TextureUpdateParams params = {mip,
@@ -768,7 +710,7 @@ void gpu::MTLTexture::update_sub(
extent[0], extent[1], 1) /* Width, Height, Layer */
threadsPerThreadgroup:MTLSizeMake(8, 8, 1)];
}
- else if (this->type_ == GPU_TEXTURE_2D_ARRAY) {
+ else if (type_ == GPU_TEXTURE_2D_ARRAY) {
id<MTLComputePipelineState> pso = texture_update_2d_array_get_kernel(
compute_specialisation_kernel);
TextureUpdateParams params = {mip,
@@ -918,35 +860,15 @@ void gpu::MTLTexture::update_sub(
if (texture_.storageMode == MTLStorageModeManaged) {
[blit_encoder synchronizeResource:texture_buffer_];
}
-
- /* End Encoding. */
- [blit_encoder endEncoding];
}
else {
-
- /* End Encoding. */
- [compute_encoder endEncoding];
-
/* Textures which use MTLStorageModeManaged need to have updated contents
* synced back to CPU to avoid an automatic flush overwriting contents. */
if (texture_.storageMode == MTLStorageModeManaged) {
- blit_encoder = [cmd_buffer blitCommandEncoder];
+ blit_encoder = ctx->main_command_buffer.ensure_begin_blit_encoder();
[blit_encoder synchronizeResource:texture_buffer_];
- [blit_encoder endEncoding];
}
}
-
- if (own_command_buffer) {
- [cmd_buffer commit];
- }
-
-#if DEBUG_TEXTURE_UPDATE_CAPTURE == 1
- if (DO_CAPTURE) {
- [cmd_buffer waitUntilCompleted];
- MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
- [capture_manager stopCapture];
- }
-#endif
}
}
@@ -954,12 +876,12 @@ void gpu::MTLTexture::ensure_mipmaps(int miplvl)
{
/* Do not update texture view. */
- BLI_assert(this->resource_mode_ != MTL_TEXTURE_MODE_TEXTURE_VIEW);
+ BLI_assert(resource_mode_ != MTL_TEXTURE_MODE_TEXTURE_VIEW);
/* Clamp level to maximum. */
- int effective_h = (this->type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : this->h_;
- int effective_d = (this->type_ != GPU_TEXTURE_3D) ? 0 : this->d_;
- int max_dimension = max_iii(this->w_, effective_h, effective_d);
+ int effective_h = (type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : h_;
+ int effective_d = (type_ != GPU_TEXTURE_3D) ? 0 : d_;
+ int max_dimension = max_iii(w_, effective_h, effective_d);
int max_miplvl = floor(log2(max_dimension));
miplvl = min_ii(max_miplvl, miplvl);
@@ -968,15 +890,15 @@ void gpu::MTLTexture::ensure_mipmaps(int miplvl)
mipmaps_ = miplvl;
/* Check if baked. */
- if (this->is_baked_ && mipmaps_ > mtl_max_mips_) {
- this->is_dirty_ = true;
+ if (is_baked_ && mipmaps_ > mtl_max_mips_) {
+ is_dirty_ = true;
MTL_LOG_WARNING("Texture requires regenerating due to increase in mip-count\n");
}
}
this->mip_range_set(0, mipmaps_);
}
-void gpu::MTLTexture::generate_mipmap(void)
+void gpu::MTLTexture::generate_mipmap()
{
/* Fetch Active Context. */
MTLContext *ctx = reinterpret_cast<MTLContext *>(GPU_context_active_get());
@@ -993,44 +915,29 @@ void gpu::MTLTexture::generate_mipmap(void)
/* Ensure texture is baked. */
this->ensure_baked();
- BLI_assert(this->is_baked_ && this->texture_ && "MTLTexture is not valid");
+ BLI_assert(is_baked_ && texture_ && "MTLTexture is not valid");
- if (this->mipmaps_ == 1 || this->mtl_max_mips_ == 1) {
+ if (mipmaps_ == 1 || mtl_max_mips_ == 1) {
MTL_LOG_WARNING("Call to generate mipmaps on texture with 'mipmaps_=1\n'");
return;
}
/* Verify if we can perform mipmap generation. */
- if (this->format_ == GPU_DEPTH_COMPONENT32F || this->format_ == GPU_DEPTH_COMPONENT24 ||
- this->format_ == GPU_DEPTH_COMPONENT16 || this->format_ == GPU_DEPTH32F_STENCIL8 ||
- this->format_ == GPU_DEPTH24_STENCIL8) {
+ if (format_ == GPU_DEPTH_COMPONENT32F || format_ == GPU_DEPTH_COMPONENT24 ||
+ format_ == GPU_DEPTH_COMPONENT16 || format_ == GPU_DEPTH32F_STENCIL8 ||
+ format_ == GPU_DEPTH24_STENCIL8) {
MTL_LOG_WARNING("Cannot generate mipmaps for textures using DEPTH formats\n");
return;
}
@autoreleasepool {
- id<MTLCommandBuffer> cmd_buffer = ctx->get_active_command_buffer();
- bool own_command_buffer = false;
- if (cmd_buffer == nil) {
- cmd_buffer = [ctx->queue commandBuffer];
- own_command_buffer = true;
- }
- else {
- /* End active graphics work. */
- ctx->end_render_pass();
- }
-
- id<MTLBlitCommandEncoder> enc = [cmd_buffer blitCommandEncoder];
-#if MTL_DEBUG_COMMAND_BUFFER_EXECUTION
- [enc insertDebugSignpost:@"Generate MipMaps"];
-#endif
- [enc generateMipmapsForTexture:this->texture_];
- [enc endEncoding];
-
- if (own_command_buffer) {
- [cmd_buffer commit];
+ /* Fetch active BlitCommandEncoder. */
+ id<MTLBlitCommandEncoder> enc = ctx->main_command_buffer.ensure_begin_blit_encoder();
+ if (G.debug & G_DEBUG_GPU) {
+ [enc insertDebugSignpost:@"Generate MipMaps"];
}
+ [enc generateMipmapsForTexture:texture_];
}
return;
}
@@ -1055,13 +962,8 @@ void gpu::MTLTexture::copy_to(Texture *dst)
this->ensure_baked();
@autoreleasepool {
- /* End render pass. */
- ctx->end_render_pass();
-
/* Setup blit encoder. */
- id<MTLCommandBuffer> cmd_buffer = ctx->get_active_command_buffer();
- BLI_assert(cmd_buffer != nil);
- id<MTLBlitCommandEncoder> blit_encoder = [cmd_buffer blitCommandEncoder];
+ id<MTLBlitCommandEncoder> blit_encoder = ctx->main_command_buffer.ensure_begin_blit_encoder();
BLI_assert(blit_encoder != nil);
/* TODO(Metal): Consider supporting multiple mip levels IF the GL implementation
@@ -1077,7 +979,7 @@ void gpu::MTLTexture::copy_to(Texture *dst)
case GPU_TEXTURE_CUBE_ARRAY:
case GPU_TEXTURE_3D: {
/* Do full texture copy for 3D textures */
- BLI_assert(mt_dst->d_ == this->d_);
+ BLI_assert(mt_dst->d_ == d_);
[blit_encoder copyFromTexture:this->get_metal_handle_base()
toTexture:mt_dst->get_metal_handle_base()];
} break;
@@ -1100,9 +1002,6 @@ void gpu::MTLTexture::copy_to(Texture *dst)
extent[2]);
} break;
}
-
- /* End encoding */
- [blit_encoder endEncoding];
}
}
@@ -1144,8 +1043,8 @@ static MTLTextureSwizzle swizzle_to_mtl(const char swizzle)
void gpu::MTLTexture::swizzle_set(const char swizzle_mask[4])
{
- if (memcmp(this->tex_swizzle_mask_, swizzle_mask, 4) != 0) {
- memcpy(this->tex_swizzle_mask_, swizzle_mask, 4);
+ if (memcmp(tex_swizzle_mask_, swizzle_mask, 4) != 0) {
+ memcpy(tex_swizzle_mask_, swizzle_mask, 4);
/* Creating the swizzle mask and flagging as dirty if changed. */
MTLTextureSwizzleChannels new_swizzle_mask = MTLTextureSwizzleChannelsMake(
@@ -1154,8 +1053,8 @@ void gpu::MTLTexture::swizzle_set(const char swizzle_mask[4])
swizzle_to_mtl(swizzle_mask[2]),
swizzle_to_mtl(swizzle_mask[3]));
- this->mtl_swizzle_mask_ = new_swizzle_mask;
- this->texture_view_dirty_flags_ |= TEXTURE_VIEW_SWIZZLE_DIRTY;
+ mtl_swizzle_mask_ = new_swizzle_mask;
+ texture_view_dirty_flags_ |= TEXTURE_VIEW_SWIZZLE_DIRTY;
}
}
@@ -1172,25 +1071,24 @@ void gpu::MTLTexture::mip_range_set(int min, int max)
*
* TODO(Metal): Add texture initialization flag to determine whether mipmaps are used
* or not. Will be important for saving memory for big textures. */
- this->mip_min_ = min;
- this->mip_max_ = max;
+ mip_min_ = min;
+ mip_max_ = max;
- if ((this->type_ == GPU_TEXTURE_1D || this->type_ == GPU_TEXTURE_1D_ARRAY ||
- this->type_ == GPU_TEXTURE_BUFFER) &&
+ if ((type_ == GPU_TEXTURE_1D || type_ == GPU_TEXTURE_1D_ARRAY || type_ == GPU_TEXTURE_BUFFER) &&
max > 1) {
MTL_LOG_ERROR(
" MTLTexture of type TEXTURE_1D_ARRAY or TEXTURE_BUFFER cannot have a mipcount "
"greater than 1\n");
- this->mip_min_ = 0;
- this->mip_max_ = 0;
- this->mipmaps_ = 0;
+ mip_min_ = 0;
+ mip_max_ = 0;
+ mipmaps_ = 0;
BLI_assert(false);
}
/* Mip range for texture view. */
- this->mip_texture_base_level_ = this->mip_min_;
- this->mip_texture_max_level_ = this->mip_max_;
+ mip_texture_base_level_ = mip_min_;
+ mip_texture_max_level_ = mip_max_;
texture_view_dirty_flags_ |= TEXTURE_VIEW_MIP_DIRTY;
}
@@ -1199,7 +1097,7 @@ void *gpu::MTLTexture::read(int mip, eGPUDataFormat type)
/* Prepare Array for return data. */
BLI_assert(!(format_flag_ & GPU_FORMAT_COMPRESSED));
BLI_assert(mip <= mipmaps_);
- BLI_assert(validate_data_format_mtl(this->format_, type));
+ BLI_assert(validate_data_format_mtl(format_, type));
/* NOTE: mip_size_get() won't override any dimension that is equal to 0. */
int extent[3] = {1, 1, 1};
@@ -1208,12 +1106,12 @@ void *gpu::MTLTexture::read(int mip, eGPUDataFormat type)
size_t sample_len = extent[0] * extent[1] * extent[2];
size_t sample_size = to_bytesize(format_, type);
size_t texture_size = sample_len * sample_size;
- int num_channels = to_component_len(this->format_);
+ int num_channels = to_component_len(format_);
void *data = MEM_mallocN(texture_size + 8, "GPU_texture_read");
/* Ensure texture is baked. */
- if (this->is_baked_) {
+ if (is_baked_) {
this->read_internal(
mip, 0, 0, 0, extent[0], extent[1], extent[2], type, num_channels, texture_size + 8, data);
}
@@ -1239,7 +1137,7 @@ void gpu::MTLTexture::read_internal(int mip,
void *r_data)
{
/* Verify textures are baked. */
- if (!this->is_baked_) {
+ if (!is_baked_) {
MTL_LOG_WARNING("gpu::MTLTexture::read_internal - Trying to read from a non-baked texture!\n");
return;
}
@@ -1248,14 +1146,14 @@ void gpu::MTLTexture::read_internal(int mip,
BLI_assert(ctx);
/* Calculate Desired output size. */
- int num_channels = to_component_len(this->format_);
+ int num_channels = to_component_len(format_);
BLI_assert(num_output_components <= num_channels);
- unsigned int desired_output_bpp = num_output_components * to_bytesize(desired_output_format);
+ uint desired_output_bpp = num_output_components * to_bytesize(desired_output_format);
/* Calculate Metal data output for trivial copy. */
- unsigned int image_bpp = get_mtl_format_bytesize(this->texture_.pixelFormat);
- unsigned int image_components = get_mtl_format_num_components(this->texture_.pixelFormat);
- bool is_depth_format = (this->format_flag_ & GPU_FORMAT_DEPTH);
+ uint image_bpp = get_mtl_format_bytesize(texture_.pixelFormat);
+ uint image_components = get_mtl_format_num_components(texture_.pixelFormat);
+ bool is_depth_format = (format_flag_ & GPU_FORMAT_DEPTH);
/* Verify if we need to use compute read. */
eGPUDataFormat data_format = to_mtl_internal_data_format(this->format_get());
@@ -1272,12 +1170,12 @@ void gpu::MTLTexture::read_internal(int mip,
BLI_assert(num_output_components == 1);
BLI_assert(image_components == 1);
BLI_assert(data_format == GPU_DATA_FLOAT || data_format == GPU_DATA_UINT_24_8);
- BLI_assert(validate_data_format_mtl(this->format_, data_format));
+ BLI_assert(validate_data_format_mtl(format_, data_format));
}
/* SPECIAL Workaround for R11G11B10 textures requesting a read using: GPU_DATA_10_11_11_REV. */
if (desired_output_format == GPU_DATA_10_11_11_REV) {
- BLI_assert(this->format_ == GPU_R11F_G11F_B10F);
+ BLI_assert(format_ == GPU_R11F_G11F_B10F);
/* override parameters - we'll be able to use simple copy, as bpp will match at 4 bytes. */
image_bpp = sizeof(int);
@@ -1291,9 +1189,9 @@ void gpu::MTLTexture::read_internal(int mip,
}
/* Determine size of output data. */
- unsigned int bytes_per_row = desired_output_bpp * width;
- unsigned int bytes_per_image = bytes_per_row * height;
- unsigned int total_bytes = bytes_per_image * depth;
+ uint bytes_per_row = desired_output_bpp * width;
+ uint bytes_per_image = bytes_per_row * height;
+ uint total_bytes = bytes_per_image * depth;
if (can_use_simple_read) {
/* DEBUG check that if direct copy is being used, then both the expected output size matches
@@ -1307,7 +1205,7 @@ void gpu::MTLTexture::read_internal(int mip,
/* Fetch allocation from scratch buffer. */
id<MTLBuffer> destination_buffer = nil;
- unsigned int destination_offset = 0;
+ uint destination_offset = 0;
void *destination_buffer_host_ptr = nullptr;
/* TODO(Metal): Optimize buffer allocation. */
@@ -1315,7 +1213,7 @@ void gpu::MTLTexture::read_internal(int mip,
destination_buffer = [ctx->device newBufferWithLength:max_ii(total_bytes, 256)
options:bufferOptions];
destination_offset = 0;
- destination_buffer_host_ptr = (void *)((unsigned char *)([destination_buffer contents]) +
+ destination_buffer_host_ptr = (void *)((uint8_t *)([destination_buffer contents]) +
destination_offset);
/* Prepare specialisation struct (For non-trivial texture read routine). */
@@ -1348,53 +1246,25 @@ void gpu::MTLTexture::read_internal(int mip,
bool copy_successful = false;
@autoreleasepool {
- bool DO_CAPTURE = false;
-#if DEBUG_TEXTURE_READ_CAPTURE == 1
- DO_CAPTURE = true;
- if (DO_CAPTURE) {
- MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
- MTLCaptureDescriptor *capture_descriptor = [[MTLCaptureDescriptor alloc] init];
- capture_descriptor.captureObject = ctx->device;
- NSError *error;
- if (![capture_manager startCaptureWithDescriptor:capture_descriptor error:&error]) {
- NSString *error_str = [NSString stringWithFormat:@"%@", error];
- const char *error_c_str = [error_str UTF8String];
- MTL_LOG_ERROR("Failed to start capture. Error: %s\n", error_c_str);
- }
- }
-#endif
-
/* TODO(Metal): Verify whether we need some form of barrier here to ensure reads
* happen after work with associated texture is finished. */
GPU_finish();
- /* Fetch or Create command buffer. */
- id<MTLCommandBuffer> cmd_buffer = ctx->get_active_command_buffer();
- bool own_command_buffer = false;
- if (cmd_buffer == nil || DO_CAPTURE || true) {
- cmd_buffer = [ctx->queue commandBuffer];
- own_command_buffer = true;
- }
- else {
- /* End any graphics workloads. */
- ctx->end_render_pass();
- }
-
/* Texture View for SRGB special case. */
- id<MTLTexture> read_texture = this->texture_;
- if (this->format_ == GPU_SRGB8_A8) {
- read_texture = [this->texture_ newTextureViewWithPixelFormat:MTLPixelFormatRGBA8Unorm];
+ id<MTLTexture> read_texture = texture_;
+ if (format_ == GPU_SRGB8_A8) {
+ read_texture = [texture_ newTextureViewWithPixelFormat:MTLPixelFormatRGBA8Unorm];
}
/* Perform per-texture type read. */
- switch (this->type_) {
+ switch (type_) {
case GPU_TEXTURE_2D: {
if (can_use_simple_read) {
/* Use Blit Encoder READ. */
- id<MTLBlitCommandEncoder> enc = [cmd_buffer blitCommandEncoder];
-#if MTL_DEBUG_COMMAND_BUFFER_EXECUTION
- [enc insertDebugSignpost:@"GPUTextureRead"];
-#endif
+ id<MTLBlitCommandEncoder> enc = ctx->main_command_buffer.ensure_begin_blit_encoder();
+ if (G.debug & G_DEBUG_GPU) {
+ [enc insertDebugSignpost:@"GPUTextureRead"];
+ }
[enc copyFromTexture:read_texture
sourceSlice:0
sourceLevel:mip
@@ -1405,13 +1275,13 @@ void gpu::MTLTexture::read_internal(int mip,
destinationBytesPerRow:bytes_per_row
destinationBytesPerImage:bytes_per_image];
[enc synchronizeResource:destination_buffer];
- [enc endEncoding];
copy_successful = true;
}
else {
/* Use Compute READ. */
- id<MTLComputeCommandEncoder> compute_encoder = [cmd_buffer computeCommandEncoder];
+ id<MTLComputeCommandEncoder> compute_encoder =
+ ctx->main_command_buffer.ensure_begin_compute_encoder();
id<MTLComputePipelineState> pso = texture_read_2d_get_kernel(
compute_specialisation_kernel);
TextureReadParams params = {
@@ -1425,15 +1295,13 @@ void gpu::MTLTexture::read_internal(int mip,
[compute_encoder setTexture:read_texture atIndex:0];
[compute_encoder dispatchThreads:MTLSizeMake(width, height, 1) /* Width, Height, Layer */
threadsPerThreadgroup:MTLSizeMake(8, 8, 1)];
- [compute_encoder endEncoding];
/* Use Blit encoder to synchronize results back to CPU. */
- id<MTLBlitCommandEncoder> enc = [cmd_buffer blitCommandEncoder];
-#if MTL_DEBUG_COMMAND_BUFFER_EXECUTION
- [enc insertDebugSignpost:@"GPUTextureRead-syncResource"];
-#endif
+ id<MTLBlitCommandEncoder> enc = ctx->main_command_buffer.ensure_begin_blit_encoder();
+ if (G.debug & G_DEBUG_GPU) {
+ [enc insertDebugSignpost:@"GPUTextureRead-syncResource"];
+ }
[enc synchronizeResource:destination_buffer];
- [enc endEncoding];
copy_successful = true;
}
} break;
@@ -1441,10 +1309,10 @@ void gpu::MTLTexture::read_internal(int mip,
case GPU_TEXTURE_2D_ARRAY: {
if (can_use_simple_read) {
/* Use Blit Encoder READ. */
- id<MTLBlitCommandEncoder> enc = [cmd_buffer blitCommandEncoder];
-#if MTL_DEBUG_COMMAND_BUFFER_EXECUTION
- [enc insertDebugSignpost:@"GPUTextureRead"];
-#endif
+ id<MTLBlitCommandEncoder> enc = ctx->main_command_buffer.ensure_begin_blit_encoder();
+ if (G.debug & G_DEBUG_GPU) {
+ [enc insertDebugSignpost:@"GPUTextureRead"];
+ }
int base_slice = z_off;
int final_slice = base_slice + depth;
int texture_array_relative_offset = 0;
@@ -1463,13 +1331,13 @@ void gpu::MTLTexture::read_internal(int mip,
texture_array_relative_offset += bytes_per_image;
}
- [enc endEncoding];
copy_successful = true;
}
else {
/* Use Compute READ */
- id<MTLComputeCommandEncoder> compute_encoder = [cmd_buffer computeCommandEncoder];
+ id<MTLComputeCommandEncoder> compute_encoder =
+ ctx->main_command_buffer.ensure_begin_compute_encoder();
id<MTLComputePipelineState> pso = texture_read_2d_array_get_kernel(
compute_specialisation_kernel);
TextureReadParams params = {
@@ -1484,25 +1352,23 @@ void gpu::MTLTexture::read_internal(int mip,
[compute_encoder
dispatchThreads:MTLSizeMake(width, height, depth) /* Width, Height, Layer */
threadsPerThreadgroup:MTLSizeMake(8, 8, 1)];
- [compute_encoder endEncoding];
/* Use Blit encoder to synchronize results back to CPU. */
- id<MTLBlitCommandEncoder> enc = [cmd_buffer blitCommandEncoder];
-#if MTL_DEBUG_COMMAND_BUFFER_EXECUTION
- [enc insertDebugSignpost:@"GPUTextureRead-syncResource"];
-#endif
+ id<MTLBlitCommandEncoder> enc = ctx->main_command_buffer.ensure_begin_blit_encoder();
+ if (G.debug & G_DEBUG_GPU) {
+ [enc insertDebugSignpost:@"GPUTextureRead-syncResource"];
+ }
[enc synchronizeResource:destination_buffer];
- [enc endEncoding];
copy_successful = true;
}
} break;
case GPU_TEXTURE_CUBE_ARRAY: {
if (can_use_simple_read) {
- id<MTLBlitCommandEncoder> enc = [cmd_buffer blitCommandEncoder];
-#if MTL_DEBUG_COMMAND_BUFFER_EXECUTION
- [enc insertDebugSignpost:@"GPUTextureRead"];
-#endif
+ id<MTLBlitCommandEncoder> enc = ctx->main_command_buffer.ensure_begin_blit_encoder();
+ if (G.debug & G_DEBUG_GPU) {
+ [enc insertDebugSignpost:@"GPUTextureRead"];
+ }
int base_slice = z_off;
int final_slice = base_slice + depth;
int texture_array_relative_offset = 0;
@@ -1522,7 +1388,6 @@ void gpu::MTLTexture::read_internal(int mip,
texture_array_relative_offset += bytes_per_image;
}
MTL_LOG_INFO("Copying texture data to buffer GPU_TEXTURE_CUBE_ARRAY\n");
- [enc endEncoding];
copy_successful = true;
}
else {
@@ -1534,27 +1399,13 @@ void gpu::MTLTexture::read_internal(int mip,
MTL_LOG_WARNING(
"[Warning] gpu::MTLTexture::read_internal simple-copy not yet supported for texture "
"type: %d\n",
- (int)this->type_);
+ (int)type_);
break;
}
if (copy_successful) {
- /* Ensure GPU copy from texture to host-accessible buffer is complete. */
- if (own_command_buffer) {
- [cmd_buffer commit];
- [cmd_buffer waitUntilCompleted];
- }
- else {
- /* Ensure GPU copy commands have completed. */
- GPU_finish();
- }
-
-#if DEBUG_TEXTURE_READ_CAPTURE == 1
- if (DO_CAPTURE) {
- MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager];
- [capture_manager stopCapture];
- }
-#endif
+ /* Ensure GPU copy commands have completed. */
+ GPU_finish();
/* Copy data from Shared Memory into ptr. */
memcpy(r_data, destination_buffer_host_ptr, total_bytes);
@@ -1576,16 +1427,16 @@ void gpu::MTLTexture::read_internal(int mip,
}
/* Remove once no longer required -- will just return 0 for now in MTL path. */
-uint gpu::MTLTexture::gl_bindcode_get(void) const
+uint gpu::MTLTexture::gl_bindcode_get() const
{
return 0;
}
-bool gpu::MTLTexture::init_internal(void)
+bool gpu::MTLTexture::init_internal()
{
- if (this->format_ == GPU_DEPTH24_STENCIL8) {
+ if (format_ == GPU_DEPTH24_STENCIL8) {
/* Apple Silicon requires GPU_DEPTH32F_STENCIL8 instead of GPU_DEPTH24_STENCIL8. */
- this->format_ = GPU_DEPTH32F_STENCIL8;
+ format_ = GPU_DEPTH32F_STENCIL8;
}
this->prepare_internal();
@@ -1609,20 +1460,20 @@ bool gpu::MTLTexture::init_internal(const GPUTexture *src, int mip_offset, int l
this->prepare_internal();
/* Flag as using texture view. */
- this->resource_mode_ = MTL_TEXTURE_MODE_TEXTURE_VIEW;
- this->source_texture_ = src;
- this->mip_texture_base_level_ = mip_offset;
- this->mip_texture_base_layer_ = layer_offset;
+ resource_mode_ = MTL_TEXTURE_MODE_TEXTURE_VIEW;
+ source_texture_ = src;
+ mip_texture_base_level_ = mip_offset;
+ mip_texture_base_layer_ = layer_offset;
/* Assign texture as view. */
const gpu::MTLTexture *mtltex = static_cast<const gpu::MTLTexture *>(unwrap(src));
- this->texture_ = mtltex->texture_;
- BLI_assert(this->texture_);
- [this->texture_ retain];
+ texture_ = mtltex->texture_;
+ BLI_assert(texture_);
+ [texture_ retain];
/* Flag texture as baked -- we do not need explicit initialization. */
- this->is_baked_ = true;
- this->is_dirty_ = false;
+ is_baked_ = true;
+ is_dirty_ = false;
/* Bake mip swizzle view. */
bake_mip_swizzle_view();
@@ -1637,7 +1488,7 @@ bool gpu::MTLTexture::init_internal(const GPUTexture *src, int mip_offset, int l
bool gpu::MTLTexture::texture_is_baked()
{
- return this->is_baked_;
+ return is_baked_;
}
/* Prepare texture parameters after initialization, but before baking. */
@@ -1645,22 +1496,21 @@ void gpu::MTLTexture::prepare_internal()
{
/* Derive implicit usage flags for Depth/Stencil attachments. */
- if (this->format_flag_ & GPU_FORMAT_DEPTH || this->format_flag_ & GPU_FORMAT_STENCIL) {
- this->gpu_image_usage_flags_ |= GPU_TEXTURE_USAGE_ATTACHMENT;
+ if (format_flag_ & GPU_FORMAT_DEPTH || format_flag_ & GPU_FORMAT_STENCIL) {
+ gpu_image_usage_flags_ |= GPU_TEXTURE_USAGE_ATTACHMENT;
}
/* Derive maximum number of mip levels by default.
* TODO(Metal): This can be removed if max mip counts are specified upfront. */
- if (this->type_ == GPU_TEXTURE_1D || this->type_ == GPU_TEXTURE_1D_ARRAY ||
- this->type_ == GPU_TEXTURE_BUFFER) {
- this->mtl_max_mips_ = 1;
+ if (type_ == GPU_TEXTURE_1D || type_ == GPU_TEXTURE_1D_ARRAY || type_ == GPU_TEXTURE_BUFFER) {
+ mtl_max_mips_ = 1;
}
else {
- int effective_h = (this->type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : this->h_;
- int effective_d = (this->type_ != GPU_TEXTURE_3D) ? 0 : this->d_;
- int max_dimension = max_iii(this->w_, effective_h, effective_d);
+ int effective_h = (type_ == GPU_TEXTURE_1D_ARRAY) ? 0 : h_;
+ int effective_d = (type_ != GPU_TEXTURE_3D) ? 0 : d_;
+ int max_dimension = max_iii(w_, effective_h, effective_d);
int max_miplvl = max_ii(floor(log2(max_dimension)) + 1, 1);
- this->mtl_max_mips_ = max_miplvl;
+ mtl_max_mips_ = max_miplvl;
}
}
@@ -1669,101 +1519,91 @@ void gpu::MTLTexture::ensure_baked()
/* If properties have changed, re-bake. */
bool copy_previous_contents = false;
- if (this->is_baked_ && this->is_dirty_) {
+ if (is_baked_ && is_dirty_) {
copy_previous_contents = true;
- id<MTLTexture> previous_texture = this->texture_;
+ id<MTLTexture> previous_texture = texture_;
[previous_texture retain];
this->reset();
}
- if (!this->is_baked_) {
+ if (!is_baked_) {
MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
BLI_assert(ctx);
/* Ensure texture mode is valid. */
- BLI_assert(this->resource_mode_ != MTL_TEXTURE_MODE_EXTERNAL);
- BLI_assert(this->resource_mode_ != MTL_TEXTURE_MODE_TEXTURE_VIEW);
- BLI_assert(this->resource_mode_ != MTL_TEXTURE_MODE_VBO);
+ BLI_assert(resource_mode_ != MTL_TEXTURE_MODE_EXTERNAL);
+ BLI_assert(resource_mode_ != MTL_TEXTURE_MODE_TEXTURE_VIEW);
+ BLI_assert(resource_mode_ != MTL_TEXTURE_MODE_VBO);
/* Format and mip levels (TODO(Metal): Optimize mipmaps counts, specify up-front). */
- MTLPixelFormat mtl_format = gpu_texture_format_to_metal(this->format_);
+ MTLPixelFormat mtl_format = gpu_texture_format_to_metal(format_);
/* Create texture descriptor. */
- switch (this->type_) {
+ switch (type_) {
/* 1D */
case GPU_TEXTURE_1D:
case GPU_TEXTURE_1D_ARRAY: {
- BLI_assert(this->w_ > 0);
- this->texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
- this->texture_descriptor_.pixelFormat = mtl_format;
- this->texture_descriptor_.textureType = (this->type_ == GPU_TEXTURE_1D_ARRAY) ?
- MTLTextureType1DArray :
- MTLTextureType1D;
- this->texture_descriptor_.width = this->w_;
- this->texture_descriptor_.height = 1;
- this->texture_descriptor_.depth = 1;
- this->texture_descriptor_.arrayLength = (this->type_ == GPU_TEXTURE_1D_ARRAY) ? this->h_ :
- 1;
- this->texture_descriptor_.mipmapLevelCount = (this->mtl_max_mips_ > 0) ?
- this->mtl_max_mips_ :
- 1;
- this->texture_descriptor_.usage =
+ BLI_assert(w_ > 0);
+ texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
+ texture_descriptor_.pixelFormat = mtl_format;
+ texture_descriptor_.textureType = (type_ == GPU_TEXTURE_1D_ARRAY) ? MTLTextureType1DArray :
+ MTLTextureType1D;
+ texture_descriptor_.width = w_;
+ texture_descriptor_.height = 1;
+ texture_descriptor_.depth = 1;
+ texture_descriptor_.arrayLength = (type_ == GPU_TEXTURE_1D_ARRAY) ? h_ : 1;
+ texture_descriptor_.mipmapLevelCount = (mtl_max_mips_ > 0) ? mtl_max_mips_ : 1;
+ texture_descriptor_.usage =
MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite |
MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */
- this->texture_descriptor_.storageMode = MTLStorageModePrivate;
- this->texture_descriptor_.sampleCount = 1;
- this->texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
- this->texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
+ texture_descriptor_.storageMode = MTLStorageModePrivate;
+ texture_descriptor_.sampleCount = 1;
+ texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
+ texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
} break;
/* 2D */
case GPU_TEXTURE_2D:
case GPU_TEXTURE_2D_ARRAY: {
- BLI_assert(this->w_ > 0 && this->h_ > 0);
- this->texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
- this->texture_descriptor_.pixelFormat = mtl_format;
- this->texture_descriptor_.textureType = (this->type_ == GPU_TEXTURE_2D_ARRAY) ?
- MTLTextureType2DArray :
- MTLTextureType2D;
- this->texture_descriptor_.width = this->w_;
- this->texture_descriptor_.height = this->h_;
- this->texture_descriptor_.depth = 1;
- this->texture_descriptor_.arrayLength = (this->type_ == GPU_TEXTURE_2D_ARRAY) ? this->d_ :
- 1;
- this->texture_descriptor_.mipmapLevelCount = (this->mtl_max_mips_ > 0) ?
- this->mtl_max_mips_ :
- 1;
- this->texture_descriptor_.usage =
+ BLI_assert(w_ > 0 && h_ > 0);
+ texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
+ texture_descriptor_.pixelFormat = mtl_format;
+ texture_descriptor_.textureType = (type_ == GPU_TEXTURE_2D_ARRAY) ? MTLTextureType2DArray :
+ MTLTextureType2D;
+ texture_descriptor_.width = w_;
+ texture_descriptor_.height = h_;
+ texture_descriptor_.depth = 1;
+ texture_descriptor_.arrayLength = (type_ == GPU_TEXTURE_2D_ARRAY) ? d_ : 1;
+ texture_descriptor_.mipmapLevelCount = (mtl_max_mips_ > 0) ? mtl_max_mips_ : 1;
+ texture_descriptor_.usage =
MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite |
MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */
- this->texture_descriptor_.storageMode = MTLStorageModePrivate;
- this->texture_descriptor_.sampleCount = 1;
- this->texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
- this->texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
+ texture_descriptor_.storageMode = MTLStorageModePrivate;
+ texture_descriptor_.sampleCount = 1;
+ texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
+ texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
} break;
/* 3D */
case GPU_TEXTURE_3D: {
- BLI_assert(this->w_ > 0 && this->h_ > 0 && this->d_ > 0);
- this->texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
- this->texture_descriptor_.pixelFormat = mtl_format;
- this->texture_descriptor_.textureType = MTLTextureType3D;
- this->texture_descriptor_.width = this->w_;
- this->texture_descriptor_.height = this->h_;
- this->texture_descriptor_.depth = this->d_;
- this->texture_descriptor_.arrayLength = 1;
- this->texture_descriptor_.mipmapLevelCount = (this->mtl_max_mips_ > 0) ?
- this->mtl_max_mips_ :
- 1;
- this->texture_descriptor_.usage =
+ BLI_assert(w_ > 0 && h_ > 0 && d_ > 0);
+ texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
+ texture_descriptor_.pixelFormat = mtl_format;
+ texture_descriptor_.textureType = MTLTextureType3D;
+ texture_descriptor_.width = w_;
+ texture_descriptor_.height = h_;
+ texture_descriptor_.depth = d_;
+ texture_descriptor_.arrayLength = 1;
+ texture_descriptor_.mipmapLevelCount = (mtl_max_mips_ > 0) ? mtl_max_mips_ : 1;
+ texture_descriptor_.usage =
MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite |
MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */
- this->texture_descriptor_.storageMode = MTLStorageModePrivate;
- this->texture_descriptor_.sampleCount = 1;
- this->texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
- this->texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
+ texture_descriptor_.storageMode = MTLStorageModePrivate;
+ texture_descriptor_.sampleCount = 1;
+ texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
+ texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
} break;
/* CUBE TEXTURES */
@@ -1771,69 +1611,63 @@ void gpu::MTLTexture::ensure_baked()
case GPU_TEXTURE_CUBE_ARRAY: {
/* NOTE: For a cube-map 'Texture::d_' refers to total number of faces,
* not just array slices. */
- BLI_assert(this->w_ > 0 && this->h_ > 0);
- this->texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
- this->texture_descriptor_.pixelFormat = mtl_format;
- this->texture_descriptor_.textureType = (this->type_ == GPU_TEXTURE_CUBE_ARRAY) ?
- MTLTextureTypeCubeArray :
- MTLTextureTypeCube;
- this->texture_descriptor_.width = this->w_;
- this->texture_descriptor_.height = this->h_;
- this->texture_descriptor_.depth = 1;
- this->texture_descriptor_.arrayLength = (this->type_ == GPU_TEXTURE_CUBE_ARRAY) ?
- this->d_ / 6 :
- 1;
- this->texture_descriptor_.mipmapLevelCount = (this->mtl_max_mips_ > 0) ?
- this->mtl_max_mips_ :
- 1;
- this->texture_descriptor_.usage =
+ BLI_assert(w_ > 0 && h_ > 0);
+ texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
+ texture_descriptor_.pixelFormat = mtl_format;
+ texture_descriptor_.textureType = (type_ == GPU_TEXTURE_CUBE_ARRAY) ?
+ MTLTextureTypeCubeArray :
+ MTLTextureTypeCube;
+ texture_descriptor_.width = w_;
+ texture_descriptor_.height = h_;
+ texture_descriptor_.depth = 1;
+ texture_descriptor_.arrayLength = (type_ == GPU_TEXTURE_CUBE_ARRAY) ? d_ / 6 : 1;
+ texture_descriptor_.mipmapLevelCount = (mtl_max_mips_ > 0) ? mtl_max_mips_ : 1;
+ texture_descriptor_.usage =
MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite |
MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */
- this->texture_descriptor_.storageMode = MTLStorageModePrivate;
- this->texture_descriptor_.sampleCount = 1;
- this->texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
- this->texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
+ texture_descriptor_.storageMode = MTLStorageModePrivate;
+ texture_descriptor_.sampleCount = 1;
+ texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
+ texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
} break;
/* GPU_TEXTURE_BUFFER */
case GPU_TEXTURE_BUFFER: {
- this->texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
- this->texture_descriptor_.pixelFormat = mtl_format;
- this->texture_descriptor_.textureType = MTLTextureTypeTextureBuffer;
- this->texture_descriptor_.width = this->w_;
- this->texture_descriptor_.height = 1;
- this->texture_descriptor_.depth = 1;
- this->texture_descriptor_.arrayLength = 1;
- this->texture_descriptor_.mipmapLevelCount = (this->mtl_max_mips_ > 0) ?
- this->mtl_max_mips_ :
- 1;
- this->texture_descriptor_.usage =
+ texture_descriptor_ = [[MTLTextureDescriptor alloc] init];
+ texture_descriptor_.pixelFormat = mtl_format;
+ texture_descriptor_.textureType = MTLTextureTypeTextureBuffer;
+ texture_descriptor_.width = w_;
+ texture_descriptor_.height = 1;
+ texture_descriptor_.depth = 1;
+ texture_descriptor_.arrayLength = 1;
+ texture_descriptor_.mipmapLevelCount = (mtl_max_mips_ > 0) ? mtl_max_mips_ : 1;
+ texture_descriptor_.usage =
MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite |
MTLTextureUsagePixelFormatView; /* TODO(Metal): Optimize usage flags. */
- this->texture_descriptor_.storageMode = MTLStorageModePrivate;
- this->texture_descriptor_.sampleCount = 1;
- this->texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
- this->texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
+ texture_descriptor_.storageMode = MTLStorageModePrivate;
+ texture_descriptor_.sampleCount = 1;
+ texture_descriptor_.cpuCacheMode = MTLCPUCacheModeDefaultCache;
+ texture_descriptor_.hazardTrackingMode = MTLHazardTrackingModeDefault;
} break;
default: {
- MTL_LOG_ERROR("[METAL] Error: Cannot create texture with unknown type: %d\n", this->type_);
+ MTL_LOG_ERROR("[METAL] Error: Cannot create texture with unknown type: %d\n", type_);
return;
} break;
}
/* Determine Resource Mode. */
- this->resource_mode_ = MTL_TEXTURE_MODE_DEFAULT;
+ resource_mode_ = MTL_TEXTURE_MODE_DEFAULT;
/* Create texture. */
- this->texture_ = [ctx->device newTextureWithDescriptor:this->texture_descriptor_];
-
- [this->texture_descriptor_ release];
- this->texture_descriptor_ = nullptr;
- this->texture_.label = [NSString stringWithUTF8String:this->get_name()];
- BLI_assert(this->texture_);
- this->is_baked_ = true;
- this->is_dirty_ = false;
+ texture_ = [ctx->device newTextureWithDescriptor:texture_descriptor_];
+
+ [texture_descriptor_ release];
+ texture_descriptor_ = nullptr;
+ texture_.label = [NSString stringWithUTF8String:this->get_name()];
+ BLI_assert(texture_);
+ is_baked_ = true;
+ is_dirty_ = false;
}
/* Re-apply previous contents. */
@@ -1850,30 +1684,30 @@ void gpu::MTLTexture::reset()
MTL_LOG_INFO("Texture %s reset. Size %d, %d, %d\n", this->get_name(), w_, h_, d_);
/* Delete associated METAL resources. */
- if (this->texture_ != nil) {
- [this->texture_ release];
- this->texture_ = nil;
- this->is_baked_ = false;
- this->is_dirty_ = true;
+ if (texture_ != nil) {
+ [texture_ release];
+ texture_ = nil;
+ is_baked_ = false;
+ is_dirty_ = true;
}
- if (this->mip_swizzle_view_ != nil) {
- [this->mip_swizzle_view_ release];
- this->mip_swizzle_view_ = nil;
+ if (mip_swizzle_view_ != nil) {
+ [mip_swizzle_view_ release];
+ mip_swizzle_view_ = nil;
}
- if (this->texture_buffer_ != nil) {
- [this->texture_buffer_ release];
+ if (texture_buffer_ != nil) {
+ [texture_buffer_ release];
}
/* Blit framebuffer. */
- if (this->blit_fb_) {
- GPU_framebuffer_free(this->blit_fb_);
- this->blit_fb_ = nullptr;
+ if (blit_fb_) {
+ GPU_framebuffer_free(blit_fb_);
+ blit_fb_ = nullptr;
}
- BLI_assert(this->texture_ == nil);
- BLI_assert(this->mip_swizzle_view_ == nil);
+ BLI_assert(texture_ == nil);
+ BLI_assert(mip_swizzle_view_ == nil);
}
/** \} */
diff --git a/source/blender/gpu/metal/mtl_texture_util.mm b/source/blender/gpu/metal/mtl_texture_util.mm
index 27efc770e73..e2f0b3c848e 100644
--- a/source/blender/gpu/metal/mtl_texture_util.mm
+++ b/source/blender/gpu/metal/mtl_texture_util.mm
@@ -493,13 +493,13 @@ void gpu::MTLTexture::update_sub_depth_2d(
int mip, int offset[3], int extent[3], eGPUDataFormat type, const void *data)
{
/* Verify we are in a valid configuration. */
- BLI_assert(ELEM(this->format_,
+ BLI_assert(ELEM(format_,
GPU_DEPTH_COMPONENT24,
GPU_DEPTH_COMPONENT32F,
GPU_DEPTH_COMPONENT16,
GPU_DEPTH24_STENCIL8,
GPU_DEPTH32F_STENCIL8));
- BLI_assert(validate_data_format_mtl(this->format_, type));
+ BLI_assert(validate_data_format_mtl(format_, type));
BLI_assert(ELEM(type, GPU_DATA_FLOAT, GPU_DATA_UINT_24_8, GPU_DATA_UINT));
/* Determine whether we are in GPU_DATA_UINT_24_8 or GPU_DATA_FLOAT mode. */
@@ -528,7 +528,7 @@ void gpu::MTLTexture::update_sub_depth_2d(
/* Push contents into an r32_tex and render contents to depth using a shader. */
GPUTexture *r32_tex_tmp = GPU_texture_create_2d(
- "depth_intermediate_copy_tex", this->w_, this->h_, 1, format, nullptr);
+ "depth_intermediate_copy_tex", w_, h_, 1, format, nullptr);
GPU_texture_filter_mode(r32_tex_tmp, false);
GPU_texture_wrap_mode(r32_tex_tmp, false, true);
gpu::MTLTexture *mtl_tex = static_cast<gpu::MTLTexture *>(unwrap(r32_tex_tmp));
@@ -538,7 +538,7 @@ void gpu::MTLTexture::update_sub_depth_2d(
GPUFrameBuffer *depth_fb_temp = GPU_framebuffer_create("depth_intermediate_copy_fb");
GPU_framebuffer_texture_attach(depth_fb_temp, wrap(static_cast<Texture *>(this)), 0, mip);
GPU_framebuffer_bind(depth_fb_temp);
- if (extent[0] == this->w_ && extent[1] == this->h_) {
+ if (extent[0] == w_ && extent[1] == h_) {
/* Skip load if the whole texture is being updated. */
GPU_framebuffer_clear_depth(depth_fb_temp, 0.0);
GPU_framebuffer_clear_stencil(depth_fb_temp, 0);
@@ -553,7 +553,7 @@ void gpu::MTLTexture::update_sub_depth_2d(
GPU_batch_uniform_1i(quad, "mip", mip);
GPU_batch_uniform_2f(quad, "extent", (float)extent[0], (float)extent[1]);
GPU_batch_uniform_2f(quad, "offset", (float)offset[0], (float)offset[1]);
- GPU_batch_uniform_2f(quad, "size", (float)this->w_, (float)this->h_);
+ GPU_batch_uniform_2f(quad, "size", (float)w_, (float)h_);
bool depth_write_prev = GPU_depth_mask_get();
uint stencil_mask_prev = GPU_stencil_mask_get();
@@ -624,11 +624,11 @@ id<MTLComputePipelineState> gpu::MTLTexture::mtl_texture_read_impl(
depth_scale_factor = 1;
break;
case 2:
- /* D24 unsigned int */
+ /* D24 uint */
depth_scale_factor = 0xFFFFFFu;
break;
case 4:
- /* D32 unsigned int */
+ /* D32 uint */
depth_scale_factor = 0xFFFFFFFFu;
break;
default:
diff --git a/source/blender/gpu/metal/mtl_uniform_buffer.hh b/source/blender/gpu/metal/mtl_uniform_buffer.hh
new file mode 100644
index 00000000000..722d819cf96
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_uniform_buffer.hh
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "MEM_guardedalloc.h"
+#include "gpu_uniform_buffer_private.hh"
+
+#include "mtl_context.hh"
+
+namespace blender::gpu {
+
+/**
+ * Implementation of Uniform Buffers using Metal.
+ **/
+class MTLUniformBuf : public UniformBuf {
+ private:
+ /* Allocation Handle. */
+ gpu::MTLBuffer *metal_buffer_ = nullptr;
+
+ /* Whether buffer has contents, if false, no GPU buffer will
+ * have yet been allocated. */
+ bool has_data_ = false;
+
+ /* Bindstate tracking. */
+ int bind_slot_ = -1;
+ MTLContext *bound_ctx_ = nullptr;
+
+ public:
+ MTLUniformBuf(size_t size, const char *name);
+ ~MTLUniformBuf();
+
+ void update(const void *data) override;
+ void bind(int slot) override;
+ void unbind() override;
+
+ id<MTLBuffer> get_metal_buffer(int *r_offset);
+ int get_size();
+ const char *get_name()
+ {
+ return name_;
+ }
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("MTLUniformBuf");
+};
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/metal/mtl_uniform_buffer.mm b/source/blender/gpu/metal/mtl_uniform_buffer.mm
new file mode 100644
index 00000000000..3415c41f2cc
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_uniform_buffer.mm
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "BKE_global.h"
+
+#include "BLI_string.h"
+
+#include "gpu_backend.hh"
+#include "gpu_context_private.hh"
+
+#include "mtl_backend.hh"
+#include "mtl_context.hh"
+#include "mtl_debug.hh"
+#include "mtl_uniform_buffer.hh"
+
+namespace blender::gpu {
+
+MTLUniformBuf::MTLUniformBuf(size_t size, const char *name) : UniformBuf(size, name)
+{
+}
+
+MTLUniformBuf::~MTLUniformBuf()
+{
+ if (metal_buffer_ != nullptr) {
+ metal_buffer_->free();
+ metal_buffer_ = nullptr;
+ }
+ has_data_ = false;
+
+ /* Ensure UBO is not bound to active CTX.
+ * UBO bindings are reset upon Context-switch so we do not need
+ * to check deactivated context's. */
+ MTLContext *ctx = MTLContext::get();
+ if (ctx) {
+ for (int i = 0; i < MTL_MAX_UNIFORM_BUFFER_BINDINGS; i++) {
+ MTLUniformBufferBinding &slot = ctx->pipeline_state.ubo_bindings[i];
+ if (slot.bound && slot.ubo == this) {
+ slot.bound = false;
+ slot.ubo = nullptr;
+ }
+ }
+ }
+}
+
+void MTLUniformBuf::update(const void *data)
+{
+ BLI_assert(this);
+ BLI_assert(size_in_bytes_ > 0);
+
+ /* Free existing allocation.
+ * The previous UBO resource will be tracked by the memory manager,
+ * in case dependent GPU work is still executing. */
+ if (metal_buffer_ != nullptr) {
+ metal_buffer_->free();
+ metal_buffer_ = nullptr;
+ }
+
+ /* Allocate MTL buffer */
+ MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
+ BLI_assert(ctx);
+ BLI_assert(ctx->device);
+ UNUSED_VARS_NDEBUG(ctx);
+
+ if (data != nullptr) {
+ metal_buffer_ = MTLContext::get_global_memory_manager().allocate_with_data(
+ size_in_bytes_, true, data);
+ has_data_ = true;
+
+ metal_buffer_->set_label(@"Uniform Buffer");
+ BLI_assert(metal_buffer_ != nullptr);
+ BLI_assert(metal_buffer_->get_metal_buffer() != nil);
+ }
+ else {
+ /* If data is not yet present, no buffer will be allocated and MTLContext will use an empty
+ * null buffer, containing zeroes, if the UBO is bound. */
+ metal_buffer_ = nullptr;
+ has_data_ = false;
+ }
+}
+
+void MTLUniformBuf::bind(int slot)
+{
+ if (slot < 0) {
+ MTL_LOG_WARNING("Failed to bind UBO %p. uniform location %d invalid.\n", this, slot);
+ return;
+ }
+
+ BLI_assert(slot < MTL_MAX_UNIFORM_BUFFER_BINDINGS);
+
+ /* Bind current UBO to active context. */
+ MTLContext *ctx = MTLContext::get();
+ BLI_assert(ctx);
+
+ MTLUniformBufferBinding &ctx_ubo_bind_slot = ctx->pipeline_state.ubo_bindings[slot];
+ ctx_ubo_bind_slot.ubo = this;
+ ctx_ubo_bind_slot.bound = true;
+
+ bind_slot_ = slot;
+ bound_ctx_ = ctx;
+
+ /* Check if we have any deferred data to upload. */
+ if (data_ != nullptr) {
+ this->update(data_);
+ MEM_SAFE_FREE(data_);
+ }
+
+ /* Ensure there is atleast an empty dummy buffer. */
+ if (metal_buffer_ == nullptr) {
+ this->update(nullptr);
+ }
+}
+
+void MTLUniformBuf::unbind()
+{
+ /* Unbind in debug mode to validate missing binds.
+ * Otherwise, only perform a full unbind upon destruction
+ * to ensure no lingering references. */
+#ifndef NDEBUG
+ if (true) {
+#else
+ if (G.debug & G_DEBUG_GPU) {
+#endif
+ if (bound_ctx_ != nullptr && bind_slot_ > -1) {
+ MTLUniformBufferBinding &ctx_ubo_bind_slot =
+ bound_ctx_->pipeline_state.ubo_bindings[bind_slot_];
+ if (ctx_ubo_bind_slot.bound && ctx_ubo_bind_slot.ubo == this) {
+ ctx_ubo_bind_slot.bound = false;
+ ctx_ubo_bind_slot.ubo = nullptr;
+ }
+ }
+ }
+
+ /* Reset bind index. */
+ bind_slot_ = -1;
+ bound_ctx_ = nullptr;
+}
+
+id<MTLBuffer> MTLUniformBuf::get_metal_buffer(int *r_offset)
+{
+ BLI_assert(this);
+ *r_offset = 0;
+ if (metal_buffer_ != nullptr && has_data_) {
+ *r_offset = 0;
+ metal_buffer_->debug_ensure_used();
+ return metal_buffer_->get_metal_buffer();
+ }
+ else {
+ *r_offset = 0;
+ return nil;
+ }
+}
+
+int MTLUniformBuf::get_size()
+{
+ BLI_assert(this);
+ return size_in_bytes_;
+}
+
+} // blender::gpu
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 0c796ddc765..4869bff2737 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -10,8 +10,6 @@
#include "gpu_capabilities_private.hh"
#include "gpu_platform_private.hh"
-#include "glew-mx.h"
-
#include "gl_debug.hh"
#include "gl_backend.hh"
@@ -408,7 +406,7 @@ static void detect_workarounds()
/* Certain Intel/AMD based platforms don't clear the viewport textures. Always clearing leads to
* noticeable performance regressions on other platforms as well. */
if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY) ||
- GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
+ GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
GCaps.clear_viewport_workaround = true;
}
diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh
index 29249111294..e425b87afe8 100644
--- a/source/blender/gpu/opengl/gl_backend.hh
+++ b/source/blender/gpu/opengl/gl_backend.hh
@@ -42,11 +42,15 @@ class GLBackend : public GPUBackend {
}
~GLBackend()
{
- GLTexture::samplers_free();
-
GLBackend::platform_exit();
}
+ void delete_resources() override
+ {
+ /* Delete any resources with context active. */
+ GLTexture::samplers_free();
+ }
+
static GLBackend *get()
{
return static_cast<GLBackend *>(GPUBackend::get());
diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc
index e738413879e..fde2a53bb0f 100644
--- a/source/blender/gpu/opengl/gl_batch.cc
+++ b/source/blender/gpu/opengl/gl_batch.cc
@@ -11,12 +11,9 @@
#include "BLI_assert.h"
-#include "glew-mx.h"
-
#include "gpu_batch_private.hh"
#include "gpu_shader_private.hh"
-#include "gl_backend.hh"
#include "gl_context.hh"
#include "gl_debug.hh"
#include "gl_index_buffer.hh"
diff --git a/source/blender/gpu/opengl/gl_batch.hh b/source/blender/gpu/opengl/gl_batch.hh
index a25e495b3b1..1a18572c683 100644
--- a/source/blender/gpu/opengl/gl_batch.hh
+++ b/source/blender/gpu/opengl/gl_batch.hh
@@ -35,9 +35,9 @@ class GLShaderInterface;
class GLVaoCache {
private:
/** Context for which the vao_cache_ was generated. */
- GLContext *context_ = NULL;
+ GLContext *context_ = nullptr;
/** Last interface this batch was drawn with. */
- GLShaderInterface *interface_ = NULL;
+ GLShaderInterface *interface_ = nullptr;
/** Cached VAO for the last interface. */
GLuint vao_id_ = 0;
/** Used when arb_base_instance is not supported. */
diff --git a/source/blender/gpu/opengl/gl_compute.cc b/source/blender/gpu/opengl/gl_compute.cc
index 2fbf23c227d..1f8bb69dc3a 100644
--- a/source/blender/gpu/opengl/gl_compute.cc
+++ b/source/blender/gpu/opengl/gl_compute.cc
@@ -8,8 +8,6 @@
#include "gl_debug.hh"
-#include "glew-mx.h"
-
namespace blender::gpu {
void GLCompute::dispatch(int group_x_len, int group_y_len, int group_z_len)
diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc
index 72892ffcd34..e6af126e9cd 100644
--- a/source/blender/gpu/opengl/gl_context.cc
+++ b/source/blender/gpu/opengl/gl_context.cc
@@ -6,7 +6,6 @@
*/
#include "BLI_assert.h"
-#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "BKE_global.h"
@@ -150,6 +149,16 @@ void GLContext::deactivate()
is_active_ = false;
}
+void GLContext::begin_frame()
+{
+ /* No-op. */
+}
+
+void GLContext::end_frame()
+{
+ /* No-op. */
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh
index c333c8a4afd..234bc712513 100644
--- a/source/blender/gpu/opengl/gl_context.hh
+++ b/source/blender/gpu/opengl/gl_context.hh
@@ -106,6 +106,8 @@ class GLContext : public Context {
void activate() override;
void deactivate() override;
+ void begin_frame() override;
+ void end_frame() override;
void flush() override;
void finish() override;
diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc
index f82138e0d65..79b28642a67 100644
--- a/source/blender/gpu/opengl/gl_debug.cc
+++ b/source/blender/gpu/opengl/gl_debug.cc
@@ -189,7 +189,7 @@ void check_gl_error(const char *info)
case err: { \
char msg[256]; \
SNPRINTF(msg, "%s : %s", #err, info); \
- debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, NULL); \
+ debug_callback(0, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, 0, msg, nullptr); \
break; \
}
diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc
index c02b6b26068..79d1b54828d 100644
--- a/source/blender/gpu/opengl/gl_debug_layer.cc
+++ b/source/blender/gpu/opengl/gl_debug_layer.cc
@@ -10,8 +10,6 @@
#include "BLI_utildefines.h"
-#include "glew-mx.h"
-
#include "gl_debug.hh"
using GPUvoidptr = void *;
diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc
index 2f87c859273..fd76d8c58f8 100644
--- a/source/blender/gpu/opengl/gl_drawlist.cc
+++ b/source/blender/gpu/opengl/gl_drawlist.cc
@@ -11,9 +11,6 @@
#include "BLI_assert.h"
#include "GPU_batch.h"
-#include "GPU_capabilities.h"
-
-#include "glew-mx.h"
#include "gpu_context_private.hh"
#include "gpu_drawlist_private.hh"
diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc
index 57eeabba0a0..bd9fba4250d 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.cc
+++ b/source/blender/gpu/opengl/gl_framebuffer.cc
@@ -7,8 +7,6 @@
#include "BKE_global.h"
-#include "GPU_capabilities.h"
-
#include "gl_backend.hh"
#include "gl_debug.hh"
#include "gl_state.hh"
diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh
index 3927ff27532..2dc0936d0fe 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.hh
+++ b/source/blender/gpu/opengl/gl_framebuffer.hh
@@ -30,9 +30,9 @@ class GLFrameBuffer : public FrameBuffer {
/** OpenGL handle. */
GLuint fbo_id_ = 0;
/** Context the handle is from. Frame-buffers are not shared across contexts. */
- GLContext *context_ = NULL;
+ GLContext *context_ = nullptr;
/** State Manager of the same contexts. */
- GLStateManager *state_manager_ = NULL;
+ GLStateManager *state_manager_ = nullptr;
/** Copy of the GL state. Contains ONLY color attachments enums for slot binding. */
GLenum gl_attachments_[GPU_FB_MAX_COLOR_ATTACHMENT];
/** Internal frame-buffers are immutable. */
@@ -77,6 +77,11 @@ class GLFrameBuffer : public FrameBuffer {
eGPUDataFormat data_format,
const void *clear_value) override;
+ /* Attachment load-stores are currently no-op's in OpenGL. */
+ void attachment_set_loadstore_op(GPUAttachmentType /*type*/,
+ eGPULoadOp /*load_action*/,
+ eGPUStoreOp /*store_action*/) override{};
+
void read(eGPUFrameBufferBits planes,
eGPUDataFormat format,
const int area[4],
diff --git a/source/blender/gpu/opengl/gl_immediate.cc b/source/blender/gpu/opengl/gl_immediate.cc
index c32a6afd8cf..a332a2fbc7c 100644
--- a/source/blender/gpu/opengl/gl_immediate.cc
+++ b/source/blender/gpu/opengl/gl_immediate.cc
@@ -7,8 +7,6 @@
* Mimics old style opengl immediate mode drawing.
*/
-#include "BKE_global.h"
-
#include "gpu_context_private.hh"
#include "gpu_shader_private.hh"
#include "gpu_vertex_format_private.h"
diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc
index 8cedb831272..566169182e3 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.cc
+++ b/source/blender/gpu/opengl/gl_index_buffer.cc
@@ -6,7 +6,6 @@
*/
#include "gl_context.hh"
-#include "gl_debug.hh"
#include "gl_index_buffer.hh"
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 5a28b8b7318..ccdf10c1ed2 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -13,7 +13,6 @@
#include "GPU_capabilities.h"
#include "GPU_platform.h"
-#include "gl_backend.hh"
#include "gl_debug.hh"
#include "gl_vertex_buffer.hh"
@@ -613,7 +612,7 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
if (info.early_fragment_test_) {
ss << "layout(early_fragment_tests) in;\n";
}
- if (GLEW_VERSION_4_2 || GLEW_ARB_conservative_depth) {
+ if (GLEW_ARB_conservative_depth) {
ss << "layout(" << to_string(info.depth_write_) << ") out float gl_FragDepth;\n";
}
ss << "\n/* Outputs. */\n";
@@ -836,7 +835,7 @@ static char *glsl_patch_default_get()
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_VERSION_4_2 && GLEW_ARB_conservative_depth) {
+ if (GLEW_ARB_conservative_depth) {
STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n");
}
if (GPU_shader_image_load_store_support()) {
diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc
index f6a7eee80c3..1b3ab2941a8 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.cc
+++ b/source/blender/gpu/opengl/gl_shader_interface.cc
@@ -9,7 +9,6 @@
#include "BLI_bitmap.h"
-#include "gl_backend.hh"
#include "gl_batch.hh"
#include "gl_context.hh"
diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc
index 68a88938f69..8be4ac29af6 100644
--- a/source/blender/gpu/opengl/gl_state.cc
+++ b/source/blender/gpu/opengl/gl_state.cc
@@ -12,10 +12,7 @@
#include "GPU_capabilities.h"
-#include "glew-mx.h"
-
#include "gl_context.hh"
-#include "gl_debug.hh"
#include "gl_framebuffer.hh"
#include "gl_texture.hh"
diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc
index b30674fe5fa..4592adc3a61 100644
--- a/source/blender/gpu/opengl/gl_storage_buffer.cc
+++ b/source/blender/gpu/opengl/gl_storage_buffer.cc
@@ -5,8 +5,6 @@
* \ingroup gpu
*/
-#include "BKE_global.h"
-
#include "BLI_string.h"
#include "gpu_backend.hh"
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index 14f84273925..cfb3184c4a5 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -5,8 +5,6 @@
* \ingroup gpu
*/
-#include "BKE_global.h"
-
#include "DNA_userdef_types.h"
#include "GPU_capabilities.h"
@@ -312,6 +310,12 @@ void GLTexture::update_sub(
*/
void GLTexture::generate_mipmap()
{
+ /* Allow users to provide mipmaps stored in compressed textures.
+ * Skip generating mipmaps to avoid overriding the existing ones. */
+ if (format_flag_ & GPU_FORMAT_COMPRESSED) {
+ return;
+ }
+
/* Some drivers have bugs when using #glGenerateMipmap with depth textures (see T56789).
* In this case we just create a complete texture with mipmaps manually without
* down-sampling. You must initialize the texture levels using other methods like
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index e5b879f1f15..aeb9fc0e6b7 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -33,7 +33,7 @@ class GLTexture : public Texture {
/** opengl identifier for texture. */
GLuint tex_id_ = 0;
/** Legacy workaround for texture copy. Created when using framebuffer_get(). */
- struct GPUFrameBuffer *framebuffer_ = NULL;
+ struct GPUFrameBuffer *framebuffer_ = nullptr;
/** 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;
diff --git a/source/blender/gpu/opengl/gl_uniform_buffer.cc b/source/blender/gpu/opengl/gl_uniform_buffer.cc
index b8bcaf0047e..e58cea9de43 100644
--- a/source/blender/gpu/opengl/gl_uniform_buffer.cc
+++ b/source/blender/gpu/opengl/gl_uniform_buffer.cc
@@ -5,14 +5,10 @@
* \ingroup gpu
*/
-#include "BKE_global.h"
-
#include "BLI_string.h"
-#include "gpu_backend.hh"
#include "gpu_context_private.hh"
-#include "gl_backend.hh"
#include "gl_debug.hh"
#include "gl_uniform_buffer.hh"
diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc
index cfcf77fe705..a3299fc3325 100644
--- a/source/blender/gpu/opengl/gl_vertex_array.cc
+++ b/source/blender/gpu/opengl/gl_vertex_array.cc
@@ -7,7 +7,6 @@
#include "gpu_shader_interface.hh"
#include "gpu_vertex_buffer_private.hh"
-#include "gpu_vertex_format_private.h"
#include "gl_batch.hh"
#include "gl_context.hh"
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 4962fb01c88..b0da035ef09 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
@@ -5,7 +5,7 @@ void main()
float dist_squared = dot(centered, centered);
const float rad_squared = 0.25;
- // round point with jaggy edges
+ /* Round point with jaggy edges. */
if (dist_squared > rad_squared) {
discard;
}
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
index 6840dfe25de..396ee64454c 100644
--- a/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh
+++ b/source/blender/gpu/shaders/infos/gpu_shader_3D_polyline_info.hh
@@ -37,7 +37,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_3D_polyline_uniform_color)
GPU_SHADER_CREATE_INFO(gpu_shader_3D_polyline_uniform_color_clipped)
.do_static_compilation(true)
- /* TODO(fclem): Put in an UBO to fit the 128byte requirement. */
+ /* TODO(fclem): Put in a UBO to fit the 128byte requirement. */
.push_constant(Type::MAT4, "ModelMatrix")
.push_constant(Type::VEC4, "ClipPlane")
.define("CLIP")
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
index ff84a0a334c..b1a29833d77 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_camera.glsl
@@ -1,6 +1,8 @@
void camera(out vec3 outview, out float outdepth, out float outdist)
{
- outdepth = abs(transform_point(ViewMatrix, g_data.P).z);
- outdist = distance(g_data.P, cameraPos);
- outview = normalize(g_data.P - cameraPos);
+ vec3 vP = transform_point(ViewMatrix, g_data.P);
+ vP.z = -vP.z;
+ outdepth = abs(vP.z);
+ outdist = length(vP);
+ outview = normalize(vP);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
index 530907859e9..c95a41c58fc 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_eevee_specular.glsl
@@ -34,6 +34,13 @@ void node_eevee_specular(vec4 diffuse,
diffuse_data.N = N;
diffuse_data.sss_id = 0u;
+ /* WORKAROUND: Nasty workaround to the current interface with the closure evaluation.
+ * Ideally the occlusion input should be move to the output node or removed all-together.
+ * This is temporary to avoid a regression in 3.2 and should be removed after EEVEE-Next rewrite.
+ */
+ diffuse_data.sss_radius.r = occlusion;
+ diffuse_data.sss_radius.g = -1.0; /* Flag */
+
ClosureReflection reflection_data;
reflection_data.weight = alpha;
if (true) {
@@ -41,7 +48,7 @@ void node_eevee_specular(vec4 diffuse,
vec2 split_sum = brdf_lut(NV, roughness);
vec3 brdf = F_brdf_single_scatter(specular.rgb, vec3(1.0), split_sum);
- reflection_data.color = specular.rgb * brdf;
+ reflection_data.color = brdf;
reflection_data.N = N;
reflection_data.roughness = roughness;
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
index 4c9ff31622f..fed7ac7df66 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -1,6 +1,6 @@
#pragma BLENDER_REQUIRE(gpu_shader_material_tangent.glsl)
-void node_geometry(vec3 orco,
+void node_geometry(vec3 orco_attr,
out vec3 position,
out vec3 normal,
out vec3 tangent,
@@ -21,8 +21,8 @@ void node_geometry(vec3 orco,
tangent = g_data.curve_T;
}
else {
- tangent_orco_z(orco, orco);
- node_tangent(orco, tangent);
+ tangent_orco_z(orco_attr, orco_attr);
+ node_tangent(orco_attr, tangent);
}
parametric = vec3(g_data.barycentric_coords, 0.0);
diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc
index 4e93e062b50..224a9afcf59 100644
--- a/source/blender/gpu/tests/gpu_testing.cc
+++ b/source/blender/gpu/tests/gpu_testing.cc
@@ -26,7 +26,6 @@ void GPUTest::SetUp()
void GPUTest::TearDown()
{
GPU_exit();
- GPU_backend_exit();
GPU_context_discard(context);
GHOST_DisposeOpenGLContext(ghost_system, ghost_context);
GHOST_DisposeSystem(ghost_system);
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index e46326467cc..1309e3810be 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -178,13 +178,13 @@ if(WITH_IMAGE_WEBP)
list(APPEND SRC
intern/webp.c
)
- list(APPEND INC_SYS
- ${WEBP_INCLUDE_DIRS}
- )
+ list(APPEND INC_SYS
+ ${WEBP_INCLUDE_DIRS}
+ )
list(APPEND LIB
${WEBP_LIBRARIES}
)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
list(APPEND INC
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 512dc674fc7..0818dd653a1 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -181,7 +181,6 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
int width,
int height,
const struct ImBuf *ibuf,
- bool compress_as_srgb,
bool store_premultiplied);
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
int offset_x,
@@ -342,6 +341,7 @@ const char *IMB_colormanagement_look_get_indexed_name(int index);
int IMB_colormanagement_colorspace_get_named_index(const char *name);
const char *IMB_colormanagement_colorspace_get_indexed_name(int index);
+const char *IMB_colormanagement_colorspace_get_name(const struct ColorSpace *colorspace);
const char *IMB_colormanagement_view_get_default_name(const char *display_name);
void IMB_colormanagement_colorspace_from_ibuf_ftype(
@@ -519,10 +519,10 @@ enum {
* \{ */
void IMB_colormanagement_blackbody_temperature_to_rgb_table(float *r_table,
- const int width,
- const float min,
- const float max);
-void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, const int width);
+ int width,
+ float min,
+ float max);
+void IMB_colormanagement_wavelength_to_rgb_table(float *r_table, int width);
/** \} */
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 16cf0e2125e..1b32bef0a98 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -41,8 +41,7 @@ typedef struct DDSData {
/**
* \ingroup imbuf
- * This is the abstraction of an image. ImBuf is the basic type used for all
- * imbuf operations.
+ * This is the abstraction of an image. ImBuf is the basic type used for all imbuf operations.
*
* Also; add new variables to the end to save pain!
*/
@@ -176,7 +175,7 @@ typedef struct ImBuf {
* avoid problems and use int. - campbell */
int x, y;
- /** Active amount of bits/bitplanes */
+ /** Active amount of bits/bit-planes. */
unsigned char planes;
/** Number of channels in `rect_float` (0 = 4 channel default) */
int channels;
@@ -276,7 +275,7 @@ typedef struct ImBuf {
} ImBuf;
/**
- * \brief userflags: Flags used internally by blender for imagebuffers
+ * \brief userflags: Flags used internally by blender for image-buffers.
*/
enum {
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
index e99572adbb0..0ac1d7bfb74 100644
--- a/source/blender/imbuf/intern/IMB_anim.h
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -109,17 +109,22 @@ struct anim {
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
const AVCodec *pCodec;
- AVFrame *pFrame;
- int pFrameComplete;
AVFrame *pFrameRGB;
AVFrame *pFrameDeinterlaced;
struct SwsContext *img_convert_ctx;
int videoStream;
+ AVFrame *pFrame;
+ bool pFrame_complete;
+ AVFrame *pFrame_backup;
+ bool pFrame_backup_complete;
+
struct ImBuf *cur_frame_final;
int64_t cur_pts;
int64_t cur_key_frame_pts;
AVPacket *cur_packet;
+
+ bool seek_before_decode;
#endif
char index_dir[768];
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 67d1aefeacb..9a0a6998fab 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -42,8 +42,8 @@ typedef struct ImFileType {
* dimensions of the full-size image in r_width & r_height.
*/
struct ImBuf *(*load_filepath_thumbnail)(const char *filepath,
- const int flags,
- const size_t max_thumb_size,
+ int flags,
+ size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
size_t *r_width,
size_t *r_height);
@@ -155,8 +155,8 @@ struct ImBuf *imb_load_jpeg(const unsigned char *buffer,
int flags,
char colorspace[IM_MAX_SPACE]);
struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
- const int flags,
- const size_t max_thumb_size,
+ int flags,
+ size_t max_thumb_size,
char colorspace[IM_MAX_SPACE],
size_t *r_width,
size_t *r_height);
@@ -240,11 +240,10 @@ void imb_loadtiletiff(
/**
* 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.
+ * #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.
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index 0052ce19aa1..52ed68a1ff3 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -675,7 +675,7 @@ static int startffmpeg(struct anim *anim)
anim->orientation = 0;
anim->framesize = anim->x * anim->y * 4;
- anim->cur_position = -1;
+ anim->cur_position = 0;
anim->cur_frame_final = 0;
anim->cur_pts = -1;
anim->cur_key_frame_pts = -1;
@@ -683,7 +683,9 @@ static int startffmpeg(struct anim *anim)
anim->cur_packet->stream_index = -1;
anim->pFrame = av_frame_alloc();
- anim->pFrameComplete = false;
+ anim->pFrame_backup = av_frame_alloc();
+ anim->pFrame_backup_complete = false;
+ anim->pFrame_complete = false;
anim->pFrameDeinterlaced = av_frame_alloc();
anim->pFrameRGB = av_frame_alloc();
anim->pFrameRGB->format = AV_PIX_FMT_RGBA;
@@ -698,6 +700,7 @@ static int startffmpeg(struct anim *anim)
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
av_frame_free(&anim->pFrame);
+ av_frame_free(&anim->pFrame_backup);
anim->pCodecCtx = NULL;
return -1;
}
@@ -710,6 +713,7 @@ static int startffmpeg(struct anim *anim)
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
av_frame_free(&anim->pFrame);
+ av_frame_free(&anim->pFrame_backup);
anim->pCodecCtx = NULL;
return -1;
}
@@ -747,6 +751,7 @@ static int startffmpeg(struct anim *anim)
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
av_frame_free(&anim->pFrame);
+ av_frame_free(&anim->pFrame_backup);
anim->pCodecCtx = NULL;
return -1;
}
@@ -781,22 +786,71 @@ static int startffmpeg(struct anim *anim)
return 0;
}
+static double ffmpeg_steps_per_frame_get(struct anim *anim)
+{
+ AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
+ AVRational time_base = v_st->time_base;
+ AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, NULL);
+ return av_q2d(av_inv_q(av_mul_q(frame_rate, time_base)));
+}
+
+/* Store backup frame.
+ * With VFR movies, if PTS is not matched perfectly, scanning continues to look for next PTS.
+ * It is likely to overshoot and scanning stops. Having previous frame backed up, it is possible
+ * to use it when overshoot happens.
+ */
+static void ffmpeg_double_buffer_backup_frame_store(struct anim *anim, int64_t pts_to_search)
+{
+ /* `anim->pFrame` is beyond `pts_to_search`. Don't store it. */
+ if (anim->pFrame_backup_complete && anim->cur_pts >= pts_to_search) {
+ return;
+ }
+ if (!anim->pFrame_complete) {
+ return;
+ }
+
+ if (anim->pFrame_backup_complete) {
+ av_frame_unref(anim->pFrame_backup);
+ }
+
+ av_frame_move_ref(anim->pFrame_backup, anim->pFrame);
+ anim->pFrame_backup_complete = true;
+}
+
+/* Free stored backup frame. */
+static void ffmpeg_double_buffer_backup_frame_clear(struct anim *anim)
+{
+ if (anim->pFrame_backup_complete) {
+ av_frame_unref(anim->pFrame_backup);
+ }
+ anim->pFrame_backup_complete = false;
+}
+
+/* Return recently decoded frame. If it does not exist, return frame from backup buffer. */
+static AVFrame *ffmpeg_double_buffer_frame_fallback_get(struct anim *anim)
+{
+ av_log(anim->pFormatCtx, AV_LOG_ERROR, "DECODE UNHAPPY: PTS not matched!\n");
+
+ if (anim->pFrame_complete) {
+ return anim->pFrame;
+ }
+ if (anim->pFrame_backup_complete) {
+ return anim->pFrame_backup;
+ }
+ return NULL;
+}
+
/* postprocess the image in anim->pFrame and do color conversion
* and deinterlacing stuff.
*
* Output is anim->cur_frame_final
*/
-static void ffmpeg_postprocess(struct anim *anim)
+static void ffmpeg_postprocess(struct anim *anim, AVFrame *input)
{
- AVFrame *input = anim->pFrame;
ImBuf *ibuf = anim->cur_frame_final;
int filter_y = 0;
- if (!anim->pFrameComplete) {
- return;
- }
-
/* This means the data wasn't read properly,
* this check stops crashing */
if (input->data[0] == 0 && input->data[1] == 0 && input->data[2] == 0 && input->data[3] == 0) {
@@ -808,7 +862,7 @@ static void ffmpeg_postprocess(struct anim *anim)
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
- " POSTPROC: anim->pFrame planes: %p %p %p %p\n",
+ " POSTPROC: AVFrame planes: %p %p %p %p\n",
input->data[0],
input->data[1],
input->data[2],
@@ -852,6 +906,52 @@ static void ffmpeg_postprocess(struct anim *anim)
}
}
+static void final_frame_log(struct anim *anim,
+ int64_t frame_pts_start,
+ int64_t frame_pts_end,
+ const char *str)
+{
+ av_log(anim->pFormatCtx,
+ AV_LOG_INFO,
+ "DECODE HAPPY: %s frame PTS range %" PRId64 " - %" PRId64 ".\n",
+ str,
+ frame_pts_start,
+ frame_pts_end);
+}
+
+static bool ffmpeg_pts_isect(int64_t pts_start, int64_t pts_end, int64_t pts_to_search)
+{
+ return pts_start <= pts_to_search && pts_to_search < pts_end;
+}
+
+/* Return frame that matches `pts_to_search`, NULL if matching frame does not exist. */
+static AVFrame *ffmpeg_frame_by_pts_get(struct anim *anim, int64_t pts_to_search)
+{
+ /* NOTE: `frame->pts + frame->pkt_duration` does not always match pts of next frame.
+ * See footage from T86361. Here it is OK to use, because PTS must match current or backup frame.
+ * If there is no current frame, return NULL.
+ */
+ if (!anim->pFrame_complete) {
+ return NULL;
+ }
+
+ const bool backup_frame_ready = anim->pFrame_backup_complete;
+ const int64_t recent_start = av_get_pts_from_frame(anim->pFrame);
+ const int64_t recent_end = recent_start + anim->pFrame->pkt_duration;
+ const int64_t backup_start = backup_frame_ready ? av_get_pts_from_frame(anim->pFrame_backup) : 0;
+
+ AVFrame *best_frame = NULL;
+ if (ffmpeg_pts_isect(recent_start, recent_end, pts_to_search)) {
+ final_frame_log(anim, recent_start, recent_end, "Recent");
+ best_frame = anim->pFrame;
+ }
+ else if (backup_frame_ready && ffmpeg_pts_isect(backup_start, recent_start, pts_to_search)) {
+ final_frame_log(anim, backup_start, recent_start, "Backup");
+ best_frame = anim->pFrame_backup;
+ }
+ return best_frame;
+}
+
static void ffmpeg_decode_store_frame_pts(struct anim *anim)
{
anim->cur_pts = av_get_pts_from_frame(anim->pFrame);
@@ -863,7 +963,7 @@ static void ffmpeg_decode_store_frame_pts(struct anim *anim)
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,
+ av_get_pts_from_frame(anim->pFrame),
(int64_t)anim->cur_pts);
}
@@ -888,8 +988,8 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
/* 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) {
+ anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
+ if (anim->pFrame_complete) {
av_log(anim->pFormatCtx, AV_LOG_DEBUG, " DECODE FROM CODEC BUFFER\n");
ffmpeg_decode_store_frame_pts(anim);
return 1;
@@ -902,20 +1002,22 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
}
while ((rval = ffmpeg_read_video_frame(anim, anim->cur_packet)) >= 0) {
+ if (anim->cur_packet->stream_index != anim->videoStream) {
+ continue;
+ }
+
av_log(anim->pFormatCtx,
AV_LOG_DEBUG,
- "%sREAD: strID=%d (VID: %d) dts=%" PRId64 " pts=%" PRId64 " %s\n",
- (anim->cur_packet->stream_index == anim->videoStream) ? "->" : " ",
+ "READ: strID=%d dts=%" PRId64 " pts=%" PRId64 " %s\n",
anim->cur_packet->stream_index,
- anim->videoStream,
(anim->cur_packet->dts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->dts,
(anim->cur_packet->pts == AV_NOPTS_VALUE) ? -1 : (int64_t)anim->cur_packet->pts,
(anim->cur_packet->flags & AV_PKT_FLAG_KEY) ? " KEY" : "");
avcodec_send_packet(anim->pCodecCtx, anim->cur_packet);
- anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
+ anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
- if (anim->pFrameComplete) {
+ if (anim->pFrame_complete) {
ffmpeg_decode_store_frame_pts(anim);
break;
}
@@ -926,9 +1028,9 @@ static int ffmpeg_decode_video_frame(struct anim *anim)
if (rval == AVERROR_EOF) {
/* Flush any remaining frames out of the decoder. */
avcodec_send_packet(anim->pCodecCtx, NULL);
- anim->pFrameComplete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
+ anim->pFrame_complete = avcodec_receive_frame(anim->pCodecCtx, anim->pFrame) == 0;
- if (anim->pFrameComplete) {
+ if (anim->pFrame_complete) {
ffmpeg_decode_store_frame_pts(anim);
rval = 0;
}
@@ -990,15 +1092,6 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
return false;
}
-static double ffmpeg_steps_per_frame_get(struct anim *anim)
-{
- AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
- AVRational time_base = v_st->time_base;
- AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, NULL);
- return av_q2d(av_inv_q(av_mul_q(frame_rate, time_base)));
- ;
-}
-
static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search)
{
/* Step back half a frame position to make sure that we get the requested
@@ -1035,75 +1128,41 @@ static int64_t ffmpeg_get_pts_to_search(struct anim *anim,
return pts_to_search;
}
-/* Check if the pts will get us the same frame that we already have in memory from last decode. */
-static bool ffmpeg_pts_matches_last_frame(struct anim *anim, int64_t pts_to_search)
+static bool ffmpeg_is_first_frame_decode(struct anim *anim)
{
- if (anim->pFrame && anim->cur_frame_final) {
- int64_t diff = pts_to_search - anim->cur_pts;
- return diff >= 0 && diff < anim->pFrame->pkt_duration;
- }
-
- return false;
+ return anim->pFrame_complete == false;
}
-static bool ffmpeg_is_first_frame_decode(struct anim *anim, int position)
+static void ffmpeg_scan_log(struct anim *anim, int64_t pts_to_search)
{
- return position == 0 && anim->cur_position == -1;
+ int64_t frame_pts_start = av_get_pts_from_frame(anim->pFrame);
+ int64_t frame_pts_end = frame_pts_start + anim->pFrame->pkt_duration;
+ av_log(anim->pFormatCtx,
+ AV_LOG_DEBUG,
+ " SCAN WHILE: PTS range %" PRId64 " - %" PRId64 " in search of %" PRId64 "\n",
+ frame_pts_start,
+ frame_pts_end,
+ pts_to_search);
}
/* Decode frames one by one until its PTS matches pts_to_search. */
static void ffmpeg_decode_video_frame_scan(struct anim *anim, int64_t pts_to_search)
{
- av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: within current GOP\n");
-
- av_log(anim->pFormatCtx,
- AV_LOG_DEBUG,
- "SCAN start: considering pts=%" PRId64 " in search of %" PRId64 "\n",
- (int64_t)anim->cur_pts,
- (int64_t)pts_to_search);
-
- int64_t start_gop_frame = anim->cur_key_frame_pts;
- bool scan_fuzzy = false;
-
- while (anim->cur_pts < pts_to_search) {
- av_log(anim->pFormatCtx,
- AV_LOG_DEBUG,
- " WHILE: pts=%" PRId64 " in search of %" PRId64 "\n",
- (int64_t)anim->cur_pts,
- (int64_t)pts_to_search);
- if (!ffmpeg_decode_video_frame(anim)) {
- break;
+ const int64_t start_gop_frame = anim->cur_key_frame_pts;
+ bool decode_error = false;
+
+ while (!decode_error && anim->cur_pts < pts_to_search) {
+ ffmpeg_scan_log(anim, pts_to_search);
+ ffmpeg_double_buffer_backup_frame_store(anim, pts_to_search);
+ decode_error = ffmpeg_decode_video_frame(anim) < 1;
+
+ /* We should not get a new GOP keyframe while scanning if seeking is working as intended.
+ * If this condition triggers, there may be and error in our seeking code.
+ * NOTE: This seems to happen if DTS value is used for seeking in ffmpeg internally. There
+ * seems to be no good way to handle such case. */
+ if (anim->seek_before_decode && start_gop_frame != anim->cur_key_frame_pts) {
+ av_log(anim->pFormatCtx, AV_LOG_ERROR, "SCAN: Frame belongs to an unexpected GOP!\n");
}
-
- if (start_gop_frame != anim->cur_key_frame_pts) {
- break;
- }
-
- if (anim->cur_pts < pts_to_search &&
- anim->cur_pts + anim->pFrame->pkt_duration > pts_to_search) {
- /* Our estimate of the pts was a bit off, but we have the frame we want. */
- av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN fuzzy frame match\n");
- scan_fuzzy = true;
- break;
- }
- }
-
- if (start_gop_frame != anim->cur_key_frame_pts) {
- /* We went into an other GOP frame. This should never happen as we should have positioned us
- * correctly by seeking into the GOP frame that contains the frame we want. */
- av_log(anim->pFormatCtx,
- AV_LOG_ERROR,
- "SCAN failed: completely lost in stream, "
- "bailing out at PTS=%" PRId64 ", searching for PTS=%" PRId64 "\n",
- (int64_t)anim->cur_pts,
- (int64_t)pts_to_search);
- }
-
- if (scan_fuzzy || anim->cur_pts == pts_to_search) {
- av_log(anim->pFormatCtx, AV_LOG_DEBUG, "SCAN HAPPY: we found our PTS!\n");
- }
- else {
- av_log(anim->pFormatCtx, AV_LOG_ERROR, "SCAN UNHAPPY: PTS not matched!\n");
}
}
@@ -1299,6 +1358,7 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim,
/* Flush the internal buffers of ffmpeg. This needs to be done after seeking to avoid decoding
* errors. */
avcodec_flush_buffers(anim->pCodecCtx);
+ ffmpeg_double_buffer_backup_frame_clear(anim);
anim->cur_pts = -1;
@@ -1310,6 +1370,13 @@ static int ffmpeg_seek_to_key_frame(struct anim *anim,
return ret;
}
+static bool ffmpeg_must_seek(struct anim *anim, int position)
+{
+ bool must_seek = position != anim->cur_position + 1 || ffmpeg_is_first_frame_decode(anim);
+ anim->seek_before_decode = must_seek;
+ return must_seek;
+}
+
static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Type tc)
{
if (anim == NULL) {
@@ -1334,23 +1401,11 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
frame_rate,
start_pts);
- if (ffmpeg_pts_matches_last_frame(anim, pts_to_search)) {
- av_log(anim->pFormatCtx,
- AV_LOG_DEBUG,
- "FETCH: frame repeat: pts: %" PRId64 "\n",
- (int64_t)anim->cur_pts);
- IMB_refImBuf(anim->cur_frame_final);
- anim->cur_position = position;
- return anim->cur_frame_final;
+ if (ffmpeg_must_seek(anim, position)) {
+ ffmpeg_seek_to_key_frame(anim, position, tc_index, pts_to_search);
}
- if (position == anim->cur_position + 1 || ffmpeg_is_first_frame_decode(anim, position)) {
- av_log(anim->pFormatCtx, AV_LOG_DEBUG, "FETCH: no seek necessary, just continue...\n");
- ffmpeg_decode_video_frame(anim);
- }
- else if (ffmpeg_seek_to_key_frame(anim, position, tc_index, pts_to_search) >= 0) {
- ffmpeg_decode_video_frame_scan(anim, pts_to_search);
- }
+ ffmpeg_decode_video_frame_scan(anim, pts_to_search);
IMB_freeImBuf(anim->cur_frame_final);
@@ -1387,7 +1442,18 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ
anim->cur_frame_final->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace);
- ffmpeg_postprocess(anim);
+ AVFrame *final_frame = ffmpeg_frame_by_pts_get(anim, pts_to_search);
+ if (final_frame == NULL) {
+ /* No valid frame was decoded for requested PTS, fall back on most recent decoded frame, even
+ * if it is incorrect. */
+ final_frame = ffmpeg_double_buffer_frame_fallback_get(anim);
+ }
+
+ /* Even with the fallback from above it is possible that the current decode frame is NULL. In
+ * this case skip post-processing and return current image buffer. */
+ if (final_frame != NULL) {
+ ffmpeg_postprocess(anim, final_frame);
+ }
anim->cur_position = position;
@@ -1408,6 +1474,7 @@ static void free_anim_ffmpeg(struct anim *anim)
av_packet_free(&anim->cur_packet);
av_frame_free(&anim->pFrame);
+ av_frame_free(&anim->pFrame_backup);
av_frame_free(&anim->pFrameRGB);
av_frame_free(&anim->pFrameDeinterlaced);
diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c
index 6448d6cd76a..1a99d2a34d9 100644
--- a/source/blender/imbuf/intern/cineon/cineon_dpx.c
+++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c
@@ -121,8 +121,8 @@ static int imb_save_dpx_cineon(ImBuf *ibuf, const char *filepath, int use_cineon
}
if (ibuf->rect_float != NULL && bitspersample != 8) {
- /* don't use the float buffer to save 8 bpp picture to prevent color banding
- * (there's no dithering algorithm behind the logImageSetDataRGBA function) */
+ /* Don't use the float buffer to save 8 BPP picture to prevent color banding
+ * (there's no dithering algorithm behind the #logImageSetDataRGBA function). */
fbuf = (float *)MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y,
"fbuf in imb_save_dpx_cineon");
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index d4c9e78a299..b62bdd5521d 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -597,7 +597,7 @@ static void colormanage_free_config(void)
while (colorspace) {
ColorSpace *colorspace_next = colorspace->next;
- /* free precomputer processors */
+ /* Free precomputed processors. */
if (colorspace->to_scene_linear) {
OCIO_cpuProcessorRelease((OCIO_ConstCPUProcessorRcPtr *)colorspace->to_scene_linear);
}
@@ -673,7 +673,7 @@ void colormanagement_init(void)
#ifdef WIN32
{
- /* quite a hack to support loading configuration from path with non-acii symbols */
+ /* Quite a hack to support loading configuration from path with non-ACII symbols. */
char short_name[256];
BLI_get_short_name(short_name, configfile);
@@ -2211,21 +2211,15 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
const int width,
const int height,
const struct ImBuf *ibuf,
- const bool compress_as_srgb,
const bool store_premultiplied)
{
- /* Convert byte buffer for texture storage on the GPU. These have builtin
- * support for converting sRGB to linear, which allows us to store textures
- * without precision or performance loss at minimal memory usage. */
+ /* Byte buffer storage, only for sRGB, scene linear and data texture since other
+ * color space conversions can't be done on the GPU. */
BLI_assert(ibuf->rect && ibuf->rect_float == NULL);
+ BLI_assert(IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_data(ibuf->rect_colorspace));
- OCIO_ConstCPUProcessorRcPtr *processor = NULL;
- if (compress_as_srgb && ibuf->rect_colorspace &&
- !IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
- processor = colorspace_to_scene_linear_cpu_processor(ibuf->rect_colorspace);
- }
-
- /* TODO(brecht): make this multi-threaded, or at least process in batches. */
const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
@@ -2235,20 +2229,7 @@ void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer,
const unsigned char *in = in_buffer + in_offset * 4;
unsigned char *out = out_buffer + out_offset * 4;
- if (processor != NULL) {
- /* Convert to scene linear, to sRGB and premultiply. */
- for (int x = 0; x < width; x++, in += 4, out += 4) {
- float pixel[4];
- rgba_uchar_to_float(pixel, in);
- OCIO_cpuProcessorApplyRGB(processor, pixel);
- linearrgb_to_srgb_v3_v3(pixel, pixel);
- if (use_premultiply) {
- mul_v3_fl(pixel, pixel[3]);
- }
- rgba_float_to_uchar(out, pixel);
- }
- }
- else if (use_premultiply) {
+ if (use_premultiply) {
/* Premultiply only. */
for (int x = 0; x < width; x++, in += 4, out += 4) {
out[0] = (in[0] * in[3]) >> 8;
@@ -2279,43 +2260,80 @@ void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer,
{
/* Float texture are stored in scene linear color space, with premultiplied
* alpha depending on the image alpha mode. */
- const float *in_buffer = ibuf->rect_float;
- const int in_channels = ibuf->channels;
- const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
-
- for (int y = 0; y < height; y++) {
- const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
- const size_t out_offset = y * width;
- const float *in = in_buffer + in_offset * in_channels;
- float *out = out_buffer + out_offset * 4;
-
- if (in_channels == 1) {
- /* Copy single channel. */
- for (int x = 0; x < width; x++, in += 1, out += 4) {
- out[0] = in[0];
- out[1] = in[0];
- out[2] = in[0];
- out[3] = in[0];
+ if (ibuf->rect_float) {
+ /* Float source buffer. */
+ const float *in_buffer = ibuf->rect_float;
+ const int in_channels = ibuf->channels;
+ const bool use_unpremultiply = IMB_alpha_affects_rgb(ibuf) && !store_premultiplied;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const float *in = in_buffer + in_offset * in_channels;
+ float *out = out_buffer + out_offset * 4;
+
+ if (in_channels == 1) {
+ /* Copy single channel. */
+ for (int x = 0; x < width; x++, in += 1, out += 4) {
+ out[0] = in[0];
+ out[1] = in[0];
+ out[2] = in[0];
+ out[3] = in[0];
+ }
}
- }
- else if (in_channels == 3) {
- /* Copy RGB. */
- for (int x = 0; x < width; x++, in += 3, out += 4) {
- out[0] = in[0];
- out[1] = in[1];
- out[2] = in[2];
- out[3] = 1.0f;
+ else if (in_channels == 3) {
+ /* Copy RGB. */
+ for (int x = 0; x < width; x++, in += 3, out += 4) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = 1.0f;
+ }
}
- }
- else if (in_channels == 4) {
- /* Copy or convert RGBA. */
- if (use_unpremultiply) {
- for (int x = 0; x < width; x++, in += 4, out += 4) {
- premul_to_straight_v4_v4(out, in);
+ else if (in_channels == 4) {
+ /* Copy or convert RGBA. */
+ if (use_unpremultiply) {
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ premul_to_straight_v4_v4(out, in);
+ }
+ }
+ else {
+ memcpy(out, in, sizeof(float[4]) * width);
}
}
- else {
- memcpy(out, in, sizeof(float[4]) * width);
+ }
+ }
+ else {
+ /* Byte source buffer. */
+ const unsigned char *in_buffer = (unsigned char *)ibuf->rect;
+ const bool use_premultiply = IMB_alpha_affects_rgb(ibuf) && store_premultiplied;
+
+ /* TODO(brecht): make this multi-threaded, or at least process in batches. */
+ OCIO_ConstCPUProcessorRcPtr *processor = (ibuf->rect_colorspace) ?
+ colorspace_to_scene_linear_cpu_processor(
+ ibuf->rect_colorspace) :
+ NULL;
+
+ for (int y = 0; y < height; y++) {
+ const size_t in_offset = (offset_y + y) * ibuf->x + offset_x;
+ const size_t out_offset = y * width;
+ const unsigned char *in = in_buffer + in_offset * 4;
+ float *out = out_buffer + out_offset * 4;
+
+ /* Convert to scene linear, to sRGB and premultiply. */
+ for (int x = 0; x < width; x++, in += 4, out += 4) {
+ float pixel[4];
+ rgba_uchar_to_float(pixel, in);
+ if (processor) {
+ OCIO_cpuProcessorApplyRGB(processor, pixel);
+ }
+ else {
+ srgb_to_linearrgb_v3_v3(pixel, pixel);
+ }
+ if (use_premultiply) {
+ mul_v3_fl(pixel, pixel[3]);
+ }
+ copy_v4_v4(out, pixel);
}
}
}
@@ -2464,22 +2482,21 @@ static ImBuf *imbuf_ensure_editable(ImBuf *ibuf, ImBuf *colormanaged_ibuf, bool
IMB_metadata_copy(colormanaged_ibuf, ibuf);
return colormanaged_ibuf;
}
- else {
- /* Render pipeline is constructing image buffer itself,
- * but it's re-using byte and float buffers from render result make copy of this buffers
- * here sine this buffers would be transformed to other color space here. */
- if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
- ibuf->rect = MEM_dupallocN(ibuf->rect);
- ibuf->mall |= IB_rect;
- }
- if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
- ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
- ibuf->mall |= IB_rectfloat;
- }
+ /* Render pipeline is constructing image buffer itself,
+ * but it's re-using byte and float buffers from render result make copy of this buffers
+ * here sine this buffers would be transformed to other color space here. */
+ if (ibuf->rect && (ibuf->mall & IB_rect) == 0) {
+ ibuf->rect = MEM_dupallocN(ibuf->rect);
+ ibuf->mall |= IB_rect;
+ }
- return ibuf;
+ if (ibuf->rect_float && (ibuf->mall & IB_rectfloat) == 0) {
+ ibuf->rect_float = MEM_dupallocN(ibuf->rect_float);
+ ibuf->mall |= IB_rectfloat;
}
+
+ return ibuf;
}
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
@@ -3158,6 +3175,11 @@ const char *IMB_colormanagement_colorspace_get_indexed_name(int index)
return "";
}
+const char *IMB_colormanagement_colorspace_get_name(const ColorSpace *colorspace)
+{
+ return colorspace->name;
+}
+
void IMB_colormanagement_colorspace_from_ibuf_ftype(
ColorManagedColorspaceSettings *colorspace_settings, ImBuf *ibuf)
{
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 588c92d748d..13c8f0887b3 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -695,9 +695,6 @@ void IMB_buffer_byte_from_byte(uchar *rect_to,
void IMB_rect_from_float(ImBuf *ibuf)
{
- float *buffer;
- const char *from_colorspace;
-
/* verify we have a float buffer */
if (ibuf->rect_float == NULL) {
return;
@@ -710,24 +707,21 @@ void IMB_rect_from_float(ImBuf *ibuf)
}
}
- if (ibuf->float_colorspace == NULL) {
- from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR);
- }
- else {
- from_colorspace = ibuf->float_colorspace->name;
- }
+ const char *from_colorspace = (ibuf->float_colorspace == NULL) ?
+ IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR) :
+ ibuf->float_colorspace->name;
+ const char *to_colorspace = (ibuf->rect_colorspace == NULL) ?
+ IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_DEFAULT_BYTE) :
+ ibuf->rect_colorspace->name;
- buffer = MEM_dupallocN(ibuf->rect_float);
+ float *buffer = MEM_dupallocN(ibuf->rect_float);
/* first make float buffer in byte space */
const bool predivide = IMB_alpha_affects_rgb(ibuf);
- IMB_colormanagement_transform(buffer,
- ibuf->x,
- ibuf->y,
- ibuf->channels,
- from_colorspace,
- ibuf->rect_colorspace->name,
- predivide);
+ IMB_colormanagement_transform(
+ buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, predivide);
/* convert from float's premul alpha to byte's straight alpha */
if (IMB_alpha_affects_rgb(ibuf)) {
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index ec25b67af5f..13bf3697946 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -22,7 +22,6 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-#include <math.h>
void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
{
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index cbc5d984755..00396c01d99 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -1098,6 +1098,7 @@ static int indexer_performance_get_decode_rate(FFmpegIndexBuilderContext *contex
while (av_read_frame(context->iFormatCtx, packet) >= 0) {
if (packet->stream_index != context->videoStream) {
+ av_packet_unref(packet);
continue;
}
@@ -1121,6 +1122,7 @@ static int indexer_performance_get_decode_rate(FFmpegIndexBuilderContext *contex
if (end > start + time_period) {
break;
}
+ av_packet_unref(packet);
}
av_packet_free(&packet);
@@ -1145,6 +1147,7 @@ static int indexer_performance_get_max_gop_size(FFmpegIndexBuilderContext *conte
while (av_read_frame(context->iFormatCtx, packet) >= 0) {
if (packet->stream_index != context->videoStream) {
+ av_packet_unref(packet);
continue;
}
packet_index++;
@@ -1158,6 +1161,7 @@ static int indexer_performance_get_max_gop_size(FFmpegIndexBuilderContext *conte
if (packet_index > packets_max) {
break;
}
+ av_packet_unref(packet);
}
av_packet_free(&packet);
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index cffa61977f7..06f9202a1c6 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -524,8 +524,8 @@ struct ImBuf *imb_thumbnail_jpeg(const char *filepath,
unsigned int i = JPEG_APP1_MAX;
/* All EXIF data is within this 64K header segment. Skip ahead until next SOI for thumbnail. */
while (!((fgetc(infile) == JPEG_MARKER_MSB) && (fgetc(infile) == JPEG_MARKER_SOI)) &&
- !feof(infile) && i--)
- ;
+ !feof(infile) && i--) {
+ }
if (i > 0 && !feof(infile)) {
/* We found a JPEG thumbnail inside this image. */
ImBuf *ibuf = NULL;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 54ef5438c23..0414fa1268d 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -174,14 +174,14 @@ class IMMapStream : public Imf::IStream {
imb_mmap_lock();
_mmap_file = BLI_mmap_open(file);
imb_mmap_unlock();
- if (_mmap_file == NULL) {
+ if (_mmap_file == nullptr) {
throw IEX_NAMESPACE::InputExc("BLI_mmap_open failed");
}
close(file);
_exrbuf = (unsigned char *)BLI_mmap_get_pointer(_mmap_file);
}
- ~IMMapStream()
+ ~IMMapStream() override
{
imb_mmap_lock();
BLI_mmap_free(_mmap_file);
@@ -512,7 +512,7 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
/* we store first everything in half array */
std::vector<RGBAZ> pixels(height * width);
- RGBAZ *to = &pixels[0];
+ RGBAZ *to = pixels.data();
int xstride = sizeof(RGBAZ);
int ystride = xstride * width;
@@ -1010,7 +1010,7 @@ void IMB_exrtile_begin_write(
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
data->ofile_stream = new OFileStream(filepath);
- data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
+ data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size());
}
catch (const std::exception &) {
delete data->mpofile;
@@ -2209,7 +2209,7 @@ struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
if (file->header().hasPreviewImage()) {
const Imf::PreviewImage &preview = file->header().previewImage();
ImBuf *ibuf = IMB_allocFromBuffer(
- (unsigned int *)preview.pixels(), NULL, preview.width(), preview.height(), 4);
+ (unsigned int *)preview.pixels(), nullptr, preview.width(), preview.height(), 4);
delete file;
delete stream;
IMB_flipy(ibuf);
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index a62c87428b6..40a724c9f42 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -27,8 +27,8 @@ bool imb_save_openexr(struct ImBuf *ibuf, const char *name, int flags);
struct ImBuf *imb_load_openexr(const unsigned char *mem, size_t size, int flags, char *colorspace);
struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
- const int flags,
- const size_t max_thumb_size,
+ int flags,
+ size_t max_thumb_size,
char colorspace[],
size_t *r_width,
size_t *r_height);
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index 52756891f21..2a0baaf6172 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -702,21 +702,21 @@ int *IMB_stereo3d_from_rect(const ImageFormatData *im_format,
int *rect_left,
int *rect_right)
{
- int *r_rect;
+ int *rect_result;
Stereo3DData s3d_data = {{NULL}};
size_t width, height;
const bool is_float = im_format->depth > 8;
IMB_stereo3d_write_dimensions(
im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
- r_rect = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
+ rect_result = MEM_mallocN(channels * sizeof(int) * width * height, __func__);
imb_stereo3d_data_init(
- &s3d_data, is_float, x, y, channels, rect_left, rect_right, r_rect, NULL, NULL, NULL);
+ &s3d_data, is_float, x, y, channels, rect_left, rect_right, rect_result, NULL, NULL, NULL);
imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
- imb_stereo3d_squeeze_rect(r_rect, &im_format->stereo3d_format, x, y, channels);
+ imb_stereo3d_squeeze_rect(rect_result, &im_format->stereo3d_format, x, y, channels);
- return r_rect;
+ return rect_result;
}
float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
@@ -726,21 +726,30 @@ float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
float *rectf_left,
float *rectf_right)
{
- float *r_rectf;
+ float *rectf_result;
Stereo3DData s3d_data = {{NULL}};
size_t width, height;
const bool is_float = im_format->depth > 8;
IMB_stereo3d_write_dimensions(
im_format->stereo3d_format.display_mode, false, x, y, &width, &height);
- r_rectf = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
+ rectf_result = MEM_mallocN(channels * sizeof(float) * width * height, __func__);
- imb_stereo3d_data_init(
- &s3d_data, is_float, x, y, channels, NULL, NULL, NULL, rectf_left, rectf_right, r_rectf);
+ imb_stereo3d_data_init(&s3d_data,
+ is_float,
+ x,
+ y,
+ channels,
+ NULL,
+ NULL,
+ NULL,
+ rectf_left,
+ rectf_right,
+ rectf_result);
imb_stereo3d_write_doit(&s3d_data, &im_format->stereo3d_format);
- imb_stereo3d_squeeze_rectf(r_rectf, &im_format->stereo3d_format, x, y, channels);
+ imb_stereo3d_squeeze_rectf(rectf_result, &im_format->stereo3d_format, x, y, channels);
- return r_rectf;
+ return rectf_result;
}
ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index f2c9c82fa66..6f39009d38d 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -30,7 +30,6 @@
#include "IMB_thumbs.h"
#include <ctype.h>
-#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -514,7 +513,7 @@ void IMB_thumb_delete(const char *filepath, ThumbSize size)
}
}
-ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source)
+ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source)
{
char thumb_path[FILE_MAX];
char thumb_name[40];
@@ -526,7 +525,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source
ImBuf *img = NULL;
char *blen_group = NULL, *blen_id = NULL;
- path = file_path = org_path;
+ path = file_path = filepath;
if (source == THB_SOURCE_BLEND) {
if (BLO_library_path_explode(path, path_buff, &blen_group, &blen_id)) {
if (blen_group) {
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index 1372aa31713..2f13ef409e3 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -8,15 +8,15 @@
* Provides TIFF file loading and saving for Blender, via libtiff.
*
* The task of loading is complicated somewhat by the fact that Blender has
- * already loaded the file into a memory buffer. libtiff is not well
+ * already loaded the file into a memory buffer. libtiff is not well
* configured to handle files in memory, so a client wrapper is written to
- * surround the memory and turn it into a virtual file. Currently, reading
- * of TIFF files is done using libtiff's RGBAImage support. This is a
+ * surround the memory and turn it into a virtual file. Currently, reading
+ * of TIFF files is done using libtiff's RGBAImage support. This is a
* 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 (gray-scale) images correctly, with
- * 8 bits per channel in all cases. The "deflate" compression algorithm is
+ * 8 bits per channel in all cases. The "deflate" compression algorithm is
* used to compress images.
*/
@@ -151,8 +151,8 @@ static tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n)
/**
* Writes data to an in-memory TIFF file.
*
- * NOTE: The current Blender implementation should not need this function. It
- * is simply a stub.
+ * NOTE: The current Blender implementation should not need this function.
+ * It is simply a stub.
*/
static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
{
@@ -176,7 +176,7 @@ static tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
* error).
*
* \return Resulting offset location within the file, measured in bytes from
- * the beginning of the file. (-1) indicates an error.
+ * the beginning of the file. (-1) indicates an error.
*/
static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
{
@@ -215,8 +215,8 @@ static toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
* Closes (virtually) an in-memory TIFF file.
*
* NOTE: All this function actually does is sets the data pointer within the
- * TIFF file to NULL. That should trigger assertion errors if attempts
- * are made to access the file after that point. However, no such
+ * TIFF file to NULL. That should trigger assertion errors if attempts
+ * are made to access the file after that point. However, no such
* attempts should ever be made (in theory).
*
* \param handle: Handle of the TIFF file (pointer to #ImbTIFFMemFile).
@@ -734,7 +734,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
int x, y, from_i, to_i, i;
int compress_mode = COMPRESSION_NONE;
- /* check for a valid number of bytes per pixel. Like the PNG writer,
+ /* check for a valid number of bytes per pixel. Like the PNG writer,
* the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
* to gray, RGB, RGBA respectively. */
samplesperpixel = (uint16_t)((ibuf->planes + 7) >> 3);
@@ -838,7 +838,7 @@ bool imb_savetiff(ImBuf *ibuf, const char *filepath, int flags)
TIFFSetField(image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
}
- /* copy pixel data. While copying, we flip the image vertically. */
+ /* copy pixel data. While copying, we flip the image vertically. */
const int channels_in_float = ibuf->channels ? ibuf->channels : 4;
for (x = 0; x < ibuf->x; x++) {
for (y = 0; y < ibuf->y; y++) {
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index edb47c8c7ce..1499c1071e3 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -293,30 +293,37 @@ class Sampler {
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);
+ bilinear_interpolation_color_fl(source, nullptr, r_sample.data(), 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);
+ nearest_interpolation_color_char(source, r_sample.data(), 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);
+ bilinear_interpolation_color_char(source, r_sample.data(), 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);
+ BLI_bilinear_interpolation_wrap_fl(source->rect_float,
+ r_sample.data(),
+ 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],
+ r_sample.data(),
source->x,
source->y,
NumChannels,
@@ -390,11 +397,11 @@ class ChannelConverter {
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]);
+ copy_v4_v4_uchar(pixel_pointer.get_pointer(), sample.data());
}
else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 4 &&
DestinationNumChannels == 4) {
- copy_v4_v4(pixel_pointer.get_pointer(), &sample[0]);
+ copy_v4_v4(pixel_pointer.get_pointer(), sample.data());
}
else if constexpr (std::is_same_v<StorageType, float> && SourceNumChannels == 3 &&
DestinationNumChannels == 4) {
diff --git a/source/blender/imbuf/intern/util_gpu.c b/source/blender/imbuf/intern/util_gpu.c
index 8e004938a89..5feb0ceb515 100644
--- a/source/blender/imbuf/intern/util_gpu.c
+++ b/source/blender/imbuf/intern/util_gpu.c
@@ -28,17 +28,30 @@ static void imb_gpu_get_format(const ImBuf *ibuf,
eGPUTextureFormat *r_texture_format)
{
const bool float_rect = (ibuf->rect_float != NULL);
- const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
- !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
- high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
-
- *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
if (float_rect) {
- *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
+ /* Float. */
+ const bool use_high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
+ *r_data_format = GPU_DATA_FLOAT;
+ *r_texture_format = use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
}
else {
- *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* Non-color data or scene linear, just store buffer as is. */
+ *r_data_format = GPU_DATA_UBYTE;
+ *r_texture_format = GPU_RGBA8;
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace)) {
+ /* sRGB, store as byte texture that the GPU can decode directly. */
+ *r_data_format = GPU_DATA_UBYTE;
+ *r_texture_format = GPU_SRGB8_A8;
+ }
+ else {
+ /* Other colorspace, store as half float texture to avoid precision loss. */
+ *r_data_format = GPU_DATA_FLOAT;
+ *r_texture_format = GPU_RGBA16F;
+ }
}
}
@@ -74,7 +87,6 @@ static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *
static void *imb_gpu_get_data(const ImBuf *ibuf,
const bool do_rescale,
const int rescale_size[2],
- const bool compress_as_srgb,
const bool store_premultiplied,
bool *r_freedata)
{
@@ -99,14 +111,16 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
}
}
else {
- /* Byte image is in original colorspace from the file. If the file is sRGB
- * scene linear, or non-color data no conversion is needed. Otherwise we
- * compress as scene linear + sRGB transfer function to avoid precision loss
- * in common cases.
+ /* Byte image is in original colorspace from the file, and may need conversion.
*
* We must also convert to premultiplied for correct texture interpolation
* and consistency with float images. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ if (IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ /* Non-color data, just store buffer as is. */
+ }
+ else if (IMB_colormanagement_space_is_srgb(ibuf->rect_colorspace) ||
+ IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace)) {
+ /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */
data_rect = MEM_mallocN(sizeof(uchar[4]) * ibuf->x * ibuf->y, __func__);
*r_freedata = freedata = true;
@@ -120,7 +134,24 @@ static void *imb_gpu_get_data(const ImBuf *ibuf,
* zero alpha areas, and appears generally closer to what game engines that we
* want to be compatible with do. */
IMB_colormanagement_imbuf_to_byte_texture(
- (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
+ (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
+ }
+ else {
+ /* Other colorspace, store as float texture to avoid precision loss. */
+ data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
+ *r_freedata = freedata = true;
+
+ if (data_rect == NULL) {
+ return NULL;
+ }
+
+ /* Texture storage of images is defined by the alpha mode of the image. The
+ * downside of this is that there can be artifacts near alpha edges. However,
+ * this allows us to use sRGB texture formats and preserves color values in
+ * zero alpha areas, and appears generally closer to what game engines that we
+ * want to be compatible with do. */
+ IMB_colormanagement_imbuf_to_float_texture(
+ (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
}
}
@@ -181,10 +212,9 @@ void IMB_update_gpu_texture_sub(GPUTexture *tex,
eGPUTextureFormat tex_format;
imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
- const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
bool freebuf = false;
- void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
/* Update Texture. */
GPU_texture_update_sub(tex, data_format, data, x, y, z, w, h, 1);
@@ -238,7 +268,6 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
eGPUTextureFormat tex_format;
imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
- const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
bool freebuf = false;
/* Create Texture. */
@@ -250,7 +279,7 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
do_rescale = true;
}
BLI_assert(tex != NULL);
- void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
+ void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
GPU_texture_update(tex, data_format, data);
GPU_texture_anisotropic_filter(tex, true);
diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt
index b5f2694c2da..8b20b50a181 100644
--- a/source/blender/io/CMakeLists.txt
+++ b/source/blender/io/CMakeLists.txt
@@ -1,8 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2020 Blender Foundation. All rights reserved.
-add_subdirectory(common)
-add_subdirectory(wavefront_obj)
+if(WITH_IO_WAVEFRONT_OBJ OR WITH_IO_STL OR WITH_IO_GPENCIL OR WITH_ALEMBIC OR WITH_USD)
+ add_subdirectory(common)
+endif()
+
+if(WITH_IO_WAVEFRONT_OBJ)
+ add_subdirectory(wavefront_obj)
+endif()
+
+if(WITH_IO_STL)
+ add_subdirectory(stl)
+endif()
+
+if(WITH_IO_GPENCIL)
+ add_subdirectory(gpencil)
+endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
@@ -19,5 +32,3 @@ endif()
if(WITH_USD)
add_subdirectory(usd)
endif()
-
-add_subdirectory(gpencil)
diff --git a/source/blender/io/alembic/exporter/abc_custom_props.cc b/source/blender/io/alembic/exporter/abc_custom_props.cc
index 23a39ca2ee6..c5cc4631e18 100644
--- a/source/blender/io/alembic/exporter/abc_custom_props.cc
+++ b/source/blender/io/alembic/exporter/abc_custom_props.cc
@@ -150,7 +150,7 @@ void CustomPropertiesExporter::write_idparray_of_strings(const IDProperty *idp_a
}
/* Alembic needs a pointer to the first value of the array. */
- const std::string *array_of_strings = &strings[0];
+ const std::string *array_of_strings = strings.data();
set_array_property<OStringArrayProperty, std::string>(
idp_array->name, array_of_strings, strings.size());
}
@@ -204,7 +204,7 @@ void CustomPropertiesExporter::write_idparray_flattened_typed(const IDProperty *
}
set_array_property<ABCPropertyType, BlenderValueType>(
- idp_array->name, &matrix_values[0], matrix_values.size());
+ idp_array->name, matrix_values.data(), matrix_values.size());
}
template<typename ABCPropertyType, typename BlenderValueType>
diff --git a/source/blender/io/alembic/exporter/abc_export_capi.cc b/source/blender/io/alembic/exporter/abc_export_capi.cc
index edaf53b3efa..dfca89e2c6d 100644
--- a/source/blender/io/alembic/exporter/abc_export_capi.cc
+++ b/source/blender/io/alembic/exporter/abc_export_capi.cc
@@ -24,6 +24,7 @@
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_timeit.hh"
#include "WM_api.h"
#include "WM_types.h"
@@ -44,6 +45,7 @@ struct ExportJobData {
bool was_canceled;
bool export_ok;
+ blender::timeit::TimePoint start_time;
};
namespace blender::io::alembic {
@@ -59,6 +61,14 @@ static void build_depsgraph(Depsgraph *depsgraph, const bool visible_objects_onl
}
}
+static void report_job_duration(const ExportJobData *data)
+{
+ blender::timeit::Nanoseconds duration = blender::timeit::Clock::now() - data->start_time;
+ std::cout << "Alembic export of '" << data->filename << "' took ";
+ blender::timeit::print_duration(duration);
+ std::cout << '\n';
+}
+
static void export_startjob(void *customdata,
/* Cannot be const, this function implements wm_jobs_start_callback.
* NOLINTNEXTLINE: readability-non-const-parameter. */
@@ -68,6 +78,7 @@ static void export_startjob(void *customdata,
{
ExportJobData *data = static_cast<ExportJobData *>(customdata);
data->was_canceled = false;
+ data->start_time = blender::timeit::Clock::now();
G.is_rendering = true;
WM_set_locked_interface(data->wm, true);
@@ -85,7 +96,7 @@ static void export_startjob(void *customdata,
/* For restoring the current frame after exporting animation is done. */
Scene *scene = DEG_get_input_scene(data->depsgraph);
- const int orig_frame = CFRA;
+ const int orig_frame = scene->r.cfra;
const bool export_animation = (data->params.frame_start != data->params.frame_end);
/* Create the Alembic archive. */
@@ -154,8 +165,8 @@ static void export_startjob(void *customdata,
iter.release_writers();
/* Finish up by going back to the keyframe that was current before we started. */
- if (CFRA != orig_frame) {
- CFRA = orig_frame;
+ if (scene->r.cfra != orig_frame) {
+ scene->r.cfra = orig_frame;
BKE_scene_graph_update_for_newframe(data->depsgraph);
}
@@ -177,6 +188,7 @@ static void export_endjob(void *customdata)
G.is_rendering = false;
WM_set_locked_interface(data->wm, false);
+ report_job_duration(data);
}
} // namespace blender::io::alembic
diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc
index d12eaf07e29..99c609b0235 100644
--- a/source/blender/io/alembic/exporter/abc_writer_hair.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc
@@ -18,6 +18,7 @@
#include "BKE_customdata.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_particle.h"
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index 633611cf1a6..2820a128072 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -257,7 +257,7 @@ void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &
/* 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);
+ mesh, reinterpret_cast<float(*)[3]>(coords.data()), mesh->totvert, true);
if (!config.abc_orco.valid()) {
/* Create the Alembic property and keep a reference so future frames can reuse it. */
@@ -273,7 +273,7 @@ void write_custom_data(const OCompoundProperty &prop,
CustomData *data,
int data_type)
{
- CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type);
if (!CustomData_has_layer(data, cd_data_type)) {
return;
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 219bba285a7..df3559c108c 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -77,10 +77,8 @@ static void assign_materials(Main *bmain,
const std::map<std::string, int> &mat_index_map)
{
std::map<std::string, int>::const_iterator it;
- for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) {
- if (!BKE_object_material_slot_add(bmain, ob)) {
- return;
- }
+ if (mat_index_map.size() > MAXMAT) {
+ return;
}
std::map<std::string, Material *> matname_to_material = build_material_map(bmain);
@@ -100,7 +98,7 @@ static void assign_materials(Main *bmain,
assigned_mat = mat_iter->second;
}
- BKE_object_material_assign(bmain, ob, assigned_mat, mat_index, BKE_MAT_ASSIGN_OBDATA);
+ BKE_object_material_assign_single_obdata(bmain, ob, assigned_mat, mat_index);
}
}
@@ -376,7 +374,7 @@ BLI_INLINE void read_uvs_params(CDStreamConfig &config,
static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
{
- CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type);
/* unsupported custom data type -- don't do anything. */
if (!ELEM(cd_data_type, CD_MLOOPUV, CD_PROP_BYTE_COLOR)) {
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index 0d4e1d04db0..27df23b38c6 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -50,6 +50,7 @@
#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_timeit.hh"
#include "WM_api.h"
#include "WM_types.h"
@@ -434,8 +435,17 @@ struct ImportJobData {
bool was_cancelled;
bool import_ok;
bool is_background_job;
+ blender::timeit::TimePoint start_time;
};
+static void report_job_duration(const ImportJobData *data)
+{
+ blender::timeit::Nanoseconds duration = blender::timeit::Clock::now() - data->start_time;
+ std::cout << "Alembic import of '" << data->filename << "' took ";
+ blender::timeit::print_duration(duration);
+ std::cout << '\n';
+}
+
static void import_startjob(void *user_data, short *stop, short *do_update, float *progress)
{
SCOPE_TIMER("Alembic import, objects reading and creation");
@@ -445,6 +455,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
data->stop = stop;
data->do_update = do_update;
data->progress = progress;
+ data->start_time = blender::timeit::Clock::now();
WM_set_locked_interface(data->wm, true);
@@ -526,14 +537,14 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
Scene *scene = data->scene;
if (data->settings.is_sequence) {
- SFRA = data->settings.sequence_offset;
- EFRA = SFRA + (data->settings.sequence_len - 1);
- CFRA = SFRA;
+ scene->r.sfra = data->settings.sequence_offset;
+ scene->r.efra = scene->r.sfra + (data->settings.sequence_len - 1);
+ scene->r.cfra = scene->r.sfra;
}
else if (min_time < max_time) {
- SFRA = static_cast<int>(round(min_time * FPS));
- EFRA = static_cast<int>(round(max_time * FPS));
- CFRA = SFRA;
+ scene->r.sfra = static_cast<int>(round(min_time * FPS));
+ scene->r.efra = static_cast<int>(round(max_time * FPS));
+ scene->r.cfra = scene->r.sfra;
}
}
@@ -573,12 +584,10 @@ static void import_endjob(void *user_data)
ImportJobData *data = static_cast<ImportJobData *>(user_data);
- std::vector<AbcObjectReader *>::iterator iter;
-
/* Delete objects on cancellation. */
if (data->was_cancelled) {
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- Object *ob = (*iter)->object();
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
/* It's possible that cancellation occurred between the creation of
* the reader and the creation of the Blender object. */
@@ -590,7 +599,6 @@ static void import_endjob(void *user_data)
}
}
else {
- /* Add object to scene. */
Base *base;
LayerCollection *lc;
ViewLayer *view_layer = data->view_layer;
@@ -599,11 +607,17 @@ static void import_endjob(void *user_data)
lc = BKE_layer_collection_get_active(view_layer);
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- Object *ob = (*iter)->object();
-
+ /* Add all objects to the collection (don't do sync for each object). */
+ BKE_layer_collection_resync_forbid();
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
BKE_collection_object_add(data->bmain, lc->collection, ob);
-
+ }
+ /* Sync the collection, and do view layer operations. */
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync(data->bmain);
+ for (AbcObjectReader *reader : data->readers) {
+ Object *ob = reader->object();
base = BKE_view_layer_base_find(view_layer, ob);
/* TODO: is setting active needed? */
BKE_view_layer_base_select_and_set_active(view_layer, base);
@@ -625,8 +639,7 @@ static void import_endjob(void *user_data)
}
}
- for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) {
- AbcObjectReader *reader = *iter;
+ for (AbcObjectReader *reader : data->readers) {
reader->decref();
if (reader->refcount() == 0) {
@@ -647,6 +660,7 @@ static void import_endjob(void *user_data)
}
WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);
+ report_job_duration(data);
}
static void import_freejob(void *user_data)
diff --git a/source/blender/io/avi/AVI_avi.h b/source/blender/io/avi/AVI_avi.h
index e3af171355d..0857b9191b2 100644
--- a/source/blender/io/avi/AVI_avi.h
+++ b/source/blender/io/avi/AVI_avi.h
@@ -235,7 +235,8 @@ AviError AVI_close_compress(AviMovie *movie);
*/
AviError AVI_set_compress_option(
AviMovie *movie, int option_type, int stream, AviOption option, void *opt_data);
-/* Hmmm... there should be some explanation about what these mean */
+
+/* TODO: there should be some explanation about what these mean. */
/**
* Compression option, for use in avi_set_compress_option
*/
diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp
index 923a392dbde..cc91c3eeac9 100644
--- a/source/blender/io/collada/AnimationImporter.cpp
+++ b/source/blender/io/collada/AnimationImporter.cpp
@@ -64,7 +64,7 @@ void AnimationImporter::add_bezt(FCurve *fcu,
bez.f1 = bez.f2 = bez.f3 = SELECT;
bez.h1 = bez.h2 = HD_AUTO;
insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
@@ -132,7 +132,7 @@ void AnimationImporter::animation_to_fcurves(COLLADAFW::AnimationCurve *curve)
insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
}
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
fcurves.push_back(fcu);
unused_curves.push_back(fcu);
diff --git a/source/blender/io/collada/BCAnimationCurve.cpp b/source/blender/io/collada/BCAnimationCurve.cpp
index fbb2ba499a5..04a7a81c0a6 100644
--- a/source/blender/io/collada/BCAnimationCurve.cpp
+++ b/source/blender/io/collada/BCAnimationCurve.cpp
@@ -96,7 +96,7 @@ void BCAnimationCurve::create_bezt(float frame, float output)
bez.f1 = bez.f2 = bez.f3 = SELECT;
bez.h1 = bez.h2 = HD_AUTO;
insert_bezt_fcurve(fcu, &bez, INSERTKEY_NOFLAGS);
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
}
BCAnimationCurve::~BCAnimationCurve()
diff --git a/source/blender/io/collada/BCAnimationSampler.cpp b/source/blender/io/collada/BCAnimationSampler.cpp
index 29c17b500f3..cbb30ccf51d 100644
--- a/source/blender/io/collada/BCAnimationSampler.cpp
+++ b/source/blender/io/collada/BCAnimationSampler.cpp
@@ -225,24 +225,26 @@ bool BCAnimationSampler::is_animated_by_constraint(Object *ob,
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {nullptr, nullptr};
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
if (!bc_validateConstraints(con)) {
continue;
}
- if (cti && cti->get_constraint_targets) {
+ if (BKE_constraint_targets_get(con, &targets)) {
bConstraintTarget *ct;
Object *obtar;
- cti->get_constraint_targets(con, &targets);
+ bool found = false;
+
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
if (obtar) {
if (animated_objects.find(obtar) != animated_objects.end()) {
- return true;
+ found = true;
+ break;
}
}
}
+ BKE_constraint_targets_flush(con, &targets, true);
+ return found;
}
}
return false;
diff --git a/source/blender/io/collada/BCMath.cpp b/source/blender/io/collada/BCMath.cpp
index fc97110611a..d48e46ca115 100644
--- a/source/blender/io/collada/BCMath.cpp
+++ b/source/blender/io/collada/BCMath.cpp
@@ -49,11 +49,7 @@ BCMatrix::BCMatrix(BC_global_forward_axis global_forward_axis, BC_global_up_axis
float mrot[3][3];
float mat[4][4];
mat3_from_axis_conversion(
- BC_DEFAULT_FORWARD, BC_DEFAULT_UP, global_forward_axis, global_up_axis, mrot);
-
- /* TODO: Verify that `mat3_from_axis_conversion()` returns a transposed matrix */
- transpose_m3(mrot);
-
+ global_forward_axis, global_up_axis, BC_DEFAULT_FORWARD, BC_DEFAULT_UP, mrot);
copy_m4_m3(mat, mrot);
set_transform(mat);
}
diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp
index 6e109353be8..fa0348fbcf2 100644
--- a/source/blender/io/collada/MeshImporter.cpp
+++ b/source/blender/io/collada/MeshImporter.cpp
@@ -145,6 +145,27 @@ VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData &vdata) : mVData(&vda
{
}
+template<typename T>
+static void colladaAddColor(T values, MLoopCol *mloopcol, int v_index, int stride)
+{
+ if (values->empty() || values->getCount() < (v_index + 1) * stride) {
+ fprintf(stderr,
+ "VCOLDataWrapper.getvcol(): Out of Bounds error: index %d points outside value "
+ "list of length %zd (with stride=%d) \n",
+ v_index,
+ values->getCount(),
+ stride);
+ return;
+ }
+
+ mloopcol->r = unit_float_to_uchar_clamp((*values)[v_index * stride]);
+ mloopcol->g = unit_float_to_uchar_clamp((*values)[v_index * stride + 1]);
+ mloopcol->b = unit_float_to_uchar_clamp((*values)[v_index * stride + 2]);
+ if (stride == 4) {
+ mloopcol->a = unit_float_to_uchar_clamp((*values)[v_index * stride + 3]);
+ }
+}
+
void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
{
int stride = mVData->getStride(0);
@@ -155,25 +176,14 @@ void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol)
switch (mVData->getType()) {
case COLLADAFW::MeshVertexData::DATA_TYPE_FLOAT: {
COLLADAFW::ArrayPrimitiveType<float> *values = mVData->getFloatValues();
- if (values->empty() || values->getCount() <= (v_index * stride + 2)) {
- return; /* XXX: need to create an error instead. */
- }
-
- mloopcol->r = unit_float_to_uchar_clamp((*values)[v_index * stride]);
- mloopcol->g = unit_float_to_uchar_clamp((*values)[v_index * stride + 1]);
- mloopcol->b = unit_float_to_uchar_clamp((*values)[v_index * stride + 2]);
+ colladaAddColor<COLLADAFW::ArrayPrimitiveType<float> *>(values, mloopcol, v_index, stride);
} break;
case COLLADAFW::MeshVertexData::DATA_TYPE_DOUBLE: {
COLLADAFW::ArrayPrimitiveType<double> *values = mVData->getDoubleValues();
- if (values->empty() || values->getCount() <= (v_index * stride + 2)) {
- return; /* XXX: need to create an error instead. */
- }
-
- mloopcol->r = unit_float_to_uchar_clamp((*values)[v_index * stride]);
- mloopcol->g = unit_float_to_uchar_clamp((*values)[v_index * stride + 1]);
- mloopcol->b = unit_float_to_uchar_clamp((*values)[v_index * stride + 2]);
+ colladaAddColor<COLLADAFW::ArrayPrimitiveType<double> *>(values, mloopcol, v_index, stride);
} break;
+
default:
fprintf(stderr, "VCOLDataWrapper.getvcol(): unknown data type\n");
}
diff --git a/source/blender/io/collada/MeshImporter.h b/source/blender/io/collada/MeshImporter.h
index 85f960abfe6..416b5728b66 100644
--- a/source/blender/io/collada/MeshImporter.h
+++ b/source/blender/io/collada/MeshImporter.h
@@ -72,7 +72,7 @@ class MeshImporter : public MeshImporterBase {
std::map<std::string, std::string> mesh_geom_map; /* needed for correct shape key naming */
std::map<COLLADAFW::UniqueId, Mesh *> uid_mesh_map; /* geometry unique id-to-mesh map */
- std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom uid-to-object */
+ std::map<COLLADAFW::UniqueId, Object *> uid_object_map; /* geom UID-to-object */
std::vector<Object *> imported_objects; /* list of imported objects */
/* this structure is used to assign material indices to polygons
@@ -86,7 +86,7 @@ class MeshImporter : public MeshImporterBase {
/* crazy name! */
std::map<COLLADAFW::UniqueId, MaterialIdPrimitiveArrayMap> geom_uid_mat_mapping_map;
/* < materials that have already been mapped to a geometry.
- * A pair/of geom uid and mat uid, one geometry can have several materials */
+ * A pair/of geom UID and mat UID, one geometry can have several materials. */
std::multimap<COLLADAFW::UniqueId, COLLADAFW::UniqueId> materials_mapped_to_geom;
bool set_poly_indices(
diff --git a/source/blender/io/collada/SceneExporter.cpp b/source/blender/io/collada/SceneExporter.cpp
index ea95729666a..1b1da110573 100644
--- a/source/blender/io/collada/SceneExporter.cpp
+++ b/source/blender/io/collada/SceneExporter.cpp
@@ -191,24 +191,19 @@ void SceneExporter::writeNode(Object *ob)
/* not ideal: add the target object name as another parameter.
* No real mapping in the `.dae`.
* Need support for multiple target objects also. */
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- ListBase targets = {nullptr, nullptr};
- if (cti && cti->get_constraint_targets) {
+ ListBase targets = {nullptr, nullptr};
+ if (BKE_constraint_targets_get(con, &targets)) {
bConstraintTarget *ct;
Object *obtar;
- cti->get_constraint_targets(con, &targets);
-
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
std::string tar_id((obtar) ? id_name(obtar) : "");
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, true);
- }
+ BKE_constraint_targets_flush(con, &targets, true);
}
con = con->next;
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index 0c902700b6b..75842734b08 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -40,6 +40,7 @@
#include "BKE_lib_id.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_mesh_runtime.h"
#include "BKE_node.h"
#include "BKE_object.h"
diff --git a/source/blender/io/common/CMakeLists.txt b/source/blender/io/common/CMakeLists.txt
index e80bd850825..a6818c0bf5d 100644
--- a/source/blender/io/common/CMakeLists.txt
+++ b/source/blender/io/common/CMakeLists.txt
@@ -8,6 +8,7 @@ set(INC
../../depsgraph
../../makesdna
../../../../intern/guardedalloc
+ ../../makesrna
)
set(INC_SYS
@@ -19,12 +20,14 @@ set(SRC
intern/dupli_persistent_id.cc
intern/object_identifier.cc
intern/path_util.cc
+ intern/orientation.c
IO_abstract_hierarchy_iterator.h
IO_dupli_persistent_id.hh
IO_path_util.hh
IO_path_util_types.h
IO_types.h
+ IO_orientation.h
intern/dupli_parent_finder.hh
)
diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
index 3371501db95..a67cfe6a9d6 100644
--- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h
+++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h
@@ -59,9 +59,8 @@ struct HierarchyContext {
*
* The export hierarchy is kept as close to the hierarchy in Blender as possible. As such, an
* object that serves as a parent for another object, but which should NOT be exported itself, is
- * exported only as transform (i.e. as empty). This happens with objects that are part of a
- * holdout collection (which prevents them from being exported) but also parent of an exported
- * object. */
+ * exported only as transform (i.e. as empty). This happens with objects that are invisible when
+ * exporting with "Visible Only" enabled, for example. */
bool weak_export;
/* When true, this object should check its parents for animation data when determining whether
diff --git a/source/blender/io/common/IO_orientation.h b/source/blender/io/common/IO_orientation.h
new file mode 100644
index 00000000000..09fcbc7045c
--- /dev/null
+++ b/source/blender/io/common/IO_orientation.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "RNA_types.h"
+
+typedef enum {
+ IO_AXIS_X = 0,
+ IO_AXIS_Y = 1,
+ IO_AXIS_Z = 2,
+ IO_AXIS_NEGATIVE_X = 3,
+ IO_AXIS_NEGATIVE_Y = 4,
+ IO_AXIS_NEGATIVE_Z = 5,
+} eIOAxis;
+
+extern const EnumPropertyItem io_transform_axis[];
diff --git a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
index 82bb1c57833..1fbddc45964 100644
--- a/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
+++ b/source/blender/io/common/intern/abstract_hierarchy_iterator.cc
@@ -267,6 +267,11 @@ void AbstractHierarchyIterator::export_graph_construct()
{
Scene *scene = DEG_get_evaluated_scene(depsgraph_);
+ /* Add a "null" root node with no children immediately for the case where the top-most node in
+ * the scene is not being exported and a root node otherwise wouldn't get added. */
+ ExportGraph::key_type root_node_id = ObjectIdentifier::for_real_object(nullptr);
+ export_graph_[root_node_id] = ExportChildren();
+
DEG_OBJECT_ITER_BEGIN (depsgraph_,
object,
DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
diff --git a/source/blender/io/common/intern/orientation.c b/source/blender/io/common/intern/orientation.c
new file mode 100644
index 00000000000..0ffbaa8fe8e
--- /dev/null
+++ b/source/blender/io/common/intern/orientation.c
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "RNA_types.h"
+
+#include "IO_orientation.h"
+
+const EnumPropertyItem io_transform_axis[] = {
+ {IO_AXIS_X, "X", 0, "X", "Positive X axis"},
+ {IO_AXIS_Y, "Y", 0, "Y", "Positive Y axis"},
+ {IO_AXIS_Z, "Z", 0, "Z", "Positive Z axis"},
+ {IO_AXIS_NEGATIVE_X, "NEGATIVE_X", 0, "-X", "Negative X axis"},
+ {IO_AXIS_NEGATIVE_Y, "NEGATIVE_Y", 0, "-Y", "Negative Y axis"},
+ {IO_AXIS_NEGATIVE_Z, "NEGATIVE_Z", 0, "-Z", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
diff --git a/source/blender/io/common/intern/path_util.cc b/source/blender/io/common/intern/path_util.cc
index 902cf552bf0..18632b410f8 100644
--- a/source/blender/io/common/intern/path_util.cc
+++ b/source/blender/io/common/intern/path_util.cc
@@ -39,7 +39,7 @@ std::string path_reference(StringRefNull filepath,
if (mode == PATH_REFERENCE_ABSOLUTE) {
return filepath_abs;
}
- else if (mode == PATH_REFERENCE_RELATIVE) {
+ if (mode == PATH_REFERENCE_RELATIVE) {
char rel_path[PATH_MAX];
BLI_strncpy(rel_path, filepath_abs, PATH_MAX);
BLI_path_rel(rel_path, base_dst.c_str());
@@ -49,7 +49,7 @@ std::string path_reference(StringRefNull filepath,
}
return rel_path + 2; /* Skip blender's internal "//" prefix. */
}
- else if (mode == PATH_REFERENCE_STRIP) {
+ if (mode == PATH_REFERENCE_STRIP) {
return BLI_path_basename(filepath_abs);
}
BLI_assert_msg(false, "Invalid path reference mode");
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc
index 05f1158c57d..6db3eccedbe 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc
@@ -91,8 +91,7 @@ void GpencilIO::prepare_camera_params(Scene *scene, const GpencilIOParams *ipara
/* Camera rectangle. */
if ((rv3d_->persp == RV3D_CAMOB) || (force_camera_view)) {
- render_x_ = (scene_->r.xsch * scene_->r.size) / 100;
- render_y_ = (scene_->r.ysch * scene_->r.size) / 100;
+ BKE_render_resolution(&scene->r, false, &render_x_, &render_y_);
ED_view3d_calc_camera_border(CTX_data_scene(params_.C),
depsgraph_,
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.hh b/source/blender/io/gpencil/intern/gpencil_io_base.hh
index a89b723ed6c..4987ab34ffc 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.hh
@@ -58,8 +58,8 @@ class GpencilIO {
struct Scene *scene_;
struct RegionView3D *rv3d_;
- int16_t winx_, winy_;
- int16_t render_x_, render_y_;
+ int winx_, winy_;
+ int render_x_, render_y_;
float camera_ratio_;
rctf camera_rect_;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
index 84b273bc570..ac5f8cf7c8d 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_capi.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
@@ -112,7 +112,7 @@ static bool gpencil_io_export_pdf(Depsgraph *depsgraph,
continue;
}
- CFRA = i;
+ scene->r.cfra = i;
BKE_scene_graph_update_for_newframe(depsgraph);
exporter->prepare_camera_params(scene, iparams);
exporter->frame_number_set(i);
@@ -122,7 +122,7 @@ static bool gpencil_io_export_pdf(Depsgraph *depsgraph,
result = exporter->write();
/* Back to original frame. */
exporter->frame_number_set(iparams->frame_cur);
- CFRA = iparams->frame_cur;
+ scene->r.cfra = iparams->frame_cur;
BKE_scene_camera_switch_update(scene);
BKE_scene_graph_update_for_newframe(depsgraph);
break;
diff --git a/source/blender/io/stl/CMakeLists.txt b/source/blender/io/stl/CMakeLists.txt
new file mode 100644
index 00000000000..e0c48bbbf7e
--- /dev/null
+++ b/source/blender/io/stl/CMakeLists.txt
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(INC
+ .
+ ./importer
+ ../common
+ ../../blenkernel
+ ../../blenlib
+ ../../bmesh
+ ../../bmesh/intern
+ ../../depsgraph
+ ../../editors/include
+ ../../makesdna
+ ../../makesrna
+ ../../nodes
+ ../../windowmanager
+ ../../../../extern/fast_float
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ IO_stl.cc
+ importer/stl_import_mesh.cc
+ importer/stl_import_ascii_reader.cc
+ importer/stl_import_binary_reader.cc
+ importer/stl_import.cc
+
+ IO_stl.h
+ importer/stl_import_mesh.hh
+ importer/stl_import_ascii_reader.hh
+ importer/stl_import_binary_reader.hh
+ importer/stl_import.hh
+)
+
+set(LIB
+ bf_blenkernel
+ bf_io_common
+)
+
+blender_add_lib(bf_stl "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/io/stl/IO_stl.cc b/source/blender/io/stl/IO_stl.cc
new file mode 100644
index 00000000000..b26c1533692
--- /dev/null
+++ b/source/blender/io/stl/IO_stl.cc
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include "BLI_timeit.hh"
+
+#include "IO_stl.h"
+#include "stl_import.hh"
+
+void STL_import(bContext *C, const struct STLImportParams *import_params)
+{
+ SCOPED_TIMER("STL Import");
+ blender::io::stl::importer_main(C, *import_params);
+}
diff --git a/source/blender/io/stl/IO_stl.h b/source/blender/io/stl/IO_stl.h
new file mode 100644
index 00000000000..bbe537948e8
--- /dev/null
+++ b/source/blender/io/stl/IO_stl.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include "BKE_context.h"
+#include "BLI_path_util.h"
+#include "IO_orientation.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct STLImportParams {
+ /** Full path to the source STL file to import. */
+ char filepath[FILE_MAX];
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
+ bool use_facet_normal;
+ bool use_scene_unit;
+ float global_scale;
+ bool use_mesh_validate;
+};
+
+/**
+ * C-interface for the importer.
+ */
+void STL_import(bContext *C, const struct STLImportParams *import_params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/io/stl/importer/stl_import.cc b/source/blender/io/stl/importer/stl_import.cc
new file mode 100644
index 00000000000..097d14b038c
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import.cc
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdio>
+
+#include "BKE_customdata.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_fileops.hh"
+#include "BLI_math_vector.h"
+#include "BLI_memory_utils.hh"
+
+#include "DNA_object_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "stl_import.hh"
+#include "stl_import_ascii_reader.hh"
+#include "stl_import_binary_reader.hh"
+
+namespace blender::io::stl {
+
+void stl_import_report_error(FILE *file)
+{
+ fprintf(stderr, "STL Importer: failed to read file");
+ if (feof(file)) {
+ fprintf(stderr, ", end of file reached.\n");
+ }
+ else if (ferror(file)) {
+ perror("Error");
+ }
+}
+
+void importer_main(bContext *C, const STLImportParams &import_params)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ importer_main(bmain, scene, view_layer, import_params);
+}
+
+void importer_main(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ const STLImportParams &import_params)
+{
+ FILE *file = BLI_fopen(import_params.filepath, "rb");
+ if (!file) {
+ fprintf(stderr, "Failed to open STL file:'%s'.\n", import_params.filepath);
+ return;
+ }
+ BLI_SCOPED_DEFER([&]() { fclose(file); });
+
+ /* Detect STL file type by comparing file size with expected file size,
+ * could check if file starts with "solid", but some files do not adhere,
+ * this is the same as the old Python importer.
+ */
+ uint32_t num_tri = 0;
+ size_t file_size = BLI_file_size(import_params.filepath);
+ fseek(file, BINARY_HEADER_SIZE, SEEK_SET);
+ if (fread(&num_tri, sizeof(uint32_t), 1, file) != 1) {
+ stl_import_report_error(file);
+ return;
+ }
+ bool is_ascii_stl = (file_size != (BINARY_HEADER_SIZE + 4 + BINARY_STRIDE * num_tri));
+
+ /* Name used for both mesh and object. */
+ char ob_name[FILE_MAX];
+ BLI_strncpy(ob_name, BLI_path_basename(import_params.filepath), FILE_MAX);
+ BLI_path_extension_replace(ob_name, FILE_MAX, "");
+
+ Mesh *mesh = nullptr;
+ if (is_ascii_stl) {
+ mesh = read_stl_ascii(import_params.filepath, bmain, ob_name, import_params.use_facet_normal);
+ }
+ else {
+ mesh = read_stl_binary(file, bmain, ob_name, import_params.use_facet_normal);
+ }
+
+ if (mesh == nullptr) {
+ fprintf(stderr, "STL Importer: Failed to import mesh '%s'\n", import_params.filepath);
+ return;
+ }
+
+ if (import_params.use_mesh_validate) {
+ bool verbose_validate = false;
+#ifdef DEBUG
+ verbose_validate = true;
+#endif
+ BKE_mesh_validate(mesh, verbose_validate, false);
+ }
+
+ BKE_view_layer_base_deselect_all(view_layer);
+ LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
+ Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name);
+ BKE_mesh_assign_object(bmain, obj, mesh);
+ BKE_collection_object_add(bmain, lc->collection, obj);
+ Base *base = BKE_view_layer_base_find(view_layer, obj);
+ BKE_view_layer_base_select_and_set_active(view_layer, base);
+
+ float global_scale = import_params.global_scale;
+ if ((scene->unit.system != USER_UNIT_NONE) && import_params.use_scene_unit) {
+ global_scale *= scene->unit.scale_length;
+ }
+ float scale_vec[3] = {global_scale, global_scale, global_scale};
+ float obmat3x3[3][3];
+ unit_m3(obmat3x3);
+ float obmat4x4[4][4];
+ unit_m4(obmat4x4);
+ /* +Y-forward and +Z-up are the Blender's default axis settings. */
+ mat3_from_axis_conversion(
+ IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, obmat3x3);
+ copy_m4_m3(obmat4x4, obmat3x3);
+ rescale_m4(obmat4x4, scale_vec);
+ BKE_object_apply_mat4(obj, obmat4x4, true, false);
+
+ DEG_id_tag_update(&lc->collection->id, ID_RECALC_COPY_ON_WRITE);
+ int flags = ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION |
+ ID_RECALC_BASE_FLAGS;
+ DEG_id_tag_update_ex(bmain, &obj->id, flags);
+ DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
+ DEG_relations_tag_update(bmain);
+}
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import.hh b/source/blender/io/stl/importer/stl_import.hh
new file mode 100644
index 00000000000..a5d252248a8
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import.hh
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include "IO_stl.h"
+
+namespace blender::io::stl {
+
+void stl_import_report_error(FILE *file);
+
+/* Main import function used from within Blender. */
+void importer_main(bContext *C, const STLImportParams &import_params);
+
+/* Used from tests, where full bContext does not exist. */
+void importer_main(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ const STLImportParams &import_params);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.cc b/source/blender/io/stl/importer/stl_import_ascii_reader.cc
new file mode 100644
index 00000000000..2edb3c6a114
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_ascii_reader.cc
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdint>
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+#include "BLI_fileops.hh"
+#include "BLI_memory_utils.hh"
+#include "BLI_string_ref.hh"
+
+#include "DNA_mesh_types.h"
+
+/* NOTE: we could use C++17 <charconv> from_chars to parse
+ * floats, but even if some compilers claim full support,
+ * their standard libraries are not quite there yet.
+ * LLVM/libc++ only has a float parser since LLVM 14,
+ * and gcc/libstdc++ since 11.1. So until at least these are
+ * the minimum spec, use an external library. */
+#include "fast_float.h"
+
+#include "stl_import.hh"
+#include "stl_import_ascii_reader.hh"
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+class StringBuffer {
+ private:
+ char *start;
+ const char *end;
+
+ public:
+ StringBuffer(char *buf, size_t len)
+ {
+ start = buf;
+ end = start + len;
+ }
+
+ bool is_empty() const
+ {
+ return start == end;
+ }
+
+ void drop_leading_control_chars()
+ {
+ while ((start < end) && (*start) <= ' ') {
+ start++;
+ }
+ }
+
+ void drop_leading_non_control_chars()
+ {
+ while ((start < end) && (*start) > ' ') {
+ start++;
+ }
+ }
+
+ void drop_line()
+ {
+ while (start < end && *start != '\n') {
+ start++;
+ }
+ }
+
+ bool parse_token(const char *token, size_t token_length)
+ {
+ drop_leading_control_chars();
+ if (end - start < token_length + 1) {
+ return false;
+ }
+ if (memcmp(start, token, token_length) != 0) {
+ return false;
+ }
+ if (start[token_length] > ' ') {
+ return false;
+ }
+ start += token_length + 1;
+ return true;
+ }
+
+ void drop_token()
+ {
+ drop_leading_non_control_chars();
+ drop_leading_control_chars();
+ }
+
+ void parse_float(float &out)
+ {
+ drop_leading_control_chars();
+ /* Skip '+' */
+ if (start < end && *start == '+') {
+ start++;
+ }
+ fast_float::from_chars_result res = fast_float::from_chars(start, end, out);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ out = 0.0f;
+ }
+ start = const_cast<char *>(res.ptr);
+ }
+};
+
+static inline void parse_float3(StringBuffer &buf, float out[3])
+{
+ for (int i = 0; i < 3; i++) {
+ buf.parse_float(out[i]);
+ }
+}
+
+Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals)
+{
+ size_t buffer_len;
+ void *buffer = BLI_file_read_text_as_mem(filepath, 0, &buffer_len);
+ if (buffer == nullptr) {
+ fprintf(stderr, "STL Importer: cannot read from ASCII STL file: '%s'\n", filepath);
+ return BKE_mesh_add(bmain, mesh_name);
+ }
+ BLI_SCOPED_DEFER([&]() { MEM_freeN(buffer); });
+
+ int num_reserved_tris = 1024;
+
+ StringBuffer str_buf(static_cast<char *>(buffer), buffer_len);
+ STLMeshHelper stl_mesh(num_reserved_tris, use_custom_normals);
+ float triangle_buf[3][3];
+ float custom_normal_buf[3];
+ str_buf.drop_line(); /* Skip header line */
+ while (!str_buf.is_empty()) {
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[0]);
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[1]);
+ }
+ if (str_buf.parse_token("vertex", 6)) {
+ parse_float3(str_buf, triangle_buf[2]);
+ }
+ if (use_custom_normals) {
+ stl_mesh.add_triangle(
+ triangle_buf[0], triangle_buf[1], triangle_buf[2], custom_normal_buf);
+ }
+ else {
+ stl_mesh.add_triangle(triangle_buf[0], triangle_buf[1], triangle_buf[2]);
+ }
+ }
+ else if (str_buf.parse_token("facet", 5)) {
+ str_buf.drop_token(); /* Expecting "normal" */
+ parse_float3(str_buf, custom_normal_buf);
+ }
+ else {
+ str_buf.drop_token();
+ }
+ }
+
+ return stl_mesh.to_mesh(bmain, mesh_name);
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.hh b/source/blender/io/stl/importer/stl_import_ascii_reader.hh
new file mode 100644
index 00000000000..e8aed911bf1
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_ascii_reader.hh
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+#include "stl_import.hh"
+
+/**
+ * ASCII STL spec:
+ * <pre>
+ * solid name
+ * facet normal ni nj nk
+ * outer loop
+ * vertex v1x v1y v1z
+ * vertex v2x v2y v2z
+ * vertex v3x v3y v3z
+ * endloop
+ * endfacet
+ * ...
+ * endsolid name
+ * </pre>
+ */
+
+namespace blender::io::stl {
+
+Mesh *read_stl_ascii(const char *filepath, Main *bmain, char *mesh_name, bool use_custom_normals);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.cc b/source/blender/io/stl/importer/stl_import_binary_reader.cc
new file mode 100644
index 00000000000..fb9dcea0a1d
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_binary_reader.cc
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include <cstdint>
+#include <cstdio>
+
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+
+#include "BLI_array.hh"
+#include "BLI_memory_utils.hh"
+
+#include "DNA_mesh_types.h"
+
+#include "stl_import.hh"
+#include "stl_import_binary_reader.hh"
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+#pragma pack(push, 1)
+struct STLBinaryTriangle {
+ float normal[3];
+ float v1[3], v2[3], v3[3];
+ uint16_t attribute_byte_count;
+};
+#pragma pack(pop)
+
+Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals)
+{
+ const int chunk_size = 1024;
+ uint32_t num_tris = 0;
+ fseek(file, BINARY_HEADER_SIZE, SEEK_SET);
+ if (fread(&num_tris, sizeof(uint32_t), 1, file) != 1) {
+ stl_import_report_error(file);
+ return nullptr;
+ }
+
+ if (num_tris == 0) {
+ return BKE_mesh_add(bmain, mesh_name);
+ }
+
+ Array<STLBinaryTriangle> tris_buf(chunk_size);
+ STLMeshHelper stl_mesh(num_tris, use_custom_normals);
+ size_t num_read_tris;
+ while ((num_read_tris = fread(tris_buf.data(), sizeof(STLBinaryTriangle), chunk_size, file))) {
+ for (size_t i = 0; i < num_read_tris; i++) {
+ if (use_custom_normals) {
+ stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3, tris_buf[i].normal);
+ }
+ else {
+ stl_mesh.add_triangle(tris_buf[i].v1, tris_buf[i].v2, tris_buf[i].v3);
+ }
+ }
+ }
+
+ return stl_mesh.to_mesh(bmain, mesh_name);
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.hh b/source/blender/io/stl/importer/stl_import_binary_reader.hh
new file mode 100644
index 00000000000..71d5dbbbe58
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_binary_reader.hh
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdio>
+
+#include "BKE_mesh.h"
+
+/* Binary STL spec.:
+ * UINT8[80] – Header - 80 bytes
+ * UINT32 – Number of triangles - 4 bytes
+ * For each triangle - 50 bytes:
+ * REAL32[3] – Normal vector - 12 bytes
+ * REAL32[3] – Vertex 1 - 12 bytes
+ * REAL32[3] – Vertex 2 - 12 bytes
+ * REAL32[3] – Vertex 3 - 12 bytes
+ * UINT16 – Attribute byte count - 2 bytes
+ */
+
+namespace blender::io::stl {
+
+const size_t BINARY_HEADER_SIZE = 80;
+const size_t BINARY_STRIDE = 12 * 4 + 2;
+
+Mesh *read_stl_binary(FILE *file, Main *bmain, char *mesh_name, bool use_custom_normals);
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc
new file mode 100644
index 00000000000..b9ed441f0d9
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_mesh.cc
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#include "BKE_customdata.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+
+#include "BLI_array.hh"
+#include "BLI_math_vector.h"
+#include "BLI_math_vector.hh"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "stl_import_mesh.hh"
+
+namespace blender::io::stl {
+
+STLMeshHelper::STLMeshHelper(int tris_num, bool use_custom_normals)
+ : use_custom_normals_(use_custom_normals)
+{
+ degenerate_tris_num_ = 0;
+ duplicate_tris_num_ = 0;
+ tris_.reserve(tris_num);
+ /* Upper bound (all vertices are unique). */
+ verts_.reserve(tris_num * 3);
+ if (use_custom_normals) {
+ loop_normals_.reserve(tris_num * 3);
+ }
+}
+
+bool STLMeshHelper::add_triangle(const float3 &a, const float3 &b, const float3 &c)
+{
+ int v1_id = verts_.index_of_or_add(a);
+ int v2_id = verts_.index_of_or_add(b);
+ int v3_id = verts_.index_of_or_add(c);
+ if ((v1_id == v2_id) || (v1_id == v3_id) || (v2_id == v3_id)) {
+ degenerate_tris_num_++;
+ return false;
+ }
+ if (!tris_.add({v1_id, v2_id, v3_id})) {
+ duplicate_tris_num_++;
+ return false;
+ }
+ return true;
+}
+
+void STLMeshHelper::add_triangle(const float3 &a,
+ const float3 &b,
+ const float3 &c,
+ const float3 &custom_normal)
+{
+ if (add_triangle(a, b, c)) {
+ loop_normals_.append_n_times(custom_normal, 3);
+ }
+}
+
+Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name)
+{
+ if (degenerate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << degenerate_tris_num_ << " degenerate triangles were removed"
+ << std::endl;
+ }
+ if (duplicate_tris_num_ > 0) {
+ std::cout << "STL Importer: " << duplicate_tris_num_ << " duplicate triangles were removed"
+ << std::endl;
+ }
+
+ Mesh *mesh = BKE_mesh_add(bmain, mesh_name);
+ /* User count is already 1 here, but will be set later in #BKE_mesh_assign_object. */
+ id_us_min(&mesh->id);
+
+ mesh->totvert = verts_.size();
+ mesh->mvert = static_cast<MVert *>(
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert));
+ for (int i = 0; i < mesh->totvert; i++) {
+ copy_v3_v3(mesh->mvert[i].co, verts_[i]);
+ }
+
+ mesh->totpoly = tris_.size();
+ mesh->totloop = tris_.size() * 3;
+ mesh->mpoly = static_cast<MPoly *>(
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly));
+ mesh->mloop = static_cast<MLoop *>(
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop));
+
+ threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) {
+ for (const int i : tris_range) {
+ mesh->mpoly[i].loopstart = 3 * i;
+ mesh->mpoly[i].totloop = 3;
+
+ mesh->mloop[3 * i].v = tris_[i].v1;
+ mesh->mloop[3 * i + 1].v = tris_[i].v2;
+ mesh->mloop[3 * i + 2].v = tris_[i].v3;
+ }
+ });
+
+ /* NOTE: edges must be calculated first before setting custom normals. */
+ BKE_mesh_calc_edges(mesh, false, false);
+
+ if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) {
+ BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data()));
+ mesh->flag |= ME_AUTOSMOOTH;
+ }
+
+ return mesh;
+}
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/stl/importer/stl_import_mesh.hh b/source/blender/io/stl/importer/stl_import_mesh.hh
new file mode 100644
index 00000000000..f1c0d2126a9
--- /dev/null
+++ b/source/blender/io/stl/importer/stl_import_mesh.hh
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup stl
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include "BLI_math_vec_types.hh"
+#include "BLI_set.hh"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_mesh_types.h"
+
+namespace blender::io::stl {
+class Triangle {
+ public:
+ int v1, v2, v3;
+ /* Based on an old version of Python's frozen-set hash
+ * https://web.archive.org/web/20220520211017/https://stackoverflow.com/questions/20832279/python-frozenset-hashing-algorithm-implementation
+ */
+ uint64_t hash() const
+ {
+ uint64_t res = 1927868237UL;
+ res *= 4;
+ res ^= (v1 ^ (v1 << 16) ^ 89869747UL) * 3644798167UL;
+ res ^= (v2 ^ (v2 << 16) ^ 89869747UL) * 3644798167UL;
+ res ^= (v3 ^ (v3 << 16) ^ 89869747UL) * 3644798167UL;
+ return res * 69069U + 907133923UL;
+ }
+ friend bool operator==(const Triangle &a, const Triangle &b)
+ {
+ bool i = (a.v1 == b.v1) && (a.v2 == b.v2) && (a.v3 == b.v3);
+ bool j = (a.v1 == b.v1) && (a.v3 == b.v2) && (a.v2 == b.v3);
+ bool k = (a.v2 == b.v1) && (a.v1 == b.v2) && (a.v3 == b.v3);
+
+ bool l = (a.v2 == b.v1) && (a.v3 == b.v2) && (a.v1 == b.v3);
+ bool m = (a.v3 == b.v1) && (a.v1 == b.v2) && (a.v2 == b.v3);
+ bool n = (a.v3 == b.v1) && (a.v2 == b.v2) && (a.v1 == b.v3);
+
+ return i || j || k || l || m || n;
+ }
+};
+
+class STLMeshHelper {
+ private:
+ VectorSet<float3> verts_;
+ VectorSet<Triangle> tris_;
+ Vector<float3> loop_normals_;
+ int degenerate_tris_num_;
+ int duplicate_tris_num_;
+ const bool use_custom_normals_;
+
+ public:
+ STLMeshHelper(int tris_num, bool use_custom_normals);
+
+ /* Creates a new triangle from specified vertex locations,
+ * duplicate vertices and triangles are merged.
+ */
+ bool add_triangle(const float3 &a, const float3 &b, const float3 &c);
+ void add_triangle(const float3 &a,
+ const float3 &b,
+ const float3 &c,
+ const float3 &custom_normal);
+ Mesh *to_mesh(Main *bmain, char *mesh_name);
+};
+
+} // namespace blender::io::stl
diff --git a/source/blender/io/usd/intern/usd_capi_export.cc b/source/blender/io/usd/intern/usd_capi_export.cc
index 2049c631671..1033f85181c 100644
--- a/source/blender/io/usd/intern/usd_capi_export.cc
+++ b/source/blender/io/usd/intern/usd_capi_export.cc
@@ -27,6 +27,7 @@
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_timeit.hh"
#include "WM_api.h"
#include "WM_types.h"
@@ -42,8 +43,17 @@ struct ExportJobData {
USDExportParams params;
bool export_ok;
+ timeit::TimePoint start_time;
};
+static void report_job_duration(const ExportJobData *data)
+{
+ timeit::Nanoseconds duration = timeit::Clock::now() - data->start_time;
+ std::cout << "USD export of '" << data->filepath << "' took ";
+ timeit::print_duration(duration);
+ std::cout << '\n';
+}
+
static void export_startjob(void *customdata,
/* Cannot be const, this function implements wm_jobs_start_callback.
* NOLINTNEXTLINE: readability-non-const-parameter. */
@@ -53,6 +63,7 @@ static void export_startjob(void *customdata,
{
ExportJobData *data = static_cast<ExportJobData *>(customdata);
data->export_ok = false;
+ data->start_time = timeit::Clock::now();
G.is_rendering = true;
WM_set_locked_interface(data->wm, true);
@@ -72,7 +83,7 @@ static void export_startjob(void *customdata,
*do_update = true;
/* For restoring the current frame after exporting animation is done. */
- const int orig_frame = CFRA;
+ const int orig_frame = scene->r.cfra;
pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(data->filepath);
if (!usd_stage) {
@@ -129,8 +140,8 @@ static void export_startjob(void *customdata,
usd_stage->GetRootLayer()->Save();
/* Finish up by going back to the keyframe that was current before we started. */
- if (CFRA != orig_frame) {
- CFRA = orig_frame;
+ if (scene->r.cfra != orig_frame) {
+ scene->r.cfra = orig_frame;
BKE_scene_graph_update_for_newframe(data->depsgraph);
}
@@ -151,6 +162,7 @@ static void export_endjob(void *customdata)
G.is_rendering = false;
WM_set_locked_interface(data->wm, false);
+ report_job_duration(data);
}
} // namespace blender::io::usd
diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc
index 29b256125f0..13ae6f4d4c0 100644
--- a/source/blender/io/usd/intern/usd_capi_import.cc
+++ b/source/blender/io/usd/intern/usd_capi_import.cc
@@ -30,6 +30,7 @@
#include "BLI_math_rotation.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_timeit.hh"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -132,8 +133,17 @@ struct ImportJobData {
char error_code;
bool was_canceled;
bool import_ok;
+ timeit::TimePoint start_time;
};
+static void report_job_duration(const ImportJobData *data)
+{
+ timeit::Nanoseconds duration = timeit::Clock::now() - data->start_time;
+ std::cout << "USD import of '" << data->filepath << "' took ";
+ timeit::print_duration(duration);
+ std::cout << '\n';
+}
+
static void import_startjob(void *customdata, short *stop, short *do_update, float *progress)
{
ImportJobData *data = static_cast<ImportJobData *>(customdata);
@@ -143,6 +153,7 @@ static void import_startjob(void *customdata, short *stop, short *do_update, flo
data->progress = progress;
data->was_canceled = false;
data->archive = nullptr;
+ data->start_time = timeit::Clock::now();
WM_set_locked_interface(data->wm, true);
G.is_break = false;
@@ -277,7 +288,6 @@ static void import_endjob(void *customdata)
}
}
else if (data->archive) {
- /* Add object to scene. */
Base *base;
LayerCollection *lc;
ViewLayer *view_layer = data->view_layer;
@@ -286,20 +296,30 @@ static void import_endjob(void *customdata)
lc = BKE_layer_collection_get_active(view_layer);
+ /* Add all objects to the collection (don't do sync for each object). */
+ BKE_layer_collection_resync_forbid();
for (USDPrimReader *reader : data->archive->readers()) {
-
if (!reader) {
continue;
}
-
Object *ob = reader->object();
-
if (!ob) {
continue;
}
-
BKE_collection_object_add(data->bmain, lc->collection, ob);
+ }
+ /* Sync the collection, and do view layer operations. */
+ BKE_layer_collection_resync_allow();
+ BKE_main_collection_sync(data->bmain);
+ for (USDPrimReader *reader : data->archive->readers()) {
+ if (!reader) {
+ continue;
+ }
+ Object *ob = reader->object();
+ if (!ob) {
+ continue;
+ }
base = BKE_view_layer_base_find(view_layer, ob);
/* TODO: is setting active needed? */
BKE_view_layer_base_select_and_set_active(view_layer, base);
@@ -328,6 +348,7 @@ static void import_endjob(void *customdata)
}
WM_main_add_notifier(NC_SCENE | ND_FRAME, data->scene);
+ report_job_duration(data);
}
static void import_freejob(void *user_data)
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index e2562eca69b..45657525527 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -62,45 +62,73 @@ static void build_mat_map(const Main *bmain, std::map<std::string, Material *> *
}
}
+static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim)
+{
+ return pxr::UsdShadeMaterialBindingAPI(prim).ComputeBoundMaterial();
+}
+
+/* Returns an existing Blender material that corresponds to the USD
+ * material with with the given path. Returns null if no such material
+ * exists. */
+static Material *find_existing_material(
+ const pxr::SdfPath &usd_mat_path,
+ const USDImportParams &params,
+ const std::map<std::string, Material *> &mat_map,
+ const std::map<std::string, std::string> &usd_path_to_mat_name)
+{
+ if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) {
+ /* Check if we've already created the Blender material with a modified name. */
+ std::map<std::string, std::string>::const_iterator path_to_name_iter =
+ usd_path_to_mat_name.find(usd_mat_path.GetAsString());
+
+ if (path_to_name_iter != usd_path_to_mat_name.end()) {
+ std::string mat_name = path_to_name_iter->second;
+ std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
+ if (mat_iter != mat_map.end()) {
+ return mat_iter->second;
+ }
+ /* We can't find the Blender material which was previously created for this USD
+ * material, which should never happen. */
+ BLI_assert_unreachable();
+ }
+ }
+ else {
+ std::string mat_name = usd_mat_path.GetName();
+ std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
+
+ if (mat_iter != mat_map.end()) {
+ return mat_iter->second;
+ }
+ }
+
+ return nullptr;
+}
+
static void assign_materials(Main *bmain,
Object *ob,
const std::map<pxr::SdfPath, int> &mat_index_map,
const USDImportParams &params,
- pxr::UsdStageRefPtr stage)
+ pxr::UsdStageRefPtr stage,
+ std::map<std::string, Material *> &mat_name_to_mat,
+ std::map<std::string, std::string> &usd_path_to_mat_name)
{
if (!(stage && bmain && ob)) {
return;
}
- bool can_assign = true;
- std::map<pxr::SdfPath, int>::const_iterator it = mat_index_map.begin();
-
- int matcount = 0;
- for (; it != mat_index_map.end(); ++it, matcount++) {
- if (!BKE_object_material_slot_add(bmain, ob)) {
- can_assign = false;
- break;
- }
- }
-
- if (!can_assign) {
+ if (mat_index_map.size() > MAXMAT) {
return;
}
- /* TODO(kevin): use global map? */
- std::map<std::string, Material *> mat_map;
- build_mat_map(bmain, &mat_map);
-
blender::io::usd::USDMaterialReader mat_reader(params, bmain);
- for (it = mat_index_map.begin(); it != mat_index_map.end(); ++it) {
- std::string mat_name = it->first.GetName();
-
- std::map<std::string, Material *>::iterator mat_iter = mat_map.find(mat_name);
-
- Material *assigned_mat = nullptr;
+ for (std::map<pxr::SdfPath, int>::const_iterator it = mat_index_map.begin();
+ it != mat_index_map.end();
+ ++it) {
- if (mat_iter == mat_map.end()) {
+ Material *assigned_mat = find_existing_material(
+ it->first, params, mat_name_to_mat, usd_path_to_mat_name);
+ if (!assigned_mat) {
/* Blender material doesn't exist, so create it now. */
/* Look up the USD material. */
@@ -122,19 +150,22 @@ static void assign_materials(Main *bmain,
continue;
}
- mat_map[mat_name] = assigned_mat;
- }
- else {
- /* We found an existing Blender material. */
- assigned_mat = mat_iter->second;
+ const std::string mat_name = pxr::TfMakeValidIdentifier(assigned_mat->id.name + 2);
+ mat_name_to_mat[mat_name] = assigned_mat;
+
+ if (params.mtl_name_collision_mode == USD_MTL_NAME_COLLISION_MAKE_UNIQUE) {
+ /* Record the name of the Blender material we created for the USD material
+ * with the given path. */
+ usd_path_to_mat_name[it->first.GetAsString()] = mat_name;
+ }
}
if (assigned_mat) {
- BKE_object_material_assign(bmain, ob, assigned_mat, it->second, BKE_MAT_ASSIGN_OBDATA);
+ BKE_object_material_assign_single_obdata(bmain, ob, assigned_mat, it->second);
}
else {
/* This shouldn't happen. */
- std::cout << "WARNING: Couldn't assign material " << mat_name << std::endl;
+ std::cout << "WARNING: Couldn't assign material " << it->first << std::endl;
}
}
}
@@ -143,7 +174,7 @@ static void assign_materials(Main *bmain,
static void *add_customdata_cb(Mesh *mesh, const char *name, const int data_type)
{
- CustomDataType cd_data_type = static_cast<CustomDataType>(data_type);
+ eCustomDataType cd_data_type = static_cast<eCustomDataType>(data_type);
void *cd_ptr;
CustomData *loopdata;
int numloops;
@@ -710,11 +741,8 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
int current_mat = 0;
if (!subsets.empty()) {
for (const pxr::UsdGeomSubset &subset : subsets) {
- pxr::UsdShadeMaterialBindingAPI subset_api = pxr::UsdShadeMaterialBindingAPI(
- subset.GetPrim());
-
- pxr::UsdShadeMaterial subset_mtl = subset_api.ComputeBoundMaterial();
+ pxr::UsdShadeMaterial subset_mtl = utils::compute_bound_material(subset.GetPrim());
if (!subset_mtl) {
continue;
}
@@ -743,10 +771,9 @@ void USDMeshReader::assign_facesets_to_mpoly(double motionSampleTime,
}
if (r_mat_map->empty()) {
- pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(prim_);
-
- if (pxr::UsdShadeMaterial mtl = api.ComputeBoundMaterial()) {
+ pxr::UsdShadeMaterial mtl = utils::compute_bound_material(prim_);
+ if (mtl) {
pxr::SdfPath mtl_path = mtl.GetPath();
if (!mtl_path.IsEmpty()) {
@@ -764,7 +791,17 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot
std::map<pxr::SdfPath, int> mat_map;
assign_facesets_to_mpoly(motionSampleTime, mesh->mpoly, mesh->totpoly, &mat_map);
- utils::assign_materials(bmain, object_, mat_map, this->import_params_, this->prim_.GetStage());
+ /* Build material name map if it's not built yet. */
+ if (this->settings_->mat_name_to_mat.empty()) {
+ utils::build_mat_map(bmain, &this->settings_->mat_name_to_mat);
+ }
+ utils::assign_materials(bmain,
+ object_,
+ mat_map,
+ this->import_params_,
+ this->prim_.GetStage(),
+ this->settings_->mat_name_to_mat,
+ this->settings_->usd_path_to_mat_name);
}
Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh,
diff --git a/source/blender/io/usd/intern/usd_reader_prim.h b/source/blender/io/usd/intern/usd_reader_prim.h
index fdf6247de16..c44c4a14ad7 100644
--- a/source/blender/io/usd/intern/usd_reader_prim.h
+++ b/source/blender/io/usd/intern/usd_reader_prim.h
@@ -7,7 +7,11 @@
#include <pxr/usd/usd/prim.h>
+#include <map>
+#include <string>
+
struct Main;
+struct Material;
struct Object;
namespace blender::io::usd {
@@ -33,6 +37,17 @@ struct ImportSettings {
CacheFile *cache_file;
+ /* Map a USD material prim path to a Blender material name.
+ * This map is updated by readers during stage traversal.
+ * This field is mutable because it is used to keep track
+ * of what the importer is doing. This is necessary even
+ * when all the other import settings are to remain const. */
+ mutable std::map<std::string, std::string> usd_path_to_mat_name;
+ /* Map a material name to Blender material.
+ * This map is updated by readers during stage traversal,
+ * and is mutable similar to the map above. */
+ mutable std::map<std::string, Material *> mat_name_to_mat;
+
ImportSettings()
: do_convert_mat(false),
from_up(0),
diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc
index 857896b9330..6862f3835cf 100644
--- a/source/blender/io/usd/intern/usd_writer_material.cc
+++ b/source/blender/io/usd/intern/usd_writer_material.cc
@@ -590,6 +590,7 @@ static std::string get_tex_image_asset_path(bNode *node,
BLI_split_dir_part(stage_path.c_str(), dir_path, FILE_MAX);
BLI_path_join(exp_path, FILE_MAX, dir_path, "textures", file_path, nullptr);
}
+ BLI_str_replace_char(exp_path, '\\', '/');
return exp_path;
}
@@ -608,7 +609,7 @@ static std::string get_tex_image_asset_path(bNode *node,
if (!BLI_path_is_rel(rel_path)) {
return path;
}
-
+ BLI_str_replace_char(rel_path, '\\', '/');
return rel_path + 2;
}
diff --git a/source/blender/io/usd/intern/usd_writer_volume.cc b/source/blender/io/usd/intern/usd_writer_volume.cc
index 4126be6966a..6300e5c657c 100644
--- a/source/blender/io/usd/intern/usd_writer_volume.cc
+++ b/source/blender/io/usd/intern/usd_writer_volume.cc
@@ -100,7 +100,7 @@ std::optional<std::string> USDVolumeWriter::resolve_vdb_file(const Volume *volum
vdb_file_path = construct_vdb_file_path(volume);
if (!BKE_volume_save(
- volume, usd_export_context_.bmain, NULL, vdb_file_path.value_or("").c_str())) {
+ volume, usd_export_context_.bmain, nullptr, vdb_file_path.value_or("").c_str())) {
return std::nullopt;
}
}
diff --git a/source/blender/io/usd/tests/usd_imaging_test.cc b/source/blender/io/usd/tests/usd_imaging_test.cc
index 497319c59bd..5cd3c042e59 100644
--- a/source/blender/io/usd/tests/usd_imaging_test.cc
+++ b/source/blender/io/usd/tests/usd_imaging_test.cc
@@ -42,8 +42,8 @@ TEST_F(USDImagingTest, CapsuleAdapterTest)
}
pxr::UsdImagingCapsuleAdapter capsule_adapter;
- pxr::VtValue points_value = capsule_adapter.GetMeshPoints(capsule.GetPrim(),
- pxr::UsdTimeCode::Default());
+ pxr::VtValue points_value = pxr::UsdImagingCapsuleAdapter::GetMeshPoints(
+ capsule.GetPrim(), pxr::UsdTimeCode::Default());
if (!points_value.IsHolding<pxr::VtArray<pxr::GfVec3f>>()) {
FAIL() << "Mesh points value holding unexpected type.";
return;
@@ -52,7 +52,7 @@ TEST_F(USDImagingTest, CapsuleAdapterTest)
pxr::VtArray<pxr::GfVec3f> points = points_value.Get<pxr::VtArray<pxr::GfVec3f>>();
EXPECT_FALSE(points.empty());
- pxr::VtValue topology_value = capsule_adapter.GetMeshTopology();
+ pxr::VtValue topology_value = pxr::UsdImagingCapsuleAdapter::GetMeshTopology();
if (!topology_value.IsHolding<pxr::HdMeshTopology>()) {
FAIL() << "Mesh topology value holding unexpected type.";
diff --git a/source/blender/io/usd/tests/usd_tests_common.h b/source/blender/io/usd/tests/usd_tests_common.h
index 7f6ae558354..949348da959 100644
--- a/source/blender/io/usd/tests/usd_tests_common.h
+++ b/source/blender/io/usd/tests/usd_tests_common.h
@@ -12,7 +12,7 @@ namespace blender::io::usd {
* Thus function must be called before instantiating a USD
* stage to avoid errors. The returned string is the path to
* the USD data files directory from which the plugins were
- * loaded. If the USD data files directory can't be determined,
+ * loaded. If the USD data files directory can't be determined,
* plugin registration is skipped and the empty string is
* returned. */
std::string register_usd_plugins_for_tests();
diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h
index 2e4dcb0da94..a07315d8b4e 100644
--- a/source/blender/io/usd/usd.h
+++ b/source/blender/io/usd/usd.h
@@ -15,6 +15,13 @@ struct CacheReader;
struct Object;
struct bContext;
+/* Behavior when the name of an imported material
+ * conflicts with an existing material. */
+typedef enum eUSDMtlNameCollisionMode {
+ USD_MTL_NAME_COLLISION_MAKE_UNIQUE = 0,
+ USD_MTL_NAME_COLLISION_REFERENCE_EXISTING = 1,
+} eUSDMtlNameCollisionMode;
+
struct USDExportParams {
bool export_animation;
bool export_hair;
@@ -57,6 +64,7 @@ struct USDImportParams {
bool import_usd_preview;
bool set_material_blend;
float light_intensity_scale;
+ eUSDMtlNameCollisionMode mtl_name_collision_mode;
};
/* The USD_export takes a as_background_job parameter, and returns a boolean.
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
index bebad06d37f..b4a00deb99c 100644
--- a/source/blender/io/wavefront_obj/IO_wavefront_obj.h
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -9,30 +9,13 @@
#include "BKE_context.h"
#include "BLI_path_util.h"
#include "DEG_depsgraph.h"
+#include "IO_orientation.h"
#include "IO_path_util_types.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 {
@@ -52,8 +35,8 @@ struct OBJExportParams {
int end_frame;
/* Geometry Transform options. */
- eTransformAxisForward forward_axis;
- eTransformAxisUp up_axis;
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
float scaling_factor;
/* File Write Options. */
@@ -62,6 +45,7 @@ struct OBJExportParams {
eEvaluationMode export_eval_mode;
bool export_uv;
bool export_normals;
+ bool export_colors;
bool export_materials;
bool export_triangulated_mesh;
bool export_curves_as_nurbs;
@@ -86,8 +70,9 @@ struct OBJImportParams {
char filepath[FILE_MAX];
/** Value 0 disables clamping. */
float clamp_size;
- eTransformAxisForward forward_axis;
- eTransformAxisUp up_axis;
+ eIOAxis forward_axis;
+ eIOAxis up_axis;
+ bool import_vertex_groups;
bool validate_meshes;
};
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
index 11d1bafdafe..731587bfcea 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -8,7 +8,9 @@
#include <cstdio>
#include "BKE_blender_version.h"
+#include "BKE_geometry_set.hh"
+#include "BLI_color.hh"
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_path_util.h"
#include "BLI_task.hh"
@@ -241,13 +243,37 @@ void obj_parallel_chunked_output(FormatHandler<eFileType::OBJ> &fh,
}
void OBJWriter::write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
- const OBJMesh &obj_mesh_data) const
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const
{
const int tot_count = obj_mesh_data.tot_vertices();
- obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
- float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
- buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
- });
+
+ Mesh *mesh = obj_mesh_data.get_mesh();
+ CustomDataLayer *colors_layer = nullptr;
+ if (write_colors) {
+ colors_layer = BKE_id_attributes_active_color_get(&mesh->id);
+ }
+ if (write_colors && (colors_layer != nullptr)) {
+ const bke::AttributeAccessor attributes = bke::mesh_attributes(*mesh);
+ const VArray<ColorGeometry4f> attribute = attributes.lookup_or_default<ColorGeometry4f>(
+ colors_layer->name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
+
+ BLI_assert(tot_count == attribute.size());
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ ColorGeometry4f linear = attribute.get(i);
+ float srgb[3];
+ linearrgb_to_srgb_v3_v3(srgb, linear);
+ buf.write<eOBJSyntaxElement::vertex_coords_color>(
+ vertex[0], vertex[1], vertex[2], srgb[0], srgb[1], srgb[2]);
+ });
+ }
+ else {
+ obj_parallel_chunked_output(fh, tot_count, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ buf.write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+ });
+ }
}
void OBJWriter::write_uv_coords(FormatHandler<eFileType::OBJ> &fh, OBJMesh &r_obj_mesh_data) const
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
index 77da7b44276..97c23484426 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -72,9 +72,11 @@ class OBJWriter : NonMovable, NonCopyable {
*/
void write_mtllib_name(const StringRefNull mtl_filepath) const;
/**
- * Write vertex coordinates for all vertices as "v x y z".
+ * Write vertex coordinates for all vertices as "v x y z" or "v x y z r g b".
*/
- void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
+ void write_vertex_coords(FormatHandler<eFileType::OBJ> &fh,
+ const OBJMesh &obj_mesh_data,
+ bool write_colors) const;
/**
* Write UV vertex coordinates for all vertices as `vt u v`.
* \note UV indices are stored here, but written with polygons later.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
index f0263989bfc..5413c9969e3 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -30,6 +30,7 @@ enum class eFileType {
enum class eOBJSyntaxElement {
vertex_coords,
+ vertex_coords_color,
uv_vertex_coords,
normal,
poly_element_begin,
@@ -130,6 +131,9 @@ constexpr FormattingSyntax syntax_elem_to_formatting(const eOBJSyntaxElement key
case eOBJSyntaxElement::vertex_coords: {
return {"v {:.6f} {:.6f} {:.6f}\n", 3, is_type_float<T...>};
}
+ case eOBJSyntaxElement::vertex_coords_color: {
+ return {"v {:.6f} {:.6f} {:.6f} {:.4f} {:.4f} {:.4f}\n", 6, is_type_float<T...>};
+ }
case eOBJSyntaxElement::uv_vertex_coords: {
return {"vt {:.6f} {:.6f}\n", 2, is_type_float<T...>};
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
index c2a9e0574eb..e2ecda32717 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -117,15 +117,12 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
return {triangulated, true};
}
-void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward,
- const eTransformAxisUp up)
+void OBJMesh::set_world_axes_transform(const eIOAxis forward, const eIOAxis 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);
+ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, 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]);
@@ -290,7 +287,7 @@ void OBJMesh::store_uv_coords_and_indices()
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 *>(
+ const MLoopUV *mloopuv = static_cast<const MLoopUV *>(
CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
if (!mloopuv) {
tot_uv_vertices_ = 0;
@@ -382,8 +379,8 @@ void OBJMesh::store_normal_coords_and_indices()
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));
+ const float(*lnors)[3] = static_cast<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 = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
@@ -453,7 +450,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int poly_index,
BLI_assert(poly_index < export_mesh_eval_->totpoly);
BLI_assert(group_weights.size() == BKE_object_defgroup_count(&export_object_eval_));
- const MDeformVert *dvert_layer = static_cast<MDeformVert *>(
+ const MDeformVert *dvert_layer = static_cast<const MDeformVert *>(
CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT));
if (!dvert_layer) {
return NOT_FOUND;
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
index f47ca423dbc..ee2e6227700 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -241,6 +241,11 @@ class OBJMesh : NonCopyable {
return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
}
+ Mesh *get_mesh() const
+ {
+ return export_mesh_eval_;
+ }
+
private:
/**
* Free the mesh if _the exporter_ created it.
@@ -256,6 +261,6 @@ class OBJMesh : NonCopyable {
/**
* Set the final transform after applying axes settings and an Object's world transform.
*/
- void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+ void set_world_axes_transform(eIOAxis forward, eIOAxis up);
};
} // 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
index c247048ce13..172a59e5341 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
@@ -25,15 +25,12 @@ OBJCurve::OBJCurve(const Depsgraph *depsgraph,
set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
}
-void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward,
- const eTransformAxisUp up)
+void OBJCurve::set_world_axes_transform(const eIOAxis forward, const eIOAxis 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);
+ mat3_from_axis_conversion(forward, up, IO_AXIS_Y, IO_AXIS_Z, 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]);
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
index fe826725daf..65389d44f59 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
@@ -56,7 +56,7 @@ class OBJCurve : NonCopyable {
/**
* Set the final transform after applying axes settings and an Object's world transform.
*/
- void set_world_axes_transform(eTransformAxisForward forward, eTransformAxisUp up);
+ void set_world_axes_transform(eIOAxis forward, eIOAxis 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
index b6e636b389d..77d4f6268bc 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -195,7 +195,7 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
auto &fh = buffers[i];
obj_writer.write_object_name(fh, obj);
- obj_writer.write_vertex_coords(fh, obj);
+ obj_writer.write_vertex_coords(fh, obj, export_params.export_colors);
if (obj.tot_polygons() > 0) {
if (export_params.export_smooth_groups) {
@@ -323,7 +323,7 @@ void exporter_main(bContext *C, const OBJExportParams &export_params)
char filepath_with_frames[FILE_MAX];
/* Used to reset the Scene to its original state. */
- const int original_frame = CFRA;
+ const int original_frame = scene->r.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);
@@ -332,11 +332,11 @@ void exporter_main(bContext *C, const OBJExportParams &export_params)
return;
}
- CFRA = frame;
+ scene->r.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;
+ scene->r.cfra = original_frame;
}
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
index 7019e67419e..f33753d720d 100644
--- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
+++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc
@@ -99,13 +99,8 @@ void transform_object(Object *object, const OBJImportParams &import_params)
float obmat[4][4];
unit_m4(obmat);
/* +Y-forward and +Z-up are the default Blender axis settings. */
- mat3_from_axis_conversion(import_params.forward_axis,
- import_params.up_axis,
- OBJ_AXIS_Y_FORWARD,
- OBJ_AXIS_Z_UP,
- axes_transform);
- /* mat3_from_axis_conversion returns a transposed matrix! */
- transpose_m3(axes_transform);
+ mat3_from_axis_conversion(
+ IO_AXIS_Y, IO_AXIS_Z, import_params.forward_axis, import_params.up_axis, axes_transform);
copy_m4_m3(obmat, axes_transform);
BKE_object_apply_mat4(object, obmat, true, false);
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
index c7990028312..a32fd90594d 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_file_reader.cc
@@ -5,12 +5,16 @@
*/
#include "BLI_map.hh"
+#include "BLI_math_color.h"
+#include "BLI_math_vector.h"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
#include "obj_import_file_reader.hh"
#include "obj_import_string_utils.hh"
+#include <charconv>
+
namespace blender::io::obj {
using std::string;
@@ -18,31 +22,24 @@ using std::string;
/**
* Based on the properties of the given Geometry instance, create a new Geometry instance
* or return the previous one.
- *
- * Also update index offsets which should always happen if a new Geometry instance is created.
*/
static Geometry *create_geometry(Geometry *const prev_geometry,
const eGeometryType new_type,
StringRef name,
- const GlobalVertices &global_vertices,
- Vector<std::unique_ptr<Geometry>> &r_all_geometries,
- VertexIndexOffset &r_offset)
+ Vector<std::unique_ptr<Geometry>> &r_all_geometries)
{
auto new_geometry = [&]() {
r_all_geometries.append(std::make_unique<Geometry>());
Geometry *g = r_all_geometries.last().get();
g->geom_type_ = new_type;
g->geometry_name_ = name.is_empty() ? "New object" : name;
- g->vertex_start_ = global_vertices.vertices.size();
- r_offset.set_index_offset(g->vertex_start_);
return g;
};
if (prev_geometry && prev_geometry->geom_type_ == GEOM_MESH) {
/* After the creation of a Geometry instance, at least one element has been found in the OBJ
- * file that indicates that it is a mesh (basically anything but the vertex positions). */
- if (!prev_geometry->face_elements_.is_empty() || prev_geometry->has_vertex_normals_ ||
- !prev_geometry->edges_.is_empty()) {
+ * file that indicates that it is a mesh (faces or edges). */
+ if (!prev_geometry->face_elements_.is_empty() || !prev_geometry->edges_.is_empty()) {
return new_geometry();
}
if (new_type == GEOM_MESH) {
@@ -65,26 +62,85 @@ static Geometry *create_geometry(Geometry *const prev_geometry,
return new_geometry();
}
-static void geom_add_vertex(Geometry *geom,
- const char *p,
- const char *end,
- GlobalVertices &r_global_vertices)
+static void geom_add_vertex(const char *p, const char *end, GlobalVertices &r_global_vertices)
{
float3 vert;
- parse_floats(p, end, 0.0f, vert, 3);
+ p = parse_floats(p, end, 0.0f, vert, 3);
r_global_vertices.vertices.append(vert);
- geom->vertex_count_++;
+ /* OBJ extension: `xyzrgb` vertex colors, when the vertex position
+ * is followed by 3 more RGB color components. See
+ * http://paulbourke.net/dataformats/obj/colour.html */
+ if (p < end) {
+ float3 srgb;
+ p = parse_floats(p, end, -1.0f, srgb, 3);
+ if (srgb.x >= 0 && srgb.y >= 0 && srgb.z >= 0) {
+ float3 linear;
+ srgb_to_linearrgb_v3_v3(linear, srgb);
+
+ auto &blocks = r_global_vertices.vertex_colors;
+ /* If we don't have vertex colors yet, or the previous vertex
+ * was without color, we need to start a new vertex colors block. */
+ if (blocks.is_empty() || (blocks.last().start_vertex_index + blocks.last().colors.size() !=
+ r_global_vertices.vertices.size() - 1)) {
+ GlobalVertices::VertexColorsBlock block;
+ block.start_vertex_index = r_global_vertices.vertices.size() - 1;
+ blocks.append(block);
+ }
+ blocks.last().colors.append(linear);
+ }
+ }
+}
+
+static void geom_add_mrgb_colors(const char *p, const char *end, GlobalVertices &r_global_vertices)
+{
+ /* MRGB color extension, in the form of
+ * "#MRGB MMRRGGBBMMRRGGBB ..."
+ * http://paulbourke.net/dataformats/obj/colour.html */
+ p = drop_whitespace(p, end);
+ const int mrgb_length = 8;
+ while (p + mrgb_length <= end) {
+ uint32_t value = 0;
+ std::from_chars_result res = std::from_chars(p, p + mrgb_length, value, 16);
+ if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
+ return;
+ }
+ unsigned char srgb[4];
+ srgb[0] = (value >> 16) & 0xFF;
+ srgb[1] = (value >> 8) & 0xFF;
+ srgb[2] = value & 0xFF;
+ srgb[3] = 0xFF;
+ float linear[4];
+ srgb_to_linearrgb_uchar4(linear, srgb);
+
+ auto &blocks = r_global_vertices.vertex_colors;
+ /* If we don't have vertex colors yet, or the previous vertex
+ * was without color, we need to start a new vertex colors block. */
+ if (blocks.is_empty() || (blocks.last().start_vertex_index + blocks.last().colors.size() !=
+ r_global_vertices.vertices.size())) {
+ GlobalVertices::VertexColorsBlock block;
+ block.start_vertex_index = r_global_vertices.vertices.size();
+ blocks.append(block);
+ }
+ blocks.last().colors.append({linear[0], linear[1], linear[2]});
+ /* MRGB colors are specified after vertex positions; each new color
+ * "pushes" the vertex colors block further back into which vertices it is for. */
+ blocks.last().start_vertex_index--;
+
+ p += mrgb_length;
+ }
}
-static void geom_add_vertex_normal(Geometry *geom,
- const char *p,
+static void geom_add_vertex_normal(const char *p,
const char *end,
GlobalVertices &r_global_vertices)
{
float3 normal;
parse_floats(p, end, 0.0f, normal, 3);
+ /* Normals can be printed with only several digits in the file,
+ * making them ever-so-slightly non unit length. Make sure they are
+ * normalized. */
+ normalize_v3(normal);
r_global_vertices.vertex_normals.append(normal);
- geom->has_vertex_normals_ = true;
}
static void geom_add_uv_vertex(const char *p, const char *end, GlobalVertices &r_global_vertices)
@@ -97,24 +153,24 @@ static void geom_add_uv_vertex(const char *p, const char *end, GlobalVertices &r
static void geom_add_edge(Geometry *geom,
const char *p,
const char *end,
- const VertexIndexOffset &offsets,
GlobalVertices &r_global_vertices)
{
int edge_v1, edge_v2;
p = parse_int(p, end, -1, edge_v1);
p = parse_int(p, end, -1, edge_v2);
/* Always keep stored indices non-negative and zero-based. */
- edge_v1 += edge_v1 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1;
- edge_v2 += edge_v2 < 0 ? r_global_vertices.vertices.size() : -offsets.get_index_offset() - 1;
+ edge_v1 += edge_v1 < 0 ? r_global_vertices.vertices.size() : -1;
+ edge_v2 += edge_v2 < 0 ? r_global_vertices.vertices.size() : -1;
BLI_assert(edge_v1 >= 0 && edge_v2 >= 0);
geom->edges_.append({static_cast<uint>(edge_v1), static_cast<uint>(edge_v2)});
+ geom->track_vertex_index(edge_v1);
+ geom->track_vertex_index(edge_v2);
}
static void geom_add_polygon(Geometry *geom,
const char *p,
const char *end,
const GlobalVertices &global_vertices,
- const VertexIndexOffset &offsets,
const int material_index,
const int group_index,
const bool shaded_smooth)
@@ -124,7 +180,7 @@ static void geom_add_polygon(Geometry *geom,
curr_face.material_index = material_index;
if (group_index >= 0) {
curr_face.vertex_group_index = group_index;
- geom->use_vertex_groups_ = true;
+ geom->has_vertex_groups_ = true;
}
const int orig_corners_size = geom->face_corners_.size();
@@ -149,12 +205,11 @@ static void geom_add_polygon(Geometry *geom,
if (p < end && *p == '/') {
++p;
p = parse_int(p, end, INT32_MAX, corner.vertex_normal_index, false);
- got_normal = corner.uv_vert_index != INT32_MAX;
+ got_normal = corner.vertex_normal_index != INT32_MAX;
}
}
/* Always keep stored indices non-negative and zero-based. */
- corner.vert_index += corner.vert_index < 0 ? global_vertices.vertices.size() :
- -offsets.get_index_offset() - 1;
+ corner.vert_index += corner.vert_index < 0 ? global_vertices.vertices.size() : -1;
if (corner.vert_index < 0 || corner.vert_index >= global_vertices.vertices.size()) {
fprintf(stderr,
"Invalid vertex index %i (valid range [0, %zu)), ignoring face\n",
@@ -162,6 +217,9 @@ static void geom_add_polygon(Geometry *geom,
(size_t)global_vertices.vertices.size());
face_valid = false;
}
+ else {
+ geom->track_vertex_index(corner.vert_index);
+ }
if (got_uv) {
corner.uv_vert_index += corner.uv_vert_index < 0 ? global_vertices.uv_vertices.size() : -1;
if (corner.uv_vert_index < 0 || corner.uv_vert_index >= global_vertices.uv_vertices.size()) {
@@ -172,7 +230,10 @@ static void geom_add_polygon(Geometry *geom,
face_valid = false;
}
}
- if (got_normal) {
+ /* Ignore corner normal index, if the geometry does not have any normals.
+ * Some obj files out there do have face definitions that refer to normal indices,
+ * without any normals being present (T98782). */
+ if (got_normal && !global_vertices.vertex_normals.is_empty()) {
corner.vertex_normal_index += corner.vertex_normal_index < 0 ?
global_vertices.vertex_normals.size() :
-1;
@@ -206,9 +267,7 @@ static void geom_add_polygon(Geometry *geom,
static Geometry *geom_set_curve_type(Geometry *geom,
const char *p,
const char *end,
- const GlobalVertices &global_vertices,
const StringRef group_name,
- VertexIndexOffset &r_offsets,
Vector<std::unique_ptr<Geometry>> &r_all_geometries)
{
p = drop_whitespace(p, end);
@@ -216,8 +275,7 @@ static Geometry *geom_set_curve_type(Geometry *geom,
std::cerr << "Curve type not supported: '" << std::string(p, end) << "'" << std::endl;
return geom;
}
- geom = create_geometry(
- geom, GEOM_CURVE, group_name, global_vertices, r_all_geometries, r_offsets);
+ geom = create_geometry(geom, GEOM_CURVE, group_name, r_all_geometries);
geom->nurbs_element_.group_ = group_name;
return geom;
}
@@ -343,9 +401,12 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
return;
}
- VertexIndexOffset offsets;
- Geometry *curr_geom = create_geometry(
- nullptr, GEOM_MESH, "", r_global_vertices, r_all_geometries, offsets);
+ /* Use the filename as the default name given to the initial object. */
+ char ob_name[FILE_MAXFILE];
+ BLI_strncpy(ob_name, BLI_path_basename(import_params_.filepath), FILE_MAXFILE);
+ BLI_path_extension_replace(ob_name, FILE_MAXFILE, "");
+
+ Geometry *curr_geom = create_geometry(nullptr, GEOM_MESH, ob_name, r_all_geometries);
/* State variables: once set, they remain the same for the remaining
* elements in the object. */
@@ -368,6 +429,11 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
break; /* No more data to read. */
}
+ /* Take care of line continuations now (turn them into spaces);
+ * the rest of the parsing code does not need to worry about them anymore. */
+ fixup_line_continuations(buffer.data() + buffer_offset,
+ buffer.data() + buffer_offset + bytes_read);
+
/* Ensure buffer ends in a newline. */
if (bytes_read < read_buffer_size_) {
if (bytes_read == 0 || buffer[buffer_offset + bytes_read - 1] != '\n') {
@@ -386,9 +452,7 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
while (last_nl > 0) {
--last_nl;
if (buffer[last_nl] == '\n') {
- if (last_nl < 1 || buffer[last_nl - 1] != '\\') {
- break;
- }
+ break;
}
}
if (buffer[last_nl] != '\n') {
@@ -415,10 +479,10 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
/* Most common things that start with 'v': vertices, normals, UVs. */
if (*p == 'v') {
if (parse_keyword(p, end, "v")) {
- geom_add_vertex(curr_geom, p, end, r_global_vertices);
+ geom_add_vertex(p, end, r_global_vertices);
}
else if (parse_keyword(p, end, "vn")) {
- geom_add_vertex_normal(curr_geom, p, end, r_global_vertices);
+ geom_add_vertex_normal(p, end, r_global_vertices);
}
else if (parse_keyword(p, end, "vt")) {
geom_add_uv_vertex(p, end, r_global_vertices);
@@ -430,26 +494,21 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
p,
end,
r_global_vertices,
- offsets,
state_material_index,
- state_group_index, /* TODO was wrongly material name! */
+ state_group_index,
state_shaded_smooth);
}
/* Faces. */
else if (parse_keyword(p, end, "l")) {
- geom_add_edge(curr_geom, p, end, offsets, r_global_vertices);
+ geom_add_edge(curr_geom, p, end, r_global_vertices);
}
/* Objects. */
else if (parse_keyword(p, end, "o")) {
state_shaded_smooth = false;
state_group_name = "";
state_material_name = "";
- curr_geom = create_geometry(curr_geom,
- GEOM_MESH,
- StringRef(p, end).trim(),
- r_global_vertices,
- r_all_geometries,
- offsets);
+ curr_geom = create_geometry(
+ curr_geom, GEOM_MESH, StringRef(p, end).trim(), r_all_geometries);
}
/* Groups. */
else if (parse_keyword(p, end, "g")) {
@@ -477,14 +536,16 @@ void OBJParser::parse(Vector<std::unique_ptr<Geometry>> &r_all_geometries,
else if (parse_keyword(p, end, "mtllib")) {
add_mtl_library(StringRef(p, end).trim());
}
+ else if (parse_keyword(p, end, "#MRGB")) {
+ geom_add_mrgb_colors(p, end, r_global_vertices);
+ }
/* Comments. */
else if (*p == '#') {
/* Nothing to do. */
}
/* Curve related things. */
else if (parse_keyword(p, end, "cstype")) {
- curr_geom = geom_set_curve_type(
- curr_geom, p, end, r_global_vertices, state_group_name, offsets, r_all_geometries);
+ curr_geom = geom_set_curve_type(curr_geom, p, end, state_group_name, r_all_geometries);
}
else if (parse_keyword(p, end, "deg")) {
geom_set_curve_degree(curr_geom, p, end);
@@ -564,15 +625,15 @@ static bool parse_texture_option(const char *&p,
{
p = drop_whitespace(p, end);
if (parse_keyword(p, end, "-o")) {
- p = parse_floats(p, end, 0.0f, tex_map.translation, 3);
+ p = parse_floats(p, end, 0.0f, tex_map.translation, 3, true);
return true;
}
if (parse_keyword(p, end, "-s")) {
- p = parse_floats(p, end, 1.0f, tex_map.scale, 3);
+ p = parse_floats(p, end, 1.0f, tex_map.scale, 3, true);
return true;
}
if (parse_keyword(p, end, "-bm")) {
- p = parse_float(p, end, 1.0f, material->map_Bump_strength);
+ p = parse_float(p, end, 1.0f, material->map_Bump_strength, true, true);
return true;
}
if (parse_keyword(p, end, "-type")) {
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
index 8d560bd2c8c..01f05466b3a 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc
@@ -8,7 +8,9 @@
#include "DNA_mesh_types.h"
#include "DNA_scene_types.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
+#include "BKE_deform.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node_tree_update.h"
@@ -29,13 +31,17 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
Map<std::string, Material *> &created_materials,
const OBJImportParams &import_params)
{
+ const int64_t tot_verts_object{mesh_geometry_.get_vertex_count()};
+ if (tot_verts_object <= 0) {
+ /* Empty mesh */
+ return nullptr;
+ }
std::string ob_name{mesh_geometry_.geometry_name_};
if (ob_name.empty()) {
ob_name = "Untitled";
}
fixup_invalid_faces();
- const int64_t tot_verts_object{mesh_geometry_.vertex_count_};
/* Total explicitly imported edges, not the ones belonging the polygons to be created. */
const int64_t tot_edges{mesh_geometry_.edges_.size()};
const int64_t tot_face_elems{mesh_geometry_.face_elements_.size()};
@@ -46,10 +52,11 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
obj->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, ob_name.c_str());
create_vertices(mesh);
- create_polys_loops(obj, mesh);
+ create_polys_loops(mesh, import_params.import_vertex_groups);
create_edges(mesh);
create_uv_verts(mesh);
create_normals(mesh);
+ create_colors(mesh);
create_materials(bmain, materials, created_materials, obj);
if (import_params.validate_meshes || mesh_geometry_.has_invalid_polys_) {
@@ -67,6 +74,9 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
BKE_mesh_nomain_to_mesh(mesh, dst, obj, &CD_MASK_EVERYTHING, true);
dst->flag |= autosmooth;
+ /* NOTE: vertex groups have to be created after final mesh is assigned to the object. */
+ create_vertex_groups(obj);
+
return obj;
}
@@ -147,9 +157,9 @@ void MeshFromGeometry::fixup_invalid_faces()
void MeshFromGeometry::create_vertices(Mesh *mesh)
{
- const int tot_verts_object{mesh_geometry_.vertex_count_};
+ const int tot_verts_object{mesh_geometry_.get_vertex_count()};
for (int i = 0; i < tot_verts_object; ++i) {
- int vi = mesh_geometry_.vertex_start_ + i;
+ int vi = mesh_geometry_.vertex_index_min_ + i;
if (vi < global_vertices_.vertices.size()) {
copy_v3_v3(mesh->mvert[i].co, global_vertices_.vertices[vi]);
}
@@ -161,19 +171,13 @@ void MeshFromGeometry::create_vertices(Mesh *mesh)
}
}
-void MeshFromGeometry::create_polys_loops(Object *obj, Mesh *mesh)
+void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
{
- /* Will not be used if vertex groups are not imported. */
mesh->dvert = nullptr;
- float weight = 0.0f;
- const int64_t total_verts = mesh_geometry_.vertex_count_;
- if (total_verts && mesh_geometry_.use_vertex_groups_) {
+ const int64_t total_verts = mesh_geometry_.get_vertex_count();
+ if (use_vertex_groups && total_verts && mesh_geometry_.has_vertex_groups_) {
mesh->dvert = static_cast<MDeformVert *>(
CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, nullptr, total_verts));
- weight = 1.0f / total_verts;
- }
- else {
- UNUSED_VARS(weight);
}
const int64_t tot_face_elems{mesh->totpoly};
@@ -204,30 +208,25 @@ void MeshFromGeometry::create_polys_loops(Object *obj, Mesh *mesh)
const PolyCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
MLoop &mloop = mesh->mloop[tot_loop_idx];
tot_loop_idx++;
- mloop.v = curr_corner.vert_index;
+ mloop.v = curr_corner.vert_index - mesh_geometry_.vertex_index_min_;
+ /* Setup vertex group data, if needed. */
if (!mesh->dvert) {
continue;
}
- /* Iterating over mloop results in finding the same vertex multiple times.
- * Another way is to allocate memory for dvert while creating vertices and fill them here.
- */
- MDeformVert &def_vert = mesh->dvert[mloop.v];
- if (!def_vert.dw) {
- def_vert.dw = static_cast<MDeformWeight *>(
- MEM_callocN(sizeof(MDeformWeight), "OBJ Import Deform Weight"));
- }
- /* Every vertex in a face is assigned the same deform group. */
- int group_idx = curr_face.vertex_group_index;
- /* Deform group number (def_nr) must behave like an index into the names' list. */
- *(def_vert.dw) = {static_cast<unsigned int>(group_idx), weight};
+ const int group_index = curr_face.vertex_group_index;
+ MDeformWeight *dw = BKE_defvert_ensure_index(mesh->dvert + mloop.v, group_index);
+ dw->weight = 1.0f;
}
}
+}
- if (!mesh->dvert) {
+void MeshFromGeometry::create_vertex_groups(Object *obj)
+{
+ Mesh *mesh = static_cast<Mesh *>(obj->data);
+ if (mesh->dvert == nullptr) {
return;
}
- /* Add deform group names. */
for (const std::string &name : mesh_geometry_.group_order_) {
BKE_object_defgroup_add_name(obj, name.data());
}
@@ -236,14 +235,14 @@ void MeshFromGeometry::create_polys_loops(Object *obj, Mesh *mesh)
void MeshFromGeometry::create_edges(Mesh *mesh)
{
const int64_t tot_edges{mesh_geometry_.edges_.size()};
- const int64_t total_verts{mesh_geometry_.vertex_count_};
+ const int64_t total_verts{mesh_geometry_.get_vertex_count()};
UNUSED_VARS_NDEBUG(total_verts);
for (int i = 0; i < tot_edges; ++i) {
const MEdge &src_edge = mesh_geometry_.edges_[i];
MEdge &dst_edge = mesh->medge[i];
- BLI_assert(src_edge.v1 < total_verts && src_edge.v2 < total_verts);
- dst_edge.v1 = src_edge.v1;
- dst_edge.v2 = src_edge.v2;
+ dst_edge.v1 = src_edge.v1 - mesh_geometry_.vertex_index_min_;
+ dst_edge.v2 = src_edge.v2 - mesh_geometry_.vertex_index_min_;
+ BLI_assert(dst_edge.v1 < total_verts && dst_edge.v2 < total_verts);
dst_edge.flag = ME_LOOSEEDGE;
}
@@ -289,7 +288,7 @@ static Material *get_or_create_material(Main *bmain,
/* We have not, will have to create it. Create a new default
* MTLMaterial too, in case the OBJ file tries to use a material
* that was not in the MTL file. */
- const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>()).get();
+ const MTLMaterial &mtl = *materials.lookup_or_add(name, std::make_unique<MTLMaterial>());
Material *mat = BKE_material_add(bmain, name.c_str());
ShaderNodetreeWrap mat_wrap{bmain, mtl, mat};
@@ -311,17 +310,14 @@ void MeshFromGeometry::create_materials(Main *bmain,
if (mat == nullptr) {
continue;
}
- BKE_object_material_slot_add(bmain, obj);
- BKE_object_material_assign(bmain, obj, mat, obj->totcol, BKE_MAT_ASSIGN_USERPREF);
+ BKE_object_material_assign_single_obdata(bmain, obj, mat, obj->totcol + 1);
}
}
void MeshFromGeometry::create_normals(Mesh *mesh)
{
- /* NOTE: Needs more clarity about what is expected in the viewport if the function works. */
-
/* No normal data: nothing to do. */
- if (global_vertices_.vertex_normals.is_empty() || !mesh_geometry_.has_vertex_normals_) {
+ if (global_vertices_.vertex_normals.is_empty()) {
return;
}
@@ -345,4 +341,29 @@ void MeshFromGeometry::create_normals(Mesh *mesh)
MEM_freeN(loop_normals);
}
+void MeshFromGeometry::create_colors(Mesh *mesh)
+{
+ /* Nothing to do if we don't have vertex colors at all. */
+ if (global_vertices_.vertex_colors.is_empty()) {
+ return;
+ }
+
+ /* Find which vertex color block is for this mesh (if any). */
+ for (const auto &block : global_vertices_.vertex_colors) {
+ if (mesh_geometry_.vertex_index_min_ >= block.start_vertex_index &&
+ mesh_geometry_.vertex_index_max_ < block.start_vertex_index + block.colors.size()) {
+ /* This block is suitable, use colors from it. */
+ CustomDataLayer *color_layer = BKE_id_attribute_new(
+ &mesh->id, "Color", CD_PROP_COLOR, ATTR_DOMAIN_POINT, nullptr);
+ float4 *colors = (float4 *)color_layer->data;
+ int offset = mesh_geometry_.vertex_index_min_ - block.start_vertex_index;
+ for (int i = 0, n = mesh_geometry_.get_vertex_count(); i != n; ++i) {
+ float3 c = block.colors[offset + i];
+ colors[i] = float4(c.x, c.y, c.z, 1.0f);
+ }
+ return;
+ }
+ }
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
index cf4a2aee394..591a7b81e63 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.hh
@@ -45,10 +45,9 @@ class MeshFromGeometry : NonMovable, NonCopyable {
void fixup_invalid_faces();
void create_vertices(Mesh *mesh);
/**
- * Create polygons for the Mesh, set smooth shading flags, deform group names,
- * Materials.
+ * Create polygons for the Mesh, set smooth shading flags, Materials.
*/
- void create_polys_loops(Object *obj, Mesh *mesh);
+ void create_polys_loops(Mesh *mesh, bool use_vertex_groups);
/**
* Add explicitly imported OBJ edges to the mesh.
*/
@@ -65,6 +64,8 @@ class MeshFromGeometry : NonMovable, NonCopyable {
Map<std::string, Material *> &created_materials,
Object *obj);
void create_normals(Mesh *mesh);
+ void create_colors(Mesh *mesh);
+ void create_vertex_groups(Object *obj);
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
index f39def0a4af..60e419728f3 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
@@ -320,7 +320,7 @@ void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat)
if (alpha != -1) {
set_property_of_socket(SOCK_FLOAT, "Alpha", {alpha}, bsdf_);
}
- if (do_tranparency) {
+ if (do_tranparency || (alpha >= 0.0f && alpha < 1.0f)) {
mat->blend_method = MA_BM_BLEND;
}
}
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
index b67ba46af03..9f0079d7c53 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_objects.hh
@@ -19,34 +19,24 @@
namespace blender::io::obj {
/**
- * List of all vertex and UV vertex coordinates in an OBJ file accessible to any
- * Geometry instance at any time.
+ * All vertex positions, normals, UVs, colors in the OBJ file.
*/
struct GlobalVertices {
Vector<float3> vertices;
Vector<float2> uv_vertices;
Vector<float3> vertex_normals;
-};
-
-/**
- * Keeps track of the vertices that belong to other Geometries.
- * Needed only for MLoop.v and MEdge.v1 which needs vertex indices ranging from (0 to total
- * vertices in the mesh) as opposed to the other OBJ indices ranging from (0 to total vertices
- * in the global list).
- */
-struct VertexIndexOffset {
- private:
- int offset_ = 0;
- public:
- void set_index_offset(const int64_t total_vertices)
- {
- offset_ = total_vertices;
- }
- int64_t get_index_offset() const
- {
- return offset_;
- }
+ /**
+ * Vertex colors might not be present in the file at all, or only
+ * provided for some meshes. Store them in chunks as they are
+ * spelled out in the file, e.g. if there are 10 vertices in sequence, all
+ * with `xyzrgb` colors, they will be one block.
+ */
+ struct VertexColorsBlock {
+ Vector<float3> colors;
+ int start_vertex_index;
+ };
+ Vector<VertexColorsBlock> vertex_colors;
};
/**
@@ -100,8 +90,8 @@ struct Geometry {
Map<std::string, int> material_indices_;
Vector<std::string> material_order_;
- int vertex_start_ = 0;
- int vertex_count_ = 0;
+ int vertex_index_min_ = INT_MAX;
+ int vertex_index_max_ = -1;
/** Edges written in the file in addition to (or even without polygon) elements. */
Vector<MEdge> edges_;
@@ -109,10 +99,21 @@ struct Geometry {
Vector<PolyElem> face_elements_;
bool has_invalid_polys_ = false;
- bool has_vertex_normals_ = false;
- bool use_vertex_groups_ = false;
+ bool has_vertex_groups_ = false;
NurbsElement nurbs_element_;
int total_loops_ = 0;
+
+ int get_vertex_count() const
+ {
+ if (vertex_index_max_ < vertex_index_min_)
+ return 0;
+ return vertex_index_max_ - vertex_index_min_ + 1;
+ }
+ void track_vertex_index(int index)
+ {
+ vertex_index_min_ = std::min(vertex_index_min_, index);
+ vertex_index_max_ = std::max(vertex_index_max_, index);
+ }
};
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc
index c8eaa046e68..9a457167fca 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.cc
@@ -18,14 +18,12 @@ StringRef read_next_line(StringRef &buffer)
const char *start = buffer.begin();
const char *end = buffer.end();
size_t len = 0;
- char prev = 0;
const char *ptr = start;
while (ptr < end) {
char c = *ptr++;
- if (c == '\n' && prev != '\\') {
+ if (c == '\n') {
break;
}
- prev = c;
++len;
}
@@ -35,7 +33,27 @@ StringRef read_next_line(StringRef &buffer)
static bool is_whitespace(char c)
{
- return c <= ' ' || c == '\\';
+ return c <= ' ';
+}
+
+void fixup_line_continuations(char *p, char *end)
+{
+ while (true) {
+ /* Find next backslash, if any. */
+ char *backslash = std::find(p, end, '\\');
+ if (backslash == end)
+ break;
+ /* Skip over possible whitespace right after it. */
+ p = backslash + 1;
+ while (p < end && is_whitespace(*p) && *p != '\n')
+ ++p;
+ /* If then we have a newline, turn both backslash
+ * and the newline into regular spaces. */
+ if (p < end && *p == '\n') {
+ *backslash = ' ';
+ *p = ' ';
+ }
+ }
}
const char *drop_whitespace(const char *p, const char *end)
@@ -62,8 +80,12 @@ static const char *drop_plus(const char *p, const char *end)
return p;
}
-const char *parse_float(
- const char *p, const char *end, float fallback, float &dst, bool skip_space)
+const char *parse_float(const char *p,
+ const char *end,
+ float fallback,
+ float &dst,
+ bool skip_space,
+ bool require_trailing_space)
{
if (skip_space) {
p = drop_whitespace(p, end);
@@ -73,13 +95,23 @@ const char *parse_float(
if (res.ec == std::errc::invalid_argument || res.ec == std::errc::result_out_of_range) {
dst = fallback;
}
+ else if (require_trailing_space && res.ptr < end && !is_whitespace(*res.ptr)) {
+ /* If there are trailing non-space characters, do not eat up the number. */
+ dst = fallback;
+ return p;
+ }
return res.ptr;
}
-const char *parse_floats(const char *p, const char *end, float fallback, float *dst, int count)
+const char *parse_floats(const char *p,
+ const char *end,
+ float fallback,
+ float *dst,
+ int count,
+ bool require_trailing_space)
{
for (int i = 0; i < count; ++i) {
- p = parse_float(p, end, fallback, dst[i]);
+ p = parse_float(p, end, fallback, dst[i], true, require_trailing_space);
}
return p;
}
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh
index 3f428b1ab5c..e42f5080d25 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh
+++ b/source/blender/io/wavefront_obj/importer/obj_import_string_utils.hh
@@ -6,9 +6,6 @@
/*
* Various text parsing utilities used by OBJ importer.
- * The utilities are not directly usable by other formats, since
- * they treat backslash (\) as a whitespace character (OBJ format
- * allows backslashes to function as a line-continuation character).
*
* Many of these functions take two pointers (p, end) indicating
* which part of a string to operate on, and return a possibly
@@ -27,21 +24,22 @@ namespace blender::io::obj {
* The returned line will not have '\n' characters at the end;
* the `buffer` is modified to contain remaining text without
* the input line.
- *
- * Note that backslash (\) character is treated as a line
- * continuation.
*/
StringRef read_next_line(StringRef &buffer);
/**
+ * Fix up OBJ line continuations by replacing backslash (\) and the
+ * following newline with spaces.
+ */
+void fixup_line_continuations(char *p, char *end);
+
+/**
* Drop leading white-space from a string part.
- * Note that backslash character is considered white-space.
*/
const char *drop_whitespace(const char *p, const char *end);
/**
* Drop leading non-white-space from a string part.
- * Note that backslash character is considered white-space.
*/
const char *drop_non_whitespace(const char *p, const char *end);
@@ -62,12 +60,17 @@ const char *parse_int(
* The parsed result is stored in `dst`. The function skips
* leading white-space unless `skip_space=false`. If the
* number can't be parsed (invalid syntax, out of range),
- * `fallback` value is stored instead.
+ * `fallback` value is stored instead. If `require_trailing_space`
+ * is true, the character after the number has to be whitespace.
*
* Returns the start of remainder of the input string after parsing.
*/
-const char *parse_float(
- const char *p, const char *end, float fallback, float &dst, bool skip_space = true);
+const char *parse_float(const char *p,
+ const char *end,
+ float fallback,
+ float &dst,
+ bool skip_space = true,
+ bool require_trailing_space = false);
/**
* Parse a number of white-space separated floats from an input string.
@@ -77,6 +80,11 @@ const char *parse_float(
*
* Returns the start of remainder of the input string after parsing.
*/
-const char *parse_floats(const char *p, const char *end, float fallback, float *dst, int count);
+const char *parse_floats(const char *p,
+ const char *end,
+ float fallback,
+ float *dst,
+ int count,
+ bool require_trailing_space = false);
} // 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
index 8c49af90a82..6aec848573f 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -315,8 +315,8 @@ TEST_F(obj_exporter_regression_test, all_quads)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params);
@@ -325,8 +325,8 @@ TEST_F(obj_exporter_regression_test, fgons)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params);
@@ -335,8 +335,8 @@ TEST_F(obj_exporter_regression_test, edges)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden(
"io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params);
@@ -355,8 +355,8 @@ TEST_F(obj_exporter_regression_test, non_uniform_scale)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = true;
compare_obj_export_to_golden(
@@ -366,8 +366,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_nurbs)
TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = true;
compare_obj_export_to_golden("io_tests/blend_geometry/nurbs_curves.blend",
@@ -379,8 +379,8 @@ TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_curves_as_nurbs = false;
compare_obj_export_to_golden(
@@ -390,8 +390,8 @@ TEST_F(obj_exporter_regression_test, nurbs_as_mesh)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_triangulated_mesh = true;
compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend",
@@ -403,8 +403,8 @@ TEST_F(obj_exporter_regression_test, cube_all_data_triangulated)
TEST_F(obj_exporter_regression_test, cube_normal_edit)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
compare_obj_export_to_golden("io_tests/blend_geometry/cube_normal_edit.blend",
"io_tests/obj/cube_normal_edit.obj",
@@ -436,6 +436,19 @@ TEST_F(obj_exporter_regression_test, cubes_positioned)
_export.params);
}
+TEST_F(obj_exporter_regression_test, cubes_vertex_colors)
+{
+ OBJExportParamsDefault _export;
+ _export.params.export_colors = true;
+ _export.params.export_normals = false;
+ _export.params.export_uv = false;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cubes_vertex_colors.blend",
+ "io_tests/obj/cubes_vertex_colors.obj",
+ "",
+ _export.params);
+}
+
TEST_F(obj_exporter_regression_test, cubes_with_textures_strip)
{
OBJExportParamsDefault _export;
@@ -459,8 +472,8 @@ TEST_F(obj_exporter_regression_test, cubes_with_textures_relative)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_materials = false;
_export.params.export_smooth_groups = true;
compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend",
@@ -491,9 +504,10 @@ TEST_F(obj_exporter_regression_test, all_curves_as_nurbs)
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.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_smooth_groups = true;
+ _export.params.export_colors = 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",
@@ -503,8 +517,8 @@ TEST_F(obj_exporter_regression_test, all_objects)
TEST_F(obj_exporter_regression_test, all_objects_mat_groups)
{
OBJExportParamsDefault _export;
- _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
- _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.forward_axis = IO_AXIS_Y;
+ _export.params.up_axis = IO_AXIS_Z;
_export.params.export_smooth_groups = true;
_export.params.export_material_groups = true;
compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
index ef27a65fb4b..7d3b41ed527 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -17,8 +17,8 @@ struct OBJExportParamsDefault {
params.start_frame = 0;
params.end_frame = 1;
- params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
- params.up_axis = OBJ_AXIS_Y_UP;
+ params.forward_axis = IO_AXIS_NEGATIVE_Z;
+ params.up_axis = IO_AXIS_Y;
params.scaling_factor = 1.f;
params.apply_modifiers = true;
@@ -26,6 +26,7 @@ struct OBJExportParamsDefault {
params.export_selected_objects = false;
params.export_uv = true;
params.export_normals = true;
+ params.export_colors = false;
params.export_materials = true;
params.path_mode = PATH_REFERENCE_AUTO;
params.export_triangulated_mesh = false;
diff --git a/source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc b/source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc
index 46e093bb8a7..dc1cfd2b449 100644
--- a/source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_import_string_utils_tests.cc
@@ -10,17 +10,34 @@ namespace blender::io::obj {
TEST(obj_import_string_utils, read_next_line)
{
- std::string str = "abc\n \n\nline with \\\ncontinuation\nCRLF ending:\r\na";
+ std::string str = "abc\n \n\nline with \t spaces\nCRLF ending:\r\na";
StringRef s = str;
EXPECT_STRREF_EQ("abc", read_next_line(s));
EXPECT_STRREF_EQ(" ", read_next_line(s));
EXPECT_STRREF_EQ("", read_next_line(s));
- EXPECT_STRREF_EQ("line with \\\ncontinuation", read_next_line(s));
+ EXPECT_STRREF_EQ("line with \t spaces", read_next_line(s));
EXPECT_STRREF_EQ("CRLF ending:\r", read_next_line(s));
EXPECT_STRREF_EQ("a", read_next_line(s));
EXPECT_TRUE(s.is_empty());
}
+TEST(obj_import_string_utils, fixup_line_continuations)
+{
+ const char *str =
+ "backslash \\\n eol\n"
+ "backslash spaces \\ \n eol\n"
+ "without eol \\ is \\\\ \\ left intact\n"
+ "\\";
+ const char *exp =
+ "backslash eol\n"
+ "backslash spaces eol\n"
+ "without eol \\ is \\\\ \\ left intact\n"
+ "\\";
+ std::string buf(str);
+ fixup_line_continuations(buf.data(), buf.data() + buf.size());
+ EXPECT_STRREF_EQ(exp, buf);
+}
+
static StringRef drop_whitespace(StringRef s)
{
return StringRef(drop_whitespace(s.begin(), s.end()), s.end());
@@ -29,9 +46,14 @@ static StringRef parse_int(StringRef s, int fallback, int &dst, bool skip_space
{
return StringRef(parse_int(s.begin(), s.end(), fallback, dst, skip_space), s.end());
}
-static StringRef parse_float(StringRef s, float fallback, float &dst, bool skip_space = true)
+static StringRef parse_float(StringRef s,
+ float fallback,
+ float &dst,
+ bool skip_space = true,
+ bool require_trailing_space = false)
{
- return StringRef(parse_float(s.begin(), s.end(), fallback, dst, skip_space), s.end());
+ return StringRef(
+ parse_float(s.begin(), s.end(), fallback, dst, skip_space, require_trailing_space), s.end());
}
TEST(obj_import_string_utils, drop_whitespace)
@@ -49,7 +71,7 @@ TEST(obj_import_string_utils, drop_whitespace)
/* No leading whitespace */
EXPECT_STRREF_EQ("c", drop_whitespace("c"));
/* Case with backslash, should be treated as whitespace */
- EXPECT_STRREF_EQ("d", drop_whitespace(" \\ d"));
+ EXPECT_STRREF_EQ("d", drop_whitespace(" \t d"));
}
TEST(obj_import_string_utils, parse_int_valid)
@@ -126,6 +148,9 @@ TEST(obj_import_string_utils, parse_float_invalid)
/* Has leading white-space when we don't expect it */
EXPECT_STRREF_EQ(" 1", parse_float(" 1", -4.0f, val, false));
EXPECT_EQ(val, -4.0f);
+ /* Has trailing non-number characters when we don't want them */
+ EXPECT_STRREF_EQ("123.5.png", parse_float(" 123.5.png", -5.0f, val, true, true));
+ EXPECT_EQ(val, -5.0f);
}
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
index d7f4ce3d773..02565556c37 100644
--- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
@@ -39,6 +39,7 @@ struct Expectation {
float3 vert_first, vert_last;
float3 normal_first;
float2 uv_first;
+ float4 color_first = {-1, -1, -1, -1};
};
class obj_importer_test : public BlendfileLoadingBaseTest {
@@ -55,8 +56,10 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
OBJImportParams params;
params.clamp_size = 0;
- params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
- params.up_axis = OBJ_AXIS_Y_UP;
+ params.forward_axis = IO_AXIS_NEGATIVE_Z;
+ params.up_axis = IO_AXIS_Y;
+ params.validate_meshes = true;
+ params.import_vertex_groups = false;
std::string obj_path = blender::tests::flags_test_asset_dir() + "/io_tests/obj/" + path;
strncpy(params.filepath, obj_path.c_str(), FILE_MAX - 1);
@@ -98,6 +101,15 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
float2 uv_first = mloopuv ? float2(mloopuv->uv) : float2(0, 0);
EXPECT_V2_NEAR(uv_first, exp.uv_first, 0.0001f);
+ if (exp.color_first.x >= 0) {
+ const float4 *colors = (const float4 *)(CustomData_get_layer(&mesh->vdata,
+ CD_PROP_COLOR));
+ EXPECT_TRUE(colors != nullptr);
+ EXPECT_V4_NEAR(colors[0], exp.color_first, 0.0001f);
+ }
+ else {
+ EXPECT_FALSE(CustomData_has_layer(&mesh->vdata, CD_PROP_COLOR));
+ }
}
if (object->type == OB_CURVES_LEGACY) {
Curve *curve = static_cast<Curve *>(DEG_get_evaluated_object(depsgraph, object)->data);
@@ -111,7 +123,7 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
int endpoint = (nurb->flagu & CU_NURB_ENDPOINT) ? 1 : 0;
EXPECT_EQ(nurb->orderu, exp.mesh_totpoly_or_curve_order);
EXPECT_EQ(endpoint, exp.mesh_totedge_or_curve_endp);
- // Cyclic flag is not set by the importer yet
+ /* Cyclic flag is not set by the importer yet. */
// int cyclic = (nurb->flagu & CU_NURB_CYCLIC) ? 1 : 0;
// EXPECT_EQ(cyclic, exp.mesh_totloop_or_curve_cyclic);
}
@@ -133,7 +145,7 @@ TEST_F(obj_importer_test, import_cube)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBcube",
OB_MESH,
8,
12,
@@ -146,6 +158,36 @@ TEST_F(obj_importer_test, import_cube)
import_and_check("cube.obj", expect, std::size(expect), 1);
}
+TEST_F(obj_importer_test, import_cube_o_after_verts)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {
+ "OBActualCube",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-1, -1, 1),
+ float3(1, -1, -1),
+ float3(0, 0, 1),
+ },
+ {
+ "OBSparseTri",
+ OB_MESH,
+ 6,
+ 3,
+ 1,
+ 3,
+ float3(1, -1, 1),
+ float3(-2, -2, 2),
+ float3(-0.2357f, 0.9428f, 0.2357f),
+ },
+ };
+ import_and_check("cube_o_after_verts.obj", expect, std::size(expect), 2);
+}
+
TEST_F(obj_importer_test, import_suzanne_all_data)
{
Expectation expect[] = {
@@ -168,7 +210,7 @@ TEST_F(obj_importer_test, import_nurbs)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBnurbs",
OB_CURVES_LEGACY,
12,
0,
@@ -184,7 +226,7 @@ TEST_F(obj_importer_test, import_nurbs_curves)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)},
+ {"OBnurbs_curves", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)},
{"OBNurbsCurveDiffWeights",
OB_CURVES_LEGACY,
4,
@@ -211,7 +253,7 @@ TEST_F(obj_importer_test, import_nurbs_cyclic)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object",
+ {"OBnurbs_cyclic",
OB_CURVES_LEGACY,
31,
0,
@@ -262,7 +304,7 @@ TEST_F(obj_importer_test, import_materials)
{
Expectation expect[] = {
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
- {"OBNew object", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)},
+ {"OBmaterials", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)},
};
import_and_check("materials.obj", expect, std::size(expect), 4);
}
@@ -281,13 +323,13 @@ TEST_F(obj_importer_test, import_faces_invalid_or_with_holes)
float3(1, 0, -1)},
{"OBFaceQuadDupSomeVerts_BecomesOneQuadUsing4Verts",
OB_MESH,
- 8,
+ 4,
4,
1,
4,
float3(3, 0, -2),
- float3(6, 0, -1)},
- {"OBFaceTriDupVert_Becomes1Tri", OB_MESH, 8, 3, 1, 3, float3(-2, 0, 3), float3(1, 0, 4)},
+ float3(7, 0, -2)},
+ {"OBFaceTriDupVert_Becomes1Tri", OB_MESH, 3, 3, 1, 3, float3(-2, 0, 3), float3(2, 0, 7)},
{"OBFaceAllVertsDup_BecomesOneOverlappingFaceUsingAllVerts",
OB_MESH,
8,
@@ -304,7 +346,7 @@ TEST_F(obj_importer_test, import_faces_invalid_or_with_holes)
8,
float3(8, 0, -2),
float3(11, 0, -1)},
- {"OBFaceJustTwoVerts_IsSkipped", OB_MESH, 8, 0, 0, 0, float3(8, 0, 3), float3(11, 0, 4)},
+ {"OBFaceJustTwoVerts_IsSkipped", OB_MESH, 2, 0, 0, 0, float3(8, 0, 3), float3(8, 0, 7)},
};
import_and_check("faces_invalid_or_with_holes.obj", expect, std::size(expect), 0);
}
@@ -315,12 +357,12 @@ TEST_F(obj_importer_test, import_invalid_indices)
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
{"OBQuad",
OB_MESH,
- 4,
+ 3,
3,
1,
3,
float3(-2, 0, -2),
- float3(2, 0, -2),
+ float3(2, 0, 2),
float3(0, 1, 0),
float2(0.5f, 0.25f)},
};
@@ -333,12 +375,12 @@ TEST_F(obj_importer_test, import_invalid_syntax)
{"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
{"OBObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLon",
OB_MESH,
- 10, /* NOTE: right now parses some invalid obj syntax as valid vertices. */
+ 3,
3,
1,
3,
float3(1, 2, 3),
- float3(10, 11, 12),
+ float3(7, 8, 9),
float3(0, 1, 0),
float2(0.5f, 0.25f)},
};
@@ -434,7 +476,17 @@ TEST_F(obj_importer_test, import_all_objects)
float3(16, 1, -1),
float3(14, 1, 1),
float3(0, 0, 1)},
- {"OBVColCube", OB_MESH, 8, 13, 7, 26, float3(13, 1, -1), float3(11, 1, 1), float3(0, 0, 1)},
+ {"OBVColCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(13, 1, -1),
+ float3(11, 1, 1),
+ float3(0, 0, 1),
+ float2(0, 0),
+ float4(0.0f, 0.002125f, 1.0f, 1.0f)},
{"OBUVCube",
OB_MESH,
8,
@@ -490,4 +542,126 @@ TEST_F(obj_importer_test, import_all_objects)
import_and_check("all_objects.obj", expect, std::size(expect), 7);
}
+TEST_F(obj_importer_test, import_cubes_vertex_colors)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCubeVertexByte",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1.0f, 1.0f, -1.0f),
+ float3(-1.0f, -1.0f, 1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.846873f, 0.027321f, 0.982123f, 1.0f)},
+ {"OBCubeVertexFloat",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(3.392028f, 1.0f, -1.0f),
+ float3(1.392028f, -1.0f, 1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(49.99467f, 0.027321f, 0.982123f, 1.0f)},
+ {"OBCubeCornerByte",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1.0f, 1.0f, -3.812445f),
+ float3(-1.0f, -1.0f, -1.812445f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.89627f, 0.036889f, 0.47932f, 1.0f)},
+ {"OBCubeCornerFloat",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(3.481967f, 1.0f, -3.812445f),
+ float3(1.481967f, -1.0f, -1.812445f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(1.564582f, 0.039217f, 0.664309f, 1.0f)},
+ {"OBCubeMultiColorAttribs",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-4.725068f, -1.0f, 1.0f),
+ float3(-2.725068f, 1.0f, -1.0f),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.270498f, 0.47932f, 0.262251f, 1.0f)},
+ {"OBCubeNoColors",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-4.550208f, -1.0f, -1.918042f),
+ float3(-2.550208f, 1.0f, -3.918042f)},
+ };
+ import_and_check("cubes_vertex_colors.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_cubes_vertex_colors_mrgb)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCubeXYZRGB",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(1, 1, -1),
+ float3(-1, -1, 1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.6038f, 0.3185f, 0.1329f, 1.0f)},
+ {"OBCubeMRGB",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(4, 1, -1),
+ float3(2, -1, 1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(0.8714f, 0.6308f, 0.5271f, 1.0f)},
+ {
+ "OBTriNoColors",
+ OB_MESH,
+ 3,
+ 3,
+ 1,
+ 3,
+ float3(8, 1, -1),
+ float3(6, 0, -1),
+ },
+ {"OBTriMRGB",
+ OB_MESH,
+ 3,
+ 3,
+ 1,
+ 3,
+ float3(12, 1, -1),
+ float3(10, 0, -1),
+ float3(0, 0, 0),
+ float2(0, 0),
+ float4(1.0f, 0.0f, 0.0f, 1.0f)},
+ };
+ import_and_check("cubes_vertex_colors_mrgb.obj", expect, std::size(expect), 0);
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc b/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc
index 068cdc0bf3a..08050ac34c9 100644
--- a/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_mtl_parser_tests.cc
@@ -158,7 +158,7 @@ TEST_F(obj_mtl_parser_test, all_objects)
TEST_F(obj_mtl_parser_test, materials)
{
- MTLMaterial mat[5];
+ MTLMaterial mat[6];
mat[0].name = "no_textures_red";
mat[0].Ka = {0.3f, 0.3f, 0.3f};
mat[0].Kd = {0.8f, 0.3f, 0.1f};
@@ -236,6 +236,20 @@ TEST_F(obj_mtl_parser_test, materials)
bump.scale = {3, 4, 5};
}
+ mat[5].name = "Parser_ScaleOffset_Test";
+ {
+ tex_map_XX &kd = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Kd);
+ kd.translation = {2.5f, 0.0f, 0.0f};
+ kd.image_path = "OffsetOneValue.png";
+ tex_map_XX &ks = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Ks);
+ ks.scale = {1.5f, 2.5f, 1.0f};
+ ks.translation = {3.5f, 4.5f, 0.0f};
+ ks.image_path = "ScaleOffsetBothTwovalues.png";
+ tex_map_XX &ns = mat[5].tex_map_of_type(eMTLSyntaxElement::map_Ns);
+ ns.scale = {0.5f, 1.0f, 1.0f};
+ ns.image_path = "1.Value.png";
+ }
+
check("materials.mtl", mat, ARRAY_SIZE(mat));
}
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 17d783d3ebf..a77b7034241 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -22,6 +22,7 @@ struct GPUTexture;
struct ID;
struct Library;
struct PackedFile;
+struct UniqueName_Map;
/* Runtime display data */
struct DrawData;
@@ -444,6 +445,11 @@ typedef struct ID {
struct ID_Runtime runtime;
} ID;
+typedef struct Library_Runtime {
+ /* Used for efficient calculations of unique names. */
+ struct UniqueName_Map *name_map;
+} Library_Runtime;
+
/**
* For each library file used, a Library struct is added to Main
* WARNING: readfile.c, expand_doit() reads this struct without DNA check!
@@ -472,10 +478,12 @@ typedef struct Library {
ushort tag;
char _pad_0[6];
- /* Temp data needed by read/write code, and liboverride recursive resync. */
+ /** Temp data needed by read/write code, and lib-override recursive re-synchronized. */
int temp_index;
/** See BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION, needed for do_versions. */
short versionfile, subversionfile;
+
+ struct Library_Runtime runtime;
} Library;
/** #Library.tag */
@@ -597,6 +605,8 @@ typedef struct PreviewImage {
* Keep in sync with #BKE_id_eval_properties_copy. */
#define ID_TYPE_SUPPORTS_PARAMS_WITHOUT_COW(id_type) ELEM(id_type, ID_ME)
+#define ID_TYPE_IS_DEPRECATED(id_type) ELEM(id_type, ID_IP)
+
#ifdef GS
# undef GS
#endif
@@ -921,6 +931,10 @@ typedef enum IDRecalcFlag {
#define FILTER_ID_PT (1ULL << 33)
#define FILTER_ID_VO (1ULL << 34)
#define FILTER_ID_SIM (1ULL << 35)
+#define FILTER_ID_KE (1ULL << 36)
+#define FILTER_ID_SCR (1ULL << 37)
+#define FILTER_ID_WM (1ULL << 38)
+#define FILTER_ID_LI (1ULL << 39)
#define FILTER_ID_ALL \
(FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU_LEGACY | \
@@ -928,7 +942,8 @@ typedef enum IDRecalcFlag {
FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | \
FILTER_ID_OB | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | \
FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | \
- FILTER_ID_WS | FILTER_ID_LP | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM)
+ FILTER_ID_WS | FILTER_ID_LP | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM | \
+ FILTER_ID_KE | FILTER_ID_SCR | FILTER_ID_WM | FILTER_ID_LI)
/**
* This enum defines the index assigned to each type of IDs in the array returned by
diff --git a/source/blender/makesdna/DNA_ID_enums.h b/source/blender/makesdna/DNA_ID_enums.h
index b0ca13615b8..5999af8bf5c 100644
--- a/source/blender/makesdna/DNA_ID_enums.h
+++ b/source/blender/makesdna/DNA_ID_enums.h
@@ -38,6 +38,8 @@ enum eIconSizes {
*
* Written to #BHead.code (for file IO)
* and the first 2 bytes of #ID.name (for runtime checks, see #GS macro).
+ *
+ * Update #ID_TYPE_IS_DEPRECATED() when deprecating types.
*/
typedef enum ID_Type {
ID_SCE = MAKE_ID2('S', 'C'), /* Scene */
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 516d3ce94f9..53e87e905b5 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -251,12 +251,18 @@ typedef struct bPoseChannel {
/** Motion path cache for this bone. */
bMotionPath *mpath;
- /** Draws custom object instead of default bone shape. */
+ /**
+ * Draws custom object instead of default bone shape.
+ *
+ * \note For the purpose of user interaction (selection, display etc),
+ * it's important this value is treated as NULL when #ARM_NO_CUSTOM is set.
+ */
struct Object *custom;
/**
- * Odd feature, display with another bones transform.
- * needed in rare cases for advanced rigs,
- * since the alternative is highly complicated - campbell
+ * This is a specific feature to display with another bones transform.
+ * Needed in rare cases for advanced rigs, since alternative solutions are highly complicated.
+ *
+ * \note This depends #bPoseChannel.custom being set and the #ARM_NO_CUSTOM flag being unset.
*/
struct bPoseChannel *custom_tx;
float custom_scale; /* Deprecated */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index c1dfab8a041..e2b58cefef6 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -771,7 +771,7 @@ typedef enum eNlaStrip_Blend_Mode {
NLASTRIP_MODE_COMBINE,
} eNlaStrip_Blend_Mode;
-/** NLA Strip Extrpolation Mode. */
+/** NLA Strip Extrapolation Mode. */
typedef enum eNlaStrip_Extrapolate_Mode {
/* extend before first frame if no previous strips in track,
* and always hold+extend last frame */
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index f409d1c0442..adda23c26f2 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -468,6 +468,12 @@ typedef enum eBrushCurvesSculptTool {
CURVES_SCULPT_TOOL_SNAKE_HOOK = 2,
CURVES_SCULPT_TOOL_ADD = 3,
CURVES_SCULPT_TOOL_GROW_SHRINK = 4,
+ CURVES_SCULPT_TOOL_SELECTION_PAINT = 5,
+ CURVES_SCULPT_TOOL_PINCH = 6,
+ CURVES_SCULPT_TOOL_SMOOTH = 7,
+ CURVES_SCULPT_TOOL_PUFF = 8,
+ CURVES_SCULPT_TOOL_DENSITY = 9,
+ CURVES_SCULPT_TOOL_SLIDE = 10,
} eBrushCurvesSculptTool;
/** When #BRUSH_ACCUMULATE is used */
@@ -621,6 +627,12 @@ typedef enum eBrushCurvesSculptFlag {
BRUSH_CURVES_SCULPT_FLAG_INTERPOLATE_POINT_COUNT = (1 << 4),
} eBrushCurvesSculptFlag;
+typedef enum eBrushCurvesSculptDensityMode {
+ BRUSH_CURVES_SCULPT_DENSITY_MODE_AUTO = 0,
+ BRUSH_CURVES_SCULPT_DENSITY_MODE_ADD = 1,
+ BRUSH_CURVES_SCULPT_DENSITY_MODE_REMOVE = 2,
+} eBrushCurvesSculptDensityMode;
+
#define MAX_BRUSH_PIXEL_RADIUS 500
#define GP_MAX_BRUSH_PIXEL_RADIUS 1000
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 24e77ecf87f..b24bb786593 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -97,7 +97,7 @@ typedef struct BrushGpencilSettings {
/** Simplify adaptive factor */
float simplify_f;
- /** Mix colorfactor */
+ /** Mix color-factor. */
float vertex_factor;
int vertex_mode;
@@ -148,6 +148,13 @@ typedef struct BrushCurvesSculptSettings {
float minimum_length;
/** Length of newly added curves when it is not interpolated from other curves. */
float curve_length;
+ /** Minimum distance between curve root points used by the Density brush. */
+ float minimum_distance;
+ /** How often the Density brush tries to add a new curve. */
+ int density_add_attempts;
+ /** #eBrushCurvesSculptDensityMode. */
+ uint8_t density_mode;
+ char _pad[7];
} BrushCurvesSculptSettings;
typedef struct Brush {
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index 9b3adc4c8dd..10a6c936be1 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -54,6 +54,7 @@ typedef struct CameraBGImage {
typedef struct CameraDOFSettings {
/** Focal distance for depth of field. */
struct Object *focus_object;
+ char focus_subtarget[64];
float focus_distance;
float aperture_fstop;
float aperture_rotation;
@@ -194,6 +195,9 @@ enum {
/* Axis flip options */
CAM_BGIMG_FLAG_FLIP_X = (1 << 7),
CAM_BGIMG_FLAG_FLIP_Y = (1 << 8),
+
+ /* That background image has been inserted in local override (i.e. it can be fully edited!). */
+ CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL = (1 << 9),
};
/* CameraBGImage->source */
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index e79a53704c9..8ac899df701 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -20,8 +20,8 @@ extern "C" {
* Mass-Spring Model to Describe Rigid Cloth Behavior by Xavier Provot.
*
* I've tried to keep similar, if not exact names for the variables as
- * are presented in the paper. Where I've changed the concept slightly,
- * as in stepsPerFrame compared to the time step in the paper, I've used
+ * are presented in the paper. Where I've changed the concept slightly,
+ * as in `stepsPerFrame` compared to the time step in the paper, I've used
* variables with different names to minimize confusion.
*/
diff --git a/source/blender/makesdna/DNA_collection_types.h b/source/blender/makesdna/DNA_collection_types.h
index 8c437d69028..26011c990d4 100644
--- a/source/blender/makesdna/DNA_collection_types.h
+++ b/source/blender/makesdna/DNA_collection_types.h
@@ -40,6 +40,7 @@ enum eCollectionLineArt_Usage {
enum eCollectionLineArt_Flags {
COLLECTION_LRT_USE_INTERSECTION_MASK = (1 << 0),
+ COLLECTION_LRT_USE_INTERSECTION_PRIORITY = (1 << 1),
};
typedef struct Collection {
@@ -62,7 +63,8 @@ typedef struct Collection {
short lineart_usage; /* eCollectionLineArt_Usage */
unsigned char lineart_flags; /* eCollectionLineArt_Flags */
unsigned char lineart_intersection_mask;
- char _pad[6];
+ unsigned char lineart_intersection_priority;
+ char _pad[5];
int16_t color_tag;
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 6557f35970d..8e0ce68f71a 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -105,8 +105,10 @@ typedef struct bConstraintTarget {
/* bConstraintTarget -> flag */
typedef enum eConstraintTargetFlag {
- /** temporary target-struct that needs to be freed after use */
+ /** Temporary target-struct that needs to be freed after use. */
CONSTRAINT_TAR_TEMP = (1 << 0),
+ /** Temporary target for the custom space reference. */
+ CONSTRAINT_TAR_CUSTOM_SPACE = (1 << 1),
} eConstraintTargetFlag;
/* bConstraintTarget/bConstraintOb -> type */
@@ -247,10 +249,9 @@ typedef struct bArmatureConstraint {
typedef struct bTrackToConstraint {
struct Object *tar;
/**
- * I'll be using reserved1 and reserved2 as Track and Up flags,
+ * NOTE(@theeth): I'll be using reserved1 and reserved2 as Track and Up flags,
* not sure if that's what they were intended for anyway.
* Not sure either if it would create backward incompatibility if I were to rename them.
- * - theeth
*/
int reserved1;
int reserved2;
diff --git a/source/blender/makesdna/DNA_curves_types.h b/source/blender/makesdna/DNA_curves_types.h
index 2388f04cc39..89deeec898b 100644
--- a/source/blender/makesdna/DNA_curves_types.h
+++ b/source/blender/makesdna/DNA_curves_types.h
@@ -67,23 +67,6 @@ typedef enum NormalMode {
*/
typedef struct CurvesGeometry {
/**
- * A runtime pointer to the "position" attribute data.
- * \note This data is owned by #point_data.
- */
- float (*position)[3];
- /**
- * A runtime pointer to the "radius" attribute data.
- * \note This data is owned by #point_data.
- */
- float *radius;
-
- /**
- * The type of each curve. #CurveType.
- * \note This data is owned by #curve_data.
- */
- int8_t *curve_type;
-
- /**
* The start index of each curve in the point data. The size of each curve can be calculated by
* subtracting the offset from the next offset. That is valid even for the last curve because
* this array is allocated with a length one larger than the number of curves. This is allowed
@@ -141,7 +124,12 @@ typedef struct Curves {
* symmetrical geometry.
*/
char symmetry;
- char _pad2[5];
+ /**
+ * #eAttrDomain. The active selection mode domain. At most one selection mode can be active
+ * at a time.
+ */
+ char selection_domain;
+ char _pad[4];
/**
* Used as base mesh when curves represent e.g. hair or fur. This surface is used in edit modes.
@@ -152,6 +140,13 @@ typedef struct Curves {
*/
struct Object *surface;
+ /**
+ * The name of the attribute on the surface #Mesh used to give meaning to the UV attachment
+ * coordinates stored on each curve. Expected to be a 2D vector attribute on the face corner
+ * domain.
+ */
+ char *surface_uv_map;
+
/* Draw Cache. */
void *batch_cache;
} Curves;
@@ -159,6 +154,7 @@ typedef struct Curves {
/** #Curves.flag */
enum {
HA_DS_EXPAND = (1 << 0),
+ CV_SCULPT_SELECTION_ENABLED = (1 << 1),
};
/** #Curves.symmetry */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index ef937fb139b..bc29de66cf9 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -81,7 +81,7 @@ typedef struct CustomData {
} CustomData;
/** #CustomData.type */
-typedef enum CustomDataType {
+typedef enum eCustomDataType {
/* Used by GLSL attributes in the cases when we need a delayed CD type
* assignment (in the cases when we don't know in advance which layer
* we are addressing).
@@ -161,9 +161,9 @@ typedef enum CustomDataType {
CD_HAIRLENGTH = 51,
CD_NUMTYPES = 52,
-} CustomDataType;
+} eCustomDataType;
-/* Bits for CustomDataMask */
+/* Bits for eCustomDataMask */
#define CD_MASK_MVERT (1 << CD_MVERT)
// #define CD_MASK_MSTICKY (1 << CD_MSTICKY) /* DEPRECATED */
#define CD_MASK_MDEFORMVERT (1 << CD_MDEFORMVERT)
@@ -260,8 +260,6 @@ enum {
#define DYNTOPO_NODE_NONE -1
-#define CD_TEMP_CHUNK_SIZE 128
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index ae47bf5d524..324252ca369 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -296,7 +296,7 @@
#define _DNA_DEFAULT_LineartGpencilModifierData \
{ \
- .edge_types = LRT_EDGE_FLAG_ALL_TYPE, \
+ .edge_types = LRT_EDGE_FLAG_INIT_TYPE, \
.thickness = 25, \
.opacity = 1.0f, \
.flags = LRT_GPENCIL_MATCH_OUTPUT_VGROUP, \
@@ -306,8 +306,12 @@
/* Do not split by default, this is for better chaining quality. */ \
.angle_splitting_threshold = 0.0f, \
.chaining_image_threshold = 0.001f, \
- .chain_smooth_tolerance = 0.2f,\
.stroke_depth_offset = 0.05,\
+ .chain_smooth_tolerance = 0.0f,\
+ .overscan = 0.1f,\
+ .shadow_camera_near = 0.1f, \
+ .shadow_camera_far = 200.0f, \
+ .shadow_camera_size = 200.0f, \
}
#define _DNA_DEFAULT_LengthGpencilModifierData \
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index c20fb180fcd..2bb95caddfb 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -998,6 +998,18 @@ typedef enum eLineartGpencilModifierSource {
LRT_SOURCE_SCENE = 2,
} eLineartGpencilModifierSource;
+typedef enum eLineartGpencilModifierShadowFilter {
+ LRT_SHADOW_FILTER_NONE = 0,
+ LRT_SHADOW_FILTER_LIT = 1,
+ LRT_SHADOW_FILTER_SHADED = 2,
+} eLineartGpencilModifierShadowFilter;
+
+typedef enum eLineartGpencilModifierSilhouetteFilter {
+ LRT_SILHOUETTE_FILTER_NONE = 0,
+ LRT_SILHOUETTE_FILTER_GROUP = (1 << 0),
+ LRT_SILHOUETTE_FILTER_INDIVIDUAL = (1 << 1),
+} eLineartGpencilModifierSilhouetteFilter;
+
/* This enum is for modifier internal state only. */
typedef enum eLineArtGPencilModifierFlags {
/* These two moved to #eLineartMainFlags to keep consistent with flag variable purpose. */
@@ -1008,6 +1020,7 @@ typedef enum eLineArtGPencilModifierFlags {
LRT_GPENCIL_USE_CACHE = (1 << 4),
LRT_GPENCIL_OFFSET_TOWARDS_CUSTOM_CAMERA = (1 << 5),
LRT_GPENCIL_INVERT_COLLECTION = (1 << 6),
+ LRT_GPENCIL_INVERT_SILHOUETTE_FILTER = (1 << 7),
} eLineArtGPencilModifierFlags;
typedef enum eLineartGpencilMaskSwitches {
@@ -1024,8 +1037,7 @@ struct LineartCache;
typedef struct LineartGpencilModifierData {
GpencilModifierData modifier;
- /** Line type enable flags, bits in #eLineartEdgeFlag. */
- short edge_types;
+ uint16_t edge_types; /* line type enable flags, bits in eLineartEdgeFlag */
/** Object or Collection, from #eLineartGpencilModifierSource. */
char source_type;
@@ -1035,6 +1047,7 @@ typedef struct LineartGpencilModifierData {
short level_end;
struct Object *source_camera;
+ struct Object *light_contour_object;
struct Object *source_object;
struct Collection *source_collection;
@@ -1049,14 +1062,19 @@ typedef struct LineartGpencilModifierData {
char source_vertex_group[64];
char vgname[64];
- /**
- * Camera focal length is divided by `1 + overscan`, before calculation, which give a wider FOV,
+ /* Camera focal length is divided by (1 + over-scan), before calculation, which give a wider FOV,
* this doesn't change coordinates range internally (-1, 1), but makes the calculated frame
* bigger than actual output. This is for the easier shifting calculation. A value of 0.5 means
- * the "internal" focal length become 2/3 of the actual camera.
- */
+ * the "internal" focal length become 2/3 of the actual camera. */
float overscan;
+ /* Values for point light and directional (sun) light. */
+ /* For point light, fov always gonna be 120 deg horizontal, with 3 "cameras" covering 360 deg. */
+ float shadow_camera_fov;
+ float shadow_camera_size;
+ float shadow_camera_near;
+ float shadow_camera_far;
+
float opacity;
short thickness;
@@ -1064,7 +1082,9 @@ typedef struct LineartGpencilModifierData {
unsigned char material_mask_bits;
unsigned char intersection_mask;
- char _pad[3];
+ unsigned char shadow_selection;
+ unsigned char silhouette_selection;
+ char _pad[1];
/** `0..1` range for cosine angle */
float crease_threshold;
@@ -1078,7 +1098,7 @@ typedef struct LineartGpencilModifierData {
/* CPU mode */
float chaining_image_threshold;
- /* Ported from SceneLineArt flags. */
+ /* eLineartMainFlags, for one time calculation. */
int calculation_flags;
/* #eLineArtGPencilModifierFlags, modifier internal state. */
@@ -1095,10 +1115,14 @@ typedef struct LineartGpencilModifierData {
char level_start_override;
char level_end_override;
short edge_types_override;
+ char shadow_selection_override;
+ char shadow_use_silhouette_override;
+
+ char _pad2[6];
struct LineartCache *cache;
/* Keep a pointer to the render buffer so we can call destroy from ModifierData. */
- struct LineartRenderBuffer *render_buffer_ptr;
+ struct LineartData *la_data_ptr;
} LineartGpencilModifierData;
diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h
index 70ee7c99d01..ef35b72d2ab 100644
--- a/source/blender/makesdna/DNA_ipo_types.h
+++ b/source/blender/makesdna/DNA_ipo_types.h
@@ -338,7 +338,7 @@ typedef struct Ipo {
#define CAM_STA 2
#define CAM_END 3
-/* yafray aperture & focal distance curves */
+/* YAFRAY aperture & focal distance curves. */
#define CAM_YF_APERT 4
#define CAM_YF_FDIST 5
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 4ee5f34fcde..0af50b2bd4f 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -35,6 +35,7 @@ typedef enum eViewLayerEEVEEPassType {
EEVEE_RENDER_PASS_BLOOM = (1 << 14),
EEVEE_RENDER_PASS_AOV = (1 << 15),
EEVEE_RENDER_PASS_CRYPTOMATTE = (1 << 16),
+ EEVEE_RENDER_PASS_VECTOR = (1 << 17),
} eViewLayerEEVEEPassType;
#define EEVEE_RENDER_PASS_MAX_BIT 17
diff --git a/source/blender/makesdna/DNA_light_types.h b/source/blender/makesdna/DNA_light_types.h
index 9202d7c2d51..f1bf0580b94 100644
--- a/source/blender/makesdna/DNA_light_types.h
+++ b/source/blender/makesdna/DNA_light_types.h
@@ -120,7 +120,7 @@ typedef struct Light {
/* #define LA_NO_DIFF (1 << 11) */ /* not used anywhere */
/* #define LA_NO_SPEC (1 << 12) */ /* not used anywhere */
/* #define LA_SHAD_RAY (1 << 13) */ /* not used anywhere - cleaned */
-/* yafray: light shadowbuffer flag, softlight */
+/* YAFRAY: light shadow-buffer flag, soft-light. */
/* Since it is used with LOCAL light, can't use LA_SHAD */
/* #define LA_YF_SOFT (1 << 14) */ /* not used anymore */
/* #define LA_LAYER_SHADOW (1 << 15) */ /* not used anymore */
diff --git a/source/blender/makesdna/DNA_lineart_types.h b/source/blender/makesdna/DNA_lineart_types.h
index 5b3a23000d7..1ff656f85ed 100644
--- a/source/blender/makesdna/DNA_lineart_types.h
+++ b/source/blender/makesdna/DNA_lineart_types.h
@@ -14,7 +14,7 @@
* Edge flags and usage flags are used by with scene/object/gpencil modifier bits, and those values
* needs to stay consistent throughout. */
-/* These flags are used for 1 time calculation, not stroke selection afterwards. */
+/** These flags are used for 1 time calculation, not stroke selection afterwards. */
typedef enum eLineartMainFlags {
LRT_INTERSECTION_AS_CONTOUR = (1 << 0),
LRT_EVERYTHING_AS_CONTOUR = (1 << 1),
@@ -38,6 +38,8 @@ typedef enum eLineartMainFlags {
LRT_USE_BACK_FACE_CULLING = (1 << 19),
LRT_USE_IMAGE_BOUNDARY_TRIMMING = (1 << 20),
LRT_CHAIN_PRESERVE_DETAILS = (1 << 22),
+ LRT_SHADOW_ENCLOSED_SHAPES = (1 << 23),
+ LRT_SHADOW_USE_SILHOUETTE = (1 << 24),
} eLineartMainFlags;
typedef enum eLineartEdgeFlag {
@@ -47,12 +49,21 @@ typedef enum eLineartEdgeFlag {
LRT_EDGE_FLAG_MATERIAL = (1 << 3),
LRT_EDGE_FLAG_INTERSECTION = (1 << 4),
LRT_EDGE_FLAG_LOOSE = (1 << 5),
+ LRT_EDGE_FLAG_LIGHT_CONTOUR = (1 << 6),
/* LRT_EDGE_FLAG_FOR_FUTURE = (1 << 7), */
- /* Limited to 8 bits for edge type flag, don't add anymore because BMEdge->head.eflag only has 8
- bits. So unless we changed this into a non-single-bit flag thing, we keep it this way. */
+ /**
+ * It's a legacy limit of 8 bits for feature lines that come from original mesh edges. It should
+ * not be needed in current object loading scheme, but might still be relevant if we are to
+ * implement edit-mesh loading, so don't exceed 8 bits just yet.
+ */
+ LRT_EDGE_FLAG_PROJECTED_SHADOW = (1 << 8),
+ /* To determine an edge to be occluded from the front or back face it's lying on. */
+ LRT_EDGE_FLAG_SHADOW_FACING_LIGHT = (1 << 9),
/** Also used as discarded line mark. */
- LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 8),
- LRT_EDGE_FLAG_CLIPPED = (1 << 9),
+ LRT_EDGE_FLAG_CHAIN_PICKED = (1 << 10),
+ LRT_EDGE_FLAG_CLIPPED = (1 << 11),
+ /** Used to specify contour from viewing camera when computing shadows. */
+ LRT_EDGE_FLAG_CONTOUR_SECONDARY = (1 << 12),
/** Limited to 16 bits for the entire thing. */
/** For object loading code to use only. */
@@ -61,4 +72,6 @@ typedef enum eLineartEdgeFlag {
LRT_EDGE_FLAG_NEXT_IS_DUPLICATION = (1 << 15),
} eLineartEdgeFlag;
-#define LRT_EDGE_FLAG_ALL_TYPE 0x3f
+#define LRT_EDGE_FLAG_ALL_TYPE 0x01ff
+#define LRT_EDGE_FLAG_INIT_TYPE 0x37 /* Without material & light contour */
+#define LRT_EDGE_FLAG_TYPE_MAX_BITS 7
diff --git a/source/blender/makesdna/DNA_mask_types.h b/source/blender/makesdna/DNA_mask_types.h
index 8efcef5addf..fbbcd340ae9 100644
--- a/source/blender/makesdna/DNA_mask_types.h
+++ b/source/blender/makesdna/DNA_mask_types.h
@@ -196,8 +196,9 @@ enum {
#define MASK_HIDE_RENDER (1 << 2)
/* SpaceClip->mask_draw_flag */
-#define MASK_DRAWFLAG_SMOOTH (1 << 0)
+/* #define MASK_DRAWFLAG_SMOOTH_DEPRECATED (1 << 0) */ /* Deprecated */
#define MASK_DRAWFLAG_OVERLAY (1 << 1)
+#define MASK_DRAWFLAG_SPLINE (1 << 2)
/* copy of eSpaceImage_UVDT */
/* SpaceClip->mask_draw_type */
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 332317142c7..460670225c8 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -150,14 +150,15 @@ typedef struct MaterialLineArt {
/** Maximum 255 levels of equivalent occlusion. */
unsigned char mat_occlusion;
- unsigned char _pad[2];
+ unsigned char intersection_priority;
+
+ char _pad;
} MaterialLineArt;
typedef enum eMaterialLineArtFlags {
LRT_MATERIAL_MASK_ENABLED = (1 << 0),
-
- /* Deprecated, kept for versioning code. */
LRT_MATERIAL_CUSTOM_OCCLUSION_EFFECTIVENESS = (1 << 1),
+ LRT_MATERIAL_CUSTOM_INTERSECTION_PRIORITY = (1 << 2),
} eMaterialLineArtFlags;
typedef struct Material {
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 4a57f60be26..2eca84959b8 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -32,6 +32,7 @@ struct MVert;
struct Material;
struct Mesh;
struct SubdivCCG;
+struct SubsurfRuntimeData;
#
#
@@ -83,7 +84,7 @@ typedef struct Mesh_Runtime {
/**
* 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`.
+ * the same mesh is used in many objects or instances. See `draw_cache_impl_mesh.cc`.
*/
void *batch_cache;
@@ -123,26 +124,18 @@ typedef struct Mesh_Runtime {
/**
* Settings for lazily evaluating the subdivision on the CPU if needed. These are
- * set in the modifier when GPU subdivision can be performed.
+ * set in the modifier when GPU subdivision can be performed, and owned by the by
+ * the modifier in the object.
*/
- SessionUUID subsurf_session_uuid;
- char subsurf_resolution;
- char subsurf_do_loop_normals;
- char subsurf_apply_render;
- char subsurf_use_optimal_display;
-
- /* Cached from the draw code for stats display. */
- int subsurf_totvert;
- int subsurf_totedge;
- int subsurf_totpoly;
- int subsurf_totloop;
- char _pad2[2];
+ struct SubsurfRuntimeData *subsurf_runtime_data;
+ void *_pad1;
/**
* Caches for lazily computed vertex and polygon normals. These are stored here rather than in
* #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
* const mesh is not thread-safe.
*/
+ char _pad2[6];
char vert_normals_dirty;
char poly_normals_dirty;
float (*vert_normals)[3];
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 6e3ce7e98a8..f148116eba8 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -178,13 +178,6 @@ 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;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 3be4f82ecb0..76d8207eead 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -71,11 +71,22 @@ namespace blender::nodes {
class NodeDeclaration;
class SocketDeclaration;
} // namespace blender::nodes
+namespace blender::bke {
+class bNodeTreeRuntime;
+class bNodeRuntime;
+class bNodeSocketRuntime;
+} // namespace blender::bke
using NodeDeclarationHandle = blender::nodes::NodeDeclaration;
using SocketDeclarationHandle = blender::nodes::SocketDeclaration;
+using bNodeTreeRuntimeHandle = blender::bke::bNodeTreeRuntime;
+using bNodeRuntimeHandle = blender::bke::bNodeRuntime;
+using bNodeSocketRuntimeHandle = blender::bke::bNodeSocketRuntime;
#else
typedef struct NodeDeclarationHandle NodeDeclarationHandle;
typedef struct SocketDeclarationHandle SocketDeclarationHandle;
+typedef struct bNodeTreeRuntimeHandle bNodeTreeRuntimeHandle;
+typedef struct bNodeRuntimeHandle bNodeRuntimeHandle;
+typedef struct bNodeSocketRuntimeHandle bNodeSocketRuntimeHandle;
#endif
typedef struct bNodeSocket {
@@ -129,7 +140,7 @@ typedef struct bNodeSocket {
short stack_type DNA_DEPRECATED;
char display_shape;
- /* #AttributeDomain used when the geometry nodes modifier creates an attribute for a group
+ /* #eAttrDomain used when the geometry nodes modifier creates an attribute for a group
* output. */
char attribute_domain;
/* Runtime-only cache of the number of input links, for multi-input sockets. */
@@ -169,15 +180,7 @@ typedef struct bNodeSocket {
/** 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];
+ bNodeSocketRuntimeHandle *runtime;
} bNodeSocket;
/** #bNodeSocket.type & #bNodeSocketType.type */
@@ -266,9 +269,7 @@ typedef struct bNode {
/** Used as a boolean for execution. */
uint8_t need_exec;
- char _pad2[5];
- /** #eNodeTreeChangedFlag. */
- uint32_t changed_flag;
+ char _pad2[1];
/** Custom user-defined color. */
float color[3];
@@ -331,25 +332,7 @@ typedef struct bNode {
/** Used at runtime when iterating over node branches. */
char iter_flag;
- /**
- * Describes the desired interface of the node. This is run-time data only.
- * The actual interface of the node may deviate from the declaration temporarily.
- * It's possible to sync the actual state of the node to the desired state. Currently, this is
- * only done when a node is created or loaded.
- *
- * In the future, we may want to keep more data only in the declaration, so that it does not have
- * to be synced to other places that are stored in files. That especially applies to data that
- * can't be edited by users directly (e.g. min/max values of sockets, tooltips, ...).
- *
- * The declaration of a node can be recreated at any time when it is used. Caching it here is
- * just a bit more efficient when it is used a lot. To make sure that the cache is up-to-date,
- * call #nodeDeclarationEnsure before using it.
- *
- * Currently, the declaration is the same for every node of the same type. Going forward, that is
- * intended to change though. Especially when nodes become more dynamic with respect to how many
- * sockets they have.
- */
- NodeDeclarationHandle *declaration;
+ bNodeRuntimeHandle *runtime;
} bNode;
/* node->flag */
@@ -462,16 +445,6 @@ typedef struct bNodeLink {
#define NTREE_CHUNKSIZE_512 512
#define NTREE_CHUNKSIZE_1024 1024
-/** Workaround to forward-declare C++ type in C header. */
-#ifdef __cplusplus
-namespace blender::nodes {
-struct FieldInferencingInterface;
-}
-using FieldInferencingInterfaceHandle = blender::nodes::FieldInferencingInterface;
-#else
-typedef struct FieldInferencingInterfaceHandle FieldInferencingInterfaceHandle;
-#endif
-
/* the basis for a Node tree, all links and nodes reside internal here */
/* only re-usable node trees are in the library though,
* materials and textures allocate own tree struct */
@@ -494,31 +467,15 @@ typedef struct bNodeTree {
float view_center[2];
ListBase nodes, links;
- /** Information about how inputs and outputs of the node group interact with fields. */
- FieldInferencingInterfaceHandle *field_inferencing_interface;
int type;
/**
- * Used to cache run-time information of the node tree.
- * #eNodeTreeRuntimeFlag.
- */
- uint8_t runtime_flag;
-
- char _pad1[3];
-
- /**
* Sockets in groups have unique identifiers, adding new sockets always
* will increase this counter.
*/
int cur_index;
int flag;
- /**
- * 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). */
@@ -552,11 +509,8 @@ typedef struct bNodeTree {
* in case multiple different editors are used and make context ambiguous.
*/
bNodeInstanceKey active_viewer_key;
- /**
- * 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;
+
+ char _pad[4];
/** Execution data.
*
@@ -579,6 +533,8 @@ typedef struct bNodeTree {
/** Image representing what the node group does. */
struct PreviewImage *preview;
+
+ bNodeTreeRuntimeHandle *runtime;
} bNodeTree;
/** #NodeTree.type, index */
@@ -1219,7 +1175,7 @@ typedef struct NodeDenoise {
} NodeDenoise;
typedef struct NodeMapRange {
- /* CustomDataType */
+ /* eCustomDataType */
uint8_t data_type;
/* NodeMapRangeType. */
@@ -1229,14 +1185,14 @@ typedef struct NodeMapRange {
} NodeMapRange;
typedef struct NodeRandomValue {
- /* CustomDataType. */
+ /* eCustomDataType. */
uint8_t data_type;
} NodeRandomValue;
typedef struct NodeAccumulateField {
- /* CustomDataType. */
+ /* eCustomDataType. */
uint8_t data_type;
- /* AttributeDomain. */
+ /* eAttrDomain. */
uint8_t domain;
} NodeAccumulateField;
@@ -1292,6 +1248,11 @@ typedef struct NodeGeometryVolumeToMesh {
uint8_t resolution_mode;
} NodeGeometryVolumeToMesh;
+typedef struct NodeGeometryMeshToVolume {
+ /* MeshToVolumeModifierResolutionMode */
+ uint8_t resolution_mode;
+} NodeGeometryMeshToVolume;
+
typedef struct NodeGeometrySubdivisionSurface {
/* eSubsurfUVSmooth. */
uint8_t uv_smooth;
@@ -1406,9 +1367,9 @@ typedef struct NodeGeometryCurveSample {
} NodeGeometryCurveSample;
typedef struct NodeGeometryTransferAttribute {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
/* GeometryNodeAttributeTransferMode. */
uint8_t mode;
@@ -1419,7 +1380,7 @@ typedef struct NodeGeometryRaycast {
/* GeometryNodeRaycastMapMode. */
uint8_t mapping;
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
/* Deprecated input types in new Ray-cast node. Can be removed when legacy nodes are no longer
@@ -1438,21 +1399,21 @@ typedef struct NodeGeometryMeshToPoints {
} NodeGeometryMeshToPoints;
typedef struct NodeGeometryAttributeCapture {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
} NodeGeometryAttributeCapture;
typedef struct NodeGeometryStoreNamedAttribute {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
} NodeGeometryStoreNamedAttribute;
typedef struct NodeGeometryInputNamedAttribute {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
} NodeGeometryInputNamedAttribute;
@@ -1468,19 +1429,19 @@ typedef struct NodeGeometryStringToCurves {
} NodeGeometryStringToCurves;
typedef struct NodeGeometryDeleteGeometry {
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
/* GeometryNodeDeleteGeometryMode. */
int8_t mode;
} NodeGeometryDeleteGeometry;
typedef struct NodeGeometryDuplicateElements {
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
} NodeGeometryDuplicateElements;
typedef struct NodeGeometrySeparateGeometry {
- /* AttributeDomain. */
+ /* eAttrDomain. */
int8_t domain;
} NodeGeometrySeparateGeometry;
@@ -1490,10 +1451,15 @@ typedef struct NodeGeometryImageTexture {
} NodeGeometryImageTexture;
typedef struct NodeGeometryViewer {
- /* CustomDataType. */
+ /* eCustomDataType. */
int8_t data_type;
} NodeGeometryViewer;
+typedef struct NodeGeometryUVUnwrap {
+ /* GeometryNodeUVUnwrapMethod. */
+ uint8_t method;
+} NodeGeometryUVUnwrap;
+
typedef struct NodeFunctionCompare {
/* NodeCompareOperation */
int8_t operation;
@@ -1959,12 +1925,6 @@ typedef enum GeometryNodeBooleanOperation {
GEO_NODE_BOOLEAN_DIFFERENCE = 2,
} GeometryNodeBooleanOperation;
-typedef enum GeometryNodeSplineType {
- GEO_NODE_SPLINE_TYPE_BEZIER = 0,
- GEO_NODE_SPLINE_TYPE_NURBS = 1,
- GEO_NODE_SPLINE_TYPE_POLY = 2,
-} GeometryNodeSplineType;
-
typedef enum GeometryNodeCurvePrimitiveCircleMode {
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS = 0,
GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS = 1
@@ -2050,6 +2010,11 @@ typedef enum GeometryNodeMergeByDistanceMode {
GEO_NODE_MERGE_BY_DISTANCE_MODE_CONNECTED = 1,
} GeometryNodeMergeByDistanceMode;
+typedef enum GeometryNodeUVUnwrapMethod {
+ GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED = 0,
+ GEO_NODE_UV_UNWRAP_METHOD_CONFORMAL = 1,
+} GeometryNodeUVUnwrapMethod;
+
typedef enum GeometryNodeMeshLineMode {
GEO_NODE_MESH_LINE_MODE_END_POINTS = 0,
GEO_NODE_MESH_LINE_MODE_OFFSET = 1,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index f257833efe8..ac9e61e03e8 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -215,6 +215,10 @@ typedef struct ObjectLineArt {
/** if OBJECT_LRT_OWN_CREASE is set */
float crease_threshold;
+
+ unsigned char intersection_priority;
+
+ char _pad[7];
} ObjectLineArt;
/**
@@ -231,6 +235,7 @@ enum eObjectLineArt_Usage {
enum eObjectLineArt_Flags {
OBJECT_LRT_OWN_CREASE = (1 << 0),
+ OBJECT_LRT_OWN_INTERSECTION_PRIORITY = (1 << 1),
};
typedef struct Object {
@@ -374,7 +379,7 @@ typedef struct Object {
/** Dupliface scale. */
float instance_faces_scale;
- /** Custom index, for renderpasses. */
+ /** Custom index, for render-passes. */
short index;
/** Current deformation group, NOTE: index starts at 1. */
unsigned short actdef DNA_DEPRECATED;
@@ -429,7 +434,10 @@ typedef struct Object {
char empty_image_visibility_flag;
char empty_image_depth;
char empty_image_flag;
- char _pad8[5];
+
+ /** ObjectModifierFlag */
+ uint8_t modifier_flag;
+ char _pad8[4];
struct PreviewImage *preview;
@@ -783,6 +791,10 @@ enum {
OB_EMPTY_IMAGE_USE_ALPHA_BLEND = 1 << 0,
};
+typedef enum ObjectModifierFlag {
+ OB_MODIFIER_FLAG_ADD_REST_POSITION = 1 << 0,
+} ObjectModifierFlag;
+
#define MAX_DUPLI_RECUR 8
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h
index 1cb490190c3..ee829ebcf6e 100644
--- a/source/blender/makesdna/DNA_pointcloud_types.h
+++ b/source/blender/makesdna/DNA_pointcloud_types.h
@@ -18,13 +18,9 @@ typedef struct PointCloud {
struct AnimData *adt; /* animation data (must be immediately after id) */
int flag;
- int _pad1[1];
/* Geometry */
- float (*co)[3];
- float *radius;
int totpoint;
- int _pad2[1];
/* Custom Data */
struct CustomData pdata;
diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h
index 74db1d14bbc..6cc01d254ce 100644
--- a/source/blender/makesdna/DNA_scene_defaults.h
+++ b/source/blender/makesdna/DNA_scene_defaults.h
@@ -337,7 +337,9 @@
.snap_mode = SCE_SNAP_MODE_INCREMENT, \
.snap_node_mode = SCE_SNAP_MODE_GRID, \
.snap_uv_mode = SCE_SNAP_MODE_INCREMENT, \
+ .snap_flag = SCE_SNAP_TO_INCLUDE_EDITED | SCE_SNAP_TO_INCLUDE_NONEDITED, \
.snap_transform_mode_flag = SCE_SNAP_TRANSFORM_MODE_TRANSLATE, \
+ .snap_face_nearest_steps = 1, \
\
.curve_paint_settings = _DNA_DEFAULTS_CurvePaintSettings, \
\
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 1be27e0354c..f8fcd78d63b 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -991,6 +991,9 @@ typedef struct Sculpt {
// float pivot[3]; XXX not used?
int flags;
+ /* Transform tool. */
+ int transform_mode;
+
int automasking_flags;
/* Control tablet input */
@@ -1011,6 +1014,8 @@ typedef struct Sculpt {
float constant_detail;
float detail_percent;
+ char _pad[4];
+
struct Object *gravity_object;
} Sculpt;
@@ -1490,19 +1495,25 @@ typedef struct ToolSettings {
/* Transform */
char transform_pivot_point;
char transform_flag;
- /** Snap elements (per spacetype). */
- char snap_mode;
+ /** Snap elements (per spacetype), #eSnapMode. */
+ char _pad1[1];
+ short snap_mode;
char snap_node_mode;
char snap_uv_mode;
- /** Generic flags (per spacetype). */
- char snap_flag;
- char snap_flag_node;
- char snap_flag_seq;
- char snap_uv_flag;
- /** Default snap source. */
+ /** Generic flags (per spacetype), #eSnapFlag. */
+ short snap_flag;
+ short snap_flag_node;
+ short snap_flag_seq;
+ short snap_uv_flag;
+ /** Default snap source, #eSnapSourceSelect. */
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of
+ * "target" (now, "source" is geometry to be moved and "target" is geometry to which moved
+ * geometry is snapped). */
char snap_target;
- /** Snap mask for transform modes. */
+ /** Snap mask for transform modes, #eSnapTransformMode. */
char snap_transform_mode_flag;
+ /** Steps to break transformation into with face nearest snapping */
+ short snap_face_nearest_steps;
char proportional_edit, prop_mode;
/** Proportional edit, object mode. */
@@ -2043,10 +2054,6 @@ extern const char *RE_engine_id_CYCLES;
#define V3D_CAMERA_SCENE(scene, v3d) \
((!(v3d)->scenelock && (v3d)->camera) ? (v3d)->camera : (scene)->camera)
-#define CFRA (scene->r.cfra)
-#define SUBFRA (scene->r.subframe)
-#define SFRA (scene->r.sfra)
-#define EFRA (scene->r.efra)
#define PRVRANGEON (scene->r.flag & SCER_PRV_RANGE)
#define PSFRA ((PRVRANGEON) ? (scene->r.psfra) : (scene->r.sfra))
#define PEFRA ((PRVRANGEON) ? (scene->r.pefra) : (scene->r.efra))
@@ -2075,30 +2082,73 @@ enum {
};
/** #ToolSettings.snap_flag */
-#define SCE_SNAP (1 << 0)
-#define SCE_SNAP_ROTATE (1 << 1)
-#define SCE_SNAP_PEEL_OBJECT (1 << 2)
-#define SCE_SNAP_PROJECT (1 << 3)
-#define SCE_SNAP_NO_SELF (1 << 4)
-#define SCE_SNAP_ABS_GRID (1 << 5)
-#define SCE_SNAP_BACKFACE_CULLING (1 << 6)
-
-/** #ToolSettings.snap_target */
-#define SCE_SNAP_TARGET_CLOSEST 0
-#define SCE_SNAP_TARGET_CENTER 1
-#define SCE_SNAP_TARGET_MEDIAN 2
-#define SCE_SNAP_TARGET_ACTIVE 3
+typedef enum eSnapFlag {
+ SCE_SNAP = (1 << 0),
+ SCE_SNAP_ROTATE = (1 << 1),
+ SCE_SNAP_PEEL_OBJECT = (1 << 2),
+ SCE_SNAP_PROJECT = (1 << 3), /* Project individual elements instead of whole object. */
+ SCE_SNAP_NOT_TO_ACTIVE = (1 << 4), /* Was `SCE_SNAP_NO_SELF`, but self should be active. */
+ SCE_SNAP_ABS_GRID = (1 << 5),
+ SCE_SNAP_BACKFACE_CULLING = (1 << 6),
+ SCE_SNAP_KEEP_ON_SAME_OBJECT = (1 << 7),
+ /* see #eSnapTargetSelect */
+ SCE_SNAP_TO_INCLUDE_EDITED = (1 << 8),
+ SCE_SNAP_TO_INCLUDE_NONEDITED = (1 << 9),
+ SCE_SNAP_TO_ONLY_SELECTABLE = (1 << 10),
+} eSnapFlag;
+/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
+/* TODO: move this macro to a more general place. */
+#ifdef ENUM_OPERATORS
+ENUM_OPERATORS(eSnapFlag, SCE_SNAP_BACKFACE_CULLING)
+#endif
+
+/** See #ToolSettings.snap_target (to be renamed `snap_source`) and #TransSnap.source_select */
+typedef enum eSnapSourceSelect {
+ SCE_SNAP_SOURCE_CLOSEST = 0,
+ SCE_SNAP_SOURCE_CENTER = 1,
+ SCE_SNAP_SOURCE_MEDIAN = 2,
+ SCE_SNAP_SOURCE_ACTIVE = 3,
+} eSnapSourceSelect;
+
+/** #TransSnap.target_select and #ToolSettings.snap_flag (#SCE_SNAP_NOT_TO_ACTIVE,
+ * #SCE_SNAP_TO_INCLUDE_EDITED, #SCE_SNAP_TO_INCLUDE_NONEDITED, #SCE_SNAP_TO_ONLY_SELECTABLE) */
+typedef enum eSnapTargetSelect {
+ SCE_SNAP_TARGET_ALL = 0,
+ SCE_SNAP_TARGET_NOT_SELECTED = (1 << 0),
+ SCE_SNAP_TARGET_NOT_ACTIVE = (1 << 1),
+ SCE_SNAP_TARGET_NOT_EDITED = (1 << 2),
+ SCE_SNAP_TARGET_ONLY_SELECTABLE = (1 << 3),
+ SCE_SNAP_TARGET_NOT_NONEDITED = (1 << 4),
+} eSnapTargetSelect;
/** #ToolSettings.snap_mode */
-#define SCE_SNAP_MODE_VERTEX (1 << 0)
-#define SCE_SNAP_MODE_EDGE (1 << 1)
-#define SCE_SNAP_MODE_FACE (1 << 2)
-#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)
+typedef enum eSnapMode {
+ SCE_SNAP_MODE_NONE = 0,
+ SCE_SNAP_MODE_VERTEX = (1 << 0),
+ SCE_SNAP_MODE_EDGE = (1 << 1),
+ SCE_SNAP_MODE_FACE_RAYCAST = (1 << 2),
+ SCE_SNAP_MODE_VOLUME = (1 << 3),
+ SCE_SNAP_MODE_EDGE_MIDPOINT = (1 << 4),
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR = (1 << 5),
+ SCE_SNAP_MODE_FACE_NEAREST = (1 << 8),
+
+ SCE_SNAP_MODE_GEOM = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST |
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT |
+ SCE_SNAP_MODE_FACE_NEAREST),
+
+ /** #ToolSettings.snap_node_mode */
+ SCE_SNAP_MODE_NODE_X = (1 << 0),
+ SCE_SNAP_MODE_NODE_Y = (1 << 1),
+
+ /** #ToolSettings.snap_mode and #ToolSettings.snap_node_mode and #ToolSettings.snap_uv_mode */
+ SCE_SNAP_MODE_INCREMENT = (1 << 6),
+ SCE_SNAP_MODE_GRID = (1 << 7),
+} eSnapMode;
+/* Due to dependency conflicts with Cycles, header cannot directly include `BLI_utildefines.h`. */
+/* TODO: move this macro to a more general place. */
+#ifdef ENUM_OPERATORS
+ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_GRID)
+#endif
/** #SequencerToolSettings.snap_mode */
#define SEQ_SNAP_TO_STRIPS (1 << 0)
@@ -2110,22 +2160,12 @@ enum {
#define SEQ_SNAP_IGNORE_SOUND (1 << 1)
#define SEQ_SNAP_CURRENT_FRAME_TO_STRIPS (1 << 2)
-/** #ToolSettings.snap_node_mode */
-#define SCE_SNAP_MODE_NODE_X (1 << 0)
-#define SCE_SNAP_MODE_NODE_Y (1 << 1)
-
-/**
- * #ToolSettings.snap_mode and #ToolSettings.snap_node_mode
- */
-#define SCE_SNAP_MODE_INCREMENT (1 << 6)
-#define SCE_SNAP_MODE_GRID (1 << 7)
-
/** #ToolSettings.snap_transform_mode_flag */
-enum {
+typedef enum eSnapTransformMode {
SCE_SNAP_TRANSFORM_MODE_TRANSLATE = (1 << 0),
SCE_SNAP_TRANSFORM_MODE_ROTATE = (1 << 1),
SCE_SNAP_TRANSFORM_MODE_SCALE = (1 << 2),
-};
+} eSnapTransformMode;
/** #ToolSettings.selectmode */
#define SCE_SELECT_VERTEX (1 << 0) /* for mesh */
@@ -2279,6 +2319,12 @@ typedef enum eSculptFlags {
SCULPT_HIDE_FACE_SETS = (1 << 17),
} eSculptFlags;
+/* Sculpt.transform_mode */
+typedef enum eSculptTransformMode {
+ SCULPT_TRANSFORM_MODE_ALL_VERTICES = 0,
+ SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC = 1,
+} eSculptTrasnformMode;
+
/** PaintModeSettings.mode */
typedef enum ePaintCanvasSource {
/** Paint on the active node of the active material slot. */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 8560f8a454e..e9178c0cbf5 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -305,12 +305,6 @@ typedef struct uiList { /* some list UI data need to be saved in file */
int filter_flag;
int filter_sort_flag;
- /** Operator executed when activating an item. */
- const char *custom_activate_opname;
- /** Operator executed when dragging an item (item gets activated too, without running
- * custom_activate_opname above). */
- const char *custom_drag_opname;
-
/* Custom sub-classes properties. */
IDProperty *properties;
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index a54fd838bbe..a46d737ba9d 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -151,21 +151,21 @@ typedef struct Sequence {
* Start frame of contents of strip in absolute frame coordinates.
* For metastrips start of first strip startdisp.
*/
- int start;
+ float start;
/**
* Frames after the first frame where display starts,
* frames before the last frame where display ends.
*/
- int startofs, endofs;
+ float startofs, endofs;
/**
* Frames that use the first frame before data begins,
* frames that use the last frame after data ends.
*/
- int startstill DNA_DEPRECATED, endstill DNA_DEPRECATED;
+ float startstill, endstill;
/** Machine: the strip channel */
int machine;
int _pad3;
- /** Starting and ending points of the strip in the sequence. */
+ /** Starting and ending points of the effect strip. Undefined for other strip types. */
int startdisp, enddisp;
float sat;
float mul;
@@ -213,7 +213,7 @@ typedef struct Sequence {
float volume;
/** Pitch (-0.1..10), pan -2..2. */
- float pitch, pan;
+ float pitch DNA_DEPRECATED, pan;
float strobe;
/** Struct pointer for effect settings. */
@@ -249,6 +249,11 @@ typedef struct Sequence {
/* modifiers */
ListBase modifiers;
+ /* Playback rate of strip content in frames per second. */
+ float media_playback_rate;
+ /* Multiply strip playback speed. */
+ float speed_factor;
+
SequenceRuntime runtime;
} Sequence;
@@ -563,7 +568,7 @@ enum {
SEQ_LOCK = (1 << 14),
SEQ_USE_PROXY = (1 << 15),
SEQ_IGNORE_CHANNEL_LOCK = (1 << 16),
- SEQ_FLAG_UNUSED_22 = (1 << 17), /* cleared */
+ SEQ_AUTO_PLAYBACK_RATE = (1 << 17),
SEQ_FLAG_UNUSED_18 = (1 << 18), /* cleared */
SEQ_FLAG_UNUSED_19 = (1 << 19), /* cleared */
SEQ_FLAG_UNUSED_21 = (1 << 21), /* cleared */
diff --git a/source/blender/makesdna/DNA_space_defaults.h b/source/blender/makesdna/DNA_space_defaults.h
index e826cb4c2ef..6193c8c2ad1 100644
--- a/source/blender/makesdna/DNA_space_defaults.h
+++ b/source/blender/makesdna/DNA_space_defaults.h
@@ -15,9 +15,10 @@
#define _DNA_DEFAULT_MaskSpaceInfo \
{ \
- .draw_flag = 0, \
+ .draw_flag = MASK_DRAWFLAG_SPLINE, \
.draw_type = MASK_DT_OUTLINE, \
.overlay_mode = MASK_OVERLAY_ALPHACHANNEL, \
+ .blend_factor = 0.7f, \
}
#define _DNA_DEFAULT_SpaceClip \
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index e33fbeb22cd..f286cfcff0b 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -732,7 +732,8 @@ typedef struct MaskSpaceInfo {
char draw_flag;
char draw_type;
char overlay_mode;
- char _pad3[5];
+ char _pad3[1];
+ float blend_factor;
} MaskSpaceInfo;
/** #SpaceSeq.gizmo_flag */
@@ -1930,9 +1931,9 @@ typedef struct SpaceSpreadsheet {
/* #GeometryComponentType. */
uint8_t geometry_component_type;
- /* #AttributeDomain. */
+ /* #eAttrDomain. */
uint8_t attribute_domain;
- /* eSpaceSpreadsheet_ObjectContext. */
+ /* eSpaceSpreadsheet_ObjectEvalState. */
uint8_t object_eval_state;
/* eSpaceSpreadsheet_Flag. */
@@ -1970,7 +1971,7 @@ typedef struct SpreadsheetRowFilter {
float value_float2[2];
float value_float3[3];
float value_color[4];
- uint8_t value_byte_color[4];
+ char _pad1[4];
} SpreadsheetRowFilter;
typedef enum eSpaceSpreadsheet_RowFilterFlag {
@@ -2008,6 +2009,7 @@ typedef enum eSpreadsheetColumnValueType {
SPREADSHEET_VALUE_TYPE_INSTANCES = 6,
SPREADSHEET_VALUE_TYPE_STRING = 7,
SPREADSHEET_VALUE_TYPE_BYTE_COLOR = 8,
+ SPREADSHEET_VALUE_TYPE_INT8 = 9,
} eSpreadsheetColumnValueType;
/**
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index b725939dbab..e32d9dbe300 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -397,8 +397,7 @@ typedef struct ColorMapping {
/* return value */
#define TEX_INT 0
-#define TEX_RGB (1 << 0)
-#define TEX_NOR (1 << 1)
+#define TEX_RGB 1
/* pr_texture in material, world, light. */
#define TEX_PR_TEXTURE 0
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 2a90212c24e..3bded743ef2 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -315,7 +315,7 @@ typedef struct ThemeSpace {
char _pad5[3];
float dash_alpha;
- /* syntax for textwindow and nodes */
+ /* Syntax for text-window and nodes. */
unsigned char syntaxl[4], syntaxs[4]; /* in nodespace used for backdrop matte */
unsigned char syntaxb[4], syntaxn[4]; /* in nodespace used for color input */
unsigned char syntaxv[4], syntaxc[4]; /* in nodespace used for converter group */
@@ -638,14 +638,13 @@ typedef struct UserDef_Experimental {
/* Debug options, always available. */
char use_undo_legacy;
char no_override_auto_resync;
+ char use_override_new_fully_editable;
char use_cycles_debug;
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. */
- char use_new_curves_type;
- /** Only available when #use_new_curves_type is enabled. */
char use_new_curves_tools;
char use_new_point_cloud_type;
char use_full_frame_compositor;
@@ -860,7 +859,7 @@ typedef struct UserDef {
float glalphaclip;
- /** #eAutokey_Mode, autokeying mode. */
+ /** #eAutokey_Mode, auto-keying mode. */
short autokey_mode;
/** Flags for autokeying. */
short autokey_flag;
@@ -915,8 +914,7 @@ typedef struct UserDef {
/** Pie menu distance from center before a direction is set. */
short pie_menu_threshold;
- short opensubdiv_compute_type;
- short _pad6;
+ short _pad6[2];
char factor_display_type;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index cfd0c986df9..116ea4821cb 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -239,6 +239,9 @@ typedef struct wmWindow {
struct Scene *new_scene;
/** Active view layer displayed in this window. */
char view_layer_name[64];
+ /** The workspace may temporarily override the window's scene with scene pinning. This is the
+ * "overridden" or "default" scene to restore when entering a workspace with no scene pinned. */
+ struct Scene *unpinned_scene;
struct WorkSpaceInstanceHook *workspace_hook;
@@ -404,13 +407,13 @@ enum {
KMI_USER_MODIFIED = (1 << 2),
KMI_UPDATE = (1 << 3),
/**
- * When set, ignore events with #wmEvent.is_repeat enabled.
+ * When set, ignore events with `wmEvent.flag & WM_EVENT_IS_REPEAT` enabled.
*
* \note this flag isn't cleared when editing/loading the key-map items,
* so it may be set in cases which don't make sense (modifier-keys or mouse-motion for example).
*
* Knowing if an event may repeat is something set at the operating-systems event handling level
- * so rely on #wmEvent.is_repeat being false non keyboard events instead of checking if this
+ * so rely on #WM_EVENT_IS_REPEAT being false non keyboard events instead of checking if this
* flag makes sense.
*
* Only used when: `ISKEYBOARD(kmi->type) || (kmi->type == KM_TEXTINPUT)`
@@ -463,14 +466,19 @@ typedef struct wmKeyMap {
/** #wmKeyMap.flag */
enum {
- KEYMAP_MODAL = (1 << 0), /* modal map, not using operatornames */
- KEYMAP_USER = (1 << 1), /* user keymap */
+ /** Modal map, not using operator-names. */
+ KEYMAP_MODAL = (1 << 0),
+ /** User key-map. */
+ KEYMAP_USER = (1 << 1),
KEYMAP_EXPANDED = (1 << 2),
KEYMAP_CHILDREN_EXPANDED = (1 << 3),
- KEYMAP_DIFF = (1 << 4), /* diff keymap for user preferences */
- KEYMAP_USER_MODIFIED = (1 << 5), /* keymap has user modifications */
+ /** Diff key-map for user preferences. */
+ KEYMAP_DIFF = (1 << 4),
+ /** Key-map has user modifications. */
+ KEYMAP_USER_MODIFIED = (1 << 5),
KEYMAP_UPDATE = (1 << 6),
- KEYMAP_TOOL = (1 << 7), /* keymap for active tool system */
+ /** key-map for active tool system. */
+ KEYMAP_TOOL = (1 << 7),
};
/**
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index b8ed39bfd5d..a72689badb1 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -123,6 +123,10 @@ typedef struct WorkSpace {
/** List of #bToolRef */
ListBase tools;
+ /** Optional, scene to switch to when enabling this workspace (NULL to disable). Cleared on
+ * link/append. */
+ struct Scene *pin_scene;
+
char _pad[4];
int object_mode;
@@ -195,6 +199,7 @@ typedef struct WorkSpaceInstanceHook {
typedef enum eWorkSpaceFlags {
WORKSPACE_USE_FILTER_BY_ORIGIN = (1 << 1),
+ WORKSPACE_USE_PIN_SCENE = (1 << 2),
} eWorkSpaceFlags;
#ifdef __cplusplus
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 4267ce47d81..005228bea72 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -284,7 +284,7 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, const int i
*/
bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop);
-bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop);
+bool RNA_property_animateable(const 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
@@ -490,6 +490,18 @@ char *RNA_path_append(
char *RNA_path_back(const char *path);
#endif
+/**
+ * Search for the start of the 'rna array index' part of the given `rna_path`.
+ *
+ * Given the root RNA pointer and resolved RNA property, and the RNA path, return the first
+ * character in `rna_path` that is part of the array index for the given property. Return NULL if
+ * none can be found, e.g. because the property is not an RNA array.
+ *
+ * \param array_prop: if not NULL, the #PropertyRNA assumed to be the last one from the RNA path.
+ * Only used to ensure it is a valid array property.
+ */
+const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop);
+
/* RNA_path_resolve() variants only ensure that a valid pointer (and optionally property) exist. */
/**
diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h
index 127c8465243..61c5c1a6c72 100644
--- a/source/blender/makesrna/RNA_enum_items.h
+++ b/source/blender/makesrna/RNA_enum_items.h
@@ -21,7 +21,7 @@ DEF_ENUM(rna_enum_metaelem_type_items)
DEF_ENUM(rna_enum_proportional_falloff_items)
DEF_ENUM(rna_enum_proportional_falloff_curve_only_items)
-DEF_ENUM(rna_enum_snap_target_items)
+DEF_ENUM(rna_enum_snap_source_items)
DEF_ENUM(rna_enum_snap_element_items)
DEF_ENUM(rna_enum_snap_node_element_items)
DEF_ENUM(rna_enum_curve_fit_method_items)
@@ -108,7 +108,7 @@ DEF_ENUM(rna_enum_brush_gpencil_types_items)
DEF_ENUM(rna_enum_brush_gpencil_vertex_types_items)
DEF_ENUM(rna_enum_brush_gpencil_sculpt_types_items)
DEF_ENUM(rna_enum_brush_gpencil_weight_types_items)
-DEF_ENUM(rna_enum_brush_curves_sculpt_tool_items);
+DEF_ENUM(rna_enum_brush_curves_sculpt_tool_items)
DEF_ENUM(rna_enum_brush_image_tool_items)
DEF_ENUM(rna_enum_axis_xy_items)
@@ -147,10 +147,19 @@ DEF_ENUM(rna_enum_keymap_propvalue_items)
DEF_ENUM(rna_enum_operator_context_items)
DEF_ENUM(rna_enum_wm_report_items)
+DEF_ENUM(rna_enum_wm_job_type_items)
DEF_ENUM(rna_enum_property_type_items)
DEF_ENUM(rna_enum_property_subtype_items)
+DEF_ENUM(rna_enum_property_subtype_string_items)
+DEF_ENUM(rna_enum_property_subtype_number_items)
+DEF_ENUM(rna_enum_property_subtype_number_array_items)
DEF_ENUM(rna_enum_property_unit_items)
+DEF_ENUM(rna_enum_property_flag_items)
+DEF_ENUM(rna_enum_property_flag_enum_items)
+DEF_ENUM(rna_enum_property_override_flag_items)
+DEF_ENUM(rna_enum_property_override_flag_collection_items)
+DEF_ENUM(rna_enum_property_string_search_flag_items)
DEF_ENUM(rna_enum_shading_type_items)
@@ -201,6 +210,7 @@ DEF_ENUM(rna_enum_attribute_type_items)
DEF_ENUM(rna_enum_color_attribute_type_items)
DEF_ENUM(rna_enum_attribute_type_with_auto_items)
DEF_ENUM(rna_enum_attribute_domain_items)
+DEF_ENUM(rna_enum_attribute_curves_domain_items)
DEF_ENUM(rna_enum_color_attribute_domain_items)
DEF_ENUM(rna_enum_attribute_domain_without_corner_items)
DEF_ENUM(rna_enum_attribute_domain_with_auto_items)
@@ -218,6 +228,8 @@ DEF_ENUM(rna_enum_transform_orientation_items)
DEF_ENUM(rna_enum_velocity_unit_items)
+DEF_ENUM(rna_enum_curves_types)
+
/* Not available to RNA pre-processing (`makesrna`).
* Defined in editors for example. */
#ifndef RNA_MAKESRNA
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index 75b514cdb13..5346228050a 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -467,6 +467,27 @@ typedef struct EnumPropertyItem {
const char *description;
} EnumPropertyItem;
+/**
+ * Heading for RNA enum items (shown in the UI).
+ *
+ * The description is currently only shown in the Python documentation.
+ * By convention the value should be a non-empty string or NULL when there is no description
+ * (never an empty string).
+ */
+#define RNA_ENUM_ITEM_HEADING(name, description) \
+ { \
+ 0, "", 0, name, description \
+ }
+
+/** Separator for RNA enum items (shown in the UI). */
+#define RNA_ENUM_ITEM_SEPR \
+ { \
+ 0, "", 0, NULL, NULL \
+ }
+
+/** Separator for RNA enum that begins a new column in menus (shown in the UI). */
+#define RNA_ENUM_ITEM_SEPR_COLUMN RNA_ENUM_ITEM_HEADING("", NULL)
+
/* extended versions with PropertyRNA argument */
typedef bool (*BooleanPropertyGetFunc)(struct PointerRNA *ptr, struct PropertyRNA *prop);
typedef void (*BooleanPropertySetFunc)(struct PointerRNA *ptr,
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 9980545c19d..778c6a6bfdd 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -84,7 +84,6 @@ set(DEFSRC
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
- add_definitions(-DWITH_NEW_CURVES_TYPE)
list(APPEND DEFSRC
rna_curves.c
rna_simulation.c
@@ -237,7 +236,7 @@ if(WITH_IMAGE_HDR)
endif()
if(WITH_IMAGE_WEBP)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
if(WITH_AUDASPACE)
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 400944d60d4..2b24bd0b39c 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -1117,8 +1117,10 @@ static char *rna_def_property_set_func(
fprintf(
f, " if (data->%s != NULL) { MEM_freeN(data->%s); }\n", dp->dnaname, dp->dnaname);
fprintf(f, " const int length = strlen(value);\n");
- fprintf(f, " data->%s = MEM_mallocN(length + 1, __func__);\n", dp->dnaname);
- fprintf(f, " %s(data->%s, value, length + 1);\n", string_copy_func, dp->dnaname);
+ fprintf(f, " if (length > 0) {\n");
+ fprintf(f, " data->%s = MEM_mallocN(length + 1, __func__);\n", dp->dnaname);
+ fprintf(f, " %s(data->%s, value, length + 1);\n", string_copy_func, dp->dnaname);
+ fprintf(f, " } else { data->%s = NULL; }\n", dp->dnaname);
}
else {
/* Handle char array properties. */
@@ -3030,7 +3032,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA
}
if (dparm->next) {
- fprintf(f, "\t_data += %d;\n", rna_parameter_size(dparm->prop));
+ fprintf(f, "\t_data += %d;\n", rna_parameter_size_pad(rna_parameter_size(dparm->prop)));
}
}
@@ -4433,9 +4435,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint},
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
{"rna_gpencil.c", NULL, RNA_def_gpencil},
-#ifdef WITH_NEW_CURVES_TYPE
{"rna_curves.c", NULL, RNA_def_curves},
-#endif
{"rna_image.c", "rna_image_api.c", RNA_def_image},
{"rna_key.c", NULL, RNA_def_key},
{"rna_light.c", NULL, RNA_def_light},
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index b5cf8abaac6..b4fa7088d38 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -16,6 +16,7 @@
#include "BKE_icons.h"
#include "BKE_lib_id.h"
+#include "BKE_main_namemap.h"
#include "BKE_object.h"
#include "RNA_access.h"
@@ -33,41 +34,41 @@ const EnumPropertyItem rna_enum_id_type_items[] = {
{ID_AC, "ACTION", ICON_ACTION, "Action", ""},
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
- {ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
{ID_CF, "CACHEFILE", ICON_FILE, "Cache File", ""},
+ {ID_CA, "CAMERA", ICON_CAMERA_DATA, "Camera", ""},
+ {ID_GR, "COLLECTION", ICON_OUTLINER_COLLECTION, "Collection", ""},
{ID_CU_LEGACY, "CURVE", ICON_CURVE_DATA, "Curve", ""},
+ {ID_CV, "CURVES", ICON_CURVES_DATA, "Curves", ""},
{ID_VF, "FONT", ICON_FONT_DATA, "Font", ""},
{ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""},
- {ID_GR, "COLLECTION", ICON_OUTLINER_COLLECTION, "Collection", ""},
{ID_IM, "IMAGE", ICON_IMAGE_DATA, "Image", ""},
{ID_KE, "KEY", ICON_SHAPEKEY_DATA, "Key", ""},
- {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""},
+ {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_LI, "LIBRARY", ICON_LIBRARY_DATA_DIRECT, "Library", ""},
+ {ID_LA, "LIGHT", ICON_LIGHT_DATA, "Light", ""},
+ {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
{ID_LS, "LINESTYLE", ICON_LINE_DATA, "Line Style", ""},
- {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_MSK, "MASK", ICON_MOD_MASK, "Mask", ""},
{ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""},
- {ID_MB, "META", ICON_META_DATA, "Metaball", ""},
{ID_ME, "MESH", ICON_MESH_DATA, "Mesh", ""},
+ {ID_MB, "META", ICON_META_DATA, "Metaball", ""},
{ID_MC, "MOVIECLIP", ICON_TRACKER, "Movie Clip", ""},
{ID_NT, "NODETREE", ICON_NODETREE, "Node Tree", ""},
{ID_OB, "OBJECT", ICON_OBJECT_DATA, "Object", ""},
{ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""},
{ID_PAL, "PALETTE", ICON_COLOR, "Palette", ""},
{ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""},
- {ID_LP, "LIGHT_PROBE", ICON_LIGHTPROBE_CUBEMAP, "Light Probe", ""},
+ {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "Point Cloud", ""},
{ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""},
{ID_SIM, "SIMULATION", ICON_PHYSICS, "Simulation", ""}, /* TODO: Use correct icon. */
{ID_SO, "SOUND", ICON_SOUND, "Sound", ""},
{ID_SPK, "SPEAKER", ICON_SPEAKER, "Speaker", ""},
{ID_TXT, "TEXT", ICON_TEXT, "Text", ""},
{ID_TE, "TEXTURE", ICON_TEXTURE_DATA, "Texture", ""},
- {ID_CV, "CURVES", ICON_CURVES_DATA, "Hair Curves", ""},
- {ID_PT, "POINTCLOUD", ICON_POINTCLOUD_DATA, "Point Cloud", ""},
{ID_VO, "VOLUME", ICON_VOLUME_DATA, "Volume", ""},
{ID_WM, "WINDOWMANAGER", ICON_WINDOW, "Window Manager", ""},
- {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
{ID_WS, "WORKSPACE", ICON_WORKSPACE, "Workspace", ""},
+ {ID_WO, "WORLD", ICON_WORLD_DATA, "World", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -273,6 +274,7 @@ int rna_ID_name_length(PointerRNA *ptr)
void rna_ID_name_set(PointerRNA *ptr, const char *value)
{
ID *id = (ID *)ptr->data;
+ BKE_main_namemap_remove_name(G_MAIN, id, id->name + 2);
BLI_strncpy_utf8(id->name + 2, value, sizeof(id->name) - 2);
BLI_assert(BKE_id_is_in_global_main(id));
BLI_libblock_ensure_unique_name(G_MAIN, id->name);
@@ -375,11 +377,9 @@ short RNA_type_to_ID_code(const StructRNA *type)
if (base_type == &RNA_FreestyleLineStyle) {
return ID_LS;
}
-# ifdef WITH_NEW_CURVES_TYPE
if (base_type == &RNA_Curves) {
return ID_CV;
}
-# endif
if (base_type == &RNA_Lattice) {
return ID_LT;
}
@@ -483,11 +483,7 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_GR:
return &RNA_Collection;
case ID_CV:
-# ifdef WITH_NEW_CURVES_TYPE
return &RNA_Curves;
-# else
- return &RNA_ID;
-# endif
case ID_IM:
return &RNA_Image;
case ID_KE:
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index c8cb0b7ffb8..cf4182243b9 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -1989,7 +1989,7 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, const int i
return rna_property_editable_do(ptr, prop, index, NULL);
}
-bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop)
+bool RNA_property_animateable(const PointerRNA *ptr, PropertyRNA *prop)
{
/* check that base ID-block can support animation data */
if (!id_can_have_animdata(ptr->owner_id)) {
@@ -2141,6 +2141,7 @@ void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
{
+ BLI_assert(bmain != NULL);
rna_property_update(NULL, bmain, scene, ptr, prop);
}
@@ -5482,6 +5483,52 @@ static UNUSED_FUNCTION_WITH_RETURN_TYPE(char *, RNA_path_back)(const char *path)
return result;
}
+const char *RNA_path_array_index_token_find(const char *rna_path, const PropertyRNA *array_prop)
+{
+ if (array_prop != NULL) {
+ if (!ELEM(array_prop->type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ BLI_assert(array_prop->arraydimension == 0);
+ return NULL;
+ }
+ if (array_prop->arraydimension == 0) {
+ return NULL;
+ }
+ }
+
+ /* Valid 'array part' of a rna path can only have '[', ']' and digit characters.
+ * It may have more than one of those (e.g. `[12][1]`) in case of multi-dimensional arrays. */
+ off_t rna_path_len = (off_t)strlen(rna_path);
+ if (rna_path[rna_path_len] != ']') {
+ return NULL;
+ }
+ const char *last_valid_index_token_start = NULL;
+ for (rna_path_len--; rna_path_len >= 0; rna_path_len--) {
+ switch (rna_path[rna_path_len]) {
+ case '[':
+ if (rna_path_len <= 0 || rna_path[rna_path_len - 1] != ']') {
+ return &rna_path[rna_path_len];
+ }
+ last_valid_index_token_start = &rna_path[rna_path_len];
+ rna_path_len--;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ default:
+ return last_valid_index_token_start;
+ }
+ }
+ return last_valid_index_token_start;
+}
+
/* generic path search func
* if its needed this could also reference the IDProperty direct */
typedef struct IDP_Chain {
@@ -6062,7 +6109,7 @@ char *RNA_path_struct_property_py(PointerRNA *ptr, PropertyRNA *prop, int index)
}
if ((index == -1) || (RNA_property_array_check(prop) == false)) {
- ret = BLI_sprintfN("%s", data_path);
+ ret = BLI_strdup(data_path);
}
else {
ret = BLI_sprintfN("%s[%d]", data_path, index);
@@ -7084,7 +7131,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms,
/* allocate data */
for (parm = func->cont.properties.first; parm; parm = parm->next) {
- alloc_size += rna_parameter_size(parm);
+ alloc_size += rna_parameter_size_pad(rna_parameter_size(parm));
if (parm->flag_parameter & PARM_OUTPUT) {
parms->ret_count++;
@@ -7160,7 +7207,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms,
}
}
- data = ((char *)data) + rna_parameter_size(parm);
+ data = ((char *)data) + rna_parameter_size_pad(size);
}
return parms;
@@ -7184,7 +7231,7 @@ void RNA_parameter_list_free(ParameterList *parms)
}
}
- tot += rna_parameter_size(parm);
+ tot += rna_parameter_size_pad(rna_parameter_size(parm));
}
MEM_freeN(parms->data);
@@ -7226,7 +7273,7 @@ void RNA_parameter_list_begin(ParameterList *parms, ParameterIterator *iter)
void RNA_parameter_list_next(ParameterIterator *iter)
{
- iter->offset += iter->size;
+ iter->offset += rna_parameter_size_pad(iter->size);
iter->parm = iter->parm->next;
iter->valid = iter->parm != NULL;
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index aea4467c162..17c00923efa 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -12,6 +12,7 @@
#include "DNA_ID.h"
#include "DNA_anim_types.h"
+#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_key_types.h"
@@ -145,6 +146,12 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
return true;
}
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_CameraBackgroundImage)) {
+ CameraBGImage *bgpic = ptr->data;
+ if (bgpic->flag & CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL) {
+ return true;
+ }
+ }
/* If this is a RNA-defined property (real or 'virtual' IDProp),
* we want to use RNA prop flag. */
return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index a1266443631..ac90ec69784 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -168,6 +168,12 @@ static void rna_Action_fcurve_remove(bAction *act, ReportList *reports, PointerR
WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
+static void rna_Action_fcurve_clear(bAction *act)
+{
+ BKE_action_fcurves_clear(act);
+ WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
static TimeMarker *rna_Action_pose_markers_new(bAction *act, const char name[])
{
TimeMarker *marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
@@ -788,6 +794,10 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "F-Curve to remove");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
+
+ /* Action.fcurves.clear() */
+ func = RNA_def_function(srna, "clear", "rna_Action_fcurve_clear");
+ RNA_def_function_ui_description(func, "Remove all F-Curves");
}
static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c
index 36706c82366..5e17f22ecf5 100644
--- a/source/blender/makesrna/intern/rna_attribute.c
+++ b/source/blender/makesrna/intern/rna_attribute.c
@@ -106,6 +106,11 @@ const EnumPropertyItem rna_enum_color_attribute_domain_items[] = {
{ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", ""},
{0, NULL, 0, NULL, NULL}};
+const EnumPropertyItem rna_enum_attribute_curves_domain_items[] = {
+ {ATTR_DOMAIN_POINT, "POINT", 0, "Control Point", ""},
+ {ATTR_DOMAIN_CURVE, "CURVE", 0, "Curve", ""},
+ {0, NULL, 0, NULL, NULL}};
+
#ifdef RNA_RUNTIME
# include "BLI_math.h"
@@ -124,7 +129,7 @@ static char *rna_Attribute_path(const PointerRNA *ptr)
return BLI_sprintfN("attributes['%s']", layer->name);
}
-static StructRNA *srna_by_custom_data_layer_type(const CustomDataType type)
+static StructRNA *srna_by_custom_data_layer_type(const eCustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT:
@@ -158,13 +163,14 @@ static StructRNA *rna_Attribute_refine(PointerRNA *ptr)
static void rna_Attribute_name_set(PointerRNA *ptr, const char *value)
{
- BKE_id_attribute_rename(ptr->owner_id, ptr->data, value, NULL);
+ const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
+ BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
}
static int rna_Attribute_name_editable(PointerRNA *ptr, const char **r_info)
{
CustomDataLayer *layer = ptr->data;
- if (BKE_id_attribute_required(ptr->owner_id, layer)) {
+ if (BKE_id_attribute_required(ptr->owner_id, layer->name)) {
*r_info = N_("Cannot modify name of required geometry attribute");
return false;
}
@@ -232,6 +238,12 @@ static int rna_Attribute_domain_get(PointerRNA *ptr)
return BKE_id_attribute_domain(ptr->owner_id, ptr->data);
}
+static bool rna_Attribute_is_internal_get(PointerRNA *ptr)
+{
+ const CustomDataLayer *layer = (const CustomDataLayer *)ptr->data;
+ return BKE_attribute_allow_procedural_access(layer->name);
+}
+
static void rna_Attribute_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
ID *id = ptr->owner_id;
@@ -347,8 +359,8 @@ static PointerRNA rna_AttributeGroup_new(
static void rna_AttributeGroup_remove(ID *id, ReportList *reports, PointerRNA *attribute_ptr)
{
- CustomDataLayer *layer = (CustomDataLayer *)attribute_ptr->data;
- BKE_id_attribute_remove(id, layer, reports);
+ const CustomDataLayer *layer = (const CustomDataLayer *)attribute_ptr->data;
+ BKE_id_attribute_remove(id, layer->name, reports);
RNA_POINTER_INVALIDATE(attribute_ptr);
DEG_id_tag_update(id, ID_RECALC_GEOMETRY);
@@ -367,7 +379,7 @@ static int rna_Attributes_noncolor_layer_skip(CollectionPropertyIterator *iter,
/* Check valid domain here, too, keep in line with rna_AttributeGroup_color_length(). */
ID *id = iter->parent.owner_id;
- AttributeDomain domain = BKE_id_attribute_domain(id, layer);
+ eAttrDomain domain = BKE_id_attribute_domain(id, layer);
if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
return 1;
}
@@ -527,7 +539,7 @@ static void rna_AttributeGroup_active_color_set(PointerRNA *ptr,
static int rna_AttributeGroup_active_color_index_get(PointerRNA *ptr)
{
- CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id);
+ const CustomDataLayer *layer = BKE_id_attributes_active_color_get(ptr->owner_id);
return BKE_id_attribute_to_index(
ptr->owner_id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL);
@@ -930,6 +942,12 @@ static void rna_def_attribute(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Domain", "Domain of the Attribute");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ prop = RNA_def_property(srna, "is_internal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_Attribute_is_internal_get", NULL);
+ RNA_def_property_ui_text(
+ prop, "Is Internal", "The attribute is meant for internal use by Blender");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
/* types */
rna_def_attribute_float(brna);
rna_def_attribute_float_vector(brna);
@@ -942,7 +960,7 @@ static void rna_def_attribute(BlenderRNA *brna)
rna_def_attribute_int8(brna);
}
-/* Mesh/PointCloud/Hair.attributes */
+/* Mesh/PointCloud/Curves.attributes */
static void rna_def_attribute_group(BlenderRNA *brna)
{
StructRNA *srna;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 72f5bd1923c..e0d55050c63 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -98,14 +98,14 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_INFLATE, "INFLATE", ICON_BRUSH_INFLATE, "Inflate", ""},
{SCULPT_TOOL_BLOB, "BLOB", ICON_BRUSH_BLOB, "Blob", ""},
{SCULPT_TOOL_CREASE, "CREASE", ICON_BRUSH_CREASE, "Crease", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_SMOOTH, "Smooth", ""},
{SCULPT_TOOL_FLATTEN, "FLATTEN", ICON_BRUSH_FLATTEN, "Flatten", ""},
{SCULPT_TOOL_FILL, "FILL", ICON_BRUSH_FILL, "Fill", ""},
{SCULPT_TOOL_SCRAPE, "SCRAPE", ICON_BRUSH_SCRAPE, "Scrape", ""},
{SCULPT_TOOL_MULTIPLANE_SCRAPE, "MULTIPLANE_SCRAPE", ICON_BRUSH_SCRAPE, "Multi-plane Scrape", ""},
{SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_PINCH, "Pinch", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SCULPT_TOOL_GRAB, "GRAB", ICON_BRUSH_GRAB, "Grab", ""},
{SCULPT_TOOL_ELASTIC_DEFORM, "ELASTIC_DEFORM", ICON_BRUSH_GRAB, "Elastic Deform", ""},
{SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_SNAKE_HOOK, "Snake Hook", ""},
@@ -115,7 +115,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
{SCULPT_TOOL_ROTATE, "ROTATE", ICON_BRUSH_ROTATE, "Rotate", ""},
{SCULPT_TOOL_SLIDE_RELAX, "TOPOLOGY", ICON_BRUSH_GRAB, "Slide Relax", ""},
{SCULPT_TOOL_BOUNDARY, "BOUNDARY", ICON_BRUSH_GRAB, "Boundary", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SCULPT_TOOL_CLOTH, "CLOTH", ICON_BRUSH_SCULPT_DRAW, "Cloth", ""},
{SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""},
{SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""},
@@ -243,14 +243,22 @@ const EnumPropertyItem rna_enum_brush_gpencil_weight_types_items[] = {
{0, NULL, 0, NULL, NULL},
};
+/* clang-format off */
const EnumPropertyItem rna_enum_brush_curves_sculpt_tool_items[] = {
- {CURVES_SCULPT_TOOL_COMB, "COMB", ICON_NONE, "Comb Curves", ""},
- {CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_NONE, "Delete Curves", ""},
- {CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_NONE, "Curves Snake Hook", ""},
- {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_NONE, "Add Curves", ""},
- {CURVES_SCULPT_TOOL_GROW_SHRINK, "GROW_SHRINK", ICON_NONE, "Grow / Shrink Curves", ""},
+ {CURVES_SCULPT_TOOL_COMB, "COMB", ICON_BRUSH_CURVES_COMB, "Comb Curves", ""},
+ {CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_BRUSH_CURVES_DELETE, "Delete Curves", ""},
+ {CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_BRUSH_CURVES_SNAKE_HOOK, "Curves Snake Hook", ""},
+ {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_BRUSH_CURVES_ADD, "Add Curves", ""},
+ {CURVES_SCULPT_TOOL_GROW_SHRINK, "GROW_SHRINK", ICON_BRUSH_CURVES_GROW_SHRINK, "Grow / Shrink Curves", ""},
+ {CURVES_SCULPT_TOOL_SELECTION_PAINT, "SELECTION_PAINT", ICON_BRUSH_PAINT_SELECT, "Paint Selection", ""},
+ {CURVES_SCULPT_TOOL_PINCH, "PINCH", ICON_BRUSH_CURVES_PINCH, "Pinch Curves", ""},
+ {CURVES_SCULPT_TOOL_SMOOTH, "SMOOTH", ICON_BRUSH_CURVES_SMOOTH, "Smooth Curves", ""},
+ {CURVES_SCULPT_TOOL_PUFF, "PUFF", ICON_BRUSH_CURVES_PUFF, "Puff Curves", ""},
+ {CURVES_SCULPT_TOOL_DENSITY, "DENSITY", ICON_BRUSH_CURVES_DENSITY, "Density Curves", ""},
+ {CURVES_SCULPT_TOOL_SLIDE, "SLIDE", ICON_BRUSH_CURVES_SLIDE, "Slide Curves", ""},
{0, NULL, 0, NULL, NULL},
};
+/* clang-format on */
#ifndef RNA_RUNTIME
static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = {
@@ -885,6 +893,8 @@ static const EnumPropertyItem *rna_Brush_direction_itemf(bContext *C,
case PAINT_MODE_SCULPT_CURVES:
switch (me->curves_sculpt_tool) {
case CURVES_SCULPT_TOOL_GROW_SHRINK:
+ case CURVES_SCULPT_TOOL_SELECTION_PAINT:
+ case CURVES_SCULPT_TOOL_PINCH:
return prop_direction_items;
default:
return DummyRNA_DEFAULT_items;
@@ -1945,6 +1955,26 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
+ static const EnumPropertyItem density_mode_items[] = {
+ {BRUSH_CURVES_SCULPT_DENSITY_MODE_AUTO,
+ "AUTO",
+ ICON_AUTO,
+ "Auto",
+ "Either add or remove curves depending on the minimum distance of the curves under the "
+ "cursor"},
+ {BRUSH_CURVES_SCULPT_DENSITY_MODE_ADD,
+ "ADD",
+ ICON_ADD,
+ "Add",
+ "Add new curves between existing curves, taking the minimum distance into account"},
+ {BRUSH_CURVES_SCULPT_DENSITY_MODE_REMOVE,
+ "REMOVE",
+ ICON_REMOVE,
+ "Remove",
+ "Remove curves whose root points are too close"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "BrushCurvesSculptSettings", NULL);
RNA_def_struct_sdna(srna, "BrushCurvesSculptSettings");
RNA_def_struct_ui_text(srna, "Curves Sculpt Brush Settings", "");
@@ -1993,6 +2023,22 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
prop,
"Curve Length",
"Length of newly added curves when it is not interpolated from other curves");
+
+ prop = RNA_def_property(srna, "minimum_distance", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0, 1000.0f, 0.001, 2);
+ RNA_def_property_ui_text(
+ prop, "Minimum Distance", "Goal distance between curve roots for the Density brush");
+
+ prop = RNA_def_property(srna, "density_add_attempts", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, INT32_MAX);
+ RNA_def_property_ui_text(
+ prop, "Density Add Attempts", "How many times the Density brush tries to add a new curve");
+
+ prop = RNA_def_property(srna, "density_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, density_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Density Mode", "Determines whether the brush adds or removes curves");
}
static void rna_def_brush(BlenderRNA *brna)
@@ -2002,7 +2048,7 @@ static void rna_def_brush(BlenderRNA *brna)
static const EnumPropertyItem prop_blend_items[] = {
{IMB_BLEND_MIX, "MIX", 0, "Mix", "Use Mix blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use Darken blending mode while painting"},
{IMB_BLEND_MUL, "MUL", 0, "Multiply", "Use Multiply blending mode while painting"},
{IMB_BLEND_COLORBURN,
@@ -2015,7 +2061,7 @@ static void rna_def_brush(BlenderRNA *brna)
0,
"Linear Burn",
"Use Linear Burn blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_LIGHTEN, "LIGHTEN", 0, "Lighten", "Use Lighten blending mode while painting"},
{IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use Screen blending mode while painting"},
{IMB_BLEND_COLORDODGE,
@@ -2024,7 +2070,7 @@ static void rna_def_brush(BlenderRNA *brna)
"Color Dodge",
"Use Color Dodge blending mode while painting"},
{IMB_BLEND_ADD, "ADD", 0, "Add", "Use Add blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use Overlay blending mode while painting"},
{IMB_BLEND_SOFTLIGHT,
"SOFTLIGHT",
@@ -2051,7 +2097,7 @@ static void rna_def_brush(BlenderRNA *brna)
0,
"Pin Light",
"Use Pin Light blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_DIFFERENCE,
"DIFFERENCE",
0,
@@ -2063,7 +2109,7 @@ static void rna_def_brush(BlenderRNA *brna)
"Exclusion",
"Use Exclusion blending mode while painting"},
{IMB_BLEND_SUB, "SUB", 0, "Subtract", "Use Subtract blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_HUE, "HUE", 0, "Hue", "Use Hue blending mode while painting"},
{IMB_BLEND_SATURATION,
"SATURATION",
@@ -2072,7 +2118,7 @@ static void rna_def_brush(BlenderRNA *brna)
"Use Saturation blending mode while painting"},
{IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use Color blending mode while painting"},
{IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Value", "Use Value blending mode while painting"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"},
{IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"},
{0, NULL, 0, NULL, NULL},
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index 92df7293c2e..99f8c263da6 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -111,6 +111,81 @@ static void rna_Camera_background_images_clear(Camera *cam)
WM_main_add_notifier(NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam);
}
+static char *rna_Camera_background_image_path(const PointerRNA *ptr)
+{
+ const CameraBGImage *bgpic = ptr->data;
+ Camera *camera = (Camera *)ptr->owner_id;
+
+ const int bgpic_index = BLI_findindex(&camera->bg_images, bgpic);
+
+ if (bgpic_index >= 0) {
+ return BLI_sprintfN("background_images[%d]", bgpic_index);
+ }
+
+ return NULL;
+}
+
+char *rna_CameraBackgroundImage_image_or_movieclip_user_path(const PointerRNA *ptr)
+{
+ const char *user = ptr->data;
+ Camera *camera = (Camera *)ptr->owner_id;
+
+ int bgpic_index = BLI_findindex(&camera->bg_images, user - offsetof(CameraBGImage, iuser));
+ if (bgpic_index >= 0) {
+ return BLI_sprintfN("background_images[%d].image_user", bgpic_index);
+ }
+
+ bgpic_index = BLI_findindex(&camera->bg_images, user - offsetof(CameraBGImage, cuser));
+ if (bgpic_index >= 0) {
+ return BLI_sprintfN("background_images[%d].clip_user", bgpic_index);
+ }
+
+ return NULL;
+}
+
+static bool rna_Camera_background_images_override_apply(Main *bmain,
+ PointerRNA *ptr_dst,
+ PointerRNA *ptr_src,
+ PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *prop_dst,
+ PropertyRNA *UNUSED(prop_src),
+ PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst),
+ const int UNUSED(len_src),
+ const int UNUSED(len_storage),
+ PointerRNA *UNUSED(ptr_item_dst),
+ PointerRNA *UNUSED(ptr_item_src),
+ PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideLibraryPropertyOperation *opop)
+{
+ BLI_assert_msg(opop->operation == IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
+ "Unsupported RNA override operation on background images collection");
+
+ Camera *cam_dst = (Camera *)ptr_dst->owner_id;
+ Camera *cam_src = (Camera *)ptr_src->owner_id;
+
+ /* 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. */
+ CameraBGImage *bgpic_anchor = BLI_findlink(&cam_dst->bg_images, opop->subitem_reference_index);
+
+ /* If `bgpic_anchor` is NULL, `bgpic_src` will be inserted in first position. */
+ CameraBGImage *bgpic_src = BLI_findlink(&cam_src->bg_images, opop->subitem_local_index);
+
+ if (bgpic_src == NULL) {
+ BLI_assert(bgpic_src != NULL);
+ return false;
+ }
+
+ CameraBGImage *bgpic_dst = BKE_camera_background_image_copy(bgpic_src, 0);
+
+ /* This handles NULL anchor as expected by adding at head of list. */
+ BLI_insertlinkafter(&cam_dst->bg_images, bgpic_anchor, bgpic_dst);
+
+ RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst);
+ return true;
+}
+
static void rna_Camera_dof_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
SEQ_relations_invalidate_scene_strips(bmain, scene);
@@ -179,6 +254,17 @@ static void rna_def_camera_background_image(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "CameraBGImage");
RNA_def_struct_ui_text(
srna, "Background Image", "Image and settings for display in the 3D View background");
+ RNA_def_struct_path_func(srna, "rna_Camera_background_image_path");
+
+ prop = RNA_def_boolean(srna,
+ "is_override_data",
+ false,
+ "Override Background Image",
+ "In a local override camera, whether this background image comes from "
+ "the linked reference camera, or is local to the override");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_negative_sdna(
+ prop, NULL, "flag", CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL);
RNA_define_lib_overridable(true);
@@ -204,6 +290,7 @@ static void rna_def_camera_background_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "ImageUser");
RNA_def_property_pointer_sdna(prop, NULL, "iuser");
RNA_def_property_ui_text(
prop,
@@ -432,6 +519,12 @@ static void rna_def_camera_dof_settings_data(BlenderRNA *brna)
prop, "Focus Object", "Use this object to define the depth of field focal point");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update");
+ prop = RNA_def_property(srna, "focus_subtarget", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "focus_subtarget");
+ RNA_def_property_ui_text(
+ prop, "Focus Bone", "Use this armature bone to define the depth of field focal point");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dependency_update");
+
prop = RNA_def_property(srna, "focus_distance", PROP_FLOAT, PROP_DISTANCE);
// RNA_def_property_pointer_sdna(prop, NULL, "focus_distance");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
@@ -736,6 +829,8 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_collection_sdna(prop, NULL, "bg_images", NULL);
RNA_def_property_struct_type(prop, "CameraBackgroundImage");
RNA_def_property_ui_text(prop, "Background Images", "List of background images");
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_LIBRARY_INSERTION | PROPOVERRIDE_NO_PROP_NAME);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Camera_background_images_override_apply");
RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
RNA_define_lib_overridable(false);
diff --git a/source/blender/makesrna/intern/rna_collection.c b/source/blender/makesrna/intern/rna_collection.c
index 599d36c0af7..8cd83ddcf12 100644
--- a/source/blender/makesrna/intern/rna_collection.c
+++ b/source/blender/makesrna/intern/rna_collection.c
@@ -549,6 +549,22 @@ void RNA_def_collections(BlenderRNA *brna)
prop, "Masks", "Intersection generated by this collection will have this mask value");
RNA_def_property_update(prop, NC_SCENE, NULL);
+ prop = RNA_def_property(srna, "lineart_intersection_priority", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_text(prop,
+ "Intersection Priority",
+ "The intersection line will be included into the object with the "
+ "higher intersection priority value");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_lineart_intersection_priority", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(
+ prop, NULL, "lineart_flags", COLLECTION_LRT_USE_INTERSECTION_PRIORITY);
+ RNA_def_property_ui_text(
+ prop, "Use Intersection Priority", "Assign intersection priority value for this collection");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
prop = RNA_def_property(srna, "color_tag", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "color_tag");
RNA_def_property_enum_funcs(
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 8829c655030..986de0930ed 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -29,11 +29,12 @@
/* please keep the names in sync with constraint.c */
const EnumPropertyItem rna_enum_constraint_type_items[] = {
- {0, "", 0, N_("Motion Tracking"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Motion Tracking"), NULL),
{CONSTRAINT_TYPE_CAMERASOLVER, "CAMERA_SOLVER", ICON_CON_CAMERASOLVER, "Camera Solver", ""},
{CONSTRAINT_TYPE_FOLLOWTRACK, "FOLLOW_TRACK", ICON_CON_FOLLOWTRACK, "Follow Track", ""},
{CONSTRAINT_TYPE_OBJECTSOLVER, "OBJECT_SOLVER", ICON_CON_OBJECTSOLVER, "Object Solver", ""},
- {0, "", 0, N_("Transform"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Transform"), NULL),
{CONSTRAINT_TYPE_LOCLIKE,
"COPY_LOCATION",
ICON_CON_LOCLIKE,
@@ -91,7 +92,8 @@ const EnumPropertyItem rna_enum_constraint_type_items[] = {
ICON_CON_TRANSFORM_CACHE,
"Transform Cache",
"Look up the transformation matrix from an external file"},
- {0, "", 0, N_("Tracking"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Tracking"), NULL),
{CONSTRAINT_TYPE_CLAMPTO,
"CLAMP_TO",
ICON_CON_CLAMPTO,
@@ -127,7 +129,8 @@ const EnumPropertyItem rna_enum_constraint_type_items[] = {
ICON_CON_TRACKTO,
"Track To",
"Legacy tracking constraint prone to twisting artifacts"},
- {0, "", 0, N_("Relationship"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Relationship"), NULL),
{CONSTRAINT_TYPE_ACTION,
"ACTION",
ICON_ACTION,
@@ -192,7 +195,7 @@ static const EnumPropertyItem target_space_pchan_items[] = {
"Custom Space",
"The transformation of the target is evaluated relative to a custom object/bone/vertex "
"group"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{CONSTRAINT_SPACE_POSE,
"POSE",
0,
@@ -233,7 +236,7 @@ static const EnumPropertyItem owner_space_pchan_items[] = {
0,
"Custom Space",
"The constraint is applied in local space of a custom object/bone/vertex group"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{CONSTRAINT_SPACE_POSE,
"POSE",
0,
@@ -595,22 +598,17 @@ static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSE
bool *UNUSED(r_free))
{
bConstraint *con = (bConstraint *)ptr->data;
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
- if (cti && cti->get_constraint_targets) {
- cti->get_constraint_targets(con, &targets);
-
+ if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
- if (ct->tar && ct->tar->type == OB_ARMATURE) {
+ if (ct->tar && ct->tar->type == OB_ARMATURE && !(ct->flag & CONSTRAINT_TAR_CUSTOM_SPACE)) {
break;
}
}
- if (cti->flush_constraint_targets) {
- cti->flush_constraint_targets(con, &targets, 1);
- }
+ BKE_constraint_targets_flush(con, &targets, 1);
if (ct) {
return target_space_pchan_items;
@@ -1623,7 +1621,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
0,
"Replace",
"Replace the original transformation with copied"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{TRANSLIKE_MIX_BEFORE_FULL,
"BEFORE_FULL",
0,
@@ -1644,7 +1642,7 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
"Before Original (Split Channels)",
"Apply copied transformation before original, handling location, rotation and scale "
"separately, similar to a sequence of three Copy constraints"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{TRANSLIKE_MIX_AFTER_FULL,
"AFTER_FULL",
0,
@@ -1782,7 +1780,7 @@ static void rna_def_constraint_action(BlenderRNA *brna)
"Before Original (Split Channels)",
"Apply the action channels before the original transformation, handling location, rotation "
"and scale separately"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{ACTCON_MIX_AFTER_FULL,
"AFTER_FULL",
0,
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 49b78e90024..fff3f479a3f 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -66,8 +66,8 @@ const EnumPropertyItem rna_enum_keyframe_handle_type_items[] = {
* Changes here will likely apply there too.
*/
const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
- /* interpolation */
- {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
+ /* Interpolation. */
+ RNA_ENUM_ITEM_HEADING(N_("Interpolation"), "Standard transitions between keyframes"),
{BEZT_IPO_CONST,
"CONSTANT",
ICON_IPO_CONSTANT,
@@ -84,13 +84,10 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
"Bezier",
"Smooth interpolation between A and B, with some control over curve shape"},
- /* easing */
- {0,
- "",
- 0,
- N_("Easing (by strength)"),
- "Predefined inertial transitions, useful for motion graphics (from least to most "
- "''dramatic'')"},
+ /* Easing. */
+ RNA_ENUM_ITEM_HEADING(N_("Easing (by strength)"),
+ "Predefined inertial transitions, useful for motion graphics "
+ "(from least to most \"dramatic\")"),
{BEZT_IPO_SINE,
"SINE",
ICON_IPO_SINE,
@@ -107,7 +104,7 @@ const EnumPropertyItem rna_enum_beztriple_interpolation_mode_items[] = {
"Circular",
"Circular easing (strongest and most dynamic)"},
- {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
+ RNA_ENUM_ITEM_HEADING(N_("Dynamic Effects"), "Simple physics-inspired easing effects"),
{BEZT_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
{BEZT_IPO_BOUNCE,
"BOUNCE",
diff --git a/source/blender/makesrna/intern/rna_curves.c b/source/blender/makesrna/intern/rna_curves.c
index 7cf34db4cf4..cb8b36f41d2 100644
--- a/source/blender/makesrna/intern/rna_curves.c
+++ b/source/blender/makesrna/intern/rna_curves.c
@@ -18,6 +18,14 @@
#include "WM_types.h"
+const EnumPropertyItem rna_enum_curves_types[] = {
+ {CURVE_TYPE_CATMULL_ROM, "CATMULL_ROM", 0, "Catmull Rom", ""},
+ {CURVE_TYPE_POLY, "POLY", 0, "Poly", ""},
+ {CURVE_TYPE_BEZIER, "BEZIER", 0, "Bezier", ""},
+ {CURVE_TYPE_NURBS, "NURBS", 0, "NURBS", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include "BLI_math_vector.h"
@@ -56,7 +64,24 @@ static int rna_CurvePoint_index_get_const(const PointerRNA *ptr)
{
const Curves *curves = rna_curves(ptr);
const float(*co)[3] = ptr->data;
- return (int)(co - curves->geometry.position);
+ const float(*positions)[3] = (const float(*)[3])CustomData_get_layer_named(
+ &curves->geometry.point_data, CD_PROP_FLOAT3, "position");
+ return (int)(co - positions);
+}
+
+static int rna_Curves_position_data_length(PointerRNA *ptr)
+{
+ const Curves *curves = rna_curves(ptr);
+ return curves->geometry.point_num;
+}
+
+static void rna_Curves_position_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ const Curves *curves = rna_curves(ptr);
+ const float(*positions)[3] = (const float(*)[3])CustomData_get_layer_named(
+ &curves->geometry.point_data, CD_PROP_FLOAT3, "position");
+ rna_iterator_array_begin(
+ iter, (void *)positions, sizeof(float[3]), curves->geometry.point_num, false, NULL);
}
static int rna_CurvePoint_index_get(PointerRNA *ptr)
@@ -77,21 +102,23 @@ static void rna_CurvePoint_location_set(PointerRNA *ptr, const float value[3])
static float rna_CurvePoint_radius_get(PointerRNA *ptr)
{
const Curves *curves = rna_curves(ptr);
- if (curves->geometry.radius == NULL) {
+ const float *radii = (const float *)CustomData_get_layer_named(
+ &curves->geometry.point_data, CD_PROP_FLOAT, "radius");
+ if (radii == NULL) {
return 0.0f;
}
- const float(*co)[3] = ptr->data;
- return curves->geometry.radius[co - curves->geometry.position];
+ return radii[rna_CurvePoint_index_get_const(ptr)];
}
static void rna_CurvePoint_radius_set(PointerRNA *ptr, float value)
{
const Curves *curves = rna_curves(ptr);
- if (curves->geometry.radius == NULL) {
+ float *radii = (float *)CustomData_get_layer_named(
+ &curves->geometry.point_data, CD_PROP_FLOAT, "radius");
+ if (radii == NULL) {
return;
}
- const float(*co)[3] = ptr->data;
- curves->geometry.radius[co - curves->geometry.position] = value;
+ radii[rna_CurvePoint_index_get_const(ptr)] = value;
}
static char *rna_CurvePoint_path(const PointerRNA *ptr)
@@ -115,16 +142,6 @@ static char *rna_CurveSlice_path(const PointerRNA *ptr)
return BLI_sprintfN("curves[%d]", rna_CurveSlice_index_get_const(ptr));
}
-static void rna_CurveSlice_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
- Curves *curves = rna_curves(ptr);
- const int *offset_ptr = (int *)ptr->data;
- const int offset = *offset_ptr;
- const int size = *(offset_ptr + 1) - offset;
- float(*co)[3] = curves->geometry.position + *offset_ptr;
- rna_iterator_array_begin(iter, co, sizeof(float[3]), size, 0, NULL);
-}
-
static int rna_CurveSlice_first_point_index_get(PointerRNA *ptr)
{
const int *offset_ptr = (int *)ptr->data;
@@ -138,6 +155,17 @@ static int rna_CurveSlice_points_length_get(PointerRNA *ptr)
return *(offset_ptr + 1) - offset;
}
+static void rna_CurveSlice_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Curves *curves = rna_curves(ptr);
+ const int offset = rna_CurveSlice_first_point_index_get(ptr);
+ const int size = rna_CurveSlice_points_length_get(ptr);
+ float(*positions)[3] = (float(*)[3])CustomData_get_layer_named(
+ &curves->geometry.point_data, CD_PROP_FLOAT3, "position");
+ float(*co)[3] = positions + offset;
+ rna_iterator_array_begin(iter, co, sizeof(float[3]), size, 0, NULL);
+}
+
static void rna_Curves_update_data(struct Main *UNUSED(bmain),
struct Scene *UNUSED(scene),
PointerRNA *ptr)
@@ -244,20 +272,32 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "CurveSlice");
RNA_def_property_ui_text(prop, "Curves", "All curves in the data-block");
- /* TODO: better solution for (*co)[3] parsing issue. */
-
- RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_num");
RNA_def_property_struct_type(prop, "CurvePoint");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Curves_position_data_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_Curves_position_data_length",
+ NULL,
+ NULL,
+ NULL);
RNA_def_property_ui_text(prop, "Points", "Control points of all curves");
- RNA_define_verify_sdna(1);
/* Direct access to built-in attributes. */
RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "position_data", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "geometry.position", "geometry.point_num");
+ RNA_def_property_collection_funcs(prop,
+ "rna_Curves_position_data_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_Curves_position_data_length",
+ NULL,
+ NULL,
+ NULL);
RNA_def_property_struct_type(prop, "FloatVectorAttributeValue");
RNA_def_property_update(prop, 0, "rna_Curves_update_data");
RNA_define_verify_sdna(1);
@@ -292,6 +332,14 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Surface", "Mesh object that the curves can be attached to");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "surface_uv_map", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "surface_uv_map");
+ RNA_def_property_ui_text(prop,
+ "Surface UV Map",
+ "The name of the attribute on the surface mesh used to define the "
+ "attachment of each curve");
+ RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
+
/* Symmetry. */
prop = RNA_def_property(srna, "use_mirror_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "symmetry", CURVES_SYMMETRY_X);
@@ -308,6 +356,18 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Z", "Enable symmetry in the Z axis");
RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
+ prop = RNA_def_property(srna, "selection_domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_attribute_curves_domain_items);
+ RNA_def_property_ui_text(prop, "Selection Domain", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Curves_update_data");
+
+ prop = RNA_def_property(srna, "use_sculpt_selection", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CV_SCULPT_SELECTION_ENABLED);
+ RNA_def_property_ui_text(prop, "Use Sculpt Selection", "");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, 0, "rna_Curves_update_draw");
+
/* attributes */
rna_def_attributes_common(srna);
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index dfb551fcb05..44b642d0fcc 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -4421,6 +4421,16 @@ int rna_parameter_size(PropertyRNA *parm)
return sizeof(void *);
}
+int rna_parameter_size_pad(const int size)
+{
+ /* Pad parameters in memory so the next parameter is properly aligned.
+ * This silences warnings in UBSAN. More complicated logic to pack parameters
+ * more tightly in memory is unlikely to improve performance, and aligning
+ * to the requirements for pointers is enough for all data types we use. */
+ const int alignment = sizeof(void *);
+ return (size + alignment - 1) & ~(alignment - 1);
+}
+
/* Dynamic Enums */
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
@@ -4435,7 +4445,7 @@ void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropert
#endif
}
else if (tot >= 8 && (tot & (tot - 1)) == 0) {
- /* power of two > 8 */
+ /* Power of two > 8. */
*items = MEM_recallocN_id(*items, sizeof(EnumPropertyItem) * tot * 2, __func__);
#ifdef DEBUG
memset((*items) + tot, 0xff, sizeof(EnumPropertyItem) * tot);
@@ -4448,7 +4458,7 @@ void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropert
void RNA_enum_item_add_separator(EnumPropertyItem **items, int *totitem)
{
- static const EnumPropertyItem sepr = {0, "", 0, NULL, NULL};
+ static const EnumPropertyItem sepr = RNA_ENUM_ITEM_SEPR;
RNA_enum_item_add(items, totitem, &sepr);
}
@@ -4467,8 +4477,8 @@ void RNA_enum_items_add_value(EnumPropertyItem **items,
for (; item->identifier; item++) {
if (item->value == value) {
RNA_enum_item_add(items, totitem, item);
- /* break on first match - does this break anything?
- * (is quick hack to get object->parent_type working ok for armature/lattice) */
+ /* Break on first match - does this break anything?
+ * (is quick hack to get `object->parent_type` working ok for armature/lattice). */
break;
}
}
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index e14a291dd01..727d329781d 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -612,7 +612,7 @@ static void rna_tag_animation_update(Main *bmain, ID *id)
static void rna_FCurve_update_data_ex(ID *id, FCurve *fcu, Main *bmain)
{
sort_time_fcurve(fcu);
- calchandles_fcurve(fcu);
+ BKE_fcurve_handles_recalc(fcu);
rna_tag_animation_update(bmain, id);
}
@@ -752,7 +752,7 @@ static void rna_FModifier_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
FModifier *fcm = (FModifier *)ptr->data;
if (fcm->curve && fcm->type == FMODIFIER_TYPE_CYCLES) {
- calchandles_fcurve(fcm->curve);
+ BKE_fcurve_handles_recalc(fcm->curve);
}
rna_tag_animation_update(bmain, id);
@@ -1021,9 +1021,20 @@ static void rna_FKeyframe_points_remove(
return;
}
- delete_fcurve_key(fcu, index, !do_fast);
+ BKE_fcurve_delete_key(fcu, index);
RNA_POINTER_INVALIDATE(bezt_ptr);
+ if (!do_fast) {
+ BKE_fcurve_handles_recalc(fcu);
+ }
+
+ rna_tag_animation_update(bmain, id);
+}
+
+static void rna_FKeyframe_points_clear(ID *id, FCurve *fcu, Main *bmain)
+{
+ BKE_fcurve_delete_keys_all(fcu);
+
rna_tag_animation_update(bmain, id);
}
@@ -1776,12 +1787,12 @@ static void rna_def_drivertarget(BlenderRNA *brna)
{DTAR_TRANSCHAN_LOCX, "LOC_X", 0, "X Location", ""},
{DTAR_TRANSCHAN_LOCY, "LOC_Y", 0, "Y Location", ""},
{DTAR_TRANSCHAN_LOCZ, "LOC_Z", 0, "Z Location", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{DTAR_TRANSCHAN_ROTX, "ROT_X", 0, "X Rotation", ""},
{DTAR_TRANSCHAN_ROTY, "ROT_Y", 0, "Y Rotation", ""},
{DTAR_TRANSCHAN_ROTZ, "ROT_Z", 0, "Z Rotation", ""},
{DTAR_TRANSCHAN_ROTW, "ROT_W", 0, "W Rotation", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{DTAR_TRANSCHAN_SCALEX, "SCALE_X", 0, "X Scale", ""},
{DTAR_TRANSCHAN_SCALEY, "SCALE_Y", 0, "Y Scale", ""},
{DTAR_TRANSCHAN_SCALEZ, "SCALE_Z", 0, "Z Scale", ""},
@@ -2306,6 +2317,10 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop)
/* optional */
RNA_def_boolean(
func, "fast", 0, "Fast", "Fast keyframe removal to avoid recalculating the curve each time");
+
+ func = RNA_def_function(srna, "clear", "rna_FKeyframe_points_clear");
+ RNA_def_function_ui_description(func, "Remove all keyframes from an F-Curve");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN);
}
static void rna_def_fcurve(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 8bbc33d2381..0647bc62081 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -46,7 +46,7 @@
#include "WM_types.h"
const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
- {0, "", 0, N_("Modify"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Modify"), NULL),
{eGpencilModifierType_Texture,
"GP_TEXTURE",
ICON_MOD_UVPROJECT,
@@ -63,7 +63,8 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_VERTEX_WEIGHT,
"Vertex Weight Proximity",
"Generate Vertex Weights base on distance to object"},
- {0, "", 0, N_("Generate"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Generate"), NULL),
{eGpencilModifierType_Array,
"GP_ARRAY",
ICON_MOD_ARRAY,
@@ -114,7 +115,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_SUBSURF,
"Subdivide",
"Subdivide stroke adding more control points"},
- {0, "", 0, N_("Deform"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Deform"), NULL),
{eGpencilModifierType_Armature,
"GP_ARMATURE",
ICON_MOD_ARMATURE,
@@ -147,7 +148,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_THICKNESS,
"Thickness",
"Change stroke thickness"},
- {0, "", 0, N_("Color"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Color"), NULL),
{eGpencilModifierType_Color,
"GP_COLOR",
ICON_MOD_HUE_SATURATION,
@@ -773,7 +774,7 @@ static bool dash_segment_name_exists_fn(void *arg, const char *name)
{
const DashGpencilModifierData *dmd = (const DashGpencilModifierData *)arg;
for (int i = 0; i < dmd->segments_len; i++) {
- if (STREQ(dmd->segments[i].name, name)) {
+ if (STREQ(dmd->segments[i].name, name) && dmd->segments[i].name != name) {
return true;
}
}
@@ -1278,8 +1279,8 @@ static void rna_def_modifier_gpencilsimplify(BlenderRNA *brna)
/* Sample */
prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "length");
- RNA_def_property_range(prop, 0, FLT_MAX);
- RNA_def_property_ui_range(prop, 0, 1.0, 0.01, 3);
+ RNA_def_property_range(prop, 0.005, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1.0, 0.05, 3);
RNA_def_property_ui_text(prop, "Length", "Length of each segment");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
@@ -3195,6 +3196,20 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem modifier_lineart_shadow_region_filtering[] = {
+ {LRT_SHADOW_FILTER_NONE, "NONE", 0, "None", ""},
+ {LRT_SHADOW_FILTER_LIT, "LIT", 0, "Lit", ""},
+ {LRT_SHADOW_FILTER_SHADED, "SHADED", 0, "Shaded", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem modifier_lineart_silhouette_filtering[] = {
+ {LRT_SILHOUETTE_FILTER_NONE, "NONE", 0, "Contour", ""},
+ {LRT_SILHOUETTE_FILTER_GROUP, "GROUP", 0, "Silhouette", ""},
+ {LRT_SILHOUETTE_FILTER_INDIVIDUAL, "INDIVIDUAL", 0, "Individual Silhouette", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
srna = RNA_def_struct(brna, "LineartGpencilModifier", "GpencilModifier");
RNA_def_struct_ui_text(
srna, "Line Art Modifier", "Generate line art strokes from selected source");
@@ -3207,7 +3222,7 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
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");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_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);
@@ -3249,8 +3264,11 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
prop = RNA_def_property(srna, "crease_threshold", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, 0, DEG2RAD(180.0f));
RNA_def_property_ui_range(prop, 0.0f, DEG2RAD(180.0f), 0.01f, 1);
- RNA_def_property_ui_text(
- prop, "Crease Threshold", "Angles smaller than this will be treated as creases");
+ RNA_def_property_ui_text(prop,
+ "Crease Threshold",
+ "Angles smaller than this will be treated as creases. Crease angle "
+ "priority: object line art crease override > mesh auto smooth angle > "
+ "line art default crease");
RNA_def_property_update(prop, NC_SCENE, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_ANGLE);
@@ -3366,6 +3384,14 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
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, "light_contour_object", 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, "Light Object", "Use this light object to generate light contour");
+ 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");
@@ -3416,6 +3442,41 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Intersection", "Generate strokes from intersections");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_light_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", LRT_EDGE_FLAG_LIGHT_CONTOUR);
+ RNA_def_property_ui_text(prop,
+ "Use Light Contour",
+ "Generate light/shadow separation lines from a reference light object");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "use_shadow", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", LRT_EDGE_FLAG_PROJECTED_SHADOW);
+ RNA_def_property_ui_text(
+ prop, "Use Shadow", "Project contour lines using a light source object");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "shadow_region_filtering", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "shadow_selection");
+ RNA_def_property_enum_items(prop, modifier_lineart_shadow_region_filtering);
+ RNA_def_property_ui_text(prop,
+ "Shadow Region Filtering",
+ "Select feature lines that comes from lit or shaded regions. Will not "
+ "affect cast shadow and light contour since they are at the border");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
+ prop = RNA_def_property(srna, "use_shadow_enclosed_shapes", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "calculation_flags", LRT_SHADOW_ENCLOSED_SHAPES);
+ RNA_def_property_ui_text(prop,
+ "Shadow Enclosed Shapes",
+ "Reproject visible lines again to get enclosed shadow shapes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "silhouette_filtering", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "silhouette_selection");
+ RNA_def_property_enum_items(prop, modifier_lineart_silhouette_filtering);
+ RNA_def_property_ui_text(prop, "Silhouette Filtering", "Select contour or silhouette");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
+
prop = RNA_def_property(srna, "use_multiple_levels", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_multiple_levels", 0);
RNA_def_property_ui_text(
@@ -3557,6 +3618,27 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
"different occlusion levels than when disabled");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "shadow_camera_near", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Shadow Camera Near", "Near clipping distance of shadow camera");
+ RNA_def_property_ui_range(prop, 0.0f, 500.0f, 0.1f, 2);
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "shadow_camera_far", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Shadow Camera Far", "Far clipping distance of shadow camera");
+ RNA_def_property_ui_range(prop, 0.0f, 500.0f, 0.1f, 2);
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "shadow_camera_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_ui_text(prop,
+ "Shadow Camera Size",
+ "This value represent the \"Orthographic Scale\" of an ortho camera."
+ "If the camera is put at the lamps position with this scale, it will "
+ "represent the coverage of the shadow \"camera\" ");
+ RNA_def_property_ui_range(prop, 0.0f, 500.0f, 0.1f, 2);
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+
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,
@@ -3564,6 +3646,11 @@ static void rna_def_modifier_gpencillineart(BlenderRNA *brna)
"Select everything except lines from specified collection");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+ prop = RNA_def_property(srna, "use_invert_silhouette", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_GPENCIL_INVERT_SILHOUETTE_FILTER);
+ RNA_def_property_ui_text(prop, "Invert Silhouette Filtering", "Select anti-silhouette lines");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
RNA_define_lib_overridable(false);
}
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 269ebe1581f..39f5b6e0e9f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -182,12 +182,12 @@ static char *rna_ImageUser_path(const PointerRNA *ptr)
switch (GS(ptr->owner_id->name)) {
case ID_OB:
- case ID_TE: {
+ case ID_TE:
return BLI_strdup("image_user");
- }
- case ID_NT: {
+ case ID_NT:
return rna_Node_ImageUser_path(ptr);
- }
+ case ID_CA:
+ return rna_CameraBackgroundImage_image_or_movieclip_user_path(ptr);
default:
break;
}
@@ -257,6 +257,51 @@ static void rna_Image_file_format_set(PointerRNA *ptr, int value)
}
}
+static void rna_UDIMTile_size_get(PointerRNA *ptr, int *values)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ ImageUser image_user;
+ BKE_imageuser_default(&image_user);
+ image_user.tile = tile->tile_number;
+
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &image_user, &lock);
+ if (ibuf) {
+ values[0] = ibuf->x;
+ values[1] = ibuf->y;
+ }
+ else {
+ values[0] = 0;
+ values[1] = 0;
+ }
+
+ BKE_image_release_ibuf(image, ibuf, lock);
+}
+
+static int rna_UDIMTile_channels_get(PointerRNA *ptr)
+{
+ ImageTile *tile = (ImageTile *)ptr->data;
+ Image *image = (Image *)ptr->owner_id;
+
+ ImageUser image_user;
+ BKE_imageuser_default(&image_user);
+ image_user.tile = tile->tile_number;
+
+ int channels = 0;
+
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, &image_user, &lock);
+ if (ibuf) {
+ channels = ibuf->channels;
+ }
+
+ BKE_image_release_ibuf(image, ibuf, lock);
+
+ return channels;
+}
+
static void rna_UDIMTile_label_get(PointerRNA *ptr, char *value)
{
ImageTile *tile = (ImageTile *)ptr->data;
@@ -656,6 +701,8 @@ static void rna_def_imageuser(BlenderRNA *brna)
"Parameters defining how an Image data-block is used by another data-block");
RNA_def_struct_path_func(srna, "rna_ImageUser_path");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use_auto_refresh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_ANIM_ALWAYS);
RNA_def_property_ui_text(prop, "Auto Refresh", "Always refresh image on frame changes");
@@ -717,6 +764,8 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "tile");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Tile", "Tile in tiled image");
+
+ RNA_define_lib_overridable(false);
}
/* image.packed_files */
@@ -826,6 +875,26 @@ static void rna_def_udim_tile(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Number", "Number of the position that this tile covers");
RNA_def_property_int_funcs(prop, NULL, "rna_UDIMTile_tile_number_set", NULL);
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+
+ prop = RNA_def_int_vector(
+ srna,
+ "size",
+ 2,
+ NULL,
+ 0,
+ 0,
+ "Size",
+ "Width and height of the tile buffer in pixels, zero when image data can't be loaded",
+ 0,
+ 0);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_int_funcs(prop, "rna_UDIMTile_size_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_UDIMTile_channels_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Channels", "Number of channels in the tile pixels buffer");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_udim_tiles(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index bac8f214441..be1e344d73f 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -59,9 +59,8 @@ static void rna_Image_save_render(
ImageSaveOptions opts;
- if (BKE_image_save_options_init(&opts, bmain, scene, image, NULL, false)) {
+ if (BKE_image_save_options_init(&opts, bmain, scene, image, NULL, false, true)) {
opts.save_copy = true;
- opts.save_as_render = true;
STRNCPY(opts.filepath, path);
if (!BKE_image_save(reports, bmain, image, NULL, &opts)) {
@@ -83,7 +82,7 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r
Scene *scene = CTX_data_scene(C);
ImageSaveOptions opts;
- if (BKE_image_save_options_init(&opts, bmain, scene, image, NULL, false)) {
+ if (BKE_image_save_options_init(&opts, bmain, scene, image, NULL, false, false)) {
if (!BKE_image_save(reports, bmain, image, NULL, &opts)) {
BKE_reportf(reports,
RPT_ERROR,
@@ -165,7 +164,10 @@ static void rna_Image_scale(Image *image, ReportList *reports, int width, int he
{
if (!BKE_image_scale(image, width, height)) {
BKE_reportf(reports, RPT_ERROR, "Image '%s' does not have any image data", image->id.name + 2);
+ return;
}
+ BKE_image_partial_update_mark_full_update(image);
+ WM_main_add_notifier(NC_IMAGE | NA_EDITED, image);
}
static int rna_Image_gl_load(
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 058c63f640a..833060e40f8 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -404,6 +404,7 @@ bool rna_GPencil_datablocks_obdata_poll(struct PointerRNA *ptr, const struct Poi
char *rna_TextureSlot_path(const struct PointerRNA *ptr);
char *rna_Node_ImageUser_path(const struct PointerRNA *ptr);
+char *rna_CameraBackgroundImage_image_or_movieclip_user_path(const struct PointerRNA *ptr);
/* Set U.is_dirty and redraw. */
@@ -503,9 +504,7 @@ void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_workspaces(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop);
-#ifdef WITH_NEW_CURVES_TYPE
void RNA_def_main_hair_curves(BlenderRNA *brna, PropertyRNA *cprop);
-#endif
void RNA_def_main_pointclouds(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_volumes(BlenderRNA *brna, PropertyRNA *cprop);
#ifdef WITH_SIMULATION_DATABLOCK
@@ -634,6 +633,7 @@ PointerRNA rna_pointer_inherit_refine(struct PointerRNA *ptr, struct StructRNA *
/* Functions */
int rna_parameter_size(struct PropertyRNA *parm);
+int rna_parameter_size_pad(const int size);
/* XXX, these should not need to be defined here~! */
struct MTex *rna_mtex_texture_slots_add(struct ID *self,
diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h
index 4f88959b5ba..a5b06cabade 100644
--- a/source/blender/makesrna/intern/rna_internal_types.h
+++ b/source/blender/makesrna/intern/rna_internal_types.h
@@ -532,7 +532,7 @@ struct StructRNA {
/* property to iterate over properties */
PropertyRNA *iteratorproperty;
- /* struct this is derivedfrom */
+ /** Struct this is derived from. */
struct StructRNA *base;
/* only use for nested structs, where both the parent and child access
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 2f6fb30dc49..b16d127a643 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -26,6 +26,14 @@
#include "rna_internal.h"
+const EnumPropertyItem rna_enum_keyblock_type_items[] = {
+ {KEY_LINEAR, "KEY_LINEAR", 0, "Linear", ""},
+ {KEY_CARDINAL, "KEY_CARDINAL", 0, "Cardinal", ""},
+ {KEY_CATMULL_ROM, "KEY_CATMULL_ROM", 0, "Catmull-Rom", ""},
+ {KEY_BSPLINE, "KEY_BSPLINE", 0, "BSpline", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include <stddef.h>
@@ -789,14 +797,6 @@ static char *rna_ShapeKeyPoint_path(const PointerRNA *ptr)
#else
-const EnumPropertyItem rna_enum_keyblock_type_items[] = {
- {KEY_LINEAR, "KEY_LINEAR", 0, "Linear", ""},
- {KEY_CARDINAL, "KEY_CARDINAL", 0, "Cardinal", ""},
- {KEY_CATMULL_ROM, "KEY_CATMULL_ROM", 0, "Catmull-Rom", ""},
- {KEY_BSPLINE, "KEY_BSPLINE", 0, "BSpline", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
static const float tilt_limit = DEG2RADF(21600.0f);
static void rna_def_keydata(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_layer.c b/source/blender/makesrna/intern/rna_layer.c
index 8c9c66bffcf..6ab9d3a46ad 100644
--- a/source/blender/makesrna/intern/rna_layer.c
+++ b/source/blender/makesrna/intern/rna_layer.c
@@ -339,6 +339,7 @@ static void rna_LayerCollection_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
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_IMAGE | ND_LAYER_CONTENT, NULL);
}
static bool rna_LayerCollection_has_objects(LayerCollection *lc)
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 7200bcaa2a6..4aedb1fc611 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -96,9 +96,7 @@ RNA_MAIN_LISTBASE_FUNCS_DEF(collections)
RNA_MAIN_LISTBASE_FUNCS_DEF(curves)
RNA_MAIN_LISTBASE_FUNCS_DEF(fonts)
RNA_MAIN_LISTBASE_FUNCS_DEF(gpencils)
-# ifdef WITH_NEW_CURVES_TYPE
RNA_MAIN_LISTBASE_FUNCS_DEF(hair_curves)
-# endif
RNA_MAIN_LISTBASE_FUNCS_DEF(images)
RNA_MAIN_LISTBASE_FUNCS_DEF(lattices)
RNA_MAIN_LISTBASE_FUNCS_DEF(libraries)
@@ -375,7 +373,6 @@ void RNA_def_main(BlenderRNA *brna)
"Light Probes",
"Light Probe data-blocks",
RNA_def_main_lightprobes},
-# ifdef WITH_NEW_CURVES_TYPE
/**
* \note The name `hair_curves` is chosen to be different than `curves`,
* but they are generic curve data-blocks, not just for hair.
@@ -386,7 +383,6 @@ void RNA_def_main(BlenderRNA *brna)
"Hair Curves",
"Hair curve data-blocks",
RNA_def_main_hair_curves},
-# endif
{"pointclouds",
"PointCloud",
"rna_Main_pointclouds_begin",
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 6c621604e40..1f21fa3fab9 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -749,7 +749,6 @@ static bGPdata *rna_Main_gpencils_new(Main *bmain, const char *name)
return gpd;
}
-# ifdef WITH_NEW_CURVES_TYPE
static Curves *rna_Main_hair_curves_new(Main *bmain, const char *name)
{
char safe_name[MAX_ID_NAME - 2];
@@ -762,7 +761,6 @@ static Curves *rna_Main_hair_curves_new(Main *bmain, const char *name)
return curves;
}
-# endif
static PointCloud *rna_Main_pointclouds_new(Main *bmain, const char *name)
{
@@ -847,9 +845,7 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(cachefiles, cachefiles, ID_CF)
RNA_MAIN_ID_TAG_FUNCS_DEF(paintcurves, paintcurves, ID_PC)
RNA_MAIN_ID_TAG_FUNCS_DEF(workspaces, workspaces, ID_WS)
RNA_MAIN_ID_TAG_FUNCS_DEF(lightprobes, lightprobes, ID_LP)
-# ifdef WITH_NEW_CURVES_TYPE
RNA_MAIN_ID_TAG_FUNCS_DEF(hair_curves, hair_curves, ID_CV)
-# endif
RNA_MAIN_ID_TAG_FUNCS_DEF(pointclouds, pointclouds, ID_PT)
RNA_MAIN_ID_TAG_FUNCS_DEF(volumes, volumes, ID_VO)
# ifdef WITH_SIMULATION_DATABLOCK
@@ -2255,7 +2251,6 @@ void RNA_def_main_lightprobes(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
-# ifdef WITH_NEW_CURVES_TYPE
void RNA_def_main_hair_curves(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -2299,7 +2294,6 @@ void RNA_def_main_hair_curves(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_pointclouds(BlenderRNA *brna, PropertyRNA *cprop)
{
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 1de144d81ef..4a9bc608598 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -25,24 +25,24 @@
const EnumPropertyItem rna_enum_ramp_blend_items[] = {
{MA_RAMP_BLEND, "MIX", 0, "Mix", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_DARK, "DARKEN", 0, "Darken", ""},
{MA_RAMP_MULT, "MULTIPLY", 0, "Multiply", ""},
{MA_RAMP_BURN, "BURN", 0, "Color Burn", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_LIGHT, "LIGHTEN", 0, "Lighten", ""},
{MA_RAMP_SCREEN, "SCREEN", 0, "Screen", ""},
{MA_RAMP_DODGE, "DODGE", 0, "Color Dodge", ""},
{MA_RAMP_ADD, "ADD", 0, "Add", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{MA_RAMP_SOFT, "SOFT_LIGHT", 0, "Soft Light", ""},
{MA_RAMP_LINEAR, "LINEAR_LIGHT", 0, "Linear Light", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_DIFF, "DIFFERENCE", 0, "Difference", ""},
{MA_RAMP_SUB, "SUBTRACT", 0, "Subtract", ""},
{MA_RAMP_DIV, "DIVIDE", 0, "Divide", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MA_RAMP_HUE, "HUE", 0, "Hue", ""},
{MA_RAMP_SAT, "SATURATION", 0, "Saturation", ""},
{MA_RAMP_COLOR, "COLOR", 0, "Color", ""},
@@ -754,6 +754,22 @@ static void rna_def_material_lineart(BlenderRNA *brna)
"Effectiveness",
"Faces with this material will behave as if it has set number of layers in occlusion");
RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "intersection_priority", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_text(prop,
+ "Intersection Priority",
+ "The intersection line will be included into the object with the "
+ "higher intersection priority value");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
+
+ prop = RNA_def_property(srna, "use_intersection_priority_override", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_default(prop, 0);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LRT_MATERIAL_CUSTOM_INTERSECTION_PRIORITY);
+ RNA_def_property_ui_text(prop,
+ "Use Intersection Priority",
+ "Override object and collection intersection priority value");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_MaterialLineArt_update");
}
void RNA_def_material(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index da4be3cd0da..65468977ccb 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -21,6 +21,7 @@
#include "BLI_math_rotation.h"
#include "BLI_utildefines.h"
+#include "BKE_attribute.h"
#include "BKE_editmesh.h"
#include "RNA_access.h"
@@ -166,27 +167,62 @@ static CustomData *rna_cd_from_layer(PointerRNA *ptr, CustomDataLayer *cdl)
static void rna_MeshVertexLayer_name_set(PointerRNA *ptr, const char *value)
{
- rna_cd_layer_name_set(rna_mesh_vdata(ptr), (CustomDataLayer *)ptr->data, value);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+
+ if (CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL) {
+ BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
+ }
+ else {
+ rna_cd_layer_name_set(rna_mesh_vdata(ptr), layer, value);
+ }
}
# if 0
static void rna_MeshEdgeLayer_name_set(PointerRNA *ptr, const char *value)
{
- rna_cd_layer_name_set(rna_mesh_edata(ptr), (CustomDataLayer *)ptr->data, value);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+
+ if (CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL) {
+ BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
+ }
+ else {
+ rna_cd_layer_name_set(rna_mesh_edata(ptr), layer, value);
+ }
}
# endif
static void rna_MeshPolyLayer_name_set(PointerRNA *ptr, const char *value)
{
- rna_cd_layer_name_set(rna_mesh_pdata(ptr), (CustomDataLayer *)ptr->data, value);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+
+ if (CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL) {
+ BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
+ }
+ else {
+ rna_cd_layer_name_set(rna_mesh_pdata(ptr), layer, value);
+ }
}
static void rna_MeshLoopLayer_name_set(PointerRNA *ptr, const char *value)
{
- rna_cd_layer_name_set(rna_mesh_ldata(ptr), (CustomDataLayer *)ptr->data, value);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+
+ if (CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL) {
+ BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
+ }
+ else {
+ rna_cd_layer_name_set(rna_mesh_ldata(ptr), layer, value);
+ }
}
/* only for layers shared between types */
static void rna_MeshAnyLayer_name_set(PointerRNA *ptr, const char *value)
{
- CustomData *cd = rna_cd_from_layer(ptr, (CustomDataLayer *)ptr->data);
- rna_cd_layer_name_set(cd, (CustomDataLayer *)ptr->data, value);
+ CustomDataLayer *layer = (CustomDataLayer *)ptr->data;
+
+ if (CD_TYPE_AS_MASK(layer->type) & CD_MASK_PROP_ALL) {
+ BKE_id_attribute_rename(ptr->owner_id, layer->name, value, NULL);
+ }
+ else {
+ CustomData *cd = rna_cd_from_layer(ptr, layer);
+ rna_cd_layer_name_set(cd, layer, value);
+ }
}
static bool rna_Mesh_has_custom_normals_get(PointerRNA *ptr)
@@ -295,6 +331,13 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr)
rna_Mesh_update_draw(bmain, scene, ptr);
}
+static void rna_Mesh_update_positions_tag(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Mesh *mesh = rna_mesh(ptr);
+ BKE_mesh_tag_coords_changed(mesh);
+ rna_Mesh_update_data_legacy_deg_tag_all(bmain, scene, ptr);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1094,7 +1137,7 @@ static int rna_MeshPoly_vertices_get_length(const PointerRNA *ptr,
{
const MPoly *mp = (MPoly *)ptr->data;
/* NOTE: raw access uses dummy item, this _could_ crash,
- * watch out for this, mface uses it but it can't work here. */
+ * watch out for this, #MFace uses it but it can't work here. */
return (length[0] = mp->totloop);
}
@@ -1680,6 +1723,56 @@ static void UNUSED_FUNCTION(rna_mesh_unused)(void)
/* end unused function block */
}
+static bool rna_Mesh_materials_override_apply(Main *bmain,
+ PointerRNA *ptr_dst,
+ PointerRNA *UNUSED(ptr_src),
+ PointerRNA *UNUSED(ptr_storage),
+ PropertyRNA *prop_dst,
+ PropertyRNA *UNUSED(prop_src),
+ PropertyRNA *UNUSED(prop_storage),
+ const int UNUSED(len_dst),
+ const int UNUSED(len_src),
+ const int UNUSED(len_storage),
+ PointerRNA *ptr_item_dst,
+ PointerRNA *ptr_item_src,
+ PointerRNA *UNUSED(ptr_item_storage),
+ IDOverrideLibraryPropertyOperation *opop)
+{
+ BLI_assert_msg(opop->operation == IDOVERRIDE_LIBRARY_OP_REPLACE,
+ "Unsupported RNA override operation on collections' objects");
+ UNUSED_VARS_NDEBUG(opop);
+
+ Mesh *mesh_dst = (Mesh *)ptr_dst->owner_id;
+
+ if (ptr_item_dst->type == NULL || ptr_item_src->type == NULL) {
+ // BLI_assert_msg(0, "invalid source or destination material.");
+ return false;
+ }
+
+ Material *mat_dst = ptr_item_dst->data;
+ Material *mat_src = ptr_item_src->data;
+
+ if (mat_src == mat_dst) {
+ return true;
+ }
+
+ bool is_modified = false;
+ for (int i = 0; i < mesh_dst->totcol; i++) {
+ if (mesh_dst->mat[i] == mat_dst) {
+ id_us_min(&mat_dst->id);
+ mesh_dst->mat[i] = mat_src;
+ id_us_plus(&mat_src->id);
+ is_modified = true;
+ }
+ }
+
+ if (is_modified) {
+ RNA_property_update_main(bmain, NULL, ptr_dst, prop_dst);
+ }
+
+ return true;
+}
+
/** \} */
#else
@@ -1727,7 +1820,7 @@ static void rna_def_mvert(BlenderRNA *brna)
prop = RNA_def_property(srna, "co", PROP_FLOAT, PROP_TRANSLATION);
RNA_def_property_ui_text(prop, "Location", "");
- RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_positions_tag");
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_array(prop, 3);
@@ -2435,6 +2528,8 @@ void rna_def_texmat_common(StructRNA *srna, const char *texspace_editable)
RNA_def_property_struct_type(prop, "Material");
RNA_def_property_ui_text(prop, "Materials", "");
RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+ RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Mesh_materials_override_apply");
RNA_def_property_collection_funcs(
prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int");
}
diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c
index e6cf743e167..75188f29fac 100644
--- a/source/blender/makesrna/intern/rna_meta.c
+++ b/source/blender/makesrna/intern/rna_meta.c
@@ -81,18 +81,16 @@ static void rna_MetaBall_redraw_data(Main *UNUSED(bmain), Scene *UNUSED(scene),
WM_main_add_notifier(NC_GEOM | ND_DATA, id);
}
-static void rna_MetaBall_update_data(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_MetaBall_update_data(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
MetaBall *mb = (MetaBall *)ptr->owner_id;
- Object *ob;
- /* cheating way for importers to avoid slow updates */
+ /* NOTE: The check on the number of users allows to avoid many repetitive (slow) updates in some
+ * cases, like e.g. importers. Calling `BKE_mball_properties_copy` on an obdata with no users
+ * would be meaningless anyway, as by definition it would not be used by any object, so not part
+ * of any meta-ball group. */
if (mb->id.us > 0) {
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
- if (ob->data == mb) {
- BKE_mball_properties_copy(scene, ob);
- }
- }
+ BKE_mball_properties_copy(bmain, mb);
DEG_id_tag_update(&mb->id, 0);
WM_main_add_notifier(NC_GEOM | ND_DATA, mb);
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 992e306b2bb..4810784b3f7 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -47,7 +47,7 @@
#include "MOD_nodes.h"
const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
- {0, "", 0, N_("Modify"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Modify"), NULL),
{eModifierType_DataTransfer,
"DATA_TRANSFER",
ICON_MOD_DATA_TRANSFER,
@@ -99,7 +99,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_VERTEX_WEIGHT,
"Vertex Weight Proximity",
"Set the vertex group weights based on the distance to another target object"},
- {0, "", 0, N_("Generate"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Generate"), NULL),
{eModifierType_Array,
"ARRAY",
ICON_MOD_ARRAY,
@@ -193,7 +194,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_WIREFRAME,
"Wireframe",
"Convert faces into thickened edges"},
- {0, "", 0, N_("Deform"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Deform"), NULL),
{eModifierType_Armature,
"ARMATURE",
ICON_MOD_ARMATURE,
@@ -272,7 +274,8 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_VOLUME_DATA,
"Volume Displace",
"Deform volume based on noise or other vector fields"}, /* TODO: Use correct icon. */
- {0, "", 0, N_("Physics"), ""},
+
+ RNA_ENUM_ITEM_HEADING(N_("Physics"), NULL),
{eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""},
{eModifierType_Collision, "COLLISION", ICON_MOD_PHYSICS, "Collision", ""},
{eModifierType_DynamicPaint, "DYNAMIC_PAINT", ICON_MOD_DYNAMICPAINT, "Dynamic Paint", ""},
@@ -1366,10 +1369,9 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
Object *ob_src = dtmd->ob_source;
if (ob_src) {
- AttributeDomain domain = STREQ(RNA_property_identifier(prop),
- "layers_vcol_vert_select_src") ?
- ATTR_DOMAIN_POINT :
- ATTR_DOMAIN_CORNER;
+ eAttrDomain domain = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_src") ?
+ ATTR_DOMAIN_POINT :
+ ATTR_DOMAIN_CORNER;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
@@ -1389,7 +1391,7 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_src_itemf(
cdata = &me_eval->ldata;
}
- CustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
+ eCustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
int idx = 0;
for (int i = 0; i < 2; i++) {
@@ -1489,7 +1491,7 @@ static const EnumPropertyItem *rna_DataTransferModifier_layers_select_dst_itemf(
Object *ob_dst = CTX_data_active_object(C); /* XXX Is this OK? */
if (ob_dst && ob_dst->data) {
- CustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
+ eCustomDataType types[2] = {CD_PROP_COLOR, CD_PROP_BYTE_COLOR};
Mesh *me_dst = ob_dst->data;
CustomData *cdata = STREQ(RNA_property_identifier(prop), "layers_vcol_vert_select_dst") ?
@@ -4991,7 +4993,7 @@ static void rna_def_modifier_weightvg_mask(BlenderRNA *UNUSED(brna),
0,
"Object",
"Use local generated coordinates of another object"},
- {MOD_DISP_MAP_UV, "UV", 0, "UV", "Use coordinates from an UV layer"},
+ {MOD_DISP_MAP_UV, "UV", 0, "UV", "Use coordinates from a UV layer"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index e9b49dbe7d1..b5302eca1bf 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -118,6 +118,22 @@ static PointerRNA rna_MovieClip_metadata_get(MovieClip *clip)
return ptr;
}
+static char *rna_MovieClipUser_path(const PointerRNA *ptr)
+{
+ if (ptr->owner_id) {
+ /* MovieClipUser *mc_user = ptr->data; */
+
+ switch (GS(ptr->owner_id->name)) {
+ case ID_CA:
+ return rna_CameraBackgroundImage_image_or_movieclip_user_path(ptr);
+ default:
+ break;
+ }
+ }
+
+ return BLI_strdup("");
+}
+
#else
static void rna_def_movieclip_proxy(BlenderRNA *brna)
@@ -244,7 +260,7 @@ static void rna_def_movieclip_proxy(BlenderRNA *brna)
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClip_reload_update");
}
-static void rna_def_moviecliUser(BlenderRNA *brna)
+static void rna_def_movieclipUser(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@@ -263,6 +279,9 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
srna,
"Movie Clip User",
"Parameters defining how a MovieClip data-block is used by another data-block");
+ RNA_def_struct_path_func(srna, "rna_MovieClipUser_path");
+
+ RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "frame_current", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "framenr");
@@ -286,6 +305,8 @@ static void rna_def_moviecliUser(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Render Undistorted", "Render preview using undistorted proxy");
RNA_def_property_update(
prop, NC_MOVIECLIP | ND_DISPLAY, "rna_MovieClipUser_proxy_render_settings_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_movieClipScopes(BlenderRNA *brna)
@@ -435,7 +456,7 @@ void RNA_def_movieclip(BlenderRNA *brna)
{
rna_def_movieclip(brna);
rna_def_movieclip_proxy(brna);
- rna_def_moviecliUser(brna);
+ rna_def_movieclipUser(brna);
rna_def_movieClipScopes(brna);
}
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
index 8aa87c1bcaa..524e3134f9c 100644
--- a/source/blender/makesrna/intern/rna_nla.c
+++ b/source/blender/makesrna/intern/rna_nla.c
@@ -23,6 +23,49 @@
#include "WM_api.h"
#include "WM_types.h"
+/* enum defines exported for rna_animation.c */
+const EnumPropertyItem rna_enum_nla_mode_blend_items[] = {
+ {NLASTRIP_MODE_REPLACE,
+ "REPLACE",
+ 0,
+ "Replace",
+ "The strip values replace the accumulated results by amount specified by influence"},
+ {NLASTRIP_MODE_COMBINE,
+ "COMBINE",
+ 0,
+ "Combine",
+ "The strip values are combined with accumulated results by appropriately using addition, "
+ "multiplication, or quaternion math, based on channel type"},
+ RNA_ENUM_ITEM_SEPR,
+ {NLASTRIP_MODE_ADD,
+ "ADD",
+ 0,
+ "Add",
+ "Weighted result of strip is added to the accumulated results"},
+ {NLASTRIP_MODE_SUBTRACT,
+ "SUBTRACT",
+ 0,
+ "Subtract",
+ "Weighted result of strip is removed from the accumulated results"},
+ {NLASTRIP_MODE_MULTIPLY,
+ "MULTIPLY",
+ 0,
+ "Multiply",
+ "Weighted result of strip is multiplied with the accumulated results"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_nla_mode_extend_items[] = {
+ {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"},
+ {NLASTRIP_EXTEND_HOLD,
+ "HOLD",
+ 0,
+ "Hold",
+ "Hold the first frame if no previous strips in track, and always hold last frame"},
+ {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame"},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifdef RNA_RUNTIME
# include <math.h>
@@ -40,9 +83,6 @@
# include "DEG_depsgraph.h"
# include "DEG_depsgraph_build.h"
-/* temp constant defined for these funcs only... */
-# define NLASTRIP_MIN_LEN_THRESH 0.1f
-
static void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value)
{
NlaStrip *data = (NlaStrip *)ptr->data;
@@ -122,75 +162,181 @@ static void rna_NlaStrip_transform_update(Main *bmain, Scene *scene, PointerRNA
static void rna_NlaStrip_start_frame_set(PointerRNA *ptr, float value)
{
+ /* Simply set the frame start in a valid range : if there are any NLA strips before/after, clamp
+ * the start value. If the new start value is past-the-end, clamp it. Otherwise, set it.
+ *
+ * NOTE: Unless neighboring strips are transitions, NLASTRIP_MIN_LEN_THRESH is not needed, as
+ * strips can be 'glued' to one another. If they are however, ensure transitions have a bit of
+ * time allotted in order to be performed.
+ */
NlaStrip *data = (NlaStrip *)ptr->data;
- /* Clamp value to lie within valid limits:
- * - Cannot start past the end of the strip + some flexibility threshold.
- * - Cannot start before the previous strip (if present) ends.
- * -> But if it was a transition,
- * we could go up to the start of the strip + some flexibility threshold.
- * as long as we re-adjust the transition afterwards.
- * - Minimum frame is -MAXFRAME so that we don't get clipping on frame 0.
- */
- if (data->prev) {
- if (data->prev->type == NLASTRIP_TYPE_TRANSITION) {
- CLAMP(
- value, data->prev->start + NLASTRIP_MIN_LEN_THRESH, data->end - NLASTRIP_MIN_LEN_THRESH);
+ const float limit_prev = BKE_nlastrip_compute_frame_from_previous_strip(data);
+ const float limit_next = BKE_nlastrip_compute_frame_to_next_strip(data);
+ CLAMP(value, limit_prev, limit_next);
- /* re-adjust the transition to stick to the endpoints of the action-clips */
- data->prev->end = value;
- }
- else {
- CLAMP(value, data->prev->end, data->end - NLASTRIP_MIN_LEN_THRESH);
+ data->start = value;
+
+ /* The ONLY case where we actively modify the value set by the user, is in case the start value
+ * value is past the old end frame (here delta = NLASTRIP_MIN_LEN_THRESH) :
+ * - if there's no "room" for the end frame to be placed at (new_start + delta), move old_end to
+ * the limit, and new_start to (limit - delta)
+ * - otherwise, do _not_ change the end frame. This property is not accessible from the UI, and
+ * can only be set via scripts. The script should be responsible of setting the end frame.
+ */
+ if (data->start > (data->end - NLASTRIP_MIN_LEN_THRESH)) {
+ /* If past-the-allowed-end : */
+ if ((data->start + NLASTRIP_MIN_LEN_THRESH) > limit_next) {
+ data->end = limit_next;
+ data->start = data->end - NLASTRIP_MIN_LEN_THRESH;
}
}
- else {
- CLAMP(value, MINAFRAME, data->end);
+
+ /* Ensure transitions are kept 'glued' to the strip : */
+ if (data->prev && data->prev->type == NLASTRIP_TYPE_TRANSITION) {
+ data->prev->end = data->start;
}
+}
+
+static void rna_NlaStrip_frame_start_ui_set(PointerRNA *ptr, float value)
+{
+ NlaStrip *data = (NlaStrip *)ptr->data;
+
+ /* Changing the NLA strip's start frame is exactly the same as translating it in the NLA editor.
+ * When 'translating' the clip, the length of it should stay identical. Se we also need to set
+ * this strip's end frame after modifying its start (to `start + (old_end - old_start)`).
+ * Of course, we might have a few other strips on this NLA track, so we have to respect the
+ * previous strip's end frame.
+ *
+ * Also, different types of NLA strips (*_CLIP, *_TRANSITION, *_META, *_SOUND) have their own
+ * properties to respect. Needs testing on a real-world use case for the transition, meta, and
+ * sound types.
+ */
+
+ /* The strip's total length before modifying it & also how long we'd like it to be afterwards. */
+ const float striplen = data->end - data->start;
+
+ /* We're only modifying one strip at a time. The start and end times of its neighbors should not
+ * change. As such, here are the 'bookends' (frame limits) for the start position to respect :
+ * - if a next strip exists, don't allow the strip to start after (next->end - striplen - delta),
+ * (delta being the min length of a Nla Strip : the NLASTRIP_MIN_THRESH macro)
+ * - if a previous strip exists, don't allow this strip to start before it (data->prev) ends
+ * - otherwise, limit to the program limit macros defined in DNA_scene_types.h : {MINA|MAX}FRAMEF
+ */
+ const float limit_prev = BKE_nlastrip_compute_frame_from_previous_strip(data);
+ const float limit_next = BKE_nlastrip_compute_frame_to_next_strip(data) - striplen;
+ /* For above : we want to be able to fit the entire strip before the next frame limit, so shift
+ * the next limit by 'striplen' no matter the context. */
+
+ CLAMP(value, limit_prev, limit_next);
data->start = value;
+
+ if (data->type != NLASTRIP_TYPE_TRANSITION) {
+ data->end = data->start + striplen;
+ }
+
+ /* Update properties of the prev/next strips if they are transitions to ensure consistency : */
+ if (data->prev && data->prev->type == NLASTRIP_TYPE_TRANSITION) {
+ data->prev->end = data->start;
+ }
+ if (data->next && data->next->type == NLASTRIP_TYPE_TRANSITION) {
+ data->next->start = data->end;
+ }
}
static void rna_NlaStrip_end_frame_set(PointerRNA *ptr, float value)
{
NlaStrip *data = (NlaStrip *)ptr->data;
+ const float limit_prev = BKE_nlastrip_compute_frame_from_previous_strip(data);
+ const float limit_next = BKE_nlastrip_compute_frame_to_next_strip(data);
+ CLAMP(value, limit_prev, limit_next);
+
+ data->end = value;
+
+ /* The ONLY case where we actively modify the value set by the user, is in case the start value
+ * value is past the old end frame (here delta = NLASTRIP_MIN_LEN_THRESH):
+ * - if there's no "room" for the end frame to be placed at (new_start + delta), move old_end to
+ * the limit, and new_start to (limit - delta)
+ * - otherwise, do _not_ change the end frame. This property is not accessible from the UI, and
+ * can only be set via scripts. The script should be responsible for setting the end frame.
+ */
+ if (data->end < (data->start + NLASTRIP_MIN_LEN_THRESH)) {
+ /* If before-the-allowed-start : */
+ if ((data->end - NLASTRIP_MIN_LEN_THRESH) < limit_prev) {
+ data->start = limit_prev;
+ data->end = data->start + NLASTRIP_MIN_LEN_THRESH;
+ }
+ }
+
+ /* Ensure transitions are kept "glued" to the strip: */
+ if (data->next && data->next->type == NLASTRIP_TYPE_TRANSITION) {
+ data->next->start = data->end;
+ }
+}
+
+static void rna_NlaStrip_frame_end_ui_set(PointerRNA *ptr, float value)
+{
+ NlaStrip *data = (NlaStrip *)ptr->data;
+
+ /* Changing the strip's end frame will update its action 'range' (defined by actstart->actend) to
+ * accommodate the extra length of the strip. No other parameters of the strip will change. But
+ * this means we have to get the current strip's end frame right now :
+ */
+ const float old_strip_end = data->end;
+
/* clamp value to lie within valid limits
* - must not have zero or negative length strip, so cannot start before the first frame
* + some minimum-strip-length threshold
* - cannot end later than the start of the next strip (if present)
- * -> but if it was a transition,
- * we could go up to the start of the end - some flexibility threshold
- * as long as we re-adjust the transition afterwards
+ * -> relies on the BKE_nlastrip_compute_frame_to_next_strip() function
*/
- if (data->next) {
- if (data->next->type == NLASTRIP_TYPE_TRANSITION) {
- CLAMP(
- value, data->start + NLASTRIP_MIN_LEN_THRESH, data->next->end - NLASTRIP_MIN_LEN_THRESH);
+ const float limit_prev = data->start + NLASTRIP_MIN_LEN_THRESH;
+ const float limit_next = BKE_nlastrip_compute_frame_to_next_strip(data);
- /* readjust the transition to stick to the endpoints of the action-clips */
- data->next->start = value;
- }
- else {
- CLAMP(value, data->start + NLASTRIP_MIN_LEN_THRESH, data->next->start);
- }
- }
- else {
- CLAMP(value, data->start + NLASTRIP_MIN_LEN_THRESH, MAXFRAME);
- }
+ CLAMP(value, limit_prev, limit_next);
data->end = value;
- /* calculate the lengths the strip and its action (if applicable) */
- if (data->type == NLASTRIP_TYPE_CLIP) {
- float len, actlen;
+ /* Only adjust transitions at this stage : */
+ if (data->next && data->next->type == NLASTRIP_TYPE_TRANSITION) {
+ data->next->start = value;
+ }
- len = data->end - data->start;
- actlen = data->actend - data->actstart;
+ /* calculate the lengths the strip and its action : *
+ * (Meta and transitions shouldn't be updated, but clip and sound should) */
+ if (data->type == NLASTRIP_TYPE_CLIP || data->type == NLASTRIP_TYPE_SOUND) {
+ float actlen = data->actend - data->actstart;
if (IS_EQF(actlen, 0.0f)) {
- actlen = 1.0f;
+ actlen = 1.0f; /* Only sanity check needed : we use this as divisor later on. */
}
- /* now, adjust the 'scale' setting to reflect this (so that this change can be valid) */
- data->scale = len / ((actlen)*data->repeat);
+ /* Modify the strip's action end frame, or repeat based on :
+ * - if data->repeat == 1.0f, modify the action end frame :
+ * - if the number of frames to subtract is the number of frames, set the action end frame
+ * to the action start + 1 and modify the end of the strip to add that frame
+ * - if the number of frames
+ * - otherwise, modify the repeat property to accommodate for the new length
+ */
+ float action_length_delta = (old_strip_end - data->end) / data->scale;
+ /* If no repeats are used, then modify the action end frame : */
+ if (IS_EQF(data->repeat, 1.0f)) {
+ /* If they're equal, strip has been reduced by the same amount as the whole strip length, so
+ * clamp the action clip length to 1 frame, and add a frame to end so that len(strip)!=0 :*/
+ if (IS_EQF(action_length_delta, actlen)) {
+ data->actend = data->actstart + 1.0f;
+ data->end += 1.0f;
+ }
+ else if (action_length_delta < actlen) {
+ /* Now, adjust the new strip's actend to the value it's supposed to have : */
+ data->actend = data->actend - action_length_delta;
+ }
+ /* The case where the delta is bigger than the action length should not be possible, since
+ * data->end is guaranteed to be clamped to data->start + threshold above.
+ */
+ }
+ else {
+ data->repeat -= (action_length_delta / actlen);
+ }
}
}
@@ -494,49 +640,6 @@ static void rna_NlaTrack_solo_set(PointerRNA *ptr, bool value)
#else
-/* enum defines exported for rna_animation.c */
-const EnumPropertyItem rna_enum_nla_mode_blend_items[] = {
- {NLASTRIP_MODE_REPLACE,
- "REPLACE",
- 0,
- "Replace",
- "The strip values replace the accumulated results by amount specified by influence"},
- {NLASTRIP_MODE_COMBINE,
- "COMBINE",
- 0,
- "Combine",
- "The strip values are combined with accumulated results by appropriately using addition, "
- "multiplication, or quaternion math, based on channel type"},
- {0, "", 0, NULL, NULL},
- {NLASTRIP_MODE_ADD,
- "ADD",
- 0,
- "Add",
- "Weighted result of strip is added to the accumulated results"},
- {NLASTRIP_MODE_SUBTRACT,
- "SUBTRACT",
- 0,
- "Subtract",
- "Weighted result of strip is removed from the accumulated results"},
- {NLASTRIP_MODE_MULTIPLY,
- "MULTIPLY",
- 0,
- "Multiply",
- "Weighted result of strip is multiplied with the accumulated results"},
- {0, NULL, 0, NULL, NULL},
-};
-
-const EnumPropertyItem rna_enum_nla_mode_extend_items[] = {
- {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents"},
- {NLASTRIP_EXTEND_HOLD,
- "HOLD",
- 0,
- "Hold",
- "Hold the first frame if no previous strips in track, and always hold last frame"},
- {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame"},
- {0, NULL, 0, NULL, NULL},
-};
-
static void rna_def_strip_fcurves(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -640,6 +743,31 @@ static void rna_def_nlastrip(BlenderRNA *brna)
RNA_def_property_update(
prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
+ /* Strip extents, when called from UI elements : */
+ prop = RNA_def_property(srna, "frame_start_ui", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_float_sdna(prop, NULL, "start");
+ RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_frame_start_ui_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "Start Frame (manipulated from UI)",
+ "Start frame of the NLA strip. Note: changing this value also updates the value of "
+ "the strip's end frame. If only the start frame should be changed, see the \"frame_start\" "
+ "property instead");
+ RNA_def_property_update(
+ prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
+
+ prop = RNA_def_property(srna, "frame_end_ui", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_float_sdna(prop, NULL, "end");
+ RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_frame_end_ui_set", NULL);
+ RNA_def_property_ui_text(
+ prop,
+ "End Frame (manipulated from UI)",
+ "End frame of the NLA strip. Note: changing this value also updates the value of "
+ "the strip's repeats or its action's end frame. If only the end frame should be "
+ "changed, see the \"frame_end\" property instead");
+ RNA_def_property_update(
+ prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_transform_update");
+
/* Blending */
prop = RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "blendin");
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index b9da7a2435e..80217decb13 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -164,20 +164,20 @@ static const EnumPropertyItem rna_enum_vector_rotate_type_items[] = {
};
const EnumPropertyItem rna_enum_node_math_items[] = {
- {0, "", 0, N_("Functions"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Functions"), NULL),
{NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
{NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
{NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"},
{NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", "A / B"},
{NODE_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_MATH_POWER, "POWER", 0, "Power", "A power B"},
{NODE_MATH_LOGARITHM, "LOGARITHM", 0, "Logarithm", "Logarithm A base B"},
{NODE_MATH_SQRT, "SQRT", 0, "Square Root", "Square root of A"},
{NODE_MATH_INV_SQRT, "INVERSE_SQRT", 0, "Inverse Square Root", "1 / Square root of A"},
{NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Magnitude of A"},
{NODE_MATH_EXPONENT, "EXPONENT", 0, "Exponent", "exp(A)"},
- {0, "", 0, N_("Comparison"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Comparison"), NULL),
{NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "The minimum from A and B"},
{NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "The maximum from A and B"},
{NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"},
@@ -194,7 +194,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
0,
"Smooth Maximum",
"The maximum from A and B with smoothing C"},
- {0, "", 0, N_("Rounding"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Rounding"), NULL),
{NODE_MATH_ROUND,
"ROUND",
0,
@@ -203,7 +203,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
{NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "The largest integer smaller than or equal A"},
{NODE_MATH_CEIL, "CEIL", 0, "Ceil", "The smallest integer greater than or equal A"},
{NODE_MATH_TRUNC, "TRUNC", 0, "Truncate", "The integer part of A, removing fractional digits"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
{NODE_MATH_MODULO, "MODULO", 0, "Modulo", "Modulo using fmod(A,B)"},
{NODE_MATH_WRAP, "WRAP", 0, "Wrap", "Wrap value to range, wrap(A,B)"},
@@ -213,20 +213,20 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
0,
"Ping-Pong",
"Wraps a value and reverses every other cycle (A,B)"},
- {0, "", 0, N_("Trigonometric"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Trigonometric"), NULL),
{NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"},
{NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"},
{NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_MATH_ARCSINE, "ARCSINE", 0, "Arcsine", "arcsin(A)"},
{NODE_MATH_ARCCOSINE, "ARCCOSINE", 0, "Arccosine", "arccos(A)"},
{NODE_MATH_ARCTANGENT, "ARCTANGENT", 0, "Arctangent", "arctan(A)"},
{NODE_MATH_ARCTAN2, "ARCTAN2", 0, "Arctan2", "The signed angle arctan(A / B)"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_MATH_SINH, "SINH", 0, "Hyperbolic Sine", "sinh(A)"},
{NODE_MATH_COSH, "COSH", 0, "Hyperbolic Cosine", "cosh(A)"},
{NODE_MATH_TANH, "TANH", 0, "Hyperbolic Tangent", "tanh(A)"},
- {0, "", 0, N_("Conversion"), ""},
+ RNA_ENUM_ITEM_HEADING(N_("Conversion"), NULL),
{NODE_MATH_RADIANS, "RADIANS", 0, "To Radians", "Convert from degrees to radians"},
{NODE_MATH_DEGREES, "DEGREES", 0, "To Degrees", "Convert from radians to degrees"},
{0, NULL, 0, NULL, NULL},
@@ -238,7 +238,7 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
{NODE_VECTOR_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "Entry-wise multiply"},
{NODE_VECTOR_MATH_DIVIDE, "DIVIDE", 0, "Divide", "Entry-wise divide"},
{NODE_VECTOR_MATH_MULTIPLY_ADD, "MULTIPLY_ADD", 0, "Multiply Add", "A * B + C"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_VECTOR_MATH_CROSS_PRODUCT, "CROSS_PRODUCT", 0, "Cross Product", "A cross B"},
{NODE_VECTOR_MATH_PROJECT, "PROJECT", 0, "Project", "Project A onto B"},
{NODE_VECTOR_MATH_REFLECT,
@@ -259,12 +259,12 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
"Orients a vector A to point away from a surface B as defined by its normal C. "
"Returns (dot(B, C) < 0) ? A : -A"},
{NODE_VECTOR_MATH_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "A dot B"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_VECTOR_MATH_DISTANCE, "DISTANCE", 0, "Distance", "Distance between A and B"},
{NODE_VECTOR_MATH_LENGTH, "LENGTH", 0, "Length", "Length of A"},
{NODE_VECTOR_MATH_SCALE, "SCALE", 0, "Scale", "A multiplied by Scale"},
{NODE_VECTOR_MATH_NORMALIZE, "NORMALIZE", 0, "Normalize", "Normalize A"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_VECTOR_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Entry-wise absolute"},
{NODE_VECTOR_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "Entry-wise minimum"},
{NODE_VECTOR_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "Entry-wise maximum"},
@@ -278,7 +278,7 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
0,
"Snap",
"Round A to the largest integer multiple of B less than or equal A"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_VECTOR_MATH_SINE, "SINE", 0, "Sine", "Entry-wise sin(A)"},
{NODE_VECTOR_MATH_COSINE, "COSINE", 0, "Cosine", "Entry-wise cos(A)"},
{NODE_VECTOR_MATH_TANGENT, "TANGENT", 0, "Tangent", "Entry-wise tan(A)"},
@@ -289,7 +289,7 @@ const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
{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},
+ RNA_ENUM_ITEM_SEPR,
{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,
@@ -302,7 +302,7 @@ const EnumPropertyItem rna_enum_node_boolean_math_items[] = {
0,
"Not Equal",
"True when both inputs are different (exclusive or)"},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NODE_BOOLEAN_MATH_IMPLY,
"IMPLY",
0,
@@ -443,9 +443,9 @@ const EnumPropertyItem rna_enum_node_clamp_items[] = {
static const EnumPropertyItem rna_enum_node_tex_dimensions_items[] = {
{1, "1D", 0, "1D", "Use the scalar value W as input"},
- {2, "2D", 0, "2D", "Use the 2D vector (x, y) as input. The z component is ignored"},
- {3, "3D", 0, "3D", "Use the 3D vector (x, y, z) as input"},
- {4, "4D", 0, "4D", "Use the 4D vector (x, y, z, w) as input"},
+ {2, "2D", 0, "2D", "Use the 2D vector (X, Y) as input. The Z component is ignored"},
+ {3, "3D", 0, "3D", "Use the 3D vector (X, Y, Z) as input"},
+ {4, "4D", 0, "4D", "Use the 4D vector (X, Y, Z, W) as input"},
{0, NULL, 0, NULL, NULL},
};
@@ -1610,26 +1610,31 @@ static char *rna_Node_path(const PointerRNA *ptr)
char *rna_Node_ImageUser_path(const PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node;
- char name_esc[sizeof(node->name) * 2];
+ if (!ELEM(ntree->type, NTREE_SHADER, NTREE_CUSTOM)) {
+ return NULL;
+ }
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_TEX_ENVIRONMENT) {
- NodeTexEnvironment *data = node->storage;
- if (&data->iuser != ptr->data) {
- continue;
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ switch (node->type) {
+ case SH_NODE_TEX_ENVIRONMENT: {
+ NodeTexEnvironment *data = node->storage;
+ if (&data->iuser != ptr->data) {
+ continue;
+ }
+ break;
}
- }
- else if (node->type == SH_NODE_TEX_IMAGE) {
- NodeTexImage *data = node->storage;
- if (&data->iuser != ptr->data) {
- continue;
+ case SH_NODE_TEX_IMAGE: {
+ NodeTexImage *data = node->storage;
+ if (&data->iuser != ptr->data) {
+ continue;
+ }
+ break;
}
- }
- else {
- continue;
+ default:
+ continue;
}
+ char name_esc[sizeof(node->name) * 2];
BLI_str_escape(name_esc, node->name, sizeof(name_esc));
return BLI_sprintfN("nodes[\"%s\"].image_user", name_esc);
}
@@ -4523,9 +4528,9 @@ static const EnumPropertyItem prop_view_layer_items[] = {
};
static const EnumPropertyItem prop_tri_channel_items[] = {
- {1, "R", 0, "R", ""},
- {2, "G", 0, "G", ""},
- {3, "B", 0, "B", ""},
+ {1, "R", 0, "R", "Red"},
+ {2, "G", 0, "G", "Green"},
+ {3, "B", 0, "B", "Blue"},
{0, NULL, 0, NULL, NULL},
};
@@ -4544,46 +4549,81 @@ static const EnumPropertyItem node_ycc_items[] = {
};
static const EnumPropertyItem node_glossy_items[] = {
- {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_SHARP,
+ "SHARP",
+ 0,
+ "Sharp",
+ "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
- {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX,
+ "MULTI_GGX",
+ 0,
+ "Multiscatter GGX",
+ "Slower than GGX but gives a more energy conserving results, which would otherwise be "
+ "visible as excessive darkening"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_anisotropic_items[] = {
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
- {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX,
+ "MULTI_GGX",
+ 0,
+ "Multiscatter GGX",
+ "Slower than GGX but gives a more energy conserving results, which would otherwise be "
+ "visible as excessive darkening"},
{SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_glass_items[] = {
- {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_SHARP,
+ "SHARP",
+ 0,
+ "Sharp",
+ "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
- {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX,
+ "MULTI_GGX",
+ 0,
+ "Multiscatter GGX",
+ "Slower than GGX but gives a more energy conserving results, which would otherwise be "
+ "visible as excessive darkening"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_refraction_items[] = {
- {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_SHARP,
+ "SHARP",
+ 0,
+ "Sharp",
+ "Results in perfectly sharp reflections like a mirror. The Roughness value is not used"},
{SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_toon_items[] = {
- {SHD_TOON_DIFFUSE, "DIFFUSE", 0, "Diffuse", ""},
- {SHD_TOON_GLOSSY, "GLOSSY", 0, "Glossy", ""},
+ {SHD_TOON_DIFFUSE, "DIFFUSE", 0, "Diffuse", "Use diffuse BSDF"},
+ {SHD_TOON_GLOSSY, "GLOSSY", 0, "Glossy", "Use glossy BSDF"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem node_hair_items[] = {
- {SHD_HAIR_REFLECTION, "Reflection", 0, "Reflection", ""},
- {SHD_HAIR_TRANSMISSION, "Transmission", 0, "Transmission", ""},
+ {SHD_HAIR_REFLECTION,
+ "Reflection",
+ 0,
+ "Reflection",
+ "The light that bounces off the surface of the hair"},
+ {SHD_HAIR_TRANSMISSION,
+ "Transmission",
+ 0,
+ "Transmission",
+ "The light that passes through the hair and exits on the other side"},
{0, NULL, 0, NULL, NULL},
};
@@ -4623,7 +4663,12 @@ static EnumPropertyItem node_ies_mode_items[] = {
static const EnumPropertyItem node_principled_distribution_items[] = {
{SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
- {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""},
+ {SHD_GLOSSY_MULTI_GGX,
+ "MULTI_GGX",
+ 0,
+ "Multiscatter GGX",
+ "Slower than GGX but gives a more energy conserving results, which would otherwise be "
+ "visible as excessive darkening"},
{0, NULL, 0, NULL, NULL},
};
@@ -5237,7 +5282,7 @@ static void def_sh_tex_sky(StructRNA *srna)
prop = RNA_def_property(srna, "sun_elevation", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_ui_text(prop, "Sun Elevation", "Sun angle from horizon");
- RNA_def_property_range(prop, -M_PI_2, M_PI_2);
+ RNA_def_property_ui_range(prop, -M_PI, M_PI, 1, 2);
RNA_def_property_float_default(prop, M_PI_2);
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
@@ -5517,8 +5562,7 @@ static void def_sh_tex_noise(StructRNA *srna)
prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dimensions");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
- RNA_def_property_ui_text(
- prop, "Dimensions", "The dimensions of the space to evaluate the noise in");
+ RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
@@ -5581,11 +5625,28 @@ static void def_sh_tex_magic(StructRNA *srna)
static void def_sh_tex_musgrave(StructRNA *srna)
{
static const EnumPropertyItem prop_musgrave_type[] = {
- {SHD_MUSGRAVE_MULTIFRACTAL, "MULTIFRACTAL", 0, "Multifractal", ""},
- {SHD_MUSGRAVE_RIDGED_MULTIFRACTAL, "RIDGED_MULTIFRACTAL", 0, "Ridged Multifractal", ""},
- {SHD_MUSGRAVE_HYBRID_MULTIFRACTAL, "HYBRID_MULTIFRACTAL", 0, "Hybrid Multifractal", ""},
- {SHD_MUSGRAVE_FBM, "FBM", 0, "fBM", ""},
- {SHD_MUSGRAVE_HETERO_TERRAIN, "HETERO_TERRAIN", 0, "Hetero Terrain", ""},
+ {SHD_MUSGRAVE_MULTIFRACTAL,
+ "MULTIFRACTAL",
+ 0,
+ "Multifractal",
+ "More uneven result (varies with location), more similar to a real terrain"},
+ {SHD_MUSGRAVE_RIDGED_MULTIFRACTAL,
+ "RIDGED_MULTIFRACTAL",
+ 0,
+ "Ridged Multifractal",
+ "Create sharp peaks"},
+ {SHD_MUSGRAVE_HYBRID_MULTIFRACTAL,
+ "HYBRID_MULTIFRACTAL",
+ 0,
+ "Hybrid Multifractal",
+ "Create peaks and valleys with different roughness values"},
+ {SHD_MUSGRAVE_FBM, "FBM", 0, "fBM", "Produce an unnatural homogeneous and isotropic result"},
+ {SHD_MUSGRAVE_HETERO_TERRAIN,
+ "HETERO_TERRAIN",
+ 0,
+ "Hetero Terrain",
+ "Similar to Hybrid Multifractal creates a heterogeneous terrain, but with the likeness of "
+ "river channels"},
{0, NULL, 0, NULL, NULL},
};
@@ -5597,13 +5658,13 @@ static void def_sh_tex_musgrave(StructRNA *srna)
prop = RNA_def_property(srna, "musgrave_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dimensions");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
- RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "musgrave_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "musgrave_type");
RNA_def_property_enum_items(prop, prop_musgrave_type);
- RNA_def_property_ui_text(prop, "Type", "");
+ RNA_def_property_ui_text(prop, "Type", "Type of the Musgrave texture");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
@@ -5652,19 +5713,21 @@ static void def_sh_tex_voronoi(StructRNA *srna)
prop = RNA_def_property(srna, "voronoi_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dimensions");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
- RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "distance", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "distance");
RNA_def_property_enum_items(prop, prop_distance_items);
- RNA_def_property_ui_text(prop, "Distance Metric", "");
+ RNA_def_property_ui_text(
+ prop, "Distance Metric", "The distance metric used to compute the texture");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "feature", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "feature");
RNA_def_property_enum_items(prop, prop_feature_items);
- RNA_def_property_ui_text(prop, "Feature Output", "");
+ RNA_def_property_ui_text(
+ prop, "Feature Output", "The Voronoi feature that the node will compute");
RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
@@ -5740,8 +5803,7 @@ static void def_sh_tex_white_noise(StructRNA *srna)
prop = RNA_def_property(srna, "noise_dimensions", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
- RNA_def_property_ui_text(
- prop, "Dimensions", "The dimensions of the space to evaluate the noise in");
+ RNA_def_property_ui_text(prop, "Dimensions", "Number of dimensions to output noise for");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
@@ -5983,7 +6045,7 @@ static void def_glossy(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_glossy_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -5994,7 +6056,7 @@ static void def_glass(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_glass_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6005,7 +6067,7 @@ static void def_principled(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_principled_distribution_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "subsurface_method", PROP_ENUM, PROP_NONE);
@@ -6023,7 +6085,7 @@ static void def_refraction(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_refraction_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6034,7 +6096,7 @@ static void def_anisotropic(StructRNA *srna)
prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_anisotropic_items);
- RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_ui_text(prop, "Distribution", "Light scattering distribution on rough surface");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6045,7 +6107,7 @@ static void def_toon(StructRNA *srna)
prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_toon_items);
- RNA_def_property_ui_text(prop, "Component", "");
+ RNA_def_property_ui_text(prop, "Component", "Toon BSDF component to use");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -6067,7 +6129,7 @@ static void def_hair(StructRNA *srna)
prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, node_hair_items);
- RNA_def_property_ui_text(prop, "Component", "");
+ RNA_def_property_ui_text(prop, "Component", "Hair BSDF component to use");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
@@ -9518,18 +9580,14 @@ static void def_geo_distribute_points_on_faces(StructRNA *srna)
static void def_geo_curve_spline_type(StructRNA *srna)
{
- static const EnumPropertyItem type_items[] = {
- {GEO_NODE_SPLINE_TYPE_BEZIER, "BEZIER", ICON_NONE, "Bezier", "Set the splines to Bezier"},
- {GEO_NODE_SPLINE_TYPE_NURBS, "NURBS", ICON_NONE, "NURBS", "Set the splines to NURBS"},
- {GEO_NODE_SPLINE_TYPE_POLY, "POLY", ICON_NONE, "Poly", "Set the splines to Poly"},
- {0, NULL, 0, NULL, NULL}};
-
PropertyRNA *prop;
RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSplineType", "storage");
prop = RNA_def_property(srna, "spline_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "spline_type");
- RNA_def_property_enum_items(prop, type_items);
+ RNA_def_property_enum_items(prop, rna_enum_curves_types);
+ RNA_def_property_ui_text(prop, "Type", "The curve type to change the selected curves to");
+
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
@@ -9821,6 +9879,33 @@ 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_uv_unwrap(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem rna_node_geometry_uv_unwrap_method_items[] = {
+ {GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED,
+ "ANGLE_BASED",
+ 0,
+ "Angle Based",
+ "This method gives a good 2D representation of a mesh"},
+ {GEO_NODE_UV_UNWRAP_METHOD_CONFORMAL,
+ "CONFORMAL",
+ 0,
+ "Conformal",
+ "Uses LSCM (Least Squares Conformal Mapping). This usually gives a less accurate UV "
+ "mapping than Angle Based, but works better for simpler objects"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryUVUnwrap", "storage");
+
+ prop = RNA_def_property(srna, "method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_node_geometry_uv_unwrap_method_items);
+ RNA_def_property_ui_text(prop, "Method", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_geo_collection_info(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9912,6 +9997,32 @@ static void def_geo_volume_to_mesh(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_mesh_to_volume(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem resolution_mode_items[] = {
+ {MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT,
+ "VOXEL_AMOUNT",
+ 0,
+ "Amount",
+ "Desired number of voxels along one axis"},
+ {MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE,
+ "VOXEL_SIZE",
+ 0,
+ "Size",
+ "Desired voxel side length"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryMeshToVolume", "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_mesh_circle(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10644,6 +10755,25 @@ static void def_geo_field_at_index(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
}
+static void def_geo_field_on_domain(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_GeometryNodeAttributeType_type_with_socket_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;
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index b192a385546..103c77fa808 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -149,7 +149,7 @@ const EnumPropertyItem rna_enum_object_gpencil_type_items[] = {
{GP_EMPTY, "EMPTY", ICON_EMPTY_AXIS, "Blank", "Create an empty grease pencil object"},
{GP_STROKE, "STROKE", ICON_STROKE, "Stroke", "Create a simple stroke with basic colors"},
{GP_MONKEY, "MONKEY", ICON_MONKEY, "Monkey", "Construct a Suzanne grease pencil object"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{GP_LRT_SCENE,
"LRT_SCENE",
ICON_SCENE_DATA,
@@ -256,17 +256,17 @@ const EnumPropertyItem rna_enum_object_type_items[] = {
{OB_POINTCLOUD, "POINTCLOUD", ICON_OUTLINER_OB_POINTCLOUD, "Point Cloud", ""},
{OB_VOLUME, "VOLUME", ICON_OUTLINER_OB_VOLUME, "Volume", ""},
{OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_ARMATURE, "ARMATURE", ICON_OUTLINER_OB_ARMATURE, "Armature", ""},
{OB_LATTICE, "LATTICE", ICON_OUTLINER_OB_LATTICE, "Lattice", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_EMPTY, "EMPTY", ICON_OUTLINER_OB_EMPTY, "Empty", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_LAMP, "LIGHT", ICON_OUTLINER_OB_LIGHT, "Light", ""},
{OB_LIGHTPROBE, "LIGHT_PROBE", ICON_OUTLINER_OB_LIGHTPROBE, "Light Probe", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_CAMERA, "CAMERA", ICON_OUTLINER_OB_CAMERA, "Camera", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{OB_SPEAKER, "SPEAKER", ICON_OUTLINER_OB_SPEAKER, "Speaker", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -511,7 +511,7 @@ static PointerRNA rna_Object_data_get(PointerRNA *ptr)
Object *ob = (Object *)ptr->data;
if (ob->type == OB_MESH) {
Mesh *me = (Mesh *)ob->data;
- me = BKE_mesh_wrapper_ensure_subdivision(ob, me);
+ me = BKE_mesh_wrapper_ensure_subdivision(me);
return rna_pointer_inherit_refine(ptr, &RNA_Mesh, me);
}
return rna_pointer_inherit_refine(ptr, &RNA_ID, ob->data);
@@ -607,11 +607,7 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr)
case OB_GPENCIL:
return &RNA_GreasePencil;
case OB_CURVES:
-# ifdef WITH_NEW_CURVES_TYPE
return &RNA_Curves;
-# else
- return &RNA_ID;
-# endif
case OB_POINTCLOUD:
return &RNA_PointCloud;
case OB_VOLUME:
@@ -2950,6 +2946,22 @@ static void rna_def_object_lineart(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, DEG2RAD(180.0f), 0.01f, 1);
RNA_def_property_ui_text(prop, "Crease", "Angles smaller than this will be treated as creases");
RNA_def_property_update(prop, 0, "rna_object_lineart_update");
+
+ prop = RNA_def_property(srna, "use_intersection_priority_override", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", OBJECT_LRT_OWN_INTERSECTION_PRIORITY);
+ RNA_def_property_ui_text(
+ prop,
+ "Use Intersection Priority",
+ "Use this object's intersection priority to override collection setting");
+ RNA_def_property_update(prop, 0, "rna_object_lineart_update");
+
+ prop = RNA_def_property(srna, "intersection_priority", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_text(prop,
+ "Intersection Priority",
+ "The intersection line will be included into the object with the "
+ "higher intersection priority value");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_SHADING, "rna_object_lineart_update");
}
static void rna_def_object_visibility(StructRNA *srna)
@@ -3563,6 +3575,14 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Empty Image Side", "Show front/back side");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "add_rest_position_attribute", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "modifier_flag", OB_MODIFIER_FLAG_ADD_REST_POSITION);
+ RNA_def_property_ui_text(prop,
+ "Add Rest Position",
+ "Add a \"rest_position\" attribute that is a copy of the position "
+ "attribute before shape keys and modifiers are evaluated");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update_data");
+
/* render */
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "index");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index a67b0f7c8e6..3fc98d769b6 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -25,6 +25,7 @@
#include "RNA_enum_types.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BLI_listbase.h"
diff --git a/source/blender/makesrna/intern/rna_pointcloud.c b/source/blender/makesrna/intern/rna_pointcloud.c
index 4c5dcd5a587..df09bff1aea 100644
--- a/source/blender/makesrna/intern/rna_pointcloud.c
+++ b/source/blender/makesrna/intern/rna_pointcloud.c
@@ -20,6 +20,7 @@
# include "BLI_math_vector.h"
+# include "BKE_customdata.h"
# include "BKE_pointcloud.h"
# include "DEG_depsgraph.h"
@@ -36,7 +37,9 @@ static int rna_Point_index_get_const(const PointerRNA *ptr)
{
const PointCloud *pointcloud = rna_pointcloud(ptr);
const float(*co)[3] = ptr->data;
- return (int)(co - pointcloud->co);
+ const float(*positions)[3] = (const float(*)[3])CustomData_get_layer_named(
+ &pointcloud->pdata, CD_PROP_FLOAT3, "position");
+ return (int)(co - positions);
}
static int rna_Point_index_get(PointerRNA *ptr)
@@ -44,6 +47,21 @@ static int rna_Point_index_get(PointerRNA *ptr)
return rna_Point_index_get_const(ptr);
}
+static int rna_PointCloud_points_length(PointerRNA *ptr)
+{
+ const PointCloud *pointcloud = rna_pointcloud(ptr);
+ return pointcloud->totpoint;
+}
+
+static void rna_PointCloud_points_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ const PointCloud *pointcloud = rna_pointcloud(ptr);
+ const float(*positions)[3] = (const float(*)[3])CustomData_get_layer_named(
+ &pointcloud->pdata, CD_PROP_FLOAT3, "position");
+ rna_iterator_array_begin(
+ iter, (void *)positions, sizeof(float[3]), pointcloud->totpoint, false, NULL);
+}
+
static void rna_Point_location_get(PointerRNA *ptr, float value[3])
{
copy_v3_v3(value, (const float *)ptr->data);
@@ -57,21 +75,22 @@ static void rna_Point_location_set(PointerRNA *ptr, const float value[3])
static float rna_Point_radius_get(PointerRNA *ptr)
{
const PointCloud *pointcloud = rna_pointcloud(ptr);
- if (pointcloud->radius == NULL) {
+ const float *radii = (const float *)CustomData_get_layer_named(
+ &pointcloud->pdata, CD_PROP_FLOAT, "radius");
+ if (radii == NULL) {
return 0.0f;
}
- const float(*co)[3] = ptr->data;
- return pointcloud->radius[co - pointcloud->co];
+ return radii[rna_Point_index_get_const(ptr)];
}
static void rna_Point_radius_set(PointerRNA *ptr, float value)
{
- const PointCloud *pointcloud = rna_pointcloud(ptr);
- if (pointcloud->radius == NULL) {
+ PointCloud *pointcloud = rna_pointcloud(ptr);
+ float *radii = (float *)CustomData_get_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, "radius");
+ if (radii == NULL) {
return;
}
- const float(*co)[3] = ptr->data;
- pointcloud->radius[co - pointcloud->co] = value;
+ radii[rna_Point_index_get_const(ptr)] = value;
}
static char *rna_Point_path(const PointerRNA *ptr)
@@ -130,13 +149,18 @@ static void rna_def_pointcloud(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_POINTCLOUD_DATA);
/* geometry */
- /* TODO: better solution for (*co)[3] parsing issue. */
- RNA_define_verify_sdna(0);
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "co", "totpoint");
RNA_def_property_struct_type(prop, "Point");
+ RNA_def_property_collection_funcs(prop,
+ "rna_PointCloud_points_begin",
+ "rna_iterator_array_next",
+ "rna_iterator_array_end",
+ "rna_iterator_array_get",
+ "rna_PointCloud_points_length",
+ NULL,
+ NULL,
+ NULL);
RNA_def_property_ui_text(prop, "Points", "");
- RNA_define_verify_sdna(1);
/* materials */
prop = RNA_def_property(srna, "materials", PROP_COLLECTION, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 4108baca2fa..30df8e20e8d 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -698,16 +698,18 @@ bool rna_PoseChannel_constraints_override_apply(Main *bmain,
return true;
}
-static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info)
+static int rna_PoseChannel_proxy_editable(PointerRNA *UNUSED(ptr), const char **UNUSED(r_info))
{
+# if 0
Object *ob = (Object *)ptr->owner_id;
bArmature *arm = ob->data;
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- if (false && pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
+ if (pchan->bone && (pchan->bone->layer & arm->layer_protected)) {
*r_info = "Can't edit property of a proxy on a protected layer";
return 0;
}
+# endif
return PROP_EDITABLE;
}
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index ae67de9228c..16a4dfe71cf 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -50,56 +50,85 @@ const EnumPropertyItem rna_enum_property_type_items[] = {
{0, NULL, 0, NULL, NULL},
};
-/* Keep in sync with RNA_types.h PropertySubType and bpy_props.c's property_subtype_xxx_items */
+/* Wraps multiple enums onto a single line in a way that is difficult to read.
+ * NOTE: these enums are split up based on their use in `bpy.props` Python module. */
+
+/* clang-format off */
+#define RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS \
+ {PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""}, \
+ {PROP_DIRPATH, "DIR_PATH", 0, "Directory Path", ""}, \
+ {PROP_FILENAME, "FILE_NAME", 0, "File Name", ""}, \
+ {PROP_BYTESTRING, "BYTE_STRING", 0, "Byte String", ""}, \
+ {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"}
+
+#define RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS \
+ {PROP_PIXEL, "PIXEL", 0, "Pixel", ""}, \
+ {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""}, \
+ {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""}, \
+ {PROP_FACTOR, "FACTOR", 0, "Factor", ""}, \
+ {PROP_ANGLE, "ANGLE", 0, "Angle", ""}, \
+ {PROP_TIME, "TIME", 0, "Time (Scene Relative)", \
+ "Time specified in frames, converted to seconds based on scene frame rate"}, \
+ {PROP_TIME_ABSOLUTE, "TIME_ABSOLUTE", 0, "Time (Absolute)", \
+ "Time specified in seconds, independent of the scene"}, \
+ {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""}, \
+ {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""}, \
+ {PROP_POWER, "POWER", 0, "Power", ""}, \
+ {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""}
+
+#define RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS \
+ {PROP_COLOR, "COLOR", 0, "Color", ""}, \
+ {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""}, \
+ {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""}, \
+ {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""}, \
+ {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""}, \
+ {PROP_MATRIX, "MATRIX", 0, "Matrix", ""}, \
+ {PROP_EULER, "EULER", 0, "Euler Angles", ""}, \
+ {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""}, \
+ {PROP_AXISANGLE, "AXISANGLE", 0, "Axis-Angle", ""}, \
+ {PROP_XYZ, "XYZ", 0, "XYZ", ""}, \
+ {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""}, \
+ {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color", ""}, \
+ {PROP_COORDS, "COORDINATES", 0, "Coordinates", ""}, \
+ /* Boolean. */ \
+ {PROP_LAYER, "LAYER", 0, "Layer", ""}, \
+ {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""}
+
+/* clang-format on */
+
+const EnumPropertyItem rna_enum_property_subtype_string_items[] = {
+ RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS,
+
+ {PROP_NONE, "NONE", 0, "None", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_subtype_number_items[] = {
+ RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS,
+
+ {PROP_NONE, "NONE", 0, "None", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_subtype_number_array_items[] = {
+ RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS,
+
+ {PROP_NONE, "NONE", 0, "None", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_property_subtype_items[] = {
{PROP_NONE, "NONE", 0, "None", ""},
- /* strings */
- {PROP_FILEPATH, "FILEPATH", 0, "File Path", ""},
- {PROP_DIRPATH, "DIRPATH", 0, "Directory Path", ""},
- {PROP_FILENAME, "FILENAME", 0, "File Name", ""},
- {PROP_BYTESTRING, "BYTESTRING", 0, "Byte String", ""},
- {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"},
-
- /* numbers */
- {PROP_PIXEL, "PIXEL", 0, "Pixel", ""},
- {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""},
- {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""},
- {PROP_FACTOR, "FACTOR", 0, "Factor", ""},
- {PROP_ANGLE, "ANGLE", 0, "Angle", ""},
- {PROP_TIME,
- "TIME",
- 0,
- "Time (Scene Relative)",
- "Time specified in frames, converted to seconds based on scene frame rate"},
- {PROP_TIME_ABSOLUTE,
- "TIME_ABSOLUTE",
- 0,
- "Time (Absolute)",
- "Time specified in seconds, independent of the scene"},
- {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""},
- {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""},
- {PROP_POWER, "POWER", 0, "Power", ""},
- {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""},
-
- /* number arrays */
- {PROP_COLOR, "COLOR", 0, "Color", ""},
- {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""},
- {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""},
- {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""},
- {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""},
- {PROP_MATRIX, "MATRIX", 0, "Matrix", ""},
- {PROP_EULER, "EULER", 0, "Euler Angles", ""},
- {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""},
- {PROP_AXISANGLE, "AXISANGLE", 0, "Axis-Angle", ""},
- {PROP_XYZ, "XYZ", 0, "XYZ", ""},
- {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""},
- {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color", ""},
- {PROP_COORDS, "COORDS", 0, "Coordinates", ""},
-
- /* booleans */
- {PROP_LAYER, "LAYER", 0, "Layer", ""},
- {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""},
+ /* String. */
+ RNA_ENUM_PROPERTY_SUBTYPE_STRING_ITEMS,
+
+ /* Number. */
+ RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ITEMS,
+
+ /* Number array. */
+ RNA_ENUM_PROPERTY_SUBTYPE_NUMBER_ARRAY_ITEMS,
+
{0, NULL, 0, NULL, NULL},
};
@@ -120,6 +149,69 @@ const EnumPropertyItem rna_enum_property_unit_items[] = {
{0, NULL, 0, NULL, NULL},
};
+const EnumPropertyItem rna_enum_property_flag_items[] = {
+ {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
+ {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
+ {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
+ {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
+ {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to each other", ""},
+ {PROP_TEXTEDIT_UPDATE,
+ "TEXTEDIT_UPDATE",
+ 0,
+ "Update on every keystroke in textedit 'mode'",
+ ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+/** Only for enum type properties. */
+const EnumPropertyItem rna_enum_property_flag_enum_items[] = {
+ {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
+ {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
+ {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
+ {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
+ {PROP_ENUM_FLAG, "ENUM_FLAG", 0, "Enum Flag", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_override_flag_items[] = {
+ {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
+ "LIBRARY_OVERRIDABLE",
+ 0,
+ "Library Overridable",
+ "Make that property editable in library overrides of linked data-blocks"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_override_flag_collection_items[] = {
+ {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
+ "LIBRARY_OVERRIDABLE",
+ 0,
+ "Library Overridable",
+ "Make that property editable in library overrides of linked data-blocks"},
+ {PROPOVERRIDE_NO_PROP_NAME,
+ "NO_PROPERTY_NAME",
+ 0,
+ "No Name",
+ "Do not use the names of the items, only their indices in the collection"},
+ {PROPOVERRIDE_LIBRARY_INSERTION,
+ "USE_INSERTION",
+ 0,
+ "Use Insertion",
+ "Allow users to add new items in that collection in library overrides"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_property_string_search_flag_items[] = {
+ {PROP_STRING_SEARCH_SORT, "SORT", 0, "Sort Search Results", ""},
+ {PROP_STRING_SEARCH_SUGGESTION,
+ "SUGGESTION",
+ 0,
+ "Suggestion",
+ "Search results are suggestions (other values may be entered)"},
+
+ {0, NULL, 0, NULL, NULL},
+};
+
/** \} */
#ifdef RNA_RUNTIME
@@ -941,17 +1033,29 @@ static int rna_EnumPropertyItem_identifier_length(PointerRNA *ptr)
static void rna_EnumPropertyItem_name_get(PointerRNA *ptr, char *value)
{
- strcpy(value, ((EnumPropertyItem *)ptr->data)->name);
+ const EnumPropertyItem *eprop = ptr->data;
+ /* Name can be NULL in the case of separators
+ * which are exposed via `_bpy.rna_enum_items_static`. */
+ if (eprop->name) {
+ strcpy(value, eprop->name);
+ }
+ else {
+ value[0] = '\0';
+ }
}
static int rna_EnumPropertyItem_name_length(PointerRNA *ptr)
{
- return strlen(((EnumPropertyItem *)ptr->data)->name);
+ const EnumPropertyItem *eprop = ptr->data;
+ if (eprop->name) {
+ return strlen(eprop->name);
+ }
+ return 0;
}
static void rna_EnumPropertyItem_description_get(PointerRNA *ptr, char *value)
{
- EnumPropertyItem *eprop = (EnumPropertyItem *)ptr->data;
+ const EnumPropertyItem *eprop = ptr->data;
if (eprop->description) {
strcpy(value, eprop->description);
@@ -968,9 +1072,7 @@ static int rna_EnumPropertyItem_description_length(PointerRNA *ptr)
if (eprop->description) {
return strlen(eprop->description);
}
- else {
- return 0;
- }
+ return 0;
}
static int rna_EnumPropertyItem_value_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 0e423b71f1d..daf4c99845d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -92,11 +92,11 @@ static const EnumPropertyItem uv_sculpt_relaxation_items[] = {
};
#endif
-const EnumPropertyItem rna_enum_snap_target_items[] = {
- {SCE_SNAP_TARGET_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
- {SCE_SNAP_TARGET_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"},
- {SCE_SNAP_TARGET_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"},
- {SCE_SNAP_TARGET_ACTIVE, "ACTIVE", 0, "Active", "Snap active onto target"},
+const EnumPropertyItem rna_enum_snap_source_items[] = {
+ {SCE_SNAP_SOURCE_CLOSEST, "CLOSEST", 0, "Closest", "Snap closest point onto target"},
+ {SCE_SNAP_SOURCE_CENTER, "CENTER", 0, "Center", "Snap transformation center onto target"},
+ {SCE_SNAP_SOURCE_MEDIAN, "MEDIAN", 0, "Median", "Snap median onto target"},
+ {SCE_SNAP_SOURCE_ACTIVE, "ACTIVE", 0, "Active", "Snap active onto target"},
{0, NULL, 0, NULL, NULL},
};
@@ -151,7 +151,16 @@ const EnumPropertyItem rna_enum_snap_element_items[] = {
"Snap to increments of grid"},
{SCE_SNAP_MODE_VERTEX, "VERTEX", ICON_SNAP_VERTEX, "Vertex", "Snap to vertices"},
{SCE_SNAP_MODE_EDGE, "EDGE", ICON_SNAP_EDGE, "Edge", "Snap to edges"},
- {SCE_SNAP_MODE_FACE, "FACE", ICON_SNAP_FACE, "Face", "Snap to faces"},
+ {SCE_SNAP_MODE_FACE_RAYCAST,
+ "FACE", /* TODO(@gfxcoder): replace with "FACE_RAYCAST" as "FACE" is not descriptive. */
+ ICON_SNAP_FACE,
+ "Face Project",
+ "Snap by projecting onto faces"},
+ {SCE_SNAP_MODE_FACE_NEAREST,
+ "FACE_NEAREST",
+ ICON_SNAP_FACE_NEAREST,
+ "Face Nearest",
+ "Snap to nearest point on faces"},
{SCE_SNAP_MODE_VOLUME, "VOLUME", ICON_SNAP_VOLUME, "Volume", "Snap to volume"},
{SCE_SNAP_MODE_EDGE_MIDPOINT,
"EDGE_MIDPOINT",
@@ -345,9 +354,9 @@ const EnumPropertyItem rna_enum_curve_fit_method_items[] = {
R_IMF_ENUM_JPEG \
R_IMF_ENUM_JPEG2K \
R_IMF_ENUM_TAGA \
- R_IMF_ENUM_TAGA_RAW{0, "", 0, " ", NULL}, \
- R_IMF_ENUM_CINEON R_IMF_ENUM_DPX R_IMF_ENUM_EXR_MULTILAYER R_IMF_ENUM_EXR R_IMF_ENUM_HDR \
- R_IMF_ENUM_TIFF R_IMF_ENUM_WEBP
+ R_IMF_ENUM_TAGA_RAW \
+ RNA_ENUM_ITEM_SEPR_COLUMN, R_IMF_ENUM_CINEON R_IMF_ENUM_DPX R_IMF_ENUM_EXR_MULTILAYER \
+ R_IMF_ENUM_EXR R_IMF_ENUM_HDR R_IMF_ENUM_TIFF R_IMF_ENUM_WEBP
#ifdef RNA_RUNTIME
static const EnumPropertyItem image_only_type_items[] = {
@@ -359,11 +368,11 @@ static const EnumPropertyItem image_only_type_items[] = {
#endif
const EnumPropertyItem rna_enum_image_type_items[] = {
- {0, "", 0, N_("Image"), NULL},
+ RNA_ENUM_ITEM_HEADING(N_("Image"), NULL),
IMAGE_TYPE_ITEMS_IMAGE_ONLY
- {0, "", 0, N_("Movie"), NULL},
+ RNA_ENUM_ITEM_HEADING(N_("Movie"), NULL),
{R_IMF_IMTYPE_AVIJPEG,
"AVI_JPEG",
ICON_FILE_MOVIE,
@@ -447,8 +456,8 @@ const EnumPropertyItem rna_enum_bake_target_items[] = {
{R_BAKE_TARGET_VERTEX_COLORS,
"VERTEX_COLORS",
0,
- "Color Attributes",
- "Bake to active color attribute layer on meshes"},
+ "Active Color Attribute",
+ "Bake to the active color attribute on meshes"},
{0, NULL, 0, NULL, NULL},
};
@@ -2712,6 +2721,23 @@ static char *rna_FFmpegSettings_path(const PointerRNA *UNUSED(ptr))
return BLI_strdup("render.ffmpeg");
}
+# ifdef WITH_FFMPEG
+/* FFMpeg Codec setting update hook. */
+static void rna_FFmpegSettings_codec_update(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+ FFMpegCodecData *codec_data = (FFMpegCodecData *)ptr->data;
+ if (!ELEM(codec_data->codec, AV_CODEC_ID_H264, AV_CODEC_ID_MPEG4, AV_CODEC_ID_VP9)) {
+ /* Constant Rate Factor (CRF) setting is only available for H264,
+ * MPEG4 and WEBM/VP9 codecs. So changing encoder quality mode to
+ * CBR as CRF is not supported.
+ */
+ codec_data->constant_rate_factor = FFM_CRF_NONE;
+ }
+}
+# endif
+
#else
/* Grease Pencil Interpolation tool settings */
@@ -3284,6 +3310,21 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Snap Element", "Type of element to snap to");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ prop = RNA_def_property(srna, "snap_face_nearest_steps", PROP_INT, PROP_FACTOR);
+ RNA_def_property_int_sdna(prop, NULL, "snap_face_nearest_steps");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(
+ prop,
+ "Face Nearest Steps",
+ "Number of steps to break transformation into for face nearest snapping");
+
+ prop = RNA_def_property(srna, "use_snap_to_same_target", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_KEEP_ON_SAME_OBJECT);
+ RNA_def_property_ui_text(
+ prop,
+ "Snap to Same Target",
+ "Snap only to target that source was initially near (Face Nearest Only)");
+
/* node editor uses own set of snap modes */
prop = RNA_def_property(srna, "snap_node_element", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "snap_node_mode");
@@ -3306,9 +3347,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Absolute grid alignment while translating (based on the pivot center)");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ /* TODO(@gfxcoder): Rename `snap_target` to `snap_source` to avoid previous ambiguity of "target"
+ * (now, "source" is geometry to be moved and "target" is geometry to which moved geometry is
+ * snapped). */
prop = RNA_def_property(srna, "snap_target", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "snap_target");
- RNA_def_property_enum_items(prop, rna_enum_snap_target_items);
+ RNA_def_property_enum_items(prop, rna_enum_snap_source_items);
RNA_def_property_ui_text(prop, "Snap Target", "Which part to snap onto the target");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
@@ -3330,9 +3374,30 @@ static void rna_def_tool_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Backface Culling", "Exclude back facing geometry from snapping");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ /* TODO(@gfxcoder): Rename `use_snap_self` to `use_snap_active`, because active is correct but
+ * self is not (breaks API). This only makes a difference when more than one mesh is edited. */
prop = RNA_def_property(srna, "use_snap_self", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "snap_flag", SCE_SNAP_NO_SELF);
- RNA_def_property_ui_text(prop, "Project onto Self", "Snap onto itself (Edit Mode Only)");
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "snap_flag", SCE_SNAP_NOT_TO_ACTIVE);
+ RNA_def_property_ui_text(
+ prop, "Snap onto Active", "Snap onto itself only if enabled (Edit Mode Only)");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "use_snap_edit", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_TO_INCLUDE_EDITED);
+ RNA_def_property_ui_text(
+ prop, "Snap onto Edited", "Snap onto non-active objects in Edit Mode (Edit Mode Only)");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "use_snap_nonedit", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_TO_INCLUDE_NONEDITED);
+ RNA_def_property_ui_text(
+ prop, "Snap onto Non-edited", "Snap onto objects not in Edit Mode (Edit Mode Only)");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
+ prop = RNA_def_property(srna, "use_snap_selectable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_TO_ONLY_SELECTABLE);
+ RNA_def_property_ui_text(
+ prop, "Snap onto Selectable Only", "Snap only onto objects that are selectable");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
prop = RNA_def_property(srna, "use_snap_translate", PROP_BOOLEAN, PROP_NONE);
@@ -5919,6 +5984,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
RNA_def_property_enum_items(prop, ffmpeg_codec_items);
RNA_def_property_enum_default(prop, AV_CODEC_ID_H264);
RNA_def_property_ui_text(prop, "Video Codec", "FFmpeg codec to use for video output");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_FFmpegSettings_codec_update");
prop = RNA_def_property(srna, "video_bitrate", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "video_bitrate");
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index 200e1d65caf..3953fc66fc8 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -140,7 +140,7 @@ static void rna_Scene_ray_cast(Scene *scene,
depsgraph,
NULL,
&(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
+ .snap_target_select = SCE_SNAP_TARGET_ALL,
},
origin,
direction,
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index ab5e4c2f0d5..2e1fa8db7fe 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -774,6 +774,20 @@ static void rna_def_sculpt(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
+ static const EnumPropertyItem sculpt_transform_mode_items[] = {
+ {SCULPT_TRANSFORM_MODE_ALL_VERTICES,
+ "ALL_VERTICES",
+ 0,
+ "All Vertices",
+ "Applies the transformation to all vertices in the mesh"},
+ {SCULPT_TRANSFORM_MODE_RADIUS_ELASTIC,
+ "RADIUS_ELASTIC",
+ 0,
+ "Elastic",
+ "Applies the transformation simulating elasticity using the radius of the cursor"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
StructRNA *srna;
PropertyRNA *prop;
@@ -912,6 +926,12 @@ static void rna_def_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Gravity", "Amount of gravity after each dab");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "transform_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, sculpt_transform_mode_items);
+ RNA_def_property_ui_text(
+ prop, "Transform Mode", "How the transformation is going to be applied to the target");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "gravity_object", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(
@@ -1283,6 +1303,7 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", PE_INTERPOLATE_ADDED);
RNA_def_property_ui_text(
prop, "Interpolate", "Interpolate new particles from the existing ones");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "default_key_count", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "totaddkey");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 5d583d3edcb..04037a64426 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -43,6 +43,7 @@
#include "SEQ_prefetch.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
+#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "SEQ_sound.h"
#include "SEQ_time.h"
@@ -240,7 +241,7 @@ static int rna_SequenceEditor_sequences_all_lookup_string(PointerRNA *ptr,
ID *id = ptr->owner_id;
Scene *scene = (Scene *)id;
- Sequence *seq = SEQ_sequence_lookup_by_name(scene, key);
+ Sequence *seq = SEQ_sequence_lookup_seq_by_name(scene, key);
if (seq) {
RNA_pointer_create(ptr->owner_id, &RNA_Sequence, seq, r_ptr);
return true;
@@ -289,27 +290,12 @@ static void rna_Sequence_views_format_update(Main *bmain, Scene *scene, PointerR
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(scene, seqbase, seq);
-
- /* ensure effects are always fit in length to their input */
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq);
- /* TODO(sergey): probably could be optimized.
- * in terms skipping update of non-changing strips
- */
- for (tseq = seqbase->first; tseq; tseq = tseq->next) {
- if (tseq->seq1 || tseq->seq2 || tseq->seq3) {
- SEQ_time_update_sequence(scene, seqbase, tseq);
- }
+ if (SEQ_transform_test_overlap(scene, seqbase, seq)) {
+ SEQ_transform_seqbase_shuffle(seqbase, seq, scene);
}
- if (SEQ_transform_test_overlap(seqbase, seq)) {
- SEQ_transform_seqbase_shuffle(seqbase, seq, scene); /* XXX: BROKEN!, uses context seqbasep. */
- }
- SEQ_sort(seqbase);
-
if (seq->type == SEQ_TYPE_SOUND_RAM) {
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
}
@@ -326,39 +312,51 @@ static void rna_Sequence_frame_change_update(Main *UNUSED(bmain),
do_sequence_frame_change_update(scene, (Sequence *)ptr->data);
}
-static void rna_Sequence_start_frame_set(PointerRNA *ptr, int value)
+static int rna_Sequence_frame_final_start_get(PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->owner_id;
+ return SEQ_time_left_handle_frame_get(scene, (Sequence *)ptr->data);
+}
+
+static int rna_Sequence_frame_final_end_get(PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->owner_id;
+ return SEQ_time_right_handle_frame_get(scene, (Sequence *)ptr->data);
+}
+
+static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, float value)
{
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- SEQ_transform_translate_sequence(scene, seq, value - seq->start);
+ SEQ_time_left_handle_frame_set(scene, seq, value);
+ SEQ_transform_fix_single_image_seq_offsets(scene, seq);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
-static void rna_Sequence_start_frame_final_set(PointerRNA *ptr, int value)
+static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value)
{
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- SEQ_time_left_handle_frame_set(seq, value);
- SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_time_right_handle_frame_set(scene, seq, value);
+ SEQ_transform_fix_single_image_seq_offsets(scene, seq);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
-static void rna_Sequence_end_frame_final_set(PointerRNA *ptr, int value)
+static void rna_Sequence_start_frame_set(PointerRNA *ptr, int value)
{
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- SEQ_time_right_handle_frame_set(seq, value);
- SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_transform_translate_sequence(scene, seq, value - seq->start);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
-static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, int value)
+static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, float value)
{
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
@@ -367,7 +365,7 @@ static void rna_Sequence_frame_offset_start_set(PointerRNA *ptr, int value)
seq->startofs = value;
}
-static void rna_Sequence_frame_offset_end_set(PointerRNA *ptr, int value)
+static void rna_Sequence_frame_offset_end_set(PointerRNA *ptr, float value)
{
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
@@ -417,7 +415,7 @@ static void rna_Sequence_anim_startofs_final_range(
}
static void rna_Sequence_frame_offset_start_range(
- PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+ PointerRNA *ptr, float *min, float *max, float *UNUSED(softmin), float *UNUSED(softmax))
{
Sequence *seq = (Sequence *)ptr->data;
*min = ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) ? 0 : INT_MIN;
@@ -425,7 +423,7 @@ static void rna_Sequence_frame_offset_start_range(
}
static void rna_Sequence_frame_offset_end_range(
- PointerRNA *ptr, int *min, int *max, int *UNUSED(softmin), int *UNUSED(softmax))
+ PointerRNA *ptr, float *min, float *max, float *UNUSED(softmin), float *UNUSED(softmax))
{
Sequence *seq = (Sequence *)ptr->data;
*min = ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) ? 0 : INT_MIN;
@@ -437,7 +435,7 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value)
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- SEQ_time_right_handle_frame_set(seq, SEQ_time_left_handle_frame_get(seq) + value);
+ SEQ_time_right_handle_frame_set(scene, seq, SEQ_time_left_handle_frame_get(scene, seq) + value);
do_sequence_frame_change_update(scene, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
@@ -445,7 +443,8 @@ static void rna_Sequence_frame_length_set(PointerRNA *ptr, int value)
static int rna_Sequence_frame_length_get(PointerRNA *ptr)
{
Sequence *seq = (Sequence *)ptr->data;
- return SEQ_time_right_handle_frame_get(seq) - SEQ_time_left_handle_frame_get(seq);
+ Scene *scene = (Scene *)ptr->owner_id;
+ return SEQ_time_right_handle_frame_get(scene, seq) - SEQ_time_left_handle_frame_get(scene, seq);
}
static int rna_Sequence_frame_editable(PointerRNA *ptr, const char **UNUSED(r_info))
@@ -459,18 +458,15 @@ static void rna_Sequence_channel_set(PointerRNA *ptr, int value)
{
Sequence *seq = (Sequence *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq);
/* check channel increment or decrement */
const int channel_delta = (value >= seq->machine) ? 1 : -1;
seq->machine = value;
- if (SEQ_transform_test_overlap(seqbase, seq)) {
- /* XXX: BROKEN!, uses context seqbasep. */
+ if (SEQ_transform_test_overlap(scene, seqbase, seq)) {
SEQ_transform_seqbase_shuffle_ex(seqbase, seq, scene, channel_delta);
}
- SEQ_sort(seqbase);
SEQ_relations_invalidate_cache_composite(scene, seq);
}
@@ -722,8 +718,6 @@ 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;
@@ -731,7 +725,6 @@ static bool rna_MovieSequence_reload_if_needed(ID *scene_id, Sequence *seq, Main
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, seqbase, seq);
SEQ_relations_invalidate_cache_raw(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -825,7 +818,20 @@ static int rna_Sequence_proxy_filepath_length(PointerRNA *ptr)
static void rna_Sequence_audio_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- DEG_id_tag_update(ptr->owner_id, ID_RECALC_SEQUENCER_STRIPS);
+ DEG_id_tag_update(ptr->owner_id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO);
+}
+
+static void rna_Sequence_speed_factor_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ SEQ_cache_cleanup(scene);
+ rna_Sequence_audio_update(bmain, scene, ptr);
+}
+
+static void rna_Sequence_speed_factor_set(PointerRNA *ptr, float value)
+{
+ Sequence *seq = (Sequence *)ptr->data;
+ Scene *scene = (Scene *)ptr->owner_id;
+ SEQ_time_speed_factor_set(scene, seq, value);
}
static void rna_Sequence_pan_range(
@@ -919,9 +925,6 @@ 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);
- 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);
}
@@ -1131,6 +1134,26 @@ static void rna_SequenceEditor_overlay_frame_set(PointerRNA *ptr, int value)
}
}
+static void rna_SequenceEditor_display_stack(ID *id,
+ Editing *ed,
+ ReportList *reports,
+ Sequence *seqm)
+{
+ /* Check for non-meta sequence */
+ if (seqm != NULL && seqm->type != SEQ_TYPE_META && SEQ_exists_in_seqbase(seqm, &ed->seqbase)) {
+ BKE_report(reports, RPT_ERROR, "Sequence type must be 'META'");
+ return;
+ }
+
+ /* Get editing base of meta sequence */
+ Scene *scene = (Scene *)id;
+ SEQ_meta_stack_set(scene, seqm);
+ /* De-activate strip. This is to prevent strip from different timeline being drawn. */
+ SEQ_select_active_set(scene, NULL);
+
+ WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
+}
+
static bool modifier_seq_cmp_fn(Sequence *seq, void *arg_pt)
{
SequenceSearchData *data = arg_pt;
@@ -1337,8 +1360,7 @@ 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 *seqbase = SEQ_get_seqbase_by_seq(scene, seqm);
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqm->seqbase) {
SEQ_edit_move_strip_to_seqbase(scene, &seqm->seqbase, seq, seqbase);
@@ -1779,33 +1801,33 @@ static void rna_def_strip_color_balance(BlenderRNA *brna)
static const EnumPropertyItem blend_mode_items[] = {
{SEQ_BLEND_REPLACE, "REPLACE", 0, "Replace", ""},
{SEQ_TYPE_CROSS, "CROSS", 0, "Cross", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_DARKEN, "DARKEN", 0, "Darken", ""},
{SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
{SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""},
{SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
{SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
{SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""},
{SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
{SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""},
{SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""},
{SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
{SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
{SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
{SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_HUE, "HUE", 0, "Hue", ""},
{SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""},
{SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
{SEQ_TYPE_VALUE, "VALUE", 0, "Value", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", ""},
{SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", ""},
{SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""},
@@ -1963,11 +1985,12 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Length", "The length of the contents of this strip before the handles are applied");
- prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME);
- RNA_def_property_int_sdna(prop, NULL, "start");
+ prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_float_sdna(prop, NULL, "start");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Start Frame", "X position where the strip begins");
- RNA_def_property_int_funcs(
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 3, 0);
+ RNA_def_property_float_funcs(
prop, NULL, "rna_Sequence_start_frame_set", NULL); /* overlap tests and calc_seq_disp */
RNA_def_property_editable_func(prop, "rna_Sequence_frame_editable");
RNA_def_property_update(
@@ -1975,6 +1998,9 @@ static void rna_def_sequence(BlenderRNA *brna)
prop = RNA_def_property(srna, "frame_final_start", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "startdisp");
+ RNA_def_property_int_funcs(
+ prop, "rna_Sequence_frame_final_start_get", "rna_Sequence_start_frame_final_set", NULL);
+ RNA_def_property_editable_func(prop, "rna_Sequence_frame_editable");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop,
@@ -1982,35 +2008,36 @@ static void rna_def_sequence(BlenderRNA *brna)
"Start frame displayed in the sequence editor after offsets are applied, setting this is "
"equivalent to moving the handle, not the actual start frame");
/* overlap tests and calc_seq_disp */
- RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_start_frame_final_set", NULL);
- RNA_def_property_editable_func(prop, "rna_Sequence_frame_editable");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "frame_final_end", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "enddisp");
+ RNA_def_property_int_funcs(
+ prop, "rna_Sequence_frame_final_end_get", "rna_Sequence_end_frame_final_set", NULL);
+ RNA_def_property_editable_func(prop, "rna_Sequence_frame_editable");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
prop, "End Frame", "End frame displayed in the sequence editor after offsets are applied");
/* overlap tests and calc_seq_disp */
- RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_end_frame_final_set", NULL);
- RNA_def_property_editable_func(prop, "rna_Sequence_frame_editable");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
- prop = RNA_def_property(srna, "frame_offset_start", PROP_INT, PROP_TIME);
- RNA_def_property_int_sdna(prop, NULL, "startofs");
+ prop = RNA_def_property(srna, "frame_offset_start", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_float_sdna(prop, NULL, "startofs");
// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
RNA_def_property_ui_text(prop, "Start Offset", "");
- RNA_def_property_int_funcs(
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 3, 0);
+ RNA_def_property_float_funcs(
prop, NULL, "rna_Sequence_frame_offset_start_set", "rna_Sequence_frame_offset_start_range");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
- prop = RNA_def_property(srna, "frame_offset_end", PROP_INT, PROP_TIME);
- RNA_def_property_int_sdna(prop, NULL, "endofs");
+ prop = RNA_def_property(srna, "frame_offset_end", PROP_FLOAT, PROP_TIME);
+ RNA_def_property_float_sdna(prop, NULL, "endofs");
// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
RNA_def_property_ui_text(prop, "End Offset", "");
- RNA_def_property_int_funcs(
+ RNA_def_property_ui_range(prop, MINFRAME, MAXFRAME, 3, 0);
+ RNA_def_property_float_funcs(
prop, NULL, "rna_Sequence_frame_offset_end_set", "rna_Sequence_frame_offset_end_range");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
@@ -2141,6 +2168,8 @@ static void rna_def_channel(BlenderRNA *brna)
static void rna_def_editor(BlenderRNA *brna)
{
StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
PropertyRNA *prop;
static const EnumPropertyItem editing_storage_items[] = {
@@ -2284,6 +2313,28 @@ static void rna_def_editor(BlenderRNA *brna)
"Prefetch Frames",
"Render frames ahead of current frame in the background for faster playback");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
+
+ /* functions */
+
+ func = RNA_def_function(srna, "display_stack", "rna_SequenceEditor_display_stack");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Display sequences stack");
+ parm = RNA_def_pointer(
+ func, "meta_sequence", "Sequence", "Meta Sequence", "Meta to display its stack");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+}
+
+static void rna_def_speed_factor(StructRNA *srna)
+{
+ PropertyRNA *prop = RNA_def_property(srna, "speed_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "speed_factor");
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_range(prop, 0.1f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 1.0f, 100.0f, 10.0, 3);
+ RNA_def_property_ui_text(prop, "Speed Factor", "Multiply playback speed");
+ RNA_def_property_float_funcs(
+ prop, NULL, "rna_Sequence_speed_factor_set", NULL); /* overlap test */
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_speed_factor_update");
}
static void rna_def_filter_video(StructRNA *srna)
@@ -2518,6 +2569,7 @@ static void rna_def_image(BlenderRNA *brna)
rna_def_proxy(srna);
rna_def_input(srna);
rna_def_color_management(srna);
+ rna_def_speed_factor(srna);
}
static void rna_def_meta(BlenderRNA *brna)
@@ -2549,6 +2601,7 @@ static void rna_def_meta(BlenderRNA *brna)
rna_def_filter_video(srna);
rna_def_proxy(srna);
rna_def_input(srna);
+ rna_def_speed_factor(srna);
}
static void rna_def_scene(BlenderRNA *brna)
@@ -2597,6 +2650,7 @@ static void rna_def_scene(BlenderRNA *brna)
rna_def_proxy(srna);
rna_def_input(srna);
rna_def_movie_types(srna);
+ rna_def_speed_factor(srna);
}
static void rna_def_movie(BlenderRNA *brna)
@@ -2680,6 +2734,7 @@ static void rna_def_movie(BlenderRNA *brna)
rna_def_input(srna);
rna_def_color_management(srna);
rna_def_movie_types(srna);
+ rna_def_speed_factor(srna);
}
static void rna_def_movieclip(BlenderRNA *brna)
@@ -2707,6 +2762,7 @@ static void rna_def_movieclip(BlenderRNA *brna)
rna_def_filter_video(srna);
rna_def_input(srna);
rna_def_movie_types(srna);
+ rna_def_speed_factor(srna);
}
static void rna_def_mask(BlenderRNA *brna)
@@ -2725,6 +2781,7 @@ static void rna_def_mask(BlenderRNA *brna)
rna_def_filter_video(srna);
rna_def_input(srna);
+ rna_def_speed_factor(srna);
}
static void rna_def_sound(BlenderRNA *brna)
@@ -2751,13 +2808,6 @@ static void rna_def_sound(BlenderRNA *brna)
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_audio_update");
- prop = RNA_def_property(srna, "pitch", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "pitch");
- RNA_def_property_range(prop, 0.1f, 10.0f);
- RNA_def_property_ui_text(prop, "Pitch", "Playback pitch of the sound");
- RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND);
- RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_audio_update");
-
prop = RNA_def_property(srna, "pan", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "pan");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
@@ -2773,6 +2823,7 @@ static void rna_def_sound(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
rna_def_input(srna);
+ rna_def_speed_factor(srna);
}
static void rna_def_effect(BlenderRNA *brna)
@@ -3164,23 +3215,23 @@ static void rna_def_color_mix(StructRNA *srna)
{SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
{SEQ_TYPE_COLOR_BURN, "BURN", 0, "Color Burn", ""},
{SEQ_TYPE_LINEAR_BURN, "LINEAR_BURN", 0, "Linear Burn", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_LIGHTEN, "LIGHTEN", 0, "Lighten", ""},
{SEQ_TYPE_SCREEN, "SCREEN", 0, "Screen", ""},
{SEQ_TYPE_DODGE, "DODGE", 0, "Color Dodge", ""},
{SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{SEQ_TYPE_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
{SEQ_TYPE_HARD_LIGHT, "HARD_LIGHT", 0, "Hard Light", ""},
{SEQ_TYPE_VIVID_LIGHT, "VIVID_LIGHT", 0, "Vivid Light", ""},
{SEQ_TYPE_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
{SEQ_TYPE_PIN_LIGHT, "PIN_LIGHT", 0, "Pin Light", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_DIFFERENCE, "DIFFERENCE", 0, "Difference", ""},
{SEQ_TYPE_EXCLUSION, "EXCLUSION", 0, "Exclusion", ""},
{SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{SEQ_TYPE_HUE, "HUE", 0, "Hue", ""},
{SEQ_TYPE_SATURATION, "SATURATION", 0, "Saturation", ""},
{SEQ_TYPE_BLEND_COLOR, "COLOR", 0, "Color", ""},
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index 36bc50e73fb..aab6174cab2 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -49,27 +49,21 @@
# include "WM_api.h"
-static void rna_Sequence_update_rnafunc(ID *id, Sequence *self, bool do_data)
+static StripElem *rna_Sequence_strip_elem_from_frame(ID *id, Sequence *self, int timeline_frame)
{
Scene *scene = (Scene *)id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, self);
-
- if (do_data) {
- SEQ_time_update_recursive(scene, self);
- // new_tstripdata(self); /* need 2.6x version of this. */
- }
-
- SEQ_time_update_sequence(scene, seqbase, self);
+ return SEQ_render_give_stripelem(scene, self, timeline_frame);
}
-static void rna_Sequence_swap_internal(Sequence *seq_self,
+static void rna_Sequence_swap_internal(ID *id,
+ Sequence *seq_self,
ReportList *reports,
Sequence *seq_other)
{
const char *error_msg;
+ Scene *scene = (Scene *)id;
- if (SEQ_edit_sequence_swap(seq_self, seq_other, &error_msg) == 0) {
+ if (SEQ_edit_sequence_swap(scene, seq_self, seq_other, &error_msg) == 0) {
BKE_report(reports, RPT_ERROR, error_msg);
}
}
@@ -96,8 +90,7 @@ static Sequence *rna_Sequence_split(
ID *id, Sequence *seq, Main *bmain, ReportList *reports, int frame, int split_method)
{
Scene *scene = (Scene *)id;
- Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, seq);
const char *error_msg = NULL;
Sequence *r_seq = SEQ_edit_strip_split(
@@ -262,7 +255,7 @@ static Sequence *rna_Sequences_new_image(ID *id,
char dir[FILE_MAX], filename[FILE_MAX];
BLI_split_dirfile(file, dir, filename, sizeof(dir), sizeof(filename));
SEQ_add_image_set_directory(seq, dir);
- SEQ_add_image_load_file(seq, 0, filename);
+ SEQ_add_image_load_file(scene, seq, 0, filename);
SEQ_add_image_init_alpha_mode(seq);
DEG_relations_tag_update(bmain);
@@ -576,8 +569,6 @@ 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,
@@ -586,7 +577,6 @@ 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(scene, seqbase, seq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
return se;
@@ -595,8 +585,6 @@ 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) {
@@ -629,8 +617,6 @@ 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(scene, seqbase, seq);
-
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
@@ -669,12 +655,8 @@ void RNA_api_sequence_strip(StructRNA *srna)
{0, NULL, 0, NULL, NULL},
};
- func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc");
+ func = RNA_def_function(srna, "strip_elem_from_frame", "rna_Sequence_strip_elem_from_frame");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
- RNA_def_function_ui_description(func, "Update the strip dimensions");
- parm = RNA_def_boolean(func, "data", false, "Data", "Update strip data");
-
- func = RNA_def_function(srna, "strip_elem_from_frame", "SEQ_render_give_stripelem");
RNA_def_function_ui_description(func, "Return the strip element from a given frame or None");
parm = RNA_def_int(func,
"frame",
@@ -691,6 +673,7 @@ void RNA_api_sequence_strip(StructRNA *srna)
RNA_def_pointer(func, "elem", "SequenceElement", "", "strip element of the current frame"));
func = RNA_def_function(srna, "swap", "rna_Sequence_swap_internal");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID);
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "other", "Sequence", "Other", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c
index 2714b4157fd..e38481a845a 100644
--- a/source/blender/makesrna/intern/rna_sound.c
+++ b/source/blender/makesrna/intern/rna_sound.c
@@ -15,7 +15,7 @@
#include "BKE_sound.h"
/* Enumeration for Audio Channels, compatible with eSoundChannels */
-const EnumPropertyItem rna_enum_audio_channels_items[] = {
+static const EnumPropertyItem rna_enum_audio_channels_items[] = {
{SOUND_CHANNELS_INVALID, "INVALID", ICON_NONE, "Invalid", "Invalid"},
{SOUND_CHANNELS_MONO, "MONO", ICON_NONE, "Mono", "Mono"},
{SOUND_CHANNELS_STEREO, "STEREO", ICON_NONE, "Stereo", "Stereo"},
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 4b5802d70ab..14522eaa54a 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -87,8 +87,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
/* empty must be here for python, is skipped for UI */
{SPACE_EMPTY, "EMPTY", ICON_NONE, "Empty", ""},
- /* General */
- {0, "", ICON_NONE, "General", ""},
+ /* General. */
+ RNA_ENUM_ITEM_HEADING("General", NULL),
{SPACE_VIEW3D,
"VIEW_3D",
ICON_VIEW3D,
@@ -107,8 +107,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
{SPACE_SEQ, "SEQUENCE_EDITOR", ICON_SEQUENCE, "Video Sequencer", "Video editing tools"},
{SPACE_CLIP, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", "Motion tracking tools"},
- /* Animation */
- {0, "", ICON_NONE, "Animation", ""},
+ /* Animation. */
+ RNA_ENUM_ITEM_HEADING("Animation", NULL),
#if 0
{SPACE_ACTION,
"TIMELINE",
@@ -124,8 +124,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
"Edit drivers and keyframe interpolation"},
{SPACE_NLA, "NLA_EDITOR", ICON_NLA, "Nonlinear Animation", "Combine and layer Actions"},
- /* Scripting */
- {0, "", ICON_NONE, "Scripting", ""},
+ /* Scripting. */
+ RNA_ENUM_ITEM_HEADING("Scripting", NULL),
{SPACE_TEXT,
"TEXT_EDITOR",
ICON_TEXT,
@@ -152,8 +152,8 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
"Global bar at the bottom of the "
"screen for general status information"},
- /* Data */
- {0, "", ICON_NONE, "Data", ""},
+ /* Data. */
+ RNA_ENUM_ITEM_HEADING("Data", NULL),
{SPACE_OUTLINER,
"OUTLINER",
ICON_OUTLINER,
@@ -440,28 +440,28 @@ static const EnumPropertyItem rna_enum_studio_light_items[] = {
};
static const EnumPropertyItem rna_enum_view3dshading_render_pass_type_items[] = {
- {0, "", ICON_NONE, "General", ""},
+ RNA_ENUM_ITEM_HEADING("General", NULL),
{EEVEE_RENDER_PASS_COMBINED, "COMBINED", 0, "Combined", ""},
{EEVEE_RENDER_PASS_EMIT, "EMISSION", 0, "Emission", ""},
{EEVEE_RENDER_PASS_ENVIRONMENT, "ENVIRONMENT", 0, "Environment", ""},
{EEVEE_RENDER_PASS_AO, "AO", 0, "Ambient Occlusion", ""},
{EEVEE_RENDER_PASS_SHADOW, "SHADOW", 0, "Shadow", ""},
- {0, "", ICON_NONE, "Light", ""},
+ RNA_ENUM_ITEM_HEADING("Light", NULL),
{EEVEE_RENDER_PASS_DIFFUSE_LIGHT, "DIFFUSE_LIGHT", 0, "Diffuse Light", ""},
{EEVEE_RENDER_PASS_DIFFUSE_COLOR, "DIFFUSE_COLOR", 0, "Diffuse Color", ""},
{EEVEE_RENDER_PASS_SPECULAR_LIGHT, "SPECULAR_LIGHT", 0, "Specular Light", ""},
{EEVEE_RENDER_PASS_SPECULAR_COLOR, "SPECULAR_COLOR", 0, "Specular Color", ""},
{EEVEE_RENDER_PASS_VOLUME_LIGHT, "VOLUME_LIGHT", 0, "Volume Light", ""},
- {0, "", ICON_NONE, "Effects", ""},
+ RNA_ENUM_ITEM_HEADING("Effects", NULL),
{EEVEE_RENDER_PASS_BLOOM, "BLOOM", 0, "Bloom", ""},
- {0, "", ICON_NONE, "Data", ""},
+ RNA_ENUM_ITEM_HEADING("Data", NULL),
{EEVEE_RENDER_PASS_NORMAL, "NORMAL", 0, "Normal", ""},
{EEVEE_RENDER_PASS_MIST, "MIST", 0, "Mist", ""},
- {0, "", ICON_NONE, "Shader AOV", ""},
+ RNA_ENUM_ITEM_HEADING("Shader AOV", NULL),
{EEVEE_RENDER_PASS_AOV, "AOV", 0, "AOV", ""},
{0, NULL, 0, NULL, NULL},
@@ -3526,9 +3526,9 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m
RNA_def_property_ui_text(prop, "Edge Display Type", "Display type for mask splines");
RNA_def_property_update(prop, noteflag, NULL);
- prop = RNA_def_property(srna, "show_mask_smooth", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_SMOOTH);
- RNA_def_property_ui_text(prop, "Display Smooth Splines", "");
+ prop = RNA_def_property(srna, "show_mask_spline", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mask_info.draw_flag", MASK_DRAWFLAG_SPLINE);
+ RNA_def_property_ui_text(prop, "Show Mask Spline", "");
RNA_def_property_update(prop, noteflag, NULL);
prop = RNA_def_property(srna, "show_mask_overlay", PROP_BOOLEAN, PROP_NONE);
@@ -3541,6 +3541,13 @@ static void rna_def_space_mask_info(StructRNA *srna, int noteflag, const char *m
RNA_def_property_enum_items(prop, overlay_mode_items);
RNA_def_property_ui_text(prop, "Overlay Mode", "Overlay mode of rasterized mask");
RNA_def_property_update(prop, noteflag, NULL);
+
+ prop = RNA_def_property(srna, "blend_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "mask_info.blend_factor");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0, 1., 0.1, 1);
+ RNA_def_property_ui_text(prop, "Blending Factor", "Overlay blending factor of rasterized mask");
+ RNA_def_property_update(prop, noteflag, NULL);
}
static void rna_def_space_image_uv(BlenderRNA *brna)
@@ -5339,6 +5346,7 @@ static void rna_def_space_image_overlay(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_overlays", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SI_OVERLAY_SHOW_OVERLAYS);
RNA_def_property_ui_text(prop, "Show Overlays", "Display overlays like UV Maps and Metadata");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
prop = RNA_def_property(srna, "show_grid_background", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SI_OVERLAY_SHOW_GRID_BACKGROUND);
@@ -6625,7 +6633,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna)
static const EnumPropertyItem display_size_items[] = {
{64, "TINY", 0, "Tiny", ""},
{96, "SMALL", 0, "Small", ""},
- {128, "NORMAL", 0, "Regular", ""},
+ {128, "NORMAL", 0, "Medium", ""},
{192, "LARGE", 0, "Large", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -7846,12 +7854,6 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Color Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
- prop = RNA_def_property(srna, "value_byte_color", PROP_INT, PROP_NONE);
- RNA_def_property_array(prop, 4);
- RNA_def_property_range(prop, 0, 255);
- RNA_def_property_ui_text(prop, "Byte Color Value", "");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
-
prop = RNA_def_property(srna, "value_string", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Text Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
@@ -7866,6 +7868,12 @@ static void rna_def_spreadsheet_row_filter(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Integer Value", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+ prop = RNA_def_property(srna, "value_int8", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "value_int");
+ RNA_def_property_range(prop, -128, 127);
+ RNA_def_property_ui_text(prop, "8-Bit Integer Value", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
+
prop = RNA_def_property(srna, "value_boolean", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_ROW_FILTER_BOOL_VALUE);
RNA_def_property_ui_text(prop, "Boolean Value", "");
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index eff7c0ca136..3b28dc70e9e 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -98,22 +98,22 @@ const EnumPropertyItem rna_enum_texture_type_items[] = {
#ifndef RNA_RUNTIME
static const EnumPropertyItem blend_type_items[] = {
{MTEX_BLEND, "MIX", 0, "Mix", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_DARK, "DARKEN", 0, "Darken", ""},
{MTEX_MUL, "MULTIPLY", 0, "Multiply", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_LIGHT, "LIGHTEN", 0, "Lighten", ""},
{MTEX_SCREEN, "SCREEN", 0, "Screen", ""},
{MTEX_ADD, "ADD", 0, "Add", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_OVERLAY, "OVERLAY", 0, "Overlay", ""},
{MTEX_SOFT_LIGHT, "SOFT_LIGHT", 0, "Soft Light", ""},
{MTEX_LIN_LIGHT, "LINEAR_LIGHT", 0, "Linear Light", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_DIFF, "DIFFERENCE", 0, "Difference", ""},
{MTEX_SUB, "SUBTRACT", 0, "Subtract", ""},
{MTEX_DIV, "DIVIDE", 0, "Divide", ""},
- {0, "", ICON_NONE, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MTEX_BLEND_HUE, "HUE", 0, "Hue", ""},
{MTEX_BLEND_SAT, "SATURATION", 0, "Saturation", ""},
{MTEX_BLEND_COLOR, "COLOR", 0, "Color", ""},
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 1d0723851ad..dabb89bcd5e 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -393,7 +393,14 @@ static StructRNA *rna_Panel_register(Main *bmain,
if (parent) {
pt->parent = parent;
- BLI_addtail(&parent->children, BLI_genericNodeN(pt));
+ LinkData *pt_child_iter = parent->children.last;
+ for (; pt_child_iter; pt_child_iter = pt_child_iter->prev) {
+ PanelType *pt_child = pt_child_iter->data;
+ if (pt_child->order <= pt->order) {
+ break;
+ }
+ }
+ BLI_insertlinkafter(&parent->children, pt_child_iter, BLI_genericNodeN(pt));
}
{
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 47c6d2bda64..13806756a2d 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -38,23 +38,6 @@
#include "BLT_lang.h"
-#ifdef WITH_OPENSUBDIV
-static const EnumPropertyItem opensubdiv_compute_type_items[] = {
- {USER_OPENSUBDIV_COMPUTE_NONE, "NONE", 0, "None", ""},
- {USER_OPENSUBDIV_COMPUTE_CPU, "CPU", 0, "CPU", ""},
- {USER_OPENSUBDIV_COMPUTE_OPENMP, "OPENMP", 0, "OpenMP", ""},
- {USER_OPENSUBDIV_COMPUTE_OPENCL, "OPENCL", 0, "OpenCL", ""},
- {USER_OPENSUBDIV_COMPUTE_CUDA, "CUDA", 0, "CUDA", ""},
- {USER_OPENSUBDIV_COMPUTE_GLSL_TRANSFORM_FEEDBACK,
- "GLSL_TRANSFORM_FEEDBACK",
- 0,
- "GLSL Transform Feedback",
- ""},
- {USER_OPENSUBDIV_COMPUTE_GLSL_COMPUTE, "GLSL_COMPUTE", 0, "GLSL Compute", ""},
- {0, NULL, 0, NULL, NULL},
-};
-#endif
-
const EnumPropertyItem rna_enum_preference_section_items[] = {
{USER_SECTION_INTERFACE, "INTERFACE", 0, "Interface", ""},
{USER_SECTION_THEME, "THEMES", 0, "Themes", ""},
@@ -62,23 +45,23 @@ const EnumPropertyItem rna_enum_preference_section_items[] = {
{USER_SECTION_LIGHT, "LIGHTS", 0, "Lights", ""},
{USER_SECTION_EDITING, "EDITING", 0, "Editing", ""},
{USER_SECTION_ANIMATION, "ANIMATION", 0, "Animation", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_ADDONS, "ADDONS", 0, "Add-ons", ""},
#if 0 /* def WITH_USERDEF_WORKSPACES */
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_WORKSPACE_CONFIG, "WORKSPACE_CONFIG", 0, "Configuration File", ""},
{USER_SECTION_WORKSPACE_ADDONS, "WORKSPACE_ADDONS", 0, "Add-on Overrides", ""},
{USER_SECTION_WORKSPACE_KEYMAPS, "WORKSPACE_KEYMAPS", 0, "Keymap Overrides", ""},
#endif
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_INPUT, "INPUT", 0, "Input", ""},
{USER_SECTION_NAVIGATION, "NAVIGATION", 0, "Navigation", ""},
{USER_SECTION_KEYMAP, "KEYMAP", 0, "Keymap", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""},
{USER_SECTION_SAVE_LOAD, "SAVE_LOAD", 0, "Save & Load", ""},
{USER_SECTION_FILE_PATHS, "FILE_PATHS", 0, "File Paths", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{USER_SECTION_EXPERIMENTAL, "EXPERIMENTAL", 0, "Experimental", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -189,10 +172,6 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "UI_interface.h"
-# ifdef WITH_OPENSUBDIV
-# include "opensubdiv_capi.h"
-# endif
-
# ifdef WITH_SDL_DYNLOAD
# include "sdlew.h"
# endif
@@ -728,55 +707,6 @@ static PointerRNA rna_Theme_space_list_generic_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_ThemeSpaceListGeneric, ptr->data);
}
-# ifdef WITH_OPENSUBDIV
-static const EnumPropertyItem *rna_userdef_opensubdiv_compute_type_itemf(bContext *UNUSED(C),
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
-{
- EnumPropertyItem *item = NULL;
- int totitem = 0;
- int evaluators = openSubdiv_getAvailableEvaluators();
-
- RNA_enum_items_add_value(
- &item, &totitem, opensubdiv_compute_type_items, USER_OPENSUBDIV_COMPUTE_NONE);
-
-# define APPEND_COMPUTE(compute) \
- if (evaluators & OPENSUBDIV_EVALUATOR_##compute) { \
- RNA_enum_items_add_value( \
- &item, &totitem, opensubdiv_compute_type_items, USER_OPENSUBDIV_COMPUTE_##compute); \
- } \
- ((void)0)
-
- APPEND_COMPUTE(CPU);
- APPEND_COMPUTE(OPENMP);
- APPEND_COMPUTE(OPENCL);
- APPEND_COMPUTE(CUDA);
- APPEND_COMPUTE(GLSL_TRANSFORM_FEEDBACK);
- APPEND_COMPUTE(GLSL_COMPUTE);
-
-# undef APPEND_COMPUTE
-
- RNA_enum_item_end(&item, &totitem);
- *r_free = true;
-
- return item;
-}
-
-static void rna_userdef_opensubdiv_update(Main *bmain,
- Scene *UNUSED(scene),
- PointerRNA *UNUSED(ptr))
-{
- Object *object;
-
- for (object = bmain->objects.first; object; object = object->id.next) {
- DEG_id_tag_update(&object->id, ID_RECALC_TRANSFORM);
- }
- USERDEF_TAG_DIRTY;
-}
-
-# endif
-
static const EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
@@ -1101,16 +1031,6 @@ int rna_show_statusbar_vram_editable(struct PointerRNA *UNUSED(ptr), const char
return GPU_mem_stats_supported() ? PROP_EDITABLE : 0;
}
-static int rna_userdef_experimental_use_new_curve_tools_editable(struct PointerRNA *UNUSED(ptr),
- const char **r_info)
-{
- if (U.experimental.use_new_curves_type) {
- return PROP_EDITABLE;
- }
- *r_info = "Only available when new curves type is enabled";
- return 0;
-}
-
#else
# define USERDEF_TAG_DIRTY_PROPERTY_UPDATE_ENABLE \
@@ -5738,17 +5658,6 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Audio Channels", "Audio channel count");
RNA_def_property_update(prop, 0, "rna_UserDef_audio_update");
-# ifdef WITH_OPENSUBDIV
- prop = RNA_def_property(srna, "opensubdiv_compute_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
- RNA_def_property_enum_sdna(prop, NULL, "opensubdiv_compute_type");
- RNA_def_property_enum_items(prop, opensubdiv_compute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_userdef_opensubdiv_compute_type_itemf");
- RNA_def_property_ui_text(
- prop, "OpenSubdiv Compute Type", "Type of computer back-end used with OpenSubdiv");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_userdef_opensubdiv_update");
-# endif
-
# ifdef WITH_CYCLES
prop = RNA_def_property(srna, "legacy_compute_device_type", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "compute_device_type");
@@ -6421,6 +6330,15 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
"Enable library overrides automatic resync detection and process on file load. Disable when "
"dealing with older .blend files that need manual Resync (Enforce) handling");
+ prop = RNA_def_property(srna, "use_override_new_fully_editable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_override_new_fully_editable", 1);
+ RNA_def_property_ui_text(
+ prop,
+ "Override New Fully Editable",
+ "Make all override of a hierarchy fully user-editable by default when creating a new "
+ "override (if that option is disabled, most overrides created as part of a hierarchy will "
+ "not be editable by the user by default)");
+
prop = RNA_def_property(srna, "use_new_point_cloud_type", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_new_point_cloud_type", 1);
RNA_def_property_ui_text(
@@ -6434,13 +6352,8 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
"reduces execution time and memory usage)");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "use_new_curves_type", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_new_curves_type", 1);
- RNA_def_property_ui_text(prop, "New Curves Type", "Enable the new curves data type in the UI");
-
prop = RNA_def_property(srna, "use_new_curves_tools", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_new_curves_tools", 1);
- RNA_def_property_editable_func(prop, "rna_userdef_experimental_use_new_curve_tools_editable");
RNA_def_property_ui_text(
prop, "New Curves Tools", "Enable additional features for the new curves data block");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index c80d0e2da39..2009f51e1f2 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -24,6 +24,7 @@
#include "rna_internal.h"
+#include "WM_api.h"
#include "WM_types.h"
#ifdef RNA_RUNTIME
@@ -36,16 +37,16 @@ static const EnumPropertyItem event_mouse_type_items[] = {
{BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5", ""},
{BUTTON6MOUSE, "BUTTON6MOUSE", 0, "Button6", ""},
{BUTTON7MOUSE, "BUTTON7MOUSE", 0, "Button7", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{TABLET_STYLUS, "PEN", 0, "Pen", ""},
{TABLET_ERASER, "ERASER", 0, "Eraser", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MOUSEMOVE, "MOUSEMOVE", 0, "Move", ""},
{MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", ""},
{MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", ""},
{MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", ""},
{MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""},
{WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""},
{WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", ""},
@@ -123,6 +124,24 @@ static const EnumPropertyItem event_ndof_type_items[] = {
};
#endif /* RNA_RUNTIME */
+/**
+ * Job types for use in the `bpy.app.is_job_running(job_type)` call.
+ *
+ * This is a subset of the `WM_JOB_TYPE_...` anonymous enum defined in `WM_api.h`. It is
+ * intentionally kept as a subset, such that by default how jobs are handled is kept as an
+ * "internal implementation detail" of Blender, rather than a public, reliable part of the API.
+ *
+ * This array can be expanded on a case-by-case basis, when there is a clear and testable use case.
+ */
+const EnumPropertyItem rna_enum_wm_job_type_items[] = {
+ {WM_JOB_TYPE_RENDER, "RENDER", 0, "Regular rendering", ""},
+ {WM_JOB_TYPE_RENDER_PREVIEW, "RENDER_PREVIEW", 0, "Rendering previews", ""},
+ {WM_JOB_TYPE_OBJECT_BAKE, "OBJECT_BAKE", 0, "Object Baking", ""},
+ {WM_JOB_TYPE_COMPOSITE, "COMPOSITE", 0, "Compositing", ""},
+ {WM_JOB_TYPE_SHADER_COMPILATION, "SHADER_COMPILATION", 0, "Shader compilation", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_event_type_items[] = {
/* - Note we abuse 'tooltip' message here to store a 'compact' form of some (too) long names.
* - Intentionally excluded: #CAPSLOCKKEY, #UNKNOWNKEY.
@@ -135,22 +154,22 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5 Mouse", "MB5"},
{BUTTON6MOUSE, "BUTTON6MOUSE", 0, "Button6 Mouse", "MB6"},
{BUTTON7MOUSE, "BUTTON7MOUSE", 0, "Button7 Mouse", "MB7"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{TABLET_STYLUS, "PEN", 0, "Pen", ""},
{TABLET_ERASER, "ERASER", 0, "Eraser", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{MOUSEMOVE, "MOUSEMOVE", 0, "Mouse Move", "MsMov"},
{INBETWEEN_MOUSEMOVE, "INBETWEEN_MOUSEMOVE", 0, "In-between Move", "MsSubMov"},
{MOUSEPAN, "TRACKPADPAN", 0, "Mouse/Trackpad Pan", "MsPan"},
{MOUSEZOOM, "TRACKPADZOOM", 0, "Mouse/Trackpad Zoom", "MsZoom"},
{MOUSEROTATE, "MOUSEROTATE", 0, "Mouse/Trackpad Rotate", "MsRot"},
{MOUSESMARTZOOM, "MOUSESMARTZOOM", 0, "Mouse/Trackpad Smart Zoom", "MsSmartZoom"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", "WhUp"},
{WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", "WhDown"},
{WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", "WhIn"},
{WHEELOUTMOUSE, "WHEELOUTMOUSE", 0, "Wheel Out", "WhOut"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_AKEY, "A", 0, "A", ""},
{EVT_BKEY, "B", 0, "B", ""},
{EVT_CKEY, "C", 0, "C", ""},
@@ -177,7 +196,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{EVT_XKEY, "X", 0, "X", ""},
{EVT_YKEY, "Y", 0, "Y", ""},
{EVT_ZKEY, "Z", 0, "Z", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_ZEROKEY, "ZERO", 0, "0", ""},
{EVT_ONEKEY, "ONE", 0, "1", ""},
{EVT_TWOKEY, "TWO", 0, "2", ""},
@@ -188,14 +207,14 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{EVT_SEVENKEY, "SEVEN", 0, "7", ""},
{EVT_EIGHTKEY, "EIGHT", 0, "8", ""},
{EVT_NINEKEY, "NINE", 0, "9", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_LEFTCTRLKEY, "LEFT_CTRL", 0, "Left Ctrl", "CtrlL"},
{EVT_LEFTALTKEY, "LEFT_ALT", 0, "Left Alt", "AltL"},
{EVT_LEFTSHIFTKEY, "LEFT_SHIFT", 0, "Left Shift", "ShiftL"},
{EVT_RIGHTALTKEY, "RIGHT_ALT", 0, "Right Alt", "AltR"},
{EVT_RIGHTCTRLKEY, "RIGHT_CTRL", 0, "Right Ctrl", "CtrlR"},
{EVT_RIGHTSHIFTKEY, "RIGHT_SHIFT", 0, "Right Shift", "ShiftR"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_OSKEY, "OSKEY", 0, "OS Key", "Cmd"},
{EVT_APPKEY, "APP", 0, "Application", "App"},
{EVT_GRLESSKEY, "GRLESS", 0, "Grless", ""},
@@ -268,14 +287,14 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{EVT_PAGEUPKEY, "PAGE_UP", 0, "Page Up", "PgUp"},
{EVT_PAGEDOWNKEY, "PAGE_DOWN", 0, "Page Down", "PgDown"},
{EVT_ENDKEY, "END", 0, "End", ""},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{EVT_MEDIAPLAY, "MEDIA_PLAY", 0, "Media Play/Pause", ">/||"},
{EVT_MEDIASTOP, "MEDIA_STOP", 0, "Media Stop", "Stop"},
{EVT_MEDIAFIRST, "MEDIA_FIRST", 0, "Media First", "|<<"},
{EVT_MEDIALAST, "MEDIA_LAST", 0, "Media Last", ">>|"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{KM_TEXTINPUT, "TEXTINPUT", 0, "Text Input", "TxtIn"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{WINDEACTIVATE, "WINDOW_DEACTIVATE", 0, "Window Deactivate", ""},
{TIMER, "TIMER", 0, "Timer", "Tmr"},
{TIMER0, "TIMER0", 0, "Timer 0", "Tmr0"},
@@ -285,7 +304,7 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
{TIMERAUTOSAVE, "TIMER_AUTOSAVE", 0, "Timer Autosave", "TmrSave"},
{TIMERREPORT, "TIMER_REPORT", 0, "Timer Report", "TmrReport"},
{TIMERREGION, "TIMERREGION", 0, "Timer Region", "TmrReg"},
- {0, "", 0, NULL, NULL},
+ RNA_ENUM_ITEM_SEPR,
{NDOF_MOTION, "NDOF_MOTION", 0, "NDOF Motion", "NdofMov"},
/* buttons on all 3dconnexion devices */
{NDOF_BUTTON_MENU, "NDOF_BUTTON_MENU", 0, "NDOF Menu", "NdofMenu"},
@@ -588,14 +607,14 @@ static PointerRNA rna_OperatorMacro_properties_get(PointerRNA *ptr)
static void rna_Event_ascii_get(PointerRNA *ptr, char *value)
{
const wmEvent *event = ptr->data;
- value[0] = event->ascii;
+ value[0] = WM_event_utf8_to_ascii(event);
value[1] = '\0';
}
static int rna_Event_ascii_length(PointerRNA *ptr)
{
const wmEvent *event = ptr->data;
- return (event->ascii) ? 1 : 0;
+ return WM_event_utf8_to_ascii(event) ? 1 : 0;
}
static void rna_Event_unicode_get(PointerRNA *ptr, char *value)
@@ -898,7 +917,7 @@ static void rna_wmKeyMapItem_map_type_set(PointerRNA *ptr, int value)
/**
* Assumes value to be an enum from rna_enum_event_type_items.
- * Function makes sure keymodifiers are only valid keys, ESC keeps it unaltered.
+ * Function makes sure key-modifiers are only valid keys, ESC keeps it unaltered.
*/
static void rna_wmKeyMapItem_keymodifier_set(PointerRNA *ptr, int value)
{
@@ -2047,6 +2066,12 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Value", "The type of event, only applies to some");
+ prop = RNA_def_property(srna, "value_prev", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "prev_val");
+ RNA_def_property_enum_items(prop, rna_enum_event_value_items);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Previous Value", "The type of event, only applies to some");
+
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, rna_enum_event_type_items);
@@ -2054,6 +2079,13 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Type", "");
+ prop = RNA_def_property(srna, "type_prev", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "prev_type");
+ RNA_def_property_enum_items(prop, rna_enum_event_type_items);
+ RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Previous Type", "");
+
prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "direction");
RNA_def_property_enum_items(prop, rna_enum_event_direction_items);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 5da65510399..eb5e2549b1d 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -23,6 +23,7 @@
#include "wm_cursors.h"
#include "wm_event_types.h"
+#include "WM_api.h"
#include "WM_types.h"
#include "rna_internal.h" /* own include */
@@ -638,16 +639,12 @@ static wmEvent *rna_Window_event_add_simulate(wmWindow *win,
}
/* TODO: validate NDOF. */
- char ascii = 0;
if (unicode != NULL) {
int len = BLI_str_utf8_size(unicode);
if (len == -1 || unicode[len] != '\0') {
BKE_report(reports, RPT_ERROR, "Only a single character supported");
return NULL;
}
- if (len == 1 && isascii(unicode[0])) {
- ascii = unicode[0];
- }
}
wmEvent e = *win->eventstate;
@@ -671,10 +668,8 @@ static wmEvent *rna_Window_event_add_simulate(wmWindow *win,
e.modifier |= KM_OSKEY;
}
- e.ascii = '\0';
e.utf8_buf[0] = '\0';
if (unicode != NULL) {
- e.ascii = ascii;
STRNCPY(e.utf8_buf, unicode);
}
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo.c b/source/blender/makesrna/intern/rna_wm_gizmo.c
index 6c3d96726bb..0e307f5b424 100644
--- a/source/blender/makesrna/intern/rna_wm_gizmo.c
+++ b/source/blender/makesrna/intern/rna_wm_gizmo.c
@@ -1398,6 +1398,11 @@ static void rna_def_gizmogroup(BlenderRNA *brna)
0,
"Tool Init",
"Postpone running until tool operator run (when used with a tool)"},
+ {WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP,
+ "TOOL_FALLBACK_KEYMAP",
+ 0,
+ "Use fallback tools keymap",
+ "Add fallback tools keymap to this gizmo type."},
{WM_GIZMOGROUPTYPE_VR_REDRAWS,
"VR_REDRAWS",
0,
diff --git a/source/blender/makesrna/intern/rna_wm_gizmo_api.c b/source/blender/makesrna/intern/rna_wm_gizmo_api.c
index 419dfa68305..760121d2279 100644
--- a/source/blender/makesrna/intern/rna_wm_gizmo_api.c
+++ b/source/blender/makesrna/intern/rna_wm_gizmo_api.c
@@ -211,7 +211,15 @@ void RNA_api_gizmo(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(parm, "", "The matrix to transform");
- RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+ RNA_def_int(func,
+ "select_id",
+ -1,
+ -1,
+ INT_MAX,
+ "ID to use when gizmo is selectable. Use -1 when not selecting",
+ "",
+ -1,
+ INT_MAX);
/* draw_preset_box */
func = RNA_def_function(srna, "draw_preset_arrow", "rna_gizmo_draw_preset_arrow");
@@ -221,7 +229,15 @@ void RNA_api_gizmo(StructRNA *srna)
RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(parm, "", "The matrix to transform");
RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation");
- RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+ RNA_def_int(func,
+ "select_id",
+ -1,
+ -1,
+ INT_MAX,
+ "ID to use when gizmo is selectable. Use -1 when not selecting",
+ "",
+ -1,
+ INT_MAX);
func = RNA_def_function(srna, "draw_preset_circle", "rna_gizmo_draw_preset_circle");
RNA_def_function_ui_description(func, "Draw a box");
@@ -230,7 +246,15 @@ void RNA_api_gizmo(StructRNA *srna)
RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4);
RNA_def_property_ui_text(parm, "", "The matrix to transform");
RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation");
- RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+ RNA_def_int(func,
+ "select_id",
+ -1,
+ -1,
+ INT_MAX,
+ "ID to use when gizmo is selectable. Use -1 when not selecting",
+ "",
+ -1,
+ INT_MAX);
/* -------------------------------------------------------------------- */
/* Other Shapes */
@@ -243,7 +267,15 @@ void RNA_api_gizmo(StructRNA *srna)
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_int(func, "face_map", 0, 0, INT_MAX, "Face map index", "", 0, INT_MAX);
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
- RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX);
+ RNA_def_int(func,
+ "select_id",
+ -1,
+ -1,
+ INT_MAX,
+ "ID to use when gizmo is selectable. Use -1 when not selecting",
+ "",
+ -1,
+ INT_MAX);
/* -------------------------------------------------------------------- */
/* Property API */
diff --git a/source/blender/makesrna/intern/rna_workspace.c b/source/blender/makesrna/intern/rna_workspace.c
index 0b6c3934985..a0d89b8b15a 100644
--- a/source/blender/makesrna/intern/rna_workspace.c
+++ b/source/blender/makesrna/intern/rna_workspace.c
@@ -413,6 +413,14 @@ static void rna_def_workspace(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Object Mode", "Switch to this object mode when activating the workspace");
+ prop = RNA_def_property(srna, "use_pin_scene", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", WORKSPACE_USE_PIN_SCENE);
+ RNA_def_property_ui_text(prop,
+ "Pin Scene",
+ "Remember the last used scene for the workspace and switch to it "
+ "whenever this workspace is activated again");
+ RNA_def_property_update(prop, NC_WORKSPACE, NULL);
+
/* Flags */
prop = RNA_def_property(srna, "use_filter_by_owner", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index 696d2d0f31d..dcfa1bbca51 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -849,7 +849,7 @@ bool rna_XrSessionState_active_action_set_set(bContext *C, const char *action_se
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = CTX_wm_manager(C);
- return WM_xr_active_action_set_set(&wm->xr, action_set_name);
+ return WM_xr_active_action_set_set(&wm->xr, action_set_name, true);
# else
UNUSED_VARS(C, action_set_name);
return false;
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 1aac3c2191d..73daabec9b3 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -217,7 +217,6 @@ endif()
if(WITH_EXPERIMENTAL_FEATURES)
add_definitions(-DWITH_SIMULATION_DATABLOCK)
- add_definitions(-DWITH_NEW_CURVES_TYPE)
endif()
# So we can have special tricks in modifier system.
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index f6e8a26f0e1..15ad361a262 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -266,7 +266,7 @@ static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
}
ModifierTypeInfo modifierType_Armature = {
- /* name */ "Armature",
+ /* name */ N_("Armature"),
/* structName */ "ArmatureModifierData",
/* structSize */ sizeof(ArmatureModifierData),
/* srna */ &RNA_ArmatureModifier,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index c44a4e0b438..569b0fd0fda 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -328,7 +328,7 @@ static void mesh_merge_transform(Mesh *result,
ml->e += cap_edges_index;
}
- /* set origindex */
+ /* Set #CD_ORIGINDEX. */
index_orig = CustomData_get_layer(&result->vdata, CD_ORIGINDEX);
if (index_orig) {
copy_vn_i(index_orig + cap_verts_index, cap_nverts, ORIGINDEX_NONE);
@@ -402,7 +402,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
start_cap_ob, ctx->object, &vgroup_start_cap_remap_len);
}
- start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob, false);
+ start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob);
if (start_cap_mesh) {
start_cap_nverts = start_cap_mesh->totvert;
start_cap_nedges = start_cap_mesh->totedge;
@@ -417,7 +417,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
end_cap_ob, ctx->object, &vgroup_end_cap_remap_len);
}
- end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob, false);
+ end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob);
if (end_cap_mesh) {
end_cap_nverts = end_cap_mesh->totvert;
end_cap_nedges = end_cap_mesh->totedge;
@@ -464,7 +464,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
copy_m4_m4(offset, result_mat);
}
- /* Check if there is some scaling. If scaling, then we will not translate mapping */
+ /* Check if there is some scaling. If scaling, then we will not translate mapping */
mat4_to_size(scale, offset);
offset_has_scale = !is_one_v3(scale);
@@ -1002,7 +1002,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Array = {
- /* name */ "Array",
+ /* name */ N_("Array"),
/* structName */ "ArrayModifierData",
/* structSize */ sizeof(ArrayModifierData),
/* srna */ &RNA_ArrayModifier,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 0b2ea0e1ade..94f2090e081 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -39,7 +39,6 @@
#include "BLO_read_write.h"
-#include "BKE_curveprofile.h"
#include "bmesh.h"
#include "bmesh_tools.h"
@@ -418,7 +417,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_Bevel = {
- /* name */ "Bevel",
+ /* name */ N_("Bevel"),
/* structName */ "BevelModifierData",
/* structSize */ sizeof(BevelModifierData),
/* srna */ &RNA_BevelModifier,
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index d47f2a130e3..aa64c1f83bc 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -14,6 +14,7 @@
#include "BLI_math_geom.h"
#include "BLI_math_matrix.h"
#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
#include "BLT_translation.h"
@@ -62,7 +63,11 @@
using blender::Array;
using blender::float4x4;
+using blender::IndexRange;
+using blender::MutableSpan;
+using blender::Span;
using blender::Vector;
+using blender::VectorSet;
static void initData(ModifierData *md)
{
@@ -146,7 +151,7 @@ static Mesh *get_quick_mesh(
mul_m4_v3(omat, mv->co);
}
- BKE_mesh_normals_tag_dirty(result);
+ BKE_mesh_tag_coords_changed(result);
}
break;
@@ -223,7 +228,7 @@ static BMesh *BMD_mesh_bm_create(
Mesh *mesh, Object *object, Mesh *mesh_operand_ob, Object *operand_ob, bool *r_is_flip)
{
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
*r_is_flip = (is_negative_m4(object->obmat) != is_negative_m4(operand_ob->obmat));
@@ -270,7 +275,7 @@ static void BMD_mesh_intersection(BMesh *bm,
bool is_flip)
{
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
BooleanModifierData *bmd = (BooleanModifierData *)md;
@@ -375,19 +380,23 @@ static void BMD_mesh_intersection(BMesh *bm,
#ifdef WITH_GMP
-/* Get a mapping from material slot numbers in the src_ob to slot numbers in the dst_ob.
- * If a material doesn't exist in the dst_ob, the mapping just goes to the same slot
- * or to zero if there aren't enough slots in the destination.
- * Caller owns the returned array. */
-static Array<short> get_material_remap(Object *dest_ob, Object *src_ob)
+/* Get a mapping from material slot numbers in the source geometry to slot numbers in the result
+ * geometry. The material is added to the result geometry if it doesn't already use it. */
+static Array<short> get_material_remap(Object &object,
+ const Mesh &mesh,
+ VectorSet<Material *> &materials)
{
- int n = src_ob->totcol;
- if (n <= 0) {
- n = 1;
+ const int material_num = mesh.totcol;
+ if (material_num == 0) {
+ /* Necessary for faces using the default material when there are no material slots. */
+ return Array<short>({materials.index_of_or_add(nullptr)});
}
- Array<short> remap(n);
- BKE_object_material_remap_calc(dest_ob, src_ob, remap.data());
- return remap;
+ Array<short> map(material_num);
+ for (const int i : IndexRange(material_num)) {
+ Material *material = BKE_object_material_get_eval(&object, i + 1);
+ map[i] = materials.index_of_or_add(material);
+ }
+ return map;
}
static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
@@ -396,10 +405,12 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
{
Vector<const Mesh *> meshes;
Vector<float4x4 *> obmats;
+
+ VectorSet<Material *> materials;
Vector<Array<short>> material_remaps;
# ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
# endif
if ((bmd->flag & eBooleanModifierFlag_Object) && bmd->object == nullptr) {
@@ -409,15 +420,23 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
meshes.append(mesh);
obmats.append((float4x4 *)&ctx->object->obmat);
material_remaps.append({});
+ if (mesh->totcol == 0) {
+ /* Necessary for faces using the default material when there are no material slots. */
+ materials.add(nullptr);
+ }
+ else {
+ materials.add_multiple({mesh->mat, mesh->totcol});
+ }
+
if (bmd->flag & eBooleanModifierFlag_Object) {
- Mesh *mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object, false);
+ Mesh *mesh_operand = BKE_modifier_get_evaluated_mesh_from_evaluated_object(bmd->object);
if (!mesh_operand) {
return mesh;
}
BKE_mesh_wrapper_ensure_mdata(mesh_operand);
meshes.append(mesh_operand);
obmats.append((float4x4 *)&bmd->object->obmat);
- material_remaps.append(get_material_remap(ctx->object, bmd->object));
+ material_remaps.append(get_material_remap(*bmd->object, *mesh_operand, materials));
}
else if (bmd->flag & eBooleanModifierFlag_Collection) {
Collection *collection = bmd->collection;
@@ -425,14 +444,14 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
if (collection) {
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) {
if (ob->type == OB_MESH && ob != ctx->object) {
- Mesh *collection_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob, false);
+ Mesh *collection_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob);
if (!collection_mesh) {
continue;
}
BKE_mesh_wrapper_ensure_mdata(collection_mesh);
meshes.append(collection_mesh);
obmats.append((float4x4 *)&ob->obmat);
- material_remaps.append(get_material_remap(ctx->object, ob));
+ material_remaps.append(get_material_remap(*ob, *collection_mesh, materials));
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
@@ -441,13 +460,19 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd,
const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0;
const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0;
- return blender::meshintersect::direct_mesh_boolean(meshes,
- obmats,
- *(float4x4 *)&ctx->object->obmat,
- material_remaps,
- use_self,
- hole_tolerant,
- bmd->operation);
+ Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes,
+ obmats,
+ *(float4x4 *)&ctx->object->obmat,
+ material_remaps,
+ use_self,
+ hole_tolerant,
+ bmd->operation,
+ nullptr);
+ MEM_SAFE_FREE(result->mat);
+ result->mat = (Material **)MEM_malloc_arrayN(materials.size(), sizeof(Material *), __func__);
+ result->totcol = materials.size();
+ MutableSpan(result->mat, result->totcol).copy_from(materials);
+ return result;
}
#endif
@@ -470,7 +495,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif
#ifdef DEBUG_TIME
- SCOPED_TIMER(__func__)
+ SCOPED_TIMER(__func__);
#endif
if (bmd->flag & eBooleanModifierFlag_Object) {
@@ -480,8 +505,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
Object *operand_ob = bmd->object;
- Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob,
- false);
+ Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob);
if (mesh_operand_ob) {
/* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
@@ -515,27 +539,31 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, operand_ob) {
if (operand_ob->type == OB_MESH && operand_ob != ctx->object) {
- Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob,
- false);
+ Mesh *mesh_operand_ob = BKE_modifier_get_evaluated_mesh_from_evaluated_object(operand_ob);
- if (mesh_operand_ob) {
- /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
- * But for 2.90 better not try to be smart here. */
- BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
+ if (mesh_operand_ob == nullptr) {
+ continue;
+ }
- bool is_flip;
- BMesh *bm = BMD_mesh_bm_create(mesh, object, mesh_operand_ob, operand_ob, &is_flip);
+ /* XXX This is utterly non-optimal, we may go from a bmesh to a mesh back to a bmesh!
+ * But for 2.90 better not try to be smart here. */
+ BKE_mesh_wrapper_ensure_mdata(mesh_operand_ob);
- BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
+ bool is_flip;
+ BMesh *bm = BMD_mesh_bm_create(result, object, mesh_operand_ob, operand_ob, &is_flip);
- /* Needed for multiple objects to work. */
- 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);
+ BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip);
+ /* Needed for multiple objects to work. */
+ if (result == mesh) {
result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh);
- BM_mesh_free(bm);
}
+ else {
+ BMeshToMeshParams bmesh_to_mesh_params{};
+ bmesh_to_mesh_params.calc_object_remap = false;
+ BM_mesh_bm_to_me(nullptr, bm, result, &bmesh_to_mesh_params);
+ }
+ BM_mesh_free(bm);
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
@@ -609,7 +637,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Boolean = {
- /* name */ "Boolean",
+ /* name */ N_("Boolean"),
/* structName */ "BooleanModifierData",
/* structSize */ sizeof(BooleanModifierData),
/* srna */ &RNA_BooleanModifier,
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 687ff04cedf..a9b6af967be 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -13,6 +13,8 @@
#include "BLI_math_vector.h"
#include "BLI_rand.h"
+#include "BLT_translation.h"
+
#include "DNA_defaults.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -311,7 +313,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Build = {
- /* name */ "Build",
+ /* name */ N_("Build"),
/* structName */ "BuildModifierData",
/* structSize */ sizeof(BuildModifierData),
/* srna */ &RNA_BuildModifier,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 3916551bc90..9aaf7fead36 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -559,7 +559,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Cast = {
- /* name */ "Cast",
+ /* name */ N_("Cast"),
/* structName */ "CastModifierData",
/* structSize */ sizeof(CastModifierData),
/* srna */ &RNA_CastModifier,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 185b05b4cf9..cc0bd87d614 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -275,7 +275,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Cloth = {
- /* name */ "Cloth",
+ /* name */ N_("Cloth"),
/* structName */ "ClothModifierData",
/* structSize */ sizeof(ClothModifierData),
/* srna */ &RNA_ClothModifier,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index f9cd3d5937d..74cb4ac700a 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -284,7 +284,7 @@ static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
}
ModifierTypeInfo modifierType_Collision = {
- /* name */ "Collision",
+ /* name */ N_("Collision"),
/* structName */ "CollisionModifierData",
/* structSize */ sizeof(CollisionModifierData),
/* srna */ &RNA_CollisionModifier,
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 8b6c306dae8..2beb1be6749 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -801,8 +801,9 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
CorrectiveSmoothModifierData csmd = *(const CorrectiveSmoothModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
- if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
BLI_assert(!ID_IS_LINKED(id_owner));
const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
if (!is_local) {
@@ -834,7 +835,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_CorrectiveSmooth = {
- /* name */ "CorrectiveSmooth",
+ /* name */ N_("CorrectiveSmooth"),
/* structName */ "CorrectiveSmoothModifierData",
/* structSize */ sizeof(CorrectiveSmoothModifierData),
/* srna */ &RNA_CorrectiveSmoothModifier,
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index a82b999f4dc..48a59f4d949 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -203,7 +203,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Curve = {
- /* name */ "Curve",
+ /* name */ N_("Curve"),
/* structName */ "CurveModifierData",
/* structSize */ sizeof(CurveModifierData),
/* srna */ &RNA_CurveModifier,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index a3b088799cc..e9f1cf47e38 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -474,7 +474,7 @@ static void panelRegister(ARegionType *region_type)
#undef DT_TYPES_AFFECT_MESH
ModifierTypeInfo modifierType_DataTransfer = {
- /* name */ "DataTransfer",
+ /* name */ N_("DataTransfer"),
/* structName */ "DataTransferModifierData",
/* structSize */ sizeof(DataTransferModifierData),
/* srna */ &RNA_DataTransferModifier,
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 70f028d6907..3df4fbcbea8 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -271,7 +271,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Decimate = {
- /* name */ "Decimate",
+ /* name */ N_("Decimate"),
/* structName */ "DecimateModifierData",
/* structSize */ sizeof(DecimateModifierData),
/* srna */ &RNA_DecimateModifier,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 149cf0c0cbb..5289fc42e21 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -197,7 +197,6 @@ static void displaceModifier_do_task(void *__restrict userdata,
}
if (data->tex_target) {
- texres.nor = NULL;
BKE_texture_get_value_ex(
data->scene, data->tex_target, tex_co[iter], &texres, data->pool, false);
delta = texres.tin - dmd->midlevel;
@@ -474,7 +473,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Displace = {
- /* name */ "Displace",
+ /* name */ N_("Displace"),
/* structName */ "DisplaceModifierData",
/* structSize */ sizeof(DisplaceModifierData),
/* srna */ &RNA_DisplaceModifier,
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index 1891ac5df7c..4afb81c04a9 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -83,17 +83,17 @@ static void requiredDataMask(Object *UNUSED(ob),
if (pmd->canvas) {
DynamicPaintSurface *surface = pmd->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- /* tface */
+ /* UV's: #CD_MLOOPUV. */
if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ ||
surface->init_color_type == MOD_DPAINT_INITIAL_TEXTURE) {
r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
}
- /* mcol */
+ /* Vertex Colors: #CD_PROP_BYTE_COLOR. */
if (surface->type == MOD_DPAINT_SURFACE_T_PAINT ||
surface->init_color_type == MOD_DPAINT_INITIAL_VERTEXCOLOR) {
r_cddata_masks->lmask |= CD_MASK_PROP_BYTE_COLOR;
}
- /* CD_MDEFORMVERT */
+ /* Vertex Weights: #CD_MDEFORMVERT. */
if (surface->type == MOD_DPAINT_SURFACE_T_WEIGHT) {
r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
}
@@ -189,7 +189,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_DynamicPaint = {
- /* name */ "Dynamic Paint",
+ /* name */ N_("Dynamic Paint"),
/* structName */ "DynamicPaintModifierData",
/* structSize */ sizeof(DynamicPaintModifierData),
/* srna */ &RNA_DynamicPaintModifier,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 49ddcb9a61d..b381ff32aa2 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -154,7 +154,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_EdgeSplit = {
- /* name */ "EdgeSplit",
+ /* name */ N_("EdgeSplit"),
/* structName */ "EdgeSplitModifierData",
/* structSize */ sizeof(EdgeSplitModifierData),
/* srna */ &RNA_EdgeSplitModifier,
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index d76a750f7e8..ff0616fd288 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -26,6 +26,7 @@
#include "BKE_lattice.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
@@ -897,7 +898,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
{
Mesh *explode, *mesh = to_explode;
MFace *mf = NULL, *mface;
- /* ParticleSettings *part=psmd->psys->part; */ /* UNUSED */
+ // ParticleSettings *part=psmd->psys->part; /* UNUSED */
ParticleSimulationData sim = {NULL};
ParticleData *pa = NULL, *pars = psmd->psys->particles;
ParticleKey state, birth;
@@ -906,7 +907,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
float *vertco = NULL, imat[4][4];
float rot[4];
float ctime;
- /* float timestep; */
+ // float timestep;
const int *facepa = emd->facepa;
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
int i, v, u;
@@ -923,7 +924,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
sim.psys = psmd->psys;
sim.psmd = psmd;
- /* timestep = psys_get_timestep(&sim); */
+ // timestep = psys_get_timestep(&sim);
ctime = BKE_scene_ctime_get(scene);
@@ -1223,7 +1224,7 @@ static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
}
ModifierTypeInfo modifierType_Explode = {
- /* name */ "Explode",
+ /* name */ N_("Explode"),
/* structName */ "ExplodeModifierData",
/* structSize */ sizeof(ExplodeModifierData),
/* srna */ &RNA_ExplodeModifier,
diff --git a/source/blender/modifiers/intern/MOD_fluid.c b/source/blender/modifiers/intern/MOD_fluid.c
index 562f0df510d..a3e9cd083d2 100644
--- a/source/blender/modifiers/intern/MOD_fluid.c
+++ b/source/blender/modifiers/intern/MOD_fluid.c
@@ -241,7 +241,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Fluid = {
- /* name */ "Fluid",
+ /* name */ N_("Fluid"),
/* structName */ "FluidModifierData",
/* structSize */ sizeof(FluidModifierData),
/* srna */ &RNA_FluidModifier,
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 3649ece12e1..3c4e6b0d90f 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -545,7 +545,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_Hook = {
- /* name */ "Hook",
+ /* name */ N_("Hook"),
/* structName */ "HookModifierData",
/* structSize */ sizeof(HookModifierData),
/* srna */ &RNA_HookModifier,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index 06ded1c4488..e29098eb218 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -846,8 +846,9 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
LaplacianDeformModifierData lmd = *(const LaplacianDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
- if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
BLI_assert(!ID_IS_LINKED(id_owner));
const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
if (!is_local) {
@@ -874,7 +875,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_LaplacianDeform = {
- /* name */ "LaplacianDeform",
+ /* name */ N_("LaplacianDeform"),
/* structName */ "LaplacianDeformModifierData",
/* structSize */ sizeof(LaplacianDeformModifierData),
/* srna */ &RNA_LaplacianDeformModifier,
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 95283b1cd20..2cce0c14e4c 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -608,7 +608,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_LaplacianSmooth = {
- /* name */ "LaplacianSmooth",
+ /* name */ N_("LaplacianSmooth"),
/* structName */ "LaplacianSmoothModifierData",
/* structSize */ sizeof(LaplacianSmoothModifierData),
/* srna */ &RNA_LaplacianSmoothModifier,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 832372304a0..0e1994eed36 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -160,7 +160,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Lattice = {
- /* name */ "Lattice",
+ /* name */ N_("Lattice"),
/* structName */ "LatticeModifierData",
/* structSize */ sizeof(LatticeModifierData),
/* srna */ &RNA_LatticeModifier,
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index 0813901fc49..fac3ea36537 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -804,7 +804,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Mask = {
- /* name */ "Mask",
+ /* name */ N_("Mask"),
/* structName */ "MaskModifierData",
/* structSize */ sizeof(MaskModifierData),
/* srna */ &RNA_MaskModifier,
diff --git a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
index 11af907adc8..9ac410eb3de 100644
--- a/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
+++ b/source/blender/modifiers/intern/MOD_mesh_to_volume.cc
@@ -7,6 +7,7 @@
#include <vector>
#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
@@ -14,6 +15,8 @@
#include "BKE_object.h"
#include "BKE_volume.h"
+#include "BLT_translation.h"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -22,6 +25,8 @@
#include "DEG_depsgraph.h"
+#include "GEO_mesh_to_volume.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -39,59 +44,6 @@
#include "RNA_access.h"
#include "RNA_prototypes.h"
-#ifdef WITH_OPENVDB
-# include <openvdb/openvdb.h>
-# include <openvdb/tools/MeshToVolume.h>
-#endif
-
-#ifdef WITH_OPENVDB
-namespace blender {
-/* This class follows the MeshDataAdapter interface from openvdb. */
-class OpenVDBMeshAdapter {
- private:
- Span<MVert> vertices_;
- Span<MLoop> loops_;
- Span<MLoopTri> looptris_;
- float4x4 transform_;
-
- public:
- OpenVDBMeshAdapter(Mesh &mesh, float4x4 transform)
- : vertices_(mesh.mvert, mesh.totvert),
- loops_(mesh.mloop, mesh.totloop),
- transform_(transform)
- {
- const MLoopTri *looptries = BKE_mesh_runtime_looptri_ensure(&mesh);
- const int looptries_len = BKE_mesh_runtime_looptri_len(&mesh);
- looptris_ = Span(looptries, looptries_len);
- }
-
- size_t polygonCount() const
- {
- return static_cast<size_t>(looptris_.size());
- }
-
- size_t pointCount() const
- {
- return static_cast<size_t>(vertices_.size());
- }
-
- size_t vertexCount(size_t UNUSED(polygon_index)) const
- {
- /* All polygons are triangles. */
- return 3;
- }
-
- void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const
- {
- const MLoopTri &looptri = looptris_[polygon_index];
- const MVert &vertex = vertices_[loops_[looptri.tri[vertex_index]].v];
- const float3 transformed_co = transform_ * float3(vertex.co);
- pos = &transformed_co.x;
- }
-};
-} // namespace blender
-#endif
-
static void initData(ModifierData *md)
{
MeshToVolumeModifierData *mvmd = reinterpret_cast<MeshToVolumeModifierData *>(md);
@@ -163,35 +115,6 @@ static void panelRegister(ARegionType *region_type)
modifier_panel_register(region_type, eModifierType_MeshToVolume, panel_draw);
}
-#ifdef WITH_OPENVDB
-static float compute_voxel_size(const ModifierEvalContext *ctx,
- const MeshToVolumeModifierData *mvmd,
- const blender::float4x4 &transform)
-{
- using namespace blender;
-
- float volume_simplify = BKE_volume_simplify_factor(ctx->depsgraph);
- if (volume_simplify == 0.0f) {
- return 0.0f;
- }
-
- if (mvmd->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
- return mvmd->voxel_size / volume_simplify;
- }
- if (mvmd->voxel_amount <= 0) {
- return 0;
- }
- /* 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 = 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;
-}
-#endif
-
static Volume *mesh_to_volume(ModifierData *md,
const ModifierEvalContext *ctx,
Volume *input_volume)
@@ -205,7 +128,7 @@ static Volume *mesh_to_volume(ModifierData *md,
if (object_to_convert == nullptr) {
return input_volume;
}
- Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_to_convert, false);
+ Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_to_convert);
if (mesh == nullptr) {
return input_volume;
}
@@ -213,51 +136,52 @@ static Volume *mesh_to_volume(ModifierData *md,
const float4x4 mesh_to_own_object_space_transform = float4x4(ctx->object->imat) *
float4x4(object_to_convert->obmat);
- const float voxel_size = compute_voxel_size(ctx, mvmd, mesh_to_own_object_space_transform);
- if (voxel_size == 0.0f) {
- return input_volume;
+ geometry::MeshToVolumeResolution resolution;
+ resolution.mode = (MeshToVolumeModifierResolutionMode)mvmd->resolution_mode;
+ if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT) {
+ resolution.settings.voxel_amount = mvmd->voxel_amount;
+ if (resolution.settings.voxel_amount <= 0.0f) {
+ return input_volume;
+ }
+ }
+ else if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
+ resolution.settings.voxel_size = mvmd->voxel_size;
+ if (resolution.settings.voxel_size <= 0.0f) {
+ return input_volume;
+ }
}
- float4x4 mesh_to_index_space_transform;
- scale_m4_fl(mesh_to_index_space_transform.values, 1.0f / voxel_size);
- mul_m4_m4_post(mesh_to_index_space_transform.values, mesh_to_own_object_space_transform.values);
- /* Better align generated grid with the source mesh. */
- add_v3_fl(mesh_to_index_space_transform.values[3], -0.5f);
-
- OpenVDBMeshAdapter mesh_adapter{*mesh, mesh_to_index_space_transform};
+ auto bounds_fn = [&](float3 &r_min, float3 &r_max) {
+ const BoundBox *bb = BKE_object_boundbox_get(mvmd->object);
+ r_min = bb->vec[0];
+ r_max = bb->vec[6];
+ };
- /* Convert the bandwidths from object in index space. */
- const float exterior_band_width = MAX2(0.001f, mvmd->exterior_band_width / voxel_size);
- const float interior_band_width = MAX2(0.001f, mvmd->interior_band_width / voxel_size);
+ const float voxel_size = geometry::volume_compute_voxel_size(ctx->depsgraph,
+ bounds_fn,
+ resolution,
+ mvmd->exterior_band_width,
+ mesh_to_own_object_space_transform);
- openvdb::FloatGrid::Ptr new_grid;
- if (mvmd->fill_volume) {
- /* Setting the interior bandwidth to FLT_MAX, will make it fill the entire volume. */
- new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
- mesh_adapter, {}, exterior_band_width, FLT_MAX);
+ /* Create a new volume. */
+ Volume *volume;
+ if (input_volume == nullptr) {
+ volume = static_cast<Volume *>(BKE_id_new_nomain(ID_VO, "Volume"));
}
else {
- new_grid = openvdb::tools::meshToVolume<openvdb::FloatGrid>(
- mesh_adapter, {}, exterior_band_width, interior_band_width);
+ volume = BKE_volume_new_for_eval(input_volume);
}
- /* Create a new volume object and add the density grid. */
- Volume *volume = BKE_volume_new_for_eval(input_volume);
- VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT);
- openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
- BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false));
-
- /* Merge the generated grid into the density grid. Should be cheap because density_grid has just
- * been created as well. */
- density_grid->merge(*new_grid);
-
- /* Change transform so that the index space is correctly transformed to object space. */
- density_grid->transform().postScale(voxel_size);
-
- /* Give each grid cell a fixed density for now. */
- openvdb::tools::foreach (
- density_grid->beginValueOn(),
- [&](const openvdb::FloatGrid::ValueOnIter &iter) { iter.setValue(mvmd->density); });
+ /* Convert mesh to grid and add to volume. */
+ geometry::volume_grid_add_from_mesh(volume,
+ "density",
+ mesh,
+ mesh_to_own_object_space_transform,
+ voxel_size,
+ mvmd->fill_volume,
+ mvmd->exterior_band_width,
+ mvmd->interior_band_width,
+ mvmd->density);
return volume;
@@ -280,7 +204,7 @@ static void modifyGeometrySet(ModifierData *md,
}
ModifierTypeInfo modifierType_MeshToVolume = {
- /* name */ "Mesh to Volume",
+ /* name */ N_("Mesh to Volume"),
/* structName */ "MeshToVolumeModifierData",
/* structSize */ sizeof(MeshToVolumeModifierData),
/* srna */ &RNA_MeshToVolumeModifier,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index 6f065797b43..8dfdd07ace9 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -416,7 +416,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_MeshCache = {
- /* name */ "MeshCache",
+ /* name */ N_("MeshCache"),
/* structName */ "MeshCacheModifierData",
/* structSize */ sizeof(MeshCacheModifierData),
/* srna */ &RNA_MeshCacheModifier,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 0cff85d30ec..334f5d75279 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -353,7 +353,7 @@ static void meshdeformModifier_do(ModifierData *md,
* We'll support this case once granular dependency graph is landed.
*/
Object *ob_target = mmd->object;
- cagemesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ cagemesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
if (cagemesh == NULL) {
BKE_modifier_set_error(ctx->object, md, "Cannot get mesh from cage object");
return;
@@ -584,8 +584,9 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
MeshDeformModifierData mmd = *(const MeshDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
- if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
BLI_assert(!ID_IS_LINKED(id_owner));
const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
if (!is_local) {
@@ -649,7 +650,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_MeshDeform = {
- /* name */ "MeshDeform",
+ /* name */ N_("MeshDeform"),
/* structName */ "MeshDeformModifierData",
/* structSize */ sizeof(MeshDeformModifierData),
/* srna */ &RNA_MeshDeformModifier,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.cc b/source/blender/modifiers/intern/MOD_meshsequencecache.cc
index 273050eafd8..1c35160d3ef 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.cc
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.cc
@@ -392,7 +392,7 @@ static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
}
ModifierTypeInfo modifierType_MeshSequenceCache = {
- /* name */ "MeshSequenceCache",
+ /* name */ N_("MeshSequenceCache"),
/* structName */ "MeshSeqCacheModifierData",
/* structSize */ sizeof(MeshSeqCacheModifierData),
/* srna */ &RNA_MeshSequenceCacheModifier,
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index b6ba8c9e0f9..5f095a72dca 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -204,7 +204,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Mirror = {
- /* name */ "Mirror",
+ /* name */ N_("Mirror"),
/* structName */ "MirrorModifierData",
/* structSize */ sizeof(MirrorModifierData),
/* srna */ &RNA_MirrorModifier,
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index a4c5ddac5c9..cdad834f9b4 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -487,7 +487,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Multires = {
- /* name */ "Multires",
+ /* name */ N_("Multires"),
/* structName */ "MultiresModifierData",
/* structSize */ sizeof(MultiresModifierData),
/* srna */ &RNA_MultiresModifier,
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 0d8cef3e083..01e4d5ff6b3 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -21,6 +21,7 @@
#include "BLI_utildefines.h"
#include "DNA_collection_types.h"
+#include "DNA_curves_types.h"
#include "DNA_defaults.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@@ -45,6 +46,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
@@ -107,7 +109,7 @@ using blender::Span;
using blender::StringRef;
using blender::StringRefNull;
using blender::Vector;
-using blender::bke::OutputAttribute;
+using blender::bke::AttributeMetaData;
using blender::fn::Field;
using blender::fn::GField;
using blender::fn::ValueOrField;
@@ -118,8 +120,8 @@ 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::eNamedAttrUsage;
using geo_log::GeometryAttributeInfo;
-using geo_log::NamedAttributeUsage;
static void initData(ModifierData *md)
{
@@ -189,6 +191,10 @@ static bool node_needs_own_transform_relation(const bNode &node)
return storage.transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE;
}
+ if (node.type == GEO_NODE_DEFORM_CURVES_ON_SURFACE) {
+ return true;
+ }
+
return false;
}
@@ -268,6 +274,14 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
Set<ID *> used_ids;
find_used_ids_from_settings(nmd->settings, used_ids);
process_nodes_for_depsgraph(*nmd->node_group, used_ids, needs_own_transform_relation);
+
+ if (ctx->object->type == OB_CURVES) {
+ Curves *curves_id = static_cast<Curves *>(ctx->object->data);
+ if (curves_id->surface != nullptr) {
+ used_ids.add(&curves_id->surface->id);
+ }
+ }
+
for (ID *id : used_ids) {
switch ((ID_Type)GS(id->name)) {
case ID_OB: {
@@ -396,8 +410,9 @@ static bool socket_type_has_attribute_toggle(const bNodeSocket &socket)
*/
static bool input_has_attribute_toggle(const bNodeTree &node_tree, const int socket_index)
{
- BLI_assert(node_tree.field_inferencing_interface != nullptr);
- const FieldInferencingInterface &field_interface = *node_tree.field_inferencing_interface;
+ BLI_assert(node_tree.runtime->field_inferencing_interface);
+ const FieldInferencingInterface &field_interface =
+ *node_tree.runtime->field_inferencing_interface;
return field_interface.inputs[socket_index] != InputSocketFieldType::None;
}
@@ -753,6 +768,7 @@ static void initialize_group_input(NodesModifierData &nmd,
{
const bNodeSocketType &socket_type = *socket.typeinfo();
const bNodeSocket &bsocket = *socket.bsocket();
+ const eNodeSocketDatatype socket_data_type = static_cast<eNodeSocketDatatype>(bsocket.type);
if (nmd.settings.properties == nullptr) {
socket_type.get_geometry_nodes_cpp_value(bsocket, r_value);
return;
@@ -769,8 +785,7 @@ static void initialize_group_input(NodesModifierData &nmd,
}
if (!input_has_attribute_toggle(*nmd.node_group, socket.index())) {
- init_socket_cpp_value_from_property(
- *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
+ init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
return;
}
@@ -779,14 +794,17 @@ static void initialize_group_input(NodesModifierData &nmd,
const IDProperty *property_attribute_name = IDP_GetPropertyFromGroup(
nmd.settings.properties, (socket.identifier() + attribute_name_suffix).c_str());
if (property_use_attribute == nullptr || property_attribute_name == nullptr) {
- init_socket_cpp_value_from_property(
- *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
+ init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
return;
}
const bool use_attribute = IDP_Int(property_use_attribute) != 0;
if (use_attribute) {
const StringRef attribute_name{IDP_String(property_attribute_name)};
+ if (!blender::bke::allow_procedural_attribute_access(attribute_name)) {
+ init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
+ return;
+ }
auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>(
attribute_name, *socket_type.base_cpp_type);
GField attribute_field{std::move(attribute_input), 0};
@@ -797,8 +815,7 @@ static void initialize_group_input(NodesModifierData &nmd,
cpp_type->construct_from_field(r_value, std::move(attribute_field));
}
else {
- init_socket_cpp_value_from_property(
- *property, static_cast<eNodeSocketDatatype>(bsocket.type), r_value);
+ init_socket_cpp_value_from_property(*property, socket_data_type, r_value);
}
}
@@ -917,7 +934,7 @@ struct OutputAttributeInfo {
struct OutputAttributeToStore {
GeometryComponentType component_type;
- AttributeDomain domain;
+ eAttrDomain domain;
StringRefNull name;
GMutableSpan data;
};
@@ -926,10 +943,10 @@ struct OutputAttributeToStore {
* The output attributes are organized based on their domain, because attributes on the same domain
* can be evaluated together.
*/
-static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attributes_to_store(
+static MultiValueMap<eAttrDomain, OutputAttributeInfo> find_output_attributes_to_store(
const NodesModifierData &nmd, const NodeRef &output_node, Span<GMutablePointer> output_values)
{
- MultiValueMap<AttributeDomain, OutputAttributeInfo> outputs_by_domain;
+ MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain;
for (const InputSocketRef *socket : output_node.inputs().drop_front(1).drop_back(1)) {
if (!socket_type_has_attribute_toggle(*socket->bsocket())) {
continue;
@@ -944,6 +961,9 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute
if (attribute_name.is_empty()) {
continue;
}
+ if (!blender::bke::allow_procedural_attribute_access(attribute_name)) {
+ continue;
+ }
const int index = socket->index();
const GPointer value = output_values[index];
@@ -953,7 +973,7 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute
const bNodeSocket *interface_socket = (const bNodeSocket *)BLI_findlink(
&nmd.node_group->outputs, socket->index());
- const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain;
+ const eAttrDomain domain = (eAttrDomain)interface_socket->attribute_domain;
OutputAttributeInfo output_info;
output_info.field = std::move(field);
output_info.name = attribute_name;
@@ -968,7 +988,7 @@ static MultiValueMap<AttributeDomain, OutputAttributeInfo> find_output_attribute
*/
static Vector<OutputAttributeToStore> compute_attributes_to_store(
const GeometrySet &geometry,
- const MultiValueMap<AttributeDomain, OutputAttributeInfo> &outputs_by_domain)
+ const MultiValueMap<eAttrDomain, OutputAttributeInfo> &outputs_by_domain)
{
Vector<OutputAttributeToStore> attributes_to_store;
for (const GeometryComponentType component_type : {GEO_COMPONENT_TYPE_MESH,
@@ -979,22 +999,27 @@ static Vector<OutputAttributeToStore> compute_attributes_to_store(
continue;
}
const GeometryComponent &component = *geometry.get_component_for_read(component_type);
+ if (component.is_empty()) {
+ continue;
+ }
+ const blender::bke::AttributeAccessor attributes = *component.attributes();
for (const auto item : outputs_by_domain.items()) {
- const AttributeDomain domain = item.key;
+ const eAttrDomain domain = item.key;
const Span<OutputAttributeInfo> outputs_info = item.value;
- if (!component.attribute_domain_supported(domain)) {
+ if (!attributes.domain_supported(domain)) {
continue;
}
- const int domain_num = component.attribute_domain_num(domain);
+ const int domain_size = attributes.domain_size(domain);
blender::bke::GeometryComponentFieldContext field_context{component, domain};
- blender::fn::FieldEvaluator field_evaluator{field_context, domain_num};
+ blender::fn::FieldEvaluator field_evaluator{field_context, domain_size};
for (const OutputAttributeInfo &output_info : outputs_info) {
const CPPType &type = output_info.field.cpp_type();
OutputAttributeToStore store{
component_type,
domain,
output_info.name,
- GMutableSpan{type, MEM_malloc_arrayN(domain_num, type.size(), __func__), domain_num}};
+ GMutableSpan{
+ type, MEM_malloc_arrayN(domain_size, type.size(), __func__), domain_size}};
field_evaluator.add_with_destination(output_info.field, store.data);
attributes_to_store.append(store);
}
@@ -1009,32 +1034,33 @@ static void store_computed_output_attributes(
{
for (const OutputAttributeToStore &store : attributes_to_store) {
GeometryComponent &component = geometry.get_component_for_write(store.component_type);
- const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(store.data.type());
- const std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(
- store.name);
+ blender::bke::MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ const eCustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(
+ store.data.type());
+ const std::optional<AttributeMetaData> meta_data = attributes.lookup_meta_data(store.name);
/* Attempt to remove the attribute if it already exists but the domain and type don't match.
* Removing the attribute won't succeed if it is built in and non-removable. */
if (meta_data.has_value() &&
(meta_data->domain != store.domain || meta_data->data_type != data_type)) {
- component.attribute_try_delete(store.name);
+ attributes.remove(store.name);
}
/* Try to create the attribute reusing the stored buffer. This will only succeed if the
* attribute didn't exist before, or if it existed but was removed above. */
- if (component.attribute_try_create(
- store.name,
- store.domain,
- blender::bke::cpp_type_to_custom_data_type(store.data.type()),
- AttributeInitMove(store.data.data()))) {
+ if (attributes.add(store.name,
+ store.domain,
+ blender::bke::cpp_type_to_custom_data_type(store.data.type()),
+ blender::bke::AttributeInitMove(store.data.data()))) {
continue;
}
- OutputAttribute attribute = component.attribute_try_get_for_output_only(
+ blender::bke::GAttributeWriter attribute = attributes.lookup_or_add_for_write(
store.name, store.domain, data_type);
if (attribute) {
- attribute.varray().set_all(store.data.data());
- attribute.save();
+ attribute.varray.set_all(store.data.data());
+ attribute.finish();
}
/* We were unable to reuse the data, so it must be destructed and freed. */
@@ -1050,7 +1076,7 @@ static void store_output_attributes(GeometrySet &geometry,
{
/* All new attribute values have to be computed before the geometry is actually changed. This is
* necessary because some fields might depend on attributes that are overwritten. */
- MultiValueMap<AttributeDomain, OutputAttributeInfo> outputs_by_domain =
+ MultiValueMap<eAttrDomain, OutputAttributeInfo> outputs_by_domain =
find_output_attributes_to_store(nmd, output_node, output_values);
Vector<OutputAttributeToStore> attributes_to_store = compute_attributes_to_store(
geometry, outputs_by_domain);
@@ -1429,6 +1455,14 @@ static void add_attribute_search_button(const bContext &C,
nullptr,
attribute_search_exec_fn,
nullptr);
+
+ char *attribute_name = RNA_string_get_alloc(
+ md_ptr, rna_path_attribute_name.c_str(), nullptr, 0, nullptr);
+ const bool access_allowed = blender::bke::allow_procedural_attribute_access(attribute_name);
+ MEM_freeN(attribute_name);
+ if (!access_allowed) {
+ UI_but_flag_enable(but, UI_BUT_REDALERT);
+ }
}
static void add_attribute_search_or_value_buttons(const bContext &C,
@@ -1649,7 +1683,7 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p
return;
}
const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log);
- Map<std::string, NamedAttributeUsage> usage_by_attribute;
+ Map<std::string, eNamedAttrUsage> usage_by_attribute;
log.foreach_node_log([&](const geo_log::NodeLog &node_log) {
for (const geo_log::UsedNamedAttribute &used_attribute : node_log.used_named_attributes()) {
usage_by_attribute.lookup_or_add_as(used_attribute.name,
@@ -1664,7 +1698,7 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p
struct NameWithUsage {
StringRefNull name;
- NamedAttributeUsage usage;
+ eNamedAttrUsage usage;
};
Vector<NameWithUsage> sorted_used_attribute;
@@ -1679,20 +1713,20 @@ static void internal_dependencies_panel_draw(const bContext *UNUSED(C), Panel *p
for (const NameWithUsage &attribute : sorted_used_attribute) {
const StringRefNull attribute_name = attribute.name;
- const NamedAttributeUsage usage = attribute.usage;
+ const eNamedAttrUsage usage = attribute.usage;
/* #uiLayoutRowWithHeading doesn't seem to work in this case. */
uiLayout *split = uiLayoutSplit(layout, 0.4f, false);
std::stringstream ss;
Vector<std::string> usages;
- if ((usage & NamedAttributeUsage::Read) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Read) != eNamedAttrUsage::None) {
usages.append(TIP_("Read"));
}
- if ((usage & NamedAttributeUsage::Write) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Write) != eNamedAttrUsage::None) {
usages.append(TIP_("Write"));
}
- if ((usage & NamedAttributeUsage::Remove) != NamedAttributeUsage::None) {
+ if ((usage & eNamedAttrUsage::Remove) != eNamedAttrUsage::None) {
usages.append(TIP_("Remove"));
}
for (const int i : usages.index_range()) {
@@ -1791,7 +1825,7 @@ static void requiredDataMask(Object *UNUSED(ob),
}
ModifierTypeInfo modifierType_Nodes = {
- /* name */ "GeometryNodes",
+ /* name */ N_("GeometryNodes"),
/* structName */ "NodesModifierData",
/* structSize */ sizeof(NodesModifierData),
/* srna */ &RNA_NodesModifier,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index c215ac601a1..09bc9546325 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -756,7 +756,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_NormalEdit = {
- /* name */ "NormalEdit",
+ /* name */ N_("NormalEdit"),
/* structName */ "NormalEditModifierData",
/* structSize */ sizeof(NormalEditModifierData),
/* srna */ &RNA_NormalEditModifier,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index b5411eee883..ea9049200cc 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -469,7 +469,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
}
}
- BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_tag_coords_changed(mesh);
if (allocated_ocean) {
BKE_ocean_free(omd->ocean);
@@ -701,7 +701,7 @@ static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
}
ModifierTypeInfo modifierType_Ocean = {
- /* name */ "Ocean",
+ /* name */ N_("Ocean"),
/* structName */ "OceanModifierData",
/* structSize */ sizeof(OceanModifierData),
/* srna */ &RNA_OceanModifier,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 2a8d2454670..5018b2d1030 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -644,7 +644,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_ParticleInstance = {
- /* name */ "ParticleInstance",
+ /* name */ N_("ParticleInstance"),
/* structName */ "ParticleInstanceModifierData",
/* structSize */ sizeof(ParticleInstanceModifierData),
/* srna */ &RNA_ParticleInstanceModifier,
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc
index c6a606360e3..7f7465947f9 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.cc
+++ b/source/blender/modifiers/intern/MOD_particlesystem.cc
@@ -21,6 +21,7 @@
#include "BKE_editmesh.h"
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_legacy_convert.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_screen.h"
@@ -300,15 +301,16 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_ParticleSystem = {
- /* name */ "ParticleSystem",
+ /* name */ N_("ParticleSystem"),
/* structName */ "ParticleSystemModifierData",
/* structSize */ sizeof(ParticleSystemModifierData),
/* srna */ &RNA_ParticleSystemModifier,
/* type */ eModifierTypeType_OnlyDeform,
/* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
- eModifierTypeFlag_UsesPointCache /* |
- eModifierTypeFlag_SupportsEditmode |
- eModifierTypeFlag_EnableInEditmode */
+ eModifierTypeFlag_UsesPointCache
+#if 0
+ | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode
+#endif
,
/* icon */ ICON_MOD_PARTICLES,
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 288faee247f..f21d536fadf 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -268,7 +268,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Remesh = {
- /* name */ "Remesh",
+ /* name */ N_("Remesh"),
/* structName */ "RemeshModifierData",
/* structSize */ sizeof(RemeshModifierData),
/* srna */ &RNA_RemeshModifier,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 0e22f59c2fb..9588b9acd3b 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -1235,7 +1235,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Screw = {
- /* name */ "Screw",
+ /* name */ N_("Screw"),
/* structName */ "ScrewModifierData",
/* structSize */ sizeof(ScrewModifierData),
/* srna */ &RNA_ScrewModifier,
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index 6953e89dfc2..56dd1fc50f8 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -9,6 +9,8 @@
#include "BLI_math.h"
+#include "BLT_translation.h"
+
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
@@ -34,7 +36,7 @@ static void deformVerts(ModifierData *UNUSED(md),
if (key && key->block.first) {
int deformedVerts_tot;
BKE_key_evaluate_object_ex(
- ctx->object, &deformedVerts_tot, (float *)vertexCos, sizeof(*vertexCos) * verts_num);
+ ctx->object, &deformedVerts_tot, (float *)vertexCos, sizeof(*vertexCos) * verts_num, NULL);
}
}
@@ -108,7 +110,7 @@ static void deformMatricesEM(ModifierData *UNUSED(md),
}
ModifierTypeInfo modifierType_ShapeKey = {
- /* name */ "ShapeKey",
+ /* name */ N_("ShapeKey"),
/* structName */ "ShapeKeyModifierData",
/* structSize */ sizeof(ShapeKeyModifierData),
/* srna */ &RNA_Modifier,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index 488df3d6f4c..be12dc6639b 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -260,7 +260,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Shrinkwrap = {
- /* name */ "Shrinkwrap",
+ /* name */ N_("Shrinkwrap"),
/* structName */ "ShrinkwrapModifierData",
/* structSize */ sizeof(ShrinkwrapModifierData),
/* srna */ &RNA_ShrinkwrapModifier,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index e3c7f1c423b..9f1d0cd36c4 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -564,7 +564,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_SimpleDeform = {
- /* name */ "SimpleDeform",
+ /* name */ N_("SimpleDeform"),
/* structName */ "SimpleDeformModifierData",
/* structSize */ sizeof(SimpleDeformModifierData),
/* srna */ &RNA_SimpleDeformModifier,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 5f238209015..84795cdb2d9 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -2069,7 +2069,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Skin = {
- /* name */ "Skin",
+ /* name */ N_("Skin"),
/* structName */ "SkinModifierData",
/* structSize */ sizeof(SkinModifierData),
/* srna */ &RNA_SkinModifier,
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index 5439083d9a7..c868c47cb90 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -253,7 +253,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Smooth = {
- /* name */ "Smooth",
+ /* name */ N_("Smooth"),
/* structName */ "SmoothModifierData",
/* structSize */ sizeof(SmoothModifierData),
/* srna */ &RNA_SmoothModifier,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index d8379cc870a..a49f2609641 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -86,7 +86,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Softbody = {
- /* name */ "Softbody",
+ /* name */ N_("Softbody"),
/* structName */ "SoftbodyModifierData",
/* structSize */ sizeof(SoftbodyModifierData),
/* srna */ &RNA_SoftBodyModifier,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 1f0aee7d689..3e2d590c928 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -241,7 +241,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Solidify = {
- /* name */ "Solidify",
+ /* name */ N_("Solidify"),
/* structName */ "SolidifyModifierData",
/* structSize */ sizeof(SolidifyModifierData),
/* srna */ &RNA_SolidifyModifier,
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 4201bab0326..8faf2bdbea2 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -196,16 +196,21 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
/* Cache settings for lazy CPU evaluation. */
-static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
- Mesh *me,
- SubsurfModifierData *smd)
+static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
+ Mesh *mesh,
+ SubsurfModifierData *smd,
+ SubsurfRuntimeData *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;
- me->runtime.subsurf_session_uuid = smd->modifier.session_uuid;
+
+ runtime_data->has_gpu_subdiv = true;
+ runtime_data->resolution = mesh_settings.resolution;
+ runtime_data->use_optimal_display = mesh_settings.use_optimal_display;
+ runtime_data->calc_loop_normals = false; /* Set at the end of modifier stack evaluation. */
+ runtime_data->use_loop_normals = (smd->flags & eSubsurfModifierFlag_UseCustomNormals);
+
+ mesh->runtime.subsurf_runtime_data = runtime_data;
}
/* Modifier itself. */
@@ -218,13 +223,11 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return result;
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return result;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
/* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
*/
@@ -237,13 +240,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
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(scene, ctx->object, mesh, smd, required_mode)) {
- subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
+ subdiv_cache_mesh_wrapper_settings(ctx, mesh, smd, runtime_data);
return result;
}
}
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@@ -294,15 +296,11 @@ static void deformMatrices(ModifierData *md,
(void)deform_matrices;
SubsurfModifierData *smd = (SubsurfModifierData *)md;
- SubdivSettings subdiv_settings;
- BKE_subsurf_modifier_subdiv_settings_init(
- &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
- if (subdiv_settings.level == 0) {
+ if (!BKE_subsurf_modifier_runtime_init(smd, (ctx->flag & MOD_APPLY_RENDER) != 0)) {
return;
}
- SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
- Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
- smd, &subdiv_settings, mesh, false);
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;
@@ -474,7 +472,7 @@ static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
}
ModifierTypeInfo modifierType_Subsurf = {
- /* name */ "Subdivision",
+ /* name */ N_("Subdivision"),
/* structName */ "SubsurfModifierData",
/* structSize */ sizeof(SubsurfModifierData),
/* srna */ &RNA_SubsurfModifier,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index af1de77d8c9..8cfe3b35949 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -211,7 +211,7 @@ static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
}
ModifierTypeInfo modifierType_Surface = {
- /* name */ "Surface",
+ /* name */ N_("Surface"),
/* structName */ "SurfaceModifierData",
/* structSize */ sizeof(SurfaceModifierData),
/* srna */ &RNA_SurfaceModifier,
diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.c b/source/blender/modifiers/intern/MOD_surfacedeform.c
index 9b0012e3890..ad19ecf5720 100644
--- a/source/blender/modifiers/intern/MOD_surfacedeform.c
+++ b/source/blender/modifiers/intern/MOD_surfacedeform.c
@@ -1449,7 +1449,7 @@ static void surfacedeformModifier_do(ModifierData *md,
}
Object *ob_target = smd->target;
- target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target, false);
+ target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
if (!target) {
BKE_modifier_set_error(ob, md, "No valid target mesh");
return;
@@ -1521,11 +1521,11 @@ static void surfacedeformModifier_do(ModifierData *md,
* added after the original ones. This covers typical case when target was at the subdivision
* level 0 and then subdivision was increased (i.e. for the render purposes). */
- BKE_modifier_set_error(ob,
- md,
- "Target vertices changed from %u to %u, continuing anyway",
- smd->target_verts_num,
- target_verts_num);
+ BKE_modifier_set_warning(ob,
+ md,
+ "Target vertices changed from %u to %u, continuing anyway",
+ smd->target_verts_num,
+ target_verts_num);
/* In theory we only need the `smd->verts_num` vertices in the `targetCos` for evaluation, but
* it is not currently possible to request a subset of coordinates: the API expects that the
@@ -1672,8 +1672,9 @@ static void panelRegister(ARegionType *region_type)
static void blendWrite(BlendWriter *writer, const ID *id_owner, const ModifierData *md)
{
SurfaceDeformModifierData smd = *(const SurfaceDeformModifierData *)md;
+ const bool is_undo = BLO_write_is_undo(writer);
- if (ID_IS_OVERRIDE_LIBRARY(id_owner)) {
+ if (ID_IS_OVERRIDE_LIBRARY(id_owner) && !is_undo) {
BLI_assert(!ID_IS_LINKED(id_owner));
const bool is_local = (md->flag & eModifierFlag_OverrideLibrary_Local) != 0;
if (!is_local) {
@@ -1740,7 +1741,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_SurfaceDeform = {
- /* name */ "SurfaceDeform",
+ /* name */ N_("SurfaceDeform"),
/* structName */ "SurfaceDeformModifierData",
/* structSize */ sizeof(SurfaceDeformModifierData),
/* srna */ &RNA_SurfaceDeformModifier,
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index f1e8ef5bf38..d4faf682cdc 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -139,7 +139,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Triangulate = {
- /* name */ "Triangulate",
+ /* name */ N_("Triangulate"),
/* structName */ "TriangulateModifierData",
/* structSize */ sizeof(TriangulateModifierData),
/* srna */ &RNA_TriangulateModifier,
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index d4d7ecef283..0474d3e47e6 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -349,7 +349,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_UVProject = {
- /* name */ "UVProject",
+ /* name */ N_("UVProject"),
/* structName */ "UVProjectModifierData",
/* structSize */ sizeof(UVProjectModifierData),
/* srna */ &RNA_UVProjectModifier,
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index a15efdaa381..c33b25c38e3 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -308,7 +308,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_UVWarp = {
- /* name */ "UVWarp",
+ /* name */ N_("UVWarp"),
/* structName */ "UVWarpModifierData",
/* structSize */ sizeof(UVWarpModifierData),
/* srna */ &RNA_UVWarpModifier,
diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc
index 059cfdbdd4e..d9b94d79348 100644
--- a/source/blender/modifiers/intern/MOD_volume_displace.cc
+++ b/source/blender/modifiers/intern/MOD_volume_displace.cc
@@ -12,6 +12,8 @@
#include "BKE_texture.h"
#include "BKE_volume.h"
+#include "BLT_translation.h"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -307,7 +309,7 @@ static void modifyGeometrySet(ModifierData *md,
}
ModifierTypeInfo modifierType_VolumeDisplace = {
- /* name */ "Volume Displace",
+ /* name */ N_("Volume Displace"),
/* structName */ "VolumeDisplaceModifierData",
/* structSize */ sizeof(VolumeDisplaceModifierData),
/* srna */ &RNA_VolumeDisplaceModifier,
diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc
index d33687e4d92..3292f73137a 100644
--- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc
+++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc
@@ -12,6 +12,8 @@
#include "BKE_volume.h"
#include "BKE_volume_to_mesh.hh"
+#include "BLT_translation.h"
+
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
@@ -193,7 +195,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
ModifierTypeInfo modifierType_VolumeToMesh = {
- /* name */ "Volume to Mesh",
+ /* name */ N_("Volume to Mesh"),
/* structName */ "VolumeToMeshModifierData",
/* structSize */ sizeof(VolumeToMeshModifierData),
/* srna */ &RNA_VolumeToMeshModifier,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 402d7b2c99e..afdc230a877 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -302,7 +302,6 @@ static void warpModifier_do(WarpModifierData *wmd,
if (tex_co) {
struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
TexResult texres;
- texres.nor = NULL;
BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
fac *= texres.tin;
}
@@ -511,7 +510,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_Warp = {
- /* name */ "Warp",
+ /* name */ N_("Warp"),
/* structName */ "WarpModifierData",
/* structSize */ sizeof(WarpModifierData),
/* srna */ &RNA_WarpModifier,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 73b26dc29cd..b92e3a0fa9d 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -262,7 +262,6 @@ static void waveModifier_do(WaveModifierData *md,
if (tex_co) {
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
TexResult texres;
- texres.nor = NULL;
BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
amplit *= texres.tin;
}
@@ -373,7 +372,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(sub, ptr, "use_normal_z", UI_ITEM_R_TOGGLE, "Z", ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "falloff_radius", 0, "Falloff", ICON_NONE);
+ uiItemR(col, ptr, "falloff_radius", 0, IFACE_("Falloff"), ICON_NONE);
uiItemR(col, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemR(col, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemR(col, ptr, "narrowness", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
@@ -395,7 +394,7 @@ static void position_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(layout, ptr, "start_position_object", 0, IFACE_("Object"), ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "start_position_x", 0, "Start Position X", ICON_NONE);
+ uiItemR(col, ptr, "start_position_x", 0, IFACE_("Start Position X"), ICON_NONE);
uiItemR(col, ptr, "start_position_y", 0, "Y", ICON_NONE);
}
@@ -409,9 +408,9 @@ static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "time_offset", 0, "Offset", ICON_NONE);
- uiItemR(col, ptr, "lifetime", 0, "Life", ICON_NONE);
- uiItemR(col, ptr, "damping_time", 0, "Damping", ICON_NONE);
+ uiItemR(col, ptr, "time_offset", 0, IFACE_("Offset"), ICON_NONE);
+ uiItemR(col, ptr, "lifetime", 0, IFACE_("Life"), ICON_NONE);
+ uiItemR(col, ptr, "damping_time", 0, IFACE_("Damping"), ICON_NONE);
uiItemR(col, ptr, "speed", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
@@ -463,7 +462,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Wave = {
- /* name */ "Wave",
+ /* name */ N_("Wave"),
/* structName */ "WaveModifierData",
/* structSize */ sizeof(WaveModifierData),
/* srna */ &RNA_WaveModifier,
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index d436acb8ad5..af992c00097 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -726,7 +726,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_WeightedNormal = {
- /* name */ "WeightedNormal",
+ /* name */ N_("WeightedNormal"),
/* structName */ "WeightedNormalModifierData",
/* structSize */ sizeof(WeightedNormalModifierData),
/* srna */ &RNA_WeightedNormalModifier,
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index 65393370268..3302384568b 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -162,7 +162,6 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT;
- texres.nor = NULL;
BKE_texture_get_value(scene, texture, tex_co[idx], &texres, do_color_manage);
/* Get the good channel value... */
switch (tex_use_channel) {
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index e1b43157adb..f6e0cd9303d 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -397,7 +397,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_WeightVGEdit = {
- /* name */ "VertexWeightEdit",
+ /* name */ N_("VertexWeightEdit"),
/* structName */ "WeightVGEditModifierData",
/* structSize */ sizeof(WeightVGEditModifierData),
/* srna */ &RNA_VertexWeightEditModifier,
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index b827d41e80a..49088d42a5e 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -496,7 +496,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_WeightVGMix = {
- /* name */ "VertexWeightMix",
+ /* name */ N_("VertexWeightMix"),
/* structName */ "WeightVGMixModifierData",
/* structSize */ sizeof(WeightVGMixModifierData),
/* srna */ &RNA_VertexWeightMixModifier,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 1bea5b93c97..b68d36366fd 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -544,7 +544,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const bool use_trgt_faces = (wmd->proximity_flags & MOD_WVG_PROXIMITY_GEOM_FACES) != 0;
if (use_trgt_verts || use_trgt_edges || use_trgt_faces) {
- Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(obr, false);
+ Mesh *target_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(obr);
/* We must check that we do have a valid target_mesh! */
if (target_mesh != NULL) {
@@ -737,7 +737,7 @@ static void blendRead(BlendDataReader *reader, ModifierData *md)
}
ModifierTypeInfo modifierType_WeightVGProximity = {
- /* name */ "VertexWeightProximity",
+ /* name */ N_("VertexWeightProximity"),
/* structName */ "WeightVGProximityModifierData",
/* structSize */ sizeof(WeightVGProximityModifierData),
/* srna */ &RNA_VertexWeightProximityModifier,
diff --git a/source/blender/modifiers/intern/MOD_weld.cc b/source/blender/modifiers/intern/MOD_weld.cc
index 93d4b56176c..19b0bf62fea 100644
--- a/source/blender/modifiers/intern/MOD_weld.cc
+++ b/source/blender/modifiers/intern/MOD_weld.cc
@@ -185,7 +185,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Weld = {
- /* name */ "Weld",
+ /* name */ N_("Weld"),
/* structName */ "WeldModifierData",
/* structSize */ sizeof(WeldModifierData),
/* srna */ &RNA_WeldModifier,
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index b657ea87244..5799da5d156 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -165,7 +165,7 @@ static void panelRegister(ARegionType *region_type)
}
ModifierTypeInfo modifierType_Wireframe = {
- /* name */ "Wireframe",
+ /* name */ N_("Wireframe"),
/* structName */ "WireframeModifierData",
/* structSize */ sizeof(WireframeModifierData),
/* srna */ &RNA_WireframeModifier,
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index 5d782674f16..58126c5722d 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -169,7 +169,7 @@ void ntreeCompositClearTags(struct bNodeTree *ntree);
struct bNodeSocket *ntreeCompositOutputFileAddSocket(struct bNodeTree *ntree,
struct bNode *node,
const char *name,
- struct ImageFormatData *im_format);
+ const struct ImageFormatData *im_format);
int ntreeCompositOutputFileRemoveActiveSocket(struct bNodeTree *ntree, struct bNode *node);
void ntreeCompositOutputFileSetPath(struct bNode *node,
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 064112b7efd..86c276fbd6f 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -47,6 +47,7 @@ void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_curve_to_mesh(void);
void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_trim(void);
+void register_node_type_geo_deform_curves_on_surface(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_duplicate_elements(void);
void register_node_type_geo_distribute_points_on_faces(void);
@@ -54,6 +55,7 @@ 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_field_on_domain(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);
@@ -62,6 +64,8 @@ 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_instance_rotation(void);
+void register_node_type_geo_input_instance_scale(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);
@@ -99,7 +103,9 @@ void register_node_type_geo_mesh_primitive_uv_sphere(void);
void register_node_type_geo_mesh_subdivide(void);
void register_node_type_geo_mesh_to_curve(void);
void register_node_type_geo_mesh_to_points(void);
+void register_node_type_geo_mesh_to_volume(void);
void register_node_type_geo_object_info(void);
+void register_node_type_geo_points(void);
void register_node_type_geo_points_to_vertices(void);
void register_node_type_geo_points_to_volume(void);
void register_node_type_geo_proximity(void);
@@ -133,7 +139,10 @@ 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_cube(void);
void register_node_type_geo_volume_to_mesh(void);
+void register_node_type_geo_uv_pack_islands(void);
+void register_node_type_geo_uv_unwrap(void);
#ifdef __cplusplus
}
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index bac4d0165e9..0d5ba6cf5db 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -5,34 +5,36 @@
#include "FN_field.hh"
#include "FN_multi_function_builder.hh"
-#include "BKE_attribute_access.hh"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
-#include "BKE_geometry_set_instances.hh"
#include "DNA_node_types.h"
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_nodes_eval_log.hh"
-#include "GEO_realize_instances.hh"
-
struct Depsgraph;
struct ModifierData;
namespace blender::nodes {
using bke::AnonymousAttributeFieldInput;
+using bke::AttributeAccessor;
using bke::AttributeFieldInput;
using bke::AttributeIDRef;
+using bke::AttributeKind;
+using bke::AttributeMetaData;
+using bke::AttributeReader;
+using bke::AttributeWriter;
+using bke::GAttributeReader;
+using bke::GAttributeWriter;
using bke::GeometryComponentFieldContext;
using bke::GeometryFieldInput;
-using bke::OutputAttribute;
-using bke::OutputAttribute_Typed;
-using bke::ReadAttributeLookup;
+using bke::GSpanAttributeWriter;
+using bke::MutableAttributeAccessor;
+using bke::SpanAttributeWriter;
using bke::StrongAnonymousAttributeID;
using bke::WeakAnonymousAttributeID;
-using bke::WriteAttributeLookup;
using fn::Field;
using fn::FieldContext;
using fn::FieldEvaluator;
@@ -40,7 +42,7 @@ using fn::FieldInput;
using fn::FieldOperation;
using fn::GField;
using fn::ValueOrField;
-using geometry_nodes_eval_log::NamedAttributeUsage;
+using geometry_nodes_eval_log::eNamedAttrUsage;
using geometry_nodes_eval_log::NodeWarningType;
/**
@@ -298,52 +300,11 @@ class GeoNodeExecParams {
*/
void error_message_add(const NodeWarningType type, std::string message) const;
- /**
- * Creates a read-only attribute based on node inputs. The method automatically detects which
- * input socket with the given name is available.
- *
- * \note This will add an error message if the string socket is active and
- * the input attribute does not exist.
- */
- GVArray get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const;
-
- template<typename T>
- 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>());
- GVArray varray = this->get_input_attribute(name, component, domain, type, &default_value);
- return varray.typed<T>();
- }
-
- /**
- * Get the type of an input property or the associated constant socket types with the
- * same names. Fall back to the default value if no attribute exists with the name.
- */
- CustomDataType get_input_attribute_data_type(const StringRef name,
- 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,
- AttributeDomain default_domain) const;
-
std::string attribute_producer_name() const;
void set_default_remaining_outputs();
- void used_named_attribute(std::string attribute_name, NamedAttributeUsage usage);
+ void used_named_attribute(std::string attribute_name, eNamedAttrUsage usage);
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 2917861f084..05c97c3903d 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -90,8 +90,8 @@ class GFieldValueLog : public ValueLog {
struct GeometryAttributeInfo {
std::string name;
/** Can be empty when #name does not actually exist on a geometry yet. */
- std::optional<AttributeDomain> domain;
- std::optional<CustomDataType> data_type;
+ std::optional<eAttrDomain> domain;
+ std::optional<eCustomDataType> data_type;
};
/** Contains information about a geometry set. In most cases this does not store the entire
@@ -171,17 +171,17 @@ struct ValueOfSockets {
destruct_ptr<ValueLog> value;
};
-enum class NamedAttributeUsage {
+enum class eNamedAttrUsage {
None = 0,
Read = 1 << 0,
Write = 1 << 1,
Remove = 1 << 2,
};
-ENUM_OPERATORS(NamedAttributeUsage, NamedAttributeUsage::Remove);
+ENUM_OPERATORS(eNamedAttrUsage, eNamedAttrUsage::Remove);
struct UsedNamedAttribute {
std::string name;
- NamedAttributeUsage usage;
+ eNamedAttrUsage usage;
};
struct NodeWithUsedNamedAttribute {
@@ -219,7 +219,7 @@ class LocalGeoLogger {
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);
- void log_used_named_attribute(DNode node, std::string attribute_name, NamedAttributeUsage usage);
+ void log_used_named_attribute(DNode node, std::string attribute_name, eNamedAttrUsage usage);
/**
* 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.
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 61d1d11d859..257aa5f4110 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -41,6 +41,7 @@
#include "BLI_vector.hh"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "DNA_node_types.h"
@@ -597,7 +598,7 @@ inline bNodeType *NodeRef::typeinfo() const
inline const NodeDeclaration *NodeRef::declaration() const
{
nodeDeclarationEnsure(this->tree().btree(), bnode_);
- return bnode_->declaration;
+ return bnode_->runtime->declaration;
}
inline int NodeRef::id() const
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index e0a4d241b3b..71d8f014399 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -17,111 +17,111 @@
/* WARNING! If you edit those strings, please do the same in relevant nodes files (under blender/nodes/...)! */
/* Tree type Node ID RNA def function Enum name Struct name UI Name UI Description */
-DefNode(Node, NODE_FRAME, def_frame, "FRAME", Frame, "Frame", "" )
-DefNode(Node, NODE_GROUP, def_group, "GROUP", Group, "Group", "" )
-DefNode(Node, NODE_GROUP_INPUT, def_group_input, "GROUP_INPUT", GroupInput, "Group Input", "" )
-DefNode(Node, NODE_GROUP_OUTPUT, def_group_output, "GROUP_OUTPUT", GroupOutput, "Group Output", "" )
-DefNode(Node, NODE_REROUTE, 0, "REROUTE", Reroute, "Reroute", "" )
+DefNode(Node, NODE_FRAME, def_frame, "FRAME", Frame, "Frame", "Collect related nodes together in a common area. Useful for organization when the re-usability of a node group is not required")
+DefNode(Node, NODE_GROUP, def_group, "GROUP", Group, "Group", "")
+DefNode(Node, NODE_GROUP_INPUT, def_group_input, "GROUP_INPUT", GroupInput, "Group Input", "Expose connected data from inside a node group as inputs to its interface")
+DefNode(Node, NODE_GROUP_OUTPUT, def_group_output, "GROUP_OUTPUT", GroupOutput, "Group Output", "Output data from inside of a node group")
+DefNode(Node, NODE_REROUTE, 0, "REROUTE", Reroute, "Reroute", "A single-socket organization tool that supports one input and multiple outputs")
-DefNode(ShaderNode, SH_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
-DefNode(ShaderNode, SH_NODE_VALUE, 0, "VALUE", Value, "Value", "" )
-DefNode(ShaderNode, SH_NODE_MIX_RGB, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "" )
-DefNode(ShaderNode, SH_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "" )
-DefNode(ShaderNode, SH_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "" )
-DefNode(ShaderNode, SH_NODE_SHADERTORGB, 0, "SHADERTORGB", ShaderToRGB, "Shader to RGB", "" )
-DefNode(ShaderNode, SH_NODE_NORMAL, 0, "NORMAL", Normal, "Normal", "" )
-DefNode(ShaderNode, SH_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "" )
-DefNode(ShaderNode, SH_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Bright Contrast", "" )
-DefNode(ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPING", Mapping, "Mapping", "" )
-DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "" )
-DefNode(ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "" )
-DefNode(ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "" )
-DefNode(ShaderNode, SH_NODE_MAP_RANGE, def_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
-DefNode(ShaderNode, SH_NODE_CLAMP, def_clamp, "CLAMP", Clamp, "Clamp", "" )
-DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" )
-DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
-DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )
-DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
-DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
-DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "" )
-DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value", "" )
+DefNode(ShaderNode, SH_NODE_RGB, 0, "RGB", RGB, "RGB", "A color picker")
+DefNode(ShaderNode, SH_NODE_VALUE, 0, "VALUE", Value, "Value", "Used to Input numerical values to other nodes in the tree")
+DefNode(ShaderNode, SH_NODE_MIX_RGB, def_mix_rgb, "MIX_RGB", MixRGB, "MixRGB", "Mix two input colors")
+DefNode(ShaderNode, SH_NODE_VALTORGB, def_colorramp, "VALTORGB", ValToRGB, "ColorRamp", "Map values to colors with the use of a gradient")
+DefNode(ShaderNode, SH_NODE_RGBTOBW, 0, "RGBTOBW", RGBToBW, "RGB to BW", "Convert a color's luminance to a grayscale value")
+DefNode(ShaderNode, SH_NODE_SHADERTORGB, 0, "SHADERTORGB", ShaderToRGB, "Shader to RGB", "Convert rendering effect (such as light and shadow) to color. Typically used for non-photorealistic rendering, to apply additional effects on the output of BSDFs.\nNote: only supported for Eevee")
+DefNode(ShaderNode, SH_NODE_NORMAL, 0, "NORMAL", Normal, "Normal", "Generate a normal vector and a dot product")
+DefNode(ShaderNode, SH_NODE_GAMMA, 0, "GAMMA", Gamma, "Gamma", "Apply a gamma correction")
+DefNode(ShaderNode, SH_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Bright Contrast", "Control the brightness and contrast of the input color")
+DefNode(ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPING", Mapping, "Mapping", "Transform the input vector by applying translation, rotation, and scale")
+DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "Map an input vectors to curves, used to fine-tune the interpolation of the input")
+DefNode(ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "Apply color corrections for each color channel")
+DefNode(ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "Retrieve information about the camera and how it relates to the current shading point's position")
+DefNode(ShaderNode, SH_NODE_MAP_RANGE, def_map_range, "MAP_RANGE", MapRange, "Map Range", "Remap a value from a range to a target range")
+DefNode(ShaderNode, SH_NODE_CLAMP, def_clamp, "CLAMP", Clamp, "Clamp", "Clamp a value between a minimum and a maximum")
+DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "Perform math operations")
+DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "Perform vector math operation")
+DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "")
+DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "Invert a color, producing a negative")
+DefNode(ShaderNode, SH_NODE_SEPRGB_LEGACY, 0, "SEPRGB", SeparateRGB, "Separate RGB", "Split a color into its red, green, and blue channels (Deprecated)")
+DefNode(ShaderNode, SH_NODE_COMBRGB_LEGACY, 0, "COMBRGB", CombineRGB, "Combine RGB", "Generate a color from its red, green, and blue channels (Deprecated)")
+DefNode(ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_SAT", HueSaturation, "Hue Saturation Value","Apply a color transformation in the HSV color model")
-DefNode(ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "" )
-DefNode(ShaderNode, SH_NODE_EEVEE_SPECULAR, 0, "EEVEE_SPECULAR", EeveeSpecular, "Specular BSDF", "" )
-DefNode(ShaderNode, SH_NODE_OUTPUT_LIGHT, def_sh_output, "OUTPUT_LIGHT", OutputLight, "Light Output", "" )
-DefNode(ShaderNode, SH_NODE_OUTPUT_WORLD, def_sh_output, "OUTPUT_WORLD", OutputWorld, "World Output", "" )
-DefNode(ShaderNode, SH_NODE_OUTPUT_LINESTYLE, def_sh_output_linestyle,"OUTPUT_LINESTYLE", OutputLineStyle, "Line Style Output", "" )
-DefNode(ShaderNode, SH_NODE_FRESNEL, 0, "FRESNEL", Fresnel, "Fresnel", "" )
-DefNode(ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LAYER_WEIGHT", LayerWeight, "Layer Weight", "" )
-DefNode(ShaderNode, SH_NODE_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "" )
-DefNode(ShaderNode, SH_NODE_ADD_SHADER, 0, "ADD_SHADER", AddShader, "Add Shader", "" )
-DefNode(ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATTRIBUTE", Attribute, "Attribute", "" )
-DefNode(ShaderNode, SH_NODE_AMBIENT_OCCLUSION, def_sh_ambient_occlusion,"AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "" )
-DefNode(ShaderNode, SH_NODE_BACKGROUND, 0, "BACKGROUND", Background, "Background", "" )
-DefNode(ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_TOON, def_toon, "BSDF_TOON", BsdfToon, "Toon BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_HAIR, def_hair, "BSDF_HAIR", BsdfHair, "Hair BSDF", "" )
-DefNode(ShaderNode, SH_NODE_BSDF_HAIR_PRINCIPLED, def_hair_principled, "BSDF_HAIR_PRINCIPLED", BsdfHairPrincipled, "Principled Hair BSDF", "")
-DefNode(ShaderNode, SH_NODE_SUBSURFACE_SCATTERING, def_sh_subsurface, "SUBSURFACE_SCATTERING",SubsurfaceScattering,"Subsurface Scattering","")
-DefNode(ShaderNode, SH_NODE_VOLUME_ABSORPTION, 0, "VOLUME_ABSORPTION", VolumeAbsorption, "Volume Absorption", "" )
-DefNode(ShaderNode, SH_NODE_VOLUME_SCATTER, 0, "VOLUME_SCATTER", VolumeScatter, "Volume Scatter", "" )
-DefNode(ShaderNode, SH_NODE_VOLUME_PRINCIPLED, 0, "PRINCIPLED_VOLUME", VolumePrincipled, "Principled Volume", "" )
-DefNode(ShaderNode, SH_NODE_EMISSION, 0, "EMISSION", Emission, "Emission", "" )
-DefNode(ShaderNode, SH_NODE_NEW_GEOMETRY, 0, "NEW_GEOMETRY", NewGeometry, "Geometry", "" )
-DefNode(ShaderNode, SH_NODE_LIGHT_PATH, 0, "LIGHT_PATH", LightPath, "Light Path", "" )
-DefNode(ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIGHT_FALLOFF", LightFalloff, "Light Falloff", "" )
-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, "Curves 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", "" )
-DefNode(ShaderNode, SH_NODE_BLACKBODY, 0, "BLACKBODY", Blackbody, "Blackbody", "" )
-DefNode(ShaderNode, SH_NODE_BUMP, def_sh_bump, "BUMP", Bump, "Bump", "" )
-DefNode(ShaderNode, SH_NODE_NORMAL_MAP, def_sh_normal_map, "NORMAL_MAP", NormalMap, "Normal Map", "" )
-DefNode(ShaderNode, SH_NODE_TANGENT, def_sh_tangent, "TANGENT", Tangent, "Tangent", "" )
-DefNode(ShaderNode, SH_NODE_SCRIPT, def_sh_script, "SCRIPT", Script, "Script", "" )
-DefNode(ShaderNode, SH_NODE_TEX_IMAGE, def_sh_tex_image, "TEX_IMAGE", TexImage, "Image Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_ENVIRONMENT, def_sh_tex_environment, "TEX_ENVIRONMENT", TexEnvironment, "Environment Texture","" )
-DefNode(ShaderNode, SH_NODE_TEX_SKY, def_sh_tex_sky, "TEX_SKY", TexSky, "Sky Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_GRADIENT, def_sh_tex_gradient, "TEX_GRADIENT", TexGradient, "Gradient Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_NOISE, def_sh_tex_noise, "TEX_NOISE", TexNoise, "Noise Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_MAGIC, def_sh_tex_magic, "TEX_MAGIC", TexMagic, "Magic Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_WAVE, def_sh_tex_wave, "TEX_WAVE", TexWave, "Wave Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_MUSGRAVE, def_sh_tex_musgrave, "TEX_MUSGRAVE", TexMusgrave, "Musgrave Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_VORONOI, def_sh_tex_voronoi, "TEX_VORONOI", TexVoronoi, "Voronoi Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_CHECKER, def_sh_tex_checker, "TEX_CHECKER", TexChecker, "Checker Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_BRICK, def_sh_tex_brick, "TEX_BRICK", TexBrick, "Brick Texture", "" )
-DefNode(ShaderNode, SH_NODE_TEX_POINTDENSITY, def_sh_tex_pointdensity,"TEX_POINTDENSITY", TexPointDensity, "Point Density", "" )
-DefNode(ShaderNode, SH_NODE_TEX_COORD, def_sh_tex_coord, "TEX_COORD", TexCoord, "Texture Coordinate","" )
-DefNode(ShaderNode, SH_NODE_VECTOR_ROTATE, def_sh_vector_rotate, "VECTOR_ROTATE", VectorRotate, "Vector Rotate", "" )
-DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VECT_TRANSFORM", VectorTransform, "Vector Transform", "" )
-DefNode(ShaderNode, SH_NODE_SEPHSV_LEGACY, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
-DefNode(ShaderNode, SH_NODE_COMBHSV_LEGACY, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
-DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" )
-DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Color Attribute", "" )
-DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" )
-DefNode(ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" )
-DefNode(ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" )
-DefNode(ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "" )
-DefNode(ShaderNode, SH_NODE_DISPLACEMENT, def_sh_displacement, "DISPLACEMENT", Displacement, "Displacement", "" )
-DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"VECTOR_DISPLACEMENT",VectorDisplacement,"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(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "" )
-DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "" )
+DefNode(ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "Output surface material information for use in rendering")
+DefNode(ShaderNode, SH_NODE_EEVEE_SPECULAR, 0, "EEVEE_SPECULAR", EeveeSpecular, "Specular BSDF", "Similar to the Principled BSDF node but uses the specular workflow instead of metallic, which functions by specifying the facing (along normal) reflection color. Energy is not conserved, so the result may not be physically accurate")
+DefNode(ShaderNode, SH_NODE_OUTPUT_LIGHT, def_sh_output, "OUTPUT_LIGHT", OutputLight, "Light Output", "Output light information to a light object")
+DefNode(ShaderNode, SH_NODE_OUTPUT_WORLD, def_sh_output, "OUTPUT_WORLD", OutputWorld, "World Output", "Output light color information to the scene's World")
+DefNode(ShaderNode, SH_NODE_OUTPUT_LINESTYLE, def_sh_output_linestyle,"OUTPUT_LINESTYLE", OutputLineStyle, "Line Style Output", "")
+DefNode(ShaderNode, SH_NODE_FRESNEL, 0, "FRESNEL", Fresnel, "Fresnel", "Produce a blending factor depending on the angle between the surface normal and the view direction using Fresnel equations.\nTypically used for mixing reflections at grazing angles")
+DefNode(ShaderNode, SH_NODE_LAYER_WEIGHT, 0, "LAYER_WEIGHT", LayerWeight, "Layer Weight", "Produce a blending factor depending on the angle between the surface normal and the view direction.\nTypically used for layering shaders with the Mix Shader node")
+DefNode(ShaderNode, SH_NODE_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "Mix two shaders together. Typically used for material layering")
+DefNode(ShaderNode, SH_NODE_ADD_SHADER, 0, "ADD_SHADER", AddShader, "Add Shader", "Add two Shaders together")
+DefNode(ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "ATTRIBUTE", Attribute, "Attribute", "Retrieve attributes attached to objects or geometry")
+DefNode(ShaderNode, SH_NODE_AMBIENT_OCCLUSION, def_sh_ambient_occlusion,"AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "Compute how much the hemisphere above the shading point is occluded, for example to add weathering effects to corners.\nNote: For Cycles, this may slow down renders significantly")
+DefNode(ShaderNode, SH_NODE_BACKGROUND, 0, "BACKGROUND", Background, "Background", "Add background light emission.\nNote: This node should only be used for the world surface output")
+DefNode(ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "Create a \"hole\" in the image with zero alpha transparency, which is useful for compositing.\nNote: the holdout shader can only create alpha when transparency is enabled in the film settings")
+DefNode(ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "Glossy reflection with separate control over U and V direction roughness")
+DefNode(ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "Lambertian and Oren-Nayar diffuse reflection")
+DefNode(ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled BSDF", "Physically-based, easy-to-use shader for rendering surface materials, based on the Disney principled model also known as the \"PBR\" shader")
+DefNode(ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "Reflection with microfacet distribution, used for materials such as metal or mirrors")
+DefNode(ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "Glass-like shader mixing refraction and reflection at grazing angles")
+DefNode(ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "Glossy refraction with sharp or microfacet distribution, typically used for materials that transmit light")
+DefNode(ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "Lambertian diffuse transmission")
+DefNode(ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "Transparency without refraction, passing straight through the surface as if there were no geometry")
+DefNode(ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "Reflection for materials such as cloth.\nTypically mixed with other shaders (such as a Diffuse Shader) and is not particularly useful on its own")
+DefNode(ShaderNode, SH_NODE_BSDF_TOON, def_toon, "BSDF_TOON", BsdfToon, "Toon BSDF", "Diffuse and Glossy shaders with cartoon light effects")
+DefNode(ShaderNode, SH_NODE_BSDF_HAIR, def_hair, "BSDF_HAIR", BsdfHair, "Hair BSDF", "Reflection and transmission shaders optimized for hair rendering")
+DefNode(ShaderNode, SH_NODE_BSDF_HAIR_PRINCIPLED, def_hair_principled, "BSDF_HAIR_PRINCIPLED", BsdfHairPrincipled, "Principled Hair BSDF", "Physically-based, easy-to-use shader for rendering hair and fur")
+DefNode(ShaderNode, SH_NODE_SUBSURFACE_SCATTERING, def_sh_subsurface, "SUBSURFACE_SCATTERING",SubsurfaceScattering,"Subsurface Scattering","Subsurface multiple scattering shader to simulate light entering the surface and bouncing internally.\nTypically used for materials such as skin, wax, marble or milk")
+DefNode(ShaderNode, SH_NODE_VOLUME_ABSORPTION, 0, "VOLUME_ABSORPTION", VolumeAbsorption, "Volume Absorption", "Absorb light as it passes through the volume")
+DefNode(ShaderNode, SH_NODE_VOLUME_SCATTER, 0, "VOLUME_SCATTER", VolumeScatter, "Volume Scatter", "Scatter light as it passes through the volume, often used to add fog to a scene")
+DefNode(ShaderNode, SH_NODE_VOLUME_PRINCIPLED, 0, "PRINCIPLED_VOLUME", VolumePrincipled, "Principled Volume", "Combine all volume shading components into a single easy to use node")
+DefNode(ShaderNode, SH_NODE_EMISSION, 0, "EMISSION", Emission, "Emission", "Lambertian emission shader")
+DefNode(ShaderNode, SH_NODE_NEW_GEOMETRY, 0, "NEW_GEOMETRY", NewGeometry, "Geometry", "Retrieve geometric information about the current shading point")
+DefNode(ShaderNode, SH_NODE_LIGHT_PATH, 0, "LIGHT_PATH", LightPath, "Light Path", "Retrieve the type of incoming ray for which the shader is being executed.\nTypically used for non-physically-based tricks")
+DefNode(ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIGHT_FALLOFF", LightFalloff, "Light Falloff", "Manipulate how light intensity decreases over distance. Typically used for non-physically-based effects; in reality light always falls off quadratically")
+DefNode(ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "Retrieve information about the object instance")
+DefNode(ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "Retrieve the data of the particle that spawned the object instance, for example to give variation to multiple instances of an object")
+DefNode(ShaderNode, SH_NODE_HAIR_INFO, 0, "HAIR_INFO", HairInfo, "Curves Info", "Retrieve hair curve information")
+DefNode(ShaderNode, SH_NODE_POINT_INFO, 0, "POINT_INFO", PointInfo, "Point Info", "Retrieve information about points in a point cloud")
+DefNode(ShaderNode, SH_NODE_VOLUME_INFO, 0, "VOLUME_INFO", VolumeInfo, "Volume Info", "Read volume data attributes from volume grids")
+DefNode(ShaderNode, SH_NODE_WIREFRAME, def_sh_tex_wireframe, "WIREFRAME", Wireframe, "Wireframe", "Retrieve the edges of an object as it appears to Cycles.\nNote: as meshes are triangulated before being processed by Cycles, topology will always appear triangulated")
+DefNode(ShaderNode, SH_NODE_WAVELENGTH, 0, "WAVELENGTH", Wavelength, "Wavelength", "Convert a wavelength value to an RGB value")
+DefNode(ShaderNode, SH_NODE_BLACKBODY, 0, "BLACKBODY", Blackbody, "Blackbody", "Convert a blackbody temperature to an RGB value")
+DefNode(ShaderNode, SH_NODE_BUMP, def_sh_bump, "BUMP", Bump, "Bump", "Generate a perturbed normal from a height texture for bump mapping. Typically used for faking highly detailed surfaces")
+DefNode(ShaderNode, SH_NODE_NORMAL_MAP, def_sh_normal_map, "NORMAL_MAP", NormalMap, "Normal Map", "Generate a perturbed normal from an RGB normal map image. Typically used for faking highly detailed surfaces")
+DefNode(ShaderNode, SH_NODE_TANGENT, def_sh_tangent, "TANGENT", Tangent, "Tangent", "Generate a tangent direction for the Anisotropic BSDF")
+DefNode(ShaderNode, SH_NODE_SCRIPT, def_sh_script, "SCRIPT", Script, "Script", "Generate an OSL shader from a file or text data-block.\nNote: OSL shaders are not supported on the GPU")
+DefNode(ShaderNode, SH_NODE_TEX_IMAGE, def_sh_tex_image, "TEX_IMAGE", TexImage, "Image Texture", "Sample an image file as a texture")
+DefNode(ShaderNode, SH_NODE_TEX_ENVIRONMENT, def_sh_tex_environment, "TEX_ENVIRONMENT", TexEnvironment, "Environment Texture","Sample an image file as an environment texture. Typically used to light the scene with the background node")
+DefNode(ShaderNode, SH_NODE_TEX_SKY, def_sh_tex_sky, "TEX_SKY", TexSky, "Sky Texture", "Generate a procedural sky texture")
+DefNode(ShaderNode, SH_NODE_TEX_GRADIENT, def_sh_tex_gradient, "TEX_GRADIENT", TexGradient, "Gradient Texture", "Generate interpolated color and intensity values based on the input vector")
+DefNode(ShaderNode, SH_NODE_TEX_NOISE, def_sh_tex_noise, "TEX_NOISE", TexNoise, "Noise Texture", "Generate fractal Perlin noise")
+DefNode(ShaderNode, SH_NODE_TEX_MAGIC, def_sh_tex_magic, "TEX_MAGIC", TexMagic, "Magic Texture", "Generate a psychedelic color texture")
+DefNode(ShaderNode, SH_NODE_TEX_WAVE, def_sh_tex_wave, "TEX_WAVE", TexWave, "Wave Texture", "Generate procedural bands or rings with noise")
+DefNode(ShaderNode, SH_NODE_TEX_MUSGRAVE, def_sh_tex_musgrave, "TEX_MUSGRAVE", TexMusgrave, "Musgrave Texture", "Generate fractal Perlin noise. Allows for greater control over how octaves are combined than the Noise Texture node")
+DefNode(ShaderNode, SH_NODE_TEX_VORONOI, def_sh_tex_voronoi, "TEX_VORONOI", TexVoronoi, "Voronoi Texture", "Generate Worley noise based on the distance to random points. Typically used to generate textures such as stones, water, or biological cells")
+DefNode(ShaderNode, SH_NODE_TEX_CHECKER, def_sh_tex_checker, "TEX_CHECKER", TexChecker, "Checker Texture", "Generate a checkerboard texture")
+DefNode(ShaderNode, SH_NODE_TEX_BRICK, def_sh_tex_brick, "TEX_BRICK", TexBrick, "Brick Texture", "Generate a procedural texture producing bricks")
+DefNode(ShaderNode, SH_NODE_TEX_POINTDENSITY, def_sh_tex_pointdensity,"TEX_POINTDENSITY", TexPointDensity, "Point Density", "Generate a volumetric point for each particle or vertex of another object")
+DefNode(ShaderNode, SH_NODE_TEX_COORD, def_sh_tex_coord, "TEX_COORD", TexCoord, "Texture Coordinate","Retrieve multiple types of texture coordinates.\nTypically used as inputs for texture nodes")
+DefNode(ShaderNode, SH_NODE_VECTOR_ROTATE, def_sh_vector_rotate, "VECTOR_ROTATE", VectorRotate, "Vector Rotate", "Rotate a vector around a pivot point (center)")
+DefNode(ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VECT_TRANSFORM", VectorTransform, "Vector Transform", "Convert a vector, point, or normal between world, camera, and object coordinate space")
+DefNode(ShaderNode, SH_NODE_SEPHSV_LEGACY, 0, "SEPHSV", SeparateHSV, "Separate HSV", "Split a color into its hue, saturation, and value channels")
+DefNode(ShaderNode, SH_NODE_COMBHSV_LEGACY, 0, "COMBHSV", CombineHSV, "Combine HSV", "Create a color from its hue, saturation, and value channels")
+DefNode(ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "Retrieve a UV map from the geometry, or the default fallback if none is specified")
+DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Color Attribute", "Retrieve a color attribute, or the default fallback if none is specified")
+DefNode(ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "")
+DefNode(ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "Split a vector into its X, Y, and Z components")
+DefNode(ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "Create a vector from X, Y, and Z components")
+DefNode(ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "Generates normals with round corners.\nNote: only supported in Cycles, and may slow down renders")
+DefNode(ShaderNode, SH_NODE_DISPLACEMENT, def_sh_displacement, "DISPLACEMENT", Displacement, "Displacement", "Displace the surface along the surface normal")
+DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"VECTOR_DISPLACEMENT",VectorDisplacement,"Vector Displacement","Displace the surface along an arbitrary direction")
+DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "Used to match real world lights with IES files, which store the directional intensity distribution of light sources")
+DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "Return a random value or color based on an input seed")
+DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "Arbitrary Output Variables.\nProvide custom render passes for arbitrary shader node outputs")
+DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "Map an input float to a curve and outputs a float value")
+DefNode(ShaderNode, SH_NODE_COMBINE_COLOR, def_sh_combsep_color, "COMBINE_COLOR", CombineColor, "Combine Color", "Create a color from individual components using multiple models")
+DefNode(ShaderNode, SH_NODE_SEPARATE_COLOR, def_sh_combsep_color, "SEPARATE_COLOR", SeparateColor, "Separate Color", "Split a color into its individual components using multiple models")
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
@@ -301,6 +301,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", Sp
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_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
+DefNode(GeometryNode, GEO_NODE_DEFORM_CURVES_ON_SURFACE, 0, "DEFORM_CURVES_ON_SURFACE", DeformCurvesOnSurface, "Deform Curves on Surface", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_DUPLICATE_ELEMENTS, def_geo_duplicate_elements, "DUPLICATE_ELEMENTS", DuplicateElements, "Duplicate Elements", "")
DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "")
@@ -308,6 +309,7 @@ DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCU
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_FIELD_ON_DOMAIN, def_geo_field_on_domain, "FIELD_ON_DOMAIN", FieldOnDomain, "Field on Domain", "")
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", "")
@@ -318,6 +320,8 @@ DefNode(GeometryNode, GEO_NODE_INPUT_CURVE_HANDLES, 0, "INPUT_CURVE_HANDLES", In
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_INSTANCE_ROTATION, 0, "INPUT_INSTANCE_ROTATION", InputInstanceRotation, "Instance Rotation", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_INSTANCE_SCALE, 0, "INPUT_INSTANCE_SCALE", InputInstanceScale, "Instance Scale", "")
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", "")
@@ -354,7 +358,9 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRI
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
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_MESH_TO_VOLUME, def_geo_mesh_to_volume, "MESH_TO_VOLUME", MeshToVolume, "Mesh To Volume", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
+DefNode(GeometryNode, GEO_NODE_POINTS, 0, "POINTS", Points, "Points", "")
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", "")
@@ -395,7 +401,10 @@ DefNode(GeometryNode, GEO_NODE_TRANSLATE_INSTANCES, 0, "TRANSLATE_INSTANCES", Tr
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
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_CUBE, 0, "VOLUME_CUBE", VolumeCube, "Volume Cube", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
+DefNode(GeometryNode, GEO_NODE_UV_PACK_ISLANDS, 0, "UV_PACK_ISLANDS", UVPackIslands, "Pack UV Islands", "")
+DefNode(GeometryNode, GEO_NODE_UV_UNWRAP, def_geo_uv_unwrap, "UV_UNWRAP", UVUnwrap, "UV Unwrap", "")
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index 0b75dd9cef3..32b5d98a556 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -15,6 +15,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_node_tree_update.h"
diff --git a/source/blender/nodes/composite/node_composite_util.hh b/source/blender/nodes/composite/node_composite_util.hh
index 3e9c43aa7d2..14210cedc95 100644
--- a/source/blender/nodes/composite/node_composite_util.hh
+++ b/source/blender/nodes/composite/node_composite_util.hh
@@ -8,24 +8,12 @@
#pragma once
#include "DNA_ID.h"
-#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
#include "BLT_translation.h"
-#include "BKE_colorband.h"
-#include "BKE_colortools.h"
-#include "BKE_image.h"
-#include "BKE_texture.h"
-#include "BKE_tracking.h"
-
#include "node_util.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "RE_pipeline.h"
-
#include "NOD_composite.h"
#include "NOD_socket.h"
#include "NOD_socket_declarations.hh"
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 9193f91087a..5462441660c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -17,12 +17,15 @@
#include "BKE_context.h"
#include "BKE_cryptomatte.hh"
#include "BKE_global.h"
+#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "MEM_guardedalloc.h"
+#include "RE_pipeline.h"
+
#include <optional>
/* -------------------------------------------------------------------- */
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index fff0d467f75..802664d7934 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -5,6 +5,8 @@
* \ingroup cmpnodes
*/
+#include "BKE_colortools.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc
index 20dd61a9725..b87bbe439db 100644
--- a/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc
@@ -19,7 +19,7 @@ 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"));
+ b.add_output<decl::Float>(N_("Matte"));
}
static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index bb5e6bf06a8..d252d96f8c3 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -7,6 +7,8 @@
#include "node_composite_util.hh"
+#include "BKE_colortools.h"
+
namespace blender::nodes::node_composite_huecorrect_cc {
static void cmp_node_huecorrect_declare(NodeDeclarationBuilder &b)
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc
index d071e9f13db..d75aa575395 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_image.cc
@@ -12,6 +12,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -19,6 +20,7 @@
#include "DNA_scene_types.h"
#include "RE_engine.h"
+#include "RE_pipeline.h"
#include "RNA_access.h"
diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
index c3ed5cd7aa8..e835ee9e721 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
@@ -6,10 +6,15 @@
*/
#include "DNA_movieclip_types.h"
+#include "DNA_tracking_types.h"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
+#include "BKE_context.h"
+#include "BKE_lib_id.h"
+#include "BKE_tracking.h"
+
#include "RNA_access.h"
#include "RNA_prototypes.h"
@@ -27,10 +32,23 @@ 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)
+static void node_composit_init_keyingscreen(const bContext *C, PointerRNA *ptr)
{
+ bNode *node = (bNode *)ptr->data;
+
NodeKeyingScreenData *data = MEM_cnew<NodeKeyingScreenData>(__func__);
node->storage = data;
+
+ const Scene *scene = CTX_data_scene(C);
+ if (scene->clip) {
+ MovieClip *clip = scene->clip;
+
+ node->id = &clip->id;
+ id_us_plus(&clip->id);
+
+ const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
+ BLI_strncpy(data->tracking_object, tracking_object->name, sizeof(data->tracking_object));
+ }
}
static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -71,7 +89,7 @@ void register_node_type_cmp_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);
+ ntype.initfunc_api = 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_map_value.cc b/source/blender/nodes/composite/nodes/node_composite_map_value.cc
index b069cce93fc..bb42628ed3d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_map_value.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_map_value.cc
@@ -5,6 +5,8 @@
* \ingroup cmpnodes
*/
+#include "BKE_texture.h"
+
#include "RNA_access.h"
#include "UI_interface.h"
diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
index 9c6c6a40b2c..4d52a767b8a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
@@ -7,6 +7,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
+#include "BKE_tracking.h"
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/nodes/composite/nodes/node_composite_output_file.cc b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
index 1fd6e62b4c5..84235b085a4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_output_file.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
@@ -114,7 +114,7 @@ void ntreeCompositOutputFileUniqueLayer(ListBase *list,
bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree,
bNode *node,
const char *name,
- ImageFormatData *im_format)
+ const ImageFormatData *im_format)
{
NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
bNodeSocket *sock = nodeAddStaticSocket(
@@ -130,7 +130,8 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree,
ntreeCompositOutputFileUniqueLayer(&node->inputs, sock, name, '_');
if (im_format) {
- sockdata->format = *im_format;
+ BKE_image_format_copy(&sockdata->format, im_format);
+ sockdata->format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE;
if (BKE_imtype_is_movie(sockdata->format.imtype)) {
sockdata->format.imtype = R_IMF_IMTYPE_OPENEXR;
}
@@ -198,7 +199,8 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
RenderData *rd = &scene->r;
BLI_strncpy(nimf->base_path, rd->pic, sizeof(nimf->base_path));
- nimf->format = rd->im_format;
+ BKE_image_format_copy(&nimf->format, &rd->im_format);
+ nimf->format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE;
if (BKE_imtype_is_movie(nimf->format.imtype)) {
nimf->format.imtype = R_IMF_IMTYPE_OPENEXR;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
index fb0c03579a2..6557478fc4b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
@@ -5,6 +5,13 @@
* \ingroup cmpnodes
*/
+#include "DNA_movieclip_types.h"
+#include "DNA_tracking_types.h"
+
+#include "BKE_context.h"
+#include "BKE_lib_id.h"
+#include "BKE_tracking.h"
+
#include "RNA_access.h"
#include "RNA_prototypes.h"
@@ -22,12 +29,33 @@ static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Plane"));
}
-static void init(bNodeTree *UNUSED(ntree), bNode *node)
+static void init(const bContext *C, PointerRNA *ptr)
{
+ bNode *node = (bNode *)ptr->data;
+
NodePlaneTrackDeformData *data = MEM_cnew<NodePlaneTrackDeformData>(__func__);
data->motion_blur_samples = 16;
data->motion_blur_shutter = 0.5f;
node->storage = data;
+
+ const Scene *scene = CTX_data_scene(C);
+ if (scene->clip) {
+ MovieClip *clip = scene->clip;
+ MovieTracking *tracking = &clip->tracking;
+
+ node->id = &clip->id;
+ id_us_plus(&clip->id);
+
+ const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ BLI_strncpy(data->tracking_object, tracking_object->name, sizeof(data->tracking_object));
+
+ const MovieTrackingPlaneTrack *active_plane_track = BKE_tracking_plane_track_get_active(
+ tracking);
+ if (active_plane_track) {
+ BLI_strncpy(
+ data->plane_track_name, active_plane_track->name, sizeof(data->plane_track_name));
+ }
+ }
}
static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -90,7 +118,7 @@ void register_node_type_cmp_planetrackdeform()
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);
+ ntype.initfunc_api = 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_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
index 17a086f306f..0e99ff59327 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
@@ -5,6 +5,13 @@
* \ingroup cmpnodes
*/
+#include "DNA_movieclip_types.h"
+#include "DNA_tracking_types.h"
+
+#include "BKE_context.h"
+#include "BKE_lib_id.h"
+#include "BKE_tracking.h"
+
#include "RNA_access.h"
#include "RNA_prototypes.h"
@@ -22,11 +29,29 @@ static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Speed")).subtype(PROP_VELOCITY);
}
-static void init(bNodeTree *UNUSED(ntree), bNode *node)
+static void init(const bContext *C, PointerRNA *ptr)
{
- NodeTrackPosData *data = MEM_cnew<NodeTrackPosData>(__func__);
+ bNode *node = (bNode *)ptr->data;
+ NodeTrackPosData *data = MEM_cnew<NodeTrackPosData>(__func__);
node->storage = data;
+
+ const Scene *scene = CTX_data_scene(C);
+ if (scene->clip) {
+ MovieClip *clip = scene->clip;
+ MovieTracking *tracking = &clip->tracking;
+
+ node->id = &clip->id;
+ id_us_plus(&clip->id);
+
+ const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
+ BLI_strncpy(data->tracking_object, tracking_object->name, sizeof(data->tracking_object));
+
+ const MovieTrackingTrack *active_track = BKE_tracking_track_get_active(tracking);
+ if (active_track) {
+ BLI_strncpy(data->track_name, active_track->name, sizeof(data->track_name));
+ }
+ }
}
static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -88,7 +113,7 @@ void register_node_type_cmp_trackpos()
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);
+ ntype.initfunc_api = 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_val_to_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc
index f71028bf8c1..df669d5beda 100644
--- a/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc
@@ -7,6 +7,8 @@
#include "node_composite_util.hh"
+#include "BKE_colorband.h"
+
/* **************** VALTORGB ******************** */
namespace blender::nodes::node_composite_val_to_rgb_cc {
@@ -47,7 +49,7 @@ 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"));
+ b.add_output<decl::Float>(N_("Val"));
}
} // namespace blender::nodes::node_composite_val_to_rgb_cc
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 a0942ced1be..360695299cb 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -57,7 +57,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
static void fn_node_random_value_update(bNodeTree *ntree, bNode *node)
{
const NodeRandomValue &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *sock_min_vector = (bNodeSocket *)node->inputs.first;
bNodeSocket *sock_max_vector = sock_min_vector->next;
@@ -86,7 +86,7 @@ static void fn_node_random_value_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL);
}
-static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
{
switch (socket.type) {
case SOCK_FLOAT:
@@ -106,7 +106,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock
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());
+ const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket());
if (!type) {
return;
}
@@ -137,7 +137,7 @@ static void fn_node_random_value_gather_link_search(GatherLinkSearchOpParams &pa
static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeRandomValue &storage = node_storage(builder.node());
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
switch (data_type) {
case CD_PROP_FLOAT3: {
diff --git a/source/blender/nodes/function/nodes/node_fn_separate_color.cc b/source/blender/nodes/function/nodes/node_fn_separate_color.cc
index 1701dfdc6fa..19613427835 100644
--- a/source/blender/nodes/function/nodes/node_fn_separate_color.cc
+++ b/source/blender/nodes/function/nodes/node_fn_separate_color.cc
@@ -60,22 +60,41 @@ class SeparateRGBAFunction : public fn::MultiFunction {
{
const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
"Color");
- MutableSpan<float> red = params.uninitialized_single_output<float>(1, "Red");
- MutableSpan<float> green = params.uninitialized_single_output<float>(2, "Green");
- MutableSpan<float> blue = params.uninitialized_single_output<float>(3, "Blue");
+
+ MutableSpan<float> red = params.uninitialized_single_output_if_required<float>(1, "Red");
+ MutableSpan<float> green = params.uninitialized_single_output_if_required<float>(2, "Green");
+ MutableSpan<float> blue = params.uninitialized_single_output_if_required<float>(3, "Blue");
MutableSpan<float> alpha = params.uninitialized_single_output_if_required<float>(4, "Alpha");
- for (int64_t i : mask) {
- red[i] = colors[i].r;
- green[i] = colors[i].g;
- blue[i] = colors[i].b;
+ std::array<MutableSpan<float>, 4> outputs = {red, green, blue, alpha};
+ Vector<int> used_outputs;
+ if (!red.is_empty()) {
+ used_outputs.append(0);
+ }
+ if (!green.is_empty()) {
+ used_outputs.append(1);
+ }
+ if (!blue.is_empty()) {
+ used_outputs.append(2);
}
-
if (!alpha.is_empty()) {
- for (int64_t i : mask) {
- alpha[i] = colors[i].a;
- }
+ used_outputs.append(3);
}
+
+ devirtualize_varray(colors, [&](auto colors) {
+ mask.to_best_mask_type([&](auto mask) {
+ const int used_outputs_num = used_outputs.size();
+ const int *used_outputs_data = used_outputs.data();
+
+ for (const int64_t i : mask) {
+ const ColorGeometry4f &color = colors[i];
+ for (const int out_i : IndexRange(used_outputs_num)) {
+ const int channel = used_outputs_data[out_i];
+ outputs[channel][i] = color[channel];
+ }
+ }
+ });
+ });
}
};
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 84280c0889a..d87f0312958 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRC
nodes/node_geo_curve_to_mesh.cc
nodes/node_geo_curve_to_points.cc
nodes/node_geo_curve_trim.cc
+ nodes/node_geo_deform_curves_on_surface.cc
nodes/node_geo_delete_geometry.cc
nodes/node_geo_distribute_points_on_faces.cc
nodes/node_geo_dual_mesh.cc
@@ -64,6 +65,7 @@ set(SRC
nodes/node_geo_edge_split.cc
nodes/node_geo_extrude_mesh.cc
nodes/node_geo_field_at_index.cc
+ nodes/node_geo_field_on_domain.cc
nodes/node_geo_flip_faces.cc
nodes/node_geo_geometry_to_instance.cc
nodes/node_geo_image_texture.cc
@@ -71,6 +73,8 @@ set(SRC
nodes/node_geo_input_curve_tilt.cc
nodes/node_geo_input_id.cc
nodes/node_geo_input_index.cc
+ nodes/node_geo_input_instance_rotation.cc
+ nodes/node_geo_input_instance_scale.cc
nodes/node_geo_input_material.cc
nodes/node_geo_input_material_index.cc
nodes/node_geo_input_mesh_edge_angle.cc
@@ -109,7 +113,9 @@ set(SRC
nodes/node_geo_mesh_subdivide.cc
nodes/node_geo_mesh_to_curve.cc
nodes/node_geo_mesh_to_points.cc
+ nodes/node_geo_mesh_to_volume.cc
nodes/node_geo_object_info.cc
+ nodes/node_geo_points.cc
nodes/node_geo_points_to_vertices.cc
nodes/node_geo_points_to_volume.cc
nodes/node_geo_proximity.cc
@@ -141,7 +147,10 @@ set(SRC
nodes/node_geo_transform.cc
nodes/node_geo_translate_instances.cc
nodes/node_geo_triangulate.cc
+ nodes/node_geo_uv_pack_islands.cc
+ nodes/node_geo_uv_unwrap.cc
nodes/node_geo_viewer.cc
+ nodes/node_geo_volume_cube.cc
nodes/node_geo_volume_to_mesh.cc
node_geometry_exec.cc
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 7f9ec329efd..8f673d2264e 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -14,7 +14,7 @@
namespace blender::nodes {
-std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
+std::optional<eCustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
{
switch (type) {
case SOCK_FLOAT:
@@ -34,7 +34,7 @@ std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSock
}
}
-std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket)
+std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket)
{
return node_data_type_to_custom_data_type(static_cast<eNodeSocketDatatype>(socket.type));
}
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 8f20da66c3b..efb7efaf1cc 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -70,13 +70,12 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
* component. If no component can work with the domain, then `error_message` is set to true.
*/
void separate_geometry(GeometrySet &geometry_set,
- AttributeDomain domain,
+ eAttrDomain domain,
GeometryNodeDeleteGeometryMode mode,
const Field<bool> &selection_field,
- bool invert,
bool &r_is_error);
-std::optional<CustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
-std::optional<CustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
+std::optional<eCustomDataType> node_data_type_to_custom_data_type(eNodeSocketDatatype type);
+std::optional<eCustomDataType> node_socket_to_custom_data_type(const bNodeSocket &socket);
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
index b29831ceeb6..58fbfb5a000 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -87,7 +87,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeAccumulateField &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *sock_in_vector = (bNodeSocket *)node->inputs.first;
bNodeSocket *sock_in_float = sock_in_vector->next;
@@ -123,7 +123,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
enum class AccumulationMode { Leading = 0, Trailing = 1 };
-static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
{
switch (socket.type) {
case SOCK_FLOAT:
@@ -141,7 +141,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
- const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket());
if (!type) {
return;
}
@@ -196,11 +196,11 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
private:
Field<T> input_;
Field<int> group_index_;
- AttributeDomain source_domain_;
+ eAttrDomain source_domain_;
AccumulationMode accumulation_mode_;
public:
- AccumulateFieldInput(const AttributeDomain source_domain,
+ AccumulateFieldInput(const eAttrDomain source_domain,
Field<T> input,
Field<int> group_index,
AccumulationMode accumulation_mode)
@@ -213,20 +213,24 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
const GeometryComponentFieldContext field_context{component, source_domain_};
- const int domain_num = component.attribute_domain_num(field_context.domain());
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+ if (domain_size == 0) {
+ return {};
+ }
+ const AttributeAccessor attributes = *component.attributes();
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ 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);
+ const VArray<T> values = evaluator.get_evaluated<T>(0);
+ const VArray<int> group_indices = evaluator.get_evaluated<int>(1);
- Array<T> accumulations_out(domain_num);
+ Array<T> accumulations_out(domain_size);
if (group_indices.is_single()) {
T accumulation = T();
@@ -261,7 +265,7 @@ template<typename T> class AccumulateFieldInput final : public GeometryFieldInpu
}
}
- return component.attribute_try_adapt_domain<T>(
+ return attributes.adapt_domain<T>(
VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
}
@@ -287,10 +291,10 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
private:
Field<T> input_;
Field<int> group_index_;
- AttributeDomain source_domain_;
+ eAttrDomain source_domain_;
public:
- TotalFieldInput(const AttributeDomain source_domain, Field<T> input, Field<int> group_index)
+ TotalFieldInput(const eAttrDomain source_domain, Field<T> input, Field<int> group_index)
: GeometryFieldInput(CPPType::get<T>(), "Total Value"),
input_(input),
group_index_(group_index),
@@ -299,28 +303,32 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
const GeometryComponentFieldContext field_context{component, source_domain_};
- const int domain_num = component.attribute_domain_num(field_context.domain());
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+ if (domain_size == 0) {
+ return {};
+ }
+ const AttributeAccessor attributes = *component.attributes();
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ 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);
+ 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_num);
+ return VArray<T>::ForSingle(accumulation, domain_size);
}
- Array<T> accumulations_out(domain_num);
+ 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]);
@@ -330,7 +338,7 @@ template<typename T> class TotalFieldInput final : public GeometryFieldInput {
accumulations_out[i] = accumulations.lookup(group_indices[i]);
}
- return component.attribute_try_adapt_domain<T>(
+ return attributes.adapt_domain<T>(
VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
}
@@ -365,8 +373,8 @@ template<typename T> std::string identifier_suffix()
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);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eAttrDomain source_domain = static_cast<eAttrDomain>(storage.domain);
Field<int> group_index_field = params.extract_input<Field<int>>("Group Index");
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
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 16967d32673..9f317075bb5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -50,7 +50,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryAttributeCapture &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *socket_value_geometry = (bNodeSocket *)node->inputs.first;
bNodeSocket *socket_value_vector = socket_value_geometry->next;
@@ -86,7 +86,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
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(
+ const std::optional<eCustomDataType> 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) {
@@ -108,25 +108,32 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void try_capture_field_on_geometry(GeometryComponent &component,
const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const GField &field)
{
+ const int domain_size = component.attribute_domain_size(domain);
+ if (domain_size == 0) {
+ return;
+ }
GeometryComponentFieldContext field_context{component, domain};
- const int domain_num = component.attribute_domain_num(domain);
- const IndexMask mask{IndexMask(domain_num)};
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ const IndexMask mask{IndexMask(domain_size)};
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
- OutputAttribute output_attribute = component.attribute_try_get_for_output_only(
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(field.cpp_type());
+ GAttributeWriter output_attribute = attributes.lookup_or_add_for_write(
attribute_id, domain, data_type);
+ if (!output_attribute) {
+ return;
+ }
fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(field, output_attribute.varray());
+ evaluator.add_with_destination(field, output_attribute.varray);
evaluator.evaluate();
- output_attribute.save();
+ output_attribute.finish();
}
-static StringRefNull identifier_suffix(CustomDataType data_type)
+static StringRefNull identifier_suffix(eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_FLOAT:
@@ -158,8 +165,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
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);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
const std::string output_identifier = "Attribute" + identifier_suffix(data_type);
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
index 8ab0eb678e7..f6ea6073459 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -65,18 +65,17 @@ static void node_update(bNodeTree *ntree, bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
{
- GeometryComponentType component = (GeometryComponentType)params.node().custom1;
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ const GeometryComponentType component = (GeometryComponentType)params.node().custom1;
+ const 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_num(ATTR_DOMAIN_POINT));
- params.set_output("Edge Count", component->attribute_domain_num(ATTR_DOMAIN_EDGE));
- params.set_output("Face Count", component->attribute_domain_num(ATTR_DOMAIN_FACE));
- params.set_output("Face Corner Count",
- component->attribute_domain_num(ATTR_DOMAIN_CORNER));
+ if (const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>()) {
+ const AttributeAccessor attributes = *component->attributes();
+ params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Edge Count", attributes.domain_size(ATTR_DOMAIN_EDGE));
+ params.set_output("Face Count", attributes.domain_size(ATTR_DOMAIN_FACE));
+ params.set_output("Face Corner Count", attributes.domain_size(ATTR_DOMAIN_CORNER));
}
else {
params.set_default_remaining_outputs();
@@ -84,10 +83,11 @@ static void node_geo_exec(GeoNodeExecParams params)
break;
}
case GEO_COMPONENT_TYPE_CURVE: {
- if (geometry_set.has_curves()) {
- const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>();
- params.set_output("Point Count", component->attribute_domain_num(ATTR_DOMAIN_POINT));
- params.set_output("Spline Count", component->attribute_domain_num(ATTR_DOMAIN_CURVE));
+ if (const CurveComponent *component =
+ geometry_set.get_component_for_read<CurveComponent>()) {
+ const AttributeAccessor attributes = *component->attributes();
+ params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT));
+ params.set_output("Spline Count", attributes.domain_size(ATTR_DOMAIN_CURVE));
}
else {
params.set_default_remaining_outputs();
@@ -95,10 +95,10 @@ static void node_geo_exec(GeoNodeExecParams params)
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_num(ATTR_DOMAIN_POINT));
+ if (const PointCloudComponent *component =
+ geometry_set.get_component_for_read<PointCloudComponent>()) {
+ const AttributeAccessor attributes = *component->attributes();
+ params.set_output("Point Count", attributes.domain_size(ATTR_DOMAIN_POINT));
}
else {
params.set_default_remaining_outputs();
@@ -106,10 +106,10 @@ static void node_geo_exec(GeoNodeExecParams params)
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_num(ATTR_DOMAIN_INSTANCE));
+ if (const InstancesComponent *component =
+ geometry_set.get_component_for_read<InstancesComponent>()) {
+ const AttributeAccessor attributes = *component->attributes();
+ params.set_output("Instance Count", attributes.domain_size(ATTR_DOMAIN_INSTANCE));
}
else {
params.set_default_remaining_outputs();
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 c7f65a68d60..34e28e50c81 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -77,7 +77,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
bNodeSocket *socket_vector_std = socket_vector_range->next;
bNodeSocket *socket_vector_variance = socket_vector_std->next;
- const CustomDataType data_type = static_cast<CustomDataType>(node->custom1);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom1);
nodeSetSocketAvailability(ntree, socket_float_attr, data_type == CD_PROP_FLOAT);
nodeSetSocketAvailability(ntree, socket_float_mean, data_type == CD_PROP_FLOAT);
@@ -100,7 +100,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3);
}
-static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
{
switch (socket.type) {
case SOCK_FLOAT:
@@ -121,7 +121,7 @@ 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(2));
- const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket());
if (!type) {
return;
}
@@ -184,8 +184,8 @@ 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);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom1);
+ const eAttrDomain domain = static_cast<eAttrDomain>(node.custom2);
Vector<const GeometryComponent *> components = geometry_set.get_components_for_read();
const Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
@@ -195,15 +195,19 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<float> input_field = params.get_input<Field<float>>("Attribute");
Vector<float> data;
for (const GeometryComponent *component : components) {
- if (component->attribute_domain_supported(domain)) {
+ const std::optional<AttributeAccessor> attributes = component->attributes();
+ if (!attributes.has_value()) {
+ continue;
+ }
+ if (attributes->domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
- const int domain_num = component->attribute_domain_num(domain);
+ const int domain_num = attributes->domain_size(domain);
fn::FieldEvaluator data_evaluator{field_context, domain_num};
data_evaluator.add(input_field);
data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- const VArray<float> &component_data = data_evaluator.get_evaluated<float>(0);
+ 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();
@@ -273,15 +277,19 @@ static void node_geo_exec(GeoNodeExecParams params)
const Field<float3> input_field = params.get_input<Field<float3>>("Attribute_001");
Vector<float3> data;
for (const GeometryComponent *component : components) {
- if (component->attribute_domain_supported(domain)) {
+ const std::optional<AttributeAccessor> attributes = component->attributes();
+ if (!attributes.has_value()) {
+ continue;
+ }
+ if (attributes->domain_supported(domain)) {
GeometryComponentFieldContext field_context{*component, domain};
- const int domain_num = component->attribute_domain_num(domain);
+ const int domain_num = attributes->domain_size(domain);
fn::FieldEvaluator data_evaluator{field_context, domain_num};
data_evaluator.add(input_field);
data_evaluator.set_selection(selection_field);
data_evaluator.evaluate();
- const VArray<float3> &component_data = data_evaluator.get_evaluated<float3>(0);
+ 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();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index e485172d3e1..69938f3e447 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -2,6 +2,7 @@
#include "DNA_mesh_types.h"
+#include "BKE_geometry_set_instances.hh"
#include "BKE_mesh_boolean_convert.hh"
#include "UI_interface.h"
@@ -20,6 +21,7 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Bool>(N_("Self Intersection"));
b.add_input<decl::Bool>(N_("Hole Tolerant"));
b.add_output<decl::Geometry>(N_("Mesh"));
+ b.add_output<decl::Bool>(N_("Intersecting Edges")).field_source();
}
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -27,6 +29,10 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
}
+struct AttributeOutputs {
+ StrongAnonymousAttributeID intersecting_edges_id;
+};
+
static void node_update(bNodeTree *ntree, bNode *node)
{
GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1;
@@ -121,13 +127,21 @@ static void node_geo_exec(GeoNodeExecParams params)
}
}
- Mesh *result = blender::meshintersect::direct_mesh_boolean(meshes,
- transforms,
- float4x4::identity(),
- material_remaps,
- use_self,
- hole_tolerant,
- operation);
+ AttributeOutputs attribute_outputs;
+ if (params.output_is_required("Intersecting Edges")) {
+ attribute_outputs.intersecting_edges_id = StrongAnonymousAttributeID("Intersecting Edges");
+ }
+
+ Vector<int> intersecting_edges;
+ Mesh *result = blender::meshintersect::direct_mesh_boolean(
+ meshes,
+ transforms,
+ float4x4::identity(),
+ material_remaps,
+ use_self,
+ hole_tolerant,
+ operation,
+ attribute_outputs.intersecting_edges_id ? &intersecting_edges : nullptr);
if (!result) {
params.set_default_remaining_outputs();
return;
@@ -138,6 +152,24 @@ static void node_geo_exec(GeoNodeExecParams params)
result->totcol = materials.size();
MutableSpan(result->mat, result->totcol).copy_from(materials);
+ /* Store intersecting edges in attribute. */
+ if (attribute_outputs.intersecting_edges_id) {
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*result);
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<bool>(
+ attribute_outputs.intersecting_edges_id.get(), ATTR_DOMAIN_EDGE);
+
+ selection.span.fill(false);
+ for (const int i : intersecting_edges) {
+ selection.span[i] = true;
+ }
+ selection.finish();
+
+ params.set_output(
+ "Intersecting Edges",
+ AnonymousAttributeFieldInput::Create<bool>(
+ std::move(attribute_outputs.intersecting_edges_id), params.attribute_producer_name()));
+ }
+
params.set_output("Mesh", GeometrySet::create_with_mesh(result));
#else
params.error_message_add(NodeWarningType::Error,
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 31f706c497c..7c26ffc2099 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -22,8 +22,6 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Convex Hull"));
}
-using bke::GeometryInstanceGroup;
-
#ifdef WITH_BULLET
static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
@@ -142,28 +140,35 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
Span<float3> positions_span;
- if (geometry_set.has_mesh()) {
+ if (const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>()) {
count++;
- const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
- total_num += component->attribute_domain_num(ATTR_DOMAIN_POINT);
+ if (const VArray<float3> positions = component->attributes()->lookup<float3>(
+ "position", ATTR_DOMAIN_POINT)) {
+ if (positions.is_span()) {
+ span_count++;
+ positions_span = positions.get_internal_span();
+ }
+ total_num += positions.size();
+ }
}
- if (geometry_set.has_pointcloud()) {
+ if (const PointCloudComponent *component =
+ geometry_set.get_component_for_read<PointCloudComponent>()) {
count++;
- span_count++;
- const PointCloudComponent *component =
- geometry_set.get_component_for_read<PointCloudComponent>();
- VArray<float3> varray = component->attribute_get_for_read<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
- total_num += varray.size();
- positions_span = varray.get_internal_span();
+ if (const VArray<float3> positions = component->attributes()->lookup<float3>(
+ "position", ATTR_DOMAIN_POINT)) {
+ if (positions.is_span()) {
+ span_count++;
+ positions_span = positions.get_internal_span();
+ }
+ total_num += positions.size();
+ }
}
- if (geometry_set.has_curves()) {
+ if (const Curves *curves_id = geometry_set.get_curves_for_read()) {
count++;
span_count++;
- const Curves &curves_id = *geometry_set.get_curves_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
positions_span = curves.evaluated_positions();
total_num += positions_span.size();
}
@@ -181,26 +186,25 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
Array<float3> positions(total_num);
int offset = 0;
- if (geometry_set.has_mesh()) {
- const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>();
- 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()));
- offset += varray.size();
+ if (const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>()) {
+ if (const VArray<float3> varray = component->attributes()->lookup<float3>("position",
+ ATTR_DOMAIN_POINT)) {
+ 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>();
- 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()));
- offset += varray.size();
+ if (const PointCloudComponent *component =
+ geometry_set.get_component_for_read<PointCloudComponent>()) {
+ if (const VArray<float3> varray = component->attributes()->lookup<float3>("position",
+ ATTR_DOMAIN_POINT)) {
+ varray.materialize(positions.as_mutable_span().slice(offset, varray.size()));
+ offset += varray.size();
+ }
}
- if (geometry_set.has_curves()) {
- const Curves &curves_id = *geometry_set.get_curves_for_read();
- const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ if (const Curves *curves_id = geometry_set.get_curves_for_read()) {
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
Span<float3> array = curves.evaluated_positions();
positions.as_mutable_span().slice(offset, array.size()).copy_from(array);
offset += array.size();
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
index bbc8758952d..db3f108aad5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
@@ -41,7 +41,7 @@ class EndpointFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
@@ -64,8 +64,8 @@ class EndpointFieldInput final : public GeometryFieldInput {
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 VArray<int> start_size = evaluator.get_evaluated<int>(0);
+ const VArray<int> end_size = evaluator.get_evaluated<int>(1);
Array<bool> selection(curves.points_num(), false);
MutableSpan<bool> selection_span = selection.as_mutable_span();
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 fb8a488ddae..ab1f8269c39 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -1,16 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BLI_task.hh"
-
#include "UI_interface.h"
#include "UI_resources.h"
-#include "DNA_node_types.h"
+#include "GEO_fillet_curves.hh"
#include "node_geometry_util.hh"
-#include "BKE_spline.hh"
-
namespace blender::nodes::node_geo_curve_fillet_cc {
NODE_STORAGE_FUNCS(NodeGeometryCurveFillet)
@@ -44,571 +40,18 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveFillet *data = MEM_cnew<NodeGeometryCurveFillet>(__func__);
-
data->mode = GEO_NODE_CURVE_FILLET_BEZIER;
node->storage = data;
}
-struct FilletParam {
- GeometryNodeCurveFilletMode mode;
-
- /* Number of points to be added. */
- VArray<int> counts;
-
- /* Radii for fillet arc at all vertices. */
- VArray<float> radii;
-
- /* Whether or not fillets are allowed to overlap. */
- bool limit_radius;
-};
-
-/* A data structure used to store fillet data about all vertices to be filleted. */
-struct FilletData {
- Span<float3> positions;
- Array<float3> directions, axes;
- Array<float> radii, angles;
- Array<int> counts;
-};
-
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryCurveFillet &storage = node_storage(*node);
const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)storage.mode;
-
bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next;
-
nodeSetSocketAvailability(ntree, poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY);
}
-/* Function to get the center of a fillet. */
-static float3 get_center(const float3 vec_pos2prev,
- const float3 pos,
- const float3 axis,
- const float angle)
-{
- float3 vec_pos2center;
- rotate_normalized_v3_v3v3fl(vec_pos2center, vec_pos2prev, axis, M_PI_2 - angle / 2.0f);
- vec_pos2center *= 1.0f / sinf(angle / 2.0f);
-
- return vec_pos2center + pos;
-}
-
-/* Function to get the center of the fillet using fillet data */
-static float3 get_center(const float3 vec_pos2prev, const FilletData &fd, const int index)
-{
- const float angle = fd.angles[index];
- const float3 axis = fd.axes[index];
- const float3 pos = fd.positions[index];
-
- return get_center(vec_pos2prev, pos, axis, angle);
-}
-
-/* Calculate the direction vectors from each vertex to their previous vertex. */
-static Array<float3> calculate_directions(const Span<float3> positions)
-{
- const int num = positions.size();
- Array<float3> directions(num);
-
- for (const int i : IndexRange(num - 1)) {
- directions[i] = math::normalize(positions[i + 1] - positions[i]);
- }
- directions[num - 1] = math::normalize(positions[0] - positions[num - 1]);
-
- return directions;
-}
-
-/* Calculate the axes around which the fillet is built. */
-static Array<float3> calculate_axes(const Span<float3> directions)
-{
- const int num = directions.size();
- Array<float3> axes(num);
-
- axes[0] = math::normalize(math::cross(-directions[num - 1], directions[0]));
- for (const int i : IndexRange(1, num - 1)) {
- axes[i] = math::normalize(math::cross(-directions[i - 1], directions[i]));
- }
-
- return axes;
-}
-
-/* Calculate the angle of the arc formed by the fillet. */
-static Array<float> calculate_angles(const Span<float3> directions)
-{
- const int num = directions.size();
- Array<float> angles(num);
-
- angles[0] = M_PI - angle_v3v3(-directions[num - 1], directions[0]);
- for (const int i : IndexRange(1, num - 1)) {
- angles[i] = M_PI - angle_v3v3(-directions[i - 1], directions[i]);
- }
-
- return angles;
-}
-
-/* Calculate the segment count in each filleted arc. */
-static Array<int> calculate_counts(const FilletParam &fillet_param,
- const int num,
- const int spline_offset,
- const bool cyclic)
-{
- Array<int> counts(num, 1);
- if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) {
- for (const int i : IndexRange(num)) {
- counts[i] = fillet_param.counts[spline_offset + i];
- }
- }
- if (!cyclic) {
- counts[0] = counts[num - 1] = 0;
- }
-
- return counts;
-}
-
-/* Calculate the radii for the vertices to be filleted. */
-static Array<float> calculate_radii(const FilletParam &fillet_param,
- const int num,
- const int spline_offset)
-{
- Array<float> radii(num, 0.0f);
- if (fillet_param.limit_radius) {
- for (const int i : IndexRange(num)) {
- radii[i] = std::max(fillet_param.radii[spline_offset + i], 0.0f);
- }
- }
- else {
- for (const int i : IndexRange(num)) {
- radii[i] = fillet_param.radii[spline_offset + i];
- }
- }
-
- return radii;
-}
-
-/* Calculate the number of vertices added per vertex on the source spline. */
-static int calculate_point_counts(MutableSpan<int> point_counts,
- const Span<float> radii,
- const Span<int> counts)
-{
- int added_count = 0;
- for (const int i : IndexRange(point_counts.size())) {
- /* Calculate number of points to be added for the vertex. */
- if (radii[i] != 0.0f) {
- added_count += counts[i];
- point_counts[i] = counts[i] + 1;
- }
- }
-
- return added_count;
-}
-
-static FilletData calculate_fillet_data(const Spline &spline,
- const FilletParam &fillet_param,
- int &added_count,
- MutableSpan<int> point_counts,
- const int spline_offset)
-{
- const int num = spline.size();
-
- FilletData fd;
- fd.directions = calculate_directions(spline.positions());
- fd.positions = spline.positions();
- fd.axes = calculate_axes(fd.directions);
- fd.angles = calculate_angles(fd.directions);
- fd.counts = calculate_counts(fillet_param, num, spline_offset, spline.is_cyclic());
- fd.radii = calculate_radii(fillet_param, num, spline_offset);
-
- added_count = calculate_point_counts(point_counts, fd.radii, fd.counts);
-
- return fd;
-}
-
-/* Limit the radius based on angle and radii to prevent overlapping. */
-static void limit_radii(FilletData &fd, const bool cyclic)
-{
- MutableSpan<float> radii(fd.radii);
- Span<float> angles(fd.angles);
- Span<float3> positions(fd.positions);
-
- const int num = radii.size();
- const int fillet_count = cyclic ? num : num - 2;
- const int start = cyclic ? 0 : 1;
- Array<float> max_radii(num, FLT_MAX);
-
- if (cyclic) {
- /* Calculate lengths between adjacent control points. */
- const float len_prev = math::distance(positions[0], positions[num - 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);
- const float tan_len_prev = radii[num - 1] * tan(angles[num - 1] / 2.0f);
- const float tan_len_next = radii[1] * tan(angles[1] / 2.0f);
-
- float factor_prev = 1.0f, factor_next = 1.0f;
- if (tan_len + tan_len_prev > len_prev) {
- factor_prev = len_prev / (tan_len + tan_len_prev);
- }
- if (tan_len + tan_len_next > len_next) {
- factor_next = len_next / (tan_len + tan_len_next);
- }
-
- /* Scale max radii by calculated factors. */
- max_radii[0] = radii[0] * std::min(factor_next, factor_prev);
- max_radii[1] = radii[1] * factor_next;
- max_radii[num - 1] = radii[num - 1] * factor_prev;
- }
-
- /* Initialize max_radii to largest possible radii. */
- float prev_dist = math::distance(positions[1], positions[0]);
- for (const int i : IndexRange(1, num - 2)) {
- 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 = 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);
-
- /* Scale down radii if too large for segment. */
- float factor = 1.0f;
- if (tan_len + tan_len_next > len_next) {
- factor = len_next / (tan_len + tan_len_next);
- }
- max_radii[i] = std::min(max_radii[i], radii[i] * factor);
- max_radii[i + 1] = std::min(max_radii[i + 1], radii[i + 1] * factor);
- }
-
- /* Assign the max_radii to the fillet data's radii. */
- for (const int i : IndexRange(num)) {
- radii[i] = std::min(radii[i], max_radii[i]);
- }
-}
-
-/*
- * Create a mapping from each vertex in the destination spline to that of the source spline.
- * Used for copying the data from the source spline.
- */
-static Array<int> create_dst_to_src_map(const Span<int> point_counts, const int total_points)
-{
- Array<int> map(total_points);
- MutableSpan<int> map_span{map};
- int index = 0;
-
- for (const int i : point_counts.index_range()) {
- map_span.slice(index, point_counts[i]).fill(i);
- index += point_counts[i];
- }
-
- BLI_assert(index == total_points);
-
- return map;
-}
-
-template<typename T>
-static void copy_attribute_by_mapping(const Span<T> src,
- MutableSpan<T> dst,
- const Span<int> mapping)
-{
- for (const int i : dst.index_range()) {
- dst[i] = src[mapping[i]];
- }
-}
-
-/* Copy radii and tilts from source spline to destination. Positions are handled later in update
- * positions methods. */
-static void copy_common_attributes_by_mapping(const Spline &src,
- Spline &dst,
- const Span<int> mapping)
-{
- copy_attribute_by_mapping(src.radii(), dst.radii(), mapping);
- copy_attribute_by_mapping(src.tilts(), dst.tilts(), mapping);
-
- 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) {
- 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;
- }
- }
- BLI_assert_unreachable();
- return false;
- },
- ATTR_DOMAIN_POINT);
-}
-
-/* Update the vertex positions and handle positions of a Bezier spline based on fillet data. */
-static void update_bezier_positions(const FilletData &fd,
- BezierSpline &dst_spline,
- const BezierSpline &src_spline,
- const Span<int> point_counts)
-{
- Span<float> radii(fd.radii);
- Span<float> angles(fd.angles);
- Span<float3> axes(fd.axes);
- Span<float3> positions(fd.positions);
- Span<float3> directions(fd.directions);
-
- const int num = radii.size();
-
- int i_dst = 0;
- for (const int i_src : IndexRange(num)) {
- const int count = point_counts[i_src];
-
- /* Skip if the point count for the vertex is 1. */
- if (count == 1) {
- dst_spline.positions()[i_dst] = src_spline.positions()[i_src];
- dst_spline.handle_types_left()[i_dst] = src_spline.handle_types_left()[i_src];
- dst_spline.handle_types_right()[i_dst] = src_spline.handle_types_right()[i_src];
- dst_spline.handle_positions_left()[i_dst] = src_spline.handle_positions_left()[i_src];
- dst_spline.handle_positions_right()[i_dst] = src_spline.handle_positions_right()[i_src];
- i_dst++;
- continue;
- }
-
- /* Calculate the angle to be formed between any 2 adjacent vertices within the fillet. */
- const float segment_angle = angles[i_src] / (count - 1);
- /* Calculate the handle length for each added vertex. Equation: L = 4R/3 * tan(A/4) */
- const float handle_length = 4.0f * radii[i_src] / 3.0f * tan(segment_angle / 4.0f);
- /* Calculate the distance by which each vertex should be displaced from their initial position.
- */
- const float displacement = radii[i_src] * tan(angles[i_src] / 2.0f);
-
- /* Position the end points of the arc and their handles. */
- const int end_i = i_dst + count - 1;
- const float3 prev_dir = i_src == 0 ? -directions[num - 1] : -directions[i_src - 1];
- const float3 next_dir = directions[i_src];
- dst_spline.positions()[i_dst] = positions[i_src] + displacement * prev_dir;
- dst_spline.positions()[end_i] = positions[i_src] + displacement * next_dir;
- dst_spline.handle_positions_right()[i_dst] = dst_spline.positions()[i_dst] -
- handle_length * prev_dir;
- dst_spline.handle_positions_left()[end_i] = dst_spline.positions()[end_i] -
- handle_length * next_dir;
- dst_spline.handle_types_right()[i_dst] = dst_spline.handle_types_left()[end_i] =
- BEZIER_HANDLE_ALIGN;
- dst_spline.handle_types_left()[i_dst] = dst_spline.handle_types_right()[end_i] =
- BEZIER_HANDLE_VECTOR;
- dst_spline.mark_cache_invalid();
-
- /* Calculate the center of the radius to be formed. */
- 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;
- float radius;
- radius_vec = math::normalize_and_get_length(radius_vec, radius);
-
- dst_spline.handle_types_right().slice(1, count - 2).fill(BEZIER_HANDLE_ALIGN);
- dst_spline.handle_types_left().slice(1, count - 2).fill(BEZIER_HANDLE_ALIGN);
-
- /* For each of the vertices in between the end points. */
- for (const int j : IndexRange(1, count - 2)) {
- int index = i_dst + j;
- /* Rotate the radius by the segment angle and determine its tangent (used for getting handle
- * directions). */
- float3 new_radius_vec, tangent_vec;
- rotate_normalized_v3_v3v3fl(new_radius_vec, radius_vec, -axes[i_src], segment_angle);
- rotate_normalized_v3_v3v3fl(tangent_vec, new_radius_vec, axes[i_src], M_PI_2);
- radius_vec = new_radius_vec;
- tangent_vec *= handle_length;
-
- /* Adjust the positions of the respective vertex and its handles. */
- dst_spline.positions()[index] = center + new_radius_vec * radius;
- dst_spline.handle_positions_left()[index] = dst_spline.positions()[index] + tangent_vec;
- dst_spline.handle_positions_right()[index] = dst_spline.positions()[index] - tangent_vec;
- }
-
- i_dst += count;
- }
-}
-
-/* Update the vertex positions of a Poly spline based on fillet data. */
-static void update_poly_positions(const FilletData &fd,
- Spline &dst_spline,
- const Spline &src_spline,
- const Span<int> point_counts)
-{
- Span<float> radii(fd.radii);
- Span<float> angles(fd.angles);
- Span<float3> axes(fd.axes);
- Span<float3> positions(fd.positions);
- Span<float3> directions(fd.directions);
-
- const int num = radii.size();
-
- int i_dst = 0;
- for (const int i_src : IndexRange(num)) {
- const int count = point_counts[i_src];
-
- /* Skip if the point count for the vertex is 1. */
- if (count == 1) {
- dst_spline.positions()[i_dst] = src_spline.positions()[i_src];
- i_dst++;
- continue;
- }
-
- const float segment_angle = angles[i_src] / (count - 1);
- const float displacement = radii[i_src] * tan(angles[i_src] / 2.0f);
-
- /* Position the end points of the arc. */
- const int end_i = i_dst + count - 1;
- const float3 prev_dir = i_src == 0 ? -directions[num - 1] : -directions[i_src - 1];
- const float3 next_dir = directions[i_src];
- dst_spline.positions()[i_dst] = positions[i_src] + displacement * prev_dir;
- dst_spline.positions()[end_i] = positions[i_src] + displacement * next_dir;
-
- /* Calculate the center of the radius to be formed. */
- 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;
-
- for (const int j : IndexRange(1, count - 2)) {
- /* Rotate the radius by the segment angle */
- float3 new_radius_vec;
- rotate_normalized_v3_v3v3fl(new_radius_vec, radius_vec, -axes[i_src], segment_angle);
- radius_vec = new_radius_vec;
-
- dst_spline.positions()[i_dst + j] = center + new_radius_vec;
- }
-
- i_dst += count;
- }
-}
-
-static SplinePtr fillet_spline(const Spline &spline,
- const FilletParam &fillet_param,
- const int spline_offset)
-{
- const int num = spline.size();
- const bool cyclic = spline.is_cyclic();
-
- if (num < 3) {
- return spline.copy();
- }
-
- /* Initialize the point_counts with 1s (at least one vertex on dst for each vertex on src). */
- Array<int> point_counts(num, 1);
-
- int added_count = 0;
- /* Update point_counts array and added_count. */
- FilletData fd = calculate_fillet_data(
- spline, fillet_param, added_count, point_counts, spline_offset);
- if (fillet_param.limit_radius) {
- limit_radii(fd, cyclic);
- }
-
- const int total_points = added_count + num;
- const Array<int> dst_to_src = create_dst_to_src_map(point_counts, total_points);
- SplinePtr dst_spline_ptr = spline.copy_only_settings();
- (*dst_spline_ptr).resize(total_points);
- copy_common_attributes_by_mapping(spline, *dst_spline_ptr, dst_to_src);
-
- switch (spline.type()) {
- case CURVE_TYPE_BEZIER: {
- const BezierSpline &src_spline = static_cast<const BezierSpline &>(spline);
- BezierSpline &dst_spline = static_cast<BezierSpline &>(*dst_spline_ptr);
- if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) {
- dst_spline.handle_types_left().fill(BEZIER_HANDLE_VECTOR);
- dst_spline.handle_types_right().fill(BEZIER_HANDLE_VECTOR);
- update_poly_positions(fd, dst_spline, src_spline, point_counts);
- }
- else {
- update_bezier_positions(fd, dst_spline, src_spline, point_counts);
- }
- break;
- }
- case CURVE_TYPE_POLY: {
- update_poly_positions(fd, *dst_spline_ptr, spline, point_counts);
- break;
- }
- case CURVE_TYPE_NURBS: {
- const NURBSpline &src_spline = static_cast<const NURBSpline &>(spline);
- NURBSpline &dst_spline = static_cast<NURBSpline &>(*dst_spline_ptr);
- copy_attribute_by_mapping(src_spline.weights(), dst_spline.weights(), dst_to_src);
- update_poly_positions(fd, dst_spline, src_spline, point_counts);
- break;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- break;
- }
- }
-
- return dst_spline_ptr;
-}
-
-static std::unique_ptr<CurveEval> fillet_curve(const CurveEval &input_curve,
- const FilletParam &fillet_param)
-{
- Span<SplinePtr> input_splines = input_curve.splines();
-
- std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
- const int splines_num = input_splines.size();
- output_curve->resize(splines_num);
- MutableSpan<SplinePtr> output_splines = output_curve->splines();
- Array<int> spline_offsets = input_curve.control_point_offsets();
-
- threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- output_splines[i] = fillet_spline(*input_splines[i], fillet_param, spline_offsets[i]);
- }
- });
- output_curve->attributes = input_curve.attributes;
-
- return output_curve;
-}
-
-static void calculate_curve_fillet(GeometrySet &geometry_set,
- const GeometryNodeCurveFilletMode mode,
- const Field<float> &radius_field,
- const std::optional<Field<int>> &count_field,
- const bool limit_radius)
-{
- if (!geometry_set.has_curves()) {
- return;
- }
-
- FilletParam fillet_param;
- fillet_param.mode = mode;
-
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- fn::FieldEvaluator field_evaluator{field_context, domain_num};
-
- field_evaluator.add(radius_field);
-
- if (mode == GEO_NODE_CURVE_FILLET_POLY) {
- field_evaluator.add(*count_field);
- }
-
- 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) {
- return;
- }
-
- if (mode == GEO_NODE_CURVE_FILLET_POLY) {
- fillet_param.counts = field_evaluator.get_evaluated<int>(1);
- }
-
- fillet_param.limit_radius = limit_radius;
-
- const std::unique_ptr<CurveEval> input_curve = curves_to_curve_eval(*component.get_for_read());
- std::unique_ptr<CurveEval> output_curve = fillet_curve(*input_curve, fillet_param);
-
- geometry_set.replace_curves(curve_eval_to_curves(*output_curve));
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
@@ -625,7 +68,42 @@ static void node_geo_exec(GeoNodeExecParams params)
}
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- calculate_curve_fillet(geometry_set, mode, radius_field, count_field, limit_radius);
+ if (!geometry_set.has_curves()) {
+ return;
+ }
+
+ const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
+ const Curves &curves_id = *component.get_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ GeometryComponentFieldContext context{component, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator{context, curves.points_num()};
+ evaluator.add(radius_field);
+
+ switch (mode) {
+ case GEO_NODE_CURVE_FILLET_BEZIER: {
+ evaluator.evaluate();
+ bke::CurvesGeometry dst_curves = geometry::fillet_curves_bezier(
+ curves, curves.curves_range(), evaluator.get_evaluated<float>(0), limit_radius);
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
+ bke::curves_copy_parameters(curves_id, *dst_curves_id);
+ geometry_set.replace_curves(dst_curves_id);
+ break;
+ }
+ case GEO_NODE_CURVE_FILLET_POLY: {
+ evaluator.add(*count_field);
+ evaluator.evaluate();
+ bke::CurvesGeometry dst_curves = geometry::fillet_curves_poly(
+ curves,
+ curves.curves_range(),
+ evaluator.get_evaluated<float>(0),
+ evaluator.get_evaluated<int>(1),
+ limit_radius);
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
+ bke::curves_copy_parameters(curves_id, *dst_curves_id);
+ geometry_set.replace_curves(dst_curves_id);
+ break;
+ }
+ }
});
params.set_output("Curve", std::move(geometry_set));
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
index dc2b9d40894..5ef20f03f28 100644
--- 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
@@ -84,7 +84,7 @@ class HandleTypeFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
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 91ba5f2845f..286d9993d0e 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
@@ -61,13 +61,13 @@ static Curves *create_star_curve(const float inner_radius,
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;
+ SpanAttributeWriter<bool> selection =
+ component.attributes_for_write()->lookup_or_add_for_write_only_span<bool>(r_attribute.get(),
+ ATTR_DOMAIN_POINT);
+ for (int i : selection.span.index_range()) {
+ selection.span[i] = i % 2 == 0;
}
- attribute.save();
+ selection.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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 78a132064ed..2815dd5b2e8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -65,8 +65,10 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<int> count = params.extract_input<Field<int>>("Count");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
- if (!component->is_empty()) {
- geometry.replace_curves(geometry::resample_to_count(*component, selection, count));
+ if (const Curves *src_curves = component->get_for_read()) {
+ Curves *dst_curves = geometry::resample_to_count(*component, selection, count);
+ bke::curves_copy_parameters(*src_curves, *dst_curves);
+ geometry.replace_curves(dst_curves);
}
}
});
@@ -76,8 +78,10 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<float> length = params.extract_input<Field<float>>("Length");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
- if (!component->is_empty()) {
- geometry.replace_curves(geometry::resample_to_length(*component, selection, length));
+ if (const Curves *src_curves = component->get_for_read()) {
+ Curves *dst_curves = geometry::resample_to_length(*component, selection, length);
+ bke::curves_copy_parameters(*src_curves, *dst_curves);
+ geometry.replace_curves(dst_curves);
}
}
});
@@ -86,8 +90,10 @@ static void node_geo_exec(GeoNodeExecParams params)
case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
geometry_set.modify_geometry_sets([&](GeometrySet &geometry) {
if (const CurveComponent *component = geometry.get_component_for_read<CurveComponent>()) {
- if (!component->is_empty()) {
- geometry.replace_curves(geometry::resample_to_evaluated(*component, selection));
+ if (const Curves *src_curves = component->get_for_read()) {
+ Curves *dst_curves = geometry::resample_to_evaluated(*component, selection);
+ bke::curves_copy_parameters(*src_curves, *dst_curves);
+ geometry.replace_curves(dst_curves);
}
}
});
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 64a174df599..de29735bd2d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -27,9 +27,9 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_num};
+ 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);
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 9077b59254c..01cf1d8db52 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -135,7 +135,7 @@ class SampleCurveFunction : public fn::MultiFunction {
}
const VArray<float> &lengths_varray = params.readonly_single_input<float>(0, "Length");
- const VArray_Span lengths{lengths_varray};
+ const VArraySpan lengths{lengths_varray};
#ifdef DEBUG
for (const float length : lengths) {
/* Lengths must be in range of the curve's total length. This is ensured in
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc
index 469d8d8d13b..f7ba724c377 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handle_type.cc
@@ -98,8 +98,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
has_curves = true;
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- if (!component.attribute_exists("handle_type_left") ||
- !component.attribute_exists("handle_type_right")) {
+ const AttributeAccessor attributes = *component.attributes();
+ if (!attributes.contains("handle_type_left") || !attributes.contains("handle_type_right")) {
return;
}
has_bezier = true;
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
index ae36248b573..b98541e3446 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -75,7 +75,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
case CURVE_TYPE_CATMULL_ROM: {
const int resolution = resolutions[i_curve];
for (const int i : IndexRange(points.size()).drop_back(1)) {
- lengths[i + 1] = evaluated_lengths[resolution * i];
+ lengths[i + 1] = evaluated_lengths[resolution * (i + 1) - 1];
}
break;
}
@@ -107,7 +107,7 @@ static Array<float> curve_length_point_domain(const bke::CurvesGeometry &curves)
static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry &curves,
const IndexMask UNUSED(mask),
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
VArray<bool> cyclic = curves.cyclic();
@@ -119,10 +119,20 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
for (const int i_curve : range) {
const float total_length = curves.evaluated_length_total_for_curve(i_curve,
cyclic[i_curve]);
- const float factor = total_length == 0.0f ? 0.0f : 1.0f / total_length;
MutableSpan<float> curve_lengths = lengths.slice(curves.points_for_curve(i_curve));
- for (float &value : curve_lengths) {
- value *= factor;
+ if (total_length > 0.0f) {
+ const float factor = 1.0f / total_length;
+ for (float &value : curve_lengths) {
+ value *= factor;
+ }
+ }
+ else {
+ /* It is arbitrary what to do in those rare cases when all the points are
+ * in the same position. In this case we are just arbitrarily giving a valid
+ * value in the range based on the point index. */
+ for (const int i : curve_lengths.index_range()) {
+ curve_lengths[i] = i / (curve_lengths.size() - 1.0f);
+ }
}
}
});
@@ -135,9 +145,19 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
const int last_index = curves.curves_num() - 1;
const int total_length = lengths.last() + curves.evaluated_length_total_for_curve(
last_index, cyclic[last_index]);
- const float factor = total_length == 0.0f ? 0.0f : 1.0f / total_length;
- for (float &value : lengths) {
- value *= factor;
+ if (total_length > 0.0f) {
+ const float factor = 1.0f / total_length;
+ for (float &value : lengths) {
+ value *= factor;
+ }
+ }
+ else {
+ /* It is arbitrary what to do in those rare cases when all the points are
+ * in the same position. In this case we are just arbitrarily giving a valid
+ * value in the range based on the curve index. */
+ for (const int i : lengths.index_range()) {
+ lengths[i] = i / (lengths.size() - 1.0f);
+ }
}
return VArray<float>::ForContainer(std::move(lengths));
}
@@ -146,7 +166,7 @@ static VArray<float> construct_curve_parameter_varray(const bke::CurvesGeometry
static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGeometry &curves,
const IndexMask UNUSED(mask),
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
curves.ensure_evaluated_lengths();
@@ -165,7 +185,7 @@ static VArray<float> construct_curve_length_parameter_varray(const bke::CurvesGe
static VArray<int> construct_index_on_spline_varray(const bke::CurvesGeometry &curves,
const IndexMask UNUSED(mask),
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (domain == ATTR_DOMAIN_POINT) {
Array<int> result(curves.points_num());
@@ -191,7 +211,7 @@ class CurveParameterFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
@@ -225,7 +245,7 @@ class CurveLengthParameterFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
@@ -259,7 +279,7 @@ class IndexOnSplineFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
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
index 500804e41f0..a92479bc5f1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -1,12 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
-
-#include "BLI_task.hh"
+#include "BKE_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GEO_set_curve_type.hh"
+
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_curve_spline_type_cc {
@@ -29,332 +29,14 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
- data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
+ data->spline_type = CURVE_TYPE_POLY;
node->storage = data;
}
-template<typename T>
-static void scale_input_assign(const Span<T> src,
- const int scale,
- const int offset,
- MutableSpan<T> dst)
-{
- for (const int i : dst.index_range()) {
- dst[i] = src[i * scale + offset];
- }
-}
-
-template<typename T>
-static void scale_output_assign(const Span<T> src,
- const int scale,
- const int offset,
- MutableSpan<T> dst)
-{
- for (const int i : src.index_range()) {
- dst[i * scale + offset] = src[i];
- }
-}
-
-template<typename T>
-static void nurbs_to_bezier_assign(const Span<T> src,
- const MutableSpan<T> dst,
- const KnotsMode knots_mode)
-{
- switch (knots_mode) {
- case NURBS_KNOT_MODE_BEZIER:
- scale_input_assign<T>(src, 3, 1, dst);
- break;
- case NURBS_KNOT_MODE_NORMAL:
- for (const int i : dst.index_range()) {
- dst[i] = src[(i + 1) % src.size()];
- }
- break;
- case NURBS_KNOT_MODE_ENDPOINT_BEZIER:
- case NURBS_KNOT_MODE_ENDPOINT:
- for (const int i : dst.index_range().drop_back(1).drop_front(1)) {
- dst[i] = src[i + 1];
- }
- dst.first() = src.first();
- dst.last() = src.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 KnotsMode knots_mode)
-{
- const int nurbs_positions_num = nurbs_positions.size();
- Vector<float3> handle_positions;
- if (knots_mode == NURBS_KNOT_MODE_BEZIER) {
- for (const int i : IndexRange(nurbs_positions_num)) {
- if (i % 3 == 1) {
- continue;
- }
- handle_positions.append(nurbs_positions[i]);
- }
- if (nurbs_positions_num % 3 == 1) {
- handle_positions.pop_last();
- }
- else if (nurbs_positions_num % 3 == 2) {
- const int last_index = nurbs_positions_num - 1;
- handle_positions.append(2 * nurbs_positions[last_index] - nurbs_positions[last_index - 1]);
- }
- }
- else {
- const bool is_periodic = knots_mode == NURBS_KNOT_MODE_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_num = nurbs_positions_num - 1;
- const bool ignore_interior_segment = segments_num == 3 && is_periodic == false;
- if (ignore_interior_segment == false) {
- const float mid_offset = (float)(segments_num - 1) / 2.0f;
- for (const int i : IndexRange(1, segments_num - 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_num - 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 KnotsMode knots_mode)
-{
- if (knots_mode == NURBS_KNOT_MODE_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 = NURBS_KNOT_MODE_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 = NURBS_KNOT_MODE_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(BEZIER_HANDLE_VECTOR);
- output->handle_types_right().fill(BEZIER_HANDLE_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;
- 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 = NURBS_KNOT_MODE_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(BEZIER_HANDLE_ALIGN);
- output->handle_types_right().fill(BEZIER_HANDLE_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 CURVE_TYPE_BEZIER:
- return input.copy();
- case CURVE_TYPE_POLY:
- return poly_to_bezier(input);
- case CURVE_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);
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- return {};
- }
- }
- BLI_assert_unreachable();
- return {};
-}
-
-static SplinePtr convert_to_nurbs(const Spline &input)
-{
- switch (input.type()) {
- case CURVE_TYPE_NURBS:
- return input.copy();
- case CURVE_TYPE_BEZIER:
- return bezier_to_nurbs(input);
- case CURVE_TYPE_POLY:
- return poly_to_nurbs(input);
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- return {};
- }
- BLI_assert_unreachable();
- return {};
-}
-
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryCurveSplineType &storage = node_storage(params.node());
- const GeometryNodeSplineType dst_type = (const GeometryNodeSplineType)storage.spline_type;
+ const CurveType dst_type = CurveType(storage.spline_type);
GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
@@ -363,45 +45,34 @@ static void node_geo_exec(GeoNodeExecParams params)
if (!geometry_set.has_curves()) {
return;
}
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ const Curves &src_curves_id = *src_component.get_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
+ if (src_curves.is_single_type(dst_type)) {
+ return;
+ }
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *curve_component->get_for_read());
- GeometryComponentFieldContext field_context{*curve_component, ATTR_DOMAIN_CURVE};
- const int domain_num = curve_component->attribute_domain_num(ATTR_DOMAIN_CURVE);
-
- Span<SplinePtr> src_splines = curve->splines();
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ return;
+ }
- fn::FieldEvaluator selection_evaluator{field_context, domain_num};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
+ if (geometry::try_curves_conversion_in_place(
+ selection, dst_type, [&]() -> bke::CurvesGeometry & {
+ return bke::CurvesGeometry::wrap(geometry_set.get_curves_for_write()->geometry);
+ })) {
+ return;
+ }
- std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- new_curve->resize(src_splines.size());
+ bke::CurvesGeometry dst_curves = geometry::convert_curves(src_curves, selection, dst_type);
- threading::parallel_for(src_splines.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- if (selection[i]) {
- switch (dst_type) {
- case GEO_NODE_SPLINE_TYPE_POLY:
- new_curve->splines()[i] = convert_to_poly_spline(*src_splines[i]);
- break;
- case GEO_NODE_SPLINE_TYPE_BEZIER:
- new_curve->splines()[i] = convert_to_bezier(*src_splines[i], params);
- break;
- case GEO_NODE_SPLINE_TYPE_NURBS:
- new_curve->splines()[i] = convert_to_nurbs(*src_splines[i]);
- break;
- }
- }
- else {
- new_curve->splines()[i] = src_splines[i]->copy();
- }
- }
- });
- new_curve->attributes = curve->attributes;
- geometry_set.replace_curves(curve_eval_to_curves(*new_curve));
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
+ bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
+ geometry_set.replace_curves(dst_curves_id);
});
params.set_output("Curve", std::move(geometry_set));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 4d8745bf79e..bd44adb35a2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -1,10 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BLI_task.hh"
-#include "BLI_timeit.hh"
+#include "BKE_curves.hh"
-#include "BKE_attribute_math.hh"
-#include "BKE_spline.hh"
+#include "GEO_subdivide_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -26,302 +24,6 @@ static void node_declare(NodeDeclarationBuilder &b)
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_num() + 1);
- int offset = 0;
- for (const int i : IndexRange(spline.segments_num())) {
- 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_num = src.size();
- threading::parallel_for(IndexRange(src_num - 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_num - 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_num,
- 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<int8_t> dst_type_left,
- MutableSpan<int8_t> 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() = BEZIER_HANDLE_VECTOR;
- }
- dst_type_left.slice(offset + 1, result_num).fill(BEZIER_HANDLE_VECTOR);
- dst_type_right.slice(offset, result_num).fill(BEZIER_HANDLE_VECTOR);
-
- const float factor_delta = 1.0f / result_num;
- for (const int cut : IndexRange(result_num)) {
- 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() = BEZIER_HANDLE_FREE;
- }
- dst_type_left.slice(offset + 1, result_num).fill(BEZIER_HANDLE_FREE);
- dst_type_right.slice(offset, result_num).fill(BEZIER_HANDLE_FREE);
-
- const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_num;
-
- /* 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_num - 1)) {
- const float parameter = 1.0f / (result_num - 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_num - 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<int8_t> dst_type_left = dst.handle_types_left();
- MutableSpan<int8_t> 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();
- dst_type_left.first() = src.handle_types_left().first();
- dst_type_right.last() = src.handle_types_right().last();
- dst_handles_left.first() = src_handles_left.first();
- dst_handles_right.last() = src_handles_right.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 CURVE_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 CURVE_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 CURVE_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;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- 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_num = offsets.last() + int(!spline.is_cyclic());
- SplinePtr new_spline = spline.copy_only_settings();
- new_spline->resize(result_num);
- 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");
@@ -333,20 +35,24 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const Curves &src_curves_id = *component.get_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
+ fn::FieldEvaluator evaluator{field_context, src_curves.points_num()};
evaluator.add(cuts_field);
evaluator.evaluate();
- const VArray<int> &cuts = evaluator.get_evaluated<int>(0);
-
+ 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(
- *curves_to_curve_eval(*component.get_for_read()), cuts);
- geometry_set.replace_curves(curve_eval_to_curves(*output_curve));
+
+ bke::CurvesGeometry dst_curves = geometry::subdivide_curves(
+ src_curves, src_curves.curves_range(), cuts);
+
+ Curves *dst_curves_id = bke::curves_new_nomain(std::move(dst_curves));
+ bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
+ geometry_set.replace_curves(dst_curves_id);
});
params.set_output("Curve", geometry_set);
}
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
index 73b2c400e90..6c4fb2e0855 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -124,21 +124,20 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
*/
static GMutableSpan ensure_point_attribute(PointCloudComponent &points,
const AttributeIDRef &attribute_id,
- const CustomDataType data_type)
+ const eCustomDataType 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();
+ return points.attributes_for_write()
+ ->lookup_or_add_for_write(attribute_id, ATTR_DOMAIN_POINT, data_type)
+ .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>();
+ return points.attributes_for_write()
+ ->lookup_or_add_for_write<T>(attribute_id, ATTR_DOMAIN_POINT)
+ .varray.get_internal_span();
}
namespace {
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 c993a3d305d..51994cb8a41 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BKE_curves.hh"
#include "BKE_spline.hh"
#include "BLI_task.hh"
@@ -506,16 +507,17 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ 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);
+ const VArray<float> starts = evaluator.get_evaluated<float>(0);
+ const VArray<float> ends = evaluator.get_evaluated<float>(1);
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*geometry_set.get_curves_for_read());
+ const Curves &src_curves_id = *geometry_set.get_curves_for_read();
+ std::unique_ptr<CurveEval> curve = curves_to_curve_eval(src_curves_id);
MutableSpan<SplinePtr> splines = curve->splines();
threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
@@ -566,7 +568,9 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set,
}
});
- geometry_set.replace_curves(curve_eval_to_curves(*curve));
+ Curves *dst_curves_id = curve_eval_to_curves(*curve);
+ bke::curves_copy_parameters(src_curves_id, *dst_curves_id);
+ geometry_set.replace_curves(dst_curves_id);
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
new file mode 100644
index 00000000000..bd08abbd070
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc
@@ -0,0 +1,360 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+#include "BKE_editmesh.h"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_wrapper.h"
+#include "BKE_modifier.h"
+#include "BKE_type_conversions.hh"
+
+#include "BLI_float3x3.hh"
+#include "BLI_task.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "NOD_socket_search_link.hh"
+
+#include "GEO_reverse_uv_sampler.hh"
+
+#include "DEG_depsgraph_query.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_deform_curves_on_surface_cc {
+
+using attribute_math::mix3;
+using bke::CurvesGeometry;
+using geometry::ReverseUVSampler;
+
+NODE_STORAGE_FUNCS(NodeGeometryCurveTrim)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Curves")).supported_type(GEO_COMPONENT_TYPE_CURVE);
+ b.add_output<decl::Geometry>(N_("Curves"));
+}
+
+static void deform_curves(CurvesGeometry &curves,
+ const Mesh &surface_mesh_old,
+ const Mesh &surface_mesh_new,
+ const Span<float2> curve_attachment_uvs,
+ const ReverseUVSampler &reverse_uv_sampler_old,
+ const ReverseUVSampler &reverse_uv_sampler_new,
+ const Span<float3> corner_normals_old,
+ const Span<float3> corner_normals_new,
+ const Span<float3> rest_positions,
+ const float4x4 &surface_to_curves,
+ std::atomic<int> &r_invalid_uv_count)
+{
+ /* Find attachment points on old and new mesh. */
+ const int curves_num = curves.curves_num();
+ Array<ReverseUVSampler::Result> surface_samples_old(curves_num);
+ Array<ReverseUVSampler::Result> surface_samples_new(curves_num);
+ threading::parallel_invoke(
+ [&]() { reverse_uv_sampler_old.sample_many(curve_attachment_uvs, surface_samples_old); },
+ [&]() { reverse_uv_sampler_new.sample_many(curve_attachment_uvs, surface_samples_new); });
+
+ MutableSpan<float3> positions = curves.positions_for_write();
+
+ const float4x4 curves_to_surface = surface_to_curves.inverted();
+
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const ReverseUVSampler::Result &surface_sample_old = surface_samples_old[curve_i];
+ if (surface_sample_old.type != ReverseUVSampler::ResultType::Ok) {
+ r_invalid_uv_count++;
+ continue;
+ }
+ const ReverseUVSampler::Result &surface_sample_new = surface_samples_new[curve_i];
+ if (surface_sample_new.type != ReverseUVSampler::ResultType::Ok) {
+ r_invalid_uv_count++;
+ continue;
+ }
+
+ const MLoopTri &looptri_old = *surface_sample_old.looptri;
+ const MLoopTri &looptri_new = *surface_sample_new.looptri;
+ const float3 &bary_weights_old = surface_sample_old.bary_weights;
+ const float3 &bary_weights_new = surface_sample_new.bary_weights;
+
+ const int corner_0_old = looptri_old.tri[0];
+ const int corner_1_old = looptri_old.tri[1];
+ const int corner_2_old = looptri_old.tri[2];
+
+ const int corner_0_new = looptri_new.tri[0];
+ const int corner_1_new = looptri_new.tri[1];
+ const int corner_2_new = looptri_new.tri[2];
+
+ const int vert_0_old = surface_mesh_old.mloop[corner_0_old].v;
+ const int vert_1_old = surface_mesh_old.mloop[corner_1_old].v;
+ const int vert_2_old = surface_mesh_old.mloop[corner_2_old].v;
+
+ const int vert_0_new = surface_mesh_new.mloop[corner_0_new].v;
+ const int vert_1_new = surface_mesh_new.mloop[corner_1_new].v;
+ const int vert_2_new = surface_mesh_new.mloop[corner_2_new].v;
+
+ const float3 &normal_0_old = corner_normals_old[corner_0_old];
+ const float3 &normal_1_old = corner_normals_old[corner_1_old];
+ const float3 &normal_2_old = corner_normals_old[corner_2_old];
+ const float3 normal_old = math::normalize(
+ mix3(bary_weights_old, normal_0_old, normal_1_old, normal_2_old));
+
+ const float3 &normal_0_new = corner_normals_new[corner_0_new];
+ const float3 &normal_1_new = corner_normals_new[corner_1_new];
+ const float3 &normal_2_new = corner_normals_new[corner_2_new];
+ const float3 normal_new = math::normalize(
+ mix3(bary_weights_new, normal_0_new, normal_1_new, normal_2_new));
+
+ const float3 &pos_0_old = surface_mesh_old.mvert[vert_0_old].co;
+ const float3 &pos_1_old = surface_mesh_old.mvert[vert_1_old].co;
+ const float3 &pos_2_old = surface_mesh_old.mvert[vert_2_old].co;
+ const float3 pos_old = mix3(bary_weights_old, pos_0_old, pos_1_old, pos_2_old);
+
+ const float3 &pos_0_new = surface_mesh_new.mvert[vert_0_new].co;
+ const float3 &pos_1_new = surface_mesh_new.mvert[vert_1_new].co;
+ const float3 &pos_2_new = surface_mesh_new.mvert[vert_2_new].co;
+ const float3 pos_new = mix3(bary_weights_new, pos_0_new, pos_1_new, pos_2_new);
+
+ /* The translation is just the difference between the old and new position on the surface. */
+ const float3 translation = pos_new - pos_old;
+
+ const float3 &rest_pos_0 = rest_positions[vert_0_new];
+ const float3 &rest_pos_1 = rest_positions[vert_1_new];
+
+ /* The tangent reference direction is used to determine the rotation of the surface point
+ * around its normal axis. It's important that the old and new tangent reference are computed
+ * in a consistent way. If the surface has not been rotated, the old and new tangent
+ * reference have to have the same direction. For that reason, the old tangent reference is
+ * computed based on the rest position attribute instead of positions on the old mesh. This
+ * way the old and new tangent reference use the same topology.
+ *
+ * TODO: Figure out if this can be smoothly interpolated across the surface as well.
+ * Currently, this is a source of discontinuity in the deformation, because the vector
+ * changes instantly from one triangle to the next. */
+ const float3 tangent_reference_dir_old = rest_pos_1 - rest_pos_0;
+ const float3 tangent_reference_dir_new = pos_1_new - pos_0_new;
+
+ /* Compute first local tangent based on the (potentially smoothed) normal and the tangent
+ * reference. */
+ const float3 tangent_x_old = math::normalize(
+ math::cross(normal_old, tangent_reference_dir_old));
+ const float3 tangent_x_new = math::normalize(
+ math::cross(normal_new, tangent_reference_dir_new));
+
+ /* The second tangent defined by the normal and first tangent. */
+ const float3 tangent_y_old = math::normalize(math::cross(normal_old, tangent_x_old));
+ const float3 tangent_y_new = math::normalize(math::cross(normal_new, tangent_x_new));
+
+ /* Construct rotation matrix that encodes the orientation of the old surface position. */
+ float3x3 rotation_old;
+ copy_v3_v3(rotation_old.values[0], tangent_x_old);
+ copy_v3_v3(rotation_old.values[1], tangent_y_old);
+ copy_v3_v3(rotation_old.values[2], normal_old);
+
+ /* Construct rotation matrix that encodes the orientation of the new surface position. */
+ float3x3 rotation_new;
+ copy_v3_v3(rotation_new.values[0], tangent_x_new);
+ copy_v3_v3(rotation_new.values[1], tangent_y_new);
+ copy_v3_v3(rotation_new.values[2], normal_new);
+
+ /* Can use transpose instead of inverse because the matrix is orthonormal. In the case of
+ * zero-area triangles, the matrix would not be orthonormal, but in this case, none of this
+ * works anyway. */
+ const float3x3 rotation_old_inv = rotation_old.transposed();
+
+ /* Compute a rotation matrix that rotates points from the old to the new surface
+ * orientation. */
+ const float3x3 rotation = rotation_new * rotation_old_inv;
+ float4x4 rotation_4x4;
+ copy_m4_m3(rotation_4x4.values, rotation.values);
+
+ /* Construction transformation matrix for this surface position that includes rotation and
+ * translation. */
+ float4x4 surface_transform = float4x4::identity();
+ /* Subtract and add #pos_old, so that the rotation origin is the position on the surface. */
+ sub_v3_v3(surface_transform.values[3], pos_old);
+ mul_m4_m4_pre(surface_transform.values, rotation_4x4.values);
+ add_v3_v3(surface_transform.values[3], pos_old);
+ add_v3_v3(surface_transform.values[3], translation);
+
+ /* Change the basis of the transformation so to that it can be applied in the local space of
+ * the curves. */
+ const float4x4 curve_transform = surface_to_curves * surface_transform * curves_to_surface;
+
+ /* Actually transform all points. */
+ const IndexRange points = curves.points_for_curve(curve_i);
+ for (const int point_i : points) {
+ const float3 old_point_pos = positions[point_i];
+ const float3 new_point_pos = curve_transform * old_point_pos;
+ positions[point_i] = new_point_pos;
+ }
+ }
+ });
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ GeometrySet curves_geometry = params.extract_input<GeometrySet>("Curves");
+
+ Mesh *surface_mesh_orig = nullptr;
+ bool free_suface_mesh_orig = false;
+ BLI_SCOPED_DEFER([&]() {
+ if (free_suface_mesh_orig) {
+ BKE_id_free(nullptr, surface_mesh_orig);
+ }
+ });
+
+ auto pass_through_input = [&]() { params.set_output("Curves", std::move(curves_geometry)); };
+
+ const Object *self_ob_eval = params.self_object();
+ if (self_ob_eval == nullptr || self_ob_eval->type != OB_CURVES) {
+ pass_through_input();
+ return;
+ }
+ const Curves *self_curves_eval = static_cast<const Curves *>(self_ob_eval->data);
+ if (self_curves_eval->surface_uv_map == nullptr || self_curves_eval->surface_uv_map[0] == '\0') {
+ pass_through_input();
+ const char *message = TIP_("Surface UV map not defined");
+ params.error_message_add(NodeWarningType::Error, message);
+ return;
+ }
+ /* Take surface information from self-object. */
+ Object *surface_ob_eval = self_curves_eval->surface;
+ const StringRefNull uv_map_name = self_curves_eval->surface_uv_map;
+ const StringRefNull rest_position_name = "rest_position";
+
+ if (!curves_geometry.has_curves()) {
+ pass_through_input();
+ return;
+ }
+ if (surface_ob_eval == nullptr || surface_ob_eval->type != OB_MESH) {
+ pass_through_input();
+ params.error_message_add(NodeWarningType::Error, "Curves not attached to a surface");
+ return;
+ }
+ Object *surface_ob_orig = DEG_get_original_object(surface_ob_eval);
+ Mesh &surface_object_data = *static_cast<Mesh *>(surface_ob_orig->data);
+
+ if (BMEditMesh *em = surface_object_data.edit_mesh) {
+ surface_mesh_orig = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, &surface_object_data);
+ free_suface_mesh_orig = true;
+ }
+ else {
+ surface_mesh_orig = &surface_object_data;
+ }
+ Mesh *surface_mesh_eval = BKE_modifier_get_evaluated_mesh_from_evaluated_object(surface_ob_eval);
+ if (surface_mesh_eval == nullptr) {
+ pass_through_input();
+ params.error_message_add(NodeWarningType::Error, "Surface has no mesh");
+ return;
+ }
+
+ BKE_mesh_wrapper_ensure_mdata(surface_mesh_eval);
+
+ const AttributeAccessor mesh_attributes_eval = bke::mesh_attributes(*surface_mesh_eval);
+ const AttributeAccessor mesh_attributes_orig = bke::mesh_attributes(*surface_mesh_orig);
+
+ Curves &curves_id = *curves_geometry.get_curves_for_write();
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+
+ if (!mesh_attributes_eval.contains(uv_map_name)) {
+ pass_through_input();
+ char *message = BLI_sprintfN(TIP_("Evaluated surface missing UV map: %s"),
+ uv_map_name.c_str());
+ params.error_message_add(NodeWarningType::Error, message);
+ MEM_freeN(message);
+ return;
+ }
+ if (!mesh_attributes_orig.contains(uv_map_name)) {
+ pass_through_input();
+ char *message = BLI_sprintfN(TIP_("Original surface missing UV map: %s"), uv_map_name.c_str());
+ params.error_message_add(NodeWarningType::Error, message);
+ MEM_freeN(message);
+ return;
+ }
+ if (!mesh_attributes_eval.contains(rest_position_name)) {
+ pass_through_input();
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Evaluated surface missing attribute: rest_position"));
+ return;
+ }
+ if (curves.surface_uv_coords().is_empty() && curves.curves_num() > 0) {
+ pass_through_input();
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Curves are not attached to any UV map"));
+ return;
+ }
+ const VArraySpan<float2> uv_map_orig = mesh_attributes_orig.lookup<float2>(uv_map_name,
+ ATTR_DOMAIN_CORNER);
+ const VArraySpan<float2> uv_map_eval = mesh_attributes_eval.lookup<float2>(uv_map_name,
+ ATTR_DOMAIN_CORNER);
+ const VArraySpan<float3> rest_positions = mesh_attributes_eval.lookup<float3>(rest_position_name,
+ ATTR_DOMAIN_POINT);
+ const Span<float2> surface_uv_coords = curves.surface_uv_coords();
+
+ const Span<MLoopTri> looptris_orig{BKE_mesh_runtime_looptri_ensure(surface_mesh_orig),
+ BKE_mesh_runtime_looptri_len(surface_mesh_orig)};
+ const Span<MLoopTri> looptris_eval{BKE_mesh_runtime_looptri_ensure(surface_mesh_eval),
+ BKE_mesh_runtime_looptri_len(surface_mesh_eval)};
+ const ReverseUVSampler reverse_uv_sampler_orig{uv_map_orig, looptris_orig};
+ const ReverseUVSampler reverse_uv_sampler_eval{uv_map_eval, looptris_eval};
+
+ /* Retrieve face corner normals from each mesh. It's necessary to use face corner normals
+ * because face normals or vertex normals may lose information (custom normals, auto smooth) in
+ * some cases. It isn't yet possible to retrieve lazily calculated face corner normals from a
+ * const mesh, so they are calculated here every time. */
+ Array<float3> corner_normals_orig(surface_mesh_orig->totloop);
+ Array<float3> corner_normals_eval(surface_mesh_eval->totloop);
+ BKE_mesh_calc_normals_split_ex(
+ surface_mesh_orig, nullptr, reinterpret_cast<float(*)[3]>(corner_normals_orig.data()));
+ BKE_mesh_calc_normals_split_ex(
+ surface_mesh_eval, nullptr, reinterpret_cast<float(*)[3]>(corner_normals_eval.data()));
+
+ std::atomic<int> invalid_uv_count = 0;
+
+ const bke::CurvesSurfaceTransforms transforms{*self_ob_eval, surface_ob_eval};
+
+ deform_curves(curves,
+ *surface_mesh_orig,
+ *surface_mesh_eval,
+ surface_uv_coords,
+ reverse_uv_sampler_orig,
+ reverse_uv_sampler_eval,
+ corner_normals_orig,
+ corner_normals_eval,
+ rest_positions,
+ transforms.surface_to_curves,
+ invalid_uv_count);
+
+ curves.tag_positions_changed();
+
+ if (invalid_uv_count) {
+ char *message = BLI_sprintfN(TIP_("Invalid surface UVs on %d curves"),
+ invalid_uv_count.load());
+ params.error_message_add(NodeWarningType::Warning, message);
+ MEM_freeN(message);
+ }
+
+ params.set_output("Curves", curves_geometry);
+}
+
+} // namespace blender::nodes::node_geo_deform_curves_on_surface_cc
+
+void register_node_type_geo_deform_curves_on_surface()
+{
+ namespace file_ns = blender::nodes::node_geo_deform_curves_on_surface_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_DEFORM_CURVES_ON_SURFACE, "Deform Curves on Surface", NODE_CLASS_GEOMETRY);
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ ntype.declare = file_ns::node_declare;
+ node_type_size(&ntype, 170, 120, 700);
+ 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
index 99edc4d298c..b74b4e45199 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -8,10 +8,11 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "node_geometry_util.hh"
@@ -38,30 +39,17 @@ static void copy_data_based_on_map(Span<T> src, MutableSpan<T> dst, Span<int> in
}
}
-/** 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)
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes,
+ const Span<eAttrDomain> 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);
+ GAttributeReader attribute = src_attributes.lookup(attribute_id);
if (!attribute) {
continue;
}
@@ -70,9 +58,9 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
if (!domains.contains(attribute.domain)) {
continue;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
- OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, attribute.domain, data_type);
if (!result_attribute) {
@@ -81,11 +69,11 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
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>();
+ VArraySpan<T> span{attribute.varray.typed<T>()};
+ MutableSpan<T> out_span = result_attribute.span.typed<T>();
out_span.copy_from(span);
});
- result_attribute.save();
+ result_attribute.finish();
}
}
@@ -94,14 +82,14 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes
* 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 bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes,
+ const eAttrDomain 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);
+ GAttributeReader attribute = src_attributes.lookup(attribute_id);
if (!attribute) {
continue;
}
@@ -110,9 +98,9 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
if (domain != attribute.domain) {
continue;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
- OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, attribute.domain, data_type);
if (!result_attribute) {
@@ -121,23 +109,23 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin
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>();
+ VArraySpan<T> span{attribute.varray.typed<T>()};
+ MutableSpan<T> out_span = result_attribute.span.typed<T>();
copy_data_based_on_mask(span, out_span, mask);
});
- result_attribute.save();
+ result_attribute.finish();
}
}
static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind> &attributes,
- const GeometryComponent &in_component,
- GeometryComponent &result_component,
- const AttributeDomain domain,
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes,
+ const eAttrDomain 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);
+ GAttributeReader attribute = src_attributes.lookup(attribute_id);
if (!attribute) {
continue;
}
@@ -146,9 +134,9 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind
if (domain != attribute.domain) {
continue;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
- OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter result_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, attribute.domain, data_type);
if (!result_attribute) {
@@ -157,17 +145,17 @@ static void copy_attributes_based_on_map(const Map<AttributeIDRef, AttributeKind
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>();
+ VArraySpan<T> span{attribute.varray.typed<T>()};
+ MutableSpan<T> out_span = result_attribute.span.typed<T>();
copy_data_based_on_map(span, out_span, index_map);
});
- result_attribute.save();
+ result_attribute.finish();
}
}
static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind> &attributes,
- const GeometryComponent &in_component,
- GeometryComponent &out_component,
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes,
const int selected_loops_num,
const Span<int> selected_poly_indices,
const Mesh &mesh_in)
@@ -183,7 +171,7 @@ static void copy_face_corner_attributes(const Map<AttributeIDRef, AttributeKind>
}
}
copy_attributes_based_on_mask(
- attributes, in_component, out_component, ATTR_DOMAIN_CORNER, IndexMask(indices));
+ attributes, src_attributes, dst_attributes, ATTR_DOMAIN_CORNER, IndexMask(indices));
}
static void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
@@ -324,227 +312,87 @@ static void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
}
}
-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 CURVE_TYPE_POLY:
- break;
- case CURVE_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 CURVE_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;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- 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)
+static void delete_curves_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const eAttrDomain selection_domain)
{
- 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;
- }
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ GeometryComponentFieldContext field_context{src_component, selection_domain};
- SplinePtr new_spline = spline_delete(spline, IndexMask(indices_to_copy));
- output_curve->add_spline(std::move(new_spline));
- copied_splines.append(i);
- }
+ const int domain_num = src_component.attribute_domain_size(selection_domain);
+ fn::FieldEvaluator evaluator{field_context, domain_num};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ return;
}
-
- if (copied_splines.is_empty()) {
- return {};
+ if (selection.size() == domain_num) {
+ geometry_set.remove<CurveComponent>();
+ return;
}
- output_curve->attributes.reallocate(output_curve->splines().size());
- copy_dynamic_attributes(
- input_curve.attributes, output_curve->attributes, IndexMask(copied_splines));
+ CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
+ Curves &curves_id = *component.get_for_write();
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- 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_num(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(
- *curves_to_curve_eval(*src_component.get_for_read()), selection, selection_domain, invert);
- if (r_curve) {
- geometry_set.replace_curves(curve_eval_to_curves(*r_curve));
+ if (selection_domain == ATTR_DOMAIN_POINT) {
+ curves.remove_points(selection);
}
- else {
- geometry_set.replace_curves(nullptr);
+ else if (selection_domain == ATTR_DOMAIN_CURVE) {
+ curves.remove_curves(selection);
}
}
static void separate_point_cloud_selection(GeometrySet &geometry_set,
- const Field<bool> &selection_field,
- const bool invert)
+ const Field<bool> &selection_field)
{
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_num(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);
+ fn::FieldEvaluator evaluator{field_context, src_points.attribute_domain_size(ATTR_DOMAIN_POINT)};
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
+ geometry_set.replace_pointcloud(nullptr);
return;
}
- PointCloudComponent dst_points;
- dst_points.replace(pointcloud, GeometryOwnershipType::Editable);
+ PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
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);
+ copy_attributes_based_on_mask(attributes,
+ bke::pointcloud_attributes(*src_points.get_for_read()),
+ bke::pointcloud_attributes_for_write(*pointcloud),
+ ATTR_DOMAIN_POINT,
+ selection);
geometry_set.replace_pointcloud(pointcloud);
}
-static void separate_instance_selection(GeometrySet &geometry_set,
- const Field<bool> &selection_field,
- const bool invert)
+static void delete_selected_instances(GeometrySet &geometry_set,
+ const Field<bool> &selection_field)
{
InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
- const int domain_num = instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
- evaluator.add(selection_field);
+ fn::FieldEvaluator evaluator{field_context, instances.instances_num()};
+ evaluator.set_selection(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()) {
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+ if (selection.is_empty()) {
geometry_set.remove<InstancesComponent>();
return;
}
- instances.remove_instances(mask);
+ instances.remove_instances(selection);
}
static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection,
- const bool invert,
MutableSpan<int> r_vertex_map,
int *r_selected_vertices_num)
{
@@ -552,7 +400,7 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver
int selected_verts_num = 0;
for (const int i : r_vertex_map.index_range()) {
- if (vertex_selection[i] != invert) {
+ if (vertex_selection[i]) {
r_vertex_map[i] = selected_verts_num;
selected_verts_num++;
}
@@ -566,7 +414,6 @@ static void compute_selected_vertices_from_vertex_selection(const Span<bool> ver
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_selected_edges_num)
{
@@ -577,7 +424,7 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
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) {
+ if (vertex_selection[edge.v1] && vertex_selection[edge.v2]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
}
@@ -591,7 +438,6 @@ static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
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_selected_polys_num,
@@ -609,7 +455,7 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
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) {
+ if (!vertex_selection[loop.v]) {
all_verts_in_selection = false;
break;
}
@@ -633,7 +479,6 @@ static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
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_selected_vertices_num,
@@ -645,7 +490,7 @@ static void compute_selected_vertices_and_edges_from_edge_selection(
int selected_verts_num = 0;
for (const int i : IndexRange(mesh.totedge)) {
const MEdge &edge = mesh.medge[i];
- if (edge_selection[i] != invert) {
+ if (edge_selection[i]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
if (r_vertex_map[edge.v1] == -1) {
@@ -671,7 +516,6 @@ static void compute_selected_vertices_and_edges_from_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_selected_edges_num)
{
@@ -679,7 +523,7 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
int selected_edges_num = 0;
for (const int i : IndexRange(mesh.totedge)) {
- if (edge_selection[i] != invert) {
+ if (edge_selection[i]) {
r_edge_map[i] = selected_edges_num;
selected_edges_num++;
}
@@ -697,7 +541,6 @@ static void compute_selected_edges_from_edge_selection(const Mesh &mesh,
*/
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_selected_polys_num,
@@ -713,7 +556,7 @@ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
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) {
+ if (!edge_selection[loop.e]) {
all_edges_in_selection = false;
break;
}
@@ -736,7 +579,6 @@ static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
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,
@@ -746,11 +588,10 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face(
{
compute_selected_edges_from_vertex_selection(
- mesh, vertex_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, vertex_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_vertex_selection(mesh,
vertex_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -763,7 +604,6 @@ static void compute_selected_mesh_data_from_vertex_selection_edge_face(
*/
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,
@@ -774,14 +614,13 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
int *r_selected_loops_num)
{
compute_selected_vertices_from_vertex_selection(
- vertex_selection, invert, r_vertex_map, r_selected_vertices_num);
+ vertex_selection, r_vertex_map, r_selected_vertices_num);
compute_selected_edges_from_vertex_selection(
- mesh, vertex_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, vertex_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_vertex_selection(mesh,
vertex_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -795,7 +634,6 @@ static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
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,
@@ -804,10 +642,9 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face(
int *r_selected_loops_num)
{
compute_selected_edges_from_edge_selection(
- mesh, edge_selection, invert, r_edge_map, r_selected_edges_num);
+ mesh, edge_selection, r_edge_map, r_selected_edges_num);
compute_selected_polygons_from_edge_selection(mesh,
edge_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -820,7 +657,6 @@ static void compute_selected_mesh_data_from_edge_selection_edge_face(
*/
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,
@@ -833,14 +669,12 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
r_vertex_map.fill(-1);
compute_selected_vertices_and_edges_from_edge_selection(mesh,
edge_selection,
- invert,
r_vertex_map,
r_edge_map,
r_selected_vertices_num,
r_selected_edges_num);
compute_selected_polygons_from_edge_selection(mesh,
edge_selection,
- invert,
r_selected_poly_indices,
r_loop_starts,
r_selected_polys_num,
@@ -852,7 +686,6 @@ static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
*/
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_selected_polys_num,
@@ -867,7 +700,7 @@ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -883,7 +716,6 @@ static void compute_selected_polygons_from_poly_selection(const Mesh &mesh,
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,
@@ -903,7 +735,7 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -930,7 +762,6 @@ static void compute_selected_mesh_data_from_poly_selection_edge_face(
*/
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,
@@ -954,7 +785,7 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
for (const int i : IndexRange(mesh.totpoly)) {
const MPoly &poly_src = mesh.mpoly[i];
/* We keep this one. */
- if (poly_selection[i] != invert) {
+ if (poly_selection[i]) {
r_selected_poly_indices.append_unchecked(i);
r_loop_starts.append_unchecked(selected_loops_num);
selected_loops_num += poly_src.totloop;
@@ -984,10 +815,9 @@ static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
* 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 Mesh &mesh_in,
+ const Span<bool> selection,
+ const eAttrDomain domain,
const GeometryNodeDeleteGeometryMode mode)
{
/* Needed in all cases. */
@@ -996,9 +826,7 @@ static void do_mesh_separation(GeometrySet &geometry_set,
int selected_polys_num = 0;
int selected_loops_num = 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(
@@ -1017,7 +845,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_POINT:
compute_selected_mesh_data_from_vertex_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1030,7 +857,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_EDGE:
compute_selected_mesh_data_from_edge_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1043,7 +869,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_FACE:
compute_selected_mesh_data_from_poly_selection(mesh_in,
selection,
- invert,
vertex_map,
edge_map,
selected_poly_indices,
@@ -1063,7 +888,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
0,
selected_loops_num,
selected_polys_num);
- 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);
@@ -1072,18 +896,24 @@ static void do_mesh_separation(GeometrySet &geometry_set,
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_map(attributes,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
+ ATTR_DOMAIN_POINT,
+ vertex_map);
+ copy_attributes_based_on_map(attributes,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
+ ATTR_DOMAIN_EDGE,
+ edge_map);
copy_attributes_based_on_mask(attributes,
- in_component,
- out_component,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
ATTR_DOMAIN_FACE,
IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
copy_face_corner_attributes(attributes,
- in_component,
- out_component,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
selected_loops_num,
selected_poly_indices,
mesh_in);
@@ -1098,7 +928,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
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,
@@ -1109,7 +938,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
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,
@@ -1120,7 +948,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
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,
@@ -1138,7 +965,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
0,
selected_loops_num,
selected_polys_num);
- 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));
@@ -1147,17 +973,23 @@ static void do_mesh_separation(GeometrySet &geometry_set,
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(attributes,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
+ {ATTR_DOMAIN_POINT});
+ copy_attributes_based_on_map(attributes,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
+ ATTR_DOMAIN_EDGE,
+ edge_map);
copy_attributes_based_on_mask(attributes,
- in_component,
- out_component,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
ATTR_DOMAIN_FACE,
IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
copy_face_corner_attributes(attributes,
- in_component,
- out_component,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
selected_loops_num,
selected_poly_indices,
mesh_in);
@@ -1169,7 +1001,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_POINT:
compute_selected_polygons_from_vertex_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1178,7 +1009,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_EDGE:
compute_selected_polygons_from_edge_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1187,7 +1017,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
case ATTR_DOMAIN_FACE:
compute_selected_polygons_from_poly_selection(mesh_in,
selection,
- invert,
selected_poly_indices,
new_loop_starts,
&selected_polys_num,
@@ -1199,7 +1028,6 @@ static void do_mesh_separation(GeometrySet &geometry_set,
}
mesh_out = BKE_mesh_new_nomain_from_template(
&mesh_in, mesh_in.totvert, mesh_in.totedge, 0, selected_loops_num, selected_polys_num);
- 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));
@@ -1207,16 +1035,18 @@ static void do_mesh_separation(GeometrySet &geometry_set,
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(attributes,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
+ {ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE});
copy_attributes_based_on_mask(attributes,
- in_component,
- out_component,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
ATTR_DOMAIN_FACE,
IndexMask(Vector<int64_t>(selected_poly_indices.as_span())));
copy_face_corner_attributes(attributes,
- in_component,
- out_component,
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out),
selected_loops_num,
selected_poly_indices,
mesh_in);
@@ -1230,32 +1060,26 @@ static void do_mesh_separation(GeometrySet &geometry_set,
static void separate_mesh_selection(GeometrySet &geometry_set,
const Field<bool> &selection_field,
- const AttributeDomain selection_domain,
- const GeometryNodeDeleteGeometryMode mode,
- const bool invert)
+ const eAttrDomain selection_domain,
+ const GeometryNodeDeleteGeometryMode mode)
{
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_num(selection_domain)};
- selection_evaluator.add(selection_field);
- selection_evaluator.evaluate();
- const VArray_Span<bool> &selection = selection_evaluator.get_evaluated<bool>(0);
-
+ fn::FieldEvaluator evaluator{field_context,
+ src_component.attribute_domain_size(selection_domain)};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const VArray<bool> 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) {
+ if (selection.is_empty() || (selection.is_single() && selection.get_internal_single())) {
return;
}
- do_mesh_separation(geometry_set, src_component, selection, invert, selection_domain, mode);
+ const VArraySpan<bool> selection_span{selection};
+
+ do_mesh_separation(
+ geometry_set, *src_component.get_for_read(), selection_span, selection_domain, mode);
}
} // namespace blender::nodes::node_geo_delete_geometry_cc
@@ -1263,10 +1087,9 @@ static void separate_mesh_selection(GeometrySet &geometry_set,
namespace blender::nodes {
void separate_geometry(GeometrySet &geometry_set,
- const AttributeDomain domain,
+ const eAttrDomain 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;
@@ -1274,25 +1097,26 @@ void separate_geometry(GeometrySet &geometry_set,
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);
+ file_ns::separate_point_cloud_selection(geometry_set, selection_field);
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);
+ file_ns::separate_mesh_selection(geometry_set, selection_field, domain, mode);
some_valid_domain = true;
}
}
if (geometry_set.has_curves()) {
if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE)) {
- file_ns::separate_curve_selection(geometry_set, selection_field, domain, invert);
+ file_ns::delete_curves_selection(
+ geometry_set, fn::invert_boolean_field(selection_field), domain);
some_valid_domain = true;
}
}
if (geometry_set.has_instances()) {
if (domain == ATTR_DOMAIN_INSTANCE) {
- file_ns::separate_instance_selection(geometry_set, selection_field, invert);
+ file_ns::delete_selected_instances(geometry_set, selection_field);
some_valid_domain = true;
}
}
@@ -1320,7 +1144,7 @@ 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);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
/* Only show the mode when it is relevant. */
@@ -1342,21 +1166,25 @@ 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");
+ /* The node's input is a selection of elements that should be deleted, but the code is
+ * implemented as a separation operation that copies the selected elements to a new geometry.
+ * Invert the selection to avoid the need to keep track of both cases in the code. */
+ const Field<bool> selection = fn::invert_boolean_field(
+ params.extract_input<Field<bool>>("Selection"));
const NodeGeometryDeleteGeometry &storage = node_storage(params.node());
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const eAttrDomain domain = static_cast<eAttrDomain>(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);
+ separate_geometry(geometry_set, domain, mode, selection, 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);
+ separate_geometry(geometry_set, domain, mode, selection, is_error);
});
}
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 c242cfd5cf3..44793926bbd 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
@@ -247,7 +247,7 @@ BLI_NOINLINE static void eliminate_points_based_on_mask(const Span<bool> elimina
BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
const Span<float3> bary_coords,
const Span<int> looptri_indices,
- const AttributeDomain source_domain,
+ const eAttrDomain source_domain,
const GVArray &source_data,
GMutableSpan output_data)
{
@@ -290,31 +290,32 @@ BLI_NOINLINE static void propagate_existing_attributes(
const Span<int> looptri_indices)
{
const Mesh &mesh = *mesh_component.get_for_read();
+ const AttributeAccessor mesh_attributes = *mesh_component.attributes();
+ MutableAttributeAccessor point_attributes = *point_component.attributes_for_write();
for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
const AttributeIDRef attribute_id = entry.key;
- const CustomDataType output_data_type = entry.value.data_type;
+ const eCustomDataType output_data_type = entry.value.data_type;
- ReadAttributeLookup source_attribute = mesh_component.attribute_try_get_for_read(attribute_id);
+ GAttributeReader source_attribute = mesh_attributes.lookup(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(
+ GSpanAttributeWriter attribute_out = point_attributes.lookup_or_add_for_write_only_span(
attribute_id, ATTR_DOMAIN_POINT, output_data_type);
if (!attribute_out) {
continue;
}
- GMutableSpan out_span = attribute_out.as_span();
interpolate_attribute(mesh,
bary_coords,
looptri_indices,
source_attribute.domain,
source_attribute.varray,
- out_span);
- attribute_out.save();
+ attribute_out.span);
+ attribute_out.finish();
}
}
@@ -331,25 +332,21 @@ BLI_NOINLINE static void compute_attribute_outputs(const MeshComponent &mesh_com
const Span<int> looptri_indices,
const AttributeOutputs &attribute_outputs)
{
- 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();
+ MutableAttributeAccessor pointcloud_attributes = *point_component.attributes_for_write();
- OutputAttribute_Typed<float3> normal_attribute;
- OutputAttribute_Typed<float3> rotation_attribute;
+ SpanAttributeWriter<int> ids = pointcloud_attributes.lookup_or_add_for_write_only_span<int>(
+ "id", ATTR_DOMAIN_POINT);
- MutableSpan<float3> normals;
- MutableSpan<float3> rotations;
+ SpanAttributeWriter<float3> normals;
+ SpanAttributeWriter<float3> rotations;
if (attribute_outputs.normal_id) {
- normal_attribute = point_component.attribute_try_get_for_output_only<float3>(
+ normals = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
attribute_outputs.normal_id.get(), ATTR_DOMAIN_POINT);
- normals = normal_attribute.as_span();
}
if (attribute_outputs.rotation_id) {
- rotation_attribute = point_component.attribute_try_get_for_output_only<float3>(
+ rotations = pointcloud_attributes.lookup_or_add_for_write_only_span<float3>(
attribute_outputs.rotation_id.get(), ATTR_DOMAIN_POINT);
- rotations = rotation_attribute.as_span();
}
const Mesh &mesh = *mesh_component.get_for_read();
@@ -368,27 +365,27 @@ 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);
- ids[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
+ ids.span[i] = noise::hash(noise::hash_float(bary_coord), looptri_index);
float3 normal;
- if (!normals.is_empty() || !rotations.is_empty()) {
+ if (!normals.span.is_empty() || !rotations.span.is_empty()) {
normal_tri_v3(normal, v0_pos, v1_pos, v2_pos);
}
- if (!normals.is_empty()) {
- normals[i] = normal;
+ if (!normals.span.is_empty()) {
+ normals.span[i] = normal;
}
- if (!rotations.is_empty()) {
- rotations[i] = normal_to_euler_rotation(normal);
+ if (!rotations.span.is_empty()) {
+ rotations.span[i] = normal_to_euler_rotation(normal);
}
}
- id_attribute.save();
+ ids.finish();
- if (normal_attribute) {
- normal_attribute.save();
+ if (normals) {
+ normals.finish();
}
- if (rotation_attribute) {
- rotation_attribute.save();
+ if (rotations) {
+ rotations.finish();
}
}
@@ -396,13 +393,13 @@ static Array<float> calc_full_density_factors_with_selection(const MeshComponent
const Field<float> &density_field,
const Field<bool> &selection_field)
{
- const AttributeDomain attribute_domain = ATTR_DOMAIN_CORNER;
+ const eAttrDomain attribute_domain = ATTR_DOMAIN_CORNER;
GeometryComponentFieldContext field_context{component, attribute_domain};
- const int domain_num = component.attribute_domain_num(attribute_domain);
+ const int domain_size = component.attribute_domain_size(attribute_domain);
- Array<float> densities(domain_num, 0.0f);
+ Array<float> densities(domain_size, 0.0f);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(density_field, densities.as_mutable_span());
evaluator.evaluate();
@@ -500,8 +497,17 @@ static void point_distribution_calculate(GeometrySet &geometry_set,
}
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);
+ bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(
+ *pointcloud);
+ bke::SpanAttributeWriter<float3> point_positions =
+ point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
+ bke::SpanAttributeWriter<float> point_radii =
+ point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
+ point_positions.span.copy_from(positions);
+ point_radii.span.fill(0.05f);
+ point_positions.finish();
+ point_radii.finish();
+
geometry_set.replace_pointcloud(pointcloud);
PointCloudComponent &point_component =
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
index dcd9bcfb034..76eeee95239 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -143,17 +143,17 @@ static void transfer_attributes(
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)
+ const AttributeAccessor src_attributes,
+ MutableAttributeAccessor dst_attributes)
{
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);
+ GAttributeReader src_attribute = src_attributes.lookup(attribute_id);
if (!src_attribute) {
continue;
}
- AttributeDomain out_domain;
+ eAttrDomain out_domain;
if (src_attribute.domain == ATTR_DOMAIN_FACE) {
out_domain = ATTR_DOMAIN_POINT;
}
@@ -164,9 +164,9 @@ static void transfer_attributes(
/* Edges and Face Corners. */
out_domain = src_attribute.domain;
}
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, out_domain, data_type);
if (!dst_attribute) {
@@ -175,8 +175,8 @@ static void transfer_attributes(
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>();
+ VArraySpan<T> span{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst_span = dst_attribute.span.typed<T>();
if (src_attribute.domain == ATTR_DOMAIN_FACE) {
dst_span.take_front(span.size()).copy_from(span);
if (keep_boundaries) {
@@ -193,7 +193,7 @@ static void transfer_attributes(
copy_data_based_on_new_to_old_map(span, dst_span, new_to_old_face_corners_map);
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -872,16 +872,14 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
}
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);
+ bke::mesh_attributes(mesh_in),
+ bke::mesh_attributes_for_write(*mesh_out));
int loop_start = 0;
for (const int i : IndexRange(mesh_out->totpoly)) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index 90837486186..679a8ba4f8c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -61,13 +61,11 @@ struct IndexAttributes {
* \{ */
static Map<AttributeIDRef, AttributeKind> gather_attributes_without_id(
- const GeometrySet &geometry_set,
- const GeometryComponentType component_type,
- const bool include_instances)
+ const GeometrySet &geometry_set, const GeometryComponentType component_type)
{
Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
- {component_type}, component_type, include_instances, attributes);
+ {component_type}, component_type, false, attributes);
attributes.remove("id");
return attributes;
};
@@ -92,12 +90,16 @@ static Array<int> accumulate_counts_to_offsets(const IndexMask selection,
/* Utility functions for threaded copying of attribute data where possible. */
template<typename T>
-static void threaded_slice_fill(Span<int> offsets, Span<T> src, MutableSpan<T> dst)
+static void threaded_slice_fill(Span<int> offsets,
+ const IndexMask selection,
+ Span<T> src,
+ MutableSpan<T> dst)
{
BLI_assert(offsets.last() == dst.size());
+ BLI_assert(selection.size() == offsets.size() - 1);
threading::parallel_for(IndexRange(offsets.size() - 1), 512, [&](IndexRange range) {
for (const int i : range) {
- dst.slice(range_for_offsets_index(offsets, i)).fill(src[i]);
+ dst.slice(range_for_offsets_index(offsets, i)).fill(src[selection[i]]);
}
});
}
@@ -128,6 +130,9 @@ static void threaded_id_offset_copy(const Span<int> offsets,
for (const int i : range) {
dst[offsets[i]] = src[i];
const int count = offsets[i + 1] - offsets[i];
+ if (count == 0) {
+ continue;
+ }
for (const int i_duplicate : IndexRange(1, count - 1)) {
dst[offsets[i] + i_duplicate] = noise::hash(src[i], i_duplicate);
}
@@ -136,23 +141,22 @@ static void threaded_id_offset_copy(const Span<int> offsets,
}
/** Create the copy indices for the duplication domain. */
-static void create_duplicate_index_attribute(GeometryComponent &component,
- const AttributeDomain output_domain,
+static void create_duplicate_index_attribute(bke::MutableAttributeAccessor attributes,
+ const eAttrDomain output_domain,
const IndexMask selection,
const IndexAttributes &attribute_outputs,
const Span<int> offsets)
{
- OutputAttribute_Typed<int> copy_attribute = component.attribute_try_get_for_output_only<int>(
+ SpanAttributeWriter<int> duplicate_indices = attributes.lookup_or_add_for_write_only_span<int>(
attribute_outputs.duplicate_index.get(), output_domain);
- MutableSpan<int> duplicate_indices = copy_attribute.as_span();
for (const int i : IndexRange(selection.size())) {
const IndexRange range = range_for_offsets_index(offsets, i);
- MutableSpan<int> indices = duplicate_indices.slice(range);
+ MutableSpan<int> indices = duplicate_indices.span.slice(range);
for (const int i : indices.index_range()) {
indices[i] = i;
}
}
- copy_attribute.save();
+ duplicate_indices.finish();
}
/**
@@ -160,61 +164,57 @@ static void create_duplicate_index_attribute(GeometryComponent &component,
* and the duplicate number. This function is used for the point domain elements.
*/
static void copy_stable_id_point(const Span<int> offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes)
{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ GAttributeReader src_attribute = src_attributes.lookup("id");
if (!src_attribute) {
return;
}
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
if (!dst_attribute) {
return;
}
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
+ VArraySpan<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.span.typed<int>();
threaded_id_offset_copy(offsets, src, dst);
- dst_attribute.save();
+ dst_attribute.finish();
}
-/* The attributes for the point (also instance) duplicated elements are stored sequentially
- * (1,1,1,2,2,2,3,3,3,etc) They can be copied by using a simple offset array. For each domain, if
- * elements are ordered differently a custom function is called to copy the attributes.
- */
-
-static void copy_point_attributes_without_id(GeometrySet &geometry_set,
- const GeometryComponentType component_type,
- const bool include_instances,
- const Span<int> offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
+static void copy_attributes_without_id(GeometrySet &geometry_set,
+ const GeometryComponentType component_type,
+ const eAttrDomain domain,
+ const Span<int> offsets,
+ const IndexMask selection,
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes)
{
- Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
- geometry_set, component_type, include_instances);
+ const Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
+ geometry_set, component_type);
for (const 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 || src_attribute.domain != ATTR_DOMAIN_POINT) {
+ GAttributeReader src_attribute = src_attributes.lookup(attribute_id);
+ if (!src_attribute || src_attribute.domain != domain) {
continue;
}
- AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ eAttrDomain out_domain = src_attribute.domain;
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
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> src = src_attribute.varray.typed<T>();
- MutableSpan<T> dst = dst_attribute.as_span<T>();
- threaded_slice_fill<T>(offsets, src, dst);
+ VArraySpan<T> src = src_attribute.varray.typed<T>();
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
+ threaded_slice_fill<T>(offsets, selection, src, dst);
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -229,40 +229,39 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set,
* copied with an offset fill, otherwise a mapping is used.
*/
static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
- const CurveComponent &src_component,
const bke::CurvesGeometry &src_curves,
const IndexMask selection,
const Span<int> curve_offsets,
- bke::CurvesGeometry &dst_curves,
- CurveComponent &dst_component)
+ bke::CurvesGeometry &dst_curves)
{
Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_CURVE, false);
+ geometry_set, GEO_COMPONENT_TYPE_CURVE);
for (const 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);
+ GAttributeReader src_attribute = src_curves.attributes().lookup(attribute_id);
if (!src_attribute) {
continue;
}
- AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ eAttrDomain out_domain = src_attribute.domain;
+ const eCustomDataType 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);
+ GSpanAttributeWriter dst_attribute =
+ dst_curves.attributes_for_write().lookup_or_add_for_write_only_span(
+ 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> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ VArraySpan<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (out_domain) {
case ATTR_DOMAIN_CURVE:
- threaded_slice_fill<T>(curve_offsets, src, dst);
+ threaded_slice_fill<T>(curve_offsets, selection, src, dst);
break;
case ATTR_DOMAIN_POINT:
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
@@ -279,7 +278,7 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
break;
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -292,22 +291,21 @@ static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves,
const IndexMask selection,
const Span<int> curve_offsets,
- const CurveComponent &src_component,
- bke::CurvesGeometry &dst_curves,
- CurveComponent &dst_component)
+ bke::CurvesGeometry &dst_curves)
{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ GAttributeReader src_attribute = src_curves.attributes().lookup("id");
if (!src_attribute) {
return;
}
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ GSpanAttributeWriter dst_attribute =
+ dst_curves.attributes_for_write().lookup_or_add_for_write_only_span(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
if (!dst_attribute) {
return;
}
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
+ VArraySpan<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.span.typed<int>();
threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
for (const int i_selection : range) {
@@ -321,7 +319,7 @@ static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves,
}
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
static void duplicate_curves(GeometrySet &geometry_set,
@@ -364,6 +362,7 @@ static void duplicate_curves(GeometrySet &geometry_set,
point_offsets.last() = dst_points_num;
Curves *new_curves_id = bke::curves_new_nomain(dst_points_num, dst_curves_num);
+ bke::curves_copy_parameters(curves_id, *new_curves_id);
bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry);
MutableSpan<int> all_dst_offsets = new_curves.offsets_for_write();
@@ -381,18 +380,16 @@ static void duplicate_curves(GeometrySet &geometry_set,
});
all_dst_offsets.last() = dst_points_num;
- CurveComponent dst_component;
- dst_component.replace(new_curves_id, GeometryOwnershipType::Editable);
+ copy_curve_attributes_without_id(geometry_set, curves, selection, curve_offsets, new_curves);
- copy_curve_attributes_without_id(
- geometry_set, src_component, curves, selection, curve_offsets, new_curves, dst_component);
-
- copy_stable_id_curves(
- curves, selection, curve_offsets, src_component, new_curves, dst_component);
+ copy_stable_id_curves(curves, selection, curve_offsets, new_curves);
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_CURVE, selection, attribute_outputs, curve_offsets);
+ create_duplicate_index_attribute(new_curves.attributes_for_write(),
+ ATTR_DOMAIN_CURVE,
+ selection,
+ attribute_outputs,
+ curve_offsets);
}
geometry_set.replace_curves(new_curves_id);
@@ -413,23 +410,24 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
const Span<int> vert_mapping,
const Span<int> loop_mapping,
const Span<int> offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
+ const IndexMask selection,
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes)
{
Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_MESH, false);
+ geometry_set, GEO_COMPONENT_TYPE_MESH);
for (const 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);
+ GAttributeReader src_attribute = src_attributes.lookup(attribute_id);
if (!src_attribute) {
continue;
}
- AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ eAttrDomain out_domain = src_attribute.domain;
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
attribute_id, out_domain, data_type);
if (!dst_attribute) {
continue;
@@ -437,12 +435,12 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
- VArray_Span<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ VArraySpan<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (out_domain) {
case ATTR_DOMAIN_FACE:
- threaded_slice_fill<T>(offsets, src, dst);
+ threaded_slice_fill<T>(offsets, selection, src, dst);
break;
case ATTR_DOMAIN_EDGE:
threaded_mapped_copy<T>(edge_mapping, src, dst);
@@ -457,7 +455,7 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
break;
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -472,21 +470,21 @@ static void copy_stable_id_faces(const Mesh &mesh,
const IndexMask selection,
const Span<int> poly_offsets,
const Span<int> vert_mapping,
- const MeshComponent &src_component,
- MeshComponent &dst_component)
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes)
{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ GAttributeReader src_attribute = src_attributes.lookup("id");
if (!src_attribute) {
return;
}
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
if (!dst_attribute) {
return;
}
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
+ VArraySpan<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.span.typed<int>();
Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
int loop_index = 0;
@@ -509,7 +507,7 @@ static void copy_stable_id_faces(const Mesh &mesh,
}
}
- dst_attribute.save();
+ dst_attribute.finish();
}
static void duplicate_faces(GeometrySet &geometry_set,
@@ -590,22 +588,28 @@ static void duplicate_faces(GeometrySet &geometry_set,
}
}
- MeshComponent dst_component;
- dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
-
copy_face_attributes_without_id(geometry_set,
edge_mapping,
vert_mapping,
loop_mapping,
offsets,
- src_component,
- dst_component);
+ selection,
+ bke::mesh_attributes(mesh),
+ bke::mesh_attributes_for_write(*new_mesh));
- copy_stable_id_faces(mesh, selection, offsets, vert_mapping, src_component, dst_component);
+ copy_stable_id_faces(mesh,
+ selection,
+ offsets,
+ vert_mapping,
+ bke::mesh_attributes(mesh),
+ bke::mesh_attributes_for_write(*new_mesh));
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_FACE, selection, attribute_outputs, offsets);
+ create_duplicate_index_attribute(bke::mesh_attributes_for_write(*new_mesh),
+ ATTR_DOMAIN_FACE,
+ selection,
+ attribute_outputs,
+ offsets);
}
geometry_set.replace_mesh(new_mesh);
@@ -624,35 +628,36 @@ static void duplicate_faces(GeometrySet &geometry_set,
static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
const Span<int> point_mapping,
const Span<int> offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
+ const IndexMask selection,
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes)
{
Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_MESH, false);
+ geometry_set, GEO_COMPONENT_TYPE_MESH);
for (const 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);
+ GAttributeReader src_attribute = src_attributes.lookup(attribute_id);
if (!src_attribute) {
continue;
}
- const AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ const eAttrDomain out_domain = src_attribute.domain;
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(
src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
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> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ VArraySpan<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (out_domain) {
case ATTR_DOMAIN_EDGE:
- threaded_slice_fill<T>(offsets, src, dst);
+ threaded_slice_fill<T>(offsets, selection, src, dst);
break;
case ATTR_DOMAIN_POINT:
threaded_mapped_copy<T>(point_mapping, src, dst);
@@ -661,7 +666,7 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
break;
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
}
@@ -672,14 +677,14 @@ static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
static void copy_stable_id_edges(const Mesh &mesh,
const IndexMask selection,
const Span<int> edge_offsets,
- const MeshComponent &src_component,
- MeshComponent &dst_component)
+ const bke::AttributeAccessor src_attributes,
+ bke::MutableAttributeAccessor dst_attributes)
{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ GAttributeReader src_attribute = src_attributes.lookup("id");
if (!src_attribute) {
return;
}
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
if (!dst_attribute) {
return;
@@ -687,15 +692,15 @@ static void copy_stable_id_edges(const Mesh &mesh,
Span<MEdge> edges(mesh.medge, mesh.totedge);
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
+ VArraySpan<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.span.typed<int>();
threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) {
- for (const int i_edge : range) {
- const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ for (const int i_selection : range) {
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
if (edge_range.size() == 0) {
continue;
}
- const MEdge &edge = edges[i_edge];
+ const MEdge &edge = edges[selection[i_selection]];
const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2};
dst[vert_range[0]] = src[edge.v1];
@@ -706,7 +711,7 @@ static void copy_stable_id_edges(const Mesh &mesh,
}
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
static void duplicate_edges(GeometrySet &geometry_set,
@@ -739,9 +744,9 @@ static void duplicate_edges(GeometrySet &geometry_set,
Array<int> vert_orig_indices(edge_offsets.last() * 2);
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
- for (const int i_edge : range) {
- const MEdge &edge = edges[i_edge];
- const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ for (const int i_selection : range) {
+ const MEdge &edge = edges[selection[i_selection]];
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
for (const int i_duplicate : IndexRange(edge_range.size())) {
@@ -752,8 +757,8 @@ static void duplicate_edges(GeometrySet &geometry_set,
});
threading::parallel_for(selection.index_range(), 1024, [&](IndexRange range) {
- for (const int i_edge : range) {
- const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ for (const int i_selection : range) {
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_selection);
const IndexRange vert_range(edge_range.start() * 2, edge_range.size() * 2);
for (const int i_duplicate : IndexRange(edge_range.size())) {
MEdge &new_edge = new_edges[edge_range[i_duplicate]];
@@ -764,17 +769,25 @@ static void duplicate_edges(GeometrySet &geometry_set,
}
});
- MeshComponent dst_component;
- dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
-
- copy_edge_attributes_without_id(
- geometry_set, vert_orig_indices, edge_offsets, src_component, dst_component);
+ copy_edge_attributes_without_id(geometry_set,
+ vert_orig_indices,
+ edge_offsets,
+ selection,
+ bke::mesh_attributes(mesh),
+ bke::mesh_attributes_for_write(*new_mesh));
- copy_stable_id_edges(mesh, selection, edge_offsets, src_component, dst_component);
+ copy_stable_id_edges(mesh,
+ selection,
+ edge_offsets,
+ bke::mesh_attributes(mesh),
+ bke::mesh_attributes_for_write(*new_mesh));
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_EDGE, selection, attribute_outputs, edge_offsets);
+ create_duplicate_index_attribute(bke::mesh_attributes_for_write(*new_mesh),
+ ATTR_DOMAIN_EDGE,
+ selection,
+ attribute_outputs,
+ edge_offsets);
}
geometry_set.replace_mesh(new_mesh);
@@ -818,6 +831,7 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
});
Curves *new_curves_id = bke::curves_new_nomain(dst_num, dst_num);
+ bke::curves_copy_parameters(src_curves_id, *new_curves_id);
bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry);
MutableSpan<int> new_curve_offsets = new_curves.offsets_for_write();
for (const int i : new_curves.curves_range()) {
@@ -825,32 +839,30 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
}
new_curve_offsets.last() = dst_num;
- CurveComponent dst_component;
- dst_component.replace(new_curves_id, GeometryOwnershipType::Editable);
-
Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_CURVE, false);
+ geometry_set, GEO_COMPONENT_TYPE_CURVE);
for (const 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);
+ GAttributeReader src_attribute = src_component.attributes()->lookup(attribute_id);
if (!src_attribute) {
continue;
}
- AttributeDomain domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ eAttrDomain domain = src_attribute.domain;
+ const eCustomDataType 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, domain, data_type);
+ GSpanAttributeWriter dst_attribute =
+ new_curves.attributes_for_write().lookup_or_add_for_write_only_span(
+ attribute_id, domain, data_type);
if (!dst_attribute) {
continue;
}
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
- VArray_Span<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ VArraySpan<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.span.typed<T>();
switch (domain) {
case ATTR_DOMAIN_CURVE:
@@ -863,20 +875,23 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
});
break;
case ATTR_DOMAIN_POINT:
- threaded_slice_fill(offsets, src, dst);
+ threaded_slice_fill(offsets, selection, src, dst);
break;
default:
break;
}
});
- dst_attribute.save();
+ dst_attribute.finish();
}
- copy_stable_id_point(offsets, src_component, dst_component);
+ copy_stable_id_point(offsets, src_curves.attributes(), new_curves.attributes_for_write());
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_POINT, selection, attribute_outputs, offsets.as_span());
+ create_duplicate_index_attribute(new_curves.attributes_for_write(),
+ ATTR_DOMAIN_POINT,
+ selection,
+ attribute_outputs,
+ offsets.as_span());
}
geometry_set.replace_curves(new_curves_id);
@@ -910,18 +925,25 @@ static void duplicate_points_mesh(GeometrySet &geometry_set,
Mesh *new_mesh = BKE_mesh_new_nomain(offsets.last(), 0, 0, 0, 0);
MutableSpan<MVert> dst_verts(new_mesh->mvert, new_mesh->totvert);
- threaded_slice_fill(offsets.as_span(), src_verts, dst_verts);
+ threaded_slice_fill(offsets.as_span(), selection, src_verts, dst_verts);
- MeshComponent dst_component;
- dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
- copy_point_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_MESH, false, offsets, src_component, dst_component);
+ copy_attributes_without_id(geometry_set,
+ GEO_COMPONENT_TYPE_MESH,
+ ATTR_DOMAIN_POINT,
+ offsets,
+ selection,
+ bke::mesh_attributes(mesh),
+ bke::mesh_attributes_for_write(*new_mesh));
- copy_stable_id_point(offsets, src_component, dst_component);
+ copy_stable_id_point(
+ offsets, bke::mesh_attributes(mesh), bke::mesh_attributes_for_write(*new_mesh));
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_POINT, selection, attribute_outputs, offsets.as_span());
+ create_duplicate_index_attribute(bke::mesh_attributes_for_write(*new_mesh),
+ ATTR_DOMAIN_POINT,
+ selection,
+ attribute_outputs,
+ offsets.as_span());
}
geometry_set.replace_mesh(new_mesh);
@@ -940,7 +962,7 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
{
const PointCloudComponent &src_points =
*geometry_set.get_component_for_read<PointCloudComponent>();
- const int point_num = src_points.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int point_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{field_context, point_num};
@@ -953,17 +975,24 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
PointCloud *pointcloud = BKE_pointcloud_new_nomain(offsets.last());
- PointCloudComponent dst_component;
- dst_component.replace(pointcloud, GeometryOwnershipType::Editable);
- copy_point_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_POINT_CLOUD, false, offsets, src_points, dst_component);
+ copy_attributes_without_id(geometry_set,
+ GEO_COMPONENT_TYPE_POINT_CLOUD,
+ ATTR_DOMAIN_POINT,
+ offsets,
+ selection,
+ *src_points.attributes(),
+ bke::pointcloud_attributes_for_write(*pointcloud));
- copy_stable_id_point(offsets, src_points, dst_component);
+ copy_stable_id_point(
+ offsets, *src_points.attributes(), bke::pointcloud_attributes_for_write(*pointcloud));
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_POINT, selection, attribute_outputs, offsets);
+ create_duplicate_index_attribute(bke::pointcloud_attributes_for_write(*pointcloud),
+ ATTR_DOMAIN_POINT,
+ selection,
+ attribute_outputs,
+ offsets);
}
geometry_set.replace_pointcloud(pointcloud);
}
@@ -1055,12 +1084,20 @@ static void duplicate_instances(GeometrySet &geometry_set,
dst_instances.instance_reference_handles().slice(range).fill(new_handle);
}
- copy_point_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_INSTANCES, true, offsets, src_instances, dst_instances);
+ copy_attributes_without_id(geometry_set,
+ GEO_COMPONENT_TYPE_INSTANCES,
+ ATTR_DOMAIN_INSTANCE,
+ offsets,
+ selection,
+ *src_instances.attributes(),
+ *dst_instances.attributes_for_write());
if (attribute_outputs.duplicate_index) {
- create_duplicate_index_attribute(
- dst_instances, ATTR_DOMAIN_INSTANCE, selection, attribute_outputs, offsets);
+ create_duplicate_index_attribute(*dst_instances.attributes_for_write(),
+ ATTR_DOMAIN_INSTANCE,
+ selection,
+ attribute_outputs,
+ offsets);
}
geometry_set = std::move(dst_geometry);
@@ -1077,7 +1114,7 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
const NodeGeometryDuplicateElements &storage = node_storage(params.node());
- const AttributeDomain duplicate_domain = AttributeDomain(storage.domain);
+ const eAttrDomain duplicate_domain = eAttrDomain(storage.domain);
Field<int> count_field = params.extract_input<Field<int>>("Amount");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index 94fbec66bfe..84acab47661 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -57,8 +57,8 @@ static void node_geo_exec(GeoNodeExecParams params)
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
GeometryComponentFieldContext field_context{mesh_component, ATTR_DOMAIN_EDGE};
- const int domain_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
- fn::FieldEvaluator selection_evaluator{field_context, domain_num};
+ 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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
index 1f16e8d55bd..acf85e74353 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -63,24 +63,24 @@ struct AttributeOutputs {
static void save_selection_as_attribute(MeshComponent &component,
const AnonymousAttributeID *id,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const IndexMask selection)
{
- BLI_assert(!component.attribute_exists(id));
+ BLI_assert(!component.attributes()->contains(id));
- OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>(
- id, domain);
+ SpanAttributeWriter<bool> attribute =
+ component.attributes_for_write()->lookup_or_add_for_write_span<bool>(id, domain);
/* Rely on the new attribute being zeroed by default. */
- BLI_assert(!attribute.as_span().as_span().contains(true));
+ BLI_assert(!attribute.span.as_span().contains(true));
if (selection.is_range()) {
- attribute.as_span().slice(selection.as_range()).fill(true);
+ attribute.span.slice(selection.as_range()).fill(true);
}
else {
- attribute.as_span().fill_indices(selection, true);
+ attribute.span.fill_indices(selection, true);
}
- attribute.save();
+ attribute.finish();
}
static MutableSpan<MVert> mesh_verts(Mesh &mesh)
@@ -145,6 +145,33 @@ static void expand_mesh(Mesh &mesh,
BKE_mesh_update_customdata_pointers(&mesh, false);
}
+static CustomData &get_customdata(Mesh &mesh, const eAttrDomain domain)
+{
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return mesh.vdata;
+ case ATTR_DOMAIN_EDGE:
+ return mesh.edata;
+ case ATTR_DOMAIN_FACE:
+ return mesh.pdata;
+ case ATTR_DOMAIN_CORNER:
+ return mesh.ldata;
+ default:
+ BLI_assert_unreachable();
+ return mesh.vdata;
+ }
+}
+
+static MutableSpan<int> get_orig_index_layer(Mesh &mesh, const eAttrDomain domain)
+{
+ const bke::AttributeAccessor attributes = bke::mesh_attributes(mesh);
+ CustomData &custom_data = get_customdata(mesh, domain);
+ if (int *orig_indices = static_cast<int *>(CustomData_get_layer(&custom_data, CD_ORIGINDEX))) {
+ return {orig_indices, attributes.domain_size(domain)};
+ }
+ return {};
+}
+
static MEdge new_edge(const int v1, const int v2)
{
MEdge edge;
@@ -252,16 +279,18 @@ static void extrude_mesh_vertices(MeshComponent &component,
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) {
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ attributes.for_all([&](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(
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
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()) {
+ MutableSpan<T> data = attribute.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);
@@ -279,7 +308,7 @@ static void extrude_mesh_vertices(MeshComponent &component,
}
});
- attribute.save();
+ attribute.finish();
return true;
});
@@ -292,6 +321,9 @@ static void extrude_mesh_vertices(MeshComponent &component,
});
});
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_POINT, new_vert_range);
@@ -393,7 +425,7 @@ static void extrude_mesh_edges(MeshComponent &component,
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);
+ const VArray<float3> edge_offsets = edge_evaluator.get_evaluated<float3>(0);
if (edge_selection.is_empty()) {
return;
}
@@ -493,8 +525,10 @@ static void extrude_mesh_edges(MeshComponent &component,
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(
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
return true; /* Impossible to write the "normal" attribute. */
@@ -502,8 +536,8 @@ static void extrude_mesh_edges(MeshComponent &component,
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()) {
+ MutableSpan<T> data = attribute.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);
@@ -595,7 +629,7 @@ static void extrude_mesh_edges(MeshComponent &component,
}
});
- attribute.save();
+ attribute.finish();
return true;
});
@@ -615,6 +649,13 @@ static void extrude_mesh_edges(MeshComponent &component,
});
}
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_EDGE, duplicate_edge_range);
@@ -648,7 +689,7 @@ static void extrude_mesh_face_regions(MeshComponent &component,
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);
+ const VArray<float3> poly_offsets = poly_evaluator.get_evaluated<float3>(0);
if (poly_selection.is_empty()) {
return;
}
@@ -864,8 +905,10 @@ static void extrude_mesh_face_regions(MeshComponent &component,
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(
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
return true; /* Impossible to write the "normal" attribute. */
@@ -873,8 +916,8 @@ static void extrude_mesh_face_regions(MeshComponent &component,
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()) {
+ MutableSpan<T> data = attribute.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);
@@ -953,7 +996,7 @@ static void extrude_mesh_face_regions(MeshComponent &component,
}
});
- attribute.save();
+ attribute.finish();
return true;
});
@@ -983,6 +1026,17 @@ static void extrude_mesh_face_regions(MeshComponent &component,
});
}
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(new_inner_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(boundary_edge_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE);
+ poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE);
+
if (attribute_outputs.top_id) {
save_selection_as_attribute(
component, attribute_outputs.top_id.get(), ATTR_DOMAIN_FACE, poly_selection);
@@ -1105,8 +1159,10 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
});
- component.attribute_foreach([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- OutputAttribute attribute = component.attribute_try_get_for_output(
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
id, meta_data.domain, meta_data.data_type);
if (!attribute) {
return true; /* Impossible to write the "normal" attribute. */
@@ -1114,8 +1170,8 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
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()) {
+ MutableSpan<T> data = attribute.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);
@@ -1218,7 +1274,7 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
});
- attribute.save();
+ attribute.finish();
return true;
});
@@ -1232,6 +1288,16 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
});
+ MutableSpan<int> vert_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_POINT);
+ vert_orig_indices.slice(new_vert_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> edge_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_EDGE);
+ edge_orig_indices.slice(connect_edge_range).fill(ORIGINDEX_NONE);
+ edge_orig_indices.slice(duplicate_edge_range).fill(ORIGINDEX_NONE);
+
+ MutableSpan<int> poly_orig_indices = get_orig_index_layer(mesh, ATTR_DOMAIN_FACE);
+ poly_orig_indices.slice(side_poly_range).fill(ORIGINDEX_NONE);
+
/* 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. */
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
index bf956f3b83d..64861e529bc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_at_index.cc
@@ -42,7 +42,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
- const CustomDataType data_type = static_cast<CustomDataType>(node->custom2);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node->custom2);
bNodeSocket *sock_index = static_cast<bNodeSocket *>(node->inputs.first);
bNodeSocket *sock_in_float = sock_index->next;
@@ -74,10 +74,10 @@ class FieldAtIndex final : public GeometryFieldInput {
private:
Field<int> index_field_;
GField value_field_;
- AttributeDomain value_field_domain_;
+ eAttrDomain value_field_domain_;
public:
- FieldAtIndex(Field<int> index_field, GField value_field, AttributeDomain value_field_domain)
+ FieldAtIndex(Field<int> index_field, GField value_field, eAttrDomain value_field_domain)
: GeometryFieldInput(value_field.cpp_type(), "Field at Index"),
index_field_(std::move(index_field)),
value_field_(std::move(value_field)),
@@ -86,12 +86,12 @@ class FieldAtIndex final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
const GeometryComponentFieldContext value_field_context{component, value_field_domain_};
FieldEvaluator value_evaluator{value_field_context,
- component.attribute_domain_num(value_field_domain_)};
+ component.attribute_domain_size(value_field_domain_)};
value_evaluator.add(value_field_);
value_evaluator.evaluate();
const GVArray &values = value_evaluator.get_evaluated(0);
@@ -100,7 +100,7 @@ class FieldAtIndex final : public GeometryFieldInput {
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);
+ const VArray<int> indices = index_evaluator.get_evaluated<int>(0);
GVArray output_array;
attribute_math::convert_to_static_type(*type_, [&](auto dummy) {
@@ -125,7 +125,7 @@ class FieldAtIndex final : public GeometryFieldInput {
}
};
-static StringRefNull identifier_suffix(CustomDataType data_type)
+static StringRefNull identifier_suffix(eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_BOOL:
@@ -147,8 +147,8 @@ static StringRefNull identifier_suffix(CustomDataType data_type)
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);
+ const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom2);
Field<int> index_field = params.extract_input<Field<int>>("Index");
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc b/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc
new file mode 100644
index 00000000000..59e243db4a2
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_field_on_domain.cc
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#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_on_domain_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ 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 eCustomDataType data_type = static_cast<eCustomDataType>(node->custom2);
+
+ bNodeSocket *sock_in_float = static_cast<bNodeSocket *>(node->inputs.first);
+ 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 FieldOnDomain final : public GeometryFieldInput {
+ private:
+ GField src_field_;
+ eAttrDomain src_domain_;
+
+ public:
+ FieldOnDomain(GField field, eAttrDomain domain)
+ : GeometryFieldInput(field.cpp_type(), "Field on Domain"),
+ src_field_(std::move(field)),
+ src_domain_(domain)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain domain,
+ IndexMask /* mask */) const final
+ {
+ const GeometryComponentFieldContext context{component, src_domain_};
+ const int64_t src_domain_size = component.attribute_domain_size(src_domain_);
+ GArray values(src_field_.cpp_type(), src_domain_size);
+ FieldEvaluator value_evaluator{context, src_domain_size};
+ value_evaluator.add_with_destination(src_field_, values.as_mutable_span());
+ value_evaluator.evaluate();
+ return component.attributes()->adapt_domain(
+ GVArray::ForGArray(std::move(values)), src_domain_, domain);
+ }
+};
+
+static StringRefNull identifier_suffix(eCustomDataType 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 eAttrDomain domain = static_cast<eAttrDomain>(node.custom1);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(node.custom2);
+
+ 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> src_field = params.extract_input<Field<T>>(identifier);
+ Field<T> dst_field{std::make_shared<FieldOnDomain>(std::move(src_field), domain)};
+ params.set_output(identifier, std::move(dst_field));
+ });
+}
+
+} // namespace blender::nodes::node_geo_field_on_domain_cc
+
+void register_node_type_geo_field_on_domain()
+{
+ namespace file_ns = blender::nodes::node_geo_field_on_domain_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_FIELD_ON_DOMAIN, "Field on Domain", 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
index 0484017cf3b..15b2822805a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc
@@ -22,11 +22,11 @@ static void node_declare(NodeDeclarationBuilder &b)
static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selection_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.add(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
@@ -49,20 +49,21 @@ static void mesh_flip_faces(MeshComponent &component, const Field<bool> &selecti
}
}
- component.attribute_foreach(
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ attributes.for_all(
[&](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);
+ GSpanAttributeWriter attribute = attributes.lookup_or_add_for_write_span(
+ attribute_id, ATTR_DOMAIN_CORNER, meta_data.data_type);
attribute_math::convert_to_static_type(meta_data.data_type, [&](auto dummy) {
using T = decltype(dummy);
- MutableSpan<T> dst_span = attribute.as_span<T>();
+ MutableSpan<T> dst_span = attribute.span.typed<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();
+ attribute.finish();
}
return true;
});
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
index 3ba1378abe1..bc1b9e940a1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc
@@ -26,7 +26,7 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
@@ -37,13 +37,15 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
fn::FieldEvaluator evaluator(field_context, &mask);
evaluator.add(relative_);
evaluator.evaluate();
- const VArray<bool> &relative = evaluator.get_evaluated<bool>(0);
+ const VArray<bool> relative = evaluator.get_evaluated<bool>(0);
- VArray<float3> positions = component.attribute_get_for_read<float3>(
+ const AttributeAccessor attributes = *component.attributes();
+
+ VArray<float3> positions = attributes.lookup_or_default<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
StringRef side = left_ ? "handle_left" : "handle_right";
- VArray<float3> handles = component.attribute_get_for_read<float3>(
+ VArray<float3> handles = attributes.lookup_or_default<float3>(
side, ATTR_DOMAIN_POINT, {0, 0, 0});
if (relative.is_single()) {
@@ -52,10 +54,10 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
for (const int i : positions.index_range()) {
output[i] = handles[i] - positions[i];
}
- return component.attribute_try_adapt_domain<float3>(
+ return attributes.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);
+ return attributes.adapt_domain<float3>(handles, ATTR_DOMAIN_POINT, domain);
}
Array<float3> output(positions.size());
@@ -67,7 +69,7 @@ class HandlePositionFieldInput final : public GeometryFieldInput {
output[i] = handles[i];
}
}
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
new file mode 100644
index 00000000000..4c7a148a797
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_instance_rotation_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Rotation")).field_source();
+}
+
+class VectorFieldInput final : public GeometryFieldInput {
+ public:
+ VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Rotation")
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain UNUSED(domain),
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return {};
+ }
+
+ const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
+ component);
+
+ auto rotation_fn = [&](const int i) -> float3 {
+ return instance_component.instance_transforms()[i].to_euler();
+ };
+
+ return VArray<float3>::ForFunc(instance_component.instances_num(), rotation_fn);
+ }
+
+ uint64_t hash() const override
+ {
+ return 22374372;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float3> rotation{std::make_shared<VectorFieldInput>()};
+ params.set_output("Rotation", std::move(rotation));
+}
+
+} // namespace blender::nodes::node_geo_input_instance_rotation_cc
+
+void register_node_type_geo_input_instance_rotation()
+{
+ namespace file_ns = blender::nodes::node_geo_input_instance_rotation_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_INPUT_INSTANCE_ROTATION, "Instance Rotation", 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_instance_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
new file mode 100644
index 00000000000..b3a362fbf3e
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_scale.cc
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_instance_scale_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Vector>(N_("Scale")).field_source();
+}
+
+class VectorFieldInput final : public GeometryFieldInput {
+ public:
+ VectorFieldInput() : GeometryFieldInput(CPPType::get<float3>(), "Scale")
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain UNUSED(domain),
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_INSTANCES) {
+ return {};
+ }
+
+ const InstancesComponent &instance_component = static_cast<const InstancesComponent &>(
+ component);
+
+ auto scale_fn = [&](const int i) -> float3 {
+ return instance_component.instance_transforms()[i].scale();
+ };
+
+ return VArray<float3>::ForFunc(instance_component.instances_num(), scale_fn);
+ }
+
+ uint64_t hash() const override
+ {
+ return 8346343;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const VectorFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float3> scale{std::make_shared<VectorFieldInput>()};
+ params.set_output("Scale", std::move(scale));
+}
+
+} // namespace blender::nodes::node_geo_input_instance_scale_cc
+
+void register_node_type_geo_input_instance_scale()
+{
+ namespace file_ns = blender::nodes::node_geo_input_instance_scale_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_INSTANCE_SCALE, "Instance Scale", 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
index 60640bcb112..b009aaa5291 100644
--- 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
@@ -61,7 +61,7 @@ class AngleFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -91,7 +91,7 @@ class AngleFieldInput final : public GeometryFieldInput {
};
VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
- return component.attribute_try_adapt_domain<float>(
+ return component.attributes()->adapt_domain<float>(
std::move(angles), ATTR_DOMAIN_EDGE, domain);
}
@@ -115,7 +115,7 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -166,7 +166,7 @@ class SignedAngleFieldInput final : public GeometryFieldInput {
};
VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
- return component.attribute_try_adapt_domain<float>(
+ return component.attributes()->adapt_domain<float>(
std::move(angles), ATTR_DOMAIN_EDGE, domain);
}
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
index 92172ce7ebd..50d6998bb27 100644
--- 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
@@ -25,7 +25,7 @@ class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
@@ -40,7 +40,7 @@ class EdgeNeighborCountFieldInput final : public GeometryFieldInput {
face_count[mesh->mloop[i].e]++;
}
- return mesh_component.attribute_try_adapt_domain<int>(
+ return mesh_component.attributes()->adapt_domain<int>(
VArray<int>::ForContainer(std::move(face_count)), ATTR_DOMAIN_EDGE, domain);
}
return {};
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
index 213a692d80f..83e511f45c2 100644
--- 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
@@ -29,7 +29,7 @@ enum VertexNumber { VERTEX_ONE, VERTEX_TWO };
static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &component,
const VertexNumber vertex,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -58,7 +58,7 @@ class EdgeVerticesFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
@@ -85,7 +85,7 @@ class EdgeVerticesFieldInput final : public GeometryFieldInput {
static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &component,
const VertexNumber vertex,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -93,14 +93,14 @@ static VArray<float3> construct_edge_positions_gvarray(const MeshComponent &comp
}
if (vertex == VERTEX_ONE) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->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>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForFunc(
mesh->totedge,
[mesh](const int i) { return float3(mesh->mvert[mesh->medge[i].v2].co); }),
@@ -120,7 +120,7 @@ class EdgePositionFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
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
index 6f58d28100a..4d21bf9443a 100644
--- 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
@@ -17,7 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -29,7 +29,7 @@ static VArray<float> construct_face_area_gvarray(const MeshComponent &component,
return BKE_mesh_calc_poly_area(mp, &mesh->mloop[mp->loopstart], mesh->mvert);
};
- return component.attribute_try_adapt_domain<float>(
+ return component.attributes()->adapt_domain<float>(
VArray<float>::ForFunc(mesh->totpoly, area_fn), ATTR_DOMAIN_FACE, domain);
}
@@ -41,7 +41,7 @@ class FaceAreaFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
index 62af0476057..6b04ff08d9e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc
@@ -34,7 +34,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
[[maybe_unused]] IndexMask mask) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -51,7 +51,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
fn::FieldEvaluator evaluator{context, mesh->totpoly};
evaluator.add(threshold_);
evaluator.evaluate();
- const VArray<float> &thresholds = evaluator.get_evaluated<float>(0);
+ const VArray<float> thresholds = evaluator.get_evaluated<float>(0);
Span<float3> poly_normals{(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly};
@@ -65,7 +65,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
float3 reference_normal = poly_normals[i_poly];
float min = FLT_MAX;
- float max = FLT_MIN;
+ float max = -FLT_MAX;
for (const int i_loop : poly_loops.index_range()) {
const float3 vert = mesh->mvert[poly_loops[i_loop].v].co;
@@ -80,7 +80,7 @@ class PlanarFieldInput final : public GeometryFieldInput {
return max - min < thresholds[i_poly] / 2.0f;
};
- return component.attribute_try_adapt_domain<bool>(
+ return component.attributes()->adapt_domain<bool>(
VArray<bool>::ForFunc(mesh->totpoly, planar_fn), ATTR_DOMAIN_FACE, domain);
}
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
index 9968c53f649..a225ce61b14 100644
--- 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
@@ -20,7 +20,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -40,7 +40,7 @@ static VArray<int> construct_neighbor_count_gvarray(const MeshComponent &compone
}
}
- return component.attribute_try_adapt_domain<int>(
+ return component.attributes()->adapt_domain<int>(
VArray<int>::ForContainer(std::move(poly_count)), ATTR_DOMAIN_FACE, domain);
}
@@ -53,7 +53,7 @@ class FaceNeighborCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
@@ -76,14 +76,14 @@ class FaceNeighborCountFieldInput final : public GeometryFieldInput {
};
static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
return {};
}
- return component.attribute_try_adapt_domain<int>(
+ return component.attributes()->adapt_domain<int>(
VArray<int>::ForFunc(mesh->totpoly,
[mesh](const int i) -> float { return mesh->mpoly[i].totloop; }),
ATTR_DOMAIN_FACE,
@@ -98,7 +98,7 @@ class FaceVertexCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
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
index 8e3a9b6769d..2c7eef5665f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -30,7 +30,7 @@ class IslandFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -54,7 +54,7 @@ class IslandFieldInput final : public GeometryFieldInput {
output[i] = ordered_roots.index_of_or_add(root);
}
- return mesh_component.attribute_try_adapt_domain<int>(
+ return mesh_component.attributes()->adapt_domain<int>(
VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
}
@@ -78,7 +78,7 @@ class IslandCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -101,7 +101,8 @@ class IslandCountFieldInput final : public GeometryFieldInput {
island_list.add(root);
}
- return VArray<int>::ForSingle(island_list.size(), mesh_component.attribute_domain_num(domain));
+ return VArray<int>::ForSingle(island_list.size(),
+ mesh_component.attribute_domain_size(domain));
}
uint64_t hash() const override
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
index b81016eda18..62b3f9d0e92 100644
--- 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
@@ -21,7 +21,7 @@ static void node_declare(NodeDeclarationBuilder &b)
}
static VArray<int> construct_vertex_count_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -47,7 +47,7 @@ class VertexCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
@@ -70,7 +70,7 @@ class VertexCountFieldInput final : public GeometryFieldInput {
};
static VArray<int> construct_face_count_gvarray(const MeshComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const Mesh *mesh = component.get_for_read();
if (mesh == nullptr) {
@@ -96,7 +96,7 @@ class VertexFaceCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_MESH) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
index 72dfff7cb39..122c7b352c7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_named_attribute.cc
@@ -37,7 +37,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryInputNamedAttribute &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *socket_vector = (bNodeSocket *)node->outputs.first;
bNodeSocket *socket_float = socket_vector->next;
@@ -58,7 +58,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
search_link_ops_for_declarations(params, declaration.inputs());
if (params.in_out() == SOCK_OUT) {
- const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
static_cast<eNodeSocketDatatype>(params.other_socket().type));
if (type && *type != CD_PROP_STRING) {
/* The input and output sockets have the same name. */
@@ -74,7 +74,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_geo_exec(GeoNodeExecParams params)
{
const NodeGeometryInputNamedAttribute &storage = node_storage(params.node());
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
const std::string name = params.extract_input<std::string>("Name");
@@ -82,8 +82,13 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_default_remaining_outputs();
return;
}
+ if (!bke::allow_procedural_attribute_access(name)) {
+ params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message));
+ params.set_default_remaining_outputs();
+ return;
+ }
- params.used_named_attribute(name, NamedAttributeUsage::Read);
+ params.used_named_attribute(name, eNamedAttrUsage::Read);
switch (data_type) {
case CD_PROP_FLOAT:
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
index 84d773ff8eb..267ba44cc00 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
@@ -17,7 +17,7 @@ static void node_declare(NodeDeclarationBuilder &b)
*/
static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -32,7 +32,7 @@ static VArray<int> construct_curve_point_count_gvarray(const CurveComponent &com
}
if (domain == ATTR_DOMAIN_POINT) {
VArray<int> count = VArray<int>::ForFunc(curves.curves_num(), count_fn);
- return component.attribute_try_adapt_domain<int>(
+ return component.attributes()->adapt_domain<int>(
std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
@@ -47,7 +47,7 @@ class SplineCountFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
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 039d6b69585..a2aab5464aa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -64,7 +64,7 @@ static Array<float3> curve_tangent_point_domain(const bke::CurvesGeometry &curve
}
static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (!component.has_curves()) {
return {};
@@ -75,7 +75,7 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp
const VArray<int8_t> types = curves.curve_types();
if (curves.is_single_type(CURVE_TYPE_POLY)) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForSpan(curves.evaluated_tangents()), ATTR_DOMAIN_POINT, domain);
}
@@ -86,7 +86,7 @@ static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &comp
}
if (domain == ATTR_DOMAIN_CURVE) {
- return component.attribute_try_adapt_domain<float3>(
+ return component.attributes()->adapt_domain<float3>(
VArray<float3>::ForContainer(std::move(tangents)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
}
@@ -101,7 +101,7 @@ class TangentFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask UNUSED(mask)) const final
{
if (component.type() == GEO_COMPONENT_TYPE_CURVE) {
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 12582f9e9c6..3ce26a086e2 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
@@ -49,8 +49,8 @@ static void add_instances_from_component(
const GeoNodeExecParams &params,
const Map<AttributeIDRef, AttributeKind> &attributes_to_propagate)
{
- const AttributeDomain domain = ATTR_DOMAIN_POINT;
- const int domain_num = src_component.attribute_domain_num(domain);
+ const eAttrDomain domain = ATTR_DOMAIN_POINT;
+ const int domain_num = src_component.attribute_domain_size(domain);
VArray<bool> pick_instance;
VArray<int> indices;
@@ -82,7 +82,7 @@ static void add_instances_from_component(
MutableSpan<float4x4> dst_transforms = dst_component.instance_transforms().slice(start_len,
select_len);
- VArray<float3> positions = src_component.attribute_get_for_read<float3>(
+ VArray<float3> positions = src_component.attributes()->lookup_or_default<float3>(
"position", domain, {0, 0, 0});
const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>();
@@ -154,12 +154,12 @@ static void add_instances_from_component(
}
}
- bke::CustomDataAttributes &instance_attributes = dst_component.attributes();
+ bke::CustomDataAttributes &instance_attributes = dst_component.instance_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(
+ const GVArray src_attribute = src_component.attributes()->lookup_or_default(
attribute_id, ATTR_DOMAIN_POINT, attribute_kind.data_type);
BLI_assert(src_attribute);
std::optional<GMutableSpan> dst_attribute_opt = instance_attributes.get_for_write(
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
index 2126a5cc329..f14329c96da 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -22,16 +22,6 @@ static void node_declare(NodeDeclarationBuilder &b)
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,
@@ -40,9 +30,9 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>();
GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
- const int domain_num = instances.attribute_domain_num(ATTR_DOMAIN_INSTANCE);
+ const int domain_size = instances.instances_num();
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ 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));
@@ -51,16 +41,24 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
if (selection.is_empty()) {
return;
}
+ const VArray<float3> &positions = evaluator.get_evaluated<float3>(0);
+ const VArray<float> radii = evaluator.get_evaluated<float>(1);
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
geometry_set.replace_pointcloud(pointcloud);
- PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
+ bke::MutableAttributeAccessor point_attributes = bke::pointcloud_attributes_for_write(
+ *pointcloud);
- 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});
+ bke::SpanAttributeWriter<float3> point_positions =
+ point_attributes.lookup_or_add_for_write_only_span<float3>("position", ATTR_DOMAIN_POINT);
+ bke::SpanAttributeWriter<float> point_radii =
+ point_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
+
+ positions.materialize_compressed_to_uninitialized(selection, point_positions.span);
+ radii.materialize_compressed_to_uninitialized(selection, point_radii.span);
+ point_positions.finish();
+ point_radii.finish();
Map<AttributeIDRef, AttributeKind> attributes_to_propagate;
geometry_set.gather_attributes_for_propagation({GEO_COMPONENT_TYPE_INSTANCES},
@@ -75,18 +73,15 @@ static void convert_instances_to_points(GeometrySet &geometry_set,
const AttributeIDRef &attribute_id = item.key;
const AttributeKind attribute_kind = item.value;
- const GVArray src = instances.attribute_get_for_read(
+ const GVArray src = instances.attributes()->lookup_or_default(
attribute_id, ATTR_DOMAIN_INSTANCE, attribute_kind.data_type);
BLI_assert(src);
- OutputAttribute dst = points.attribute_try_get_for_output_only(
+ GSpanAttributeWriter dst = point_attributes.lookup_or_add_for_write_only_span(
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();
+ src.materialize_compressed_to_uninitialized(selection, dst.span.data());
+ dst.finish();
}
}
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 2067086c298..083a505539a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -24,7 +24,7 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info(
Map<AttributeIDRef, AttributeMetaData> info;
for (const GeometryComponent *component : components) {
- component->attribute_foreach(
+ component->attributes()->for_all(
[&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
if (attribute_id.is_named() && ignored_attributes.contains(attribute_id.name())) {
return true;
@@ -47,8 +47,8 @@ static Map<AttributeIDRef, AttributeMetaData> get_final_attribute_info(
static void fill_new_attribute(Span<const GeometryComponent *> src_components,
const AttributeIDRef &attribute_id,
- const CustomDataType data_type,
- const AttributeDomain domain,
+ const eCustomDataType data_type,
+ const eAttrDomain domain,
GMutableSpan dst_span)
{
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type);
@@ -56,14 +56,14 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
int offset = 0;
for (const GeometryComponent *component : src_components) {
- const int domain_num = component->attribute_domain_num(domain);
+ const int domain_num = component->attribute_domain_size(domain);
if (domain_num == 0) {
continue;
}
- GVArray read_attribute = component->attribute_get_for_read(
+ GVArray read_attribute = component->attributes()->lookup_or_default(
attribute_id, domain, data_type, nullptr);
- GVArray_GSpan src_span{read_attribute};
+ GVArraySpan 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_num);
@@ -83,15 +83,15 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
const AttributeIDRef attribute_id = item.key;
const AttributeMetaData &meta_data = item.value;
- OutputAttribute write_attribute = result.attribute_try_get_for_output_only(
- attribute_id, meta_data.domain, meta_data.data_type);
+ GSpanAttributeWriter write_attribute =
+ result.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, meta_data.domain, meta_data.data_type);
if (!write_attribute) {
continue;
}
- GMutableSpan dst_span = write_attribute.as_span();
fill_new_attribute(
- src_components, attribute_id, meta_data.data_type, meta_data.domain, dst_span);
- write_attribute.save();
+ src_components, attribute_id, meta_data.data_type, meta_data.domain, write_attribute.span);
+ write_attribute.finish();
}
}
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 c245260f259..ca613ae009b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -51,7 +51,7 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput {
}
GVArray get_varray_for_context(const GeometryComponent &component,
- const AttributeDomain domain,
+ const eAttrDomain domain,
IndexMask mask) const final
{
if (component.type() != GEO_COMPONENT_TYPE_MESH) {
@@ -71,7 +71,7 @@ class MaterialSelectionFieldInput final : public GeometryFieldInput {
Array<bool> selection(mesh->totpoly);
select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection);
- return mesh_component.attribute_try_adapt_domain<bool>(
+ return mesh_component.attributes()->adapt_domain<bool>(
VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain);
return nullptr;
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
index 1def4089115..a4fb79bef7a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_merge_by_distance.cc
@@ -39,7 +39,7 @@ static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_p
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = src_points.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int src_num = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext context{src_points, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{context, src_num};
evaluator.add(selection_field);
@@ -50,14 +50,14 @@ static PointCloud *pointcloud_merge_by_distance(const PointCloudComponent &src_p
return nullptr;
}
- return geometry::point_merge_by_distance(src_points, merge_distance, selection);
+ return geometry::point_merge_by_distance(*src_points.get_for_read(), merge_distance, selection);
}
static std::optional<Mesh *> mesh_merge_by_distance_connected(const MeshComponent &mesh_component,
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
Array<bool> selection(src_num);
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{context, src_num};
@@ -72,7 +72,7 @@ static std::optional<Mesh *> mesh_merge_by_distance_all(const MeshComponent &mes
const float merge_distance,
const Field<bool> &selection_field)
{
- const int src_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int src_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
GeometryComponentFieldContext context{mesh_component, ATTR_DOMAIN_POINT};
FieldEvaluator evaluator{context, src_num};
evaluator.add(selection_field);
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 b882d4bdf09..cb79ef93de9 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
@@ -480,53 +480,49 @@ static void calculate_selection_outputs(Mesh *mesh,
const ConeConfig &config,
ConeAttributeOutputs &attribute_outputs)
{
- MeshComponent mesh_component;
- mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
/* 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>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<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;
+ selection.span[config.first_vert] = true;
}
else {
- selection.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true);
+ selection.span.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true);
}
- attribute.save();
+ selection.finish();
}
/* 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>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<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;
+ selection.span[config.last_vert] = true;
}
else if (face) {
- selection.slice(config.bottom_faces_start, config.bottom_faces_len).fill(true);
+ selection.span.slice(config.bottom_faces_start, config.bottom_faces_len).fill(true);
}
else {
- selection.slice(config.last_ring_verts_start + 1, config.circle_segments).fill(true);
+ selection.span.slice(config.last_ring_verts_start + 1, config.circle_segments).fill(true);
}
- attribute.save();
+ selection.finish();
}
/* Populate "Side" selection output. */
if (attribute_outputs.side_id) {
- OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>(
+ SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_only_span<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();
+ selection.span.slice(config.side_faces_start, config.side_faces_len).fill(true);
+ selection.finish();
}
}
@@ -540,11 +536,11 @@ static void calculate_selection_outputs(Mesh *mesh,
*/
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();
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+
+ SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
+ "uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.span;
Array<float2> circle(config.circle_segments);
float angle = 0.0f;
@@ -654,7 +650,7 @@ static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
}
}
- uv_attribute.save();
+ uv_attribute.finish();
}
static Mesh *create_vertex_mesh()
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 523dbd5dac2..9baf0b3171e 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
@@ -18,23 +18,22 @@ namespace blender::nodes {
static void calculate_uvs(
Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y)
{
- 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();
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+
+ SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
+ "uv_map", ATTR_DOMAIN_CORNER);
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;
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.span[i].x = (co.x + size_x * 0.5f) * dx;
+ uv_attribute.span[i].y = (co.y + size_y * 0.5f) * dy;
}
});
- uv_attribute.save();
+ uv_attribute.finish();
}
Mesh *create_grid_mesh(const int verts_x,
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 4e0e5c7c912..f78752387c6 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
@@ -220,11 +220,11 @@ static void calculate_sphere_faces(MutableSpan<MLoop> loops,
static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float rings)
{
- 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();
+ MutableAttributeAccessor attributes = bke::mesh_attributes_for_write(*mesh);
+
+ SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
+ "uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.span;
int loop_index = 0;
const float dy = 1.0f / rings;
@@ -254,7 +254,7 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r
uvs[loop_index++] = float2(segment / segments, 1.0f - dy);
}
- uv_attribute.save();
+ uv_attribute.finish();
}
static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings)
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
index ec6acf55dd8..4a79ec159f4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -18,14 +18,15 @@ 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()) {
+ const Mesh *mesh = geometry_set.get_mesh_for_read();
+ if (mesh == nullptr) {
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_num(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);
@@ -34,7 +35,8 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- geometry_set.replace_curves(geometry::mesh_to_curve_convert(component, selection));
+ bke::CurvesGeometry curves = geometry::mesh_to_curve_convert(*mesh, selection);
+ geometry_set.replace_curves(bke::curves_new_nomain(std::move(curves)));
geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
});
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 6b23b685549..8e621d3ed97 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
@@ -58,7 +58,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
Field<float3> &position_field,
Field<float> &radius_field,
Field<bool> &selection_field,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>();
if (mesh_component == nullptr) {
@@ -66,7 +66,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
return;
}
GeometryComponentFieldContext field_context{*mesh_component, domain};
- const int domain_num = mesh_component->attribute_domain_num(domain);
+ const int domain_num = mesh_component->attribute_domain_size(domain);
if (domain_num == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
@@ -83,20 +83,20 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set,
PointCloud *pointcloud = BKE_pointcloud_new_nomain(selection.size());
geometry_set.replace_pointcloud(pointcloud);
- PointCloudComponent &point_component =
- geometry_set.get_component_for_write<PointCloudComponent>();
+ MutableAttributeAccessor pointcloud_attributes = bke::pointcloud_attributes_for_write(
+ *pointcloud);
- OutputAttribute position = point_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter position = pointcloud_attributes.lookup_or_add_for_write_only_span(
"position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
materialize_compressed_to_uninitialized_threaded(
- evaluator.get_evaluated(0), selection, position.as_span());
- position.save();
+ evaluator.get_evaluated(0), selection, position.span);
+ position.finish();
- OutputAttribute radius = point_component.attribute_try_get_for_output_only(
+ GSpanAttributeWriter radius = pointcloud_attributes.lookup_or_add_for_write_only_span(
"radius", ATTR_DOMAIN_POINT, CD_PROP_FLOAT);
materialize_compressed_to_uninitialized_threaded(
- evaluator.get_evaluated(1), selection, radius.as_span());
- radius.save();
+ evaluator.get_evaluated(1), selection, radius.span);
+ radius.finish();
Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
@@ -105,13 +105,13 @@ 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;
- GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type);
- OutputAttribute dst = point_component.attribute_try_get_for_output_only(
+ const eCustomDataType data_type = entry.value.data_type;
+ GVArray src = mesh_component->attributes()->lookup_or_default(attribute_id, domain, data_type);
+ GSpanAttributeWriter dst = pointcloud_attributes.lookup_or_add_for_write_only_span(
attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
- materialize_compressed_to_uninitialized_threaded(src, selection, dst.as_span());
- dst.save();
+ materialize_compressed_to_uninitialized_threaded(src, selection, dst.span);
+ dst.finish();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc
new file mode 100644
index 00000000000..5890e070b2f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "DEG_depsgraph_query.h"
+#include "node_geometry_util.hh"
+
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_wrapper.h"
+#include "BKE_object.h"
+#include "BKE_volume.h"
+
+#include "GEO_mesh_to_volume.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_mesh_to_volume_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryMeshToVolume)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
+ b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.01f).max(FLT_MAX);
+ b.add_input<decl::Float>(N_("Voxel Size"))
+ .default_value(0.3f)
+ .min(0.01f)
+ .max(FLT_MAX)
+ .subtype(PROP_DISTANCE);
+ b.add_input<decl::Float>(N_("Voxel Amount")).default_value(64.0f).min(0.0f).max(FLT_MAX);
+ b.add_input<decl::Float>(N_("Exterior Band Width"))
+ .default_value(0.1f)
+ .min(0.0f)
+ .max(FLT_MAX)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Width of the volume outside of the mesh"));
+ b.add_input<decl::Float>(N_("Interior Band Width"))
+ .default_value(0.0f)
+ .min(0.0f)
+ .max(FLT_MAX)
+ .subtype(PROP_DISTANCE)
+ .description(N_("Width of the volume inside of the mesh"));
+ b.add_input<decl::Bool>(N_("Fill Volume"))
+ .default_value(true)
+ .description(N_("Initialize the density grid in every cell inside the enclosed volume"));
+ 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(tree), bNode *node)
+{
+ NodeGeometryMeshToVolume *data = (NodeGeometryMeshToVolume *)MEM_callocN(
+ sizeof(NodeGeometryMeshToVolume), __func__);
+ data->resolution_mode = MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ NodeGeometryMeshToVolume *data = (NodeGeometryMeshToVolume *)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 == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT);
+ nodeSetSocketAvailability(ntree,
+ voxel_size_socket,
+ data->resolution_mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE);
+}
+
+#ifdef WITH_OPENVDB
+
+static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams &params)
+{
+ const NodeGeometryMeshToVolume &storage =
+ *(const NodeGeometryMeshToVolume *)params.node().storage;
+
+ const float density = params.get_input<float>("Density");
+ const float exterior_band_width = params.get_input<float>("Exterior Band Width");
+ const float interior_band_width = params.get_input<float>("Interior Band Width");
+ const bool fill_volume = params.get_input<bool>("Fill Volume");
+
+ geometry::MeshToVolumeResolution resolution;
+ resolution.mode = (MeshToVolumeModifierResolutionMode)storage.resolution_mode;
+ if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT) {
+ resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
+ if (resolution.settings.voxel_amount <= 0.0f) {
+ return nullptr;
+ }
+ }
+ else if (resolution.mode == MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE) {
+ resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
+ if (resolution.settings.voxel_size <= 0.0f) {
+ return nullptr;
+ }
+ }
+
+ if (mesh.totvert == 0 || mesh.totpoly == 0) {
+ return nullptr;
+ }
+
+ const float4x4 mesh_to_volume_space_transform = float4x4::identity();
+
+ auto bounds_fn = [&](float3 &r_min, float3 &r_max) {
+ float3 min{std::numeric_limits<float>::max()};
+ float3 max{-std::numeric_limits<float>::max()};
+ BKE_mesh_wrapper_minmax(&mesh, min, max);
+ r_min = min;
+ r_max = max;
+ };
+
+ const float voxel_size = geometry::volume_compute_voxel_size(params.depsgraph(),
+ bounds_fn,
+ resolution,
+ exterior_band_width,
+ mesh_to_volume_space_transform);
+
+ Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ BKE_volume_init_grids(volume);
+
+ /* Convert mesh to grid and add to volume. */
+ geometry::volume_grid_add_from_mesh(volume,
+ "density",
+ &mesh,
+ mesh_to_volume_space_transform,
+ voxel_size,
+ fill_volume,
+ exterior_band_width,
+ interior_band_width,
+ density);
+
+ return volume;
+}
+
+#endif /* WITH_OPENVDB */
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+#ifdef WITH_OPENVDB
+ GeometrySet geometry_set(params.extract_input<GeometrySet>("Mesh"));
+
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ if (geometry_set.has_mesh()) {
+ Volume *volume = create_volume_from_mesh(*geometry_set.get_mesh_for_read(), params);
+ geometry_set.replace_volume(volume);
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES});
+ }
+ });
+ 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();
+ return;
+#endif
+}
+
+} // namespace blender::nodes::node_geo_mesh_to_volume_cc
+
+void register_node_type_geo_mesh_to_volume()
+{
+ namespace file_ns = blender::nodes::node_geo_mesh_to_volume_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_VOLUME, "Mesh to Volume", NODE_CLASS_GEOMETRY);
+ ntype.declare = file_ns::node_declare;
+ node_type_size(&ntype, 200, 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;
+ node_type_storage(
+ &ntype, "NodeGeometryMeshToVolume", 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 f4d91d7496b..0b2159364f1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -2,6 +2,8 @@
#include "BLI_math_matrix.h"
+#include "BKE_geometry_set_instances.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points.cc b/source/blender/nodes/geometry/nodes/node_geo_points.cc
new file mode 100644
index 00000000000..dd32e6714f4
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_points.cc
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_pointcloud.h"
+
+#include "BLI_task.hh"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_points_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Int>(N_("Count"))
+ .default_value(1)
+ .description(N_("The number of points to create"))
+ .min(0);
+ b.add_input<decl::Vector>(N_("Position"))
+ .supports_field()
+ .default_value(float3(0.0f))
+ .description(N_("The positions of the new points"));
+ b.add_input<decl::Float>(N_("Radius"))
+ .supports_field()
+ .subtype(PROP_DISTANCE)
+ .default_value(float(0.1f))
+ .description(N_("The radii of the new points"));
+ b.add_output<decl::Geometry>(N_("Geometry"));
+}
+
+class PointsFieldContext : public FieldContext {
+ private:
+ int points_num_;
+
+ public:
+ PointsFieldContext(const int points_num) : points_num_(points_num)
+ {
+ }
+
+ int64_t points_num() const
+ {
+ return points_num_;
+ }
+
+ GVArray get_varray_for_input(const FieldInput &field_input,
+ const IndexMask mask,
+ ResourceScope &UNUSED(scope)) const
+ {
+ const bke::IDAttributeFieldInput *id_field_input =
+ dynamic_cast<const bke::IDAttributeFieldInput *>(&field_input);
+
+ const fn::IndexFieldInput *index_field_input = dynamic_cast<const fn::IndexFieldInput *>(
+ &field_input);
+
+ if (id_field_input == nullptr && index_field_input == nullptr) {
+ return {};
+ }
+
+ return fn::IndexFieldInput::get_index_varray(mask);
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const int count = params.extract_input<int>("Count");
+ if (count <= 0) {
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ Field<float3> position_field = params.extract_input<Field<float3>>("Position");
+ Field<float> radius_field = params.extract_input<Field<float>>("Radius");
+
+ PointCloud *new_point_cloud = BKE_pointcloud_new_nomain(count);
+ GeometrySet geometry_set = GeometrySet::create_with_pointcloud(new_point_cloud);
+ PointCloudComponent &points = geometry_set.get_component_for_write<PointCloudComponent>();
+ MutableAttributeAccessor attributes = *points.attributes_for_write();
+ AttributeWriter<float3> output_position = attributes.lookup_or_add_for_write<float3>(
+ "position", ATTR_DOMAIN_POINT);
+ AttributeWriter<float> output_radii = attributes.lookup_or_add_for_write<float>(
+ "radius", ATTR_DOMAIN_POINT);
+
+ PointsFieldContext context{count};
+ fn::FieldEvaluator evaluator{context, count};
+ evaluator.add_with_destination(position_field, output_position.varray);
+ evaluator.add_with_destination(radius_field, output_radii.varray);
+ evaluator.evaluate();
+
+ output_position.finish();
+ output_radii.finish();
+ params.set_output("Geometry", std::move(geometry_set));
+}
+
+} // namespace blender::nodes::node_geo_points_cc
+
+void register_node_type_geo_points()
+{
+ namespace file_ns = blender::nodes::node_geo_points_cc;
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_POINTS, "Points", 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_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
index 577b001fd06..74fff8efeee 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
@@ -18,14 +18,6 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Mesh"));
}
-template<typename T>
-static void copy_attribute_to_vertices(const Span<T> src, const IndexMask mask, MutableSpan<T> dst)
-{
- for (const int i : mask.index_range()) {
- dst[i] = src[mask[i]];
- }
-}
-
/* One improvement would be to move the attribute arrays directly to the mesh when possible. */
static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
Field<bool> &selection_field)
@@ -38,7 +30,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set,
}
GeometryComponentFieldContext field_context{*point_component, ATTR_DOMAIN_POINT};
- const int domain_num = point_component->attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int domain_num = point_component->attribute_domain_size(ATTR_DOMAIN_POINT);
if (domain_num == 0) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
@@ -59,19 +51,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;
- 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(
+ const eCustomDataType data_type = entry.value.data_type;
+ GVArray src = point_component->attributes()->lookup_or_default(
attribute_id, ATTR_DOMAIN_POINT, data_type);
+ GSpanAttributeWriter dst =
+ mesh_component.attributes_for_write()->lookup_or_add_for_write_only_span(
+ attribute_id, ATTR_DOMAIN_POINT, data_type);
if (dst && src) {
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- 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();
+ src.materialize_compressed_to_uninitialized(selection, dst.span.data());
+ dst.finish();
}
}
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
index 42cee4c0efe..28a01a5cbce 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -163,12 +163,15 @@ static void gather_point_data_from_component(GeoNodeExecParams &params,
Vector<float3> &r_positions,
Vector<float> &r_radii)
{
- VArray<float3> positions = component.attribute_get_for_read<float3>(
+ if (component.is_empty()) {
+ return;
+ }
+ VArray<float3> positions = component.attributes()->lookup_or_default<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_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ const int domain_num = component.attribute_domain_size(ATTR_DOMAIN_POINT);
r_positions.resize(r_positions.size() + domain_num);
positions.materialize(r_positions.as_mutable_span().take_back(domain_num));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index 0c30d50076f..f81748da587 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -70,7 +70,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryRaycast &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *socket_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
bNodeSocket *socket_float = socket_vector->next;
@@ -104,7 +104,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
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(
+ const std::optional<eCustomDataType> 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. */
@@ -215,7 +215,7 @@ class RaycastFunction : public fn::MultiFunction {
/* 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;
+ const eAttrDomain domain_ = ATTR_DOMAIN_CORNER;
fn::MFSignature signature_;
@@ -312,15 +312,15 @@ class RaycastFunction : public fn::MultiFunction {
}
const MeshComponent &mesh_component = *target_.get_component_for_read<MeshComponent>();
target_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
- const int domain_num = mesh_component.attribute_domain_num(domain_);
- target_evaluator_ = std::make_unique<FieldEvaluator>(*target_context_, domain_num);
+ 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)
+static GField get_input_attribute_field(GeoNodeExecParams &params, const eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_FLOAT:
@@ -387,7 +387,7 @@ 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);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
if (target.is_empty()) {
params.set_default_remaining_outputs();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
index effeac5a37f..ee279ba58f9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_remove_attribute.cc
@@ -21,6 +21,11 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
return;
}
+ if (!bke::allow_procedural_attribute_access(name)) {
+ params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message));
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+ }
std::atomic<bool> attribute_exists = false;
std::atomic<bool> cannot_delete = false;
@@ -34,7 +39,7 @@ static void node_geo_exec(GeoNodeExecParams params)
/* First check if the attribute exists before getting write access,
* to avoid potentially expensive unnecessary copies. */
const GeometryComponent &read_only_component = *geometry_set.get_component_for_read(type);
- if (read_only_component.attribute_exists(name)) {
+ if (read_only_component.attributes()->contains(name)) {
attribute_exists = true;
}
else {
@@ -42,7 +47,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
GeometryComponent &component = geometry_set.get_component_for_write(type);
- if (!component.attribute_try_delete(name)) {
+ if (!component.attributes_for_write()->remove(name)) {
cannot_delete = true;
}
}
@@ -50,7 +55,7 @@ static void node_geo_exec(GeoNodeExecParams params)
});
if (attribute_exists && !cannot_delete) {
- params.used_named_attribute(name, NamedAttributeUsage::Remove);
+ params.used_named_attribute(name, eNamedAttrUsage::Remove);
}
if (!attribute_exists) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
index 59e203afd08..d414bb1fa1d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -29,9 +29,9 @@ static void rotate_instances(GeoNodeExecParams &params, InstancesComponent &inst
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);
+ 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();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
index 7923ad6264d..d674f611c9f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
@@ -183,8 +183,7 @@ static void scale_vertex_islands_uniformly(Mesh &mesh,
}
});
- /* Positions have changed, so the normals will have to be recomputed. */
- BKE_mesh_normals_tag_dirty(&mesh);
+ BKE_mesh_tag_coords_changed(&mesh);
}
static void scale_vertex_islands_on_axis(Mesh &mesh,
@@ -228,8 +227,7 @@ static void scale_vertex_islands_on_axis(Mesh &mesh,
}
});
- /* Positions have changed, so the normals will have to be recomputed. */
- BKE_mesh_normals_tag_dirty(&mesh);
+ BKE_mesh_tag_coords_changed(&mesh);
}
static Vector<ElementIsland> prepare_face_islands(const Mesh &mesh, const IndexMask face_selection)
@@ -397,7 +395,7 @@ static void scale_edges_on_axis(MeshComponent &mesh_component, const AxisScaleFi
static void node_geo_exec(GeoNodeExecParams params)
{
const bNode &node = params.node();
- const AttributeDomain domain = static_cast<AttributeDomain>(node.custom1);
+ const eAttrDomain domain = static_cast<eAttrDomain>(node.custom1);
const GeometryNodeScaleElementsMode scale_mode = static_cast<GeometryNodeScaleElementsMode>(
node.custom2);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
index d4716a6b6f0..7156feb37d7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -31,9 +31,9 @@ static void scale_instances(GeoNodeExecParams &params, InstancesComponent &insta
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);
+ 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();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index a48d422e4c0..d785694f253 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -43,38 +43,31 @@ static void node_geo_exec(GeoNodeExecParams params)
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);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
- auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set, bool invert) {
+ auto separate_geometry_maybe_recursively = [&](GeometrySet &geometry_set,
+ const Field<bool> &selection) {
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);
+ separate_geometry(
+ geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection, 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);
+ separate_geometry(
+ geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection, is_error);
});
}
};
GeometrySet second_set(geometry_set);
if (params.output_is_required("Selection")) {
- separate_geometry_maybe_recursively(geometry_set, false);
+ separate_geometry_maybe_recursively(geometry_set, selection_field);
params.set_output("Selection", std::move(geometry_set));
}
if (params.output_is_required("Inverted")) {
- separate_geometry_maybe_recursively(second_set, true);
+ separate_geometry_maybe_recursively(second_set, fn::invert_boolean_field(selection_field));
params.set_output("Inverted", std::move(second_set));
}
}
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
index d2082924fa7..fc3cb7006bb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc
@@ -75,19 +75,19 @@ static void set_position_in_component(CurveComponent &component,
const Field<float3> &offset_field)
{
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ 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();
- const VArray<float3> &new_positions = evaluator.get_evaluated<float3>(0);
- const VArray<float3> &new_offsets = evaluator.get_evaluated<float3>(1);
+ const VArray<float3> new_positions = evaluator.get_evaluated<float3>(0);
+ const VArray<float3> new_offsets = evaluator.get_evaluated<float3>(1);
Curves &curves_id = *component.get_for_write();
bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
@@ -146,8 +146,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
has_curves = true;
const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- if (!component.attribute_exists("handle_left") ||
- !component.attribute_exists("handle_right")) {
+ const AttributeAccessor attributes = *component.attributes();
+ if (!attributes.contains("handle_left") || !attributes.contains("handle_right")) {
return;
}
has_bezier = true;
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
index 4c84093bfcb..e4fae95b5a5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -10,7 +10,7 @@ static void node_declare(NodeDeclarationBuilder &b)
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)
+ .default_value(0.005f)
.supports_field()
.subtype(PROP_DISTANCE);
b.add_output<decl::Geometry>(N_("Curve"));
@@ -20,21 +20,22 @@ 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_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
- "radius", ATTR_DOMAIN_POINT);
+ AttributeWriter<float> radii = attributes.lookup_or_add_for_write<float>("radius",
+ ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.add_with_destination(radius_field, radii.varray);
evaluator.evaluate();
- radii.save();
+ radii.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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
index 8b1e5935a61..2211ac62727 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -16,21 +16,23 @@ 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_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- OutputAttribute_Typed<float> tilts = component.attribute_try_get_for_output_only<float>(
- "tilt", ATTR_DOMAIN_POINT);
+ AttributeWriter<float> tilts = attributes.lookup_or_add_for_write<float>("tilt",
+ ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(tilt_field, tilts.varray());
+ evaluator.add_with_destination(tilt_field, tilts.varray);
evaluator.evaluate();
- tilts.save();
+ tilts.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
index ec95f9a89f5..fbb2ecbb799 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -16,37 +16,37 @@ static void set_id_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<int> &id_field)
{
- const AttributeDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ?
- ATTR_DOMAIN_INSTANCE :
- ATTR_DOMAIN_POINT;
- GeometryComponentFieldContext field_context{component, domain};
- const int domain_num = component.attribute_domain_num(domain);
- if (domain_num == 0) {
+ const eAttrDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ?
+ ATTR_DOMAIN_INSTANCE :
+ ATTR_DOMAIN_POINT;
+ const int domain_size = component.attribute_domain_size(domain);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ GeometryComponentFieldContext field_context{component, domain};
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ 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", domain);
- evaluator.add_with_destination(id_field, id_attribute.varray());
+ if (attributes.contains("id")) {
+ AttributeWriter<int> id_attribute = attributes.lookup_or_add_for_write<int>("id", domain);
+ evaluator.add_with_destination(id_field, id_attribute.varray);
evaluator.evaluate();
- id_attribute.save();
+ id_attribute.finish();
}
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", domain);
- result_ids.materialize(selection, id_attribute.as_span());
- id_attribute.save();
+ const VArray<int> result_ids = evaluator.get_evaluated<int>(0);
+ SpanAttributeWriter<int> id_attribute = attributes.lookup_or_add_for_write_span<int>("id",
+ domain);
+ result_ids.materialize(selection, id_attribute.span);
+ id_attribute.finish();
}
}
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
index 58613dae832..0dc89bb7ef4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
@@ -16,20 +16,21 @@ 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_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- OutputAttribute_Typed<int> indices = component.attribute_try_get_for_output_only<int>(
- "material_index", ATTR_DOMAIN_FACE);
+ AttributeWriter<int> indices = attributes.lookup_or_add_for_write<int>("material_index",
+ ATTR_DOMAIN_FACE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(index_field, indices.varray());
+ evaluator.add_with_destination(index_field, indices.varray);
evaluator.evaluate();
- indices.save();
+ indices.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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
index 571bead9743..da7977a4fb4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
@@ -20,21 +20,22 @@ 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_num = component.attribute_domain_num(ATTR_DOMAIN_POINT);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- OutputAttribute_Typed<float> radii = component.attribute_try_get_for_output_only<float>(
- "radius", ATTR_DOMAIN_POINT);
+ AttributeWriter<float> radii = attributes.lookup_or_add_for_write<float>("radius",
+ ATTR_DOMAIN_POINT);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(radius_field, radii.varray());
+ evaluator.add_with_destination(radius_field, radii.varray);
evaluator.evaluate();
- radii.save();
+ radii.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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 caf33108716..880252de4fa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -25,12 +25,10 @@ static void node_declare(NodeDeclarationBuilder &b)
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});
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+ AttributeWriter<float3> positions = attributes.lookup_for_write<float3>("position");
const int grain_size = 10000;
@@ -38,7 +36,7 @@ static void set_computed_position_and_offset(GeometryComponent &component,
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())) {
+ 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) {
@@ -67,18 +65,13 @@ static void set_computed_position_and_offset(GeometryComponent &component,
CurveComponent &curve_component = static_cast<CurveComponent &>(component);
Curves &curves_id = *curve_component.get_for_write();
bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- if (component.attribute_exists("handle_right") &&
- component.attribute_exists("handle_left")) {
- OutputAttribute_Typed<float3> handle_right_attribute =
- component.attribute_try_get_for_output<float3>(
- "handle_right", ATTR_DOMAIN_POINT, {0, 0, 0});
- OutputAttribute_Typed<float3> handle_left_attribute =
- component.attribute_try_get_for_output<float3>(
- "handle_left", ATTR_DOMAIN_POINT, {0, 0, 0});
- MutableSpan<float3> handle_right = handle_right_attribute.as_span();
- MutableSpan<float3> handle_left = handle_left_attribute.as_span();
-
- MutableSpan<float3> out_positions_span = positions.as_span();
+ if (attributes.contains("handle_right") && attributes.contains("handle_left")) {
+ SpanAttributeWriter<float3> handle_right_attribute =
+ attributes.lookup_or_add_for_write_span<float3>("handle_right", ATTR_DOMAIN_POINT);
+ SpanAttributeWriter<float3> handle_left_attribute =
+ attributes.lookup_or_add_for_write_span<float3>("handle_left", ATTR_DOMAIN_POINT);
+
+ MutableVArraySpan<float3> out_positions_span = positions.varray;
devirtualize_varray2(
in_positions, in_offsets, [&](const auto in_positions, const auto in_offsets) {
threading::parallel_for(
@@ -86,15 +79,16 @@ static void set_computed_position_and_offset(GeometryComponent &component,
for (const int i : selection.slice(range)) {
const float3 new_position = in_positions[i] + in_offsets[i];
const float3 delta = new_position - out_positions_span[i];
- handle_right[i] += delta;
- handle_left[i] += delta;
+ handle_right_attribute.span[i] += delta;
+ handle_left_attribute.span[i] += delta;
out_positions_span[i] = new_position;
}
});
});
- handle_right_attribute.save();
- handle_left_attribute.save();
+ out_positions_span.save();
+ handle_right_attribute.finish();
+ handle_left_attribute.finish();
/* Automatic Bezier handles must be recalculated based on the new positions. */
curves.calculate_bezier_auto_handles();
@@ -105,8 +99,8 @@ static void set_computed_position_and_offset(GeometryComponent &component,
}
}
default: {
- MutableSpan<float3> out_positions_span = positions.as_span();
- if (in_positions.is_same(positions.varray())) {
+ MutableVArraySpan<float3> out_positions_span = positions.varray;
+ 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) {
@@ -127,11 +121,12 @@ static void set_computed_position_and_offset(GeometryComponent &component,
});
});
}
+ out_positions_span.save();
break;
}
}
- positions.save();
+ positions.finish();
}
static void set_position_in_component(GeometryComponent &component,
@@ -139,25 +134,25 @@ static void set_position_in_component(GeometryComponent &component,
const Field<float3> &position_field,
const Field<float3> &offset_field)
{
- AttributeDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ?
- ATTR_DOMAIN_INSTANCE :
- ATTR_DOMAIN_POINT;
+ eAttrDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? ATTR_DOMAIN_INSTANCE :
+ ATTR_DOMAIN_POINT;
GeometryComponentFieldContext field_context{component, domain};
- const int domain_num = component.attribute_domain_num(domain);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(domain);
+ if (domain_size == 0) {
return;
}
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ 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();
- 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);
+
+ 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, selection);
}
static void node_geo_exec(GeoNodeExecParams params)
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
index b98fbd0a0fe..e0cf0f98d58 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
@@ -16,21 +16,23 @@ 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_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- OutputAttribute_Typed<bool> shades = component.attribute_try_get_for_output_only<bool>(
- "shade_smooth", ATTR_DOMAIN_FACE);
+ AttributeWriter<bool> shades = attributes.lookup_or_add_for_write<bool>("shade_smooth",
+ ATTR_DOMAIN_FACE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(shade_field, shades.varray());
+ evaluator.add_with_destination(shade_field, shades.varray);
evaluator.evaluate();
- shades.save();
+ shades.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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
index 976857883f0..a35d8d66558 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -16,21 +16,23 @@ 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_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- OutputAttribute_Typed<bool> cyclics = component.attribute_try_get_for_output_only<bool>(
- "cyclic", ATTR_DOMAIN_CURVE);
+ AttributeWriter<bool> cyclics = attributes.lookup_or_add_for_write<bool>("cyclic",
+ ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(cyclic_field, cyclics.varray());
+ evaluator.add_with_destination(cyclic_field, cyclics.varray);
evaluator.evaluate();
- cyclics.save();
+ cyclics.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
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
index 8b665376c01..fcebc1116d7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
@@ -16,21 +16,23 @@ 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_num = component.attribute_domain_num(ATTR_DOMAIN_CURVE);
- if (domain_num == 0) {
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ if (domain_size == 0) {
return;
}
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
+ GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
- OutputAttribute_Typed<int> resolutions = component.attribute_try_get_for_output_only<int>(
- "resolution", ATTR_DOMAIN_CURVE);
+ AttributeWriter<int> resolutions = attributes.lookup_or_add_for_write<int>("resolution",
+ ATTR_DOMAIN_CURVE);
- fn::FieldEvaluator evaluator{field_context, domain_num};
+ fn::FieldEvaluator evaluator{field_context, domain_size};
evaluator.set_selection(selection_field);
- evaluator.add_with_destination(resolution_field, resolutions.varray());
+ evaluator.add_with_destination(resolution_field, resolutions.varray);
evaluator.evaluate();
- resolutions.save();
+ resolutions.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
index 3b348dd0136..69a4fad10e2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_store_named_attribute.cc
@@ -45,7 +45,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_update(bNodeTree *ntree, bNode *node)
{
const NodeGeometryStoreNamedAttribute &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
bNodeSocket *socket_geometry = (bNodeSocket *)node->inputs.first;
bNodeSocket *socket_name = socket_geometry->next;
@@ -69,7 +69,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
search_link_ops_for_declarations(params, declaration.inputs().take_front(2));
if (params.in_out() == SOCK_OUT) {
- const std::optional<CustomDataType> type = node_data_type_to_custom_data_type(
+ const std::optional<eCustomDataType> type = node_data_type_to_custom_data_type(
static_cast<eNodeSocketDatatype>(params.other_socket().type));
if (type && *type != CD_PROP_STRING) {
/* The input and output sockets have the same name. */
@@ -84,41 +84,48 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void try_capture_field_on_geometry(GeometryComponent &component,
const StringRef name,
- const AttributeDomain domain,
+ const eAttrDomain domain,
const GField &field)
{
+ const int domain_size = component.attribute_domain_size(domain);
+ if (domain_size == 0) {
+ return;
+ }
+ MutableAttributeAccessor attributes = *component.attributes_for_write();
+
GeometryComponentFieldContext field_context{component, domain};
- const int domain_num = component.attribute_domain_num(domain);
- const IndexMask mask{IndexMask(domain_num)};
+ const IndexMask mask{IndexMask(domain_size)};
const CPPType &type = field.cpp_type();
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
+ const eCustomDataType data_type = bke::cpp_type_to_custom_data_type(type);
/* Could avoid allocating a new buffer if:
* - We are writing to an attribute that exists already.
* - The field does not depend on that attribute (we can't easily check for that yet). */
- void *buffer = MEM_mallocN(type.size() * domain_num, __func__);
+ void *buffer = MEM_mallocN(type.size() * domain_size, __func__);
fn::FieldEvaluator evaluator{field_context, &mask};
- evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_num});
+ evaluator.add_with_destination(field, GMutableSpan{type, buffer, domain_size});
evaluator.evaluate();
- component.attribute_try_delete(name);
- if (component.attribute_exists(name)) {
- WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name);
+ attributes.remove(name);
+ if (attributes.contains(name)) {
+ GAttributeWriter write_attribute = attributes.lookup_for_write(name);
if (write_attribute && write_attribute.domain == domain &&
write_attribute.varray.type() == type) {
write_attribute.varray.set_all(buffer);
- write_attribute.tag_modified_fn();
+ write_attribute.finish();
}
else {
/* Cannot change type of built-in attribute. */
}
- type.destruct_n(buffer, domain_num);
+ type.destruct_n(buffer, domain_size);
MEM_freeN(buffer);
}
else {
- component.attribute_try_create(name, domain, data_type, AttributeInitMove{buffer});
+ if (!attributes.add(name, domain, data_type, bke::AttributeInitMove{buffer})) {
+ MEM_freeN(buffer);
+ }
}
}
@@ -131,12 +138,17 @@ static void node_geo_exec(GeoNodeExecParams params)
params.set_output("Geometry", std::move(geometry_set));
return;
}
+ if (!bke::allow_procedural_attribute_access(name)) {
+ params.error_message_add(NodeWarningType::Info, TIP_(bke::no_procedural_access_message));
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+ }
- params.used_named_attribute(name, NamedAttributeUsage::Write);
+ params.used_named_attribute(name, eNamedAttrUsage::Write);
const NodeGeometryStoreNamedAttribute &storage = node_storage(params.node());
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
GField field;
switch (data_type) {
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 33f5eccd719..afd7db6604d 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
@@ -4,7 +4,8 @@
#include "DNA_vfont_types.h"
#include "BKE_curve.h"
-#include "BKE_spline.hh"
+#include "BKE_curve_legacy_convert.hh"
+#include "BKE_curves.hh"
#include "BKE_vfont.h"
#include "BLI_hash.h"
@@ -101,7 +102,7 @@ static void node_update(bNodeTree *ntree, bNode *node)
ntree, height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW);
}
-static float3 get_pivot_point(GeoNodeExecParams &params, CurveEval &curve)
+static float3 get_pivot_point(GeoNodeExecParams &params, bke::CurvesGeometry &curves)
{
const NodeGeometryStringToCurves &storage = node_storage(params.node());
const GeometryNodeStringToCurvesPivotMode pivot_mode = (GeometryNodeStringToCurvesPivotMode)
@@ -110,7 +111,7 @@ static float3 get_pivot_point(GeoNodeExecParams &params, CurveEval &curve)
float3 min(FLT_MAX), max(FLT_MIN);
/* Check if curve is empty. */
- if (!curve.bounds_min_max(min, max, false)) {
+ if (!curves.bounds_min_max(min, max)) {
return {0.0f, 0.0f, 0.0f};
}
@@ -156,12 +157,18 @@ struct TextLayout {
float final_font_size;
};
-static TextLayout get_text_layout(GeoNodeExecParams &params)
+static std::optional<TextLayout> get_text_layout(GeoNodeExecParams &params)
{
+ VFont *vfont = reinterpret_cast<VFont *>(params.node().id);
+ if (!vfont) {
+ params.error_message_add(NodeWarningType::Error, TIP_("Font not specified"));
+ return std::nullopt;
+ }
+
TextLayout layout;
layout.text = params.extract_input<std::string>("String");
if (layout.text.empty()) {
- return {};
+ return std::nullopt;
}
const NodeGeometryStringToCurves &storage = node_storage(params.node());
@@ -180,7 +187,6 @@ static TextLayout get_text_layout(GeoNodeExecParams &params)
const float textbox_h = overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ?
0.0f :
params.extract_input<float>("Text Box Height");
- VFont *vfont = (VFont *)params.node().id;
Curve cu = dna::shallow_zero_initialize();
cu.type = OB_FONT;
@@ -264,7 +270,7 @@ static TextLayout get_text_layout(GeoNodeExecParams &params)
/* Returns a mapping of UTF-32 character code to instance handle. */
static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
TextLayout &layout,
- InstancesComponent &instance_component)
+ InstancesComponent &instances)
{
VFont *vfont = (VFont *)params.node().id;
Map<int, int> handles;
@@ -282,22 +288,29 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams &params,
charinfo.mat_nr = 1;
BKE_vfont_build_char(&cu, &cu.nurb, layout.char_codes[i], &charinfo, 0, 0, 0, i, 1);
- std::unique_ptr<CurveEval> curve_eval = curve_eval_from_dna_curve(cu);
+ Curves *curves_id = bke::curve_legacy_to_curves(cu);
+ if (curves_id == nullptr) {
+ if (pivot_required) {
+ layout.pivot_points.add_new(layout.char_codes[i], float3(0));
+ }
+ handles.add_new(layout.char_codes[i], instances.add_reference({}));
+ continue;
+ }
+
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
BKE_nurbList_free(&cu.nurb);
float4x4 size_matrix = float4x4::identity();
size_matrix.apply_scale(layout.final_font_size);
- curve_eval->transform(size_matrix);
+ curves.transform(size_matrix);
if (pivot_required) {
- float3 pivot_point = get_pivot_point(params, *curve_eval);
+ float3 pivot_point = get_pivot_point(params, curves);
layout.pivot_points.add_new(layout.char_codes[i], pivot_point);
}
- GeometrySet geometry_set_curve = GeometrySet::create_with_curves(
- curve_eval_to_curves(*curve_eval));
- handles.add_new(layout.char_codes[i],
- instance_component.add_reference(std::move(geometry_set_curve)));
+ GeometrySet geometry_set = GeometrySet::create_with_curves(curves_id);
+ handles.add_new(layout.char_codes[i], instances.add_reference(std::move(geometry_set)));
}
return handles;
}
@@ -322,13 +335,14 @@ static void create_attributes(GeoNodeExecParams &params,
const TextLayout &layout,
InstancesComponent &instances)
{
+ MutableAttributeAccessor attributes = *instances.attributes_for_write();
+
if (params.output_is_required("Line")) {
StrongAnonymousAttributeID line_id = StrongAnonymousAttributeID("Line");
- OutputAttribute_Typed<int> line_attribute = instances.attribute_try_get_for_output_only<int>(
+ SpanAttributeWriter<int> line_attribute = attributes.lookup_or_add_for_write_only_span<int>(
line_id.get(), ATTR_DOMAIN_INSTANCE);
- MutableSpan<int> lines = line_attribute.as_span();
- lines.copy_from(layout.line_numbers);
- line_attribute.save();
+ line_attribute.span.copy_from(layout.line_numbers);
+ line_attribute.finish();
params.set_output("Line",
AnonymousAttributeFieldInput::Create<int>(std::move(line_id),
params.attribute_producer_name()));
@@ -336,15 +350,14 @@ static void create_attributes(GeoNodeExecParams &params,
if (params.output_is_required("Pivot Point")) {
StrongAnonymousAttributeID pivot_id = StrongAnonymousAttributeID("Pivot");
- OutputAttribute_Typed<float3> pivot_attribute =
- instances.attribute_try_get_for_output_only<float3>(pivot_id.get(), ATTR_DOMAIN_INSTANCE);
- MutableSpan<float3> pivots = pivot_attribute.as_span();
+ SpanAttributeWriter<float3> pivot_attribute =
+ attributes.lookup_or_add_for_write_only_span<float3>(pivot_id.get(), ATTR_DOMAIN_INSTANCE);
for (const int i : layout.char_codes.index_range()) {
- pivots[i] = layout.pivot_points.lookup(layout.char_codes[i]);
+ pivot_attribute.span[i] = layout.pivot_points.lookup(layout.char_codes[i]);
}
- pivot_attribute.save();
+ pivot_attribute.finish();
params.set_output("Pivot Point",
AnonymousAttributeFieldInput::Create<float3>(
std::move(pivot_id), params.attribute_producer_name()));
@@ -353,15 +366,19 @@ static void create_attributes(GeoNodeExecParams &params,
static void node_geo_exec(GeoNodeExecParams params)
{
- TextLayout layout = get_text_layout(params);
+ std::optional<TextLayout> layout = get_text_layout(params);
+ if (!layout) {
+ params.set_default_remaining_outputs();
+ return;
+ }
const NodeGeometryStringToCurves &storage =
*(const NodeGeometryStringToCurves *)params.node().storage;
if (storage.overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE) {
- params.set_output("Remainder", std::move(layout.truncated_text));
+ params.set_output("Remainder", std::move(layout->truncated_text));
}
- if (layout.positions.size() == 0) {
+ if (layout->positions.size() == 0) {
params.set_output("Curve Instances", GeometrySet());
params.set_default_remaining_outputs();
return;
@@ -370,9 +387,9 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Create and add instances. */
GeometrySet geometry_set_out;
InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
- Map<int, int> char_handles = create_curve_instances(params, layout, instances);
- add_instances_from_handles(instances, char_handles, layout);
- create_attributes(params, layout, instances);
+ Map<int, int> char_handles = create_curve_instances(params, *layout, instances);
+ add_instances_from_handles(instances, char_handles, *layout);
+ create_attributes(params, *layout, instances);
params.set_output("Curve Instances", std::move(geometry_set_out));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 9eda5bb34ff..eda6a51d412 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -6,6 +6,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
+#include "BKE_attribute.hh"
#include "BKE_mesh.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_mesh.h"
@@ -79,10 +80,11 @@ static void write_vertex_creases(Mesh &mesh, const VArray<float> &crease_varray)
static void write_edge_creases(MeshComponent &mesh, const VArray<float> &crease_varray)
{
- OutputAttribute_Typed<float> attribute = mesh.attribute_try_get_for_output_only<float>(
- "crease", ATTR_DOMAIN_EDGE);
- materialize_and_clamp_creases(crease_varray, attribute.as_span());
- attribute.save();
+ bke::SpanAttributeWriter<float> attribute =
+ mesh.attributes_for_write()->lookup_or_add_for_write_only_span<float>("crease",
+ ATTR_DOMAIN_EDGE);
+ materialize_and_clamp_creases(crease_varray, attribute.span);
+ attribute.finish();
}
static bool varray_is_nonzero(const VArray<float> &varray)
@@ -118,8 +120,8 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
- const int verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
- const int edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
+ const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
if (verts_num == 0 || edges_num == 0) {
return;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
index dca214660c8..cd75822f665 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -81,7 +81,7 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
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 eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
const GeometryNodeAttributeTransferMode mapping = (GeometryNodeAttributeTransferMode)
storage.mode;
@@ -123,7 +123,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
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(
+ const std::optional<eCustomDataType> 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. */
@@ -356,7 +356,7 @@ void copy_with_indices_and_comparison(const VArray<T> &src_1,
static bool component_is_available(const GeometrySet &geometry,
const GeometryComponentType type,
- const AttributeDomain domain)
+ const eAttrDomain domain)
{
if (!geometry.has(type)) {
return false;
@@ -365,7 +365,7 @@ static bool component_is_available(const GeometrySet &geometry,
if (component.is_empty()) {
return false;
}
- return component.attribute_domain_num(domain) != 0;
+ return component.attribute_domain_size(domain) != 0;
}
/**
@@ -383,7 +383,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
* 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;
+ eAttrDomain domain_ = ATTR_DOMAIN_CORNER;
fn::MFSignature signature_;
@@ -433,7 +433,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
{
const MeshComponent &mesh_component = *source_.get_component_for_read<MeshComponent>();
source_context_.emplace(GeometryComponentFieldContext{mesh_component, domain_});
- const int domain_num = mesh_component.attribute_domain_num(domain_);
+ const int domain_num = mesh_component.attribute_domain_size(domain_);
source_evaluator_ = std::make_unique<FieldEvaluator>(*source_context_, domain_num);
source_evaluator_->add(src_field_);
source_evaluator_->evaluate();
@@ -449,7 +449,7 @@ class NearestInterpolatedTransferFunction : public fn::MultiFunction {
class NearestTransferFunction : public fn::MultiFunction {
GeometrySet source_;
GField src_field_;
- AttributeDomain domain_;
+ eAttrDomain domain_;
fn::MFSignature signature_;
@@ -466,7 +466,7 @@ class NearestTransferFunction : public fn::MultiFunction {
const GVArray *point_data_;
public:
- NearestTransferFunction(GeometrySet geometry, GField src_field, AttributeDomain domain)
+ NearestTransferFunction(GeometrySet geometry, GField src_field, eAttrDomain domain)
: source_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain)
{
source_.ensure_owns_direct_data();
@@ -578,7 +578,7 @@ class NearestTransferFunction : public fn::MultiFunction {
{
if (use_mesh_) {
const MeshComponent &mesh = *source_.get_component_for_read<MeshComponent>();
- const int domain_num = mesh.attribute_domain_num(domain_);
+ const int domain_num = mesh.attribute_domain_size(domain_);
mesh_context_.emplace(GeometryComponentFieldContext(mesh, domain_));
mesh_evaluator_ = std::make_unique<FieldEvaluator>(*mesh_context_, domain_num);
mesh_evaluator_->add(src_field_);
@@ -588,7 +588,7 @@ class NearestTransferFunction : public fn::MultiFunction {
if (use_points_) {
const PointCloudComponent &points = *source_.get_component_for_read<PointCloudComponent>();
- const int domain_num = points.attribute_domain_num(domain_);
+ const int domain_num = points.attribute_domain_size(domain_);
point_context_.emplace(GeometryComponentFieldContext(points, domain_));
point_evaluator_ = std::make_unique<FieldEvaluator>(*point_context_, domain_num);
point_evaluator_->add(src_field_);
@@ -599,7 +599,7 @@ class NearestTransferFunction : public fn::MultiFunction {
};
static const GeometryComponent *find_source_component(const GeometrySet &geometry,
- const AttributeDomain domain)
+ const eAttrDomain 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. */
@@ -624,7 +624,7 @@ static const GeometryComponent *find_source_component(const GeometrySet &geometr
class IndexTransferFunction : public fn::MultiFunction {
GeometrySet src_geometry_;
GField src_field_;
- AttributeDomain domain_;
+ eAttrDomain domain_;
fn::MFSignature signature_;
@@ -633,7 +633,7 @@ class IndexTransferFunction : public fn::MultiFunction {
const GVArray *src_data_ = nullptr;
public:
- IndexTransferFunction(GeometrySet geometry, GField src_field, const AttributeDomain domain)
+ IndexTransferFunction(GeometrySet geometry, GField src_field, const eAttrDomain domain)
: src_geometry_(std::move(geometry)), src_field_(std::move(src_field)), domain_(domain)
{
src_geometry_.ensure_owns_direct_data();
@@ -658,7 +658,7 @@ class IndexTransferFunction : public fn::MultiFunction {
if (component == nullptr) {
return;
}
- const int domain_num = component->attribute_domain_num(domain_);
+ const int domain_num = component->attribute_domain_size(domain_);
geometry_context_.emplace(GeometryComponentFieldContext(*component, domain_));
evaluator_ = std::make_unique<FieldEvaluator>(*geometry_context_, domain_num);
evaluator_->add(src_field_);
@@ -684,7 +684,7 @@ class IndexTransferFunction : public fn::MultiFunction {
}
};
-static GField get_input_attribute_field(GeoNodeExecParams &params, const CustomDataType data_type)
+static GField get_input_attribute_field(GeoNodeExecParams &params, const eCustomDataType data_type)
{
switch (data_type) {
case CD_PROP_FLOAT:
@@ -737,8 +737,8 @@ static void node_geo_exec(GeoNodeExecParams params)
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);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
+ const eAttrDomain domain = static_cast<eAttrDomain>(storage.domain);
GField field = get_input_attribute_field(params, data_type);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index e95db205920..8e65e73d1e2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -47,21 +47,24 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform)
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);
+ MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud);
+ SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
+ "position", ATTR_DOMAIN_POINT);
+ for (const int i : position.span.index_range()) {
+ position.span[i] += translation;
}
+ position.finish();
}
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;
+ MutableAttributeAccessor attributes = bke::pointcloud_attributes_for_write(pointcloud);
+ SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>(
+ "position", ATTR_DOMAIN_POINT);
+ for (const int i : position.span.index_range()) {
+ position.span[i] = transform * position.span[i];
}
+ position.finish();
}
static void translate_instances(InstancesComponent &instances, const float3 translation)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
index 258c1ac3fba..ae538072e65 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -26,8 +26,8 @@ static void translate_instances(GeoNodeExecParams &params, InstancesComponent &i
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);
+ 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();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index e47dc22da04..992470e8279 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -83,9 +83,9 @@ static void node_geo_exec(GeoNodeExecParams params)
GeometryComponent &component = geometry_set.get_component_for_write<MeshComponent>();
const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
- const int domain_num = component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
GeometryComponentFieldContext context{component, ATTR_DOMAIN_FACE};
- FieldEvaluator evaluator{context, domain_num};
+ FieldEvaluator evaluator{context, domain_size};
evaluator.add(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_as_mask(0);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
new file mode 100644
index 00000000000..17413e64f7d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "GEO_uv_parametrizer.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_uv_pack_islands_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Vector>(N_("UV")).hide_value().supports_field();
+ b.add_input<decl::Bool>(N_("Selection"))
+ .default_value(true)
+ .hide_value()
+ .supports_field()
+ .description(N_("Faces to consider when packing islands"));
+ b.add_input<decl::Float>(N_("Margin"))
+ .default_value(0.001f)
+ .min(0.0f)
+ .max(1.0f)
+ .description(N_("Space between islands"));
+ b.add_input<decl::Bool>(N_("Rotate"))
+ .default_value(true)
+ .description(N_("Rotate islands for best fit"));
+ b.add_output<decl::Vector>(N_("UV")).field_source();
+}
+
+static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
+ const Field<bool> selection_field,
+ const Field<float3> uv_field,
+ const bool rotate,
+ const float margin,
+ const eAttrDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator face_evaluator{face_context, face_num};
+ face_evaluator.add(selection_field);
+ face_evaluator.evaluate();
+ const IndexMask selection = face_evaluator.get_evaluated_as_mask(0);
+ if (selection.is_empty()) {
+ return {};
+ }
+
+ const int corner_num = component.attribute_domain_size(ATTR_DOMAIN_CORNER);
+ GeometryComponentFieldContext corner_context{component, ATTR_DOMAIN_CORNER};
+ FieldEvaluator evaluator{corner_context, corner_num};
+ Array<float3> uv(corner_num);
+ evaluator.add_with_destination(uv_field, uv.as_mutable_span());
+ evaluator.evaluate();
+
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
+ for (const int mp_index : selection) {
+ const MPoly &mp = mesh->mpoly[mp_index];
+ Array<ParamKey, 16> mp_vkeys(mp.totloop);
+ Array<bool, 16> mp_pin(mp.totloop);
+ Array<bool, 16> mp_select(mp.totloop);
+ Array<const float *, 16> mp_co(mp.totloop);
+ Array<float *, 16> mp_uv(mp.totloop);
+ for (const int i : IndexRange(mp.totloop)) {
+ const MLoop &ml = mesh->mloop[mp.loopstart + i];
+ mp_vkeys[i] = ml.v;
+ mp_co[i] = mesh->mvert[ml.v].co;
+ mp_uv[i] = uv[mp.loopstart + i];
+ mp_pin[i] = false;
+ mp_select[i] = false;
+ }
+ GEO_uv_parametrizer_face_add(handle,
+ mp_index,
+ mp.totloop,
+ mp_vkeys.data(),
+ mp_co.data(),
+ mp_uv.data(),
+ mp_pin.data(),
+ mp_select.data());
+ }
+ GEO_uv_parametrizer_construct_end(handle, true, true, nullptr);
+
+ GEO_uv_parametrizer_pack(handle, margin, rotate, true);
+ GEO_uv_parametrizer_flush(handle);
+ GEO_uv_parametrizer_delete(handle);
+
+ return component.attributes()->adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
+}
+
+class PackIslandsFieldInput final : public GeometryFieldInput {
+ private:
+ const Field<bool> selection_field;
+ const Field<float3> uv_field;
+ const bool rotate;
+ const float margin;
+
+ public:
+ PackIslandsFieldInput(const Field<bool> selection_field,
+ const Field<float3> uv_field,
+ const bool rotate,
+ const float margin)
+ : GeometryFieldInput(CPPType::get<float3>(), "Pack UV Islands Field"),
+ selection_field(selection_field),
+ uv_field(uv_field),
+ rotate(rotate),
+ margin(margin)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_uv_gvarray(
+ mesh_component, selection_field, uv_field, rotate, margin, domain);
+ }
+ return {};
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ const Field<float3> uv_field = params.extract_input<Field<float3>>("UV");
+ const bool rotate = params.extract_input<bool>("Rotate");
+ const float margin = params.extract_input<float>("Margin");
+ params.set_output("UV",
+ Field<float3>(std::make_shared<PackIslandsFieldInput>(
+ selection_field, uv_field, rotate, margin)));
+}
+
+} // namespace blender::nodes::node_geo_uv_pack_islands_cc
+
+void register_node_type_geo_uv_pack_islands()
+{
+ namespace file_ns = blender::nodes::node_geo_uv_pack_islands_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_UV_PACK_ISLANDS, "Pack UV Islands", NODE_CLASS_CONVERTER);
+ 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_uv_unwrap.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
new file mode 100644
index 00000000000..03657f3e016
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "GEO_uv_parametrizer.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_uv_unwrap_cc {
+
+NODE_STORAGE_FUNCS(NodeGeometryUVUnwrap)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Bool>(N_("Selection"))
+ .default_value(true)
+ .hide_value()
+ .supports_field()
+ .description(N_("Faces to participate in the unwrap operation"));
+ b.add_input<decl::Bool>(N_("Seam"))
+ .hide_value()
+ .supports_field()
+ .description(N_("Edges to mark where the mesh is \"cut\" for the purposes of unwrapping"));
+ b.add_input<decl::Float>(N_("Margin"))
+ .default_value(0.001f)
+ .min(0.0f)
+ .max(1.0f)
+ .description(N_("Space between islands"));
+ b.add_input<decl::Bool>(N_("Fill Holes"))
+ .default_value(true)
+ .description(N_("Virtually fill holes in mesh before unwrapping, to better avoid overlaps "
+ "and preserve symmetry"));
+ b.add_output<decl::Vector>(N_("UV")).field_source().description(
+ N_("UV coordinates between 0 and 1 for each face corner in the selected faces"));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "method", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryUVUnwrap *data = MEM_cnew<NodeGeometryUVUnwrap>(__func__);
+ data->method = GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED;
+ node->storage = data;
+}
+
+static VArray<float3> construct_uv_gvarray(const MeshComponent &component,
+ const Field<bool> selection_field,
+ const Field<bool> seam_field,
+ const bool fill_holes,
+ const float margin,
+ const GeometryNodeUVUnwrapMethod method,
+ const eAttrDomain domain)
+{
+ const Mesh *mesh = component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ GeometryComponentFieldContext face_context{component, ATTR_DOMAIN_FACE};
+ FieldEvaluator face_evaluator{face_context, face_num};
+ face_evaluator.add(selection_field);
+ face_evaluator.evaluate();
+ const IndexMask selection = face_evaluator.get_evaluated_as_mask(0);
+ if (selection.is_empty()) {
+ return {};
+ }
+
+ const int edge_num = component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ GeometryComponentFieldContext edge_context{component, ATTR_DOMAIN_EDGE};
+ FieldEvaluator edge_evaluator{edge_context, edge_num};
+ edge_evaluator.add(seam_field);
+ edge_evaluator.evaluate();
+ const IndexMask seam = edge_evaluator.get_evaluated_as_mask(0);
+
+ Array<float3> uv(mesh->totloop, float3(0));
+
+ ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
+ for (const int mp_index : selection) {
+ const MPoly &mp = mesh->mpoly[mp_index];
+ Array<ParamKey, 16> mp_vkeys(mp.totloop);
+ Array<bool, 16> mp_pin(mp.totloop);
+ Array<bool, 16> mp_select(mp.totloop);
+ Array<const float *, 16> mp_co(mp.totloop);
+ Array<float *, 16> mp_uv(mp.totloop);
+ for (const int i : IndexRange(mp.totloop)) {
+ const MLoop &ml = mesh->mloop[mp.loopstart + i];
+ mp_vkeys[i] = ml.v;
+ mp_co[i] = mesh->mvert[ml.v].co;
+ mp_uv[i] = uv[mp.loopstart + i];
+ mp_pin[i] = false;
+ mp_select[i] = false;
+ }
+ GEO_uv_parametrizer_face_add(handle,
+ mp_index,
+ mp.totloop,
+ mp_vkeys.data(),
+ mp_co.data(),
+ mp_uv.data(),
+ mp_pin.data(),
+ mp_select.data());
+ }
+ for (const int i : seam) {
+ const MEdge &edge = mesh->medge[i];
+ ParamKey vkeys[2]{edge.v1, edge.v2};
+ GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
+ }
+ /* TODO: once field input nodes are able to emit warnings (T94039), emit a
+ * warning if we fail to solve an island. */
+ GEO_uv_parametrizer_construct_end(handle, fill_holes, false, nullptr);
+
+ GEO_uv_parametrizer_lscm_begin(handle, false, method == GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED);
+ GEO_uv_parametrizer_lscm_solve(handle, nullptr, nullptr);
+ GEO_uv_parametrizer_lscm_end(handle);
+ GEO_uv_parametrizer_average(handle, true, false, false);
+ GEO_uv_parametrizer_pack(handle, margin, true, true);
+ GEO_uv_parametrizer_flush(handle);
+ GEO_uv_parametrizer_delete(handle);
+
+ return component.attributes()->adapt_domain<float3>(
+ VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
+}
+
+class UnwrapFieldInput final : public GeometryFieldInput {
+ private:
+ const Field<bool> selection;
+ const Field<bool> seam;
+ const bool fill_holes;
+ const float margin;
+ const GeometryNodeUVUnwrapMethod method;
+
+ public:
+ UnwrapFieldInput(const Field<bool> selection,
+ const Field<bool> seam,
+ const bool fill_holes,
+ const float margin,
+ const GeometryNodeUVUnwrapMethod method)
+ : GeometryFieldInput(CPPType::get<float3>(), "UV Unwrap Field"),
+ selection(selection),
+ seam(seam),
+ fill_holes(fill_holes),
+ margin(margin),
+ method(method)
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const eAttrDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() == GEO_COMPONENT_TYPE_MESH) {
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ return construct_uv_gvarray(
+ mesh_component, selection, seam, fill_holes, margin, method, domain);
+ }
+ return {};
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryUVUnwrap &storage = node_storage(params.node());
+ const GeometryNodeUVUnwrapMethod method = (GeometryNodeUVUnwrapMethod)storage.method;
+ const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
+ const Field<bool> seam_field = params.extract_input<Field<bool>>("Seam");
+ const bool fill_holes = params.extract_input<bool>("Fill Holes");
+ const float margin = params.extract_input<float>("Margin");
+ params.set_output("UV",
+ Field<float3>(std::make_shared<UnwrapFieldInput>(
+ selection_field, seam_field, fill_holes, margin, method)));
+}
+
+} // namespace blender::nodes::node_geo_uv_unwrap_cc
+
+void register_node_type_geo_uv_unwrap()
+{
+ namespace file_ns = blender::nodes::node_geo_uv_unwrap_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_UV_UNWRAP, "UV Unwrap", NODE_CLASS_CONVERTER);
+ node_type_init(&ntype, file_ns::node_init);
+ node_type_storage(
+ &ntype, "NodeGeometryUVUnwrap", 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_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 8e9d7b0e46d..6979693e215 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -39,7 +39,7 @@ 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)
+static eNodeSocketDatatype custom_data_type_to_socket_type(const eCustomDataType type)
{
switch (type) {
case CD_PROP_FLOAT:
@@ -61,7 +61,7 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType
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 eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
const eNodeSocketDatatype socket_type = custom_data_type_to_socket_type(data_type);
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
@@ -82,7 +82,7 @@ static void node_gather_link_searches(GatherLinkSearchOpParams &params)
ED_spreadsheet_context_paths_set_geometry_node(bmain, snode, &viewer_node);
};
- const std::optional<CustomDataType> type = node_socket_to_custom_data_type(
+ const std::optional<eCustomDataType> type = node_socket_to_custom_data_type(
params.other_socket());
if (params.in_out() == SOCK_OUT) {
/* The viewer node only has inputs. */
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
new file mode 100644
index 00000000000..d7e9e38ea0d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifdef WITH_OPENVDB
+# include <openvdb/openvdb.h>
+# include <openvdb/tools/Dense.h>
+# include <openvdb/tools/LevelSetUtil.h>
+# include <openvdb/tools/ParticlesToLevelSet.h>
+#endif
+
+#include "node_geometry_util.hh"
+
+#include "DNA_mesh_types.h"
+
+#include "BLI_task.hh"
+
+#include "BKE_geometry_set.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+#include "BKE_volume.h"
+
+namespace blender::nodes::node_geo_volume_cube_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Density"))
+ .description(N_("Volume density per voxel"))
+ .supports_field()
+ .default_value(1.0f);
+ b.add_input<decl::Float>(N_("Background"))
+ .description(N_("Value for voxels outside of the cube"));
+
+ b.add_input<decl::Vector>(N_("Min"))
+ .description(N_("Minimum boundary of volume"))
+ .default_value(float3(-1.0f));
+ b.add_input<decl::Vector>(N_("Max"))
+ .description(N_("Maximum boundary of volume"))
+ .default_value(float3(1.0f));
+
+ b.add_input<decl::Int>(N_("Resolution X"))
+ .description(N_("Number of voxels in the X axis"))
+ .default_value(32)
+ .min(2);
+ b.add_input<decl::Int>(N_("Resolution Y"))
+ .description(N_("Number of voxels in the Y axis"))
+ .default_value(32)
+ .min(2);
+ b.add_input<decl::Int>(N_("Resolution Z"))
+ .description(N_("Number of voxels in the Z axis"))
+ .default_value(32)
+ .min(2);
+
+ b.add_output<decl::Geometry>(N_("Volume"));
+}
+
+static float map(const float x,
+ const float in_min,
+ const float in_max,
+ const float out_min,
+ const float out_max)
+{
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+class Grid3DFieldContext : public FieldContext {
+ private:
+ int3 resolution_;
+ float3 bounds_min_;
+ float3 bounds_max_;
+
+ public:
+ Grid3DFieldContext(const int3 resolution, const float3 bounds_min, const float3 bounds_max)
+ : resolution_(resolution), bounds_min_(bounds_min), bounds_max_(bounds_max)
+ {
+ }
+
+ int64_t points_num() const
+ {
+ return static_cast<int64_t>(resolution_.x) * static_cast<int64_t>(resolution_.y) *
+ static_cast<int64_t>(resolution_.z);
+ }
+
+ GVArray get_varray_for_input(const FieldInput &field_input,
+ const IndexMask UNUSED(mask),
+ ResourceScope &UNUSED(scope)) const
+ {
+ const bke::AttributeFieldInput *attribute_field_input =
+ dynamic_cast<const bke::AttributeFieldInput *>(&field_input);
+ if (attribute_field_input == nullptr) {
+ return {};
+ }
+ if (attribute_field_input->attribute_name() != "position") {
+ return {};
+ }
+
+ Array<float3> positions(this->points_num());
+
+ threading::parallel_for(IndexRange(resolution_.x), 1, [&](const IndexRange x_range) {
+ /* Start indexing at current X slice. */
+ int64_t index = x_range.start() * resolution_.y * resolution_.z;
+ for (const int64_t x_i : x_range) {
+ const float x = map(x_i, 0.0f, resolution_.x - 1, bounds_min_.x, bounds_max_.x);
+ for (const int64_t y_i : IndexRange(resolution_.y)) {
+ const float y = map(y_i, 0.0f, resolution_.y - 1, bounds_min_.y, bounds_max_.y);
+ for (const int64_t z_i : IndexRange(resolution_.z)) {
+ const float z = map(z_i, 0.0f, resolution_.z - 1, bounds_min_.z, bounds_max_.z);
+ positions[index] = float3(x, y, z);
+ index++;
+ }
+ }
+ }
+ });
+ return VArray<float3>::ForContainer(std::move(positions));
+ }
+};
+
+#ifdef WITH_OPENVDB
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const float3 bounds_min = params.extract_input<float3>("Min");
+ const float3 bounds_max = params.extract_input<float3>("Max");
+
+ const int3 resolution = int3(params.extract_input<int>("Resolution X"),
+ params.extract_input<int>("Resolution Y"),
+ params.extract_input<int>("Resolution Z"));
+
+ if (resolution.x < 2 || resolution.y < 2 || resolution.z < 2) {
+ params.error_message_add(NodeWarningType::Error, TIP_("Resolution must be greater than 1"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ if (bounds_min.x == bounds_max.x || bounds_min.y == bounds_max.y ||
+ bounds_min.z == bounds_max.z) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Bounding box volume must be greater than 0"));
+ params.set_default_remaining_outputs();
+ return;
+ }
+
+ Field<float> input_field = params.extract_input<Field<float>>("Density");
+
+ /* Evaluate input field on a 3D grid. */
+ Grid3DFieldContext context(resolution, bounds_min, bounds_max);
+ FieldEvaluator evaluator(context, context.points_num());
+ Array<float> densities(context.points_num());
+ evaluator.add_with_destination(std::move(input_field), densities.as_mutable_span());
+ evaluator.evaluate();
+
+ /* Store resulting values in openvdb grid. */
+ const float background = params.extract_input<float>("Background");
+ openvdb::FloatGrid::Ptr grid = openvdb::FloatGrid::create(background);
+ grid->setGridClass(openvdb::GRID_FOG_VOLUME);
+
+ openvdb::tools::Dense<float, openvdb::tools::LayoutZYX> dense_grid{
+ openvdb::math::CoordBBox({0, 0, 0}, {resolution.x - 1, resolution.y - 1, resolution.z - 1}),
+ densities.data()};
+ openvdb::tools::copyFromDense(dense_grid, *grid, 0.0f);
+
+ grid->transform().preTranslate(openvdb::math::Vec3<float>(-0.5f));
+ const float3 scale_fac = (bounds_max - bounds_min) / float3(resolution - 1);
+ grid->transform().postScale(openvdb::math::Vec3<float>(scale_fac.x, scale_fac.y, scale_fac.z));
+ grid->transform().postTranslate(
+ openvdb::math::Vec3<float>(bounds_min.x, bounds_min.y, bounds_min.z));
+
+ Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
+ BKE_volume_init_grids(volume);
+
+ BKE_volume_grid_add_vdb(*volume, "density", std::move(grid));
+
+ GeometrySet r_geometry_set;
+ r_geometry_set.replace_volume(volume);
+ params.set_output("Volume", r_geometry_set);
+}
+
+#else
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("Disabled, Blender was compiled without OpenVDB"));
+ params.set_default_remaining_outputs();
+}
+#endif /* WITH_OPENVDB */
+
+} // namespace blender::nodes::node_geo_volume_cube_cc
+
+void register_node_type_geo_volume_cube()
+{
+ namespace file_ns = blender::nodes::node_geo_volume_cube_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_VOLUME_CUBE, "Volume 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_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index e5827c24320..e1d1c67b8c8 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
@@ -41,7 +41,9 @@ static void node_declare(NodeDeclarationBuilder &b)
.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_("Threshold"))
+ .default_value(0.1f)
+ .description(N_("Values larger than the threshold are inside the generated mesh"));
b.add_input<decl::Float>(N_("Adaptivity")).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
b.add_output<decl::Geometry>(N_("Mesh"));
}
@@ -151,6 +153,16 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam
}
const bke::VolumeToMeshResolution resolution = get_resolution_param(params);
+
+ if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE &&
+ resolution.settings.voxel_size <= 0.0f) {
+ return nullptr;
+ }
+ if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT &&
+ resolution.settings.voxel_amount <= 0) {
+ return nullptr;
+ }
+
const Main *bmain = DEG_get_bmain(params.depsgraph());
BKE_volume_load(volume, bmain);
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 9a316190720..cf7cbbdc4bf 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -228,7 +228,7 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
all_component_types,
true,
[&](const bke::AttributeIDRef &attribute_id,
- const AttributeMetaData &meta_data,
+ const bke::AttributeMetaData &meta_data,
const GeometryComponent &UNUSED(component)) {
if (attribute_id.is_named() && names.add(attribute_id.name())) {
this->attributes_.append({attribute_id.name(), meta_data.domain, meta_data.data_type});
@@ -241,21 +241,21 @@ GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_ful
case GEO_COMPONENT_TYPE_MESH: {
const MeshComponent &mesh_component = *(const MeshComponent *)component;
MeshInfo &info = this->mesh_info.emplace();
- info.verts_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_POINT);
- info.edges_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_EDGE);
- info.faces_num = mesh_component.attribute_domain_num(ATTR_DOMAIN_FACE);
+ info.verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ info.edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ info.faces_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE);
break;
}
case GEO_COMPONENT_TYPE_CURVE: {
const CurveComponent &curve_component = *(const CurveComponent *)component;
CurveInfo &info = this->curve_info.emplace();
- info.splines_num = curve_component.attribute_domain_num(ATTR_DOMAIN_CURVE);
+ info.splines_num = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
break;
}
case GEO_COMPONENT_TYPE_POINT_CLOUD: {
const PointCloudComponent &pointcloud_component = *(const PointCloudComponent *)component;
PointCloudInfo &info = this->pointcloud_info.emplace();
- info.points_num = pointcloud_component.attribute_domain_num(ATTR_DOMAIN_POINT);
+ info.points_num = pointcloud_component.attribute_domain_size(ATTR_DOMAIN_POINT);
break;
}
case GEO_COMPONENT_TYPE_INSTANCES: {
@@ -495,7 +495,7 @@ void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds ex
void LocalGeoLogger::log_used_named_attribute(DNode node,
std::string attribute_name,
- NamedAttributeUsage usage)
+ eNamedAttrUsage usage)
{
used_named_attributes_.append({node, {std::move(attribute_name), usage}});
}
diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc
index abbfe4b823d..b7c5f9570e4 100644
--- a/source/blender/nodes/intern/node_common.cc
+++ b/source/blender/nodes/intern/node_common.cc
@@ -156,7 +156,8 @@ static void group_verify_socket_list(bNodeTree &node_tree,
bNode &node,
const ListBase &interface_sockets,
ListBase &verify_lb,
- const eNodeSocketInOut in_out)
+ const eNodeSocketInOut in_out,
+ const bool ensure_extend_socket_exists)
{
ListBase old_sockets = verify_lb;
BLI_listbase_clear(&verify_lb);
@@ -177,6 +178,17 @@ static void group_verify_socket_list(bNodeTree &node_tree,
}
}
+ if (ensure_extend_socket_exists) {
+ bNodeSocket *last_socket = static_cast<bNodeSocket *>(old_sockets.last);
+ if (last_socket != nullptr && STREQ(last_socket->identifier, "__extend__")) {
+ BLI_remlink(&old_sockets, last_socket);
+ BLI_addtail(&verify_lb, last_socket);
+ }
+ else {
+ nodeAddSocket(&node_tree, &node, in_out, "NodeSocketVirtual", "__extend__", "");
+ }
+ }
+
/* 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);
@@ -195,8 +207,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, false);
+ group_verify_socket_list(*ntree, *node, ngroup->outputs, node->outputs, SOCK_OUT, false);
}
}
@@ -484,15 +496,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
}
BLI_freelistN(&tmplinks);
-
- /* 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);
-
- /* add virtual extension socket */
- nodeAddSocket(ntree, node, SOCK_OUT, "NodeSocketVirtual", "__extend__", "");
- }
+ group_verify_socket_list(*ntree, *node, ntree->inputs, node->outputs, SOCK_OUT, true);
}
void register_node_type_group_input()
@@ -582,15 +586,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
}
BLI_freelistN(&tmplinks);
-
- /* 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);
-
- /* add virtual extension socket */
- nodeAddSocket(ntree, node, SOCK_IN, "NodeSocketVirtual", "__extend__", "");
- }
+ group_verify_socket_list(*ntree, *node, ntree->outputs, node->inputs, SOCK_IN, true);
}
void register_node_type_group_output()
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index 39d8c453e43..56e9c9f0496 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -24,7 +24,7 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin
}
void GeoNodeExecParams::used_named_attribute(std::string attribute_name,
- const NamedAttributeUsage usage)
+ const eNamedAttrUsage usage)
{
if (provider_->logger == nullptr) {
return;
@@ -37,7 +37,7 @@ void GeoNodeExecParams::check_input_geometry_set(StringRef identifier,
const GeometrySet &geometry_set) const
{
const SocketDeclaration &decl =
- *provider_->dnode->input_by_identifier(identifier).bsocket()->declaration;
+ *provider_->dnode->input_by_identifier(identifier).bsocket()->runtime->declaration;
const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl);
if (geo_decl == nullptr) {
return;
@@ -110,137 +110,6 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name
return nullptr;
}
-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. */
- const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
- const int64_t domain_num = component.attribute_domain_num(domain);
-
- if (default_value == nullptr) {
- default_value = cpp_type->default_value();
- }
-
- if (found_socket == nullptr) {
- return GVArray::ForSingle(*cpp_type, domain_num, 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. */
- GVArray attribute = component.attribute_try_get_for_read(name, domain, type);
- if (attribute) {
- return attribute;
- }
-
- /* If the attribute doesn't exist, use the default value and output an error message
- * (except when the field is empty, to avoid spamming error messages, and not when
- * the domain is empty and we don't expect an attribute anyway). */
- if (!name.empty() && component.attribute_domain_num(domain) != 0) {
- this->error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + name + "\"");
- }
- return GVArray::ForSingle(*cpp_type, domain_num, default_value);
- }
- 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 GVArray::ForSingle(*cpp_type, domain_num, 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 GVArray::ForSingle(*cpp_type, domain_num, 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 GVArray::ForSingle(*cpp_type, domain_num, 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 GVArray::ForSingle(*cpp_type, domain_num, buffer);
- }
- BLI_assert(false);
- return GVArray::ForSingle(*cpp_type, domain_num, default_value);
-}
-
-CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
- const StringRef name,
- const GeometryComponent &component,
- const CustomDataType default_type) const
-{
- const bNodeSocket *found_socket = this->find_available_socket(name);
- BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
- if (found_socket == nullptr) {
- return default_type;
- }
-
- if (found_socket->type == SOCK_STRING) {
- const std::string name = this->get_input<std::string>(found_socket->identifier);
- std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name);
- if (info) {
- return info->data_type;
- }
- return default_type;
- }
- if (found_socket->type == SOCK_FLOAT) {
- return CD_PROP_FLOAT;
- }
- if (found_socket->type == SOCK_VECTOR) {
- return CD_PROP_FLOAT3;
- }
- if (found_socket->type == SOCK_RGBA) {
- return CD_PROP_COLOR;
- }
- if (found_socket->type == SOCK_BOOLEAN) {
- return CD_PROP_BOOL;
- }
-
- BLI_assert(false);
- return default_type;
-}
-
-AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
- Span<std::string> names,
- const GeometryComponent &component,
- const AttributeDomain default_domain) const
-{
- Vector<AttributeDomain, 8> input_domains;
- for (const std::string &name : names) {
- const bNodeSocket *found_socket = this->find_available_socket(name);
- BLI_assert(found_socket != nullptr); /* A socket should be available socket for the name. */
- if (found_socket == nullptr) {
- continue;
- }
-
- if (found_socket->type == SOCK_STRING) {
- const std::string name = this->get_input<std::string>(found_socket->identifier);
- std::optional<AttributeMetaData> info = component.attribute_get_meta_data(name);
- if (info) {
- input_domains.append(info->domain);
- }
- }
- }
-
- if (input_domains.size() > 0) {
- return bke::attribute_domain_highest_priority(input_domains);
- }
-
- return default_domain;
-}
-
std::string GeoNodeExecParams::attribute_producer_name() const
{
return provider_->dnode->label_or_name() + TIP_(" node");
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 0ab446d8b0c..098f766589d 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -19,6 +19,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "DNA_collection_types.h"
#include "DNA_material_types.h"
@@ -261,8 +262,8 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user)
}
if (ntype->declare != nullptr) {
nodeDeclarationEnsureOnOutdatedNode(ntree, node);
- if (!node->declaration->matches(*node)) {
- refresh_node(*ntree, *node, *node->declaration, do_id_user);
+ if (!node->runtime->declaration->matches(*node)) {
+ refresh_node(*ntree, *node, *node->runtime->declaration, do_id_user);
}
nodeSocketDeclarationsUpdate(node);
return;
diff --git a/source/blender/nodes/intern/node_socket_declarations.cc b/source/blender/nodes/intern/node_socket_declarations.cc
index 06925761bc7..b9fb75f30c7 100644
--- a/source/blender/nodes/intern/node_socket_declarations.cc
+++ b/source/blender/nodes/intern/node_socket_declarations.cc
@@ -4,6 +4,7 @@
#include "NOD_socket_declarations_geometry.hh"
#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
#include "BLI_math_vector.h"
@@ -33,14 +34,14 @@ static bool sockets_can_connect(const SocketDeclaration &socket_decl,
return false;
}
- if (other_socket.declaration) {
+ if (other_socket.runtime->declaration) {
if (socket_decl.in_out() == SOCK_IN) {
- if (!field_types_are_compatible(socket_decl, *other_socket.declaration)) {
+ if (!field_types_are_compatible(socket_decl, *other_socket.runtime->declaration)) {
return false;
}
}
else {
- if (!field_types_are_compatible(*other_socket.declaration, socket_decl)) {
+ if (!field_types_are_compatible(*other_socket.runtime->declaration, socket_decl)) {
return false;
}
}
diff --git a/source/blender/nodes/shader/node_shader_tree.cc b/source/blender/nodes/shader/node_shader_tree.cc
index f107ec73c60..43dbf5060bd 100644
--- a/source/blender/nodes/shader/node_shader_tree.cc
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -712,6 +712,7 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
switch (node->type) {
case SH_NODE_SHADERTORGB:
+ case SH_NODE_OUTPUT_LIGHT:
case SH_NODE_OUTPUT_WORLD:
case SH_NODE_OUTPUT_MATERIAL: {
/* Start the tree with full weight. */
@@ -810,6 +811,7 @@ static void ntree_shader_weight_tree_invert(bNodeTree *ntree, bNode *output_node
switch (node->type) {
case SH_NODE_SHADERTORGB:
+ case SH_NODE_OUTPUT_LIGHT:
case SH_NODE_OUTPUT_WORLD:
case SH_NODE_OUTPUT_MATERIAL:
case SH_NODE_ADD_SHADER: {
@@ -1007,6 +1009,7 @@ static void ntree_shader_pruned_unused(bNodeTree *ntree, bNode *output_node)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->type == SH_NODE_OUTPUT_AOV) {
+ node->tmp_flag = 1;
nodeChainIterBackwards(ntree, node, ntree_branch_node_tag, nullptr, 0);
}
}
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
index 6495dcfffba..a0579372a15 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
@@ -42,8 +42,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.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_("IOR")).default_value(1.55f).min(0.0f).max(1000.0f);
b.add_input<decl::Float>(N_("Offset"))
.default_value(2.0f * ((float)M_PI) / 180.0f)
.min(-M_PI_2)
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 a487e07bd5a..5fc69987c67 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -53,7 +53,7 @@ static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), Po
static int node_shader_map_range_ui_class(const bNode *node)
{
const NodeMapRange &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
if (data_type == CD_PROP_FLOAT3) {
return NODE_CLASS_OP_VECTOR;
}
@@ -63,7 +63,7 @@ static int node_shader_map_range_ui_class(const bNode *node)
static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
{
const NodeMapRange &storage = node_storage(*node);
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const eCustomDataType data_type = static_cast<eCustomDataType>(storage.data_type);
const int type = (data_type == CD_PROP_FLOAT) ? SOCK_FLOAT : SOCK_VECTOR;
Array<bool> new_input_availability(BLI_listbase_count(&node->inputs));
@@ -108,7 +108,7 @@ static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
class SocketSearchOp {
public:
std::string socket_name;
- CustomDataType data_type;
+ eCustomDataType data_type;
int interpolation_type = NODE_MAP_RANGE_LINEAR;
void operator()(LinkSearchOpParams &params)
@@ -120,7 +120,7 @@ class SocketSearchOp {
}
};
-static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+static std::optional<eCustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
{
switch (socket.type) {
case SOCK_FLOAT:
@@ -137,7 +137,7 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock
static void node_map_range_gather_link_searches(GatherLinkSearchOpParams &params)
{
- const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ const std::optional<eCustomDataType> type = node_type_from_other_socket(params.other_socket());
if (!type) {
return;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.cc b/source/blender/nodes/shader/nodes/node_shader_output_light.cc
index 0eb8a60fdaa..3707806841e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_light.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_output_light.cc
@@ -10,6 +10,22 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Shader>(N_("Surface"));
}
+static int node_shader_gpu_output_light(GPUMaterial *mat,
+ bNode *UNUSED(node),
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *UNUSED(out))
+{
+ GPUNodeLink *outlink_surface;
+ /* Passthrough node in order to do the right socket conversions. */
+ if (in[0].link) {
+ /* Reuse material output. */
+ GPU_link(mat, "node_output_material_surface", in[0].link, &outlink_surface);
+ GPU_material_output_surface(mat, outlink_surface);
+ }
+ return true;
+}
+
} // namespace blender::nodes::node_shader_output_light_cc
/* node type definition */
@@ -21,6 +37,8 @@ void register_node_type_sh_output_light()
sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT);
ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_light);
+
ntype.no_muting = true;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
index 94a6febe92e..d4413036555 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
@@ -48,16 +48,36 @@ class MF_SeparateXYZ : public fn::MultiFunction {
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
const VArray<float3> &vectors = params.readonly_single_input<float3>(0, "XYZ");
- MutableSpan<float> xs = params.uninitialized_single_output<float>(1, "X");
- MutableSpan<float> ys = params.uninitialized_single_output<float>(2, "Y");
- MutableSpan<float> zs = params.uninitialized_single_output<float>(3, "Z");
-
- for (int64_t i : mask) {
- float3 xyz = vectors[i];
- xs[i] = xyz.x;
- ys[i] = xyz.y;
- zs[i] = xyz.z;
+ MutableSpan<float> xs = params.uninitialized_single_output_if_required<float>(1, "X");
+ MutableSpan<float> ys = params.uninitialized_single_output_if_required<float>(2, "Y");
+ MutableSpan<float> zs = params.uninitialized_single_output_if_required<float>(3, "Z");
+
+ std::array<MutableSpan<float>, 3> outputs = {xs, ys, zs};
+ Vector<int> used_outputs;
+ if (!xs.is_empty()) {
+ used_outputs.append(0);
}
+ if (!ys.is_empty()) {
+ used_outputs.append(1);
+ }
+ if (!zs.is_empty()) {
+ used_outputs.append(2);
+ }
+
+ devirtualize_varray(vectors, [&](auto vectors) {
+ mask.to_best_mask_type([&](auto mask) {
+ const int used_outputs_num = used_outputs.size();
+ const int *used_outputs_data = used_outputs.data();
+
+ for (const int64_t i : mask) {
+ const float3 &vector = vectors[i];
+ for (const int out_i : IndexRange(used_outputs_num)) {
+ const int coordinate = used_outputs_data[out_i];
+ outputs[coordinate][i] = vector[coordinate];
+ }
+ }
+ });
+ });
}
};
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
index 91d89952da7..53228f0a314 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
@@ -46,7 +46,7 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
NodeShaderUVMap *attr = static_cast<NodeShaderUVMap *>(node->storage);
/* NOTE: using CD_AUTO_FROM_NAME instead of CD_MTFACE as geometry nodes may overwrite data which
- * will also change the CustomDataType. This will also make EEVEE and Cycles consistent. See
+ * will also change the eCustomDataType. This will also make EEVEE and Cycles consistent. See
* T93179. */
GPUNodeLink *mtface = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->uv_map);
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
index cba944c671c..830f02d8df1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
@@ -43,7 +43,7 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
{
NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
/* NOTE: using CD_AUTO_FROM_NAME instead of CD_MCOL or CD_PROP_COLOR for named attributes
- * as geometry nodes may overwrite data which will also change the CustomDataType.
+ * as geometry nodes may overwrite data which will also change the eCustomDataType.
* This will also make EEVEE and Cycles
* consistent. See T93179. */
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 903e293a962..03dc61af9a2 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -324,7 +324,6 @@ int ntreeTexExecTree(bNodeTree *ntree,
MTex *mtex)
{
TexCallData data;
- float *nor = target->nor;
int retval = TEX_INT;
bNodeThreadStack *nts = NULL;
bNodeTreeExec *exec = ntree->execdata;
@@ -356,14 +355,7 @@ int ntreeTexExecTree(bNodeTree *ntree,
ntreeExecThreadNodes(exec, nts, &data, thread);
ntreeReleaseThreadStack(nts);
- if (target->nor) {
- retval |= TEX_NOR;
- }
retval |= TEX_RGB;
- /* confusing stuff; the texture output node sets this to NULL to indicate no normal socket was
- * set however, the texture code checks this for other reasons
- * (namely, a normal is required for material). */
- target->nor = nor;
return retval;
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index cf5e32cb486..b300ba9ef77 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -13,7 +13,6 @@
/* **************** COMPOSITE ******************** */
static bNodeSocketTemplate inputs[] = {
{SOCK_RGBA, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_DIRECTION},
{-1, ""},
};
@@ -32,12 +31,7 @@ static void exec(void *data,
TexParams params;
params_from_cdata(&params, cdata);
- if (in[1] && in[1]->hasinput && !in[0]->hasinput) {
- tex_input_rgba(target->trgba, in[1], &params, cdata->thread);
- }
- else {
- tex_input_rgba(target->trgba, in[0], &params, cdata->thread);
- }
+ tex_input_rgba(target->trgba, in[0], &params, cdata->thread);
}
else {
/* 0 means don't care, so just use first */
@@ -49,15 +43,6 @@ static void exec(void *data,
target->tin = (target->trgba[0] + target->trgba[1] + target->trgba[2]) / 3.0f;
target->talpha = true;
-
- if (target->nor) {
- if (in[1] && in[1]->hasinput) {
- tex_input_vec(target->nor, in[1], &params, cdata->thread);
- }
- else {
- target->nor = NULL;
- }
- }
}
}
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index fd7e6fdfc7f..d925c9f3554 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -14,10 +14,8 @@
* In this file: wrappers to use procedural textures as nodes
*/
-static bNodeSocketTemplate outputs_both[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 0.0f, 1.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, PROP_DIRECTION},
- {-1, ""}};
+static bNodeSocketTemplate outputs_both[] = {{SOCK_RGBA, N_("Color"), 1.0f, 0.0f, 0.0f, 1.0f},
+ {-1, ""}};
static bNodeSocketTemplate outputs_color_only[] = {{SOCK_RGBA, N_("Color")}, {-1, ""}};
/* Inputs common to all, #defined because nodes will need their own inputs too */
@@ -34,27 +32,15 @@ static void do_proc(float *result,
TexParams *p,
const float col1[4],
const float col2[4],
- char is_normal,
Tex *tex,
const short thread)
{
TexResult texres;
int textype;
- if (is_normal) {
- texres.nor = result;
- }
- else {
- texres.nor = NULL;
- }
-
textype = multitex_nodes(
tex, p->co, p->dxt, p->dyt, p->osatex, &texres, thread, 0, p->mtex, NULL);
- if (is_normal) {
- return;
- }
-
if (textype & TEX_RGB) {
copy_v4_v4(result, texres.trgba);
}
@@ -66,13 +52,8 @@ static void do_proc(float *result,
typedef void (*MapFn)(Tex *tex, bNodeStack **in, TexParams *p, const short thread);
-static void texfn(float *result,
- TexParams *p,
- bNode *node,
- bNodeStack **in,
- char is_normal,
- MapFn map_inputs,
- short thread)
+static void texfn(
+ float *result, TexParams *p, bNode *node, bNodeStack **in, MapFn map_inputs, short thread)
{
Tex tex = *((Tex *)(node->storage));
float col1[4], col2[4];
@@ -81,7 +62,7 @@ static void texfn(float *result,
map_inputs(&tex, in, p, thread);
- do_proc(result, p, col1, col2, is_normal, &tex, thread);
+ do_proc(result, p, col1, col2, &tex, thread);
}
static int count_outputs(bNode *node)
@@ -106,12 +87,7 @@ static int count_outputs(bNode *node)
static void name##_colorfn( \
float *result, TexParams *p, bNode *node, bNodeStack **in, short thread) \
{ \
- texfn(result, p, node, in, 0, &name##_map_inputs, thread); \
- } \
- static void name##_normalfn( \
- float *result, TexParams *p, bNode *node, bNodeStack **in, short thread) \
- { \
- texfn(result, p, node, in, 1, &name##_map_inputs, thread); \
+ texfn(result, p, node, in, &name##_map_inputs, thread); \
} \
static void name##_exec(void *data, \
int UNUSED(thread), \
@@ -124,9 +100,6 @@ static int count_outputs(bNode *node)
if (outs >= 1) { \
tex_output(node, execdata, in, out[0], &name##_colorfn, data); \
} \
- if (outs >= 2) { \
- tex_output(node, execdata, in, out[1], &name##_normalfn, data); \
- } \
}
/* --- VORONOI -- */
diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c
index 2d2b4e06665..79cd8bbb1df 100644
--- a/source/blender/nodes/texture/nodes/node_texture_texture.c
+++ b/source/blender/nodes/texture/nodes/node_texture_texture.c
@@ -45,13 +45,11 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
else if (nodetex) {
TexResult texres;
int textype;
- float nor[] = {0, 0, 0};
float col1[4], col2[4];
tex_input_rgba(col1, in[0], p, thread);
tex_input_rgba(col2, in[1], p, thread);
- texres.nor = nor;
textype = multitex_nodes(nodetex, co, dxt, dyt, p->osatex, &texres, thread, 0, p->mtex, NULL);
if (textype & TEX_RGB) {
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 0ab26fde34f..8075e4ecd22 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -70,6 +70,11 @@ void BPY_modules_load_user(struct bContext *C);
void BPY_app_handlers_reset(bool do_all);
/**
+ * Run on exit to free any cached data.
+ */
+void BPY_driver_exit(void);
+
+/**
* Update function, it gets rid of python-drivers global dictionary: `bpy.app.driver_namespace`,
* forcing #BPY_driver_exec to recreate it. Use this when loading a new `.blend` file
* so any variables setup by the previous blend file are cleared.
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 92ed0c51b1f..f5c1f060e80 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -1082,18 +1082,34 @@ static PyObject *Buffer_repr(Buffer *self)
/** \name OpenGL API Wrapping
* \{ */
-#define BGL_Wrap(funcname, ret, arg_list) \
- static PyObject *Method_##funcname(PyObject *UNUSED(self), PyObject *args) \
- { \
- arg_def arg_list; \
- ret_def_##ret; \
- if (!PyArg_ParseTuple(args, arg_str arg_list, arg_ref arg_list)) { \
+#ifdef WITH_OPENGL
+# define BGL_Wrap(funcname, ret, arg_list) \
+ static PyObject *Method_##funcname(PyObject *UNUSED(self), PyObject *args) \
+ { \
+ arg_def arg_list; \
+ ret_def_##ret; \
+ if (!PyArg_ParseTuple(args, arg_str arg_list, arg_ref arg_list)) { \
+ return NULL; \
+ } \
+ GPU_bgl_start(); \
+ ret_set_##ret gl##funcname(arg_var arg_list); \
+ ret_ret_##ret; \
+ }
+#else
+
+static void bgl_no_opengl_error(void)
+{
+ PyErr_SetString(PyExc_RuntimeError, "Built without OpenGL support");
+}
+
+# define BGL_Wrap(funcname, ret, arg_list) \
+ static PyObject *Method_##funcname(PyObject *UNUSED(self), PyObject *args) \
+ { \
+ (void)args; \
+ bgl_no_opengl_error(); \
return NULL; \
- } \
- GPU_bgl_start(); \
- ret_set_##ret gl##funcname(arg_var arg_list); \
- ret_ret_##ret; \
- }
+ }
+#endif
/* GL_VERSION_1_0 */
BGL_Wrap(BlendFunc, void, (GLenum, GLenum));
@@ -1421,12 +1437,22 @@ static void py_module_dict_add_method(PyObject *submodule,
#ifdef __GNUC__
# pragma GCC diagnostic ignored "-Waddress"
#endif
-#define PY_MOD_ADD_METHOD(func) \
- { \
- static PyMethodDef method_def = {"gl" #func, Method_##func, METH_VARARGS}; \
- py_module_dict_add_method(submodule, dict, &method_def, (gl##func != NULL)); \
- } \
- ((void)0)
+
+#ifdef WITH_OPENGL
+# define PY_MOD_ADD_METHOD(func) \
+ { \
+ static PyMethodDef method_def = {"gl" #func, Method_##func, METH_VARARGS}; \
+ py_module_dict_add_method(submodule, dict, &method_def, (gl##func != NULL)); \
+ } \
+ ((void)0)
+#else
+# define PY_MOD_ADD_METHOD(func) \
+ { \
+ static PyMethodDef method_def = {"gl" #func, Method_##func, METH_VARARGS}; \
+ py_module_dict_add_method(submodule, dict, &method_def, false); \
+ } \
+ ((void)0)
+#endif
static void init_bgl_version_1_0_methods(PyObject *submodule, PyObject *dict)
{
@@ -2620,9 +2646,13 @@ static PyObject *Method_ShaderSource(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
+#ifdef WITH_OPENGL
glShaderSource(shader, 1, (const char **)&source, NULL);
-
Py_RETURN_NONE;
+#else
+ bgl_no_opengl_error();
+ return NULL;
+#endif
}
/** \} */
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index d2e3c44c1b6..8230801e184 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -641,6 +641,7 @@ void PyC_StackSpit(void)
void PyC_FileAndNum(const char **r_filename, int *r_lineno)
{
PyFrameObject *frame;
+ PyCodeObject *code;
if (r_filename) {
*r_filename = NULL;
@@ -649,13 +650,16 @@ void PyC_FileAndNum(const char **r_filename, int *r_lineno)
*r_lineno = -1;
}
- if (!(frame = PyThreadState_GET()->frame)) {
+ if (!(frame = PyEval_GetFrame())) {
+ return;
+ }
+ if (!(code = PyFrame_GetCode(frame))) {
return;
}
/* when executing a script */
if (r_filename) {
- *r_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
+ *r_filename = PyUnicode_AsUTF8(code->co_filename);
}
/* when executing a module */
diff --git a/source/blender/python/gpu/gpu_py_api.c b/source/blender/python/gpu/gpu_py_api.c
index d45fdc21130..a2075566f31 100644
--- a/source/blender/python/gpu/gpu_py_api.c
+++ b/source/blender/python/gpu/gpu_py_api.c
@@ -14,8 +14,6 @@
#include "BLI_utildefines.h"
-#include "../generic/python_utildefines.h"
-
#include "gpu_py_capabilities.h"
#include "gpu_py_matrix.h"
#include "gpu_py_platform.h"
@@ -23,7 +21,7 @@
#include "gpu_py_state.h"
#include "gpu_py_types.h"
-#include "gpu_py_api.h" /* own include */
+#include "gpu_py_api.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name GPU Module
diff --git a/source/blender/python/gpu/gpu_py_batch.c b/source/blender/python/gpu/gpu_py_batch.c
index 02bcf80aa5d..533e5154d83 100644
--- a/source/blender/python/gpu/gpu_py_batch.c
+++ b/source/blender/python/gpu/gpu_py_batch.c
@@ -13,14 +13,10 @@
#include <Python.h>
-#include "MEM_guardedalloc.h"
-
#include "BLI_utildefines.h"
#include "GPU_batch.h"
-#include "../mathutils/mathutils.h"
-
#include "../generic/py_capi_utils.h"
#include "gpu_py.h"
diff --git a/source/blender/python/gpu/gpu_py_element.c b/source/blender/python/gpu/gpu_py_element.c
index 616e7da6e9f..d52a97c0c84 100644
--- a/source/blender/python/gpu/gpu_py_element.c
+++ b/source/blender/python/gpu/gpu_py_element.c
@@ -16,7 +16,6 @@
#include "MEM_guardedalloc.h"
#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
#include "gpu_py.h"
#include "gpu_py_element.h" /* own include */
diff --git a/source/blender/python/gpu/gpu_py_framebuffer.c b/source/blender/python/gpu/gpu_py_framebuffer.c
index 2a7857b3059..33d9ff0b041 100644
--- a/source/blender/python/gpu/gpu_py_framebuffer.c
+++ b/source/blender/python/gpu/gpu_py_framebuffer.c
@@ -21,11 +21,9 @@
#include "../mathutils/mathutils.h"
#include "gpu_py.h"
-#include "gpu_py_texture.h"
-
-#include "gpu_py.h"
#include "gpu_py_buffer.h"
#include "gpu_py_framebuffer.h" /* own include */
+#include "gpu_py_texture.h"
/* -------------------------------------------------------------------- */
/** \name GPUFrameBuffer Common Utilities
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index b50f536da8a..621c6647cb9 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -13,8 +13,6 @@
#include <Python.h>
-#include "MEM_guardedalloc.h"
-
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -31,7 +29,6 @@
#include "GPU_texture.h"
#include "GPU_viewport.h"
-#include "ED_view3d.h"
#include "ED_view3d_offscreen.h"
#include "../mathutils/mathutils.h"
diff --git a/source/blender/python/gpu/gpu_py_platform.c b/source/blender/python/gpu/gpu_py_platform.c
index 6c5a5bdaaf8..656024ae22c 100644
--- a/source/blender/python/gpu/gpu_py_platform.c
+++ b/source/blender/python/gpu/gpu_py_platform.c
@@ -13,7 +13,7 @@
#include "GPU_platform.h"
-#include "gpu_py_platform.h" /* own include */
+#include "gpu_py_platform.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name Functions
diff --git a/source/blender/python/gpu/gpu_py_select.c b/source/blender/python/gpu/gpu_py_select.c
index 8e5c172f90c..8869ea38e32 100644
--- a/source/blender/python/gpu/gpu_py_select.c
+++ b/source/blender/python/gpu/gpu_py_select.c
@@ -20,7 +20,7 @@
#include "GPU_select.h"
-#include "gpu_py_select.h" /* own include */
+#include "gpu_py_select.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name Methods
diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c
index d7369731a98..101b9f8e4c6 100644
--- a/source/blender/python/gpu/gpu_py_shader.c
+++ b/source/blender/python/gpu/gpu_py_shader.c
@@ -16,7 +16,6 @@
#include "GPU_uniform_buffer.h"
#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
#include "../mathutils/mathutils.h"
#include "gpu_py.h"
diff --git a/source/blender/python/gpu/gpu_py_shader_create_info.cc b/source/blender/python/gpu/gpu_py_shader_create_info.cc
index 3b043c605fa..e00d01174f4 100644
--- a/source/blender/python/gpu/gpu_py_shader_create_info.cc
+++ b/source/blender/python/gpu/gpu_py_shader_create_info.cc
@@ -15,7 +15,6 @@
#include "intern/gpu_shader_create_info.hh"
#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
#include "gpu_py_shader.h" /* own include */
diff --git a/source/blender/python/gpu/gpu_py_types.c b/source/blender/python/gpu/gpu_py_types.c
index 65201df4a9e..eccbebbd8dd 100644
--- a/source/blender/python/gpu/gpu_py_types.c
+++ b/source/blender/python/gpu/gpu_py_types.c
@@ -10,7 +10,6 @@
#include <Python.h>
#include "../generic/py_capi_utils.h"
-#include "../generic/python_utildefines.h"
#include "gpu_py_types.h" /* own include */
diff --git a/source/blender/python/gpu/gpu_py_uniformbuffer.c b/source/blender/python/gpu/gpu_py_uniformbuffer.c
index f8f88d61cf6..dcf9ab76470 100644
--- a/source/blender/python/gpu/gpu_py_uniformbuffer.c
+++ b/source/blender/python/gpu/gpu_py_uniformbuffer.c
@@ -14,13 +14,11 @@
#include "BLI_string.h"
#include "GPU_context.h"
-#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
#include "../generic/py_capi_utils.h"
#include "gpu_py.h"
-#include "gpu_py_buffer.h"
#include "gpu_py_uniformbuffer.h" /* own include */
diff --git a/source/blender/python/gpu/gpu_py_vertex_buffer.c b/source/blender/python/gpu/gpu_py_vertex_buffer.c
index a295bedeae2..ac050128a1d 100644
--- a/source/blender/python/gpu/gpu_py_vertex_buffer.c
+++ b/source/blender/python/gpu/gpu_py_vertex_buffer.c
@@ -323,14 +323,14 @@ static void pygpu_vertbuf__tp_dealloc(BPyGPUVertBuf *self)
}
PyDoc_STRVAR(pygpu_vertbuf__tp_doc,
- ".. class:: GPUVertBuf(len, format)\n"
+ ".. class:: GPUVertBuf(format, len)\n"
"\n"
" Contains a VBO.\n"
"\n"
- " :param len: Amount of vertices that will fit into this buffer.\n"
- " :type type: `int`\n"
" :param format: Vertex format.\n"
- " :type buf: :class:`gpu.types.GPUVertFormat`\n");
+ " :type buf: :class:`gpu.types.GPUVertFormat`\n"
+ " :param len: Amount of vertices that will fit into this buffer.\n"
+ " :type type: `int`\n");
PyTypeObject BPyGPUVertBuf_Type = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUVertBuf",
.tp_basicsize = sizeof(BPyGPUVertBuf),
diff --git a/source/blender/python/gpu/gpu_py_vertex_format.c b/source/blender/python/gpu/gpu_py_vertex_format.c
index 3e6695419c0..40a0e5d1e9f 100644
--- a/source/blender/python/gpu/gpu_py_vertex_format.c
+++ b/source/blender/python/gpu/gpu_py_vertex_format.c
@@ -9,10 +9,6 @@
#include <Python.h>
-#include "BLI_math.h"
-
-#include "MEM_guardedalloc.h"
-
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 959fbc7ee98..71138134370 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -232,7 +232,7 @@ if(WITH_IMAGE_TIFF)
endif()
if(WITH_WEBP)
- add_definitions(-DWITH_WEBP)
+ add_definitions(-DWITH_WEBP)
endif()
if(WITH_INPUT_NDOF)
@@ -310,6 +310,18 @@ if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
+if(WITH_IO_WAVEFRONT_OBJ)
+ add_definitions(-DWITH_IO_WAVEFRONT_OBJ)
+endif()
+
+if(WITH_IO_STL)
+ add_definitions(-DWITH_IO_STL)
+endif()
+
+if(WITH_IO_GPENCIL)
+ add_definitions(-DWITH_IO_GPENCIL)
+endif()
+
if(WITH_ALEMBIC)
add_definitions(-DWITH_ALEMBIC)
endif()
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 9d8602d51bd..7fe0b9455e6 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -23,6 +23,7 @@
#include "BKE_global.h" /* XXX, G_MAIN only */
#include "RNA_access.h"
+#include "RNA_enum_types.h"
#include "RNA_prototypes.h"
#include "RNA_types.h"
@@ -31,6 +32,7 @@
#include "bpy.h"
#include "bpy_app.h"
#include "bpy_capi_utils.h"
+#include "bpy_driver.h"
#include "bpy_library.h"
#include "bpy_operator.h"
#include "bpy_props.h"
@@ -325,6 +327,49 @@ static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObj
return PyC_UnicodeFromByte(path ? path : "");
}
+/* This is only exposed for tests, see: `tests/python/bl_pyapi_bpy_driver_secure_eval.py`. */
+PyDoc_STRVAR(bpy_driver_secure_code_test_doc,
+ ".. function:: _driver_secure_code_test(code)\n"
+ "\n"
+ " Test if the script should be considered trusted.\n"
+ "\n"
+ " :arg code: The code to test.\n"
+ " :type code: code\n"
+ " :arg namespace: The namespace of values which are allowed.\n"
+ " :type namespace: dict\n"
+ " :arg verbose: Print the reason for considering insecure to the ``stderr``.\n"
+ " :type verbose: bool\n"
+ " :return: True when the script is considered trusted.\n"
+ " :rtype: bool\n");
+static PyObject *bpy_driver_secure_code_test(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ PyObject *py_code;
+ PyObject *py_namespace = NULL;
+ const bool verbose = false;
+ static const char *_keywords[] = {"code", "namespace", "verbose", NULL};
+ static _PyArg_Parser _parser = {
+ "O!" /* `expression` */
+ "|$" /* Optional keyword only arguments. */
+ "O!" /* `namespace` */
+ "O&" /* `verbose` */
+ ":driver_secure_code_test",
+ _keywords,
+ 0,
+ };
+ if (!_PyArg_ParseTupleAndKeywordsFast(args,
+ kw,
+ &_parser,
+ &PyCode_Type,
+ &py_code,
+ &PyDict_Type,
+ &py_namespace,
+ PyC_ParseBool,
+ &verbose)) {
+ return NULL;
+ }
+ return PyBool_FromLong(BPY_driver_secure_bytecode_test(py_code, py_namespace, verbose));
+}
+
PyDoc_STRVAR(bpy_escape_identifier_doc,
".. function:: escape_identifier(string)\n"
"\n"
@@ -456,59 +501,72 @@ static PyObject *bpy_context_members(PyObject *UNUSED(self))
return result;
}
-static PyMethodDef meth_bpy_script_paths = {
- "script_paths",
- (PyCFunction)bpy_script_paths,
- METH_NOARGS,
- bpy_script_paths_doc,
-};
-static PyMethodDef meth_bpy_blend_paths = {
- "blend_paths",
- (PyCFunction)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,
- METH_VARARGS | METH_KEYWORDS,
- NULL,
-};
-static PyMethodDef meth_bpy_system_resource = {
- "system_resource",
- (PyCFunction)bpy_system_resource,
- METH_VARARGS | METH_KEYWORDS,
- bpy_system_resource_doc,
-};
-static PyMethodDef meth_bpy_resource_path = {
- "resource_path",
- (PyCFunction)bpy_resource_path,
- METH_VARARGS | METH_KEYWORDS,
- bpy_resource_path_doc,
-};
-static PyMethodDef meth_bpy_escape_identifier = {
- "escape_identifier",
- (PyCFunction)bpy_escape_identifier,
- METH_O,
- bpy_escape_identifier_doc,
-};
-static PyMethodDef meth_bpy_unescape_identifier = {
- "unescape_identifier",
- (PyCFunction)bpy_unescape_identifier,
- METH_O,
- bpy_unescape_identifier_doc,
-};
-static PyMethodDef meth_bpy_context_members = {
- "context_members",
- (PyCFunction)bpy_context_members,
- METH_NOARGS,
- bpy_context_members_doc,
+/**
+ * \note only exposed for generating documentation, see: `doc/python_api/sphinx_doc_gen.py`.
+ */
+PyDoc_STRVAR(bpy_rna_enum_items_static_doc,
+ ".. function:: rna_enum_items_static()\n"
+ "\n"
+ " :return: A dict where the key the name of the enum, the value is a tuple of "
+ ":class:`bpy.types.EnumPropertyItem`.\n"
+ " :rtype: dict of \n");
+static PyObject *bpy_rna_enum_items_static(PyObject *UNUSED(self))
+{
+#define DEF_ENUM(id) {STRINGIFY(id), id},
+ struct {
+ const char *id;
+ const EnumPropertyItem *items;
+ } enum_info[] = {
+#include "RNA_enum_items.h"
+ };
+ PyObject *result = _PyDict_NewPresized(ARRAY_SIZE(enum_info));
+ for (int i = 0; i < ARRAY_SIZE(enum_info); i++) {
+ /* Include all items (including headings & separators), can be shown in documentation. */
+ const EnumPropertyItem *items = enum_info[i].items;
+ const int items_count = RNA_enum_items_count(items);
+ PyObject *value = PyTuple_New(items_count);
+ for (int item_index = 0; item_index < items_count; item_index++) {
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_EnumPropertyItem, (void *)&items[item_index], &ptr);
+ PyTuple_SET_ITEM(value, item_index, pyrna_struct_CreatePyObject(&ptr));
+ }
+ PyDict_SetItemString(result, enum_info[i].id, value);
+ Py_DECREF(value);
+ }
+ return result;
+}
+
+static PyMethodDef bpy_methods[] = {
+ {"script_paths", (PyCFunction)bpy_script_paths, METH_NOARGS, bpy_script_paths_doc},
+ {"blend_paths",
+ (PyCFunction)bpy_blend_paths,
+ METH_VARARGS | METH_KEYWORDS,
+ bpy_blend_paths_doc},
+ {"flip_name", (PyCFunction)bpy_flip_name, METH_VARARGS | METH_KEYWORDS, bpy_flip_name_doc},
+ {"user_resource", (PyCFunction)bpy_user_resource, METH_VARARGS | METH_KEYWORDS, NULL},
+ {"system_resource",
+ (PyCFunction)bpy_system_resource,
+ METH_VARARGS | METH_KEYWORDS,
+ bpy_system_resource_doc},
+ {"resource_path",
+ (PyCFunction)bpy_resource_path,
+ METH_VARARGS | METH_KEYWORDS,
+ bpy_resource_path_doc},
+ {"_driver_secure_code_test",
+ (PyCFunction)bpy_driver_secure_code_test,
+ METH_VARARGS | METH_KEYWORDS,
+ bpy_driver_secure_code_test_doc},
+ {"escape_identifier", (PyCFunction)bpy_escape_identifier, METH_O, bpy_escape_identifier_doc},
+ {"unescape_identifier",
+ (PyCFunction)bpy_unescape_identifier,
+ METH_O,
+ bpy_unescape_identifier_doc},
+ {"context_members", (PyCFunction)bpy_context_members, METH_NOARGS, bpy_context_members_doc},
+ {"rna_enum_items_static",
+ (PyCFunction)bpy_rna_enum_items_static,
+ METH_NOARGS,
+ bpy_rna_enum_items_static_doc},
+ {NULL, NULL, 0, NULL},
};
static PyObject *bpy_import_test(const char *modname)
@@ -590,32 +648,12 @@ void BPy_init_modules(struct bContext *C)
/* Register methods and property get/set for RNA types. */
BPY_rna_types_extend_capi();
- /* utility func's that have nowhere else to go */
- PyModule_AddObject(mod,
- meth_bpy_script_paths.ml_name,
- (PyObject *)PyCFunction_New(&meth_bpy_script_paths, NULL));
- PyModule_AddObject(
- mod, meth_bpy_blend_paths.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_blend_paths, NULL));
- PyModule_AddObject(mod,
- meth_bpy_user_resource.ml_name,
- (PyObject *)PyCFunction_New(&meth_bpy_user_resource, NULL));
- PyModule_AddObject(mod,
- meth_bpy_system_resource.ml_name,
- (PyObject *)PyCFunction_New(&meth_bpy_system_resource, NULL));
- PyModule_AddObject(mod,
- meth_bpy_resource_path.ml_name,
- (PyObject *)PyCFunction_New(&meth_bpy_resource_path, NULL));
- PyModule_AddObject(mod,
- meth_bpy_escape_identifier.ml_name,
- (PyObject *)PyCFunction_New(&meth_bpy_escape_identifier, NULL));
- 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));
- PyModule_AddObject(mod,
- meth_bpy_context_members.ml_name,
- (PyObject *)PyCFunction_New(&meth_bpy_context_members, NULL));
+ for (int i = 0; bpy_methods[i].ml_name; i++) {
+ PyMethodDef *m = &bpy_methods[i];
+ /* Currently there is no need to support these. */
+ BLI_assert((m->ml_flags & (METH_CLASS | METH_STATIC)) == 0);
+ PyModule_AddObject(mod, m->ml_name, (PyObject *)PyCFunction_New(m, NULL));
+ }
/* register funcs (bpy_rna.c) */
PyModule_AddObject(mod,
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 621cc79a8db..939473ceaa0 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -36,15 +36,19 @@
#include "BKE_appdir.h"
#include "BKE_blender_version.h"
#include "BKE_global.h"
+#include "BKE_main.h"
#include "DNA_ID.h"
#include "UI_interface_icons.h"
+#include "RNA_enum_types.h" /* For `rna_enum_wm_job_type_items`. */
+
/* for notifiers */
#include "WM_api.h"
#include "WM_types.h"
+#include "../generic/py_capi_rna.h"
#include "../generic/py_capi_utils.h"
#include "../generic/python_utildefines.h"
@@ -450,6 +454,44 @@ static PyGetSetDef bpy_app_getsets[] = {
{NULL, NULL, NULL, NULL, NULL},
};
+PyDoc_STRVAR(bpy_app_is_job_running_doc,
+ ".. staticmethod:: is_job_running(job_type)\n"
+ "\n"
+ " Check whether a job of the given type is running.\n"
+ "\n"
+ " :arg job_type: job type in :ref:`rna_enum_wm_job_type_items`.\n"
+ " :type job_type: str\n"
+ " :return: Whether a job of the given type is currently running.\n"
+ " :rtype: bool.\n");
+static PyObject *bpy_app_is_job_running(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
+{
+ struct BPy_EnumProperty_Parse job_type_enum = {
+ .items = rna_enum_wm_job_type_items,
+ .value = 0,
+ };
+ static const char *_keywords[] = {"job_type", NULL};
+ static _PyArg_Parser _parser = {
+ "O&" /* `job_type` */
+ ":is_job_running",
+ _keywords,
+ 0,
+ };
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser, pyrna_enum_value_parse_string, &job_type_enum)) {
+ return NULL;
+ }
+ wmWindowManager *wm = G_MAIN->wm.first;
+ return PyBool_FromLong(WM_jobs_has_running_type(wm, job_type_enum.value));
+}
+
+static struct PyMethodDef bpy_app_methods[] = {
+ {"is_job_running",
+ (PyCFunction)bpy_app_is_job_running,
+ METH_VARARGS | METH_KEYWORDS | METH_STATIC,
+ bpy_app_is_job_running_doc},
+ {NULL, NULL, 0, NULL},
+};
+
static void py_struct_seq_getset_init(void)
{
/* tricky dynamic members, not to py-spec! */
@@ -459,6 +501,17 @@ static void py_struct_seq_getset_init(void)
Py_DECREF(item);
}
}
+
+static void py_struct_seq_method_init(void)
+{
+ for (PyMethodDef *method = bpy_app_methods; method->ml_name; method++) {
+ BLI_assert_msg(method->ml_flags & METH_STATIC, "Only static methods make sense for 'bpy.app'");
+ PyObject *item = PyCFunction_New(method, NULL);
+ PyDict_SetItemString(BlenderAppType.tp_dict, method->ml_name, item);
+ Py_DECREF(item);
+ }
+}
+
/* end dynamic bpy.app */
PyObject *BPY_app_struct(void)
@@ -477,6 +530,7 @@ PyObject *BPY_app_struct(void)
/* kindof a hack ontop of PyStructSequence */
py_struct_seq_getset_init();
+ py_struct_seq_method_init();
return ret;
}
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index beb78753406..fe5111c37f2 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -43,6 +43,9 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{"mod_oceansim", NULL},
{"mod_remesh", NULL},
{"collada", NULL},
+ {"io_wavefront_obj", NULL},
+ {"io_stl", NULL},
+ {"io_gpencil", NULL},
{"opencolorio", NULL},
{"openmp", NULL},
{"openvdb", NULL},
@@ -251,6 +254,24 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_IO_WAVEFRONT_OBJ
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_IO_STL
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
+#ifdef WITH_IO_GPENCIL
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_OCIO
SetObjIncref(Py_True);
#else
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index bf427d9639a..8c5fb22eab1 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -66,6 +66,12 @@ static PyStructSequence_Field app_cb_info_fields[] = {
{"xr_session_start_pre", "on starting an xr session (before)"},
{"annotation_pre", "on drawing an annotation (before)"},
{"annotation_post", "on drawing an annotation (after)"},
+ {"object_bake_pre", "before starting a bake job"},
+ {"object_bake_complete", "on completing a bake job; will be called in the main thread"},
+ {"object_bake_cancel", "on canceling a bake job; will be called in the main thread"},
+ {"composite_pre", "on a compositing background job (before)"},
+ {"composite_post", "on a compositing background job (after)"},
+ {"composite_cancel", "on a compositing background job (cancel)"},
/* sets the permanent tag */
#define APP_CB_OTHER_FIELDS 1
@@ -139,41 +145,41 @@ static PyTypeObject BPyPersistent_Type = {
0, /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- bpy_app_handlers_persistent_new, /* tp_new */
- 0, /* tp_free */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ bpy_app_handlers_persistent_new, /* tp_new */
+ 0, /* tp_free */
};
static PyObject *py_cb_array[BKE_CB_EVT_TOT] = {NULL};
diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c
index a9cc0019783..04aa203d198 100644
--- a/source/blender/python/intern/bpy_driver.c
+++ b/source/blender/python/intern/bpy_driver.c
@@ -19,6 +19,7 @@
#include "BKE_animsys.h"
#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
+#include "BKE_idtype.h"
#include "RNA_access.h"
#include "RNA_prototypes.h"
@@ -233,15 +234,8 @@ static void bpy_pydriver_namespace_update_depsgraph(struct Depsgraph *depsgraph)
}
}
-void BPY_driver_reset(void)
+void BPY_driver_exit(void)
{
- PyGILState_STATE gilstate;
- const bool use_gil = true; /* !PyC_IsInterpreterActive(); */
-
- if (use_gil) {
- gilstate = PyGILState_Ensure();
- }
-
if (bpy_pydriver_Dict) { /* Free the global dict used by python-drivers. */
PyDict_Clear(bpy_pydriver_Dict);
Py_DECREF(bpy_pydriver_Dict);
@@ -261,19 +255,46 @@ void BPY_driver_reset(void)
/* Freed when clearing driver dictionary. */
g_pydriver_state_prev.self = NULL;
g_pydriver_state_prev.depsgraph = NULL;
+}
+
+void BPY_driver_reset(void)
+{
+ PyGILState_STATE gilstate;
+ const bool use_gil = true; /* !PyC_IsInterpreterActive(); */
+
+ if (use_gil) {
+ gilstate = PyGILState_Ensure();
+ }
+
+ /* Currently exit/reset are practically the same besides the GIL check. */
+ BPY_driver_exit();
if (use_gil) {
PyGILState_Release(gilstate);
}
}
-/** Error return function for #BPY_eval_pydriver. */
-static void pydriver_error(ChannelDriver *driver)
+/**
+ * Error return function for #BPY_driver_exec.
+ *
+ * \param anim_rna: Used to show the target when printing the error to give additional context.
+ */
+static void pydriver_error(ChannelDriver *driver, const struct PathResolvedRNA *anim_rna)
{
driver->flag |= DRIVER_FLAG_INVALID; /* Python expression failed. */
+
+ const char *null_str = "<null>";
+ const ID *id = anim_rna->ptr.owner_id;
fprintf(stderr,
- "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n",
- driver->expression);
+ "\n"
+ "Error in PyDriver: expression failed: %s\n"
+ "For target: (type=%s, name=\"%s\", property=%s, property_index=%d)\n"
+ "\n",
+ driver->expression,
+ id ? BKE_idtype_idcode_to_name(GS(id->name)) : null_str,
+ id ? id->name + 2 : null_str,
+ anim_rna->prop ? RNA_property_identifier(anim_rna->prop) : null_str,
+ anim_rna->prop_index);
// BPy_errors_to_report(NULL); /* TODO: reports. */
PyErr_Print();
@@ -282,14 +303,75 @@ static void pydriver_error(ChannelDriver *driver)
#ifdef USE_BYTECODE_WHITELIST
-# define OK_OP(op) [op] = 1
+# define OK_OP(op) [op] = true
+
+static const bool secure_opcodes[255] = {
+# if PY_VERSION_HEX >= 0x030b0000 /* Python 3.11 & newer. */
+
+ OK_OP(CACHE),
+ OK_OP(POP_TOP),
+ OK_OP(PUSH_NULL),
+ OK_OP(NOP),
+ OK_OP(UNARY_POSITIVE),
+ OK_OP(UNARY_NEGATIVE),
+ OK_OP(UNARY_NOT),
+ OK_OP(UNARY_INVERT),
+ OK_OP(BINARY_SUBSCR),
+ OK_OP(GET_LEN),
+ OK_OP(LIST_TO_TUPLE),
+ OK_OP(RETURN_VALUE),
+ OK_OP(SWAP),
+ OK_OP(BUILD_TUPLE),
+ OK_OP(BUILD_LIST),
+ OK_OP(BUILD_SET),
+ OK_OP(BUILD_MAP),
+ OK_OP(COMPARE_OP),
+ OK_OP(JUMP_FORWARD),
+ OK_OP(JUMP_IF_FALSE_OR_POP),
+ OK_OP(JUMP_IF_TRUE_OR_POP),
+ OK_OP(POP_JUMP_FORWARD_IF_FALSE),
+ OK_OP(POP_JUMP_FORWARD_IF_TRUE),
+ OK_OP(LOAD_GLOBAL),
+ OK_OP(IS_OP),
+ OK_OP(CONTAINS_OP),
+ OK_OP(BINARY_OP),
+ OK_OP(LOAD_FAST),
+ OK_OP(STORE_FAST),
+ OK_OP(DELETE_FAST),
+ OK_OP(POP_JUMP_FORWARD_IF_NOT_NONE),
+ OK_OP(POP_JUMP_FORWARD_IF_NONE),
+ OK_OP(BUILD_SLICE),
+ OK_OP(LOAD_DEREF),
+ OK_OP(STORE_DEREF),
+ OK_OP(RESUME),
+ OK_OP(LIST_EXTEND),
+ OK_OP(SET_UPDATE),
+/* NOTE(@campbellbarton): Don't enable dict manipulation, unless we can prove there is not way it
+ * can be used to manipulate the name-space (potentially allowing malicious code). */
+# if 0
+ OK_OP(DICT_MERGE),
+ OK_OP(DICT_UPDATE),
+# endif
+ OK_OP(POP_JUMP_BACKWARD_IF_NOT_NONE),
+ OK_OP(POP_JUMP_BACKWARD_IF_NONE),
+ OK_OP(POP_JUMP_BACKWARD_IF_FALSE),
+ OK_OP(POP_JUMP_BACKWARD_IF_TRUE),
+
+ /* Special cases. */
+ OK_OP(LOAD_CONST), /* Ok because constants are accepted. */
+ OK_OP(LOAD_NAME), /* Ok, because `PyCodeObject.names` is checked. */
+ OK_OP(CALL), /* Ok, because we check its "name" before calling. */
+ OK_OP(KW_NAMES), /* Ok, because it's used for calling functions with keyword arguments. */
+ OK_OP(PRECALL), /* Ok, because it's used for calling. */
+
+# else /* Python 3.10 and older. */
-static const char secure_opcodes[255] = {
OK_OP(POP_TOP),
OK_OP(ROT_TWO),
OK_OP(ROT_THREE),
OK_OP(DUP_TOP),
OK_OP(DUP_TOP_TWO),
+ OK_OP(ROT_FOUR),
OK_OP(NOP),
OK_OP(UNARY_POSITIVE),
OK_OP(UNARY_NEGATIVE),
@@ -307,6 +389,7 @@ static const char secure_opcodes[255] = {
OK_OP(BINARY_TRUE_DIVIDE),
OK_OP(INPLACE_FLOOR_DIVIDE),
OK_OP(INPLACE_TRUE_DIVIDE),
+ OK_OP(GET_LEN),
OK_OP(INPLACE_ADD),
OK_OP(INPLACE_SUBTRACT),
OK_OP(INPLACE_MULTIPLY),
@@ -322,7 +405,9 @@ static const char secure_opcodes[255] = {
OK_OP(INPLACE_AND),
OK_OP(INPLACE_XOR),
OK_OP(INPLACE_OR),
+ OK_OP(LIST_TO_TUPLE),
OK_OP(RETURN_VALUE),
+ OK_OP(ROT_N),
OK_OP(BUILD_TUPLE),
OK_OP(BUILD_LIST),
OK_OP(BUILD_SET),
@@ -335,11 +420,22 @@ static const char secure_opcodes[255] = {
OK_OP(POP_JUMP_IF_FALSE),
OK_OP(POP_JUMP_IF_TRUE),
OK_OP(LOAD_GLOBAL),
+ OK_OP(IS_OP),
+ OK_OP(CONTAINS_OP),
OK_OP(LOAD_FAST),
OK_OP(STORE_FAST),
OK_OP(DELETE_FAST),
+ OK_OP(BUILD_SLICE),
OK_OP(LOAD_DEREF),
OK_OP(STORE_DEREF),
+ OK_OP(LIST_EXTEND),
+ OK_OP(SET_UPDATE),
+/* NOTE(@campbellbarton): Don't enable dict manipulation, unless we can prove there is not way it
+ * can be used to manipulate the name-space (potentially allowing malicious code). */
+# if 0
+ OK_OP(DICT_MERGE),
+ OK_OP(DICT_UPDATE),
+# endif
/* Special cases. */
OK_OP(LOAD_CONST), /* Ok because constants are accepted. */
@@ -347,11 +443,16 @@ static const char secure_opcodes[255] = {
OK_OP(CALL_FUNCTION), /* Ok, because we check its "name" before calling. */
OK_OP(CALL_FUNCTION_KW),
OK_OP(CALL_FUNCTION_EX),
+
+# endif /* Python 3.10 and older. */
};
# undef OK_OP
-static bool bpy_driver_secure_bytecode_validate(PyObject *expr_code, PyObject *dict_arr[])
+bool BPY_driver_secure_bytecode_test_ex(PyObject *expr_code,
+ PyObject *namespace_array[],
+ const bool verbose,
+ const char *error_prefix)
{
PyCodeObject *py_code = (PyCodeObject *)expr_code;
@@ -359,20 +460,23 @@ static bool bpy_driver_secure_bytecode_validate(PyObject *expr_code, PyObject *d
{
for (int i = 0; i < PyTuple_GET_SIZE(py_code->co_names); i++) {
PyObject *name = PyTuple_GET_ITEM(py_code->co_names, i);
-
+ const char *name_str = PyUnicode_AsUTF8(name);
bool contains_name = false;
- for (int j = 0; dict_arr[j]; j++) {
- if (PyDict_Contains(dict_arr[j], name)) {
+ for (int j = 0; namespace_array[j]; j++) {
+ if (PyDict_Contains(namespace_array[j], name)) {
contains_name = true;
break;
}
}
- if (contains_name == false) {
- fprintf(stderr,
- "\tBPY_driver_eval() - restricted access disallows name '%s', "
- "enable auto-execution to support\n",
- PyUnicode_AsUTF8(name));
+ if ((contains_name == false) || (name_str[0] == '_')) {
+ if (verbose) {
+ fprintf(stderr,
+ "\t%s: restricted access disallows name '%s', "
+ "enable auto-execution to support\n",
+ error_prefix,
+ name_str);
+ }
return false;
}
}
@@ -383,26 +487,70 @@ static bool bpy_driver_secure_bytecode_validate(PyObject *expr_code, PyObject *d
const _Py_CODEUNIT *codestr;
Py_ssize_t code_len;
- PyBytes_AsStringAndSize(py_code->co_code, (char **)&codestr, &code_len);
+ PyObject *co_code;
+
+# if PY_VERSION_HEX >= 0x030b0000 /* Python 3.11 & newer. */
+ co_code = PyCode_GetCode(py_code);
+ if (UNLIKELY(!co_code)) {
+ PyErr_Print();
+ PyErr_Clear();
+ return false;
+ }
+# else
+ co_code = py_code->co_code;
+# endif
+
+ PyBytes_AsStringAndSize(co_code, (char **)&codestr, &code_len);
code_len /= sizeof(*codestr);
+ bool ok = true;
+ /* Loop over op-code's, the op-code arguments are ignored. */
for (Py_ssize_t i = 0; i < code_len; i++) {
const int opcode = _Py_OPCODE(codestr[i]);
- if (secure_opcodes[opcode] == 0) {
- fprintf(stderr,
- "\tBPY_driver_eval() - restricted access disallows opcode '%d', "
- "enable auto-execution to support\n",
- opcode);
- return false;
+ if (secure_opcodes[opcode] == false) {
+ if (verbose) {
+ fprintf(stderr,
+ "\t%s: restricted access disallows opcode '%d', "
+ "enable auto-execution to support\n",
+ error_prefix,
+ opcode);
+ }
+ ok = false;
+ break;
}
}
-# undef CODESIZE
+# if PY_VERSION_HEX >= 0x030b0000 /* Python 3.11 & newer. */
+ Py_DECREF(co_code);
+# endif
+ if (!ok) {
+ return false;
+ }
}
return true;
}
+bool BPY_driver_secure_bytecode_test(PyObject *expr_code, PyObject *namespace, const bool verbose)
+{
+
+ if (!bpy_pydriver_Dict) {
+ if (bpy_pydriver_create_dict() != 0) {
+ fprintf(stderr, "%s: couldn't create Python dictionary\n", __func__);
+ return false;
+ }
+ }
+ return BPY_driver_secure_bytecode_test_ex(expr_code,
+ (PyObject *[]){
+ bpy_pydriver_Dict,
+ bpy_pydriver_Dict__whitelist,
+ namespace,
+ NULL,
+ },
+ verbose,
+ __func__);
+}
+
#endif /* USE_BYTECODE_WHITELIST */
float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
ChannelDriver *driver,
@@ -435,7 +583,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
DriverVar *dvar;
double result = 0.0; /* Default return. */
const char *expr;
- short targets_ok = 1;
+ bool targets_ok = true;
int i;
/* Get the python expression to be evaluated. */
@@ -470,7 +618,7 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
/* Initialize global dictionary for Python driver evaluation settings. */
if (!bpy_pydriver_Dict) {
if (bpy_pydriver_create_dict() != 0) {
- fprintf(stderr, "PyDriver error: couldn't create Python dictionary\n");
+ fprintf(stderr, "%s: couldn't create Python dictionary\n", __func__);
if (use_gil) {
PyGILState_Release(gilstate);
}
@@ -579,12 +727,11 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
/* This target failed - bad name. */
if (targets_ok) {
/* First one, print some extra info for easier identification. */
- fprintf(stderr, "\nBPY_driver_eval() - Error while evaluating PyDriver:\n");
- targets_ok = 0;
+ fprintf(stderr, "\n%s: Error while evaluating PyDriver:\n", __func__);
+ targets_ok = false;
}
- fprintf(
- stderr, "\tBPY_driver_eval() - couldn't add variable '%s' to namespace\n", dvar->name);
+ fprintf(stderr, "\t%s: couldn't add variable '%s' to namespace\n", __func__, dvar->name);
// BPy_errors_to_report(NULL); /* TODO: reports. */
PyErr_Print();
PyErr_Clear();
@@ -595,13 +742,17 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
#ifdef USE_BYTECODE_WHITELIST
if (is_recompile && expr_code) {
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC)) {
- if (!bpy_driver_secure_bytecode_validate(expr_code,
- (PyObject *[]){
- bpy_pydriver_Dict,
- bpy_pydriver_Dict__whitelist,
- driver_vars,
- NULL,
- })) {
+ if (!BPY_driver_secure_bytecode_test_ex(
+ expr_code,
+ (PyObject *[]){
+ bpy_pydriver_Dict,
+ bpy_pydriver_Dict__whitelist,
+ driver_vars,
+ NULL,
+ },
+ /* Always be verbose since this can give hints to why evaluation fails. */
+ true,
+ __func__)) {
if (!(G.f & G_FLAG_SCRIPT_AUTOEXEC_FAIL_QUIET)) {
G.f |= G_FLAG_SCRIPT_AUTOEXEC_FAIL;
BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Driver '%s'", expr);
@@ -630,11 +781,11 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
/* Process the result. */
if (retval == NULL) {
- pydriver_error(driver);
+ pydriver_error(driver, anim_rna);
}
else {
- if ((result = PyFloat_AsDouble(retval)) == -1.0 && PyErr_Occurred()) {
- pydriver_error(driver);
+ if (UNLIKELY((result = PyFloat_AsDouble(retval)) == -1.0 && PyErr_Occurred())) {
+ pydriver_error(driver, anim_rna);
result = 0.0;
}
else {
@@ -648,11 +799,10 @@ float BPY_driver_exec(struct PathResolvedRNA *anim_rna,
PyGILState_Release(gilstate);
}
- if (isfinite(result)) {
- return (float)result;
+ if (UNLIKELY(!isfinite(result))) {
+ fprintf(stderr, "\t%s: driver '%s' evaluates to '%f'\n", __func__, driver->expression, result);
+ return 0.0f;
}
- fprintf(
- stderr, "\tBPY_driver_eval() - driver '%s' evaluates to '%f'\n", driver->expression, result);
- return 0.0f;
+ return (float)result;
}
diff --git a/source/blender/python/intern/bpy_driver.h b/source/blender/python/intern/bpy_driver.h
index 301c6b3662e..f0d9717dbbd 100644
--- a/source/blender/python/intern/bpy_driver.h
+++ b/source/blender/python/intern/bpy_driver.h
@@ -10,6 +10,8 @@
extern "C" {
#endif
+#include <stdbool.h>
+
/**
* For faster execution we keep a special dictionary for py-drivers, with
* the needed modules and aliases.
@@ -21,6 +23,14 @@ int bpy_pydriver_create_dict(void);
*/
extern PyObject *bpy_pydriver_Dict;
+extern bool BPY_driver_secure_bytecode_test_ex(PyObject *expr_code,
+ PyObject *namespace_array[],
+ const bool verbose,
+ const char *error_prefix);
+extern bool BPY_driver_secure_bytecode_test(PyObject *expr_code,
+ PyObject *namespace,
+ const bool verbose);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 0ab8b4385e5..939fa475344 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -512,6 +512,9 @@ void BPY_python_end(void)
/* finalizing, no need to grab the state, except when we are a module */
gilstate = PyGILState_Ensure();
+ /* Frees the python-driver name-space & cached data. */
+ BPY_driver_exit();
+
/* Clear Python values in the context so freeing the context after Python exits doesn't crash. */
bpy_context_end(BPY_context_get());
@@ -582,16 +585,17 @@ void BPY_python_use_system_env(void)
void BPY_python_backtrace(FILE *fp)
{
fputs("\n# Python backtrace\n", fp);
- PyThreadState *tstate = PyGILState_GetThisThreadState();
- if (tstate != NULL && tstate->frame != NULL) {
- PyFrameObject *frame = tstate->frame;
- do {
- const int line = PyCode_Addr2Line(frame->f_code, frame->f_lasti);
- const char *filepath = PyUnicode_AsUTF8(frame->f_code->co_filename);
- const char *funcname = PyUnicode_AsUTF8(frame->f_code->co_name);
- fprintf(fp, " File \"%s\", line %d in %s\n", filepath, line, funcname);
- } while ((frame = frame->f_back));
+ PyFrameObject *frame;
+ if (!(frame = PyEval_GetFrame())) {
+ return;
}
+ do {
+ PyCodeObject *code = PyFrame_GetCode(frame);
+ const int line = PyFrame_GetLineNumber(frame);
+ const char *filepath = PyUnicode_AsUTF8(code->co_filename);
+ const char *funcname = PyUnicode_AsUTF8(code->co_name);
+ fprintf(fp, " File \"%s\", line %d in %s\n", filepath, line, funcname);
+ } while ((frame = PyFrame_GetBack(frame)));
}
void BPY_DECREF(void *pyob_ptr)
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 1ee778ae801..3f2154189e8 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -45,163 +45,34 @@
/** \name Shared Enums & Doc-Strings
* \{ */
-static const EnumPropertyItem property_flag_items[] = {
- {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
- {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
- {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
- {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
- {PROP_PROPORTIONAL, "PROPORTIONAL", 0, "Adjust values proportionally to eachother", ""},
- {PROP_TEXTEDIT_UPDATE,
- "TEXTEDIT_UPDATE",
- 0,
- "Update on every keystroke in textedit 'mode'",
- ""},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_OPTIONS_DOC \
- " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', " \
- "'PROPORTIONAL'," \
- "'TEXTEDIT_UPDATE'].\n" \
+ " :arg options: Enumerator in :ref:`rna_enum_property_flag_items`.\n" \
" :type options: set\n"
-static const EnumPropertyItem property_flag_enum_items[] = {
- {PROP_HIDDEN, "HIDDEN", 0, "Hidden", ""},
- {PROP_SKIP_SAVE, "SKIP_SAVE", 0, "Skip Save", ""},
- {PROP_ANIMATABLE, "ANIMATABLE", 0, "Animatable", ""},
- {PROP_LIB_EXCEPTION, "LIBRARY_EDITABLE", 0, "Library Editable", ""},
- {PROP_ENUM_FLAG, "ENUM_FLAG", 0, "Enum Flag", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_OPTIONS_ENUM_DOC \
- " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'ENUM_FLAG', " \
- "'LIBRARY_EDITABLE'].\n" \
+ " :arg options: Enumerator in :ref:`rna_enum_property_flag_enum_items`.\n" \
" :type options: set\n"
-static const EnumPropertyItem property_flag_override_items[] = {
- {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
- "LIBRARY_OVERRIDABLE",
- 0,
- "Library Overridable",
- "Make that property editable in library overrides of linked data-blocks"},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_OPTIONS_OVERRIDE_DOC \
- " :arg override: Enumerator in ['LIBRARY_OVERRIDABLE'].\n" \
+ " :arg override: Enumerator in :ref:`rna_enum_property_override_flag_items`.\n" \
" :type override: set\n"
-static const EnumPropertyItem property_flag_override_collection_items[] = {
- {PROPOVERRIDE_OVERRIDABLE_LIBRARY,
- "LIBRARY_OVERRIDABLE",
- 0,
- "Library Overridable",
- "Make that property editable in library overrides of linked data-blocks"},
- {PROPOVERRIDE_NO_PROP_NAME,
- "NO_PROPERTY_NAME",
- 0,
- "No Name",
- "Do not use the names of the items, only their indices in the collection"},
- {PROPOVERRIDE_LIBRARY_INSERTION,
- "USE_INSERTION",
- 0,
- "Use Insertion",
- "Allow users to add new items in that collection in library overrides"},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_OPTIONS_OVERRIDE_COLLECTION_DOC \
- " :arg override: Enumerator in ['LIBRARY_OVERRIDABLE', 'NO_PROPERTY_NAME', " \
- "'USE_INSERTION'].\n" \
+ " :arg override: Enumerator in :ref:`rna_enum_property_override_flag_collection_items`.\n" \
" :type override: set\n"
-/* subtypes */
-/* Keep in sync with RNA_types.h PropertySubType and rna_rna.c's rna_enum_property_subtype_items */
-static const EnumPropertyItem property_subtype_string_items[] = {
- {PROP_FILEPATH, "FILE_PATH", 0, "File Path", ""},
- {PROP_DIRPATH, "DIR_PATH", 0, "Directory Path", ""},
- {PROP_FILENAME, "FILE_NAME", 0, "Filename", ""},
- {PROP_BYTESTRING, "BYTE_STRING", 0, "Byte String", ""},
- {PROP_PASSWORD, "PASSWORD", 0, "Password", "A string that is displayed hidden ('********')"},
-
- {PROP_NONE, "NONE", 0, "None", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_SUBTYPE_STRING_DOC \
- " :arg subtype: Enumerator in ['FILE_PATH', 'DIR_PATH', 'FILE_NAME', 'BYTE_STRING', " \
- "'PASSWORD', 'NONE'].\n" \
+ " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_string_items`.\n" \
" :type subtype: string\n"
-static const EnumPropertyItem property_subtype_number_items[] = {
- {PROP_PIXEL, "PIXEL", 0, "Pixel", ""},
- {PROP_UNSIGNED, "UNSIGNED", 0, "Unsigned", ""},
- {PROP_PERCENTAGE, "PERCENTAGE", 0, "Percentage", ""},
- {PROP_FACTOR, "FACTOR", 0, "Factor", ""},
- {PROP_ANGLE, "ANGLE", 0, "Angle", ""},
- {PROP_TIME,
- "TIME",
- 0,
- "Time (Scene Relative)",
- "Time specified in frames, converted to seconds based on scene frame rate"},
- {PROP_TIME_ABSOLUTE,
- "TIME_ABSOLUTE",
- 0,
- "Time (Absolute)",
- "Time specified in seconds, independent of the scene"},
- {PROP_DISTANCE, "DISTANCE", 0, "Distance", ""},
- {PROP_DISTANCE_CAMERA, "DISTANCE_CAMERA", 0, "Camera Distance", ""},
- {PROP_POWER, "POWER", 0, "Power", ""},
- {PROP_TEMPERATURE, "TEMPERATURE", 0, "Temperature", ""},
-
- {PROP_NONE, "NONE", 0, "None", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
#define BPY_PROPDEF_SUBTYPE_NUMBER_DOC \
- " :arg subtype: Enumerator in ['PIXEL', 'UNSIGNED', 'PERCENTAGE', 'FACTOR', 'ANGLE', " \
- "'TIME', 'DISTANCE', 'DISTANCE_CAMERA', 'POWER', 'TEMPERATURE', 'NONE'].\n" \
+ " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_number_items`.\n" \
" :type subtype: string\n"
-static const EnumPropertyItem property_subtype_array_items[] = {
- {PROP_COLOR, "COLOR", 0, "Color", ""},
- {PROP_TRANSLATION, "TRANSLATION", 0, "Translation", ""},
- {PROP_DIRECTION, "DIRECTION", 0, "Direction", ""},
- {PROP_VELOCITY, "VELOCITY", 0, "Velocity", ""},
- {PROP_ACCELERATION, "ACCELERATION", 0, "Acceleration", ""},
- {PROP_MATRIX, "MATRIX", 0, "Matrix", ""},
- {PROP_EULER, "EULER", 0, "Euler", ""},
- {PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""},
- {PROP_AXISANGLE, "AXISANGLE", 0, "Axis Angle", ""},
- {PROP_XYZ, "XYZ", 0, "XYZ", ""},
- {PROP_XYZ_LENGTH, "XYZ_LENGTH", 0, "XYZ Length", ""},
- {PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Color Gamma", ""},
- {PROP_COORDS, "COORDINATES", 0, "Vector Coordinates", ""},
- {PROP_LAYER, "LAYER", 0, "Layer", ""},
- {PROP_LAYER_MEMBER, "LAYER_MEMBER", 0, "Layer Member", ""},
-
- {PROP_NONE, "NONE", 0, "None", ""},
- {0, NULL, 0, NULL, NULL},
-};
-
-#define BPY_PROPDEF_SUBTYPE_ARRAY_DOC \
- " :arg subtype: Enumerator in ['COLOR', 'TRANSLATION', 'DIRECTION', " \
- "'VELOCITY', 'ACCELERATION', 'MATRIX', 'EULER', 'QUATERNION', 'AXISANGLE', " \
- "'XYZ', 'XYZ_LENGTH', 'COLOR_GAMMA', 'COORDINATES', 'LAYER', 'LAYER_MEMBER', 'NONE'].\n" \
+#define BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC \
+ " :arg subtype: Enumerator in :ref:`rna_enum_property_subtype_number_array_items`.\n" \
" :type subtype: string\n"
-static const EnumPropertyItem property_string_search_options_items[] = {
- {PROP_STRING_SEARCH_SORT, "SORT", 0, "Sort Search Results", ""},
- {PROP_STRING_SEARCH_SUGGESTION,
- "SUGGESTION",
- 0,
- "Suggestion",
- "Search results are suggestions (other values may be entered)"},
-
- {0, NULL, 0, NULL, NULL},
-};
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -2750,8 +2621,7 @@ static int bpy_prop_arg_parse_tag_defines(PyObject *o, void *p)
" :type description: string\n"
#define BPY_PROPDEF_UNIT_DOC \
- " :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', " \
- "'VELOCITY', 'ACCELERATION', 'MASS', 'CAMERA', 'POWER'].\n" \
+ " :arg unit: Enumerator in :ref:`rna_enum_property_unit_items`.\n" \
" :type unit: string\n"
#define BPY_PROPDEF_NUM_MIN_DOC \
@@ -2900,18 +2770,18 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
bool default_value = false;
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_number_items,
+ .items = rna_enum_property_subtype_number_items,
.value = PROP_NONE,
};
@@ -3025,7 +2895,7 @@ PyDoc_STRVAR(
"\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC
" :arg default: sequence of booleans the length of *size*.\n"
" :type default: sequence\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
- BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
+ BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -3048,18 +2918,18 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject
PropertyRNA *prop;
PyObject *default_py = NULL;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_array_items,
+ .items = rna_enum_property_subtype_number_array_items,
.value = PROP_NONE,
};
PyObject *update_fn = NULL;
@@ -3224,18 +3094,18 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_number_items,
+ .items = rna_enum_property_subtype_number_items,
.value = PROP_NONE,
};
PyObject *update_fn = NULL;
@@ -3371,8 +3241,8 @@ PyDoc_STRVAR(BPy_IntVectorProperty_doc,
" :type soft_min: int\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
" :type soft_max: int\n" BPY_PROPDEF_INT_STEP_DOC BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_OPTIONS_OVERRIDE_DOC BPY_PROPDEF_TAGS_DOC
- BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC
- BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_VECSIZE_DOC
+ BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3397,18 +3267,18 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject
PyObject *default_py = NULL;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_array_items,
+ .items = rna_enum_property_subtype_number_array_items,
.value = PROP_NONE,
};
PyObject *update_fn = NULL;
@@ -3594,18 +3464,18 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_number_items,
+ .items = rna_enum_property_subtype_number_items,
.value = PROP_NONE,
};
struct BPy_EnumProperty_Parse unit_enum = {
@@ -3739,8 +3609,9 @@ PyDoc_STRVAR(BPy_FloatVectorProperty_doc,
" :type soft_min: float\n" BPY_PROPDEF_NUM_SOFTMAX_DOC
" :type soft_max: float\n" BPY_PROPDEF_OPTIONS_DOC BPY_PROPDEF_OPTIONS_OVERRIDE_DOC
BPY_PROPDEF_TAGS_DOC BPY_PROPDEF_FLOAT_STEP_DOC BPY_PROPDEF_FLOAT_PREC_DOC
- BPY_PROPDEF_SUBTYPE_ARRAY_DOC BPY_PROPDEF_UNIT_DOC BPY_PROPDEF_VECSIZE_DOC
- BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC BPY_PROPDEF_SET_DOC);
+ BPY_PROPDEF_SUBTYPE_NUMBER_ARRAY_DOC BPY_PROPDEF_UNIT_DOC
+ BPY_PROPDEF_VECSIZE_DOC BPY_PROPDEF_UPDATE_DOC BPY_PROPDEF_GET_DOC
+ BPY_PROPDEF_SET_DOC);
static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
StructRNA *srna;
@@ -3766,18 +3637,18 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec
PyObject *default_py = NULL;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_array_items,
+ .items = rna_enum_property_subtype_number_array_items,
.value = PROP_NONE,
};
struct BPy_EnumProperty_Parse unit_enum = {
@@ -3955,18 +3826,18 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
.srna = srna,
};
struct BPy_EnumProperty_Parse subtype_enum = {
- .items = property_subtype_string_items,
+ .items = rna_enum_property_subtype_string_items,
.value = PROP_NONE,
};
PyObject *update_fn = NULL;
@@ -3974,7 +3845,7 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw
PyObject *set_fn = NULL;
PyObject *search_fn = NULL;
static struct BPy_EnumProperty_Parse search_options_enum = {
- .items = property_string_search_options_items,
+ .items = rna_enum_property_string_search_flag_items,
.value = PROP_STRING_SEARCH_SUGGESTION,
};
@@ -4161,11 +4032,11 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
PropertyRNA *prop;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_enum_items,
+ .items = rna_enum_property_flag_enum_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
@@ -4384,11 +4255,11 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *type = Py_None;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_items,
+ .items = rna_enum_property_override_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
@@ -4521,11 +4392,11 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw)
PyObject *type = Py_None;
struct BPy_EnumProperty_Parse options_enum = {
- .items = property_flag_items,
+ .items = rna_enum_property_flag_items,
.value = 0,
};
struct BPy_EnumProperty_Parse override_enum = {
- .items = property_flag_override_collection_items,
+ .items = rna_enum_property_override_flag_collection_items,
.value = 0,
};
struct BPy_EnumProperty_Parse_WithSRNA tags_enum = {
diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c
index fb744432d4b..f25e9d0bbbc 100644
--- a/source/blender/python/intern/bpy_rna_anim.c
+++ b/source/blender/python/intern/bpy_rna_anim.c
@@ -487,7 +487,8 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb
i = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, cfra, fcu->totvert, &found);
if (found) {
/* delete the key at the index (will sanity check + do recalc afterwards) */
- delete_fcurve_key(fcu, i, 1);
+ BKE_fcurve_delete_key(fcu, i);
+ BKE_fcurve_handles_recalc(fcu);
result = true;
}
}
diff --git a/source/blender/python/intern/bpy_rna_gizmo.c b/source/blender/python/intern/bpy_rna_gizmo.c
index 61f439e5152..32ef7865e84 100644
--- a/source/blender/python/intern/bpy_rna_gizmo.c
+++ b/source/blender/python/intern/bpy_rna_gizmo.c
@@ -314,6 +314,8 @@ PyDoc_STRVAR(
"\n"
" Assigns callbacks to a gizmos property.\n"
"\n"
+ " :arg target: Target property name.\n"
+ " :type target: string\n"
" :arg get: Function that returns the value for this property (single value or sequence).\n"
" :type get: callable\n"
" :arg set: Function that takes a single value argument and applies it.\n"
diff --git a/source/blender/python/intern/bpy_traceback.c b/source/blender/python/intern/bpy_traceback.c
index 45977ba400c..1f2458c752f 100644
--- a/source/blender/python/intern/bpy_traceback.c
+++ b/source/blender/python/intern/bpy_traceback.c
@@ -20,7 +20,8 @@
static const char *traceback_filepath(PyTracebackObject *tb, PyObject **coerce)
{
- *coerce = PyUnicode_EncodeFSDefault(tb->tb_frame->f_code->co_filename);
+ PyCodeObject *code = PyFrame_GetCode(tb->tb_frame);
+ *coerce = PyUnicode_EncodeFSDefault(code->co_filename);
return PyBytes_AS_STRING(*coerce);
}
@@ -165,7 +166,7 @@ finally:
bool python_script_error_jump(
const char *filepath, int *r_lineno, int *r_offset, int *r_lineno_end, int *r_offset_end)
{
- /* WARNING(@campbellbarton): The normalized exception is restored (loosing line number info).
+ /* WARNING(@campbellbarton): The normalized exception is restored (losing line number info).
* Ideally this would leave the exception state as it found it, but that needs to be done
* carefully with regards to reference counting, see: T97731. */
diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt
index 747d6c0e8f8..f355d03cadc 100644
--- a/source/blender/python/mathutils/CMakeLists.txt
+++ b/source/blender/python/mathutils/CMakeLists.txt
@@ -4,9 +4,9 @@ set(INC
.
../../blenkernel
../../blenlib
- ../../imbuf
../../bmesh
../../depsgraph
+ ../../imbuf
../../makesdna
../../../../intern/guardedalloc
)
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 8cd7a5c7d87..1e85ece124d 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -290,6 +290,18 @@ static PyObject *matrix__apply_to_copy(PyObject *(*matrix_func)(MatrixObject *),
return NULL;
}
+static bool matrix_is_identity(MatrixObject *self)
+{
+ for (int row = 0; row < self->row_num; row++) {
+ for (int col = 0; col < self->col_num; col++) {
+ if (MATRIX_ITEM(self, row, col) != ((row != col) ? 0.0f : 1.0f)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -3104,6 +3116,16 @@ static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closur
return PyFloat_FromDouble(mat3_to_scale(mat));
}
+PyDoc_STRVAR(Matrix_is_identity_doc,
+ "True if this is an identity matrix (read-only).\n\n:type: bool");
+static PyObject *Matrix_is_identity_get(MatrixObject *self, void *UNUSED(closure))
+{
+ if (BaseMath_ReadCallback(self) == -1) {
+ return NULL;
+ }
+ return PyBool_FromLong(matrix_is_identity(self));
+}
+
PyDoc_STRVAR(Matrix_is_negative_doc,
"True if this matrix results in a negative scale, 3x3 and 4x4 only, "
"(read-only).\n\n:type: bool");
@@ -3187,6 +3209,7 @@ static PyGetSetDef Matrix_getseters[] = {
NULL},
{"row", (getter)Matrix_row_get, (setter)NULL, Matrix_row_doc, NULL},
{"col", (getter)Matrix_col_get, (setter)NULL, Matrix_col_doc, NULL},
+ {"is_identity", (getter)Matrix_is_identity_get, (setter)NULL, Matrix_is_identity_doc, NULL},
{"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, Matrix_is_negative_doc, NULL},
{"is_orthogonal",
(getter)Matrix_is_orthogonal_get,
diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py
index 61df784336c..b4e23547c62 100644
--- a/source/blender/python/rna_dump.py
+++ b/source/blender/python/rna_dump.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
if 1:
# Print once every 1000
GEN_PATH = True
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 0a8668221ad..548e38d3ef3 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -74,10 +74,12 @@ typedef struct RenderPass {
int pad;
} RenderPass;
-/* a renderlayer is a full image, but with all passes and samples */
-/* size of the rects is defined in RenderResult */
-/* after render, the Combined pass is in combined,
- * for renderlayers read from files it is a real pass */
+/**
+ * - A render-layer is a full image, but with all passes and samples.
+ * - The size of the rects is defined in #RenderResult.
+ * - After render, the Combined pass is in combined,
+ * for render-layers read from files it is a real pass.
+ */
typedef struct RenderLayer {
struct RenderLayer *next, *prev;
@@ -247,15 +249,15 @@ void RE_render_result_full_channel_name(char *fullname,
const char *passname,
const char *viewname,
const char *chan_id,
- const int channel);
+ int channel);
struct ImBuf *RE_render_result_rect_to_ibuf(struct RenderResult *rr,
const struct ImageFormatData *imf,
const float dither,
- const int view_id);
+ int view_id);
void RE_render_result_rect_from_ibuf(struct RenderResult *rr,
const struct ImBuf *ibuf,
- const int view_id);
+ int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname);
diff --git a/source/blender/render/RE_texture.h b/source/blender/render/RE_texture.h
index be50eacd7bf..a4e30c917d5 100644
--- a/source/blender/render/RE_texture.h
+++ b/source/blender/render/RE_texture.h
@@ -44,8 +44,6 @@ bool RE_texture_evaluate(const struct MTex *mtex,
* \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);
void RE_texture_rng_init(void);
@@ -89,7 +87,6 @@ typedef struct TexResult {
float trgba[4];
/* Is actually a boolean: When true -> use alpha, false -> set alpha to 1.0. */
int talpha;
- float *nor;
} TexResult;
/* This one uses nodes. */
diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h
index 0c91abeaddd..023615cea87 100644
--- a/source/blender/render/RE_texture_margin.h
+++ b/source/blender/render/RE_texture_margin.h
@@ -27,16 +27,13 @@ struct Mesh;
*/
void RE_generate_texturemargin_adjacentfaces(struct ImBuf *ibuf,
char *mask,
- const int margin,
+ int margin,
struct Mesh const *me,
char const *uv_layer,
const float uv_offset[2]);
-void RE_generate_texturemargin_adjacentfaces_dm(struct ImBuf *ibuf,
- char *mask,
- const int margin,
- struct DerivedMesh *dm,
- const float uv_offset[2]);
+void RE_generate_texturemargin_adjacentfaces_dm(
+ struct ImBuf *ibuf, char *mask, int margin, struct DerivedMesh *dm, const float uv_offset[2]);
#ifdef __cplusplus
}
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index 8a4b4c2a70d..266e66092b8 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -46,6 +46,8 @@
#include "DRW_engine.h"
+#include "GPU_context.h"
+
#include "pipeline.h"
#include "render_result.h"
#include "render_types.h"
@@ -950,6 +952,16 @@ bool RE_engine_render(Render *re, bool do_all)
re->draw_lock(re->dlh, true);
}
+ if ((type->flag & RE_USE_GPU_CONTEXT) && !GPU_backend_supported()) {
+ /* Clear UI drawing locks. */
+ if (re->draw_lock) {
+ re->draw_lock(re->dlh, false);
+ }
+ BKE_report(re->reports, RPT_ERROR, "Can not initialize the GPU");
+ G.is_break = true;
+ return true;
+ }
+
/* update animation here so any render layer animation is applied before
* creating the render result */
if ((re->r.scemode & (R_NO_FRAME_UPDATE | R_BUTS_PREVIEW)) == 0) {
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 6c06cd663fa..1c42467bc3d 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -87,8 +87,6 @@
# include "FRS_freestyle.h"
#endif
-#include "DEG_depsgraph.h"
-
/* internal */
#include "pipeline.h"
#include "render_result.h"
@@ -983,7 +981,7 @@ static void render_result_uncrop(Render *re)
render_result_free(re->result);
re->result = rres;
- /* weak... the display callback wants an active renderlayer pointer... */
+ /* Weak, the display callback wants an active render-layer pointer. */
re->result->renlay = render_get_active_layer(re, re->result);
BLI_rw_mutex_unlock(&re->resultmutex);
@@ -1038,8 +1036,7 @@ static void do_render_compositor_scene(Render *re, Scene *sce, int cfra)
/* exception: scene uses own size (unfinished code) */
if (0) {
- winx = (sce->r.size * sce->r.xsch) / 100;
- winy = (sce->r.size * sce->r.ysch) / 100;
+ BKE_render_resolution(&sce->r, false, &winx, &winy);
}
/* initial setup */
@@ -1224,7 +1221,7 @@ static void do_render_compositor(Render *re)
}
}
- /* weak... the display callback wants an active renderlayer pointer... */
+ /* Weak: the display callback wants an active render-layer pointer. */
if (re->result != NULL) {
re->result->renlay = render_get_active_layer(re, re->result);
re->display_update(re->duh, re->result, NULL);
@@ -1315,8 +1312,8 @@ static void do_render_sequencer(Render *re)
true,
&context);
- /* the renderresult gets destroyed during the rendering, so we first collect all ibufs
- * and then we populate the final renderesult */
+ /* The render-result gets destroyed during the rendering, so we first collect all ibufs
+ * and then we populate the final render-result. */
for (view_id = 0; view_id < tot_views; view_id++) {
context.view_id = view_id;
@@ -1677,8 +1674,7 @@ static int render_init_from_main(Render *re,
* r.border is the clipping rect */
/* calculate actual render result and display size */
- winx = (rd->size * rd->xsch) / 100;
- winy = (rd->size * rd->ysch) / 100;
+ BKE_render_resolution(rd, false, &winx, &winy);
/* We always render smaller part, inserting it in larger image is compositor business,
* it uses 'disprect' for it. */
@@ -2411,8 +2407,7 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
Object *camera;
int winx, winy;
- winx = (sce->r.size * sce->r.xsch) / 100;
- winy = (sce->r.size * sce->r.ysch) / 100;
+ BKE_render_resolution(&sce->r, false, &winx, &winy);
RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, winx, winy, NULL);
@@ -2441,8 +2436,7 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
rcti disprect;
/* calculate actual render result and display size */
- winx = (scene->r.size * scene->r.xsch) / 100;
- winy = (scene->r.size * scene->r.ysch) / 100;
+ BKE_render_resolution(&scene->r, false, &winx, &winy);
/* only in movie case we render smaller part */
if (scene->r.mode & R_BORDER) {
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index 9f4aa642773..3386a74daba 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -301,7 +301,7 @@ RenderResult *render_result_new(Render *re,
} \
} while (false)
- /* A renderlayer should always have a Combined pass. */
+ /* A render-layer should always have a "Combined" pass. */
render_layer_add_pass(rr, rl, 4, "Combined", view, "RGBA", false);
if (view_layer->passflag & SCE_PASS_Z) {
@@ -398,7 +398,7 @@ RenderResult *render_result_new(Render *re,
}
}
- /* a renderlayer should always have a Combined pass */
+ /* A render-layer should always have a "Combined" pass. */
render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, view, "RGBA", false);
}
@@ -825,7 +825,7 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
if (rpass->rect == NULL || rpassp->rect == NULL) {
continue;
}
- /* Renderresult have all passes, renderpart only the active view's passes. */
+ /* Render-result have all passes, render-part only the active view's passes. */
if (!STREQ(rpassp->fullname, rpass->fullname)) {
continue;
}
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index 30f49775562..c84e0a04018 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -44,7 +44,7 @@ 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
+ * 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(
diff --git a/source/blender/render/intern/texture_image.c b/source/blender/render/intern/texture_image.c
index 3b1eb293a3a..7da9e7c3d58 100644
--- a/source/blender/render/intern/texture_image.c
+++ b/source/blender/render/intern/texture_image.c
@@ -88,14 +88,13 @@ int imagewrap(Tex *tex,
struct ImagePool *pool,
const bool skip_load_image)
{
- float fx, fy, val1, val2, val3;
+ float fx, fy;
int x, y, retval;
int xi, yi; /* original values */
texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
- /* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
+ retval = TEX_RGB;
/* quick tests */
if (ima == NULL) {
@@ -256,47 +255,6 @@ int imagewrap(Tex *tex,
ibuf_get_color(texres->trgba, ibuf, x, y);
}
- if (texres->nor) {
- if (tex->imaflag & TEX_NORMALMAP) {
- /* Normal from color:
- * The invert of the red channel is to make
- * the normal map compliant with the outside world.
- * It needs to be done because in Blender
- * the normal used in the renderer points inward. It is generated
- * this way in calc_vertexnormals(). Should this ever change
- * this negate must be removed. */
- texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f);
- texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f);
- texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f);
- }
- else {
- /* bump: take three samples */
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
-
- if (x < ibuf->x - 1) {
- float col[4];
- ibuf_get_color(col, ibuf, x + 1, y);
- val2 = (col[0] + col[1] + col[2]);
- }
- else {
- val2 = val1;
- }
-
- if (y < ibuf->y - 1) {
- float col[4];
- ibuf_get_color(col, ibuf, x, y + 1);
- val3 = (col[0] + col[1] + col[2]);
- }
- else {
- val3 = val1;
- }
-
- /* do not mix up x and y here! */
- texres->nor[0] = (val1 - val2);
- texres->nor[1] = (val1 - val3);
- }
- }
-
if (texres->talpha) {
texres->tin = texres->trgba[3];
}
@@ -989,7 +947,7 @@ static int imagewraposa_aniso(Tex *tex,
{
TexResult texr;
float fx, fy, minx, maxx, miny, maxy;
- float maxd, val1, val2, val3;
+ float maxd;
int curmap, retval, intpol, extflag = 0;
afdata_t AFD;
@@ -1008,8 +966,7 @@ static int imagewraposa_aniso(Tex *tex,
texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
- /* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
+ retval = TEX_RGB;
/* quick tests */
if (ibuf == NULL && ima == NULL) {
@@ -1040,7 +997,7 @@ static int imagewraposa_aniso(Tex *tex,
if (ima) {
if ((tex->imaflag & TEX_USEALPHA) && (ima->alpha_mode != IMA_ALPHA_IGNORE)) {
if ((tex->imaflag & TEX_CALCALPHA) == 0) {
- texres->talpha = 1;
+ texres->talpha = true;
}
}
}
@@ -1301,48 +1258,17 @@ static int imagewraposa_aniso(Tex *tex,
}
/* filter functions take care of interpolation themselves, no need to modify dxt/dyt here */
-
- if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) {
- /* color & normal */
- filterfunc(texres, curibuf, fx, fy, &AFD);
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
- filterfunc(&texr, curibuf, fx + dxt[0], fy + dxt[1], &AFD);
- val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- filterfunc(&texr, curibuf, fx + dyt[0], fy + dyt[1], &AFD);
- val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- /* don't switch x or y! */
- texres->nor[0] = val1 - val2;
- texres->nor[1] = val1 - val3;
- if (previbuf != curibuf) { /* interpolate */
- filterfunc(&texr, previbuf, fx, fy, &AFD);
- /* rgb */
- texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]);
- texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]);
- texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]);
- texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]);
- /* normal */
- val1 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val1);
- filterfunc(&texr, previbuf, fx + dxt[0], fy + dxt[1], &AFD);
- val2 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val2);
- filterfunc(&texr, previbuf, fx + dyt[0], fy + dyt[1], &AFD);
- val3 += levf * ((texr.trgba[0] + texr.trgba[1] + texr.trgba[2]) - val3);
- texres->nor[0] = val1 - val2; /* vals have been interpolated above! */
- texres->nor[1] = val1 - val3;
- }
+ filterfunc(texres, curibuf, fx, fy, &AFD);
+ if (previbuf != curibuf) { /* interpolate */
+ filterfunc(&texr, previbuf, fx, fy, &AFD);
+ texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]);
+ texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]);
+ texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]);
+ texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]);
}
- else { /* color */
- filterfunc(texres, curibuf, fx, fy, &AFD);
- if (previbuf != curibuf) { /* interpolate */
- filterfunc(&texr, previbuf, fx, fy, &AFD);
- texres->trgba[0] += levf * (texr.trgba[0] - texres->trgba[0]);
- texres->trgba[1] += levf * (texr.trgba[1] - texres->trgba[1]);
- texres->trgba[2] += levf * (texr.trgba[2] - texres->trgba[2]);
- texres->trgba[3] += levf * (texr.trgba[3] - texres->trgba[3]);
- }
- if (tex->texfilter != TXF_EWA) {
- alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
- }
+ if (tex->texfilter != TXF_EWA) {
+ alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
}
}
else { /* no mipmap */
@@ -1372,23 +1298,9 @@ static int imagewraposa_aniso(Tex *tex,
AFD.dusc = 1.0f / ff;
AFD.dvsc = ff / (float)ibuf->y;
}
- if (texres->nor && ((tex->imaflag & TEX_NORMALMAP) == 0)) {
- /* color & normal */
- filterfunc(texres, ibuf, fx, fy, &AFD);
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
- filterfunc(&texr, ibuf, fx + dxt[0], fy + dxt[1], &AFD);
- val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- filterfunc(&texr, ibuf, fx + dyt[0], fy + dyt[1], &AFD);
- val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- /* don't switch x or y! */
- texres->nor[0] = val1 - val2;
- texres->nor[1] = val1 - val3;
- }
- else {
- filterfunc(texres, ibuf, fx, fy, &AFD);
- if (tex->texfilter != TXF_EWA) {
- alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
- }
+ filterfunc(texres, ibuf, fx, fy, &AFD);
+ if (tex->texfilter != TXF_EWA) {
+ alpha_clip_aniso(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, extflag, texres);
}
}
@@ -1403,18 +1315,6 @@ static int imagewraposa_aniso(Tex *tex,
texres->trgba[3] = 1.0f - texres->trgba[3];
}
- if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) { /* normal from color */
- /* The invert of the red channel is to make
- * the normal map compliant with the outside world.
- * It needs to be done because in Blender
- * the normal used in the renderer points inward. It is generated
- * this way in calc_vertexnormals(). Should this ever change
- * this negate must be removed. */
- texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f);
- texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f);
- texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f);
- }
-
/* de-premul, this is being pre-multiplied in shade_input_do_shade()
* TXF: this currently does not (yet?) work properly, destroys edge AA in clip/checker mode,
* so for now commented out also disabled in imagewraposa()
@@ -1451,7 +1351,7 @@ int imagewraposa(Tex *tex,
{
TexResult texr;
float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2];
- float maxd, pixsize, val1, val2, val3;
+ float maxd, pixsize;
int curmap, retval, imaprepeat, imapextend;
/* TXF: since dxt/dyt might be modified here and since they might be needed after imagewraposa()
@@ -1466,8 +1366,7 @@ int imagewraposa(Tex *tex,
texres->tin = texres->trgba[3] = texres->trgba[0] = texres->trgba[1] = texres->trgba[2] = 0.0f;
- /* we need to set retval OK, otherwise texture code generates normals itself... */
- retval = texres->nor ? (TEX_RGB | TEX_NOR) : TEX_RGB;
+ retval = TEX_RGB;
/* quick tests */
if (ibuf == NULL && ima == NULL) {
@@ -1762,118 +1661,30 @@ int imagewraposa(Tex *tex,
}
}
- if (texres->nor && (tex->imaflag & TEX_NORMALMAP) == 0) {
- /* a bit extra filter */
- // minx*= 1.35f;
- // miny*= 1.35f;
-
- boxsample(
- curibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
- boxsample(curibuf,
- fx - minx + dxt[0],
- fy - miny + dxt[1],
- fx + minx + dxt[0],
- fy + miny + dxt[1],
- &texr,
- imaprepeat,
- imapextend);
- val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- boxsample(curibuf,
- fx - minx + dyt[0],
- fy - miny + dyt[1],
- fx + minx + dyt[0],
- fy + miny + dyt[1],
- &texr,
- imaprepeat,
- imapextend);
- val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
-
- /* don't switch x or y! */
- texres->nor[0] = (val1 - val2);
- texres->nor[1] = (val1 - val3);
-
- if (previbuf != curibuf) { /* interpolate */
-
- boxsample(
- previbuf, fx - minx, fy - miny, fx + minx, fy + miny, &texr, imaprepeat, imapextend);
-
- /* calc rgb */
- dx = 2.0f * (pixsize - maxd) / pixsize;
- if (dx >= 1.0f) {
- texres->trgba[3] = texr.trgba[3];
- texres->trgba[2] = texr.trgba[2];
- texres->trgba[1] = texr.trgba[1];
- texres->trgba[0] = texr.trgba[0];
- }
- else {
- dy = 1.0f - dx;
- texres->trgba[2] = dy * texres->trgba[2] + dx * texr.trgba[2];
- texres->trgba[1] = dy * texres->trgba[1] + dx * texr.trgba[1];
- texres->trgba[0] = dy * texres->trgba[0] + dx * texr.trgba[0];
- texres->trgba[3] = dy * texres->trgba[3] + dx * texr.trgba[3];
- }
-
- val1 = dy * val1 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]);
- boxsample(previbuf,
- fx - minx + dxt[0],
- fy - miny + dxt[1],
- fx + minx + dxt[0],
- fy + miny + dxt[1],
- &texr,
- imaprepeat,
- imapextend);
- val2 = dy * val2 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]);
- boxsample(previbuf,
- fx - minx + dyt[0],
- fy - miny + dyt[1],
- fx + minx + dyt[0],
- fy + miny + dyt[1],
- &texr,
- imaprepeat,
- imapextend);
- val3 = dy * val3 + dx * (texr.trgba[0] + texr.trgba[1] + texr.trgba[2]);
-
- texres->nor[0] = (val1 - val2); /* vals have been interpolated above! */
- texres->nor[1] = (val1 - val3);
-
- if (dx < 1.0f) {
- dy = 1.0f - dx;
- texres->trgba[2] = dy * texres->trgba[2] + dx * texr.trgba[2];
- texres->trgba[1] = dy * texres->trgba[1] + dx * texr.trgba[1];
- texres->trgba[0] = dy * texres->trgba[0] + dx * texr.trgba[0];
- texres->trgba[3] = dy * texres->trgba[3] + dx * texr.trgba[3];
- }
- }
- texres->nor[0] *= bumpscale;
- texres->nor[1] *= bumpscale;
- }
- else {
- maxx = fx + minx;
- minx = fx - minx;
- maxy = fy + miny;
- miny = fy - miny;
+ maxx = fx + minx;
+ minx = fx - minx;
+ maxy = fy + miny;
+ miny = fy - miny;
- boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);
+ boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);
- if (previbuf != curibuf) { /* interpolate */
- boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
+ if (previbuf != curibuf) { /* interpolate */
+ boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
- fx = 2.0f * (pixsize - maxd) / pixsize;
+ fx = 2.0f * (pixsize - maxd) / pixsize;
- if (fx >= 1.0f) {
- texres->trgba[3] = texr.trgba[3];
- texres->trgba[2] = texr.trgba[2];
- texres->trgba[1] = texr.trgba[1];
- texres->trgba[0] = texr.trgba[0];
- }
- else {
- fy = 1.0f - fx;
- texres->trgba[2] = fy * texres->trgba[2] + fx * texr.trgba[2];
- texres->trgba[1] = fy * texres->trgba[1] + fx * texr.trgba[1];
- texres->trgba[0] = fy * texres->trgba[0] + fx * texr.trgba[0];
- texres->trgba[3] = fy * texres->trgba[3] + fx * texr.trgba[3];
- }
+ if (fx >= 1.0f) {
+ texres->trgba[3] = texr.trgba[3];
+ texres->trgba[2] = texr.trgba[2];
+ texres->trgba[1] = texr.trgba[1];
+ texres->trgba[0] = texr.trgba[0];
+ }
+ else {
+ fy = 1.0f - fx;
+ texres->trgba[2] = fy * texres->trgba[2] + fx * texr.trgba[2];
+ texres->trgba[1] = fy * texres->trgba[1] + fx * texr.trgba[1];
+ texres->trgba[0] = fy * texres->trgba[0] + fx * texr.trgba[0];
+ texres->trgba[3] = fy * texres->trgba[3] + fx * texr.trgba[3];
}
}
}
@@ -1889,35 +1700,7 @@ int imagewraposa(Tex *tex,
}
}
- if (texres->nor && (tex->imaflag & TEX_NORMALMAP) == 0) {
- boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
- val1 = texres->trgba[0] + texres->trgba[1] + texres->trgba[2];
- boxsample(ibuf,
- fx - minx + dxt[0],
- fy - miny + dxt[1],
- fx + minx + dxt[0],
- fy + miny + dxt[1],
- &texr,
- imaprepeat,
- imapextend);
- val2 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
- boxsample(ibuf,
- fx - minx + dyt[0],
- fy - miny + dyt[1],
- fx + minx + dyt[0],
- fy + miny + dyt[1],
- &texr,
- imaprepeat,
- imapextend);
- val3 = texr.trgba[0] + texr.trgba[1] + texr.trgba[2];
-
- /* don't switch x or y! */
- texres->nor[0] = (val1 - val2);
- texres->nor[1] = (val1 - val3);
- }
- else {
- boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
- }
+ boxsample(ibuf, fx - minx, fy - miny, fx + minx, fy + miny, texres, imaprepeat, imapextend);
}
if (tex->imaflag & TEX_CALCALPHA) {
@@ -1932,17 +1715,6 @@ int imagewraposa(Tex *tex,
texres->trgba[3] = 1.0f - texres->trgba[3];
}
- if (texres->nor && (tex->imaflag & TEX_NORMALMAP)) {
- /* Normal from color:
- * The invert of the red channel is to make the normal map compliant with the outside world.
- * It needs to be done because in Blender the normal used in the renderer points inward.
- * It is generated this way in #calc_vertexnormals().
- * Should this ever change this negate must be removed. */
- texres->nor[0] = -2.0f * (texres->trgba[0] - 0.5f);
- texres->nor[1] = 2.0f * (texres->trgba[1] - 0.5f);
- texres->nor[2] = 2.0f * (texres->trgba[2] - 0.5f);
- }
-
/* de-premul, this is being pre-multiplied in shade_input_do_shade() */
/* do not de-premul for generated alpha, it is already in straight */
if (texres->trgba[3] != 1.0f && texres->trgba[3] > 1e-4f && !(tex->imaflag & TEX_CALCALPHA)) {
diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c
index ce58993b7cf..37605236738 100644
--- a/source/blender/render/intern/texture_procedural.c
+++ b/source/blender/render/intern/texture_procedural.c
@@ -61,34 +61,6 @@ void RE_texture_rng_exit(void)
/* ------------------------------------------------------------------------- */
-/* This allows color-banded textures to control normals as well. */
-static void tex_normal_derivate(const Tex *tex, TexResult *texres)
-{
- if (tex->flag & TEX_COLORBAND) {
- float col[4];
- if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) {
- float fac0, fac1, fac2, fac3;
-
- fac0 = (col[0] + col[1] + col[2]);
- BKE_colorband_evaluate(tex->coba, texres->nor[0], col);
- fac1 = (col[0] + col[1] + col[2]);
- BKE_colorband_evaluate(tex->coba, texres->nor[1], col);
- fac2 = (col[0] + col[1] + col[2]);
- BKE_colorband_evaluate(tex->coba, texres->nor[2], col);
- fac3 = (col[0] + col[1] + col[2]);
-
- texres->nor[0] = (fac0 - fac1) / 3.0f;
- texres->nor[1] = (fac0 - fac2) / 3.0f;
- texres->nor[2] = (fac0 - fac3) / 3.0f;
-
- return;
- }
- }
- texres->nor[0] = texres->tin - texres->nor[0];
- texres->nor[1] = texres->tin - texres->nor[1];
- texres->nor[2] = texres->tin - texres->nor[2];
-}
-
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
{
float x, y, t;
@@ -165,37 +137,7 @@ static int clouds(const Tex *tex, const float texvec[3], TexResult *texres)
(tex->noisetype != TEX_NOISESOFT),
tex->noisebasis);
- if (texres->nor != NULL) {
- /* calculate bumpnormal */
- texres->nor[0] = BLI_noise_generic_turbulence(tex->noisesize,
- texvec[0] + tex->nabla,
- texvec[1],
- texvec[2],
- tex->noisedepth,
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
- texres->nor[1] = BLI_noise_generic_turbulence(tex->noisesize,
- texvec[0],
- texvec[1] + tex->nabla,
- texvec[2],
- tex->noisedepth,
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
- texres->nor[2] = BLI_noise_generic_turbulence(tex->noisesize,
- texvec[0],
- texvec[1],
- texvec[2] + tex->nabla,
- tex->noisedepth,
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
if (tex->stype == TEX_COLOR) {
- /* in this case, int. value should really be computed from color,
- * and bumpnormal from that, would be too slow, looks ok as is */
texres->trgba[0] = texres->tin;
texres->trgba[1] = BLI_noise_generic_turbulence(tex->noisesize,
texvec[1],
@@ -298,15 +240,6 @@ static int wood(const Tex *tex, const float texvec[3], TexResult *texres)
int rv = TEX_INT;
texres->tin = wood_int(tex, texvec[0], texvec[1], texvec[2]);
- if (texres->nor != NULL) {
- /* calculate bumpnormal */
- texres->nor[0] = wood_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]);
- texres->nor[1] = wood_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]);
- texres->nor[2] = wood_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
BRICONT;
@@ -358,17 +291,6 @@ static int marble(const Tex *tex, const float texvec[3], TexResult *texres)
texres->tin = marble_int(tex, texvec[0], texvec[1], texvec[2]);
- if (texres->nor != NULL) {
- /* calculate bumpnormal */
- texres->nor[0] = marble_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]);
- texres->nor[1] = marble_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]);
- texres->nor[2] = marble_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla);
-
- tex_normal_derivate(tex, texres);
-
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -454,7 +376,7 @@ static int magic(const Tex *tex, const float texvec[3], TexResult *texres)
/* newnoise: stucci also modified to use different noisebasis */
static int stucci(const Tex *tex, const float texvec[3], TexResult *texres)
{
- float nor[3], b2, ofs;
+ float b2, ofs;
int retval = TEX_INT;
b2 = BLI_noise_generic_noise(tex->noisesize,
@@ -469,40 +391,13 @@ static int stucci(const Tex *tex, const float texvec[3], TexResult *texres)
if (tex->stype) {
ofs *= (b2 * b2);
}
- nor[0] = BLI_noise_generic_noise(tex->noisesize,
- texvec[0] + ofs,
- texvec[1],
- texvec[2],
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
- nor[1] = BLI_noise_generic_noise(tex->noisesize,
- texvec[0],
- texvec[1] + ofs,
- texvec[2],
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
- nor[2] = BLI_noise_generic_noise(tex->noisesize,
- texvec[0],
- texvec[1],
- texvec[2] + ofs,
- (tex->noisetype != TEX_NOISESOFT),
- tex->noisebasis);
-
- texres->tin = nor[2];
-
- if (texres->nor) {
-
- copy_v3_v3(texres->nor, nor);
- tex_normal_derivate(tex, texres);
-
- if (tex->stype == TEX_WALLOUT) {
- texres->nor[0] = -texres->nor[0];
- texres->nor[1] = -texres->nor[1];
- texres->nor[2] = -texres->nor[2];
- }
- retval |= TEX_NOR;
- }
+ texres->tin = BLI_noise_generic_noise(tex->noisesize,
+ texvec[0],
+ texvec[1],
+ texvec[2] + ofs,
+ (tex->noisetype != TEX_NOISESOFT),
+ tex->noisebasis);
if (tex->stype == TEX_WALLOUT) {
texres->tin = 1.0f - texres->tin;
@@ -538,36 +433,6 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult
tex->mg_octaves,
tex->noisebasis);
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs,
- texvec[1],
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->noisebasis);
- texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1] + ofs,
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->noisebasis);
- texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1],
- texvec[2] + ofs,
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->noisebasis);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -595,42 +460,6 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu
tex->mg_gain,
tex->noisebasis);
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs,
- texvec[1],
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->mg_gain,
- tex->noisebasis);
- texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1] + ofs,
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->mg_gain,
- tex->noisebasis);
- texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0],
- texvec[1],
- texvec[2] + ofs,
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->mg_gain,
- tex->noisebasis);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -649,39 +478,6 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr
tex->mg_offset,
tex->noisebasis);
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + ofs,
- texvec[1],
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->noisebasis);
- texres->nor[1] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
- texvec[1] + ofs,
- texvec[2],
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->noisebasis);
- texres->nor[2] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
- texvec[1],
- texvec[2] + ofs,
- tex->mg_H,
- tex->mg_lacunarity,
- tex->mg_octaves,
- tex->mg_offset,
- tex->noisebasis);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -694,33 +490,6 @@ static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *tex
texres->tin = BLI_noise_mg_variable_lacunarity(
texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2);
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + ofs,
- texvec[1],
- texvec[2],
- tex->dist_amount,
- tex->noisebasis,
- tex->noisebasis2);
- texres->nor[1] = BLI_noise_mg_variable_lacunarity(texvec[0],
- texvec[1] + ofs,
- texvec[2],
- tex->dist_amount,
- tex->noisebasis,
- tex->noisebasis2);
- texres->nor[2] = BLI_noise_mg_variable_lacunarity(texvec[0],
- texvec[1],
- texvec[2] + ofs,
- tex->dist_amount,
- tex->noisebasis,
- tex->noisebasis2);
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
BRICONT;
return rv;
@@ -788,21 +557,6 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
}
}
- if (texres->nor != NULL) {
- float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */
-
- /* calculate bumpnormal */
- BLI_noise_voronoi(texvec[0] + ofs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
- BLI_noise_voronoi(texvec[0], texvec[1] + ofs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
- BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + ofs, da, pa, tex->vn_mexp, tex->vn_distm);
- texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
-
- tex_normal_derivate(tex, texres);
- rv |= TEX_NOR;
- }
-
if (tex->vn_coltype) {
BRICONTRGB;
texres->trgba[3] = 1.0;
@@ -1148,7 +902,7 @@ static int multitex(Tex *tex,
const bool use_nodes)
{
float tmpvec[3];
- int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */
+ int retval = 0; /* return value, TEX_INT or TEX_RGB. */
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
@@ -1283,14 +1037,14 @@ static int multitex_nodes_intern(Tex *tex,
}
if (tex->type == TEX_IMAGE) {
- int rgbnor;
+ int retval;
if (mtex) {
float texvec_l[3];
copy_v3_v3(texvec_l, texvec);
/* we have mtex, use it for 2d mapping images only */
do_2d_mapping(mtex, texvec_l, NULL, dxt, dyt);
- rgbnor = multitex(tex,
+ retval = multitex(tex,
texvec_l,
dxt,
dyt,
@@ -1307,7 +1061,7 @@ static int multitex_nodes_intern(Tex *tex,
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
/* don't linearize float buffers, assumed to be linear */
- if (ibuf != NULL && ibuf->rect_float == NULL && (rgbnor & TEX_RGB) && scene_color_manage) {
+ if (ibuf != NULL && ibuf->rect_float == NULL && (retval & TEX_RGB) && scene_color_manage) {
IMB_colormanagement_colorspace_to_scene_linear_v3(texres->trgba, ibuf->rect_colorspace);
}
@@ -1335,7 +1089,7 @@ static int multitex_nodes_intern(Tex *tex,
}
do_2d_mapping(&localmtex, texvec_l, NULL, dxt_l, dyt_l);
- rgbnor = multitex(tex,
+ retval = multitex(tex,
texvec_l,
dxt_l,
dyt_l,
@@ -1352,7 +1106,7 @@ static int multitex_nodes_intern(Tex *tex,
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
/* don't linearize float buffers, assumed to be linear */
- if (ibuf != NULL && ibuf->rect_float == NULL && (rgbnor & TEX_RGB) && scene_color_manage) {
+ if (ibuf != NULL && ibuf->rect_float == NULL && (retval & TEX_RGB) && scene_color_manage) {
IMB_colormanagement_colorspace_to_scene_linear_v3(texres->trgba, ibuf->rect_colorspace);
}
@@ -1360,7 +1114,7 @@ static int multitex_nodes_intern(Tex *tex,
}
}
- return rgbnor;
+ return retval;
}
return multitex(tex,
@@ -1456,145 +1210,6 @@ int multitex_ext_safe(Tex *tex,
/* ------------------------------------------------------------------------- */
-void texture_rgb_blend(
- float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype)
-{
- float facm;
-
- switch (blendtype) {
- case MTEX_BLEND:
- fact *= facg;
- facm = 1.0f - fact;
-
- in[0] = (fact * tex[0] + facm * out[0]);
- in[1] = (fact * tex[1] + facm * out[1]);
- in[2] = (fact * tex[2] + facm * out[2]);
- break;
-
- case MTEX_MUL:
- fact *= facg;
- facm = 1.0f - fact;
- in[0] = (facm + fact * tex[0]) * out[0];
- in[1] = (facm + fact * tex[1]) * out[1];
- in[2] = (facm + fact * tex[2]) * out[2];
- break;
-
- case MTEX_SCREEN:
- fact *= facg;
- facm = 1.0f - fact;
- in[0] = 1.0f - (facm + fact * (1.0f - tex[0])) * (1.0f - out[0]);
- in[1] = 1.0f - (facm + fact * (1.0f - tex[1])) * (1.0f - out[1]);
- in[2] = 1.0f - (facm + fact * (1.0f - tex[2])) * (1.0f - out[2]);
- break;
-
- case MTEX_OVERLAY:
- fact *= facg;
- facm = 1.0f - fact;
-
- if (out[0] < 0.5f) {
- in[0] = out[0] * (facm + 2.0f * fact * tex[0]);
- }
- else {
- in[0] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[0])) * (1.0f - out[0]);
- }
- if (out[1] < 0.5f) {
- in[1] = out[1] * (facm + 2.0f * fact * tex[1]);
- }
- else {
- in[1] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[1])) * (1.0f - out[1]);
- }
- if (out[2] < 0.5f) {
- in[2] = out[2] * (facm + 2.0f * fact * tex[2]);
- }
- else {
- in[2] = 1.0f - (facm + 2.0f * fact * (1.0f - tex[2])) * (1.0f - out[2]);
- }
- break;
-
- case MTEX_SUB:
- fact = -fact;
- ATTR_FALLTHROUGH;
- case MTEX_ADD:
- fact *= facg;
- in[0] = (fact * tex[0] + out[0]);
- in[1] = (fact * tex[1] + out[1]);
- in[2] = (fact * tex[2] + out[2]);
- break;
-
- case MTEX_DIV:
- fact *= facg;
- facm = 1.0f - fact;
-
- if (tex[0] != 0.0f) {
- in[0] = facm * out[0] + fact * out[0] / tex[0];
- }
- if (tex[1] != 0.0f) {
- in[1] = facm * out[1] + fact * out[1] / tex[1];
- }
- if (tex[2] != 0.0f) {
- in[2] = facm * out[2] + fact * out[2] / tex[2];
- }
-
- break;
-
- case MTEX_DIFF:
- fact *= facg;
- facm = 1.0f - fact;
- in[0] = facm * out[0] + fact * fabsf(tex[0] - out[0]);
- in[1] = facm * out[1] + fact * fabsf(tex[1] - out[1]);
- in[2] = facm * out[2] + fact * fabsf(tex[2] - out[2]);
- break;
-
- case MTEX_DARK:
- fact *= facg;
- facm = 1.0f - fact;
-
- in[0] = min_ff(out[0], tex[0]) * fact + out[0] * facm;
- in[1] = min_ff(out[1], tex[1]) * fact + out[1] * facm;
- in[2] = min_ff(out[2], tex[2]) * fact + out[2] * facm;
- break;
-
- case MTEX_LIGHT:
- fact *= facg;
-
- in[0] = max_ff(fact * tex[0], out[0]);
- in[1] = max_ff(fact * tex[1], out[1]);
- in[2] = max_ff(fact * tex[2], out[2]);
- break;
-
- case MTEX_BLEND_HUE:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_HUE, in, fact, tex);
- break;
- case MTEX_BLEND_SAT:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_SAT, in, fact, tex);
- break;
- case MTEX_BLEND_VAL:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_VAL, in, fact, tex);
- break;
- case MTEX_BLEND_COLOR:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_COLOR, in, fact, tex);
- break;
- case MTEX_SOFT_LIGHT:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_SOFT, in, fact, tex);
- break;
- case MTEX_LIN_LIGHT:
- fact *= facg;
- copy_v3_v3(in, out);
- ramp_blend(MA_RAMP_LINEAR, in, fact, tex);
- break;
- }
-}
-
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype)
{
float in = 0.0, facm, col, scf;
@@ -1703,7 +1318,6 @@ bool RE_texture_evaluate(const MTex *mtex,
if (tex == NULL) {
return 0;
}
- texr.nor = NULL;
/* placement */
if (mtex->projx) {
diff --git a/source/blender/sequencer/SEQ_add.h b/source/blender/sequencer/SEQ_add.h
index c195165a792..7c2d50a815e 100644
--- a/source/blender/sequencer/SEQ_add.h
+++ b/source/blender/sequencer/SEQ_add.h
@@ -50,6 +50,7 @@ typedef struct SeqLoadData {
struct Stereo3dFormat *stereo3d_format;
bool allow_invalid_file; /* Used by RNA API to create placeholder strips. */
double r_video_stream_start; /* For AV synchronization. Set by `SEQ_add_movie_strip`. */
+ bool adjust_playback_rate;
} SeqLoadData;
/**
@@ -176,16 +177,16 @@ void SEQ_add_image_set_directory(struct Sequence *seq, char *path);
* \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);
+void SEQ_add_image_load_file(struct Scene *scene,
+ 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,
diff --git a/source/blender/sequencer/SEQ_channels.h b/source/blender/sequencer/SEQ_channels.h
index dcfdb933940..197ad5e55de 100644
--- a/source/blender/sequencer/SEQ_channels.h
+++ b/source/blender/sequencer/SEQ_channels.h
@@ -24,8 +24,8 @@ void SEQ_channels_duplicate(struct ListBase *channels_dst, struct ListBase *chan
void SEQ_channels_free(struct ListBase *channels);
struct SeqTimelineChannel *SEQ_channel_get_by_index(const struct ListBase *channels,
- const int channel_index);
-char *SEQ_channel_name_get(struct ListBase *channels, const int channel_index);
+ int channel_index);
+char *SEQ_channel_name_get(struct ListBase *channels, int channel_index);
bool SEQ_channel_is_locked(const struct SeqTimelineChannel *channel);
bool SEQ_channel_is_muted(const struct SeqTimelineChannel *channel);
int SEQ_channel_index_get(const struct SeqTimelineChannel *channel);
diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h
index 2f07d5ae940..ff9c387e527 100644
--- a/source/blender/sequencer/SEQ_edit.h
+++ b/source/blender/sequencer/SEQ_edit.h
@@ -16,7 +16,10 @@ struct Main;
struct Scene;
struct Sequence;
-int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str);
+int SEQ_edit_sequence_swap(struct Scene *scene,
+ struct Sequence *seq_a,
+ struct Sequence *seq_b,
+ const char **error_str);
/**
* Move sequence to seqbase.
*
diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h
index e5af6f963e2..fa5d6d18736 100644
--- a/source/blender/sequencer/SEQ_effects.h
+++ b/source/blender/sequencer/SEQ_effects.h
@@ -55,7 +55,10 @@ struct SeqEffectHandle {
int (*early_out)(struct Sequence *seq, float fac);
/* sets the default `fac` value */
- void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *fac);
+ void (*get_default_fac)(const struct Scene *scene,
+ struct Sequence *seq,
+ float timeline_frame,
+ float *fac);
/* execute the effect
* sequence effects are only required to either support
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index 8cb20d41ba2..e5adb2a33b1 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -131,6 +131,9 @@ bool SEQ_collection_remove_strip(struct Sequence *seq, SeqCollection *collection
* \param collection: collection to be freed
*/
void SEQ_collection_free(SeqCollection *collection);
+/** Quiet compiler warning for free function. */
+#define SEQ_collection_free_void_p ((GHashValFreeFP)SEQ_collection_free)
+
/**
* Move strips from collection_src to collection_dst. Source collection will be freed.
*
@@ -154,9 +157,11 @@ void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_el
* \param collection: SeqCollection to be expanded
* \param seq_query_func: query function callback
*/
-void SEQ_collection_expand(struct ListBase *seqbase,
+void SEQ_collection_expand(const struct Scene *scene,
+ struct ListBase *seqbase,
SeqCollection *collection,
- void seq_query_func(struct Sequence *seq_reference,
+ void seq_query_func(const struct Scene *scene,
+ struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection));
/**
@@ -168,8 +173,10 @@ void SEQ_collection_expand(struct ListBase *seqbase,
* \return strip collection
*/
SeqCollection *SEQ_query_by_reference(struct Sequence *seq_reference,
+ const struct Scene *scene,
struct ListBase *seqbase,
- void seq_query_func(struct Sequence *seq_reference,
+ void seq_query_func(const struct Scene *scene,
+ struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection));
/**
@@ -208,7 +215,8 @@ SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase);
* \param displayed_channel: viewed channel. when set to 0, no channel filter is applied
* \return strip collection
*/
-SeqCollection *SEQ_query_rendered_strips(ListBase *channels,
+SeqCollection *SEQ_query_rendered_strips(const struct Scene *scene,
+ ListBase *channels,
ListBase *seqbase,
int timeline_frame,
int displayed_channel);
@@ -221,7 +229,8 @@ SeqCollection *SEQ_query_rendered_strips(ListBase *channels,
* \param seqbase: ListBase in which strips are queried
* \param collection: collection to be filled
*/
-void SEQ_query_strip_effect_chain(struct Sequence *seq_reference,
+void SEQ_query_strip_effect_chain(const struct Scene *scene,
+ struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection);
void SEQ_filter_selected_strips(SeqCollection *collection);
diff --git a/source/blender/sequencer/SEQ_relations.h b/source/blender/sequencer/SEQ_relations.h
index 917f549f16d..9678ac1cc1c 100644
--- a/source/blender/sequencer/SEQ_relations.h
+++ b/source/blender/sequencer/SEQ_relations.h
@@ -68,6 +68,7 @@ void SEQ_cache_iterate(
struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase /* = ed->seqbase */,
struct Sequence *meta /* = NULL */,
struct Sequence *seq);
+bool SEQ_exists_in_seqbase(const struct Sequence *seq, const struct ListBase *seqbase);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/SEQ_render.h b/source/blender/sequencer/SEQ_render.h
index a74eba5fc6f..9c163de4230 100644
--- a/source/blender/sequencer/SEQ_render.h
+++ b/source/blender/sequencer/SEQ_render.h
@@ -79,20 +79,23 @@ struct ImBuf *SEQ_get_thumbnail(const struct SeqRenderData *context,
/**
* Get frame for first thumbnail.
*/
-float SEQ_render_thumbnail_first_frame_get(struct Sequence *seq,
+float SEQ_render_thumbnail_first_frame_get(const struct Scene *scene,
+ struct Sequence *seq,
float frame_step,
struct rctf *view_area);
/**
* Get frame for first thumbnail.
*/
-float SEQ_render_thumbnail_next_frame_get(struct Sequence *seq,
+float SEQ_render_thumbnail_next_frame_get(const struct Scene *scene,
+ struct Sequence *seq,
float last_frame,
float frame_step);
/**
* 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);
+int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const struct Scene *scene,
+ const struct Sequence *seq);
/**
* Render set of evenly spaced thumbnails that are drawn when zooming..
*/
@@ -112,7 +115,9 @@ void SEQ_render_new_render_data(struct Main *bmain,
int for_render,
SeqRenderData *r_context);
int SEQ_render_evaluate_frame(struct ListBase *seqbase, int timeline_frame);
-struct StripElem *SEQ_render_give_stripelem(struct Sequence *seq, int timeline_frame);
+struct StripElem *SEQ_render_give_stripelem(const struct Scene *scene,
+ struct Sequence *seq,
+ int timeline_frame);
void SEQ_render_imbuf_from_sequencer_space(struct Scene *scene, struct ImBuf *ibuf);
void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4]);
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index 8ded6d99a8d..a77ca1c7baf 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -70,27 +70,24 @@ 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);
/**
- * Create and initialize #MetaStack, append it to `ed->metastack` ListBase
+ * Get #MetaStack that corresponds to current level that is being viewed
*
- * \param ed: sequence editor data
- * \param seq_meta: meta strip
- * \return pointer to created meta stack
+ * \return pointer to meta stack
*/
-struct MetaStack *SEQ_meta_stack_alloc(struct Editing *ed, struct Sequence *seq_meta);
+struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed);
/**
- * Get #MetaStack that corresponds to current level that is being viewed
+ * Open Meta strip content for editing.
*
* \param ed: sequence editor data
- * \return pointer to meta stack
+ * \param seqm: meta sequence or NULL for top level view
*/
-struct MetaStack *SEQ_meta_stack_active_get(const struct Editing *ed);
+void SEQ_meta_stack_set(const struct Scene *scene, struct Sequence *dst_seq);
/**
- * Free #MetaStack and remove it from `ed->metastack` ListBase.
+ * Close last Meta strip open for editing.
*
* \param ed: sequence editor data
- * \param ms: meta stack
*/
-void SEQ_meta_stack_free(struct Editing *ed, struct MetaStack *ms);
+struct Sequence *SEQ_meta_stack_pop(struct Editing *ed);
struct Sequence *SEQ_sequence_dupli_recursive(const struct Scene *scene_src,
struct Scene *scene_dst,
struct ListBase *new_seq_list,
@@ -143,7 +140,8 @@ typedef enum eSequenceLookupTag {
*
* \return pointer to Sequence
*/
-struct Sequence *SEQ_sequence_lookup_by_name(const struct Scene *scene, const char *key);
+struct Sequence *SEQ_sequence_lookup_seq_by_name(const struct Scene *scene, const char *key);
+
/**
* Free lookup hash data.
*
diff --git a/source/blender/sequencer/SEQ_sound.h b/source/blender/sequencer/SEQ_sound.h
index 52bdb68a554..e49f081109f 100644
--- a/source/blender/sequencer/SEQ_sound.h
+++ b/source/blender/sequencer/SEQ_sound.h
@@ -20,6 +20,7 @@ void SEQ_sound_update_bounds_all(struct Scene *scene);
void SEQ_sound_update_bounds(struct Scene *scene, struct Sequence *seq);
void SEQ_sound_update(struct Scene *scene, struct bSound *sound);
void SEQ_sound_update_length(struct Main *bmain, struct Scene *scene);
+float SEQ_sound_pitch_get(const struct Scene *scene, const struct Sequence *seq);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/SEQ_time.h b/source/blender/sequencer/SEQ_time.h
index 1da6efb1d04..69dc20d39ca 100644
--- a/source/blender/sequencer/SEQ_time.h
+++ b/source/blender/sequencer/SEQ_time.h
@@ -29,7 +29,9 @@ void SEQ_timeline_init_boundbox(const struct Scene *scene, struct rctf *rect);
* \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);
+void SEQ_timeline_expand_boundbox(const struct Scene *scene,
+ const struct ListBase *seqbase,
+ struct rctf *rect);
/**
* Define boundary rectangle of sequencer timeline and fill in rect data
*
@@ -47,8 +49,6 @@ int SEQ_time_find_next_prev_edit(struct Scene *scene,
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
@@ -58,15 +58,24 @@ void SEQ_time_update_recursive(struct Scene *scene, struct Sequence *changed_seq
* \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);
-bool SEQ_time_has_still_frames(const struct Sequence *seq);
-bool SEQ_time_has_left_still_frames(const struct Sequence *seq);
-bool SEQ_time_has_right_still_frames(const struct Sequence *seq);
-int SEQ_time_left_handle_frame_get(struct Sequence *seq);
-int SEQ_time_right_handle_frame_get(struct Sequence *seq);
-void SEQ_time_left_handle_frame_set(struct Sequence *seq, int val);
-void SEQ_time_right_handle_frame_set(struct Sequence *seq, int val);
+bool SEQ_time_strip_intersects_frame(const struct Scene *scene,
+ const struct Sequence *seq,
+ int timeline_frame);
+bool SEQ_time_has_still_frames(const struct Scene *scene, const struct Sequence *seq);
+bool SEQ_time_has_left_still_frames(const struct Scene *scene, const struct Sequence *seq);
+bool SEQ_time_has_right_still_frames(const struct Scene *scene, const struct Sequence *seq);
+
+int SEQ_time_left_handle_frame_get(const struct Scene *scene, const struct Sequence *seq);
+int SEQ_time_right_handle_frame_get(const struct Scene *scene, const struct Sequence *seq);
+void SEQ_time_left_handle_frame_set(const struct Scene *scene, struct Sequence *seq, int val);
+void SEQ_time_right_handle_frame_set(const struct Scene *scene, struct Sequence *seq, int val);
+int SEQ_time_strip_length_get(const struct Scene *scene, const struct Sequence *seq);
+void SEQ_time_speed_factor_set(const struct Scene *scene,
+ struct Sequence *seq,
+ const float speed_factor);
+float SEQ_time_start_frame_get(const struct Sequence *seq);
+void SEQ_time_start_frame_set(const struct Scene *scene, struct Sequence *seq, int timeline_frame);
+void SEQ_time_update_meta_strip_range(const 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 bd4258bfdb1..8bc7733861c 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -17,20 +17,19 @@ struct Scene;
struct SeqCollection;
struct Sequence;
-/**
- * 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_fix_single_image_seq_offsets(const struct Scene *scene, struct Sequence *seq);
+bool SEQ_transform_test_overlap(const struct Scene *scene,
+ struct ListBase *seqbasep,
+ struct Sequence *test);
+bool SEQ_transform_test_overlap_seq_seq(const struct Scene *scene,
+ 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.
@@ -43,6 +42,7 @@ bool SEQ_transform_seqbase_shuffle(struct ListBase *seqbasep,
struct Sequence *test,
struct Scene *evil_scene);
bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
+ struct SeqCollection *time_dependent_strips,
struct ListBase *seqbasep,
struct Scene *evil_scene,
struct ListBase *markers,
@@ -51,6 +51,7 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle,
void SEQ_transform_handle_overlap(struct Scene *scene,
struct ListBase *seqbasep,
struct SeqCollection *transformed_strips,
+ struct SeqCollection *time_dependent_strips,
bool use_sync_markers);
/**
* Check if the selected seq's reference unselected seq's.
diff --git a/source/blender/sequencer/SEQ_utils.h b/source/blender/sequencer/SEQ_utils.h
index ce3c81606ea..24ca7559166 100644
--- a/source/blender/sequencer/SEQ_utils.h
+++ b/source/blender/sequencer/SEQ_utils.h
@@ -20,14 +20,6 @@ struct SeqRenderData;
struct Sequence;
struct StripElem;
-/**
- * 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,
struct Sequence *seq);
@@ -39,7 +31,7 @@ const struct Sequence *SEQ_get_topmost_sequence(const struct Scene *scene, int f
/**
* In cases where we don't know the sequence's listbase.
*/
-struct ListBase *SEQ_get_seqbase_by_seq(struct ListBase *seqbase, struct Sequence *seq);
+struct ListBase *SEQ_get_seqbase_by_seq(const struct Scene *scene, struct Sequence *seq);
/**
* Only use as last resort when the StripElem is available but no the Sequence.
* (needed for RNA)
diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c
index f8e8fc32a5d..37830205588 100644
--- a/source/blender/sequencer/intern/disk_cache.c
+++ b/source/blender/sequencer/intern/disk_cache.c
@@ -37,6 +37,7 @@
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "disk_cache.h"
#include "image_cache.h"
@@ -411,8 +412,8 @@ void seq_disk_cache_invalidate(SeqDiskCache *disk_cache,
BLI_mutex_lock(&disk_cache->read_write_mutex);
- start = seq_changed->startdisp - DCACHE_IMAGES_PER_FILE;
- end = seq_changed->enddisp;
+ start = SEQ_time_left_handle_frame_get(scene, seq_changed) - DCACHE_IMAGES_PER_FILE;
+ end = SEQ_time_right_handle_frame_get(scene, seq_changed);
seq_disk_cache_delete_invalid_files(disk_cache, scene, seq, invalidate_types, start, end);
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index d9d21ee3b05..25a6acb8975 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -49,6 +49,7 @@
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
+#include "SEQ_time.h"
#include "SEQ_utils.h"
#include "BLF_api.h"
@@ -2431,7 +2432,7 @@ static ImBuf *do_multicam(const SeqRenderData *context,
if (!ed) {
return NULL;
}
- ListBase *seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbasep = SEQ_get_seqbase_by_seq(context->scene, seq);
ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, &ed->channels, seq);
if (!seqbasep) {
return NULL;
@@ -2467,13 +2468,15 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl
ed = context->scene->ed;
- ListBase *seqbasep = SEQ_get_seqbase_by_seq(&ed->seqbase, seq);
+ ListBase *seqbasep = SEQ_get_seqbase_by_seq(context->scene, seq);
ListBase *channels = SEQ_get_channels_by_seq(&ed->seqbase, &ed->channels, seq);
/* Clamp timeline_frame to strip range so it behaves as if it had "still frame" offset (last
* frame is static after end of strip). This is how most strips behave. This way transition
* effects that doesn't overlap or speed effect can't fail rendering outside of strip range. */
- timeline_frame = clamp_i(timeline_frame, seq->startdisp, seq->enddisp - 1);
+ timeline_frame = clamp_i(timeline_frame,
+ SEQ_time_left_handle_frame_get(context->scene, seq),
+ SEQ_time_right_handle_frame_get(context->scene, seq) - 1);
if (seq->machine > 1) {
i = seq_render_give_ibuf_seqbase(
@@ -2575,20 +2578,6 @@ static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac))
return EARLY_DO_EFFECT;
}
-/**
- * Generator strips with zero inputs have their length set to 1 permanently. In some cases it is
- * useful to use speed effect on these strips because they can be animated. This can be done by
- * using their length as is on timeline as content length. See T82698.
- */
-static int seq_effect_speed_get_strip_content_length(const Sequence *seq)
-{
- if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) == 0) {
- return seq->enddisp - seq->startdisp;
- }
-
- return seq->len;
-}
-
static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *seq)
{
return id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL);
@@ -2596,7 +2585,10 @@ static FCurve *seq_effect_speed_speed_factor_curve_get(Scene *scene, Sequence *s
void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
{
- if ((seq->seq1 == NULL) || (seq->len < 1)) {
+ const int effect_strip_length = SEQ_time_right_handle_frame_get(scene, seq) -
+ SEQ_time_left_handle_frame_get(scene, seq);
+
+ if ((seq->seq1 == NULL) || (effect_strip_length < 1)) {
return; /* Make coverity happy and check for (CID 598) input strip... */
}
@@ -2610,14 +2602,14 @@ void seq_effect_speed_rebuild_map(Scene *scene, Sequence *seq)
MEM_freeN(v->frameMap);
}
- const int effect_strip_length = seq->enddisp - seq->startdisp;
v->frameMap = MEM_mallocN(sizeof(float) * effect_strip_length, __func__);
v->frameMap[0] = 0.0f;
float target_frame = 0;
for (int frame_index = 1; frame_index < effect_strip_length; frame_index++) {
- target_frame += evaluate_fcurve(fcu, seq->startdisp + frame_index);
- CLAMP(target_frame, 0, seq->seq1->len);
+ target_frame += evaluate_fcurve(fcu, SEQ_time_left_handle_frame_get(scene, seq) + frame_index);
+ const int target_frame_max = SEQ_time_strip_length_get(scene, seq->seq1);
+ CLAMP(target_frame, 0, target_frame_max);
v->frameMap[frame_index] = target_frame;
}
}
@@ -2642,7 +2634,7 @@ float seq_speed_effect_target_frame_get(Scene *scene,
}
SEQ_effect_handle_get(seq_speed); /* Ensure, that data are initialized. */
- int frame_index = seq_give_frame_index(seq_speed, timeline_frame);
+ int frame_index = seq_give_frame_index(scene, seq_speed, timeline_frame);
SpeedControlVars *s = (SpeedControlVars *)seq_speed->effectdata;
const Sequence *source = seq_speed->seq1;
@@ -2650,9 +2642,10 @@ float seq_speed_effect_target_frame_get(Scene *scene,
switch (s->speed_control_type) {
case SEQ_SPEED_STRETCH: {
/* Only right handle controls effect speed! */
- const float target_content_length = seq_effect_speed_get_strip_content_length(source) -
+ const float target_content_length = SEQ_time_strip_length_get(scene, source) -
source->startofs;
- const float speed_effetct_length = seq_speed->enddisp - seq_speed->startdisp;
+ const float speed_effetct_length = SEQ_time_right_handle_frame_get(scene, seq_speed) -
+ SEQ_time_left_handle_frame_get(scene, seq_speed);
const float ratio = frame_index / speed_effetct_length;
target_frame = target_content_length * ratio;
break;
@@ -2669,15 +2662,14 @@ float seq_speed_effect_target_frame_get(Scene *scene,
break;
}
case SEQ_SPEED_LENGTH:
- target_frame = seq_effect_speed_get_strip_content_length(source) *
- (s->speed_fader_length / 100.0f);
+ target_frame = SEQ_time_strip_length_get(scene, source) * (s->speed_fader_length / 100.0f);
break;
case SEQ_SPEED_FRAME_NUMBER:
target_frame = s->speed_fader_frame_number;
break;
}
- CLAMP(target_frame, 0, seq_effect_speed_get_strip_content_length(source));
+ CLAMP(target_frame, 0, SEQ_time_strip_length_get(scene, source));
target_frame += seq_speed->start;
/* No interpolation. */
@@ -3502,15 +3494,21 @@ static int early_out_mul_input1(Sequence *UNUSED(seq), float fac)
return EARLY_DO_EFFECT;
}
-static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *fac)
+static void get_default_fac_noop(const Scene *UNUSED(scene),
+ Sequence *UNUSED(seq),
+ float UNUSED(timeline_frame),
+ float *fac)
{
*fac = 1.0f;
}
-static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac)
+static void get_default_fac_fade(const Scene *scene,
+ Sequence *seq,
+ float timeline_frame,
+ float *fac)
{
- *fac = (float)(timeline_frame - seq->startdisp);
- *fac /= seq->len;
+ *fac = (float)(timeline_frame - SEQ_time_left_handle_frame_get(scene, seq));
+ *fac /= SEQ_time_strip_length_get(scene, seq);
}
static struct ImBuf *init_execution(const SeqRenderData *context,
diff --git a/source/blender/sequencer/intern/image_cache.c b/source/blender/sequencer/intern/image_cache.c
index e1ff0ff64b3..53f076c9681 100644
--- a/source/blender/sequencer/intern/image_cache.c
+++ b/source/blender/sequencer/intern/image_cache.c
@@ -36,6 +36,7 @@
#include "SEQ_prefetch.h"
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "disk_cache.h"
#include "image_cache.h"
@@ -132,21 +133,24 @@ static bool seq_cache_hashcmp(const void *a_, const void *b_)
seq_cmp_render_data(&a->context, &b->context));
}
-static float seq_cache_timeline_frame_to_frame_index(Sequence *seq, float timeline_frame, int type)
+static float seq_cache_timeline_frame_to_frame_index(Scene *scene,
+ Sequence *seq,
+ float timeline_frame,
+ int type)
{
/* 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 (ELEM(type, SEQ_CACHE_STORE_RAW, SEQ_CACHE_STORE_THUMBNAIL)) {
- return seq_give_frame_index(seq, timeline_frame);
+ return seq_give_frame_index(scene, seq, timeline_frame);
}
- return timeline_frame - seq->start;
+ return timeline_frame - SEQ_time_start_frame_get(seq);
}
float seq_cache_frame_index_to_timeline_frame(Sequence *seq, float frame_index)
{
- return frame_index + seq->start;
+ return frame_index + SEQ_time_start_frame_get(seq);
}
static SeqCache *seq_cache_get_from_scene(Scene *scene)
@@ -517,7 +521,8 @@ static void seq_cache_populate_key(SeqCacheKey *key,
key->cache_owner = seq_cache_get_from_scene(context->scene);
key->seq = seq;
key->context = *context;
- key->frame_index = seq_cache_timeline_frame_to_frame_index(seq, timeline_frame, type);
+ key->frame_index = seq_cache_timeline_frame_to_frame_index(
+ context->scene, seq, timeline_frame, type);
key->timeline_frame = timeline_frame;
key->type = type;
key->link_prev = NULL;
@@ -557,9 +562,10 @@ void seq_cache_free_temp_cache(Scene *scene, short id, int timeline_frame)
if (key->is_temp_cache && key->task_id == id && key->type != SEQ_CACHE_STORE_THUMBNAIL) {
/* Use frame_index here to avoid freeing raw images if they are used for multiple frames. */
float frame_index = seq_cache_timeline_frame_to_frame_index(
- key->seq, timeline_frame, key->type);
- if (frame_index != key->frame_index || timeline_frame > key->seq->enddisp ||
- timeline_frame < key->seq->startdisp) {
+ scene, key->seq, timeline_frame, key->type);
+ if (frame_index != key->frame_index ||
+ timeline_frame > SEQ_time_right_handle_frame_get(scene, key->seq) ||
+ timeline_frame < SEQ_time_left_handle_frame_get(scene, key->seq)) {
BLI_ghash_remove(cache->hash, key, seq_cache_keyfree, seq_cache_valfree);
}
}
@@ -634,17 +640,12 @@ void seq_cache_cleanup_sequence(Scene *scene,
seq_cache_lock(scene);
- int range_start = seq_changed->startdisp;
- int range_end = seq_changed->enddisp;
+ int range_start = SEQ_time_left_handle_frame_get(scene, seq_changed);
+ int range_end = SEQ_time_right_handle_frame_get(scene, seq_changed);
if (!force_seq_changed_range) {
- if (seq->startdisp > range_start) {
- range_start = seq->startdisp;
- }
-
- if (seq->enddisp < range_end) {
- range_end = seq->enddisp;
- }
+ range_start = max_ii(range_start, SEQ_time_left_handle_frame_get(scene, seq));
+ range_end = min_ii(range_end, SEQ_time_right_handle_frame_get(scene, seq));
}
int invalidate_composite = invalidate_types & SEQ_CACHE_STORE_FINAL_OUT;
@@ -668,8 +669,8 @@ void seq_cache_cleanup_sequence(Scene *scene,
}
if (key->type & invalidate_source && key->seq == seq &&
- key->timeline_frame >= seq_changed->startdisp &&
- key->timeline_frame <= seq_changed->enddisp) {
+ key->timeline_frame >= SEQ_time_left_handle_frame_get(scene, seq_changed) &&
+ key->timeline_frame <= SEQ_time_right_handle_frame_get(scene, seq_changed)) {
if (key->link_next || key->link_prev) {
seq_cache_relink_keys(key->link_next, key->link_prev);
}
@@ -700,11 +701,12 @@ void seq_cache_thumbnail_cleanup(Scene *scene, rctf *view_area_safe)
SeqCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
BLI_ghashIterator_step(&gh_iter);
- const int frame_index = key->timeline_frame - key->seq->startdisp;
- const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(key->seq);
+ const int frame_index = key->timeline_frame - SEQ_time_left_handle_frame_get(scene, key->seq);
+ const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(scene, key->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 + key->seq->startdisp;
+ const int nearest_guaranted_absolute_frame = relative_base_frame +
+ SEQ_time_left_handle_frame_get(scene, key->seq);
if (nearest_guaranted_absolute_frame == key->timeline_frame) {
continue;
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
index 2710edd6e80..acf6776c4ed 100644
--- a/source/blender/sequencer/intern/iterator.c
+++ b/source/blender/sequencer/intern/iterator.c
@@ -103,13 +103,15 @@ bool SEQ_collection_has_strip(const Sequence *seq, const SeqCollection *collecti
}
SeqCollection *SEQ_query_by_reference(Sequence *seq_reference,
+ const Scene *scene,
ListBase *seqbase,
- void seq_query_func(Sequence *seq_reference,
+ void seq_query_func(const Scene *scene,
+ Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection))
{
SeqCollection *collection = SEQ_collection_create(__func__);
- seq_query_func(seq_reference, seqbase, collection);
+ seq_query_func(scene, seq_reference, seqbase, collection);
return collection;
}
bool SEQ_collection_append_strip(Sequence *seq, SeqCollection *collection)
@@ -146,9 +148,11 @@ void SEQ_collection_exclude(SeqCollection *collection, SeqCollection *exclude_el
SEQ_collection_free(exclude_elements);
}
-void SEQ_collection_expand(ListBase *seqbase,
+void SEQ_collection_expand(const Scene *scene,
+ ListBase *seqbase,
SeqCollection *collection,
- void seq_query_func(Sequence *seq_reference,
+ void seq_query_func(const Scene *scene,
+ Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection))
{
@@ -157,7 +161,8 @@ void SEQ_collection_expand(ListBase *seqbase,
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, collection) {
- SEQ_collection_merge(query_matches, SEQ_query_by_reference(seq, seqbase, seq_query_func));
+ SEQ_collection_merge(query_matches,
+ SEQ_query_by_reference(seq, scene, seqbase, seq_query_func));
}
/* Merge all expanded results in provided SeqIteratorCollection. */
@@ -219,12 +224,14 @@ SeqCollection *SEQ_query_selected_strips(ListBase *seqbase)
return collection;
}
-static SeqCollection *query_strips_at_frame(ListBase *seqbase, const int timeline_frame)
+static SeqCollection *query_strips_at_frame(const Scene *scene,
+ ListBase *seqbase,
+ const int timeline_frame)
{
SeqCollection *collection = SEQ_collection_create(__func__);
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (SEQ_time_strip_intersects_frame(seq, timeline_frame)) {
+ if (SEQ_time_strip_intersects_frame(scene, seq, timeline_frame)) {
SEQ_collection_append_strip(seq, collection);
}
}
@@ -299,12 +306,13 @@ static void collection_filter_rendered_strips(ListBase *channels, SeqCollection
}
}
-SeqCollection *SEQ_query_rendered_strips(ListBase *channels,
+SeqCollection *SEQ_query_rendered_strips(const Scene *scene,
+ ListBase *channels,
ListBase *seqbase,
const int timeline_frame,
const int displayed_channel)
{
- SeqCollection *collection = query_strips_at_frame(seqbase, timeline_frame);
+ SeqCollection *collection = query_strips_at_frame(scene, seqbase, timeline_frame);
if (displayed_channel != 0) {
collection_filter_channel_up_to_incl(collection, displayed_channel);
}
@@ -324,7 +332,8 @@ SeqCollection *SEQ_query_unselected_strips(ListBase *seqbase)
return collection;
}
-void SEQ_query_strip_effect_chain(Sequence *seq_reference,
+void SEQ_query_strip_effect_chain(const Scene *scene,
+ Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
{
@@ -335,13 +344,13 @@ void SEQ_query_strip_effect_chain(Sequence *seq_reference,
/* Find all strips that seq_reference is connected to. */
if (seq_reference->type & SEQ_TYPE_EFFECT) {
if (seq_reference->seq1) {
- SEQ_query_strip_effect_chain(seq_reference->seq1, seqbase, collection);
+ SEQ_query_strip_effect_chain(scene, seq_reference->seq1, seqbase, collection);
}
if (seq_reference->seq2) {
- SEQ_query_strip_effect_chain(seq_reference->seq2, seqbase, collection);
+ SEQ_query_strip_effect_chain(scene, seq_reference->seq2, seqbase, collection);
}
if (seq_reference->seq3) {
- SEQ_query_strip_effect_chain(seq_reference->seq3, seqbase, collection);
+ SEQ_query_strip_effect_chain(scene, seq_reference->seq3, seqbase, collection);
}
}
@@ -349,7 +358,7 @@ void SEQ_query_strip_effect_chain(Sequence *seq_reference,
LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
if (seq_test->seq1 == seq_reference || seq_test->seq2 == seq_reference ||
seq_test->seq3 == seq_reference) {
- SEQ_query_strip_effect_chain(seq_test, seqbase, collection);
+ SEQ_query_strip_effect_chain(scene, seq_test, seqbase, collection);
}
}
}
diff --git a/source/blender/sequencer/intern/prefetch.c b/source/blender/sequencer/intern/prefetch.c
index 01f581bc6c1..2a9f7f52779 100644
--- a/source/blender/sequencer/intern/prefetch.c
+++ b/source/blender/sequencer/intern/prefetch.c
@@ -395,7 +395,7 @@ static bool seq_prefetch_scene_strip_is_rendered(PrefetchJob *pfjob,
{
float cfra = seq_prefetch_cfra(pfjob);
Sequence *seq_arr[MAXSEQ + 1];
- int count = seq_get_shown_sequences(channels, seqbase, cfra, 0, seq_arr);
+ int count = seq_get_shown_sequences(pfjob->scene_eval, channels, seqbase, cfra, 0, seq_arr);
/* Iterate over rendered strips. */
for (int i = 0; i < count; i++) {
diff --git a/source/blender/sequencer/intern/proxy.c b/source/blender/sequencer/intern/proxy.c
index 59b4c6de1ef..374e18dd36a 100644
--- a/source/blender/sequencer/intern/proxy.c
+++ b/source/blender/sequencer/intern/proxy.c
@@ -43,6 +43,7 @@
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
+#include "SEQ_time.h"
#include "multiview.h"
#include "proxy.h"
@@ -122,7 +123,7 @@ bool seq_proxy_get_custom_file_fname(Sequence *seq, char *name, const int view_i
return true;
}
-static bool seq_proxy_get_fname(Editing *ed,
+static bool seq_proxy_get_fname(Scene *scene,
Sequence *seq,
int timeline_frame,
eSpaceSeq_Proxy_RenderSize render_size,
@@ -131,6 +132,7 @@ static bool seq_proxy_get_fname(Editing *ed,
{
char dir[PROXY_MAXFILE];
char suffix[24] = {'\0'};
+ Editing *ed = SEQ_editing_get(scene);
StripProxy *proxy = seq->strip->proxy;
if (proxy == NULL) {
@@ -178,7 +180,7 @@ static bool seq_proxy_get_fname(Editing *ed,
"%s/images/%d/%s_proxy%s",
dir,
proxy_size_number,
- SEQ_render_give_stripelem(seq, timeline_frame)->name,
+ SEQ_render_give_stripelem(scene, seq, timeline_frame)->name,
suffix);
BLI_path_abs(name, BKE_main_blendfile_path_from_global());
strcat(name, ".jpg");
@@ -201,7 +203,6 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline
char name[PROXY_MAXFILE];
StripProxy *proxy = seq->strip->proxy;
const eSpaceSeq_Proxy_RenderSize psize = context->preview_render_size;
- Editing *ed = context->scene->ed;
StripAnim *sanim;
/* only use proxies, if they are enabled (even if present!) */
@@ -210,9 +211,11 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline
}
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
- int frameno = (int)seq_give_frame_index(seq, timeline_frame) + seq->anim_startofs;
+ int frameno = (int)seq_give_frame_index(context->scene, seq, timeline_frame) +
+ seq->anim_startofs;
if (proxy->anim == NULL) {
- if (seq_proxy_get_fname(ed, seq, timeline_frame, psize, name, context->view_id) == 0) {
+ if (seq_proxy_get_fname(
+ context->scene, seq, timeline_frame, psize, name, context->view_id) == 0) {
return NULL;
}
@@ -231,7 +234,8 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline
return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
- if (seq_proxy_get_fname(ed, seq, timeline_frame, psize, name, context->view_id) == 0) {
+ if (seq_proxy_get_fname(context->scene, seq, timeline_frame, psize, name, context->view_id) ==
+ 0) {
return NULL;
}
@@ -259,9 +263,10 @@ static void seq_proxy_build_frame(const SeqRenderData *context,
int quality;
int rectx, recty;
ImBuf *ibuf_tmp, *ibuf;
- Editing *ed = context->scene->ed;
+ Scene *scene = context->scene;
- if (!seq_proxy_get_fname(ed, seq, timeline_frame, proxy_render_size, name, context->view_id)) {
+ if (!seq_proxy_get_fname(
+ scene, seq, timeline_frame, proxy_render_size, name, context->view_id)) {
return;
}
@@ -506,15 +511,11 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context,
}
/* fail safe code */
+ int width, height;
+ BKE_render_resolution(&scene->r, false, &width, &height);
- SEQ_render_new_render_data(bmain,
- context->depsgraph,
- context->scene,
- roundf((scene->r.size * (float)scene->r.xsch) / 100.0f),
- roundf((scene->r.size * (float)scene->r.ysch) / 100.0f),
- 100,
- false,
- &render_context);
+ SEQ_render_new_render_data(
+ bmain, context->depsgraph, context->scene, width, height, 100, false, &render_context);
render_context.skip_cache = true;
render_context.is_proxy_render = true;
@@ -523,7 +524,9 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context,
SeqRenderState state;
seq_render_state_init(&state);
- for (timeline_frame = seq->startdisp; timeline_frame < seq->enddisp; timeline_frame++) {
+ for (timeline_frame = SEQ_time_left_handle_frame_get(scene, seq);
+ timeline_frame < SEQ_time_right_handle_frame_get(scene, seq);
+ timeline_frame++) {
if (context->size_flags & IMB_PROXY_25) {
seq_proxy_build_frame(&render_context, &state, seq, timeline_frame, 25, overwrite);
}
@@ -537,7 +540,9 @@ void SEQ_proxy_rebuild(SeqIndexBuildContext *context,
seq_proxy_build_frame(&render_context, &state, seq, timeline_frame, 100, overwrite);
}
- *progress = (float)(timeline_frame - seq->startdisp) / (seq->enddisp - seq->startdisp);
+ *progress = (float)(timeline_frame - SEQ_time_left_handle_frame_get(scene, seq)) /
+ (SEQ_time_right_handle_frame_get(scene, seq) -
+ SEQ_time_left_handle_frame_get(scene, seq));
*do_update = true;
if (*stop || G.is_break) {
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index b0898be3765..b7dc0e7035d 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -233,7 +233,7 @@ void seq_render_state_init(SeqRenderState *state)
state->scene_parents = NULL;
}
-StripElem *SEQ_render_give_stripelem(Sequence *seq, int timeline_frame)
+StripElem *SEQ_render_give_stripelem(const Scene *scene, Sequence *seq, int timeline_frame)
{
StripElem *se = seq->strip->stripdata;
@@ -242,7 +242,7 @@ StripElem *SEQ_render_give_stripelem(Sequence *seq, int timeline_frame)
* all other strips don't use this...
*/
- int frame_index = (int)seq_give_frame_index(seq, timeline_frame);
+ int frame_index = (int)seq_give_frame_index(scene, seq, timeline_frame);
if (frame_index == -1 || se == NULL) {
return NULL;
@@ -258,14 +258,15 @@ static int seq_channel_cmp_fn(const void *a, const void *b)
return (*(Sequence **)a)->machine - (*(Sequence **)b)->machine;
}
-int seq_get_shown_sequences(ListBase *channels,
+int seq_get_shown_sequences(const Scene *scene,
+ ListBase *channels,
ListBase *seqbase,
const int timeline_frame,
const int chanshown,
Sequence **r_seq_arr)
{
SeqCollection *collection = SEQ_query_rendered_strips(
- channels, seqbase, timeline_frame, chanshown);
+ scene, channels, seqbase, timeline_frame, chanshown);
const int strip_count = BLI_gset_len(collection->set);
if (strip_count > MAXSEQ) {
@@ -795,7 +796,7 @@ 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);
+ sh.get_default_fac(scene, seq, timeline_frame, &fac);
}
else {
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
@@ -936,7 +937,7 @@ static ImBuf *seq_render_image_strip(const SeqRenderData *context,
char prefix[FILE_MAX];
ImBuf *ibuf = NULL;
- StripElem *s_elem = SEQ_render_give_stripelem(seq, timeline_frame);
+ StripElem *s_elem = SEQ_render_give_stripelem(context->scene, seq, timeline_frame);
if (s_elem == NULL) {
return NULL;
}
@@ -1024,7 +1025,8 @@ static ImBuf *seq_render_movie_strip_custom_file_proxy(const SeqRenderData *cont
}
}
- int frameno = (int)seq_give_frame_index(seq, timeline_frame) + seq->anim_startofs;
+ int frameno = (int)seq_give_frame_index(context->scene, seq, timeline_frame) +
+ seq->anim_startofs;
return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
@@ -1445,8 +1447,8 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
if ((sequencer_view3d_fn && do_seq_gl && camera) && is_thread_main) {
char err_out[256] = "unknown";
- const int width = (scene->r.xsch * scene->r.size) / 100;
- const int height = (scene->r.ysch * scene->r.size) / 100;
+ int width, height;
+ BKE_render_resolution(&scene->r, false, &width, &height);
const char *viewname = BKE_scene_multiview_render_view_name_get(&scene->r, context->view_id);
unsigned int draw_flags = V3D_OFSDRAW_NONE;
@@ -1622,7 +1624,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
- float frame_index = seq_give_frame_index(seq, timeline_frame);
+ float frame_index = seq_give_frame_index(context->scene, seq, timeline_frame);
int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type;
switch (type) {
case SEQ_TYPE_META: {
@@ -1826,7 +1828,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context,
ImBuf *out = NULL;
count = seq_get_shown_sequences(
- channels, seqbasep, timeline_frame, chanshown, (Sequence **)&seq_arr);
+ context->scene, channels, seqbasep, timeline_frame, chanshown, (Sequence **)&seq_arr);
if (count == 0) {
return NULL;
@@ -1940,7 +1942,7 @@ ImBuf *SEQ_render_give_ibuf(const SeqRenderData *context, float timeline_frame,
Sequence *seq_arr[MAXSEQ + 1];
int count;
- count = seq_get_shown_sequences(channels, seqbasep, timeline_frame, chanshown, seq_arr);
+ count = seq_get_shown_sequences(scene, channels, seqbasep, timeline_frame, chanshown, seq_arr);
if (count) {
out = seq_cache_get(context, seq_arr[count - 1], timeline_frame, SEQ_CACHE_STORE_FINAL_OUT);
@@ -1992,13 +1994,17 @@ ImBuf *SEQ_render_give_ibuf_direct(const SeqRenderData *context,
return ibuf;
}
-float SEQ_render_thumbnail_first_frame_get(Sequence *seq, float frame_step, rctf *view_area)
+float SEQ_render_thumbnail_first_frame_get(const Scene *scene,
+ Sequence *seq,
+ float frame_step,
+ rctf *view_area)
{
- int first_drawable_frame = max_iii(seq->startdisp, seq->start, view_area->xmin);
+ int first_drawable_frame = max_iii(
+ SEQ_time_left_handle_frame_get(scene, seq), seq->start, view_area->xmin);
/* First frame should correspond to handle position. */
- if (first_drawable_frame == seq->startdisp) {
- return seq->startdisp;
+ if (first_drawable_frame == SEQ_time_left_handle_frame_get(scene, seq)) {
+ return SEQ_time_left_handle_frame_get(scene, seq);
}
float aligned_frame_offset = (int)((first_drawable_frame - seq->start) / frame_step) *
@@ -2006,12 +2012,15 @@ float SEQ_render_thumbnail_first_frame_get(Sequence *seq, float frame_step, rctf
return seq->start + aligned_frame_offset;
}
-float SEQ_render_thumbnail_next_frame_get(Sequence *seq, float last_frame, float frame_step)
+float SEQ_render_thumbnail_next_frame_get(const Scene *scene,
+ Sequence *seq,
+ float last_frame,
+ float frame_step)
{
float next_frame = last_frame + frame_step;
/* If handle position was displayed, align next frame with `seq->start`. */
- if (last_frame == seq->startdisp) {
+ if (last_frame == SEQ_time_left_handle_frame_get(scene, seq)) {
next_frame = seq->start + ((int)((last_frame - seq->start) / frame_step) + 1) * frame_step;
}
@@ -2085,21 +2094,23 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
{
SeqRenderState state;
seq_render_state_init(&state);
+ const Scene *scene = context->scene;
/* Adding the hold offset value (seq->anim_startofs) to the start frame. Position of image not
* affected, but frame loaded affected. */
- float upper_thumb_bound = SEQ_time_has_right_still_frames(seq) ? (seq->start + seq->len) :
- seq->enddisp;
+ float upper_thumb_bound = SEQ_time_has_right_still_frames(scene, seq) ?
+ (seq->start + seq->len) :
+ SEQ_time_right_handle_frame_get(scene, seq);
upper_thumb_bound = (upper_thumb_bound > view_area->xmax) ? view_area->xmax + frame_step :
upper_thumb_bound;
- float timeline_frame = SEQ_render_thumbnail_first_frame_get(seq, frame_step, view_area);
+ float timeline_frame = SEQ_render_thumbnail_first_frame_get(scene, seq, frame_step, view_area);
while ((timeline_frame < upper_thumb_bound) & !*stop) {
ImBuf *ibuf = seq_cache_get(
context, seq_orig, round_fl_to_int(timeline_frame), SEQ_CACHE_STORE_THUMBNAIL);
if (ibuf) {
IMB_freeImBuf(ibuf);
- timeline_frame = SEQ_render_thumbnail_next_frame_get(seq, timeline_frame, frame_step);
+ timeline_frame = SEQ_render_thumbnail_next_frame_get(scene, seq, timeline_frame, frame_step);
continue;
}
@@ -2116,14 +2127,15 @@ void SEQ_render_thumbnails(const SeqRenderData *context,
return;
}
- timeline_frame = SEQ_render_thumbnail_next_frame_get(seq, timeline_frame, frame_step);
+ timeline_frame = SEQ_render_thumbnail_next_frame_get(scene, seq, timeline_frame, frame_step);
}
}
-int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Sequence *seq)
+int SEQ_render_thumbnails_guaranteed_set_frame_step_get(const Scene *scene, const Sequence *seq)
{
- const int content_start = max_ii(seq->startdisp, seq->start);
- const int content_end = min_ii(seq->enddisp, seq->start + seq->len);
+ const int content_start = max_ii(SEQ_time_left_handle_frame_get(scene, seq), seq->start);
+ const int content_end = min_ii(SEQ_time_right_handle_frame_get(scene, seq),
+ seq->start + seq->len);
const int content_len = content_end - content_start;
/* Arbitrary, but due to performance reasons should be as low as possible. */
@@ -2142,11 +2154,12 @@ void SEQ_render_thumbnails_base_set(const SeqRenderData *context,
{
SeqRenderState state;
seq_render_state_init(&state);
+ const Scene *scene = context->scene;
- int timeline_frame = seq->startdisp;
- const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(seq);
+ int timeline_frame = SEQ_time_left_handle_frame_get(scene, seq);
+ const int frame_step = SEQ_render_thumbnails_guaranteed_set_frame_step_get(scene, seq);
- while (timeline_frame < seq->enddisp && !*stop) {
+ while (timeline_frame < SEQ_time_right_handle_frame_get(scene, seq) && !*stop) {
ImBuf *ibuf = seq_cache_get(
context, seq_orig, roundf(timeline_frame), SEQ_CACHE_STORE_THUMBNAIL);
if (ibuf) {
diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h
index d41a0e3f86f..3690eb71ac4 100644
--- a/source/blender/sequencer/intern/render.h
+++ b/source/blender/sequencer/intern/render.h
@@ -44,7 +44,8 @@ struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3);
void seq_imbuf_to_sequencer_space(struct Scene *scene, struct ImBuf *ibuf, bool make_float);
-int seq_get_shown_sequences(struct ListBase *channels,
+int seq_get_shown_sequences(const struct Scene *scene,
+ struct ListBase *channels,
struct ListBase *seqbase,
int timeline_frame,
int chanshown,
diff --git a/source/blender/sequencer/intern/sequence_lookup.c b/source/blender/sequencer/intern/sequence_lookup.c
index 2a2626d8abf..8d18e381171 100644
--- a/source/blender/sequencer/intern/sequence_lookup.c
+++ b/source/blender/sequencer/intern/sequence_lookup.c
@@ -6,6 +6,7 @@
*/
#include "SEQ_sequencer.h"
+#include "sequencer.h"
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
@@ -14,6 +15,7 @@
#include "SEQ_iterator.h"
#include "BLI_ghash.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_sys_types.h"
#include "BLI_threads.h"
@@ -24,24 +26,66 @@
static ThreadMutex lookup_lock = BLI_MUTEX_INITIALIZER;
typedef struct SequenceLookup {
- GHash *by_name;
+ GHash *seq_by_name;
+ GHash *meta_by_seq;
+ GHash *effects_by_seq;
eSequenceLookupTag tag;
} SequenceLookup;
static void seq_sequence_lookup_init(struct SequenceLookup *lookup)
{
- lookup->by_name = BLI_ghash_str_new(__func__);
+ lookup->seq_by_name = BLI_ghash_str_new(__func__);
+ lookup->meta_by_seq = BLI_ghash_ptr_new(__func__);
+ lookup->effects_by_seq = BLI_ghash_ptr_new(__func__);
lookup->tag |= SEQ_LOOKUP_TAG_INVALID;
}
-static void seq_sequence_lookup_build(const struct Scene *scene, struct SequenceLookup *lookup)
+static void seq_sequence_lookup_append_effect(Sequence *input,
+ Sequence *effect,
+ struct SequenceLookup *lookup)
+{
+ if (input == NULL) {
+ return;
+ }
+
+ SeqCollection *effects = BLI_ghash_lookup(lookup->effects_by_seq, input);
+ if (effects == NULL) {
+ effects = SEQ_collection_create(__func__);
+ BLI_ghash_insert(lookup->effects_by_seq, input, effects);
+ }
+
+ SEQ_collection_append_strip(effect, effects);
+}
+
+static void seq_sequence_lookup_build_effect(Sequence *seq, struct SequenceLookup *lookup)
{
- SeqCollection *all_strips = SEQ_query_all_strips_recursive(&scene->ed->seqbase);
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, all_strips) {
- BLI_ghash_insert(lookup->by_name, seq->name + 2, seq);
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
+ return;
}
- SEQ_collection_free(all_strips);
+
+ seq_sequence_lookup_append_effect(seq->seq1, seq, lookup);
+ seq_sequence_lookup_append_effect(seq->seq2, seq, lookup);
+}
+
+static void seq_sequence_lookup_build_from_seqbase(Sequence *parent_meta,
+ const ListBase *seqbase,
+ struct SequenceLookup *lookup)
+{
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ BLI_ghash_insert(lookup->seq_by_name, seq->name + 2, seq);
+ BLI_ghash_insert(lookup->meta_by_seq, seq, parent_meta);
+ seq_sequence_lookup_build_effect(seq, lookup);
+
+ if (seq->type == SEQ_TYPE_META) {
+ seq_sequence_lookup_build_from_seqbase(seq, &seq->seqbase, lookup);
+ }
+ }
+}
+
+static void seq_sequence_lookup_build(const struct Scene *scene, struct SequenceLookup *lookup)
+{
+ Editing *ed = SEQ_editing_get(scene);
+ seq_sequence_lookup_build_from_seqbase(NULL, &ed->seqbase, lookup);
lookup->tag &= ~SEQ_LOOKUP_TAG_INVALID;
}
@@ -58,8 +102,12 @@ static void seq_sequence_lookup_free(struct SequenceLookup **lookup)
return;
}
- BLI_ghash_free((*lookup)->by_name, NULL, NULL);
- (*lookup)->by_name = NULL;
+ BLI_ghash_free((*lookup)->seq_by_name, NULL, NULL);
+ BLI_ghash_free((*lookup)->meta_by_seq, NULL, NULL);
+ BLI_ghash_free((*lookup)->effects_by_seq, NULL, SEQ_collection_free_void_p);
+ (*lookup)->seq_by_name = NULL;
+ (*lookup)->meta_by_seq = NULL;
+ (*lookup)->effects_by_seq = NULL;
MEM_freeN(*lookup);
*lookup = NULL;
}
@@ -98,17 +146,39 @@ void SEQ_sequence_lookup_free(const Scene *scene)
BLI_mutex_unlock(&lookup_lock);
}
-Sequence *SEQ_sequence_lookup_by_name(const Scene *scene, const char *key)
+Sequence *SEQ_sequence_lookup_seq_by_name(const Scene *scene, const char *key)
+{
+ BLI_assert(scene->ed);
+ BLI_mutex_lock(&lookup_lock);
+ seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
+ SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
+ Sequence *seq = BLI_ghash_lookup(lookup->seq_by_name, key);
+ BLI_mutex_unlock(&lookup_lock);
+ return seq;
+}
+
+Sequence *seq_sequence_lookup_meta_by_seq(const Scene *scene, const Sequence *key)
{
BLI_assert(scene->ed);
BLI_mutex_lock(&lookup_lock);
seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
- Sequence *seq = BLI_ghash_lookup(lookup->by_name, key);
+ Sequence *seq = BLI_ghash_lookup(lookup->meta_by_seq, key);
BLI_mutex_unlock(&lookup_lock);
return seq;
}
+SeqCollection *seq_sequence_lookup_effects_by_seq(const Scene *scene, const Sequence *key)
+{
+ BLI_assert(scene->ed);
+ BLI_mutex_lock(&lookup_lock);
+ seq_sequence_lookup_update_if_needed(scene, &scene->ed->runtime.sequence_lookup);
+ SequenceLookup *lookup = scene->ed->runtime.sequence_lookup;
+ SeqCollection *effects = BLI_ghash_lookup(lookup->effects_by_seq, key);
+ BLI_mutex_unlock(&lookup_lock);
+ return effects;
+}
+
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 ad57412034a..a184f727b9e 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -37,6 +37,7 @@
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "SEQ_sound.h"
+#include "SEQ_time.h"
#include "SEQ_utils.h"
#include "BLO_read_write.h"
@@ -126,9 +127,10 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int
seq->mul = 1.0;
seq->blend_opacity = 100.0;
seq->volume = 1.0f;
- seq->pitch = 1.0f;
seq->scene_sound = NULL;
seq->type = type;
+ seq->media_playback_rate = 0.0f;
+ seq->speed_factor = 1.0f;
if (seq->type == SEQ_TYPE_ADJUSTMENT) {
seq->blend_mode = SEQ_TYPE_CROSS;
@@ -397,21 +399,22 @@ void SEQ_seqbase_active_set(Editing *ed, ListBase *seqbase)
ed->seqbasep = seqbase;
}
-MetaStack *SEQ_meta_stack_alloc(Editing *ed, Sequence *seq_meta)
+static MetaStack *seq_meta_stack_alloc(const Scene *scene, Sequence *seq_meta)
{
+ Editing *ed = SEQ_editing_get(scene);
+
MetaStack *ms = MEM_mallocN(sizeof(MetaStack), "metastack");
- BLI_addtail(&ed->metastack, ms);
+ BLI_addhead(&ed->metastack, ms);
ms->parseq = seq_meta;
- ms->oldbasep = ed->seqbasep;
- ms->old_channels = ed->displayed_channels;
- copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
- return ms;
-}
-void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
-{
- BLI_remlink(&ed->metastack, ms);
- MEM_freeN(ms);
+ /* Reference to previously displayed timeline data. */
+ Sequence *higher_level_meta = seq_sequence_lookup_meta_by_seq(scene, seq_meta);
+ ms->oldbasep = higher_level_meta ? &higher_level_meta->seqbase : &ed->seqbase;
+ ms->old_channels = higher_level_meta ? &higher_level_meta->channels : &ed->channels;
+
+ ms->disp_range[0] = SEQ_time_left_handle_frame_get(scene, ms->parseq);
+ ms->disp_range[1] = SEQ_time_right_handle_frame_get(scene, ms->parseq);
+ return ms;
}
MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
@@ -423,6 +426,41 @@ MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
return ed->metastack.last;
}
+void SEQ_meta_stack_set(const Scene *scene, Sequence *seqm)
+{
+ Editing *ed = SEQ_editing_get(scene);
+ /* Clear metastack */
+ BLI_freelistN(&ed->metastack);
+
+ if (seqm != NULL) {
+ /* Allocate meta stack in a way, that represents meta hierarchy in timeline. */
+ seq_meta_stack_alloc(scene, seqm);
+ Sequence *meta_parent = seqm;
+ while ((meta_parent = seq_sequence_lookup_meta_by_seq(scene, meta_parent))) {
+ seq_meta_stack_alloc(scene, meta_parent);
+ }
+
+ SEQ_seqbase_active_set(ed, &seqm->seqbase);
+ SEQ_channels_displayed_set(ed, &seqm->channels);
+ }
+ else {
+ /* Go to top level, exiting meta strip. */
+ SEQ_seqbase_active_set(ed, &ed->seqbase);
+ SEQ_channels_displayed_set(ed, &ed->channels);
+ }
+}
+
+Sequence *SEQ_meta_stack_pop(Editing *ed)
+{
+ MetaStack *ms = SEQ_meta_stack_active_get(ed);
+ Sequence *meta_parent = ms->parseq;
+ SEQ_seqbase_active_set(ed, ms->oldbasep);
+ SEQ_channels_displayed_set(ed, ms->old_channels);
+ BLI_remlink(&ed->metastack, ms);
+ MEM_freeN(ms);
+ return meta_parent;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -928,8 +966,9 @@ static bool seq_update_seq_cb(Sequence *seq, void *user_data)
}
BKE_sound_set_scene_sound_volume(
seq->scene_sound, seq->volume, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
- BKE_sound_set_scene_sound_pitch(
- seq->scene_sound, seq->pitch, (seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
+ BKE_sound_set_scene_sound_pitch(seq->scene_sound,
+ SEQ_sound_pitch_get(scene, seq),
+ (seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
BKE_sound_set_scene_sound_pan(
seq->scene_sound, seq->pan, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
}
diff --git a/source/blender/sequencer/intern/sequencer.h b/source/blender/sequencer/intern/sequencer.h
index 9f5bdf672c0..5e78c8c6f96 100644
--- a/source/blender/sequencer/intern/sequencer.h
+++ b/source/blender/sequencer/intern/sequencer.h
@@ -14,13 +14,37 @@ extern "C" {
struct Scene;
struct Sequence;
struct StripProxy;
+struct SeqCollection;
/**
* 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);
-
+/**
+ * Find meta strip, that contains strip `key`.
+ * 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: pointer to Sequence inside of meta strip
+ *
+ * \return pointer to meta strip
+ */
+struct Sequence *seq_sequence_lookup_meta_by_seq(const struct Scene *scene,
+ const struct Sequence *key);
+/**
+ * Find effect strips, that use strip `seq` as one of inputs.
+ * 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: pointer to Sequence inside of meta strip
+ *
+ * \return collection of effect strips
+ */
+struct SeqCollection *seq_sequence_lookup_effects_by_seq(const struct Scene *scene,
+ const struct Sequence *key);
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/intern/sound.c b/source/blender/sequencer/intern/sound.c
index 8076c600560..c4992848cb5 100644
--- a/source/blender/sequencer/intern/sound.c
+++ b/source/blender/sequencer/intern/sound.c
@@ -23,6 +23,7 @@
#include "SEQ_sound.h"
#include "SEQ_time.h"
+#include "sequencer.h"
#include "strip_time.h"
/* Unlike _update_sound_ funcs, these ones take info from audaspace to update sequence length! */
@@ -35,7 +36,6 @@ 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, seqbase, seq);
changed = true;
}
}
@@ -55,7 +55,6 @@ static bool sequencer_refresh_sound_length_recursive(Main *bmain, Scene *scene,
seq->endofs *= fac;
seq->start += (old - seq->startofs); /* So that visual/"real" start frame does not change! */
- SEQ_time_update_sequence(scene, seqbase, seq);
changed = true;
}
}
@@ -99,8 +98,12 @@ 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, 0.0);
+ BKE_sound_move_scene_sound(scene,
+ seq->scene_sound,
+ SEQ_time_left_handle_frame_get(scene, seq),
+ SEQ_time_right_handle_frame_get(scene, seq),
+ startofs,
+ 0.0);
}
}
else {
@@ -131,3 +134,12 @@ void SEQ_sound_update(Scene *scene, bSound *sound)
seq_update_sound_recursive(scene, &scene->ed->seqbase, sound);
}
}
+
+float SEQ_sound_pitch_get(const Scene *scene, const Sequence *seq)
+{
+ Sequence *meta_parent = seq_sequence_lookup_meta_by_seq(scene, seq);
+ if (meta_parent != NULL) {
+ return seq->speed_factor * SEQ_sound_pitch_get(scene, meta_parent);
+ }
+ return seq->speed_factor;
+}
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index 77b0fc946d9..753a6ee39e0 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -51,6 +51,8 @@
#include "multiview.h"
#include "proxy.h"
+#include "sequencer.h"
+#include "strip_time.h"
#include "utils.h"
void SEQ_add_load_data_init(SeqLoadData *load_data,
@@ -70,12 +72,12 @@ void SEQ_add_load_data_init(SeqLoadData *load_data,
load_data->channel = channel;
}
-static void seq_add_generic_update(Scene *scene, ListBase *seqbase, Sequence *seq)
+static void seq_add_generic_update(Scene *scene, Sequence *seq)
{
SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
- SEQ_time_update_sequence(scene, seqbase, seq);
- SEQ_sort(seqbase);
SEQ_relations_invalidate_cache_composite(scene, seq);
+ SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID);
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}
static void seq_add_set_name(Scene *scene, Sequence *seq, SeqLoadData *load_data)
@@ -128,7 +130,7 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1;
id_us_ensure_real((ID *)load_data->scene);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -140,7 +142,7 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
seq->len = BKE_movieclip_get_duration(load_data->clip);
id_us_ensure_real((ID *)load_data->clip);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -152,7 +154,7 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
seq->len = BKE_mask_get_duration(load_data->mask);
id_us_ensure_real((ID *)load_data->mask);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -174,11 +176,12 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
if (!load_data->effect.seq1) {
seq->len = 1; /* Effect is generator, set non zero length. */
- SEQ_time_right_handle_frame_set(seq, load_data->effect.end_frame);
+ SEQ_time_right_handle_frame_set(scene, seq, load_data->effect.end_frame);
}
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
+ seq_time_effect_range_set(scene, seq);
return seq;
}
@@ -188,9 +191,10 @@ void SEQ_add_image_set_directory(Sequence *seq, char *path)
BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
}
-void SEQ_add_image_load_file(Sequence *seq, size_t strip_frame, char *filename)
+void SEQ_add_image_load_file(Scene *scene, Sequence *seq, size_t strip_frame, char *filename)
{
- StripElem *se = SEQ_render_give_stripelem(seq, seq->start + strip_frame);
+ StripElem *se = SEQ_render_give_stripelem(
+ scene, seq, SEQ_time_start_frame_get(seq) + strip_frame);
BLI_strncpy(se->name, filename, sizeof(se->name));
}
@@ -264,7 +268,7 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
BLI_strncpy(scene->ed->act_imagedir, seq->strip->dir, sizeof(scene->ed->act_imagedir));
seq_add_set_view_transform(scene, seq, load_data);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -335,7 +339,7 @@ Sequence *SEQ_add_sound_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
/* Set Last active directory. */
BLI_strncpy(scene->ed->act_sounddir, strip->dir, FILE_MAXDIR);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
return seq;
}
@@ -362,7 +366,6 @@ 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, seqbase, seqm);
return seqm;
}
@@ -466,9 +469,19 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
orig_height = IMB_anim_get_image_height(anim_arr[0]);
SEQ_set_scale_to_fit(
seq, orig_width, orig_height, scene->r.xsch, scene->r.ysch, load_data->fit_method);
+
+ short frs_sec;
+ float frs_sec_base;
+ if (IMB_anim_get_fps(anim_arr[0], &frs_sec, &frs_sec_base, true)) {
+ seq->media_playback_rate = (float)frs_sec / frs_sec_base;
+ }
}
seq->len = MAX2(1, seq->len);
+ if (load_data->adjust_playback_rate) {
+ seq->flag |= SEQ_AUTO_PLAYBACK_RATE;
+ }
+
BLI_strncpy(seq->strip->colorspace_settings.name,
colorspace,
sizeof(seq->strip->colorspace_settings.name));
@@ -484,7 +497,7 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
seq_add_set_view_transform(scene, seq, load_data);
seq_add_set_name(scene, seq, load_data);
- seq_add_generic_update(scene, seqbase, seq);
+ seq_add_generic_update(scene, seq);
MEM_freeN(anim_arr);
return seq;
@@ -509,11 +522,8 @@ 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) */
- 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;
+ prev_startdisp = SEQ_time_left_handle_frame_get(scene, seq);
+ prev_enddisp = SEQ_time_right_handle_frame_get(scene, seq);
}
switch (seq->type) {
@@ -656,13 +666,11 @@ void SEQ_add_reload_new_file(Main *bmain, Scene *scene, Sequence *seq, const boo
free_proxy_seq(seq);
if (lock_range) {
- SEQ_time_left_handle_frame_set(seq, prev_startdisp);
- SEQ_time_right_handle_frame_set(seq, prev_enddisp);
- SEQ_transform_fix_single_image_seq_offsets(seq);
+ SEQ_time_left_handle_frame_set(scene, seq, prev_startdisp);
+ SEQ_time_right_handle_frame_set(scene, seq, prev_enddisp);
+ SEQ_transform_fix_single_image_seq_offsets(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);
}
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 96bfce8f740..15c472dd5a7 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -37,11 +37,11 @@
#include "SEQ_transform.h"
#include "SEQ_utils.h"
-int SEQ_edit_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
+int SEQ_edit_sequence_swap(Scene *scene, Sequence *seq_a, Sequence *seq_b, const char **error_str)
{
char name[sizeof(seq_a->name)];
- if (seq_a->len != seq_b->len) {
+ if (SEQ_time_strip_length_get(scene, seq_a) != SEQ_time_strip_length_get(scene, seq_b)) {
*error_str = N_("Strips must be the same length");
return 0;
}
@@ -80,12 +80,12 @@ int SEQ_edit_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_
SWAP(Sequence *, seq_a->prev, seq_b->prev);
SWAP(Sequence *, seq_a->next, seq_b->next);
- SWAP(int, seq_a->start, seq_b->start);
- SWAP(int, seq_a->startofs, seq_b->startofs);
- SWAP(int, seq_a->endofs, seq_b->endofs);
+ SWAP(float, seq_a->start, seq_b->start);
+ SWAP(float, seq_a->startofs, seq_b->startofs);
+ SWAP(float, seq_a->endofs, seq_b->endofs);
SWAP(int, seq_a->machine, seq_b->machine);
- SWAP(int, seq_a->startdisp, seq_b->startdisp);
- SWAP(int, seq_a->enddisp, seq_b->enddisp);
+ seq_time_effect_range_set(scene, seq_a);
+ seq_time_effect_range_set(scene, seq_b);
return 1;
}
@@ -192,19 +192,6 @@ void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
}
}
-static bool seq_exists_in_seqbase(Sequence *seq, ListBase *seqbase)
-{
- LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
- if (seq_test->type == SEQ_TYPE_META && seq_exists_in_seqbase(seq, &seq_test->seqbase)) {
- return true;
- }
- if (seq_test == seq) {
- return true;
- }
- }
- return false;
-}
-
bool SEQ_edit_move_strip_to_seqbase(Scene *scene,
ListBase *seqbase,
Sequence *seq,
@@ -216,7 +203,7 @@ bool SEQ_edit_move_strip_to_seqbase(Scene *scene,
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
/* Update meta. */
- if (SEQ_transform_test_overlap(dst_seqbase, seq)) {
+ if (SEQ_transform_test_overlap(scene, dst_seqbase, seq)) {
SEQ_transform_seqbase_shuffle(dst_seqbase, seq, scene);
}
@@ -230,7 +217,7 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene,
{
/* Find the appropriate seqbase */
Editing *ed = SEQ_editing_get(scene);
- ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, src_seq);
+ ListBase *seqbase = SEQ_get_seqbase_by_seq(scene, src_seq);
if (dst_seqm->type != SEQ_TYPE_META) {
*error_str = N_("Can not move strip to non-meta strip");
@@ -247,19 +234,19 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene,
return false;
}
- if (src_seq->type == SEQ_TYPE_META && seq_exists_in_seqbase(dst_seqm, &src_seq->seqbase)) {
+ if (src_seq->type == SEQ_TYPE_META && SEQ_exists_in_seqbase(dst_seqm, &src_seq->seqbase)) {
*error_str = N_("Moved strip is parent of provided meta strip");
return false;
}
- if (!seq_exists_in_seqbase(dst_seqm, &ed->seqbase)) {
+ if (!SEQ_exists_in_seqbase(dst_seqm, &ed->seqbase)) {
*error_str = N_("Can not move strip to different scene");
return false;
}
SeqCollection *collection = SEQ_collection_create(__func__);
SEQ_collection_append_strip(src_seq, collection);
- SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(scene, seqbase, collection, SEQ_query_strip_effect_chain);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, collection) {
@@ -272,138 +259,126 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene,
return true;
}
-static void seq_split_set_left_hold_offset(Sequence *seq, int timeline_frame)
+static void seq_split_set_left_hold_offset(Scene *scene, Sequence *seq, int timeline_frame)
{
/* Adjust within range of extended stillframes before strip. */
if (timeline_frame < seq->start) {
- SEQ_time_left_handle_frame_set(seq, timeline_frame);
- }
- /* Adjust within range of strip contents. */
- else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) {
- seq->anim_startofs += timeline_frame - seq->start;
- seq->start = timeline_frame;
- seq->startofs = 0;
- }
- /* Adjust within range of extended stillframes after strip. */
- else if ((seq->start + seq->len) < timeline_frame) {
- const int right_handle_backup = SEQ_time_right_handle_frame_get(seq);
- seq->start += timeline_frame - seq->start;
- seq->anim_startofs += seq->len - 1;
- seq->len = 1;
- SEQ_time_left_handle_frame_set(seq, timeline_frame);
- SEQ_time_right_handle_frame_set(seq, right_handle_backup);
- }
-}
-
-static void seq_split_set_right_hold_offset(Sequence *seq, int timeline_frame)
-{
- /* Adjust within range of extended stillframes before strip. */
- if (timeline_frame < seq->start) {
- const int left_handle_backup = SEQ_time_left_handle_frame_get(seq);
seq->start = timeline_frame - 1;
- SEQ_time_left_handle_frame_set(seq, left_handle_backup);
- SEQ_time_right_handle_frame_set(seq, timeline_frame);
+ seq->anim_endofs += SEQ_time_strip_length_get(scene, seq) - 1;
+ seq->startstill = timeline_frame - seq->startdisp - 1;
+ seq->endstill = 0;
}
/* Adjust within range of strip contents. */
- else if ((timeline_frame >= seq->start) && (timeline_frame <= (seq->start + seq->len))) {
- seq->anim_endofs += seq->start + seq->len - timeline_frame;
+ else if ((timeline_frame >= seq->start) &&
+ (timeline_frame <= (seq->start + SEQ_time_strip_length_get(scene, seq)))) {
seq->endofs = 0;
+ seq->endstill = 0;
+ seq->anim_endofs += (seq->start + SEQ_time_strip_length_get(scene, seq)) - timeline_frame;
}
/* Adjust within range of extended stillframes after strip. */
- else if ((seq->start + seq->len) < timeline_frame) {
- SEQ_time_right_handle_frame_set(seq, timeline_frame);
+ else if ((seq->start + SEQ_time_strip_length_get(scene, seq)) < timeline_frame) {
+ seq->endstill = timeline_frame - seq->start - SEQ_time_strip_length_get(scene, seq);
}
}
-static void seq_split_set_right_offset(Sequence *seq, int timeline_frame)
+static void seq_split_set_right_hold_offset(Scene *scene, Sequence *seq, int timeline_frame)
{
/* Adjust within range of extended stillframes before strip. */
if (timeline_frame < seq->start) {
- const int content_offset = seq->start - timeline_frame + 1;
- seq->start = timeline_frame - 1;
- seq->startofs += content_offset;
+ seq->startstill = seq->start - timeline_frame;
+ }
+ /* Adjust within range of strip contents. */
+ else if ((timeline_frame >= seq->start) &&
+ (timeline_frame <= (seq->start + SEQ_time_strip_length_get(scene, seq)))) {
+ seq->anim_startofs += timeline_frame - seq->start;
+ seq->start = timeline_frame;
+ seq->startstill = 0;
+ seq->startofs = 0;
}
-
- SEQ_time_right_handle_frame_set(seq, timeline_frame);
-}
-
-static void seq_split_set_left_offset(Sequence *seq, int timeline_frame)
-{
/* Adjust within range of extended stillframes after strip. */
- if (timeline_frame > seq->start + seq->len) {
- const int content_offset = timeline_frame - (seq->start + seq->len) + 1;
- seq->start += content_offset;
- seq->endofs += content_offset;
+ else if ((seq->start + SEQ_time_strip_length_get(scene, seq)) < timeline_frame) {
+ seq->start = timeline_frame;
+ seq->startofs = 0;
+ seq->anim_startofs += SEQ_time_strip_length_get(scene, seq) - 1;
+ seq->endstill = seq->enddisp - timeline_frame - 1;
+ seq->startstill = 0;
}
-
- SEQ_time_left_handle_frame_set(seq, timeline_frame);
}
-static bool seq_edit_split_effect_intersect_check(const Sequence *seq, const int timeline_frame)
+static bool seq_edit_split_effect_intersect_check(const Scene *scene,
+ const Sequence *seq,
+ const int timeline_frame)
{
- return timeline_frame > seq->startdisp && timeline_frame < seq->enddisp;
+ return timeline_frame > SEQ_time_left_handle_frame_get(scene, seq) &&
+ timeline_frame < SEQ_time_right_handle_frame_get(scene, seq);
}
static void seq_edit_split_handle_strip_offsets(Main *bmain,
Scene *scene,
- ListBase *seqbase,
Sequence *left_seq,
Sequence *right_seq,
const int timeline_frame,
const eSeqSplitMethod method)
{
- if (seq_edit_split_effect_intersect_check(right_seq, timeline_frame)) {
+ if (seq_edit_split_effect_intersect_check(scene, right_seq, timeline_frame)) {
switch (method) {
case SEQ_SPLIT_SOFT:
- seq_split_set_left_offset(right_seq, timeline_frame);
+ SEQ_time_left_handle_frame_set(scene, right_seq, timeline_frame);
break;
case SEQ_SPLIT_HARD:
- seq_split_set_left_hold_offset(right_seq, timeline_frame);
+ seq_split_set_left_hold_offset(scene, right_seq, timeline_frame);
SEQ_add_reload_new_file(bmain, scene, right_seq, false);
break;
}
- SEQ_time_update_sequence(scene, seqbase, right_seq);
}
- if (seq_edit_split_effect_intersect_check(left_seq, timeline_frame)) {
+ if (seq_edit_split_effect_intersect_check(scene, left_seq, timeline_frame)) {
switch (method) {
case SEQ_SPLIT_SOFT:
- seq_split_set_right_offset(left_seq, timeline_frame);
+ SEQ_time_right_handle_frame_set(scene, left_seq, timeline_frame);
break;
case SEQ_SPLIT_HARD:
- seq_split_set_right_hold_offset(left_seq, timeline_frame);
+ seq_split_set_right_hold_offset(scene, left_seq, timeline_frame);
SEQ_add_reload_new_file(bmain, scene, left_seq, false);
break;
}
- SEQ_time_update_sequence(scene, seqbase, left_seq);
}
}
-static bool seq_edit_split_effect_inputs_intersect(const Sequence *seq, const int timeline_frame)
+static bool seq_edit_split_effect_inputs_intersect(const Scene *scene,
+ const Sequence *seq,
+ const int timeline_frame)
{
bool input_does_intersect = false;
if (seq->seq1) {
- input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq1, timeline_frame);
+ input_does_intersect |= seq_edit_split_effect_intersect_check(
+ scene, seq->seq1, timeline_frame);
if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) {
- input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq1, timeline_frame);
+ input_does_intersect |= seq_edit_split_effect_inputs_intersect(
+ scene, seq->seq1, timeline_frame);
}
}
if (seq->seq2) {
- input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq2, timeline_frame);
+ input_does_intersect |= seq_edit_split_effect_intersect_check(
+ scene, seq->seq2, timeline_frame);
if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) {
- input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq2, timeline_frame);
+ input_does_intersect |= seq_edit_split_effect_inputs_intersect(
+ scene, seq->seq2, timeline_frame);
}
}
if (seq->seq3) {
- input_does_intersect |= seq_edit_split_effect_intersect_check(seq->seq3, timeline_frame);
+ input_does_intersect |= seq_edit_split_effect_intersect_check(
+ scene, seq->seq3, timeline_frame);
if ((seq->seq1->type & SEQ_TYPE_EFFECT) != 0) {
- input_does_intersect |= seq_edit_split_effect_inputs_intersect(seq->seq3, timeline_frame);
+ input_does_intersect |= seq_edit_split_effect_inputs_intersect(
+ scene, seq->seq3, timeline_frame);
}
}
return input_does_intersect;
}
-static bool seq_edit_split_operation_permitted_check(SeqCollection *strips,
+static bool seq_edit_split_operation_permitted_check(const Scene *scene,
+ SeqCollection *strips,
const int timeline_frame,
const char **r_error)
{
@@ -412,7 +387,7 @@ static bool seq_edit_split_operation_permitted_check(SeqCollection *strips,
if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
continue;
}
- if (!seq_edit_split_effect_intersect_check(seq, timeline_frame)) {
+ if (!seq_edit_split_effect_intersect_check(scene, seq, timeline_frame)) {
continue;
}
if (SEQ_effect_get_num_inputs(seq->type) <= 1) {
@@ -422,7 +397,7 @@ static bool seq_edit_split_operation_permitted_check(SeqCollection *strips,
*r_error = "Splitting transition effect is not permitted.";
return false;
}
- if (!seq_edit_split_effect_inputs_intersect(seq, timeline_frame)) {
+ if (!seq_edit_split_effect_inputs_intersect(scene, seq, timeline_frame)) {
*r_error = "Effect inputs don't overlap. Can not split such effect.";
return false;
}
@@ -438,16 +413,16 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
const eSeqSplitMethod method,
const char **r_error)
{
- if (!seq_edit_split_effect_intersect_check(seq, timeline_frame)) {
+ if (!seq_edit_split_effect_intersect_check(scene, seq, timeline_frame)) {
return NULL;
}
/* Whole strip chain must be duplicated in order to preserve relationships. */
SeqCollection *collection = SEQ_collection_create(__func__);
SEQ_collection_append_strip(seq, collection);
- SEQ_collection_expand(seqbase, collection, SEQ_query_strip_effect_chain);
+ SEQ_collection_expand(scene, seqbase, collection, SEQ_query_strip_effect_chain);
- if (!seq_edit_split_operation_permitted_check(collection, timeline_frame, r_error)) {
+ if (!seq_edit_split_operation_permitted_check(scene, collection, timeline_frame, r_error)) {
SEQ_collection_free(collection);
return NULL;
}
@@ -468,10 +443,6 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
SEQ_collection_free(collection);
- /* Sort list, so that no strip can depend on next strip in list.
- * This is important for SEQ_time_update_sequence functionality. */
- SEQ_sort(&left_strips);
-
/* Duplicate ListBase. */
ListBase right_strips = {NULL, NULL};
SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0);
@@ -480,18 +451,23 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
Sequence *right_seq = right_strips.first;
Sequence *return_seq = NULL;
- /* 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. */
+ /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal. */
BLI_movelisttolist(seqbase, &left_strips);
BLI_movelisttolist(seqbase, &right_strips);
+ /* Rename duplicated strips. This has to be done immediately after adding
+ * strips to seqbase, for lookup cache to work correctly. */
+ Sequence *seq_rename = right_seq;
+ for (; seq_rename; seq_rename = seq_rename->next) {
+ SEQ_ensure_unique_name(seq_rename, scene);
+ }
+
/* Split strips. */
while (left_seq && right_seq) {
- if (left_seq->startdisp >= timeline_frame) {
+ if (SEQ_time_left_handle_frame_get(scene, left_seq) >= timeline_frame) {
SEQ_edit_flag_for_removal(scene, seqbase, left_seq);
}
- if (right_seq->enddisp <= timeline_frame) {
+ else if (SEQ_time_right_handle_frame_get(scene, right_seq) <= timeline_frame) {
SEQ_edit_flag_for_removal(scene, seqbase, right_seq);
}
else if (return_seq == NULL) {
@@ -499,20 +475,12 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
return_seq = right_seq;
}
- seq_edit_split_handle_strip_offsets(
- bmain, scene, seqbase, left_seq, right_seq, timeline_frame, method);
+ seq_edit_split_handle_strip_offsets(bmain, scene, left_seq, right_seq, timeline_frame, method);
left_seq = left_seq->next;
right_seq = right_seq->next;
}
SEQ_edit_remove_flagged_sequences(scene, seqbase);
-
- /* Rename duplicated strips. */
- Sequence *seq_rename = return_seq;
- for (; seq_rename; seq_rename = seq_rename->next) {
- SEQ_ensure_unique_name(seq_rename, scene);
- }
-
SEQ_animation_restore_original(scene, &fcurves_original_backup);
return return_seq;
diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c
index 1899cc99263..f89974b8fef 100644
--- a/source/blender/sequencer/intern/strip_relations.c
+++ b/source/blender/sequencer/intern/strip_relations.c
@@ -29,6 +29,7 @@
#include "SEQ_relations.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
+#include "SEQ_transform.h"
#include "effects.h"
#include "image_cache.h"
@@ -40,14 +41,15 @@ bool SEQ_relation_is_effect_of_strip(const Sequence *effect, const Sequence *inp
}
/* check whether sequence cur depends on seq */
-static bool seq_relations_check_depend(Sequence *seq, Sequence *cur)
+static bool seq_relations_check_depend(const Scene *scene, Sequence *seq, Sequence *cur)
{
if (SEQ_relation_is_effect_of_strip(cur, seq)) {
return true;
}
/* sequences are not intersecting in time, assume no dependency exists between them */
- if (cur->enddisp < seq->startdisp || cur->startdisp > seq->enddisp) {
+ if (SEQ_time_right_handle_frame_get(scene, cur) < SEQ_time_left_handle_frame_get(scene, seq) ||
+ SEQ_time_left_handle_frame_get(scene, cur) > SEQ_time_right_handle_frame_get(scene, seq)) {
return false;
}
@@ -77,7 +79,7 @@ static void sequence_do_invalidate_dependent(Scene *scene, Sequence *seq, ListBa
continue;
}
- if (seq_relations_check_depend(seq, cur)) {
+ if (seq_relations_check_depend(scene, seq, cur)) {
/* Effect must be invalidated completely if they depend on invalidated seq. */
if ((cur->type & SEQ_TYPE_EFFECT) != 0) {
seq_cache_cleanup_sequence(scene, cur, seq, SEQ_CACHE_ALL_TYPES, false);
@@ -248,7 +250,7 @@ void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
SEQ_prefetch_stop(scene);
for (seq = seqbase->first; seq; seq = seq->next) {
- if (for_render && SEQ_time_strip_intersects_frame(seq, CFRA)) {
+ if (for_render && SEQ_time_strip_intersects_frame(scene, seq, scene->r.cfra)) {
continue;
}
@@ -270,13 +272,14 @@ void SEQ_relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
}
}
-static void sequencer_all_free_anim_ibufs(Editing *ed,
+static void sequencer_all_free_anim_ibufs(const Scene *scene,
ListBase *seqbase,
int timeline_frame,
const int frame_range[2])
{
+ Editing *ed = SEQ_editing_get(scene);
for (Sequence *seq = seqbase->first; seq != NULL; seq = seq->next) {
- if (!SEQ_time_strip_intersects_frame(seq, timeline_frame) ||
+ if (!SEQ_time_strip_intersects_frame(scene, seq, timeline_frame) ||
!((frame_range[0] <= timeline_frame) && (frame_range[1] > timeline_frame))) {
SEQ_relations_sequence_free_anim(seq);
}
@@ -290,11 +293,11 @@ static void sequencer_all_free_anim_ibufs(Editing *ed,
}
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);
+ meta_range[0] = max_ii(frame_range[0], SEQ_time_left_handle_frame_get(scene, seq));
+ meta_range[1] = min_ii(frame_range[1], SEQ_time_right_handle_frame_get(scene, seq));
}
- sequencer_all_free_anim_ibufs(ed, &seq->seqbase, timeline_frame, meta_range);
+ sequencer_all_free_anim_ibufs(scene, &seq->seqbase, timeline_frame, meta_range);
}
}
}
@@ -307,7 +310,7 @@ void SEQ_relations_free_all_anim_ibufs(Scene *scene, int timeline_frame)
}
const int frame_range[2] = {-MAXFRAME, MAXFRAME};
- sequencer_all_free_anim_ibufs(ed, &ed->seqbase, timeline_frame, frame_range);
+ sequencer_all_free_anim_ibufs(scene, &ed->seqbase, timeline_frame, frame_range);
}
static Sequence *sequencer_check_scene_recursion(Scene *scene, ListBase *seqbase)
@@ -345,7 +348,7 @@ bool SEQ_relations_check_scene_recursion(Scene *scene, ReportList *reports)
RPT_WARNING,
"Recursion detected in video sequencer. Strip %s at frame %d will not be rendered",
recursive_seq->name + 2,
- recursive_seq->startdisp);
+ SEQ_time_left_handle_frame_get(scene, recursive_seq));
LISTBASE_FOREACH (Sequence *, seq, &ed->seqbase) {
if (seq->type != SEQ_TYPE_SCENE && sequencer_seq_generates_image(seq)) {
@@ -456,3 +459,16 @@ struct Sequence *SEQ_find_metastrip_by_sequence(ListBase *seqbase, Sequence *met
return NULL;
}
+
+bool SEQ_exists_in_seqbase(const Sequence *seq, const ListBase *seqbase)
+{
+ LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
+ if (seq_test->type == SEQ_TYPE_META && SEQ_exists_in_seqbase(seq, &seq_test->seqbase)) {
+ return true;
+ }
+ if (seq_test == seq) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index e4f7a5e87e8..5d8266dbc6e 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -27,17 +27,36 @@
#include "SEQ_time.h"
#include "SEQ_transform.h"
+#include "sequencer.h"
#include "strip_time.h"
#include "utils.h"
-float seq_give_frame_index(Sequence *seq, float timeline_frame)
+static float seq_time_media_playback_rate_factor_get(const Scene *scene, const Sequence *seq)
+{
+ if ((seq->flag & SEQ_AUTO_PLAYBACK_RATE) == 0) {
+ return 1.0f;
+ }
+ if (seq->media_playback_rate == 0.0f) {
+ return 1.0f;
+ }
+
+ float scene_playback_rate = (float)scene->r.frs_sec / scene->r.frs_sec_base;
+ return seq->media_playback_rate / scene_playback_rate;
+}
+
+static float seq_time_playback_rate_factor_get(const Scene *scene, const Sequence *seq)
+{
+ return seq_time_media_playback_rate_factor_get(scene, seq) * seq->speed_factor;
+}
+
+float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_frame)
{
float frame_index;
- int sta = seq->start;
- int end = seq->start + seq->len - 1;
+ float sta = SEQ_time_start_frame_get(seq);
+ float end = SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq) - 1;
if (seq->type & SEQ_TYPE_EFFECT) {
- end = seq->enddisp;
+ end = SEQ_time_right_handle_frame_get(scene, seq);
}
if (end < sta) {
@@ -45,29 +64,16 @@ float seq_give_frame_index(Sequence *seq, float timeline_frame)
}
if (seq->flag & SEQ_REVERSE_FRAMES) {
- /* Reverse frame in this sequence. */
- if (timeline_frame <= sta) {
- frame_index = end - sta;
- }
- else if (timeline_frame >= end) {
- frame_index = 0;
- }
- else {
- frame_index = end - timeline_frame;
- }
+ frame_index = end - timeline_frame;
}
else {
- if (timeline_frame <= sta) {
- frame_index = 0;
- }
- else if (timeline_frame >= end) {
- frame_index = end - sta;
- }
- else {
- frame_index = timeline_frame - sta;
- }
+ frame_index = timeline_frame - sta;
}
+ /* Clamp frame index to strip frame range. */
+ frame_index = clamp_f(frame_index, 0, end - sta);
+ frame_index *= seq_time_playback_rate_factor_get(scene, seq);
+
if (seq->strobe < 1.0f) {
seq->strobe = 1.0f;
}
@@ -89,7 +95,7 @@ static int metaseq_end(Sequence *metaseq)
return metaseq->start + metaseq->len - metaseq->endofs;
}
-static void seq_update_sound_bounds_recursive_impl(Scene *scene,
+static void seq_update_sound_bounds_recursive_impl(const Scene *scene,
Sequence *metaseq,
int start,
int end)
@@ -131,33 +137,31 @@ static void seq_update_sound_bounds_recursive_impl(Scene *scene,
}
}
-void seq_update_sound_bounds_recursive(Scene *scene, Sequence *metaseq)
+void seq_update_sound_bounds_recursive(const Scene *scene, Sequence *metaseq)
{
seq_update_sound_bounds_recursive_impl(
scene, metaseq, metaseq_start(metaseq), metaseq_end(metaseq));
}
-static void seq_time_update_sequence_bounds(Scene *scene, Sequence *seq)
+/* Update meta strip content start and end, update sound playback range. */
+void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta)
{
- seq->startdisp = seq->start + seq->startofs;
- seq->enddisp = seq->start + seq->len - seq->endofs;
-
- if (seq->type == SEQ_TYPE_META) {
- seq_update_sound_bounds_recursive(scene, seq);
+ if (seq_meta == NULL) {
+ return;
}
-}
-static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
-{
if (BLI_listbase_is_empty(&seq_meta->seqbase)) {
return;
}
+ const int strip_start = SEQ_time_left_handle_frame_get(scene, seq_meta);
+ const int strip_end = SEQ_time_right_handle_frame_get(scene, seq_meta);
+
int min = MAXFRAME * 2;
int max = -MAXFRAME * 2;
LISTBASE_FOREACH (Sequence *, seq, &seq_meta->seqbase) {
- min = min_ii(seq->startdisp, min);
- max = max_ii(seq->enddisp, max);
+ min = min_ii(SEQ_time_left_handle_frame_get(scene, seq), min);
+ max = max_ii(SEQ_time_right_handle_frame_get(scene, seq), max);
}
seq_meta->start = min + seq_meta->anim_startofs;
@@ -166,144 +170,60 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
seq_meta->len -= seq_meta->anim_endofs;
seq_update_sound_bounds_recursive(scene, 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. */
- SEQ_time_left_handle_frame_set(seq_meta, seq_meta->startdisp);
- SEQ_time_right_handle_frame_set(seq_meta, seq_meta->enddisp);
+ SEQ_time_left_handle_frame_set(scene, seq_meta, strip_start);
+ SEQ_time_right_handle_frame_set(scene, seq_meta, strip_end);
}
-void SEQ_time_update_sequence(Scene *scene, ListBase *seqbase, Sequence *seq)
+void seq_time_effect_range_set(const Scene *scene, Sequence *seq)
{
- Sequence *seqm;
-
- /* Check all meta-strips recursively. */
- seqm = seq->seqbase.first;
- while (seqm) {
- if (seqm->seqbase.first) {
- SEQ_time_update_sequence(scene, &seqm->seqbase, seqm);
- }
- seqm = seqm->next;
+ if (seq->seq1 == NULL && seq->seq2 == NULL) {
+ return;
}
- /* effects and meta: automatic start and end */
- if (seq->type & SEQ_TYPE_EFFECT) {
- if (seq->seq1) {
- seq->startofs = seq->endofs = 0;
- if (seq->seq3) {
- seq->start = seq->startdisp = max_iii(
- seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
- seq->enddisp = min_iii(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
- }
- else if (seq->seq2) {
- seq->start = seq->startdisp = max_ii(seq->seq1->startdisp, seq->seq2->startdisp);
- seq->enddisp = min_ii(seq->seq1->enddisp, seq->seq2->enddisp);
- }
- else {
- seq->start = seq->startdisp = seq->seq1->startdisp;
- seq->enddisp = seq->seq1->enddisp;
- }
- /* we can't help if strips don't overlap, it won't give useful results.
- * but at least ensure 'len' is never negative which causes bad bugs elsewhere. */
- if (seq->enddisp < seq->startdisp) {
- /* simple start/end swap */
- seq->start = seq->enddisp;
- seq->enddisp = seq->startdisp;
- seq->startdisp = seq->start;
- seq->flag |= SEQ_INVALID_EFFECT;
- }
- else {
- seq->flag &= ~SEQ_INVALID_EFFECT;
- }
-
- seq->len = seq->enddisp - seq->startdisp;
- }
- else {
- seq_time_update_sequence_bounds(scene, seq);
- }
+ if (seq->seq1 && seq->seq2) { /* 2 - input effect. */
+ seq->startdisp = max_ii(SEQ_time_left_handle_frame_get(scene, seq->seq1),
+ SEQ_time_left_handle_frame_get(scene, seq->seq2));
+ seq->enddisp = min_ii(SEQ_time_right_handle_frame_get(scene, seq->seq1),
+ SEQ_time_right_handle_frame_get(scene, seq->seq2));
}
- else if (seq->type == SEQ_TYPE_META) {
- seq_time_update_meta_strip(scene, seq);
+ else if (seq->seq1) { /* Single input effect. */
+ seq->startdisp = SEQ_time_right_handle_frame_get(scene, seq->seq1);
+ seq->enddisp = SEQ_time_left_handle_frame_get(scene, seq->seq1);
}
- else {
- seq_time_update_sequence_bounds(scene, seq);
+ else if (seq->seq2) { /* Strip may be missing one of inputs. */
+ seq->startdisp = SEQ_time_right_handle_frame_get(scene, seq->seq2);
+ seq->enddisp = SEQ_time_left_handle_frame_get(scene, seq->seq2);
}
- 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);
+ if (seq->startdisp > seq->enddisp) {
+ SWAP(int, seq->startdisp, seq->enddisp);
}
- seq_time_update_sequence_bounds(scene, seq);
+ /* Values unusable for effects, these should be always 0. */
+ seq->startofs = seq->endofs = seq->anim_startofs = seq->anim_endofs = 0;
+ seq->start = seq->startdisp;
+ seq->len = seq->enddisp - seq->startdisp;
}
-static bool update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *changed_seq)
+/* Update strip startdisp and enddisp (n-input effects have no len to calculate these). */
+void seq_time_update_effects_strip_range(const Scene *scene, SeqCollection *effects)
{
- 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;
- }
- }
-
- 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);
+ if (effects == NULL) {
+ return;
}
- 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;
+ /* First pass: Update length of immediate effects. */
+ SEQ_ITERATOR_FOREACH (seq, effects) {
+ seq_time_effect_range_set(scene, seq);
}
- for (seq = ed->seqbase.first; seq; seq = seq->next) {
- update_changed_seq_recurs(scene, seq, changed_seq);
+ /* Second pass: Recursive call to update effects in chain and in order, so they inherit length
+ * correctly. */
+ SEQ_ITERATOR_FOREACH (seq, effects) {
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}
}
@@ -342,12 +262,14 @@ int SEQ_time_find_next_prev_edit(Scene *scene,
}
if (do_center) {
- seq_frames[0] = (seq->startdisp + seq->enddisp) / 2;
+ seq_frames[0] = (SEQ_time_left_handle_frame_get(scene, seq) +
+ SEQ_time_right_handle_frame_get(scene, seq)) /
+ 2;
seq_frames_tot = 1;
}
else {
- seq_frames[0] = seq->startdisp;
- seq_frames[1] = seq->enddisp;
+ seq_frames[0] = SEQ_time_left_handle_frame_get(scene, seq);
+ seq_frames[1] = SEQ_time_right_handle_frame_get(scene, seq);
seq_frames_tot = 2;
}
@@ -424,18 +346,18 @@ void SEQ_timeline_init_boundbox(const Scene *scene, rctf *rect)
rect->ymax = 8.0f;
}
-void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
+void SEQ_timeline_expand_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
{
if (seqbase == NULL) {
return;
}
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (rect->xmin > seq->startdisp - 1) {
- rect->xmin = seq->startdisp - 1;
+ if (rect->xmin > SEQ_time_left_handle_frame_get(scene, seq) - 1) {
+ rect->xmin = SEQ_time_left_handle_frame_get(scene, seq) - 1;
}
- if (rect->xmax < seq->enddisp + 1) {
- rect->xmax = seq->enddisp + 1;
+ if (rect->xmax < SEQ_time_right_handle_frame_get(scene, seq) + 1) {
+ rect->xmax = SEQ_time_right_handle_frame_get(scene, seq) + 1;
}
if (rect->ymax < seq->machine) {
rect->ymax = seq->machine;
@@ -446,14 +368,16 @@ void SEQ_timeline_expand_boundbox(const ListBase *seqbase, rctf *rect)
void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect)
{
SEQ_timeline_init_boundbox(scene, rect);
- SEQ_timeline_expand_boundbox(seqbase, rect);
+ SEQ_timeline_expand_boundbox(scene, seqbase, rect);
}
-static bool strip_exists_at_frame(SeqCollection *all_strips, const int timeline_frame)
+static bool strip_exists_at_frame(const Scene *scene,
+ SeqCollection *all_strips,
+ const int timeline_frame)
{
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, all_strips) {
- if (SEQ_time_strip_intersects_frame(seq, timeline_frame)) {
+ if (SEQ_time_strip_intersects_frame(scene, seq, timeline_frame)) {
return true;
}
}
@@ -475,10 +399,10 @@ void seq_time_gap_info_get(const Scene *scene,
SeqCollection *collection = SEQ_query_all_strips(seqbase);
- if (!strip_exists_at_frame(collection, initial_frame)) {
+ if (!strip_exists_at_frame(scene, collection, initial_frame)) {
/* Search backward for gap_start_frame. */
for (; timeline_frame >= sfra; timeline_frame--) {
- if (strip_exists_at_frame(collection, timeline_frame)) {
+ if (strip_exists_at_frame(scene, collection, timeline_frame)) {
break;
}
}
@@ -488,7 +412,7 @@ void seq_time_gap_info_get(const Scene *scene,
else {
/* Search forward for gap_start_frame. */
for (; timeline_frame <= efra; timeline_frame++) {
- if (!strip_exists_at_frame(collection, timeline_frame)) {
+ if (!strip_exists_at_frame(scene, collection, timeline_frame)) {
r_gap_info->gap_start_frame = timeline_frame;
break;
}
@@ -496,7 +420,7 @@ void seq_time_gap_info_get(const Scene *scene,
}
/* Search forward for gap_end_frame. */
for (; timeline_frame <= efra; timeline_frame++) {
- if (strip_exists_at_frame(collection, timeline_frame)) {
+ if (strip_exists_at_frame(scene, collection, timeline_frame)) {
const int gap_end_frame = timeline_frame;
r_gap_info->gap_length = gap_end_frame - r_gap_info->gap_start_frame;
r_gap_info->gap_exists = true;
@@ -505,41 +429,120 @@ void seq_time_gap_info_get(const Scene *scene,
}
}
-bool SEQ_time_strip_intersects_frame(const Sequence *seq, const int timeline_frame)
+bool SEQ_time_strip_intersects_frame(const Scene *scene,
+ const Sequence *seq,
+ const int timeline_frame)
+{
+ return (SEQ_time_left_handle_frame_get(scene, seq) <= timeline_frame) &&
+ (SEQ_time_right_handle_frame_get(scene, seq) > timeline_frame);
+}
+
+void SEQ_time_speed_factor_set(const Scene *scene, Sequence *seq, const float speed_factor)
+{
+
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ seq->speed_factor = speed_factor;
+ }
+ else {
+ const float left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
+ const float unity_start_offset = seq->startofs * seq->speed_factor;
+ const float unity_end_offset = seq->endofs * seq->speed_factor;
+ /* Left handle is pivot point for content scaling - it must always show same frame. */
+ seq->speed_factor = speed_factor;
+ seq->startofs = unity_start_offset / speed_factor;
+ seq->start = left_handle_frame - seq->startofs;
+ seq->endofs = unity_end_offset / speed_factor;
+ }
+
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
+}
+
+bool SEQ_time_has_left_still_frames(const Scene *scene, const Sequence *seq)
{
- return (seq->startdisp <= timeline_frame) && (seq->enddisp > timeline_frame);
+ return SEQ_time_left_handle_frame_get(scene, seq) < SEQ_time_start_frame_get(seq);
}
-bool SEQ_time_has_left_still_frames(const Sequence *seq)
+bool SEQ_time_has_right_still_frames(const Scene *scene, const Sequence *seq)
{
- return seq->startofs < 0;
+ return SEQ_time_right_handle_frame_get(scene, seq) >
+ SEQ_time_start_frame_get(seq) + SEQ_time_strip_length_get(scene, seq);
}
-bool SEQ_time_has_right_still_frames(const Sequence *seq)
+bool SEQ_time_has_still_frames(const Scene *scene, const Sequence *seq)
{
- return seq->endofs < 0;
+ return SEQ_time_has_right_still_frames(scene, seq) || SEQ_time_has_left_still_frames(scene, seq);
}
-bool SEQ_time_has_still_frames(const Sequence *seq)
+/* Length of strip content in frames. This is number of original frames adjusted by playback rate
+ * factor */
+int SEQ_time_strip_length_get(const Scene *scene, const Sequence *seq)
{
- return SEQ_time_has_right_still_frames(seq) || SEQ_time_has_left_still_frames(seq);
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ return seq->len;
+ }
+
+ return seq->len / seq_time_playback_rate_factor_get(scene, seq);
}
-int SEQ_time_left_handle_frame_get(Sequence *seq)
+/* Return timeline frame, where strip content starts. */
+float SEQ_time_start_frame_get(const Sequence *seq)
{
+ return seq->start;
+}
+
+void SEQ_time_start_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
+{
+ seq->start = timeline_frame;
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
+}
+
+int SEQ_time_left_handle_frame_get(const Scene *UNUSED(scene), const Sequence *seq)
+{
+ if (seq->seq1 || seq->seq2) {
+ return seq->startdisp;
+ }
+
return seq->start + seq->startofs;
}
-int SEQ_time_right_handle_frame_get(Sequence *seq)
+
+int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
{
- return seq->start + seq->len - seq->endofs;
+ if (seq->seq1 || seq->seq2) {
+ return seq->enddisp;
+ }
+
+ return seq->start + SEQ_time_strip_length_get(scene, seq) - seq->endofs;
}
-void SEQ_time_left_handle_frame_set(Sequence *seq, int val)
+void SEQ_time_left_handle_frame_set(const Scene *scene, Sequence *seq, int val)
{
+ const float right_handle_orig_frame = SEQ_time_right_handle_frame_get(scene, seq);
+
+ if (val >= right_handle_orig_frame) {
+ val = right_handle_orig_frame - 1;
+ }
+
seq->startofs = val - seq->start;
+ seq->startdisp = val; /* Only to make files usable in older versions. */
+
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}
-void SEQ_time_right_handle_frame_set(Sequence *seq, int val)
+void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int val)
{
- seq->endofs = seq->start + seq->len - val;
+ const float strip_content_end_frame = seq->start + SEQ_time_strip_length_get(scene, seq);
+ const float left_handle_orig_frame = SEQ_time_left_handle_frame_get(scene, seq);
+
+ if (val <= left_handle_orig_frame) {
+ val = left_handle_orig_frame + 1;
+ }
+
+ seq->endofs = strip_content_end_frame - val;
+ seq->enddisp = val; /* Only to make files usable in older versions. */
+
+ SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
+ seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}
diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h
index c96a016e646..db581649f8a 100644
--- a/source/blender/sequencer/intern/strip_time.h
+++ b/source/blender/sequencer/intern/strip_time.h
@@ -14,9 +14,10 @@ extern "C" {
struct ListBase;
struct Scene;
struct Sequence;
+struct SeqCollection;
-float seq_give_frame_index(struct Sequence *seq, float timeline_frame);
-void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq);
+float seq_give_frame_index(const struct Scene *scene, struct Sequence *seq, float timeline_frame);
+void seq_update_sound_bounds_recursive(const struct Scene *scene, struct Sequence *metaseq);
/* Describes gap between strips in timeline. */
typedef struct GapInfo {
@@ -37,6 +38,8 @@ void seq_time_gap_info_get(const struct Scene *scene,
struct ListBase *seqbase,
int initial_frame,
struct GapInfo *r_gap_info);
+void seq_time_effect_range_set(const struct Scene *scene, Sequence *seq);
+void seq_time_update_effects_strip_range(const struct Scene *scene, struct SeqCollection *effects);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 8ff577240d6..68b30c9ce19 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -13,11 +13,13 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BKE_main.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "SEQ_animation.h"
#include "SEQ_channels.h"
+#include "SEQ_edit.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
@@ -25,19 +27,13 @@
#include "SEQ_time.h"
#include "SEQ_transform.h"
+#include "sequencer.h"
+#include "strip_time.h"
+
#include "CLG_log.h"
static CLG_LogRef LOG = {"seq.strip_transform"};
-static int seq_tx_get_start(Sequence *seq)
-{
- return seq->start;
-}
-static int seq_tx_get_end(Sequence *seq)
-{
- return seq->start + seq->len;
-}
-
bool SEQ_transform_single_image_check(Sequence *seq)
{
return ((seq->len == 1) &&
@@ -86,50 +82,7 @@ bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
return true;
}
-void SEQ_transform_handle_xlimits(Sequence *seq, int leftflag, int rightflag)
-{
- if (leftflag) {
- if (SEQ_time_left_handle_frame_get(seq) >= SEQ_time_right_handle_frame_get(seq)) {
- SEQ_time_left_handle_frame_set(seq, SEQ_time_right_handle_frame_get(seq) - 1);
- }
-
- if (SEQ_transform_single_image_check(seq) == 0) {
- if (SEQ_time_left_handle_frame_get(seq) >= seq_tx_get_end(seq)) {
- SEQ_time_left_handle_frame_set(seq, seq_tx_get_end(seq) - 1);
- }
-
- /* TODO: This doesn't work at the moment. */
-#if 0
- if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) {
- int ofs;
- ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0);
- seq->start -= ofs;
- seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs);
- }
-#endif
- }
- }
-
- if (rightflag) {
- if (SEQ_time_right_handle_frame_get(seq) <= SEQ_time_left_handle_frame_get(seq)) {
- SEQ_time_right_handle_frame_set(seq, SEQ_time_left_handle_frame_get(seq) + 1);
- }
-
- if (SEQ_transform_single_image_check(seq) == 0) {
- if (SEQ_time_right_handle_frame_get(seq) <= seq_tx_get_start(seq)) {
- SEQ_time_right_handle_frame_set(seq, seq_tx_get_start(seq) + 1);
- }
- }
- }
-
- /* sounds cannot be extended past their endpoints */
- if (seq->type == SEQ_TYPE_SOUND_RAM) {
- CLAMP(seq->startofs, 0, MAXFRAME);
- CLAMP(seq->endofs, 0, MAXFRAME);
- }
-}
-
-void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq)
+void SEQ_transform_fix_single_image_seq_offsets(const Scene *scene, Sequence *seq)
{
int left, start, offset;
if (!SEQ_transform_single_image_check(seq)) {
@@ -138,12 +91,14 @@ void SEQ_transform_fix_single_image_seq_offsets(Sequence *seq)
/* make sure the image is always at the start since there is only one,
* adjusting its start should be ok */
- left = SEQ_time_left_handle_frame_get(seq);
+ left = SEQ_time_left_handle_frame_get(scene, seq);
start = seq->start;
if (start != left) {
offset = left - start;
- SEQ_time_left_handle_frame_set(seq, SEQ_time_left_handle_frame_get(seq) - offset);
- SEQ_time_right_handle_frame_set(seq, SEQ_time_right_handle_frame_get(seq) - offset);
+ SEQ_time_left_handle_frame_set(
+ scene, seq, SEQ_time_left_handle_frame_get(scene, seq) - offset);
+ SEQ_time_right_handle_frame_set(
+ scene, seq, SEQ_time_right_handle_frame_get(scene, seq) - offset);
seq->start += offset;
}
}
@@ -153,19 +108,22 @@ bool SEQ_transform_sequence_can_be_translated(Sequence *seq)
return !(seq->type & SEQ_TYPE_EFFECT) || (SEQ_effect_get_num_inputs(seq->type) == 0);
}
-bool SEQ_transform_test_overlap_seq_seq(Sequence *seq1, Sequence *seq2)
+bool SEQ_transform_test_overlap_seq_seq(const Scene *scene, Sequence *seq1, Sequence *seq2)
{
return (seq1 != seq2 && seq1->machine == seq2->machine &&
- ((seq1->enddisp <= seq2->startdisp) || (seq1->startdisp >= seq2->enddisp)) == 0);
+ ((SEQ_time_right_handle_frame_get(scene, seq1) <=
+ SEQ_time_left_handle_frame_get(scene, seq2)) ||
+ (SEQ_time_left_handle_frame_get(scene, seq1) >=
+ SEQ_time_right_handle_frame_get(scene, seq2))) == 0);
}
-bool SEQ_transform_test_overlap(ListBase *seqbasep, Sequence *test)
+bool SEQ_transform_test_overlap(const Scene *scene, ListBase *seqbasep, Sequence *test)
{
Sequence *seq;
seq = seqbasep->first;
while (seq) {
- if (SEQ_transform_test_overlap_seq_seq(test, seq)) {
+ if (SEQ_transform_test_overlap_seq_seq(scene, test, seq)) {
return true;
}
@@ -180,9 +138,6 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
return;
}
- SEQ_offset_animdata(evil_scene, seq, delta);
- seq->start += delta;
-
/* Meta strips requires special handling: their content is to be translated, and then frame range
* of the meta is to be updated for the updated content. */
if (seq->type == SEQ_TYPE_META) {
@@ -190,16 +145,23 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
for (seq_child = seq->seqbase.first; seq_child; seq_child = seq_child->next) {
SEQ_transform_translate_sequence(evil_scene, seq_child, delta);
}
- /* Ensure that meta bounds are updated, but this function prevents resets seq->start and
- * start/end point in timeline. */
- SEQ_time_update_meta_strip_range(evil_scene, seq);
/* Move meta start/end points. */
- SEQ_time_left_handle_frame_set(seq, seq->startdisp + delta);
- SEQ_time_right_handle_frame_set(seq, seq->enddisp + delta);
+ SEQ_time_left_handle_frame_set(
+ evil_scene, seq, SEQ_time_left_handle_frame_get(evil_scene, seq) + delta);
+ SEQ_time_right_handle_frame_set(
+ evil_scene, seq, SEQ_time_right_handle_frame_get(evil_scene, seq) + delta);
+ }
+ else { /* All other strip types. */
+ seq->start += delta;
+ /* Only to make files usable in older versions. */
+ seq->startdisp = SEQ_time_left_handle_frame_get(evil_scene, seq);
+ seq->enddisp = SEQ_time_right_handle_frame_get(evil_scene, seq);
}
- ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(evil_scene));
- SEQ_time_update_sequence(evil_scene, seqbase, seq);
+ SEQ_offset_animdata(evil_scene, seq, delta);
+ SEQ_time_update_meta_strip_range(evil_scene, seq_sequence_lookup_meta_by_seq(evil_scene, seq));
+ seq_time_update_effects_strip_range(evil_scene,
+ seq_sequence_lookup_effects_by_seq(evil_scene, seq));
}
bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
@@ -211,16 +173,12 @@ 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, seqbasep, test);
- while (SEQ_transform_test_overlap(seqbasep, test)) {
+ while (SEQ_transform_test_overlap(evil_scene, seqbasep, test)) {
if ((channel_delta > 0) ? (test->machine >= MAXSEQ) : (test->machine < 1)) {
break;
}
test->machine += channel_delta;
-
- /* XXX: I don't think this is needed since were only moving vertically, Campbell. */
- SEQ_time_update_sequence(evil_scene, seqbasep, test);
}
if (!SEQ_valid_strip_channel(test)) {
@@ -228,19 +186,18 @@ bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,
* nicer to move it to the end */
Sequence *seq;
- int new_frame = test->enddisp;
+ int new_frame = SEQ_time_right_handle_frame_get(evil_scene, test);
for (seq = seqbasep->first; seq; seq = seq->next) {
if (seq->machine == orig_machine) {
- new_frame = max_ii(new_frame, seq->enddisp);
+ new_frame = max_ii(new_frame, SEQ_time_right_handle_frame_get(evil_scene, seq));
}
}
test->machine = orig_machine;
- new_frame = new_frame + (test->start - test->startdisp); /* adjust by the startdisp */
+ new_frame = new_frame + (test->start - SEQ_time_left_handle_frame_get(
+ evil_scene, test)); /* adjust by the startdisp */
SEQ_transform_translate_sequence(evil_scene, test, new_frame - test->start);
-
- SEQ_time_update_sequence(evil_scene, seqbasep, test);
return false;
}
@@ -252,71 +209,72 @@ bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *ev
return SEQ_transform_seqbase_shuffle_ex(seqbasep, test, evil_scene, 1);
}
-static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle,
- ListBase *seqbasep,
- char dir)
+static bool shuffle_seq_test_overlap(const Scene *scene,
+ const Sequence *seq1,
+ const Sequence *seq2,
+ const int offset)
{
- int offset = 0;
- Sequence *seq;
-
- SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
- LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) {
- if (!SEQ_transform_test_overlap_seq_seq(seq, seq_other)) {
- continue;
- }
- if (SEQ_relation_is_effect_of_strip(seq_other, seq)) {
- continue;
- }
- if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) {
- CLOG_WARN(&LOG,
- "Strip overlaps with itself or another strip, that is to be shuffled. "
- "This should never happen.");
- continue;
- }
- if (dir == 'L') {
- offset = min_ii(offset, seq_other->startdisp - seq->enddisp);
- }
- else {
- offset = max_ii(offset, seq_other->enddisp - seq->startdisp);
- }
- }
- }
- return offset;
+ return (seq1 != seq2 && seq1->machine == seq2->machine &&
+ ((SEQ_time_right_handle_frame_get(scene, seq1) + offset <=
+ SEQ_time_left_handle_frame_get(scene, seq2)) ||
+ (SEQ_time_left_handle_frame_get(scene, seq1) + offset >=
+ SEQ_time_right_handle_frame_get(scene, seq2))) == 0);
}
-static int shuffle_seq_time_offset(SeqCollection *strips_to_shuffle,
- ListBase *seqbasep,
- Scene *scene,
- char dir)
+static int shuffle_seq_time_offset_get(const Scene *scene,
+ SeqCollection *strips_to_shuffle,
+ ListBase *seqbasep,
+ char dir)
{
- int ofs = 0;
- int tot_ofs = 0;
+ int offset = 0;
Sequence *seq;
- while ((ofs = shuffle_seq_time_offset_test(strips_to_shuffle, seqbasep, dir))) {
+ bool all_conflicts_resolved = false;
+
+ while (!all_conflicts_resolved) {
+ all_conflicts_resolved = true;
SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
- /* seq_test_overlap only tests display values */
- seq->startdisp += ofs;
- seq->enddisp += ofs;
- }
+ LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) {
+ if (!shuffle_seq_test_overlap(scene, seq, seq_other, offset)) {
+ continue;
+ }
+ if (SEQ_relation_is_effect_of_strip(seq_other, seq)) {
+ continue;
+ }
+ if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) {
+ CLOG_WARN(&LOG,
+ "Strip overlaps with itself or another strip, that is to be shuffled. "
+ "This should never happen.");
+ continue;
+ }
- tot_ofs += ofs;
- }
+ all_conflicts_resolved = false;
- SEQ_ITERATOR_FOREACH (seq, strips_to_shuffle) {
- SEQ_time_update_sequence(scene, seqbasep, seq); /* corrects dummy startdisp/enddisp values */
+ if (dir == 'L') {
+ offset = min_ii(offset,
+ SEQ_time_left_handle_frame_get(scene, seq_other) -
+ SEQ_time_right_handle_frame_get(scene, seq));
+ }
+ else {
+ offset = max_ii(offset,
+ SEQ_time_right_handle_frame_get(scene, seq_other) -
+ SEQ_time_left_handle_frame_get(scene, seq));
+ }
+ }
+ }
}
- return tot_ofs;
+ return offset;
}
bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
+ SeqCollection *time_dependent_strips,
ListBase *seqbasep,
Scene *evil_scene,
ListBase *markers,
const bool use_sync_markers)
{
- int offset_l = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'L');
- int offset_r = shuffle_seq_time_offset(strips_to_shuffle, seqbasep, evil_scene, 'R');
+ int offset_l = shuffle_seq_time_offset_get(evil_scene, strips_to_shuffle, seqbasep, 'L');
+ int offset_r = shuffle_seq_time_offset_get(evil_scene, strips_to_shuffle, seqbasep, 'R');
int offset = (-offset_l < offset_r) ? offset_l : offset_r;
if (offset) {
@@ -326,6 +284,12 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
seq->flag &= ~SEQ_OVERLAP;
}
+ if (time_dependent_strips != NULL) {
+ SEQ_ITERATOR_FOREACH (seq, time_dependent_strips) {
+ SEQ_offset_animdata(evil_scene, seq, offset);
+ }
+ }
+
if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != NULL)) {
TimeMarker *marker;
/* affect selected markers - it's unlikely that we will want to affect all in this way? */
@@ -340,15 +304,318 @@ bool SEQ_transform_seqbase_shuffle_time(SeqCollection *strips_to_shuffle,
return offset ? false : true;
}
+static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == NULL) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* Query strips positioned after left edge of transformed strips bound-box. */
+static SeqCollection *query_right_side_strips(const Scene *scene,
+ ListBase *seqbase,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips)
+{
+ int minframe = MAXFRAME;
+ {
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(scene, seq));
+ }
+ }
+
+ SeqCollection *collection = SEQ_collection_create(__func__);
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (SEQ_collection_has_strip(seq, time_dependent_strips)) {
+ continue;
+ }
+ if (SEQ_collection_has_strip(seq, transformed_strips)) {
+ continue;
+ }
+
+ if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(scene, seq) >= minframe) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+/* 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(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ SeqCollection *right_side_strips = query_right_side_strips(
+ scene, seqbasep, transformed_strips, time_dependent_strips);
+
+ /* Temporarily move right side strips beyond timeline boundary. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine += MAXSEQ * 2;
+ }
+
+ /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
+ * strips on left side. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+
+ /* Move temporarily moved strips back to their original place and tag for shuffling. */
+ SEQ_ITERATOR_FOREACH (seq, right_side_strips) {
+ seq->machine -= MAXSEQ * 2;
+ }
+ /* Shuffle again to displace strips on right side. Final effect shuffling is done in
+ * SEQ_transform_handle_overlap. */
+ SEQ_transform_seqbase_shuffle_time(
+ right_side_strips, NULL, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(right_side_strips);
+}
+
+static SeqCollection *query_overwrite_targets(const Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *collection = SEQ_query_unselected_strips(seqbasep);
+
+ Sequence *seq, *seq_transformed;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ bool does_overlap = false;
+
+ SEQ_ITERATOR_FOREACH (seq_transformed, transformed_strips) {
+ /* Effects of transformed strips can be unselected. These must not be included. */
+ if (seq == seq_transformed) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ if (SEQ_transform_test_overlap_seq_seq(scene, seq, seq_transformed)) {
+ does_overlap = true;
+ }
+ }
+
+ if (!does_overlap) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ }
+
+ return collection;
+}
+
+typedef enum eOvelapDescrition {
+ /* No overlap. */
+ STRIP_OVERLAP_NONE,
+ /* Overlapping strip covers overlapped completely. */
+ STRIP_OVERLAP_IS_FULL,
+ /* Overlapping strip is inside overlapped. */
+ STRIP_OVERLAP_IS_INSIDE,
+ /* Partial overlap between 2 strips. */
+ STRIP_OVERLAP_LEFT_SIDE,
+ STRIP_OVERLAP_RIGHT_SIDE,
+} eOvelapDescrition;
+
+static eOvelapDescrition overlap_description_get(const Scene *scene,
+ const Sequence *transformed,
+ const Sequence *target)
+{
+ if (SEQ_time_left_handle_frame_get(scene, transformed) <=
+ SEQ_time_left_handle_frame_get(scene, target) &&
+ SEQ_time_right_handle_frame_get(scene, transformed) >=
+ SEQ_time_right_handle_frame_get(scene, target)) {
+ return STRIP_OVERLAP_IS_FULL;
+ }
+ if (SEQ_time_left_handle_frame_get(scene, transformed) >
+ SEQ_time_left_handle_frame_get(scene, target) &&
+ SEQ_time_right_handle_frame_get(scene, transformed) <
+ SEQ_time_right_handle_frame_get(scene, target)) {
+ return STRIP_OVERLAP_IS_INSIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(scene, transformed) <=
+ SEQ_time_left_handle_frame_get(scene, target) &&
+ SEQ_time_left_handle_frame_get(scene, target) <=
+ SEQ_time_right_handle_frame_get(scene, transformed)) {
+ return STRIP_OVERLAP_LEFT_SIDE;
+ }
+ if (SEQ_time_left_handle_frame_get(scene, transformed) <=
+ SEQ_time_right_handle_frame_get(scene, target) &&
+ SEQ_time_right_handle_frame_get(scene, target) <=
+ SEQ_time_right_handle_frame_get(scene, transformed)) {
+ return STRIP_OVERLAP_RIGHT_SIDE;
+ }
+ return STRIP_OVERLAP_NONE;
+}
+
+/* Split strip in 3 parts, remove middle part and fit transformed inside. */
+static void seq_transform_handle_overwrite_split(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target)
+{
+ /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass
+ * NULL here. */
+ Main *bmain = NULL;
+
+ Sequence *split_strip = SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ target,
+ SEQ_time_left_handle_frame_get(scene, transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_strip_split(bmain,
+ scene,
+ seqbasep,
+ split_strip,
+ SEQ_time_right_handle_frame_get(scene, transformed),
+ SEQ_SPLIT_SOFT,
+ NULL);
+ SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+}
+
+/* Trim strips by adjusting handle position.
+ * This is bit more complicated in case overlap happens on effect. */
+static void seq_transform_handle_overwrite_trim(Scene *scene,
+ ListBase *seqbasep,
+ const Sequence *transformed,
+ Sequence *target,
+ const eOvelapDescrition overlap)
+{
+ SeqCollection *targets = SEQ_query_by_reference(
+ target, scene, seqbasep, SEQ_query_strip_effect_chain);
+
+ /* Expand collection by adding all target's children, effects and their children. */
+ if ((target->type & SEQ_TYPE_EFFECT) != 0) {
+ SEQ_collection_expand(scene, seqbasep, targets, SEQ_query_strip_effect_chain);
+ }
+
+ /* Trim all non effects, that have influence on effect length which is overlapping. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, targets) {
+ if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
+ continue;
+ }
+ if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
+ SEQ_time_left_handle_frame_set(
+ scene, seq, SEQ_time_right_handle_frame_get(scene, transformed));
+ }
+ else {
+ BLI_assert(overlap == STRIP_OVERLAP_RIGHT_SIDE);
+ SEQ_time_right_handle_frame_set(
+ scene, seq, SEQ_time_left_handle_frame_get(scene, transformed));
+ }
+ }
+ SEQ_collection_free(targets);
+}
+
+static void seq_transform_handle_overwrite(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips)
+{
+ SeqCollection *targets = query_overwrite_targets(scene, seqbasep, transformed_strips);
+ SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+
+ Sequence *target;
+ Sequence *transformed;
+ SEQ_ITERATOR_FOREACH (target, targets) {
+ SEQ_ITERATOR_FOREACH (transformed, transformed_strips) {
+ if (transformed->machine != target->machine) {
+ continue;
+ }
+
+ const eOvelapDescrition overlap = overlap_description_get(scene, transformed, target);
+
+ if (overlap == STRIP_OVERLAP_IS_FULL) {
+ SEQ_collection_append_strip(target, strips_to_delete);
+ }
+ else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
+ seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
+ }
+ else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) {
+ seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
+ }
+ }
+ }
+
+ SEQ_collection_free(targets);
+
+ /* 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(scene, seqbasep, seq);
+ }
+ SEQ_edit_remove_flagged_sequences(scene, seqbasep);
+ }
+ SEQ_collection_free(strips_to_delete);
+}
+
+static void seq_transform_handle_overlap_shuffle(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ ListBase *markers = &scene->markers;
+
+ /* Shuffle non strips with no effects attached. */
+ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips);
+ SEQ_transform_seqbase_shuffle_time(
+ standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
+ SEQ_collection_free(standalone_strips);
+}
+
+void SEQ_transform_handle_overlap(Scene *scene,
+ ListBase *seqbasep,
+ SeqCollection *transformed_strips,
+ SeqCollection *time_dependent_strips,
+ bool use_sync_markers)
+{
+ const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
+
+ switch (overlap_mode) {
+ case SEQ_OVERLAP_EXPAND:
+ seq_transform_handle_expand_to_fit(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ case SEQ_OVERLAP_OVERWRITE:
+ seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
+ break;
+ case SEQ_OVERLAP_SHUFFLE:
+ seq_transform_handle_overlap_shuffle(
+ scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
+ break;
+ }
+
+ /* If any effects still overlap, we need to move them up.
+ * In some cases other strips can be overlapping still, see T90646. */
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, transformed_strips) {
+ if (SEQ_transform_test_overlap(scene, seqbasep, seq)) {
+ SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
+ }
+ seq->flag &= ~SEQ_OVERLAP;
+ }
+}
+
void SEQ_transform_offset_after_frame(Scene *scene,
ListBase *seqbase,
const int delta,
const int timeline_frame)
{
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (seq->startdisp >= timeline_frame) {
+ if (SEQ_time_left_handle_frame_get(scene, seq) >= timeline_frame) {
SEQ_transform_translate_sequence(scene, seq, delta);
- SEQ_time_update_sequence(scene, seqbase, seq);
SEQ_relations_invalidate_cache_preprocessed(scene, seq);
}
}
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index 0cf47420d8f..2026e322763 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -39,55 +39,9 @@
#include "multiview.h"
#include "proxy.h"
+#include "sequencer.h"
#include "utils.h"
-void SEQ_sort(ListBase *seqbase)
-{
- if (seqbase == NULL) {
- return;
- }
-
- /* all strips together per kind, and in order of y location ("machine") */
- ListBase inputbase, effbase;
- Sequence *seq, *seqt;
-
- BLI_listbase_clear(&inputbase);
- BLI_listbase_clear(&effbase);
-
- while ((seq = BLI_pophead(seqbase))) {
-
- if (seq->type & SEQ_TYPE_EFFECT) {
- seqt = effbase.first;
- while (seqt) {
- if (seqt->machine >= seq->machine) {
- BLI_insertlinkbefore(&effbase, seqt, seq);
- break;
- }
- seqt = seqt->next;
- }
- if (seqt == NULL) {
- BLI_addtail(&effbase, seq);
- }
- }
- else {
- seqt = inputbase.first;
- while (seqt) {
- if (seqt->machine >= seq->machine) {
- BLI_insertlinkbefore(&inputbase, seqt, seq);
- break;
- }
- seqt = seqt->next;
- }
- if (seqt == NULL) {
- BLI_addtail(&inputbase, seq);
- }
- }
- }
-
- BLI_movelisttolist(seqbase, &inputbase);
- BLI_movelisttolist(seqbase, &effbase);
-}
-
typedef struct SeqUniqueInfo {
Sequence *seq;
char name_src[SEQ_NAME_MAXSTR];
@@ -233,7 +187,7 @@ ListBase *SEQ_get_seqbase_from_sequence(Sequence *seq, ListBase **r_channels, in
case SEQ_TYPE_META: {
seqbase = &seq->seqbase;
*r_channels = &seq->channels;
- *r_offset = seq->start;
+ *r_offset = SEQ_time_start_frame_get(seq);
break;
}
case SEQ_TYPE_SCENE: {
@@ -263,7 +217,7 @@ void seq_open_anim_file(Scene *scene, Sequence *seq, bool openfile)
const bool is_multiview = (seq->flag & SEQ_USE_VIEWS) != 0 &&
(scene->r.scemode & R_MULTIVIEW) != 0;
- if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL)) {
+ if ((seq->anims.first != NULL) && (((StripAnim *)seq->anims.first)->anim != NULL) && !openfile) {
return;
}
@@ -393,7 +347,8 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame)
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- if (SEQ_render_is_muted(channels, seq) || !SEQ_time_strip_intersects_frame(seq, frame)) {
+ if (SEQ_render_is_muted(channels, seq) ||
+ !SEQ_time_strip_intersects_frame(scene, seq, frame)) {
continue;
}
/* Only use strips that generate an image, not ones that combine
@@ -414,20 +369,18 @@ const Sequence *SEQ_get_topmost_sequence(const Scene *scene, int frame)
return best_seq;
}
-ListBase *SEQ_get_seqbase_by_seq(ListBase *seqbase, Sequence *seq)
+ListBase *SEQ_get_seqbase_by_seq(const Scene *scene, Sequence *seq)
{
- Sequence *iseq;
- ListBase *lb = NULL;
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *main_seqbase = &ed->seqbase;
+ Sequence *seq_meta = seq_sequence_lookup_meta_by_seq(scene, seq);
- for (iseq = seqbase->first; iseq; iseq = iseq->next) {
- if (seq == iseq) {
- return seqbase;
- }
- if (iseq->seqbase.first && (lb = SEQ_get_seqbase_by_seq(&iseq->seqbase, seq))) {
- return lb;
- }
+ if (seq_meta != NULL) {
+ return &seq_meta->seqbase;
+ }
+ if (BLI_findindex(main_seqbase, seq) >= 0) {
+ return main_seqbase;
}
-
return NULL;
}
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 73a5f1e6f8d..4c553d0edfe 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -39,7 +39,7 @@ set(SRC
intern/wm_dragdrop.c
intern/wm_draw.c
intern/wm_event_query.c
- intern/wm_event_system.c
+ intern/wm_event_system.cc
intern/wm_files.c
intern/wm_files_link.c
intern/wm_gesture.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index dda60975a96..44c5b86857d 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -314,10 +314,6 @@ 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. */
@@ -388,6 +384,12 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C,
wmUIHandlerRemoveFunc remove_fn,
void *user_data,
char flag);
+
+/**
+ * Return the first modal operator of type \a ot or NULL.
+ */
+wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot);
+
/**
* \param postpone: Enable for `win->modalhandlers`,
* this is in a running for () loop in wm_handlers_do().
@@ -732,6 +734,7 @@ void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct Pointe
wmOperator *WM_operator_last_redo(const struct bContext *C);
/**
* Use for drag & drop a path or name with operators invoke() function.
+ * Returns null if no operator property is set to identify the file or ID to use.
*/
ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, short idcode);
@@ -1211,10 +1214,24 @@ int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent
/* Drag and drop. */
/**
- * Note that the pointer should be valid allocated and not on stack.
+ * Start dragging immediately with the given data.
+ * Note that \a poin should be valid allocated and not on stack.
*/
-struct wmDrag *WM_event_start_drag(
+void WM_event_start_drag(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
+/**
+ * Create and fill the dragging data, but don't start dragging just yet (unlike
+ * #WM_event_start_drag()). Must be followed up by #WM_event_start_prepared_drag(), otherwise the
+ * returned pointer will leak memory.
+ *
+ * Note that \a poin should be valid allocated and not on stack.
+ */
+wmDrag *WM_drag_data_create(
+ struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
+/**
+ * Invoke dragging using the given \a drag data.
+ */
+void WM_event_start_prepared_drag(struct bContext *C, wmDrag *drag);
void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale);
void WM_drag_free(struct wmDrag *drag);
void WM_drag_data_free(int dragtype, void *poin);
@@ -1400,6 +1417,14 @@ void WM_jobs_callbacks(struct wmJob *,
void (*update)(void *),
void (*endjob)(void *));
+void WM_jobs_callbacks_ex(wmJob *wm_job,
+ wm_jobs_start_callback startjob,
+ void (*initjob)(void *),
+ void (*update)(void *),
+ void (*endjob)(void *),
+ void (*completed)(void *),
+ void (*canceled)(void *));
+
/**
* If job running, the same owner gave it a new job.
* if different owner starts existing startjob, it suspends itself
@@ -1426,6 +1451,7 @@ 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);
bool WM_jobs_has_running(const struct wmWindowManager *wm);
+bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type);
void WM_job_main_thread_lock_acquire(struct wmJob *job);
void WM_job_main_thread_lock_release(struct wmJob *job);
@@ -1515,10 +1541,10 @@ void WM_event_print(const struct wmEvent *event);
bool WM_event_is_modal_drag_exit(const struct wmEvent *event,
short init_event_type,
short init_event_val);
-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);
int WM_event_drag_direction(const wmEvent *event);
+char WM_event_utf8_to_ascii(const struct wmEvent *event) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Detect motion between selection (callers should only use this for selection picking),
@@ -1700,7 +1726,7 @@ void WM_xr_action_binding_destroy(wmXrData *xr,
/**
* 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_active_action_set_set(wmXrData *xr, const char *action_set_name, bool delayed);
bool WM_xr_controller_pose_actions_set(wmXrData *xr,
const char *action_set_name,
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 71a4b7c4559..79d42c18b21 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -323,34 +323,35 @@ typedef struct wmNotifier {
#define NOTE_CATEGORY 0xFF000000
#define NC_WM (1 << 24)
#define NC_WINDOW (2 << 24)
-#define NC_SCREEN (3 << 24)
-#define NC_SCENE (4 << 24)
-#define NC_OBJECT (5 << 24)
-#define NC_MATERIAL (6 << 24)
-#define NC_TEXTURE (7 << 24)
-#define NC_LAMP (8 << 24)
-#define NC_GROUP (9 << 24)
-#define NC_IMAGE (10 << 24)
-#define NC_BRUSH (11 << 24)
-#define NC_TEXT (12 << 24)
-#define NC_WORLD (13 << 24)
-#define NC_ANIMATION (14 << 24)
+#define NC_WORKSPACE (3 << 24)
+#define NC_SCREEN (4 << 24)
+#define NC_SCENE (5 << 24)
+#define NC_OBJECT (6 << 24)
+#define NC_MATERIAL (7 << 24)
+#define NC_TEXTURE (8 << 24)
+#define NC_LAMP (9 << 24)
+#define NC_GROUP (10 << 24)
+#define NC_IMAGE (11 << 24)
+#define NC_BRUSH (12 << 24)
+#define NC_TEXT (13 << 24)
+#define NC_WORLD (14 << 24)
+#define NC_ANIMATION (15 << 24)
/* When passing a space as reference data with this (e.g. `WM_event_add_notifier(..., space)`),
* the notifier will only be sent to this space. That avoids unnecessary updates for unrelated
* spaces. */
-#define NC_SPACE (15 << 24)
-#define NC_GEOM (16 << 24)
-#define NC_NODE (17 << 24)
-#define NC_ID (18 << 24)
-#define NC_PAINTCURVE (19 << 24)
-#define NC_MOVIECLIP (20 << 24)
-#define NC_MASK (21 << 24)
-#define NC_GPENCIL (22 << 24)
-#define NC_LINESTYLE (23 << 24)
-#define NC_CAMERA (24 << 24)
-#define NC_LIGHTPROBE (25 << 24)
+#define NC_SPACE (16 << 24)
+#define NC_GEOM (17 << 24)
+#define NC_NODE (18 << 24)
+#define NC_ID (19 << 24)
+#define NC_PAINTCURVE (20 << 24)
+#define NC_MOVIECLIP (21 << 24)
+#define NC_MASK (22 << 24)
+#define NC_GPENCIL (23 << 24)
+#define NC_LINESTYLE (24 << 24)
+#define NC_CAMERA (25 << 24)
+#define NC_LIGHTPROBE (26 << 24)
/* Changes to asset data in the current .blend. */
-#define NC_ASSET (26 << 24)
+#define NC_ASSET (27 << 24)
/* data type, 256 entries is enough, it can overlap */
#define NOTE_DATA 0x00FF0000
@@ -615,6 +616,7 @@ typedef enum eWM_EventFlag {
*/
WM_EVENT_FORCE_DRAG_THRESHOLD = (1 << 2),
} eWM_EventFlag;
+ENUM_OPERATORS(eWM_EventFlag, WM_EVENT_FORCE_DRAG_THRESHOLD);
typedef struct wmTabletData {
/** 0=EVT_TABLET_NONE, 1=EVT_TABLET_STYLUS, 2=EVT_TABLET_ERASER. */
@@ -680,13 +682,11 @@ typedef struct wmEvent {
/** Region relative mouse position (name convention before Blender 2.5). */
int mval[2];
/**
- * From, ghost if utf8 is enabled for the platform,
- * #BLI_str_utf8_size() must _always_ be valid, check
- * when assigning s we don't need to check on every access after.
+ * A single UTF8 encoded character.
+ * #BLI_str_utf8_size() must _always_ return a valid value,
+ * check when assigning so we don't need to check on every access after.
*/
char utf8_buf[6];
- /** From ghost, fallback if utf8 isn't set. */
- char ascii;
/** Modifier states: #KM_SHIFT, #KM_CTRL, #KM_ALT & #KM_OSKEY. */
uint8_t modifier;
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index 80d29bb8c40..663c8a0baed 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -388,6 +388,8 @@ void WM_gizmomap_message_subscribe(const struct bContext *C,
struct ARegion *region,
struct wmMsgBus *mbus);
bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap);
+struct wmGizmo *WM_gizmomap_get_modal(const struct wmGizmoMap *gzmap);
+
/**
* \note We could use a callback to define bounds, for now just use matrix location.
*/
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index f481f19045d..f5974a2176b 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -229,6 +229,11 @@ bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap)
return gzmap->gzmap_context.select.len != 0;
}
+wmGizmo *WM_gizmomap_get_modal(const wmGizmoMap *gzmap)
+{
+ return gzmap->gzmap_context.modal;
+}
+
bool WM_gizmomap_minmax(const wmGizmoMap *gzmap,
bool UNUSED(use_hidden),
bool use_select,
@@ -669,7 +674,7 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C,
* This way we always use the first hit. */
if (has_3d) {
- /* The depth buffer is needed for for gizmos to obscure eachother. */
+ /* The depth buffer is needed for for gizmos to obscure each other. */
GPUViewport *viewport = WM_draw_region_get_viewport(CTX_wm_region(C));
/* When switching between modes and the mouse pointer is over a gizmo, the highlight test is
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 af083630623..80876dfd798 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c
@@ -343,9 +343,9 @@ void WM_gizmo_target_property_anim_autokey(bContext *C,
{
if (gz_prop->prop != NULL) {
Scene *scene = CTX_data_scene(C);
- const float cfra = (float)CFRA;
+ const float cfra = (float)scene->r.cfra;
const int index = gz_prop->index == -1 ? 0 : gz_prop->index;
- ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra);
+ ED_autokeyframe_property(C, scene, &gz_prop->ptr, gz_prop->prop, index, cfra, false);
}
}
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 40d9b0b9a35..0d74bc259f4 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -81,6 +81,8 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data)
if (BKE_lib_query_foreachid_iter_stop(data)) {
return;
}
+
+ BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, win->unpinned_scene, IDWALK_CB_NOP);
}
if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) {
@@ -224,6 +226,7 @@ static void lib_link_workspace_instance_hook(BlendLibReader *reader,
{
WorkSpace *workspace = BKE_workspace_active_get(hook);
BLO_read_id_address(reader, id->lib, &workspace);
+
BKE_workspace_active_set(hook, workspace);
}
@@ -239,6 +242,11 @@ static void window_manager_blend_read_lib(BlendLibReader *reader, ID *id)
/* deprecated, but needed for versioning (will be NULL'ed then) */
BLO_read_id_address(reader, NULL, &win->screen);
+ /* The unpinned scene is a UI->Scene-data pointer, and should be NULL'ed on linking (like
+ * WorkSpace.pin_scene). But the WindowManager ID (owning the window) is never linked. */
+ BLI_assert(!ID_IS_LINKED(id));
+ BLO_read_id_address(reader, id->lib, &win->unpinned_scene);
+
LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
BKE_screen_area_blend_read_lib(reader, &wm->id, area);
}
@@ -249,7 +257,7 @@ static void window_manager_blend_read_lib(BlendLibReader *reader, ID *id)
IDTypeInfo IDType_ID_WM = {
.id_code = ID_WM,
- .id_filter = 0,
+ .id_filter = FILTER_ID_WM,
.main_listbase_index = INDEX_ID_WM,
.struct_size = sizeof(wmWindowManager),
.name = "WindowManager",
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index b7066178abd..43be87fce39 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -228,11 +228,11 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
/* Only grab cursor when not running debug.
* It helps not to get a stuck WM when hitting a break-point. */
GHOST_TGrabCursorMode mode = GHOST_kGrabNormal;
- GHOST_TAxisFlag mode_axis = GHOST_kAxisX | GHOST_kGrabAxisY;
+ GHOST_TAxisFlag mode_axis = GHOST_kAxisX | GHOST_kAxisY;
if (bounds) {
- wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]);
- wm_cursor_position_to_ghost(win, &bounds[2], &bounds[3]);
+ wm_cursor_position_to_ghost_screen_coords(win, &bounds[0], &bounds[1]);
+ wm_cursor_position_to_ghost_screen_coords(win, &bounds[2], &bounds[3]);
}
if (hide) {
@@ -245,7 +245,7 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
mode_axis = GHOST_kAxisX;
}
else if (wrap == WM_CURSOR_WRAP_Y) {
- mode_axis = GHOST_kGrabAxisY;
+ mode_axis = GHOST_kAxisY;
}
}
@@ -266,12 +266,11 @@ void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
if (win && win->ghostwin) {
if (mouse_ungrab_xy) {
int mouse_xy[2] = {mouse_ungrab_xy[0], mouse_ungrab_xy[1]};
- wm_cursor_position_to_ghost(win, &mouse_xy[0], &mouse_xy[1]);
- GHOST_SetCursorGrab(
- win->ghostwin, GHOST_kGrabDisable, GHOST_kGrabAxisNone, NULL, mouse_xy);
+ wm_cursor_position_to_ghost_screen_coords(win, &mouse_xy[0], &mouse_xy[1]);
+ GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, GHOST_kAxisNone, NULL, mouse_xy);
}
else {
- GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, GHOST_kGrabAxisNone, NULL, NULL);
+ GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, GHOST_kAxisNone, NULL, NULL);
}
win->grabcursor = GHOST_kGrabDisable;
@@ -383,7 +382,7 @@ void WM_cursor_time(wmWindow *win, int nr)
/**
* Because defining a cursor mixes declarations and executable code
* each cursor needs its own scoping block or it would be split up
- * over several hundred lines of code. To enforce/document this better
+ * over several hundred lines of code. To enforce/document this better
* I define 2 pretty brain-dead macros so it's obvious what the extra "[]"
* are for */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 8f96080c810..36bd69a9b25 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -175,16 +175,14 @@ static void wm_dropbox_invoke(bContext *C, wmDrag *drag)
}
}
-wmDrag *WM_event_start_drag(
+wmDrag *WM_drag_data_create(
struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags)
{
- wmWindowManager *wm = CTX_wm_manager(C);
wmDrag *drag = MEM_callocN(sizeof(struct wmDrag), "new drag");
/* Keep track of future multi-touch drag too, add a mouse-pointer id or so. */
/* if multiple drags are added, they're drawn as list */
- BLI_addtail(&wm->drags, drag);
drag->flags = flags;
drag->icon = icon;
drag->type = type;
@@ -226,9 +224,22 @@ wmDrag *WM_event_start_drag(
}
drag->value = value;
+ return drag;
+}
+
+void WM_event_start_prepared_drag(bContext *C, wmDrag *drag)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ BLI_addtail(&wm->drags, drag);
wm_dropbox_invoke(C, drag);
+}
- return drag;
+void WM_event_start_drag(
+ struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags)
+{
+ wmDrag *drag = WM_drag_data_create(C, icon, type, poin, value, flags);
+ WM_event_start_prepared_drag(C, drag);
}
void wm_drags_exit(wmWindowManager *wm, wmWindow *win)
@@ -712,9 +723,7 @@ void WM_drag_add_asset_list_item(
const AssetLibraryReference *asset_library_ref,
const AssetHandle *asset)
{
- if (drag->type != WM_DRAG_ASSET_LIST) {
- return;
- }
+ BLI_assert(drag->type == WM_DRAG_ASSET_LIST);
/* No guarantee that the same asset isn't added twice. */
@@ -827,7 +836,7 @@ static void wm_drag_draw_icon(bContext *UNUSED(C),
x = xy[0] - (wm_drag_imbuf_icon_width_get(drag) / 2);
y = xy[1] - (wm_drag_imbuf_icon_height_get(drag) / 2);
- float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
+ const 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,
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index d2ade7b0376..66ed36b373d 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -41,6 +41,7 @@
#include "GPU_debug.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "GPU_texture.h"
#include "GPU_viewport.h"
@@ -119,6 +120,216 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Draw Software Cursor
+ *
+ * Draw the cursor instead of relying on the graphical environment.
+ * Needed when setting the cursor position (warping) isn't supported (GHOST/WAYLAND).
+ * \{ */
+
+/**
+ * Track the state of the last drawn cursor.
+ */
+static struct {
+ int8_t enabled;
+ int winid;
+ int xy[2];
+} g_software_cursor = {
+ .enabled = -1,
+ .winid = -1,
+};
+
+/** Reuse the result from #GHOST_GetCursorGrabState. */
+struct GrabState {
+ GHOST_TGrabCursorMode mode;
+ GHOST_TAxisFlag wrap_axis;
+ int bounds[4];
+};
+
+static bool wm_software_cursor_needed(void)
+{
+ if (UNLIKELY(g_software_cursor.enabled == -1)) {
+ g_software_cursor.enabled = !GHOST_SupportsCursorWarp();
+ }
+ return g_software_cursor.enabled;
+}
+
+static bool wm_software_cursor_needed_for_window(const wmWindow *win, struct GrabState *grab_state)
+{
+ BLI_assert(wm_software_cursor_needed());
+ if (GHOST_GetCursorVisibility(win->ghostwin)) {
+ /* NOTE: The value in `win->grabcursor` can't be used as it
+ * doesn't always match GHOST's value in the case of tablet events. */
+ bool use_software_cursor;
+ GHOST_GetCursorGrabState(win->ghostwin,
+ &grab_state->mode,
+ &grab_state->wrap_axis,
+ grab_state->bounds,
+ &use_software_cursor);
+ if (use_software_cursor) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool wm_software_cursor_motion_test(const wmWindow *win)
+{
+ return (g_software_cursor.winid != win->winid) ||
+ (g_software_cursor.xy[0] != win->eventstate->xy[0]) ||
+ (g_software_cursor.xy[1] != win->eventstate->xy[1]);
+}
+
+static void wm_software_cursor_motion_update(const wmWindow *win)
+{
+
+ g_software_cursor.winid = win->winid;
+ g_software_cursor.xy[0] = win->eventstate->xy[0];
+ g_software_cursor.xy[1] = win->eventstate->xy[1];
+}
+
+static void wm_software_cursor_motion_clear(void)
+{
+ g_software_cursor.winid = -1;
+ g_software_cursor.xy[0] = -1;
+ g_software_cursor.xy[1] = -1;
+}
+
+static void wm_software_cursor_draw_bitmap(const int event_xy[2],
+ const GHOST_CursorBitmapRef *bitmap)
+{
+ GPU_blend(GPU_BLEND_ALPHA);
+
+ float gl_matrix[4][4];
+ GPUTexture *texture = GPU_texture_create_2d(
+ "softeare_cursor", bitmap->data_size[0], bitmap->data_size[1], 1, GPU_RGBA8, NULL);
+ GPU_texture_update(texture, GPU_DATA_UBYTE, bitmap->data);
+ GPU_texture_filter_mode(texture, false);
+
+ GPU_matrix_push();
+
+ const int scale = (int)U.pixelsize;
+
+ unit_m4(gl_matrix);
+
+ gl_matrix[3][0] = event_xy[0] - (bitmap->hot_spot[0] * scale);
+ gl_matrix[3][1] = event_xy[1] - ((bitmap->data_size[1] - bitmap->hot_spot[1]) * scale);
+
+ gl_matrix[0][0] = bitmap->data_size[0] * scale;
+ gl_matrix[1][1] = bitmap->data_size[1] * scale;
+
+ GPU_matrix_mul(gl_matrix);
+
+ GPUVertFormat *imm_format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(imm_format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint texCoord = GPU_vertformat_attr_add(
+ imm_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ /* Use 3D image for correct display of planar tracked images. */
+ immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_MODULATE_ALPHA);
+
+ immBindTexture("image", texture);
+ immUniform1f("alpha", 1.0f);
+
+ immBegin(GPU_PRIM_TRI_FAN, 4);
+
+ immAttr2f(texCoord, 0.0f, 1.0f);
+ immVertex3f(pos, 0.0f, 0.0f, 0.0f);
+
+ immAttr2f(texCoord, 1.0f, 1.0f);
+ immVertex3f(pos, 1.0f, 0.0f, 0.0f);
+
+ immAttr2f(texCoord, 1.0f, 0.0f);
+ immVertex3f(pos, 1.0f, 1.0f, 0.0f);
+
+ immAttr2f(texCoord, 0.0f, 0.0f);
+ immVertex3f(pos, 0.0f, 1.0f, 0.0f);
+
+ immEnd();
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+ GPU_texture_unbind(texture);
+ GPU_texture_free(texture);
+
+ GPU_blend(GPU_BLEND_NONE);
+}
+
+static void wm_software_cursor_draw_crosshair(const int event_xy[2])
+{
+ /* Draw a primitive cross-hair cursor.
+ * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors
+ * are set by the operating-system, where the pixel information isn't easily available. */
+ const float unit = max_ff(U.dpi_fac, 1.0f);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1, 1, 1, 1);
+ {
+ const int ofs_line = (8 * unit);
+ const int ofs_size = (2 * unit);
+ immRecti(pos,
+ event_xy[0] - ofs_line,
+ event_xy[1] - ofs_size,
+ event_xy[0] + ofs_line,
+ event_xy[1] + ofs_size);
+ immRecti(pos,
+ event_xy[0] - ofs_size,
+ event_xy[1] - ofs_line,
+ event_xy[0] + ofs_size,
+ event_xy[1] + ofs_line);
+ }
+ immUniformColor4f(0, 0, 0, 1);
+ {
+ const int ofs_line = (7 * unit);
+ const int ofs_size = (1 * unit);
+ immRecti(pos,
+ event_xy[0] - ofs_line,
+ event_xy[1] - ofs_size,
+ event_xy[0] + ofs_line,
+ event_xy[1] + ofs_size);
+ immRecti(pos,
+ event_xy[0] - ofs_size,
+ event_xy[1] - ofs_line,
+ event_xy[0] + ofs_size,
+ event_xy[1] + ofs_line);
+ }
+ immUnbindProgram();
+}
+
+static void wm_software_cursor_draw(wmWindow *win, const struct GrabState *grab_state)
+{
+ int event_xy[2] = {UNPACK2(win->eventstate->xy)};
+
+ if (grab_state->wrap_axis & GHOST_kAxisX) {
+ const int min = grab_state->bounds[0];
+ const int max = grab_state->bounds[2];
+ if (min != max) {
+ event_xy[0] = mod_i(event_xy[0] - min, max - min) + min;
+ }
+ }
+ if (grab_state->wrap_axis & GHOST_kAxisY) {
+ const int height = WM_window_pixels_y(win);
+ const int min = height - grab_state->bounds[1];
+ const int max = height - grab_state->bounds[3];
+ if (min != max) {
+ event_xy[1] = mod_i(event_xy[1] - max, min - max) + max;
+ }
+ }
+
+ GHOST_CursorBitmapRef bitmap = {0};
+ if (GHOST_GetCursorBitmap(win->ghostwin, &bitmap) == GHOST_kSuccess) {
+ wm_software_cursor_draw_bitmap(event_xy, &bitmap);
+ }
+ else {
+ wm_software_cursor_draw_crosshair(event_xy);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Post Draw Region on display handlers
* \{ */
@@ -862,6 +1073,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
/* always draw, not only when screen tagged */
if (win->gesture.first) {
wm_gesture_draw(win);
+ wmWindowViewport(win);
}
/* Needs pixel coords in screen. */
@@ -870,11 +1082,24 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
wmWindowViewport(win);
}
+ if (wm_software_cursor_needed()) {
+ struct GrabState grab_state;
+ if (wm_software_cursor_needed_for_window(win, &grab_state)) {
+ wm_software_cursor_draw(win, &grab_state);
+ wm_software_cursor_motion_update(win);
+ }
+ else {
+ wm_software_cursor_motion_clear();
+ }
+ }
+
GPU_debug_group_end();
}
static void wm_draw_window(bContext *C, wmWindow *win)
{
+ GPU_context_begin_frame(win->gpuctx);
+
bScreen *screen = WM_window_get_active_screen(win);
bool stereo = WM_stereo3d_enabled(win, false);
@@ -944,6 +1169,8 @@ static void wm_draw_window(bContext *C, wmWindow *win)
}
screen->do_draw = false;
+
+ GPU_context_end_frame(win->gpuctx);
}
/**
@@ -954,8 +1181,12 @@ static void wm_draw_surface(bContext *C, wmSurface *surface)
wm_window_clear_drawable(CTX_wm_manager(C));
wm_surface_make_drawable(surface);
+ GPU_context_begin_frame(surface->gpu_ctx);
+
surface->draw(C);
+ GPU_context_end_frame(surface->gpu_ctx);
+
/* Avoid interference with window drawable */
wm_surface_clear_drawable();
}
@@ -1020,6 +1251,22 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
return true;
}
+ if (wm_software_cursor_needed()) {
+ struct GrabState grab_state;
+ if (wm_software_cursor_needed_for_window(win, &grab_state)) {
+ if (wm_software_cursor_motion_test(win)) {
+ return true;
+ }
+ }
+ else {
+ /* Detect the edge case when the previous draw used the software cursor but this one doesn't,
+ * it's important to redraw otherwise the software cursor will remain displayed. */
+ if (g_software_cursor.winid != -1) {
+ return true;
+ }
+ }
+ }
+
#ifndef WITH_XR_OPENXR
UNUSED_VARS(wm);
#endif
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index 503dae53122..81044197ae7 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -112,7 +112,7 @@ void WM_event_print(const wmEvent *event)
"wmEvent type:%d/%s, val:%d/%s, "
"prev_type:%d/%s, prev_val:%d/%s, "
"modifier=%s, keymodifier:%d, flag:%s, "
- "mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p",
+ "mouse:(%d,%d), utf8:'%.*s', pointer:%p",
event->type,
type_id,
event->val,
@@ -126,7 +126,6 @@ void WM_event_print(const wmEvent *event)
flag_id,
event->xy[0],
event->xy[1],
- event->ascii,
BLI_str_utf8_size(event->utf8_buf),
event->utf8_buf,
(const void *)event);
@@ -199,6 +198,13 @@ bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask ma
}
}
+ /* NDOF */
+ if (mask & EVT_TYPE_MASK_NDOF) {
+ if (ISNDOF(event_type)) {
+ return true;
+ }
+ }
+
/* Action Zone. */
if (mask & EVT_TYPE_MASK_ACTIONZONE) {
if (IS_EVENT_ACTIONZONE(event_type)) {
@@ -247,16 +253,6 @@ bool WM_event_is_modal_drag_exit(const wmEvent *event,
return 0;
}
-bool WM_event_is_last_mousemove(const wmEvent *event)
-{
- while ((event = event->next)) {
- if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- return false;
- }
- }
- return true;
-}
-
bool WM_event_is_mouse_drag(const wmEvent *event)
{
return (ISMOUSE_BUTTON(event->type) && (event->val == KM_CLICK_DRAG));
@@ -404,6 +400,20 @@ void WM_event_drag_start_xy(const wmEvent *event, int r_xy[2])
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Event Text Queries
+ * \{ */
+
+char WM_event_utf8_to_ascii(const struct wmEvent *event)
+{
+ if (BLI_str_utf8_size(event->utf8_buf) == 1) {
+ return event->utf8_buf[0];
+ }
+ return '\0';
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Event Preference Mapping
* \{ */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.cc
index 3ff3117dafe..79b303364d8 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.cc
@@ -9,9 +9,9 @@
* Also some operator reports utility functions.
*/
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
#include "DNA_listBase.h"
#include "DNA_scene_types.h"
@@ -116,11 +116,11 @@ wmEvent *wm_event_add_ex(wmWindow *win,
const wmEvent *event_to_add,
const wmEvent *event_to_add_after)
{
- wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent");
+ wmEvent *event = MEM_new<wmEvent>(__func__);
*event = *event_to_add;
- if (event_to_add_after == NULL) {
+ if (event_to_add_after == nullptr) {
BLI_addtail(&win->event_queue, event);
}
else {
@@ -133,14 +133,14 @@ wmEvent *wm_event_add_ex(wmWindow *win,
wmEvent *wm_event_add(wmWindow *win, const wmEvent *event_to_add)
{
- return wm_event_add_ex(win, event_to_add, NULL);
+ return wm_event_add_ex(win, event_to_add, nullptr);
}
wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add)
{
if ((G.f & G_FLAG_EVENT_SIMULATE) == 0) {
BLI_assert_unreachable();
- return NULL;
+ return nullptr;
}
wmEvent *event = wm_event_add(win, event_to_add);
@@ -166,7 +166,7 @@ static void wm_event_custom_free(wmEvent *event)
/* NOTE: pointer to #ListBase struct elsewhere. */
if (event->custom == EVT_DATA_DRAGDROP) {
- ListBase *lb = event->customdata;
+ ListBase *lb = static_cast<ListBase *>(event->customdata);
WM_drag_free_list(lb);
}
else {
@@ -177,7 +177,7 @@ static void wm_event_custom_free(wmEvent *event)
static void wm_event_custom_clear(wmEvent *event)
{
event->custom = 0;
- event->customdata = NULL;
+ event->customdata = nullptr;
event->customdata_free = false;
}
@@ -209,7 +209,7 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event)
* As this function should be interchangeable with #wm_event_free. */
#ifndef NDEBUG
{
- wmEvent *event_copy = MEM_dupallocN(event);
+ wmEvent *event_copy = static_cast<wmEvent *>(MEM_dupallocN(event));
MEM_freeN(event);
event = event_copy;
}
@@ -227,8 +227,8 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event)
static void wm_event_free_last(wmWindow *win)
{
- wmEvent *event = BLI_poptail(&win->event_queue);
- if (event != NULL) {
+ wmEvent *event = static_cast<wmEvent *>(BLI_poptail(&win->event_queue));
+ if (event != nullptr) {
wm_event_free(event);
}
}
@@ -236,7 +236,7 @@ static void wm_event_free_last(wmWindow *win)
void wm_event_free_all(wmWindow *win)
{
wmEvent *event;
- while ((event = BLI_pophead(&win->event_queue))) {
+ while ((event = static_cast<wmEvent *>(BLI_pophead(&win->event_queue)))) {
wm_event_free(event);
}
}
@@ -270,7 +270,7 @@ void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint typ
return;
}
- wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
+ wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
BLI_addtail(&wm->notifier_queue, note);
@@ -293,13 +293,13 @@ void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_main_add_notifier(unsigned int type, void *reference)
{
Main *bmain = G_MAIN;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (!wm || wm_test_duplicate_notifier(wm, type, reference)) {
return;
}
- wmNotifier *note = MEM_callocN(sizeof(wmNotifier), "notifier");
+ wmNotifier *note = MEM_cnew<wmNotifier>(__func__);
BLI_addtail(&wm->notifier_queue, note);
@@ -314,7 +314,7 @@ void WM_main_add_notifier(unsigned int type, void *reference)
void WM_main_remove_notifier_reference(const void *reference)
{
Main *bmain = G_MAIN;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (wm) {
LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) {
@@ -341,8 +341,8 @@ static void wm_main_remap_assetlist(ID *old_id, ID *new_id, void *UNUSED(user_da
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) {
+ wmMsgBus *mbus = static_cast<wmMsgBus *>(user_data);
+ if (new_id != nullptr) {
WM_msg_id_update(mbus, old_id, new_id);
}
else {
@@ -350,7 +350,7 @@ static void wm_main_remap_msgbus_notify(ID *old_id, ID *new_id, void *user_data)
}
}
-void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
+void WM_main_remap_editor_id_reference(const IDRemapper *mappings)
{
Main *bmain = G_MAIN;
@@ -362,9 +362,9 @@ void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
}
}
- BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, NULL);
+ BKE_id_remapper_iter(mappings, wm_main_remap_assetlist, nullptr);
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (wm && wm->message_bus) {
BKE_id_remapper_iter(mappings, wm_main_remap_msgbus_notify, wm->message_bus);
}
@@ -372,7 +372,7 @@ void WM_main_remap_editor_id_reference(const struct IDRemapper *mappings)
static void wm_notifier_clear(wmNotifier *note)
{
- /* NULL the entire notifier, only leaving (`next`, `prev`) members intact. */
+ /* nullptr the entire notifier, only leaving (`next`, `prev`) members intact. */
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
}
@@ -435,22 +435,22 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
wm_event_do_depsgraph(C, false);
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
static void wm_event_execute_timers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- if (UNLIKELY(wm == NULL)) {
+ if (UNLIKELY(wm == nullptr)) {
return;
}
/* Set the first window as context, so that there is some minimal context. This avoids crashes
* when calling code that assumes that there is always a window in the context (which many
* operators do). */
- CTX_wm_window_set(C, wm->windows.first);
+ CTX_wm_window_set(C, static_cast<wmWindow *>(wm->windows.first));
BLI_timer_execute();
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
void wm_event_do_notifiers(bContext *C)
@@ -459,7 +459,7 @@ void wm_event_do_notifiers(bContext *C)
wm_event_execute_timers(C);
wmWindowManager *wm = CTX_wm_manager(C);
- if (wm == NULL) {
+ if (wm == nullptr) {
return;
}
@@ -489,7 +489,7 @@ void wm_event_do_notifiers(bContext *C)
if (note->window == win) {
if (note->category == NC_SCREEN) {
if (note->data == ND_WORKSPACE_SET) {
- WorkSpace *ref_ws = note->reference;
+ WorkSpace *ref_ws = static_cast<WorkSpace *>(note->reference);
UI_popup_handlers_remove_all(C, &win->modalhandlers);
@@ -499,7 +499,7 @@ void wm_event_do_notifiers(bContext *C)
}
}
else if (note->data == ND_WORKSPACE_DELETE) {
- WorkSpace *workspace = note->reference;
+ WorkSpace *workspace = static_cast<WorkSpace *>(note->reference);
ED_workspace_delete(
workspace, CTX_data_main(C), C, wm); /* XXX: hum, think this over! */
@@ -508,7 +508,8 @@ void wm_event_do_notifiers(bContext *C)
}
}
else if (note->data == ND_LAYOUTBROWSE) {
- bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
+ bScreen *ref_screen = BKE_workspace_layout_screen_get(
+ static_cast<WorkSpaceLayout *>(note->reference));
/* Free popup handlers only T35434. */
UI_popup_handlers_remove_all(C, &win->modalhandlers);
@@ -520,7 +521,7 @@ void wm_event_do_notifiers(bContext *C)
}
else if (note->data == ND_LAYOUTDELETE) {
WorkSpace *workspace = WM_window_get_active_workspace(win);
- WorkSpaceLayout *layout = note->reference;
+ WorkSpaceLayout *layout = static_cast<WorkSpaceLayout *>(note->reference);
ED_workspace_layout_delete(workspace, layout, C); /* XXX: hum, think this over! */
if (G.debug & G_DEBUG_EVENTS) {
@@ -530,7 +531,8 @@ void wm_event_do_notifiers(bContext *C)
}
}
- if (note->window == win || (note->window == NULL && (ELEM(note->reference, NULL, scene)))) {
+ if (note->window == win ||
+ (note->window == nullptr && (ELEM(note->reference, nullptr, scene)))) {
if (note->category == NC_SCENE) {
if (note->data == ND_FRAME) {
do_anim = true;
@@ -546,7 +548,7 @@ void wm_event_do_notifiers(bContext *C)
/* Only do once since adding notifiers is slow when there are many. */
ViewLayer *view_layer = CTX_data_view_layer(C);
ED_info_stats_clear(wm, view_layer);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, nullptr);
}
if (do_anim) {
@@ -564,7 +566,7 @@ void wm_event_do_notifiers(bContext *C)
/* The notifiers are sent without context, to keep it clean. */
wmNotifier *note;
- while ((note = BLI_pophead(&wm->notifier_queue))) {
+ while ((note = static_cast<wmNotifier *>(BLI_pophead(&wm->notifier_queue)))) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
Scene *scene = WM_window_get_active_scene(win);
bScreen *screen = WM_window_get_active_screen(win);
@@ -591,13 +593,13 @@ void wm_event_do_notifiers(bContext *C)
ED_screen_do_listen(C, note);
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
- wmRegionListenerParams region_params = {
- .window = win,
- .area = NULL,
- .region = region,
- .scene = scene,
- .notifier = note,
- };
+ wmRegionListenerParams region_params{};
+ region_params.window = win;
+ region_params.area = nullptr;
+ region_params.region = region;
+ region_params.scene = scene;
+ region_params.notifier = note;
+
ED_region_do_listen(&region_params);
}
@@ -609,21 +611,19 @@ void wm_event_do_notifiers(bContext *C)
continue;
}
}
- wmSpaceTypeListenerParams area_params = {
- .window = win,
- .area = area,
- .notifier = note,
- .scene = scene,
- };
+ wmSpaceTypeListenerParams area_params{};
+ area_params.window = win;
+ area_params.area = area;
+ area_params.notifier = note;
+ area_params.scene = scene;
ED_area_do_listen(&area_params);
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- wmRegionListenerParams region_params = {
- .window = win,
- .area = area,
- .region = region,
- .scene = scene,
- .notifier = note,
- };
+ wmRegionListenerParams region_params{};
+ region_params.window = win;
+ region_params.area = area;
+ region_params.region = region;
+ region_params.scene = scene;
+ region_params.notifier = note;
ED_region_do_listen(&region_params);
}
}
@@ -640,7 +640,7 @@ void wm_event_do_notifiers(bContext *C)
CTX_wm_window_set(C, win);
WM_msgbus_handle(wm->message_bus, C);
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
wm_event_do_refresh_wm_and_depsgraph(C);
@@ -650,7 +650,7 @@ void wm_event_do_notifiers(bContext *C)
wmWindow *win = wm->winactive;
CTX_wm_window_set(C, win);
WM_window_cursor_keymap_status_refresh(C, win);
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/* Auto-run warning. */
@@ -668,7 +668,7 @@ static int wm_event_always_pass(const wmEvent *event)
* don't cause non-passing handler return values, and thus actually pass.
*
* Can't be executed if the handler just loaded a file (typically identified by `CTX_wm_window(C)`
- * returning `NULL`), because the event will have been freed then.
+ * returning `nullptr`), because the event will have been freed then.
*/
BLI_INLINE void wm_event_handler_return_value_check(const wmEvent *event, const int action)
{
@@ -739,9 +739,9 @@ static int wm_handler_ui_call(bContext *C,
}
else {
/* This special cases is for areas and regions that get removed. */
- CTX_wm_area_set(C, NULL);
- CTX_wm_region_set(C, NULL);
- CTX_wm_menu_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_menu_set(C, nullptr);
}
if (retval == WM_UI_HANDLER_BREAK) {
@@ -768,12 +768,12 @@ void wm_event_handler_ui_cancel_ex(bContext *C,
LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &region->handlers) {
if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
- BLI_assert(handler->handle_fn != NULL);
+ BLI_assert(handler->handle_fn != nullptr);
wmEvent event;
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_CANCEL;
event.val = reactivate_button ? 0 : 1;
- event.flag = 0;
+ event.flag = (eWM_EventFlag)0;
handler->handle_fn(C, &event, handler->user_data);
}
}
@@ -796,24 +796,24 @@ static void wm_event_handler_ui_cancel(bContext *C)
void WM_report_banner_show(void)
{
- wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
ReportList *wm_reports = &wm->reports;
/* After adding reports to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm_reports->reporttimer);
+ WM_event_remove_timer(wm, nullptr, wm_reports->reporttimer);
/* Records time since last report was added. */
wm_reports->reporttimer = WM_event_add_timer(wm, wm->winactive, TIMERREPORT, 0.05);
- ReportTimerInfo *rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
+ ReportTimerInfo *rti = MEM_cnew<ReportTimerInfo>(__func__);
wm_reports->reporttimer->customdata = rti;
}
void WM_report_banners_cancel(Main *bmain)
{
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
BKE_reports_clear(&wm->reports);
- WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
+ WM_event_remove_timer(wm, nullptr, wm->reports.reporttimer);
}
#ifdef WITH_INPUT_NDOF
@@ -827,7 +827,7 @@ static void wm_add_reports(ReportList *reports)
{
/* If the caller owns them, handle this. */
if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
- wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
/* Add reports to the global list, otherwise they are not seen. */
BLI_movelisttolist(&wm->reports.list, &reports->list);
@@ -873,7 +873,7 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
{
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, 0);
+ wmOperatorType *ot_macro = WM_operatortype_find(macro->idname, false);
if (!WM_operator_poll(C, ot_macro)) {
return false;
@@ -894,15 +894,16 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot)
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);
+ return wm_operator_call_internal(
+ C, ot, nullptr, nullptr, static_cast<wmOperatorCallContext>(context), true, nullptr);
}
bool WM_operator_check_ui_empty(wmOperatorType *ot)
{
- if (ot->macro.first != NULL) {
+ if (ot->macro.first != nullptr) {
/* For macros, check all have exec() we can call. */
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
if (otm && !WM_operator_check_ui_empty(otm)) {
return false;
}
@@ -951,8 +952,8 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (win_prev == NULL) {
- CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+ if (win_prev == nullptr) {
+ CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first));
}
UI_popup_menu_reports(C, op->reports);
@@ -982,7 +983,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
/* Refresh Info Editor with reports immediately, even if op returned #OPERATOR_CANCELLED. */
if ((retval & OPERATOR_CANCELLED) && !BLI_listbase_is_empty(&op->reports->list)) {
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, nullptr);
}
/* If the caller owns them, handle this. */
wm_add_reports(op->reports);
@@ -1008,7 +1009,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
CLEAR,
} hud_status = NOP;
- op->customdata = NULL;
+ op->customdata = nullptr;
if (store) {
WM_operator_last_properties_store(op);
@@ -1064,7 +1065,7 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
}
}
else if (hud_status == CLEAR) {
- ED_area_type_hud_clear(wm, NULL);
+ ED_area_type_hud_clear(wm, nullptr);
}
else {
BLI_assert_unreachable();
@@ -1082,7 +1083,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
CTX_wm_operator_poll_msg_clear(C);
- if (op == NULL || op->type == NULL) {
+ if (op == nullptr || op->type == nullptr) {
return retval;
}
@@ -1130,7 +1131,7 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op)
{
int retval = OPERATOR_CANCELLED;
- if (op == NULL || op->type == NULL || op->type->exec == NULL) {
+ if (op == nullptr || op->type == nullptr || op->type->exec == nullptr) {
return retval;
}
@@ -1173,14 +1174,14 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op)
}
bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
{
- if (op->type->exec != NULL) {
+ if (op->type->exec != nullptr) {
return true;
}
if (op->opm) {
/* For macros, check all have exec() we can call. */
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- if (otm && otm->exec == NULL) {
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ if (otm && otm->exec == nullptr) {
return false;
}
}
@@ -1194,9 +1195,9 @@ bool WM_operator_is_repeat(const bContext *C, const wmOperator *op)
{
/* May be in the operators list or not. */
wmOperator *op_prev;
- if (op->prev == NULL && op->next == NULL) {
+ if (op->prev == nullptr && op->next == nullptr) {
wmWindowManager *wm = CTX_wm_manager(C);
- op_prev = wm->operators.last;
+ op_prev = static_cast<wmOperator *>(wm->operators.last);
}
else {
op_prev = op->prev;
@@ -1210,16 +1211,16 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
ReportList *reports)
{
/* Operator-type names are static still. pass to allocation name for debugging. */
- wmOperator *op = MEM_callocN(sizeof(wmOperator), ot->idname);
+ wmOperator *op = MEM_cnew<wmOperator>(ot->idname);
/* Adding new operator could be function, only happens here now. */
op->type = ot;
BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME);
/* Initialize properties, either copy or create. */
- op->ptr = MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA");
+ op->ptr = MEM_cnew<PointerRNA>("wmOperatorPtrRNA");
if (properties && properties->data) {
- op->properties = IDP_CopyProperty(properties->data);
+ op->properties = IDP_CopyProperty(static_cast<const IDProperty *>(properties->data));
}
else {
IDPropertyTemplate val = {0};
@@ -1232,36 +1233,36 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
op->reports = reports; /* Must be initialized already. */
}
else {
- op->reports = MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
+ op->reports = MEM_cnew<ReportList>("wmOperatorReportList");
BKE_reports_init(op->reports, RPT_STORE | RPT_FREE);
}
/* Recursive filling of operator macro list. */
if (ot->macro.first) {
- static wmOperator *motherop = NULL;
+ static wmOperator *motherop = nullptr;
int root = 0;
/* Ensure all ops are in execution order in 1 list. */
- if (motherop == NULL) {
+ if (motherop == nullptr) {
motherop = op;
root = 1;
}
/* If properties exist, it will contain everything needed. */
if (properties) {
- wmOperatorTypeMacro *otmacro = ot->macro.first;
+ wmOperatorTypeMacro *otmacro = static_cast<wmOperatorTypeMacro *>(ot->macro.first);
RNA_STRUCT_BEGIN (properties, prop) {
- if (otmacro == NULL) {
+ if (otmacro == nullptr) {
break;
}
/* Skip invalid properties. */
if (STREQ(RNA_property_identifier(prop), otmacro->idname)) {
- wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
+ wmOperatorType *otm = WM_operatortype_find(otmacro->idname, false);
PointerRNA someptr = RNA_property_pointer_get(properties, prop);
- wmOperator *opm = wm_operator_create(wm, otm, &someptr, NULL);
+ wmOperator *opm = wm_operator_create(wm, otm, &someptr, nullptr);
IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties);
@@ -1275,8 +1276,8 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
}
else {
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, NULL);
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, nullptr);
BLI_addtail(&motherop->macro, opm);
opm->opm = motherop; /* Pointer to mom, for modal(). */
@@ -1284,11 +1285,11 @@ static wmOperator *wm_operator_create(wmWindowManager *wm,
}
if (root) {
- motherop = NULL;
+ motherop = nullptr;
}
}
- WM_operator_properties_sanitize(op->ptr, 0);
+ WM_operator_properties_sanitize(op->ptr, false);
return op;
}
@@ -1302,12 +1303,12 @@ static void wm_region_tag_draw_on_gizmo_delay_refresh_for_tweak(wmWindow *win)
bScreen *screen = WM_window_get_active_screen(win);
/* Unlikely but not impossible as this runs after events have been handled. */
- if (UNLIKELY(screen == NULL)) {
+ if (UNLIKELY(screen == nullptr)) {
return;
}
ED_screen_areas_iter (win, screen, area) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- if (region->gizmo_map != NULL) {
+ if (region->gizmo_map != nullptr) {
if (WM_gizmomap_tag_delay_refresh_for_tweak_check(region->gizmo_map)) {
ED_region_tag_redraw(region);
}
@@ -1332,7 +1333,7 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
}
/**
- * Also used for exec when 'event' is NULL.
+ * Also used for exec when 'event' is nullptr.
*/
static int wm_operator_invoke(bContext *C,
wmOperatorType *ot,
@@ -1353,12 +1354,12 @@ static int wm_operator_invoke(bContext *C,
if (WM_operator_poll(C, ot)) {
wmWindowManager *wm = CTX_wm_manager(C);
- /* If `reports == NULL`, they'll be initialized. */
+ /* If `reports == nullptr`, they'll be initialized. */
wmOperator *op = wm_operator_create(wm, ot, properties, reports);
const bool is_nested_call = (wm->op_undo_depth != 0);
- if (event != NULL) {
+ if (event != nullptr) {
op->flag |= OP_IS_INVOKE;
}
@@ -1367,7 +1368,7 @@ static int wm_operator_invoke(bContext *C,
WM_operator_last_properties_init(op);
}
- if ((event == NULL) || (event->type != MOUSEMOVE)) {
+ if ((event == nullptr) || (event->type != MOUSEMOVE)) {
CLOG_INFO(WM_LOG_HANDLERS,
2,
"handle evt %d win %p op %s",
@@ -1377,22 +1378,20 @@ static int wm_operator_invoke(bContext *C,
}
if (op->type->invoke && event) {
- /* Temporarily write into `mval` (not technically `const` correct) but this is restored. */
- int mval_prev[2] = {UNPACK2(event->mval)};
- wm_region_mouse_co(C, (wmEvent *)event);
+ /* Make a copy of the event as it's `const` and the #wmEvent.mval to be written into. */
+ wmEvent event_temp = *event;
+ wm_region_mouse_co(C, &event_temp);
if (op->type->flag & OPTYPE_UNDO) {
wm->op_undo_depth++;
}
- retval = op->type->invoke(C, op, event);
+ retval = op->type->invoke(C, op, &event_temp);
OPERATOR_RETVAL_CHECK(retval);
if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) {
wm->op_undo_depth--;
}
-
- copy_v2_v2_int(((wmEvent *)event)->mval, mval_prev);
}
else if (op->type->exec) {
if (op->type->flag & OPTYPE_UNDO) {
@@ -1415,7 +1414,7 @@ static int wm_operator_invoke(bContext *C,
* them currently Python only uses this. */
if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) {
/* Only show the report if the report list was not given in the function. */
- wm_operator_reports(C, op, retval, (reports != NULL));
+ wm_operator_reports(C, op, retval, (reports != nullptr));
}
if (retval & OPERATOR_HANDLED) {
@@ -1451,7 +1450,7 @@ static int wm_operator_invoke(bContext *C,
}
if (wrap) {
- const rcti *winrect = NULL;
+ const rcti *winrect = nullptr;
ARegion *region = CTX_wm_region(C);
ScrArea *area = CTX_wm_area(C);
@@ -1514,7 +1513,7 @@ static int wm_operator_call_internal(bContext *C,
if (ot) {
wmWindow *window = CTX_wm_window(C);
- if (event == NULL) {
+ if (event == nullptr) {
switch (context) {
case WM_OP_INVOKE_DEFAULT:
case WM_OP_INVOKE_REGION_WIN:
@@ -1523,7 +1522,7 @@ static int wm_operator_call_internal(bContext *C,
case WM_OP_INVOKE_AREA:
case WM_OP_INVOKE_SCREEN:
/* Window is needed for invoke and cancel operators. */
- if (window == NULL) {
+ if (window == nullptr) {
if (poll_only) {
CTX_wm_operator_poll_msg_set(C, "Missing 'window' in context");
}
@@ -1534,7 +1533,7 @@ static int wm_operator_call_internal(bContext *C,
}
break;
default:
- event = NULL;
+ event = nullptr;
break;
}
}
@@ -1546,7 +1545,7 @@ static int wm_operator_call_internal(bContext *C,
case WM_OP_EXEC_REGION_CHANNELS:
case WM_OP_EXEC_AREA:
case WM_OP_EXEC_SCREEN:
- event = NULL;
+ event = nullptr;
default:
break;
}
@@ -1604,7 +1603,7 @@ static int wm_operator_call_internal(bContext *C,
/* Remove region from context. */
ARegion *region = CTX_wm_region(C);
- CTX_wm_region_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_region_set(C, region);
@@ -1616,8 +1615,8 @@ static int wm_operator_call_internal(bContext *C,
ARegion *region = CTX_wm_region(C);
ScrArea *area = CTX_wm_area(C);
- CTX_wm_region_set(C, NULL);
- CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_area_set(C, nullptr);
retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -1640,7 +1639,7 @@ int WM_operator_name_call_ptr(bContext *C,
const wmEvent *event)
{
BLI_assert(ot == WM_operatortype_find(ot->idname, true));
- return wm_operator_call_internal(C, ot, properties, NULL, context, false, event);
+ return wm_operator_call_internal(C, ot, properties, nullptr, context, false, event);
}
int WM_operator_name_call(bContext *C,
const char *opstring,
@@ -1648,7 +1647,7 @@ int WM_operator_name_call(bContext *C,
PointerRNA *properties,
const wmEvent *event)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (ot) {
return WM_operator_name_call_ptr(C, ot, context, properties, event);
}
@@ -1658,7 +1657,7 @@ int WM_operator_name_call(bContext *C,
bool WM_operator_name_poll(bContext *C, const char *opstring)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (!ot) {
return false;
}
@@ -1666,15 +1665,16 @@ bool WM_operator_name_poll(bContext *C, const char *opstring)
return WM_operator_poll(C, ot);
}
-int WM_operator_name_call_with_properties(struct bContext *C,
+int WM_operator_name_call_with_properties(bContext *C,
const char *opstring,
wmOperatorCallContext context,
- struct IDProperty *properties,
+ IDProperty *properties,
const wmEvent *event)
{
PointerRNA props_ptr;
wmOperatorType *ot = WM_operatortype_find(opstring, false);
- RNA_pointer_create(G_MAIN->wm.first, ot->srna, properties, &props_ptr);
+ RNA_pointer_create(
+ &static_cast<wmWindowManager *>(G_MAIN->wm.first)->id, ot->srna, properties, &props_ptr);
return WM_operator_name_call_ptr(C, ot, context, &props_ptr, event);
}
@@ -1684,7 +1684,7 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context)
PointerRNA ptr;
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "name", menu_name);
- WM_operator_name_call_ptr(C, ot, context, &ptr, NULL);
+ WM_operator_name_call_ptr(C, ot, static_cast<wmOperatorCallContext>(context), &ptr, nullptr);
WM_operator_properties_free(&ptr);
}
@@ -1703,7 +1703,7 @@ int WM_operator_call_py(bContext *C,
wm->op_undo_depth++;
}
- retval = wm_operator_call_internal(C, ot, properties, reports, context, false, NULL);
+ retval = wm_operator_call_internal(C, ot, properties, reports, context, false, nullptr);
if (!is_undo && wm && (wm == CTX_wm_manager(C))) {
wm->op_undo_depth--;
@@ -1722,18 +1722,18 @@ int WM_operator_call_py(bContext *C,
* See: #OPTYPE_DEPENDS_ON_CURSOR doc-string for more information.
* \{ */
-typedef struct uiOperatorWaitForInput {
+struct uiOperatorWaitForInput {
ScrArea *area;
wmOperatorCallParams optype_params;
bContextStore *context;
-} uiOperatorWaitForInput;
+};
static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
{
- uiOperatorWaitForInput *opwait = userdata;
+ uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata);
if (opwait->optype_params.opptr) {
if (opwait->optype_params.opptr->data) {
- IDP_FreeProperty(opwait->optype_params.opptr->data);
+ IDP_FreeProperty(static_cast<IDProperty *>(opwait->optype_params.opptr->data));
}
MEM_freeN(opwait->optype_params.opptr);
}
@@ -1741,11 +1741,11 @@ static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
CTX_store_free(opwait->context);
}
- if (opwait->area != NULL) {
- ED_area_status_text(opwait->area, NULL);
+ if (opwait->area != nullptr) {
+ ED_area_status_text(opwait->area, nullptr);
}
else {
- ED_workspace_status_text(C, NULL);
+ ED_workspace_status_text(C, nullptr);
}
MEM_freeN(opwait);
@@ -1753,7 +1753,7 @@ static void ui_handler_wait_for_input_remove(bContext *C, void *userdata)
static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *userdata)
{
- uiOperatorWaitForInput *opwait = userdata;
+ uiOperatorWaitForInput *opwait = static_cast<uiOperatorWaitForInput *>(userdata);
enum { CONTINUE = 0, EXECUTE, CANCEL } state = CONTINUE;
state = CONTINUE;
@@ -1798,7 +1798,7 @@ static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *us
opwait->optype_params.opcontext,
opwait->optype_params.opptr,
event);
- CTX_store_set(C, NULL);
+ CTX_store_set(C, nullptr);
}
WM_event_remove_ui_handler(&win->modalhandlers,
@@ -1825,8 +1825,8 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
int flag = ot->flag;
LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) {
- wmOperatorType *otm = WM_operatortype_find(macro->idname, 0);
- if (otm != NULL) {
+ wmOperatorType *otm = WM_operatortype_find(macro->idname, false);
+ if (otm != nullptr) {
flag |= otm->flag;
}
}
@@ -1840,7 +1840,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *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;
+ ScrArea *area = WM_OP_CONTEXT_HAS_AREA(opcontext) ? CTX_wm_area(C) : nullptr;
{
char header_text[UI_MAX_DRAW_STR];
@@ -1848,7 +1848,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
"%s %s",
IFACE_("Input pending "),
(drawstr && drawstr[0]) ? drawstr : CTX_IFACE_(ot->translation_context, ot->name));
- if (area != NULL) {
+ if (area != nullptr) {
ED_area_status_text(area, header_text);
}
else {
@@ -1858,7 +1858,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
WM_cursor_modal_set(win, ot->cursor_pending);
- uiOperatorWaitForInput *opwait = MEM_callocN(sizeof(*opwait), __func__);
+ uiOperatorWaitForInput *opwait = MEM_cnew<uiOperatorWaitForInput>(__func__);
opwait->optype_params.optype = ot;
opwait->optype_params.opcontext = opcontext;
opwait->optype_params.opptr = properties;
@@ -1866,10 +1866,11 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C,
opwait->area = area;
if (properties) {
- opwait->optype_params.opptr = MEM_mallocN(sizeof(*opwait->optype_params.opptr), __func__);
+ opwait->optype_params.opptr = MEM_cnew<PointerRNA>(__func__);
*opwait->optype_params.opptr = *properties;
- if (properties->data != NULL) {
- opwait->optype_params.opptr->data = IDP_CopyProperty(properties->data);
+ if (properties->data != nullptr) {
+ opwait->optype_params.opptr->data = IDP_CopyProperty(
+ static_cast<IDProperty *>(properties->data));
}
}
@@ -1916,18 +1917,18 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
* possible. */
bScreen *screen = handler->context.win ? WM_window_get_active_screen(win) : CTX_wm_screen(C);
- *r_area = NULL;
- *r_region = NULL;
+ *r_area = nullptr;
+ *r_region = nullptr;
- if (screen == NULL || handler->op == NULL) {
+ if (screen == nullptr || handler->op == nullptr) {
return;
}
- if (handler->context.area == NULL) {
+ if (handler->context.area == nullptr) {
/* Pass */
}
else {
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
ED_screen_areas_iter (win, screen, area_iter) {
if (area_iter == handler->context.area) {
@@ -1936,10 +1937,10 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
}
}
- if (area == NULL) {
+ if (area == nullptr) {
/* When changing screen layouts with running modal handlers (like render display), this
* is not an error to print. */
- if (handler->op == NULL) {
+ if (handler->op == nullptr) {
CLOG_ERROR(WM_LOG_HANDLERS,
"internal error: handler (%s) has invalid area",
handler->op->type->idname);
@@ -1947,7 +1948,7 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
}
else {
ARegion *region;
- wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL;
+ wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : nullptr;
*r_area = area;
if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
@@ -1957,10 +1958,10 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
}
}
else {
- region = NULL;
+ region = nullptr;
}
- if ((region == NULL) && handler->context.region) {
+ if ((region == nullptr) && handler->context.region) {
if (BLI_findindex(&area->regionbase, handler->context.region) != -1) {
region = handler->context.region;
}
@@ -1976,8 +1977,8 @@ static void wm_handler_op_context_get_if_valid(bContext *C,
static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const wmEvent *event)
{
- ScrArea *area = NULL;
- ARegion *region = NULL;
+ ScrArea *area = nullptr;
+ ARegion *region = nullptr;
wm_handler_op_context_get_if_valid(C, handler, event, &area, &region);
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -1989,7 +1990,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
/* C is zero on freeing database, modal handlers then already were freed. */
wmEventHandler *handler_base;
- while ((handler_base = BLI_pophead(handlers))) {
+ while ((handler_base = static_cast<wmEventHandler *>(BLI_pophead(handlers)))) {
BLI_assert(handler_base->type != 0);
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
@@ -2028,7 +2029,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
CTX_wm_region_set(C, region);
}
- WM_cursor_grab_disable(win, NULL);
+ WM_cursor_grab_disable(win, nullptr);
if (handler->is_fileselect) {
wm_operator_free_for_fileselect(handler->op);
@@ -2085,9 +2086,7 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
/* The matching rules. */
if (kmitype == KM_TEXTINPUT) {
if (winevent->val == KM_PRESS) { /* Prevent double clicks. */
- /* Not using #ISTEXTINPUT anymore because (at least on Windows) some key codes above 255
- * could have printable ascii keys, See T30479. */
- if (ISKEYBOARD(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) {
+ if (ISKEYBOARD(winevent->type) && winevent->utf8_buf[0]) {
return true;
}
}
@@ -2132,25 +2131,26 @@ static bool wm_eventmatch(const wmEvent *winevent, const wmKeyMapItem *kmi)
/* Account for rare case of when these keys are used as the 'type' not as modifiers. */
if (kmi->shift != KM_ANY) {
const bool shift = (winevent->modifier & KM_SHIFT) != 0;
- if ((shift != kmi->shift) && !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
+ if ((shift != (bool)kmi->shift) &&
+ !ELEM(winevent->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY)) {
return false;
}
}
if (kmi->ctrl != KM_ANY) {
const bool ctrl = (winevent->modifier & KM_CTRL) != 0;
- if (ctrl != kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ if (ctrl != (bool)kmi->ctrl && !ELEM(winevent->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
return false;
}
}
if (kmi->alt != KM_ANY) {
const bool alt = (winevent->modifier & KM_ALT) != 0;
- if (alt != kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
+ if (alt != (bool)kmi->alt && !ELEM(winevent->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY)) {
return false;
}
}
if (kmi->oskey != KM_ANY) {
const bool oskey = (winevent->modifier & KM_OSKEY) != 0;
- if ((oskey != kmi->oskey) && (winevent->type != EVT_OSKEY)) {
+ if ((oskey != (bool)kmi->oskey) && (winevent->type != EVT_OSKEY)) {
return false;
}
}
@@ -2175,12 +2175,12 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap,
/* Should already be handled by #wm_user_modal_keymap_set_items. */
BLI_assert(kmi->propvalue_str[0] == '\0');
if (wm_eventmatch(event, kmi)) {
- if ((keymap->poll_modal_item == NULL) || (keymap->poll_modal_item(op, kmi->propvalue))) {
+ if ((keymap->poll_modal_item == nullptr) || (keymap->poll_modal_item(op, kmi->propvalue))) {
return kmi;
}
}
}
- return NULL;
+ return nullptr;
}
struct wmEvent_ModalMapStore {
@@ -2203,7 +2203,7 @@ struct wmEvent_ModalMapStore {
static void wm_event_modalkeymap_begin(const bContext *C,
wmOperator *op,
wmEvent *event,
- struct wmEvent_ModalMapStore *event_backup)
+ wmEvent_ModalMapStore *event_backup)
{
BLI_assert(event->type != EVT_MODAL_MAP);
@@ -2216,9 +2216,9 @@ static void wm_event_modalkeymap_begin(const bContext *C,
if (op->type->modalkeymap) {
wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
- wmKeyMapItem *kmi = NULL;
+ wmKeyMapItem *kmi = nullptr;
- const wmEvent *event_match = NULL;
+ const wmEvent *event_match = nullptr;
wmEvent event_no_dbl_click;
if ((kmi = wm_eventmatch_modal_keymap_items(keymap, op, event))) {
@@ -2232,7 +2232,7 @@ static void wm_event_modalkeymap_begin(const bContext *C,
}
}
- if (event_match != NULL) {
+ if (event_match != nullptr) {
event_backup->prev_type = event->prev_type;
event_backup->prev_val = event->prev_val;
@@ -2267,8 +2267,7 @@ static void wm_event_modalkeymap_begin(const bContext *C,
* better restore event type for checking of #KM_CLICK for example.
* Modal maps could use different method (ton).
*/
-static void wm_event_modalkeymap_end(wmEvent *event,
- const struct wmEvent_ModalMapStore *event_backup)
+static void wm_event_modalkeymap_end(wmEvent *event, const wmEvent_ModalMapStore *event_backup)
{
if (event->type == EVT_MODAL_MAP) {
event->type = event->prev_type;
@@ -2297,7 +2296,7 @@ static int wm_handler_operator_call(bContext *C,
/* Derived, modal or blocking operator. */
if ((handler_base->type == WM_HANDLER_TYPE_OP) &&
- (((wmEventHandler_Op *)handler_base)->op != NULL)) {
+ (((wmEventHandler_Op *)handler_base)->op != nullptr)) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
wmOperator *op = handler->op;
wmOperatorType *ot = op->type;
@@ -2316,7 +2315,7 @@ static int wm_handler_operator_call(bContext *C,
wm_handler_op_context(C, handler, event);
wm_region_mouse_co(C, event);
- struct wmEvent_ModalMapStore event_backup;
+ wmEvent_ModalMapStore event_backup;
wm_event_modalkeymap_begin(C, op, event, &event_backup);
if (ot->flag & OPTYPE_UNDO) {
@@ -2352,14 +2351,14 @@ static int wm_handler_operator_call(bContext *C,
}
}
- /* Important to run 'wm_operator_finished' before NULL-ing the context members. */
+ /* Important to run 'wm_operator_finished' before setting the context members to null. */
if (retval & OPERATOR_FINISHED) {
wm_operator_finished(C, op, false, true);
- handler->op = NULL;
+ handler->op = nullptr;
}
else if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
WM_operator_free(op);
- handler->op = NULL;
+ handler->op = nullptr;
}
/* Putting back screen context, `reval` can pass through after modal failures! */
@@ -2369,8 +2368,8 @@ static int wm_handler_operator_call(bContext *C,
}
else {
/* This special cases is for areas and regions that get removed. */
- CTX_wm_area_set(C, NULL);
- CTX_wm_region_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
+ CTX_wm_region_set(C, nullptr);
}
/* Update gizmos during modal handlers. */
@@ -2378,7 +2377,7 @@ static int wm_handler_operator_call(bContext *C,
/* Remove modal handler, operator itself should have been canceled and freed. */
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
- WM_cursor_grab_disable(CTX_wm_window(C), NULL);
+ WM_cursor_grab_disable(CTX_wm_window(C), nullptr);
BLI_remlink(handlers, handler);
wm_event_free_handler(&handler->head);
@@ -2393,13 +2392,13 @@ static int wm_handler_operator_call(bContext *C,
}
}
else {
- wmOperatorType *ot = WM_operatortype_find(kmi_idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi_idname, false);
if (ot && wm_operator_check_locked_interface(C, ot)) {
bool use_last_properties = true;
- PointerRNA tool_properties = {0};
+ PointerRNA tool_properties = {nullptr};
- bToolRef *keymap_tool = NULL;
+ bToolRef *keymap_tool = nullptr;
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
keymap_tool = ((wmEventHandler_Keymap *)handler_base)->keymap_tool;
}
@@ -2411,7 +2410,7 @@ static int wm_handler_operator_call(bContext *C,
}
}
- const bool is_tool = (keymap_tool != NULL);
+ const bool is_tool = (keymap_tool != nullptr);
const bool use_tool_properties = is_tool;
if (use_tool_properties) {
@@ -2421,7 +2420,7 @@ static int wm_handler_operator_call(bContext *C,
use_last_properties = false;
}
- retval = wm_operator_invoke(C, ot, event, properties, NULL, false, use_last_properties);
+ retval = wm_operator_invoke(C, ot, event, properties, nullptr, false, use_last_properties);
if (use_tool_properties) {
WM_operator_properties_free(&tool_properties);
@@ -2434,10 +2433,10 @@ static int wm_handler_operator_call(bContext *C,
if (tref_rt->gizmo_group[0]) {
const char *idname = tref_rt->gizmo_group;
wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false);
- if (gzgt != NULL) {
+ if (gzgt != nullptr) {
if ((gzgt->flag & WM_GIZMOGROUPTYPE_TOOL_INIT) != 0) {
ARegion *region = CTX_wm_region(C);
- if (region != NULL) {
+ if (region != nullptr) {
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
WM_gizmo_group_type_ensure_ptr_ex(gzgt, gzmap_type);
wmGizmoGroup *gzgroup = WM_gizmomaptype_group_init_runtime_with_region(
@@ -2477,9 +2476,9 @@ static void wm_operator_free_for_fileselect(wmOperator *file_operator)
LISTBASE_FOREACH (bScreen *, screen, &G_MAIN->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_FILE) {
- SpaceFile *sfile = area->spacedata.first;
+ SpaceFile *sfile = static_cast<SpaceFile *>(area->spacedata.first);
if (sfile->op == file_operator) {
- sfile->op = NULL;
+ sfile->op = nullptr;
}
}
}
@@ -2551,16 +2550,16 @@ static int wm_handler_fileselect_do(bContext *C,
if (val == EVT_FILESELECT_EXTERNAL_CANCEL) {
/* The window might have been freed already. */
if (BLI_findindex(&wm->windows, handler->context.win) == -1) {
- handler->context.win = NULL;
+ handler->context.win = nullptr;
}
}
else {
ScrArea *ctx_area = CTX_wm_area(C);
- wmWindow *temp_win = NULL;
+ wmWindow *temp_win = nullptr;
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- ScrArea *file_area = screen->areabase.first;
+ ScrArea *file_area = static_cast<ScrArea *>(screen->areabase.first);
if ((file_area->spacetype != SPACE_FILE) || !WM_window_is_temp_screen(win)) {
continue;
@@ -2576,14 +2575,15 @@ static int wm_handler_fileselect_do(bContext *C,
int win_size[2];
bool is_maximized;
ED_fileselect_window_params_get(win, win_size, &is_maximized);
- ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized);
+ ED_fileselect_params_to_userdef(
+ static_cast<SpaceFile *>(file_area->spacedata.first), win_size, is_maximized);
if (BLI_listbase_is_single(&file_area->spacedata)) {
BLI_assert(root_win != win);
wm_window_close(C, wm, win);
- CTX_wm_window_set(C, root_win); /* #wm_window_close() NULLs. */
+ CTX_wm_window_set(C, root_win); /* #wm_window_close() nullptrs. */
/* Some operators expect a drawable context (for #EVT_FILESELECT_EXEC). */
wm_window_make_drawable(wm, root_win);
/* Ensure correct cursor position, otherwise, popups may close immediately after
@@ -2603,7 +2603,8 @@ static int wm_handler_fileselect_do(bContext *C,
}
if (!temp_win && ctx_area->full) {
- ED_fileselect_params_to_userdef(ctx_area->spacedata.first, NULL, false);
+ ED_fileselect_params_to_userdef(
+ static_cast<SpaceFile *>(ctx_area->spacedata.first), nullptr, false);
ED_screen_full_prevspace(C, ctx_area);
}
}
@@ -2656,8 +2657,8 @@ static int wm_handler_fileselect_do(bContext *C,
ScrArea *area_prev = CTX_wm_area(C);
ARegion *region_prev = CTX_wm_region(C);
- if (win_prev == NULL) {
- CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+ if (win_prev == nullptr) {
+ CTX_wm_window_set(C, static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first));
}
BKE_report_print_level_set(handler->op->reports, RPT_WARNING);
@@ -2701,7 +2702,7 @@ static int wm_handler_fileselect_do(bContext *C,
wm_operator_free_for_fileselect(handler->op);
}
- CTX_wm_area_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
wm_event_free_handler(&handler->head);
@@ -2763,18 +2764,18 @@ static const char *keymap_handler_log_kmi_op_str(bContext *C,
size_t buf_maxlen)
{
/* 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);
+ char *kmi_props = nullptr;
+ if (kmi->properties != nullptr) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
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);
+ kmi_props = IDP_reprN(kmi->properties, nullptr);
}
}
BLI_snprintf(buf, buf_maxlen, "%s(%s)", kmi->idname, kmi_props ? kmi_props : "");
- if (kmi_props != NULL) {
+ if (kmi_props != nullptr) {
MEM_freeN(kmi_props);
}
return buf;
@@ -2796,8 +2797,8 @@ static int wm_handlers_do_keymap_with_keymap_handler(
{
int action = WM_HANDLER_CONTINUE;
- if (keymap == NULL) {
- /* Only callback is allowed to have NULL key-maps. */
+ if (keymap == nullptr) {
+ /* Only callback is allowed to have nullptr key-maps. */
BLI_assert(handler->dynamic.keymap_fn);
}
else {
@@ -2809,7 +2810,7 @@ static int wm_handlers_do_keymap_with_keymap_handler(
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (wm_eventmatch(event, kmi)) {
- struct wmEventHandler_KeymapPost keymap_post = handler->post;
+ wmEventHandler_KeymapPost keymap_post = handler->post;
action |= wm_handler_operator_call(
C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
@@ -2826,7 +2827,7 @@ static int wm_handlers_do_keymap_with_keymap_handler(
if (action & WM_HANDLER_BREAK) {
/* Not always_pass here, it denotes removed handler_base. */
- if (keymap_post.post_fn != NULL) {
+ if (keymap_post.post_fn != nullptr) {
keymap_post.post_fn(keymap, kmi, keymap_post.user_data);
}
break;
@@ -2872,7 +2873,7 @@ static int wm_handlers_do_keymap_with_gizmo_handler(
action |= wm_handler_operator_call(
C, handlers, &handler->head, event, kmi->ptr, kmi->idname);
- CTX_wm_gizmo_group_set(C, NULL);
+ CTX_wm_gizmo_group_set(C, nullptr);
if (action & WM_HANDLER_BREAK) {
if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
@@ -2922,7 +2923,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
wmGizmoMap *gzmap = handler->gizmo_map;
- BLI_assert(gzmap != NULL);
+ BLI_assert(gzmap != nullptr);
wmGizmo *gz = wm_gizmomap_highlight_get(gzmap);
/* Needed so UI blocks over gizmos don't let events fall through to the gizmos,
@@ -2930,25 +2931,25 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
* 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->xy, true)) {
- if (gz != NULL && event->type != EVT_GIZMO_UPDATE) {
+ if (gz != nullptr && event->type != EVT_GIZMO_UPDATE) {
if (restore_highlight_unless_activated == false) {
WM_tooltip_clear(C, CTX_wm_window(C));
- wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
+ wm_gizmomap_highlight_set(gzmap, C, nullptr, 0);
}
}
return action;
}
}
- struct {
+ struct PrevGizmoData {
wmGizmo *gz_modal;
wmGizmo *gz;
int part;
- } prev = {
- .gz_modal = wm_gizmomap_modal_get(gzmap),
- .gz = gz,
- .part = gz ? gz->highlight_part : 0,
};
+ PrevGizmoData prev{};
+ prev.gz_modal = wm_gizmomap_modal_get(gzmap);
+ prev.gz = gz;
+ prev.part = gz ? gz->highlight_part : 0;
if (region->gizmo_map != handler->gizmo_map) {
WM_gizmomap_tag_refresh(handler->gizmo_map);
@@ -2961,7 +2962,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
bool handle_keymap = false;
/* Handle gizmo highlighting. */
- if ((prev.gz_modal == NULL) &&
+ if ((prev.gz_modal == nullptr) &&
((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) {
handle_highlight = true;
if (is_event_modifier || is_event_drag) {
@@ -2992,7 +2993,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
}
if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) {
- if (gz != NULL) {
+ if (gz != nullptr) {
if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) {
WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init);
}
@@ -3005,7 +3006,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if (handle_keymap) {
/* Handle highlight gizmo. */
- if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
+ if ((gz != nullptr) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) {
bool keymap_poll = false;
wmGizmoGroup *gzgroup = gz->parent_gzgroup;
wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap);
@@ -3026,7 +3027,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if ((kmi->flag & KMI_INACTIVE) == 0) {
if (wm_eventmatch(&event_test_click, kmi) ||
wm_eventmatch(&event_test_click_drag, kmi)) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
is_event_handle_all = true;
break;
@@ -3040,7 +3041,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
}
/* Don't use from now on. */
- gz = NULL;
+ gz = nullptr;
/* Fallback to selected gizmo (when un-handled). */
if ((action & WM_HANDLER_BREAK) == 0) {
@@ -3050,7 +3051,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C,
if (wm_gizmogroup_is_any_selected(gzgroup)) {
wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap);
action |= wm_handlers_do_keymap_with_gizmo_handler(
- C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL);
+ C, event, handlers, handler, gzgroup, keymap, do_debug_handler, nullptr);
if (action & WM_HANDLER_BREAK) {
break;
}
@@ -3099,7 +3100,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
wmWindowManager *wm = CTX_wm_manager(C);
int action = WM_HANDLER_CONTINUE;
- if (handlers == NULL) {
+ if (handlers == nullptr) {
wm_event_handler_return_value_check(event, action);
return action;
}
@@ -3110,7 +3111,8 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
* by the event that's called, for eg:
*
* Calling a python script which changes the area.type, see T32232. */
- for (wmEventHandler *handler_base = handlers->first, *handler_base_next;
+ for (wmEventHandler *handler_base = static_cast<wmEventHandler *>(handlers->first),
+ *handler_base_next;
handler_base && handlers->first;
handler_base = handler_base_next) {
handler_base_next = handler_base->next;
@@ -3119,7 +3121,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
if (handler_base->flag & WM_HANDLER_DO_FREE) {
/* Pass. */
}
- else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) {
+ else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) {
/* In advance to avoid access to freed event on window close. */
const int always_pass = wm_event_always_pass(event);
@@ -3148,14 +3150,14 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
* are kept when a modal operators starts (annoying but otherwise harmless). */
if (action & WM_HANDLER_BREAK) {
/* Window may be gone after file read. */
- if (CTX_wm_window(C) != NULL) {
+ if (CTX_wm_window(C) != nullptr) {
WM_tooltip_clear(C, CTX_wm_window(C));
}
}
}
else if (handler_base->type == WM_HANDLER_TYPE_UI) {
wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base;
- BLI_assert(handler->handle_fn != NULL);
+ BLI_assert(handler->handle_fn != nullptr);
if (!wm->is_interface_locked) {
action |= wm_handler_ui_call(C, handler, event, always_pass);
}
@@ -3173,13 +3175,13 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
/* Pass single matched #wmDrag onto the operator. */
BLI_remlink(lb, drag);
- ListBase single_lb = {0};
+ ListBase single_lb = {nullptr};
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, opcontext, false, event);
+ C, drop->ot, drop->ptr, nullptr, opcontext, false, event);
OPERATOR_RETVAL_CHECK(op_retval);
if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) {
@@ -3197,7 +3199,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
wm_drop_end(C, drag, drop);
/* XXX file-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
return action;
}
@@ -3224,7 +3226,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
}
}
else {
- action |= wm_handler_operator_call(C, handlers, handler_base, event, NULL, NULL);
+ action |= wm_handler_operator_call(C, handlers, handler_base, event, nullptr, nullptr);
}
}
else {
@@ -3244,7 +3246,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
/* File-read case, if the wm is freed then the handler's
* will have been too so the code below need not run. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
return action;
}
@@ -3265,7 +3267,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis
}
/* Do some extra sanity checking before returning the action. */
- if (CTX_wm_window(C) != NULL) {
+ if (CTX_wm_window(C) != nullptr) {
wm_event_handler_return_value_check(event, action);
}
return action;
@@ -3278,9 +3280,9 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
{
int action = wm_handlers_do_intern(C, CTX_wm_window(C), event, handlers);
- /* Will be NULL in the file read case. */
+ /* Will be nullptr in the file read case. */
wmWindow *win = CTX_wm_window(C);
- if (win == NULL) {
+ if (win == nullptr) {
return action;
}
@@ -3370,11 +3372,10 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
}
}
- if (event->prev_press_type == event->type) {
-
- if (event->val == KM_RELEASE) {
+ if (event->val == KM_RELEASE) {
+ if (event->prev_press_type == event->type) {
if (event->prev_val == KM_PRESS) {
- if (win->event_queue_check_click == true) {
+ if (win->event_queue_check_click) {
if (WM_event_drag_test(event, event->prev_press_xy)) {
win->event_queue_check_click = false;
if (win->event_queue_check_drag) {
@@ -3387,7 +3388,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
else {
/* Position is where the actual click happens, for more
* accurate selecting in case the mouse drifts a little. */
- int xy[2] = {UNPACK2(event->xy)};
+ const int xy[2] = {UNPACK2(event->xy)};
copy_v2_v2_int(event->xy, event->prev_press_xy);
event->val = KM_CLICK;
@@ -3402,15 +3403,15 @@ 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, win, event, 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, win, event, handlers);
- /* Revert value if not handled. */
- if (wm_action_not_handled(action)) {
- event->val = KM_DBL_CLICK;
- }
+ /* Revert value if not handled. */
+ if (wm_action_not_handled(action)) {
+ event->val = KM_DBL_CLICK;
}
}
}
@@ -3474,7 +3475,7 @@ static ScrArea *area_event_inside(bContext *C, const int xy[2])
}
}
}
- return NULL;
+ return nullptr;
}
static ARegion *region_event_inside(bContext *C, const int xy[2])
@@ -3489,14 +3490,14 @@ static ARegion *region_event_inside(bContext *C, const int xy[2])
}
}
}
- return NULL;
+ return nullptr;
}
static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *region)
{
if (region) {
for (; pc; pc = pc->next) {
- if (pc->poll == NULL || pc->poll(C)) {
+ if (pc->poll == nullptr || pc->poll(C)) {
wmWindow *win = CTX_wm_window(C);
WM_paint_cursor_tag_redraw(win, region);
}
@@ -3517,17 +3518,18 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
ARegion *region = CTX_wm_region(C);
if (region) {
- wm_paintcursor_tag(C, wm->paintcursors.first, region);
+ wm_paintcursor_tag(C, static_cast<wmPaintCursor *>(wm->paintcursors.first), region);
}
/* 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->prev_xy)) {
+ if (region == nullptr || !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->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));
+ wm_paintcursor_tag(
+ C, static_cast<wmPaintCursor *>(wm->paintcursors.first), CTX_wm_region(C));
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
@@ -3644,27 +3646,29 @@ static void wm_event_handle_xrevent(bContext *C,
int action = wm_handlers_do(C, event, &win->modalhandlers);
if ((action & WM_HANDLER_BREAK) == 0) {
- wmXrActionData *actiondata = event->customdata;
+ wmXrActionData *actiondata = static_cast<wmXrActionData *>(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};
+ PointerRNA properties{};
+ properties.type = actiondata->ot->srna;
+ properties.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,
+ actiondata->op_properties ? &properties : nullptr,
+ nullptr,
false,
false);
}
else {
/* Execute operator. */
wmOperator *op = wm_operator_create(
- wm, actiondata->ot, actiondata->op_properties ? &properties : NULL, NULL);
+ wm, actiondata->ot, actiondata->op_properties ? &properties : nullptr, nullptr);
if ((WM_operator_call(C, op) & OPERATOR_HANDLED) == 0) {
WM_operator_free(op);
}
@@ -3672,8 +3676,8 @@ static void wm_event_handle_xrevent(bContext *C,
}
}
- CTX_wm_region_set(C, NULL);
- CTX_wm_area_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
+ CTX_wm_area_set(C, nullptr);
}
#endif /* WITH_XR_OPENXR */
@@ -3743,16 +3747,16 @@ void wm_event_do_handlers(bContext *C)
BLI_assert(WM_window_get_active_screen(win));
BLI_assert(WM_window_get_active_workspace(win));
- if (screen == NULL) {
+ if (screen == nullptr) {
wm_event_free_all(win);
}
else {
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer);
- Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL;
+ Scene *scene_eval = (depsgraph != nullptr) ? DEG_get_evaluated_scene(depsgraph) : nullptr;
- if (scene_eval != NULL) {
+ if (scene_eval != nullptr) {
const int is_playing_sound = BKE_sound_scene_playing(scene_eval);
if (scene_eval->id.recalc & ID_RECALC_FRAME_CHANGE) {
@@ -3762,7 +3766,7 @@ void wm_event_do_handlers(bContext *C)
else if (is_playing_sound != -1) {
bool is_playing_screen;
- is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
+ is_playing_screen = (ED_screen_animation_playing(wm) != nullptr);
if (((is_playing_sound == 1) && (is_playing_screen == 0)) ||
((is_playing_sound == 0) && (is_playing_screen == 1))) {
@@ -3788,7 +3792,7 @@ void wm_event_do_handlers(bContext *C)
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
ED_update_for_newframe(CTX_data_main(C), depsgraph);
- WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WINDOW, nullptr);
}
}
}
@@ -3797,7 +3801,7 @@ void wm_event_do_handlers(bContext *C)
}
wmEvent *event;
- while ((event = win->event_queue.first)) {
+ while ((event = static_cast<wmEvent *>(win->event_queue.first))) {
int action = WM_HANDLER_CONTINUE;
/* Force handling drag if a key is pressed even if the drag threshold has not been met.
@@ -3869,7 +3873,7 @@ void wm_event_do_handlers(bContext *C)
action |= wm_handlers_do(C, event, &win->modalhandlers);
/* File-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
@@ -3905,7 +3909,7 @@ void wm_event_do_handlers(bContext *C)
ED_screen_areas_iter (win, screen, area) {
/* After restoring a screen from SCREENMAXIMIZED we have to wait
* with the screen handling till the region coordinates are updated. */
- if (screen->skip_handling == true) {
+ if (screen->skip_handling) {
/* Restore for the next iteration of wm_event_do_handlers. */
screen->skip_handling = false;
break;
@@ -3923,18 +3927,18 @@ void wm_event_do_handlers(bContext *C)
action |= wm_event_do_handlers_area_regions(C, event, area);
/* File-read case (Python), T29489. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
- CTX_wm_region_set(C, NULL);
+ CTX_wm_region_set(C, nullptr);
if ((action & WM_HANDLER_BREAK) == 0) {
wm_region_mouse_co(C, event); /* Only invalidates `event->mval` in this case. */
action |= wm_handlers_do(C, event, &area->handlers);
}
- CTX_wm_area_set(C, NULL);
+ CTX_wm_area_set(C, nullptr);
/* NOTE: do not escape on #WM_HANDLER_BREAK,
* mouse-move needs handled for previous area. */
@@ -3951,7 +3955,7 @@ void wm_event_do_handlers(bContext *C)
action |= wm_handlers_do(C, event, &win->handlers);
/* File-read case. */
- if (CTX_wm_window(C) == NULL) {
+ if (CTX_wm_window(C) == nullptr) {
wm_event_free_and_remove_from_queue_if_valid(event);
return;
}
@@ -3992,12 +3996,12 @@ void wm_event_do_handlers(bContext *C)
tevent.val = KM_NOTHING;
tevent.prev_xy[0] = tevent.xy[0];
tevent.prev_xy[1] = tevent.xy[1];
- tevent.flag = 0;
+ tevent.flag = (eWM_EventFlag)0;
wm_event_add(win, &tevent);
win->addmousemove = 0;
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/* Update key configuration after handling events. */
@@ -4019,7 +4023,7 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval
event.type = EVT_FILESELECT;
event.val = eventval;
- event.flag = 0;
+ event.flag = (eWM_EventFlag)0;
event.customdata = ophandle; /* Only as void pointer type check. */
wm_event_add(win, &event);
@@ -4063,8 +4067,9 @@ static wmWindow *wm_event_find_fileselect_root_window_from_context(const bContex
/* Fallback to the first window. */
const wmWindowManager *wm = CTX_wm_manager(C);
- BLI_assert(!ED_fileselect_handler_area_find_any_with_op(wm->windows.first));
- return wm->windows.first;
+ BLI_assert(!ED_fileselect_handler_area_find_any_with_op(
+ static_cast<const wmWindow *>(wm->windows.first)));
+ return static_cast<wmWindow *>(wm->windows.first);
}
/* Operator is supposed to have a filled "path" property. */
@@ -4079,8 +4084,8 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
* File Browser operation, to be restored for eventually executing the file operation. */
wmWindow *root_win = wm_event_find_fileselect_root_window_from_context(C);
/* Determined later. */
- ScrArea *root_area = NULL;
- ARegion *root_region = NULL;
+ ScrArea *root_area = nullptr;
+ ARegion *root_region = nullptr;
/* Close any popups, like when opening a file browser from the splash. */
UI_popup_handlers_remove_all(C, &root_win->modalhandlers);
@@ -4117,7 +4122,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
}
}
- BLI_assert(root_win != NULL);
+ BLI_assert(root_win != nullptr);
/* When not reusing the root context from a previous file browsing operation, use the current
* area & region, if they are inside the root window. */
if (!root_area && ctx_win == root_win) {
@@ -4125,7 +4130,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
root_region = CTX_wm_region(C);
}
- wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__);
handler->head.type = WM_HANDLER_TYPE_OP;
handler->is_fileselect = true;
@@ -4165,7 +4170,7 @@ static void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
wmEventHandler_Op *WM_event_add_modal_handler(bContext *C, wmOperator *op)
{
- wmEventHandler_Op *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Op *handler = MEM_cnew<wmEventHandler_Op>(__func__);
handler->head.type = WM_HANDLER_TYPE_OP;
wmWindow *win = CTX_wm_window(C);
@@ -4219,7 +4224,7 @@ void WM_event_modal_handler_region_replace(wmWindow *win,
* it needs to keep old region stored in handler, so don't change it. */
if ((handler->context.region == old_region) && (handler->is_fileselect == false)) {
handler->context.region = new_region;
- handler->context.region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW;
+ handler->context.region_type = new_region ? new_region->regiontype : (int)RGN_TYPE_WINDOW;
}
}
}
@@ -4228,8 +4233,8 @@ void WM_event_modal_handler_region_replace(wmWindow *win,
wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
{
if (!keymap) {
- CLOG_WARN(WM_LOG_HANDLERS, "called with NULL key-map");
- return NULL;
+ CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr key-map");
+ return nullptr;
}
/* Only allow same key-map once. */
@@ -4242,7 +4247,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap
}
}
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__);
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addtail(handlers, handler);
handler->keymap = keymap;
@@ -4274,16 +4279,16 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
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.
+ /* NOTE(@campbellbarton): If `win` is nullptr, 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;
+ * Keep nullptr checks in run-time code since any crashes here are difficult to redo. */
+ BLI_assert_msg(win != nullptr, "The window should always be set for tool interactions!");
+ const Scene *scene = win ? win->scene : nullptr;
- ScrArea *area = handler->dynamic.user_data;
- handler->keymap_tool = NULL;
- bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL;
+ ScrArea *area = static_cast<ScrArea *>(handler->dynamic.user_data);
+ handler->keymap_tool = nullptr;
+ bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : nullptr;
if (tref_rt && tref_rt->keymap[0]) {
keymap_id_list[keymap_id_list_len++] = tref_rt->keymap;
@@ -4302,18 +4307,18 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
}
if (with_gizmos && (tref_rt->gizmo_group[0] != '\0')) {
- wmGizmoMap *gzmap = NULL;
- wmGizmoGroup *gzgroup = NULL;
+ wmGizmoMap *gzmap = nullptr;
+ wmGizmoGroup *gzgroup = nullptr;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
- if (region->gizmo_map != NULL) {
+ if (region->gizmo_map != nullptr) {
gzmap = region->gizmo_map;
gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group);
- if (gzgroup != NULL) {
+ if (gzgroup != nullptr) {
break;
}
}
}
- if (gzgroup != NULL) {
+ if (gzgroup != nullptr) {
if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
/* If all are hidden, don't override. */
is_gizmo_visible = true;
@@ -4344,7 +4349,7 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty(
&wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW);
/* We shouldn't use key-maps from unrelated spaces. */
- if (km == NULL) {
+ if (km == nullptr) {
printf("Key-map: '%s' not found for tool '%s'\n", keymap_id, area->runtime.tool->idname);
continue;
}
@@ -4369,12 +4374,12 @@ void WM_event_get_keymap_from_toolsystem(wmWindowManager *wm,
wm_event_get_keymap_from_toolsystem_ex(wm, win, handler, km_result, false);
}
-struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
+wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
ListBase *handlers, wmEventHandler_KeymapDynamicFn *keymap_fn, void *user_data)
{
if (!keymap_fn) {
- CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap_fn");
- return NULL;
+ CLOG_WARN(WM_LOG_HANDLERS, "called with nullptr keymap_fn");
+ return nullptr;
}
/* Only allow same key-map once. */
@@ -4389,7 +4394,7 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic(
}
}
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>(__func__);
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addtail(handlers, handler);
handler->dynamic.keymap_fn = keymap_fn;
@@ -4404,7 +4409,7 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers,
{
WM_event_remove_keymap_handler(handlers, keymap);
- wmEventHandler_Keymap *handler = MEM_callocN(sizeof(*handler), "event key-map handler");
+ wmEventHandler_Keymap *handler = MEM_cnew<wmEventHandler_Keymap>("event key-map handler");
handler->head.type = WM_HANDLER_TYPE_KEYMAP;
BLI_addhead(handlers, handler);
@@ -4436,8 +4441,8 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler_poll(ListBase *handlers,
EventHandlerPoll poll)
{
wmEventHandler_Keymap *handler = WM_event_add_keymap_handler(handlers, keymap);
- if (handler == NULL) {
- return NULL;
+ if (handler == nullptr) {
+ return nullptr;
}
handler->head.poll = poll;
@@ -4480,7 +4485,7 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
void *user_data,
const char flag)
{
- wmEventHandler_UI *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_UI *handler = MEM_cnew<wmEventHandler_UI>(__func__);
handler->head.type = WM_HANDLER_TYPE_UI;
handler->handle_fn = handle_fn;
handler->remove_fn = remove_fn;
@@ -4491,9 +4496,9 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C,
handler->context.menu = CTX_wm_menu(C);
}
else {
- handler->context.area = NULL;
- handler->context.region = NULL;
- handler->context.menu = NULL;
+ handler->context.area = nullptr;
+ handler->context.region = nullptr;
+ handler->context.menu = nullptr;
}
BLI_assert((flag & WM_HANDLER_DO_FREE) == 0);
@@ -4558,7 +4563,7 @@ wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, ListBas
}
}
- wmEventHandler_Dropbox *handler = MEM_callocN(sizeof(*handler), __func__);
+ wmEventHandler_Dropbox *handler = MEM_cnew<wmEventHandler_Dropbox>(__func__);
handler->head.type = WM_HANDLER_TYPE_DROPBOX;
/* Dropbox stored static, no free or copy. */
@@ -4583,6 +4588,20 @@ void WM_event_remove_area_handler(ListBase *handlers, void *area)
}
}
+wmOperator *WM_operator_find_modal_by_type(wmWindow *win, const wmOperatorType *ot)
+{
+ LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
+ if (handler_base->type != WM_HANDLER_TYPE_OP) {
+ continue;
+ }
+ wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
+ if (handler->op && handler->op->type == ot) {
+ return handler->op;
+ }
+ }
+ return nullptr;
+}
+
#if 0
static void WM_event_remove_handler(ListBase *handlers, wmEventHandler *handler)
{
@@ -4853,22 +4872,25 @@ static void wm_eventemulation(wmEvent *event, bool test_only)
}
}
-static const wmTabletData wm_event_tablet_data_default = {
- .active = EVT_TABLET_NONE,
- .pressure = 1.0f,
- .x_tilt = 0.0f,
- .y_tilt = 0.0f,
- .is_motion_absolute = false,
-};
+constexpr wmTabletData wm_event_tablet_data_default()
+{
+ wmTabletData tablet_data{};
+ tablet_data.active = EVT_TABLET_NONE;
+ tablet_data.pressure = 1.0f;
+ tablet_data.x_tilt = 0.0f;
+ tablet_data.y_tilt = 0.0f;
+ tablet_data.is_motion_absolute = false;
+ return tablet_data;
+}
void WM_event_tablet_data_default_set(wmTabletData *tablet_data)
{
- *tablet_data = wm_event_tablet_data_default;
+ *tablet_data = wm_event_tablet_data_default();
}
void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab)
{
- if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) {
+ if ((tablet_data != nullptr) && tablet_data->Active != GHOST_kTabletModeNone) {
wmtab->active = (int)tablet_data->Active;
wmtab->pressure = wm_pressure_curve(tablet_data->Pressure);
wmtab->x_tilt = tablet_data->Xtilt;
@@ -4878,7 +4900,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData
// printf("%s: using tablet %.5f\n", __func__, wmtab->pressure);
}
else {
- *wmtab = wm_event_tablet_data_default;
+ *wmtab = wm_event_tablet_data_default();
// printf("%s: not using tablet\n", __func__);
}
}
@@ -4887,7 +4909,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData
/* Adds custom-data to event. */
static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *ghost)
{
- wmNDOFMotionData *data = MEM_mallocN(sizeof(wmNDOFMotionData), "Custom-data NDOF");
+ wmNDOFMotionData *data = MEM_cnew<wmNDOFMotionData>("Custom-data NDOF");
const float ts = U.ndof_sensitivity;
const float rs = U.ndof_orbit_sensitivity;
@@ -4915,33 +4937,38 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g
/* 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->xy[0], event->xy[1]};
+ /* If GHOST doesn't support window positioning, don't use this feature at all. */
+ const static int8_t supports_window_position = GHOST_SupportsWindowPosition();
+ if (!supports_window_position) {
+ return nullptr;
+ }
if (wm->windows.first == wm->windows.last) {
- return NULL;
+ return nullptr;
}
/* In order to use window size and mouse position (pixels), we have to use a WM function. */
/* Check if outside, include top window bar. */
- if (mval[0] < 0 || mval[1] < 0 || mval[0] > WM_window_pixels_x(win) ||
- mval[1] > WM_window_pixels_y(win) + 30) {
+ int event_xy[2] = {UNPACK2(event->xy)};
+ if (event_xy[0] < 0 || event_xy[1] < 0 || event_xy[0] > WM_window_pixels_x(win) ||
+ event_xy[1] > WM_window_pixels_y(win) + 30) {
/* Let's skip windows having modal handlers now. */
/* Potential XXX ugly... I wouldn't have added a `modalhandlers` list
* (introduced in rev 23331, ton). */
LISTBASE_FOREACH (wmEventHandler *, handler, &win->modalhandlers) {
if (ELEM(handler->type, WM_HANDLER_TYPE_UI, WM_HANDLER_TYPE_OP)) {
- return NULL;
+ return nullptr;
}
}
- wmWindow *win_other = WM_window_find_under_cursor(win, mval, mval);
+ wmWindow *win_other = WM_window_find_under_cursor(win, event_xy, event_xy);
if (win_other && win_other != win) {
- copy_v2_v2_int(event->xy, mval);
+ copy_v2_v2_int(event->xy, event_xy);
return win_other;
}
}
- return NULL;
+ return nullptr;
}
static bool wm_event_is_double_click(const wmEvent *event)
@@ -4982,18 +5009,18 @@ static void wm_event_prev_click_set(wmEvent *event_state)
static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event)
{
- wmEvent *event_last = win->event_queue.last;
+ wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last);
/* Some painting operators want accurate mouse events, they can
* handle in between mouse move moves, others can happily ignore
* them for better performance. */
if (event_last && event_last->type == MOUSEMOVE) {
event_last->type = INBETWEEN_MOUSEMOVE;
- event_last->flag = 0;
+ event_last->flag = (eWM_EventFlag)0;
}
wmEvent *event_new = wm_event_add(win, event);
- if (event_last == NULL) {
+ if (event_last == nullptr) {
event_last = win->eventstate;
}
@@ -5012,8 +5039,7 @@ static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win)
if (event_last) {
tevent = *event_last;
- tevent.flag = 0;
- tevent.ascii = '\0';
+ tevent.flag = (eWM_EventFlag)0;
tevent.utf8_buf[0] = '\0';
wm_event_custom_clear(&tevent);
@@ -5038,7 +5064,7 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d
{
/* Ignore in between track-pad events for performance, we only need high accuracy
* for painting with mouse moves, for navigation using the accumulated value is ok. */
- wmEvent *event_last = win->event_queue.last;
+ wmEvent *event_last = static_cast<wmEvent *>(win->event_queue.last);
if (event_last && event_last->type == event->type) {
deltax += event_last->xy[0] - event_last->prev_xy[0];
deltay += event_last->xy[1] - event_last->prev_xy[1];
@@ -5107,6 +5133,53 @@ static void wm_event_state_update_and_click_set(wmEvent *event,
wm_event_state_update_and_click_set_ex(event, event_state, is_keyboard, check_double_click);
}
+/* Returns true when the two events corresponds to a press of the same key with the same modifiers.
+ */
+static bool wm_event_is_same_key_press(const wmEvent &event_a, const wmEvent &event_b)
+{
+ if (event_a.val != KM_PRESS || event_b.val != KM_PRESS) {
+ return false;
+ }
+
+ if (event_a.modifier != event_b.modifier || event_a.type != event_b.type) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Returns true if the event is a key press event which is to be ignored and not added to the event
+ * queue.
+ *
+ * A key press event will be ignored if there is already matched key press in the queue.
+ * This avoids the event queue "clogging" in the situations when there is an operator bound to a
+ * key press event and the execution time of the operator is longer than the key repeat.
+ */
+static bool wm_event_is_ignorable_key_press(const wmWindow *win, const wmEvent &event)
+{
+ if (BLI_listbase_is_empty(&win->event_queue)) {
+ /* If the queue is empty never ignore the event.
+ * Empty queue at this point means that the events are handled fast enough, and there is no
+ * reason to ignore anything. */
+ return false;
+ }
+
+ if ((event.flag & WM_EVENT_IS_REPEAT) == 0) {
+ /* Only ignore repeat events from the keyboard, and allow accumulation of non-repeat events.
+ *
+ * The goal of this check is to allow events coming from a keyboard macro software, which can
+ * generate events quicker than the main loop handles them. In this case we want all events to
+ * be handled (unless the keyboard macro software tags them as repeat) because otherwise it
+ * will become impossible to get reliable results of automated events testing. */
+ return false;
+ }
+
+ const wmEvent &last_event = *reinterpret_cast<const wmEvent *>(win->event_queue.last);
+
+ return wm_event_is_same_key_press(last_event, event);
+}
+
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata)
{
if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
@@ -5127,7 +5200,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Initialize and copy state (only mouse x y and modifiers). */
event = *event_state;
- event.flag = 0;
+ event.flag = (eWM_EventFlag)0;
/**
* Always support accessing the last key press/release. This is set from `win->eventstate`,
@@ -5164,7 +5237,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
switch (type) {
/* Mouse move, also to inactive window (X11 does this). */
case GHOST_kEventCursorMove: {
- GHOST_TEventCursorData *cd = customdata;
+ GHOST_TEventCursorData *cd = static_cast<GHOST_TEventCursorData *>(customdata);
copy_v2_v2_int(event.xy, &cd->x);
wm_stereo3d_mouse_offset_apply(win, event.xy);
@@ -5201,7 +5274,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
break;
}
case GHOST_kEventTrackpad: {
- GHOST_TEventTrackpadData *pd = customdata;
+ GHOST_TEventTrackpadData *pd = static_cast<GHOST_TEventTrackpadData *>(customdata);
switch (pd->subtype) {
case GHOST_kTrackpadEventMagnify:
event.type = MOUSEZOOM;
@@ -5235,7 +5308,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Mouse button. */
case GHOST_kEventButtonDown:
case GHOST_kEventButtonUp: {
- GHOST_TEventButtonData *bd = customdata;
+ GHOST_TEventButtonData *bd = static_cast<GHOST_TEventButtonData *>(customdata);
/* Get value and type from Ghost. */
event.val = (type == GHOST_kEventButtonDown) ? KM_PRESS : KM_RELEASE;
@@ -5266,7 +5339,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
wm_tablet_data_from_ghost(&bd->tablet, &event.tablet);
wm_eventemulation(&event, false);
- wm_event_state_update_and_click_set(&event, event_state, type);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
/* Add to other window if event is there (not to both!). */
wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event);
@@ -5294,14 +5367,13 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Keyboard. */
case GHOST_kEventKeyDown:
case GHOST_kEventKeyUp: {
- GHOST_TEventKeyData *kd = customdata;
+ GHOST_TEventKeyData *kd = static_cast<GHOST_TEventKeyData *>(customdata);
event.type = convert_key(kd->key);
if (UNLIKELY(event.type == EVENT_NONE)) {
break;
}
- event.ascii = kd->ascii;
- /* Might be not NULL terminated. */
+ /* Might be not null terminated. */
memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf));
if (kd->is_repeat) {
event.flag |= WM_EVENT_IS_REPEAT;
@@ -5312,8 +5384,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
/* Exclude arrow keys, escape, etc from text input. */
if (type == GHOST_kEventKeyUp) {
- event.ascii = '\0';
-
/* Ghost should do this already for key up. */
if (event.utf8_buf[0]) {
CLOG_ERROR(WM_LOG_EVENTS,
@@ -5322,15 +5392,28 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
event.utf8_buf[0] = '\0';
}
else {
- if (event.ascii < 32 && event.ascii > 0) {
- event.ascii = '\0';
- }
if (event.utf8_buf[0] < 32 && event.utf8_buf[0] > 0) {
event.utf8_buf[0] = '\0';
}
}
if (event.utf8_buf[0]) {
+ /* NOTE(@campbellbarton): Detect non-ASCII characters stored in `utf8_buf`,
+ * ideally this would never happen but it can't be ruled out for X11 which has
+ * special handling of Latin1 when building without UTF8 support.
+ * Avoid regressions by adding this conversions, it should eventually be removed. */
+ if ((event.utf8_buf[0] >= 0x80) && (event.utf8_buf[1] == '\0')) {
+ const uint c = (uint)event.utf8_buf[0];
+ int utf8_buf_len = BLI_str_utf8_from_unicode(c, event.utf8_buf, sizeof(event.utf8_buf));
+ CLOG_ERROR(WM_LOG_EVENTS,
+ "ghost detected non-ASCII single byte character '%u', converting to utf8 "
+ "('%.*s', length=%d)",
+ c,
+ utf8_buf_len,
+ event.utf8_buf,
+ utf8_buf_len);
+ }
+
if (BLI_str_utf8_size(event.utf8_buf) == -1) {
CLOG_ERROR(WM_LOG_EVENTS,
"ghost detected an invalid unicode character '%d'",
@@ -5390,7 +5473,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
/* It's important `event.modifier` has been initialized first. */
- wm_event_state_update_and_click_set(&event, event_state, type);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
/* If test_break set, it catches this. Do not set with modifier presses.
* Exclude modifiers because MS-Windows uses these to bring up the task manager.
@@ -5403,13 +5486,15 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
G.is_break = true;
}
- wm_event_add(win, &event);
+ if (!wm_event_is_ignorable_key_press(win, event)) {
+ wm_event_add(win, &event);
+ }
break;
}
case GHOST_kEventWheel: {
- GHOST_TEventWheelData *wheelData = customdata;
+ GHOST_TEventWheelData *wheelData = static_cast<GHOST_TEventWheelData *>(customdata);
if (wheelData->z > 0) {
event.type = WHEELUPMOUSE;
@@ -5438,7 +5523,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case GHOST_kEventNDOFMotion: {
event.type = NDOF_MOTION;
event.val = KM_NOTHING;
- attach_ndof_data(&event, customdata);
+ attach_ndof_data(&event, static_cast<const GHOST_TEventNDOFMotionData *>(customdata));
wm_event_add(win, &event);
CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.xy[0], event.xy[1]);
@@ -5446,7 +5531,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
case GHOST_kEventNDOFButton: {
- GHOST_TEventNDOFButtonData *e = customdata;
+ GHOST_TEventNDOFButtonData *e = static_cast<GHOST_TEventNDOFButtonData *>(customdata);
event.type = NDOF_BUTTON_NONE + e->button;
@@ -5462,9 +5547,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
}
event.custom = 0;
- event.customdata = NULL;
+ event.customdata = nullptr;
- wm_event_state_update_and_click_set(&event, event_state, type);
+ wm_event_state_update_and_click_set(&event, event_state, (GHOST_TEventType)type);
wm_event_add(win, &event);
@@ -5486,7 +5571,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
#ifdef WITH_INPUT_IME
case GHOST_kEventImeCompositionStart: {
event.val = KM_PRESS;
- win->ime_data = customdata;
+ win->ime_data = static_cast<wmIMEData *>(customdata);
win->ime_data->is_ime_composing = true;
event.type = WM_IME_COMPOSITE_START;
wm_event_add(win, &event);
@@ -5520,14 +5605,13 @@ void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val)
{
BLI_assert(ELEM(val, KM_PRESS, KM_RELEASE));
- wmEvent event = {
- .type = EVT_XR_ACTION,
- .val = val,
- .flag = 0,
- .custom = EVT_DATA_XR,
- .customdata = actiondata,
- .customdata_free = true,
- };
+ wmEvent event{};
+ event.type = EVT_XR_ACTION;
+ event.val = val;
+ event.flag = (eWM_EventFlag)0;
+ event.custom = EVT_DATA_XR;
+ event.customdata = actiondata;
+ event.customdata_free = true;
wm_event_add(win, &event);
}
@@ -5588,15 +5672,15 @@ void WM_event_get_keymaps_from_handler(wmWindowManager *wm,
wmEventHandler_Keymap *handler,
wmEventHandler_KeymapResult *km_result)
{
- if (handler->dynamic.keymap_fn != NULL) {
+ if (handler->dynamic.keymap_fn != nullptr) {
handler->dynamic.keymap_fn(wm, win, handler, km_result);
- BLI_assert(handler->keymap == NULL);
+ BLI_assert(handler->keymap == nullptr);
}
else {
memset(km_result, 0x0, sizeof(*km_result));
wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap);
- BLI_assert(keymap != NULL);
- if (keymap != NULL) {
+ BLI_assert(keymap != nullptr);
+ if (keymap != nullptr) {
km_result->keymaps[km_result->keymaps_len++] = keymap;
}
}
@@ -5606,13 +5690,13 @@ wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wm
{
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (wm_eventmatch(event, kmi)) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
return kmi;
}
}
}
- return NULL;
+ return nullptr;
}
wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
@@ -5623,7 +5707,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
if (handler_base->flag & WM_HANDLER_DO_FREE) {
/* Pass. */
}
- else if (handler_base->poll == NULL || handler_base->poll(CTX_wm_region(C), event)) {
+ else if (handler_base->poll == nullptr || handler_base->poll(CTX_wm_region(C), event)) {
if (handler_base->type == WM_HANDLER_TYPE_KEYMAP) {
wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
wmEventHandler_KeymapResult km_result;
@@ -5632,7 +5716,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
wmKeyMap *keymap = km_result.keymaps[km_index];
if (WM_keymap_poll(C, keymap)) {
wmKeyMapItem *kmi = WM_event_match_keymap_item(C, keymap, event);
- if (kmi != NULL) {
+ if (kmi != nullptr) {
return kmi;
}
}
@@ -5640,7 +5724,7 @@ wmKeyMapItem *WM_event_match_keymap_item_from_handlers(
}
}
}
- return NULL;
+ return nullptr;
}
/** \} */
@@ -5670,10 +5754,10 @@ struct CursorKeymapInfo {
*/
char text[3][2][128];
wmEvent state_event;
- struct CursorKeymapInfo_State state;
+ CursorKeymapInfo_State state;
};
-static void wm_event_cursor_store(struct CursorKeymapInfo_State *state,
+static void wm_event_cursor_store(CursorKeymapInfo_State *state,
const wmEvent *event,
short space_type,
short region_type,
@@ -5682,29 +5766,29 @@ static void wm_event_cursor_store(struct CursorKeymapInfo_State *state,
state->modifier = event->modifier;
state->space_type = space_type;
state->region_type = region_type;
- state->tref = tref ? *tref : (bToolRef){0};
+ state->tref = tref ? *tref : bToolRef{};
}
const char *WM_window_cursor_keymap_status_get(const wmWindow *win,
int button_index,
int type_index)
{
- if (win->cursor_keymap_status != NULL) {
- struct CursorKeymapInfo *cd = win->cursor_keymap_status;
+ if (win->cursor_keymap_status != nullptr) {
+ CursorKeymapInfo *cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
const char *msg = cd->text[button_index][type_index];
if (*msg) {
return msg;
}
}
- return NULL;
+ return nullptr;
}
ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
{
if (screen->state == SCREENFULL) {
- return NULL;
+ return nullptr;
}
- ScrArea *area_statusbar = NULL;
+ ScrArea *area_statusbar = nullptr;
LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
if (area->spacetype == SPACE_STATUSBAR) {
area_statusbar = area;
@@ -5718,7 +5802,7 @@ void WM_window_status_area_tag_redraw(wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
ScrArea *area = WM_window_status_area_find(win, screen);
- if (area != NULL) {
+ if (area != nullptr) {
ED_area_tag_redraw(area);
}
}
@@ -5727,16 +5811,16 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
ScrArea *area_statusbar = WM_window_status_area_find(win, screen);
- if (area_statusbar == NULL) {
+ if (area_statusbar == nullptr) {
MEM_SAFE_FREE(win->cursor_keymap_status);
return;
}
- struct CursorKeymapInfo *cd;
- if (UNLIKELY(win->cursor_keymap_status == NULL)) {
- win->cursor_keymap_status = MEM_callocN(sizeof(struct CursorKeymapInfo), __func__);
+ CursorKeymapInfo *cd;
+ if (UNLIKELY(win->cursor_keymap_status == nullptr)) {
+ win->cursor_keymap_status = MEM_callocN(sizeof(CursorKeymapInfo), __func__);
}
- cd = win->cursor_keymap_status;
+ cd = static_cast<CursorKeymapInfo *>(win->cursor_keymap_status);
/* Detect unchanged state (early exit). */
if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) {
@@ -5745,23 +5829,23 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
/* Now perform more comprehensive check,
* still keep this fast since it happens on mouse-move. */
- struct CursorKeymapInfo cd_prev = *((struct CursorKeymapInfo *)win->cursor_keymap_status);
+ CursorKeymapInfo cd_prev = *((CursorKeymapInfo *)win->cursor_keymap_status);
cd->state_event = *win->eventstate;
/* Find active region and associated area. */
ARegion *region = screen->active_region;
- if (region == NULL) {
+ if (region == nullptr) {
return;
}
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
ED_screen_areas_iter (win, screen, area_iter) {
if (BLI_findindex(&area_iter->regionbase, region) != -1) {
area = area_iter;
break;
}
}
- if (area == NULL) {
+ if (area == nullptr) {
return;
}
@@ -5784,15 +5868,14 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
/* Detect changes to the state. */
{
- bToolRef *tref = NULL;
+ bToolRef *tref = nullptr;
if ((region->regiontype == RGN_TYPE_WINDOW) &&
((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
WorkSpace *workspace = WM_window_get_active_workspace(win);
- const bToolKey tkey = {
- .space_type = area->spacetype,
- .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype),
- };
+ bToolKey tkey{};
+ tkey.space_type = area->spacetype;
+ tkey.mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype);
tref = WM_toolsystem_ref_find(workspace, &tkey);
}
wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref);
@@ -5846,9 +5929,9 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
wmEvent test_event = *win->eventstate;
test_event.type = event_data[data_index].event_type;
test_event.val = event_data[data_index].event_value;
- test_event.flag = 0;
+ test_event.flag = (eWM_EventFlag)0;
wm_eventemulation(&test_event, true);
- wmKeyMapItem *kmi = NULL;
+ wmKeyMapItem *kmi = nullptr;
for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
kmi = WM_event_match_keymap_item_from_handlers(
C, wm, win, handlers[handler_index], &test_event);
@@ -5857,7 +5940,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
}
}
if (kmi) {
- wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, false);
const char *name = (ot) ? WM_operatortype_name(ot, kmi->ptr) : kmi->idname;
STRNCPY(cd->text[button_index][type_index], name);
}
@@ -5867,7 +5950,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
ED_area_tag_redraw(area_statusbar);
}
- CTX_wm_window_set(C, NULL);
+ CTX_wm_window_set(C, nullptr);
}
/** \} */
@@ -5879,12 +5962,12 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *layout)
{
wmWindowManager *wm = CTX_wm_manager(C);
- wmKeyMap *keymap = NULL;
- wmOperator *op = NULL;
+ wmKeyMap *keymap = nullptr;
+ wmOperator *op = nullptr;
LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
if (handler_base->type == WM_HANDLER_TYPE_OP) {
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
- if (handler->op != NULL) {
+ if (handler->op != nullptr) {
/* 'handler->keymap' could be checked too, seems not to be used. */
wmKeyMap *keymap_test = WM_keymap_active(wm, handler->op->type->modalkeymap);
if (keymap_test && keymap_test->modal_items) {
@@ -5895,17 +5978,17 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la
}
}
}
- if (keymap == NULL || keymap->modal_items == NULL) {
+ if (keymap == nullptr || keymap->modal_items == nullptr) {
return false;
}
- const EnumPropertyItem *items = keymap->modal_items;
+ const EnumPropertyItem *items = static_cast<const EnumPropertyItem *>(keymap->modal_items);
uiLayout *row = uiLayoutRow(layout, true);
for (int i = 0; items[i].identifier; i++) {
if (!items[i].identifier[0]) {
continue;
}
- if ((keymap->poll_modal_item != NULL) &&
+ if ((keymap->poll_modal_item != nullptr) &&
(keymap->poll_modal_item(op, items[i].value) == false)) {
continue;
}
@@ -5914,13 +5997,13 @@ bool WM_window_modal_keymap_status_draw(bContext *C, wmWindow *win, uiLayout *la
{
/* WARNING: O(n^2). */
- wmKeyMapItem *kmi = NULL;
- for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ wmKeyMapItem *kmi = nullptr;
+ for (kmi = static_cast<wmKeyMapItem *>(keymap->items.first); kmi; kmi = kmi->next) {
if (kmi->propvalue == items[i].value) {
break;
}
}
- if (kmi != NULL) {
+ if (kmi != nullptr) {
if (kmi->val == KM_RELEASE) {
/* Assume release events just disable something which was toggled on. */
continue;
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index a2e454218cb..e334131e406 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -850,8 +850,13 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports)
bf_reports->count.missing_obproxies);
}
else {
- BLI_assert(bf_reports->count.missing_obdata == 0);
- BLI_assert(bf_reports->count.missing_obproxies == 0);
+ if (bf_reports->count.missing_obdata != 0 || bf_reports->count.missing_obproxies != 0) {
+ CLOG_ERROR(&LOG,
+ "%d local ObjectData and %d local Object proxies are reported to be missing, "
+ "this should never happen",
+ bf_reports->count.missing_obdata,
+ bf_reports->count.missing_obproxies);
+ }
}
if (bf_reports->resynced_lib_overrides_libraries_count != 0) {
@@ -1095,7 +1100,7 @@ void wm_homefile_read_ex(bContext *C,
const bool reset_app_template = ((!app_template && U.app_template[0]) ||
(app_template && !STREQ(app_template, U.app_template)));
- /* options exclude eachother */
+ /* Options exclude each other. */
BLI_assert((use_factory_settings && filepath_startup_override) == 0);
if ((G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) == 0) {
@@ -3062,8 +3067,7 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
char path[FILE_MAX];
const bool is_save_as = (op->type->invoke == wm_save_as_mainfile_invoke);
- const bool use_save_as_copy = (RNA_struct_property_is_set(op->ptr, "copy") &&
- RNA_boolean_get(op->ptr, "copy"));
+ const bool use_save_as_copy = is_save_as && RNA_boolean_get(op->ptr, "copy");
/* We could expose all options to the users however in most cases remapping
* existing relative paths is a good default.
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index b41ffb4cfc2..f2c41dada48 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -438,7 +438,7 @@ void WM_OT_link(wmOperatorType *ot)
ot->exec = wm_link_append_exec;
ot->poll = wm_link_append_poll;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB,
@@ -462,7 +462,7 @@ void WM_OT_append(wmOperatorType *ot)
ot->exec = wm_link_append_exec;
ot->poll = wm_link_append_poll;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB,
@@ -803,7 +803,7 @@ void WM_OT_lib_relocate(wmOperatorType *ot)
ot->invoke = wm_lib_relocate_invoke;
ot->exec = wm_lib_relocate_exec;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate");
RNA_def_property_flag(prop, PROP_HIDDEN);
@@ -833,7 +833,7 @@ void WM_OT_lib_reload(wmOperatorType *ot)
ot->exec = wm_lib_reload_exec;
- ot->flag |= OPTYPE_UNDO;
+ ot->flag = OPTYPE_UNDO;
prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload");
RNA_def_property_flag(prop, PROP_HIDDEN);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 8d6741dcfb6..7f5ec77e16d 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -59,6 +59,7 @@
#include "BKE_mask.h" /* free mask clipboard */
#include "BKE_material.h" /* BKE_material_copybuf_clear */
#include "BKE_studiolight.h"
+#include "BKE_subdiv.h"
#include "BKE_tracking.h" /* free tracking clipboard */
#include "RE_engine.h"
@@ -114,9 +115,6 @@
#include "GPU_init_exit.h"
#include "GPU_material.h"
-#include "BKE_sound.h"
-#include "BKE_subdiv.h"
-
#include "COM_compositor.h"
#include "DEG_depsgraph.h"
@@ -171,6 +169,10 @@ void WM_init_opengl(void)
wm_ghost_init(NULL);
}
+ if (!GPU_backend_supported()) {
+ return;
+ }
+
/* Needs to be first to have an OpenGL context bound. */
DRW_opengl_context_create();
@@ -312,6 +314,7 @@ void WM_init(bContext *C, int argc, const char **argv)
IMB_thumb_clear_translations();
if (!G.background) {
+ GPU_render_begin();
#ifdef WITH_INPUT_NDOF
/* Sets 3D mouse dead-zone. */
@@ -324,7 +327,10 @@ void WM_init(bContext *C, int argc, const char **argv)
exit(-1);
}
+ GPU_context_begin_frame(GPU_context_active_get());
UI_init();
+ GPU_context_end_frame(GPU_context_active_get());
+ GPU_render_end();
}
BKE_subdiv_init();
@@ -340,10 +346,10 @@ void WM_init(bContext *C, int argc, const char **argv)
if (!G.background) {
if (wm_start_with_console) {
- setConsoleWindowState(GHOST_kConsoleWindowStateShow);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateShow);
}
else {
- setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateHideForNonConsoleLaunch);
}
}
@@ -382,7 +388,7 @@ static void free_openrecent(void)
}
#ifdef WIN32
-/* Read console events until there is a key event. Also returns on any error. */
+/* Read console events until there is a key event. Also returns on any error. */
static void wait_for_console_key(void)
{
HANDLE hConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
@@ -570,14 +576,6 @@ void WM_exit_ex(bContext *C, const bool do_python)
BLF_exit();
- if (opengl_is_init) {
- DRW_opengl_context_enable_ex(false);
- GPU_pass_cache_free();
- GPU_exit();
- DRW_opengl_context_disable_ex(false);
- DRW_opengl_context_destroy();
- }
-
BLT_lang_free();
ANIM_keyingset_infos_exit();
@@ -602,13 +600,24 @@ void WM_exit_ex(bContext *C, const bool do_python)
ED_file_exit(); /* for fsmenu */
- UI_exit();
+ /* Delete GPU resources and context. The UI also uses GPU resources and so
+ * is also deleted with the context active. */
+ if (opengl_is_init) {
+ DRW_opengl_context_enable_ex(false);
+ UI_exit();
+ GPU_pass_cache_free();
+ GPU_exit();
+ DRW_opengl_context_disable_ex(false);
+ DRW_opengl_context_destroy();
+ }
+ else {
+ UI_exit();
+ }
+
BKE_blender_userdef_data_free(&U, false);
RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */
- GPU_backend_exit();
-
wm_ghost_exit();
CTX_free(C);
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c
index b44cf9e48b8..d5c4d07e9ed 100644
--- a/source/blender/windowmanager/intern/wm_jobs.c
+++ b/source/blender/windowmanager/intern/wm_jobs.c
@@ -87,6 +87,16 @@ struct wmJob {
* Executed in main thread.
*/
void (*endjob)(void *);
+ /**
+ * Called when job is stopped normally, i.e. by simply completing the startjob function.
+ * Executed in main thread.
+ */
+ void (*completed)(void *);
+ /**
+ * Called when job is stopped abnormally, i.e. when stop=true but ready=false.
+ * Executed in main thread.
+ */
+ void (*canceled)(void *);
/** Running jobs each have own timer */
double timestep;
@@ -344,10 +354,23 @@ void WM_jobs_callbacks(wmJob *wm_job,
void (*update)(void *),
void (*endjob)(void *))
{
+ WM_jobs_callbacks_ex(wm_job, startjob, initjob, update, endjob, NULL, NULL);
+}
+
+void WM_jobs_callbacks_ex(wmJob *wm_job,
+ wm_jobs_start_callback startjob,
+ void (*initjob)(void *),
+ void (*update)(void *),
+ void (*endjob)(void *),
+ void (*completed)(void *),
+ void (*canceled)(void *))
+{
wm_job->startjob = startjob;
wm_job->initjob = initjob;
wm_job->update = update;
wm_job->endjob = endjob;
+ wm_job->completed = completed;
+ wm_job->canceled = canceled;
}
static void *do_job_thread(void *job_v)
@@ -465,6 +488,24 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
}
}
+static void wm_job_end(wmJob *wm_job)
+{
+ BLI_assert_msg(BLI_thread_is_main(), "wm_job_end should only be called from the main thread");
+ if (wm_job->endjob) {
+ wm_job->endjob(wm_job->run_customdata);
+ }
+
+ /* Do the final callback based on whether the job was run to completion or not.
+ * Not all jobs have the same way of signaling cancellation (i.e. rendering stops when
+ * `G.is_break == true`, but doesn't set any wm_job properties to cancel the WM job). */
+ const bool was_canceled = wm_job->stop || G.is_break;
+ void (*final_callback)(void *) = (wm_job->ready && !was_canceled) ? wm_job->completed :
+ wm_job->canceled;
+ if (final_callback) {
+ final_callback(wm_job->run_customdata);
+ }
+}
+
static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
{
BLI_remlink(&wm->jobs, wm_job);
@@ -485,10 +526,7 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
WM_job_main_thread_lock_release(wm_job);
BLI_threadpool_end(&wm_job->threads);
WM_job_main_thread_lock_acquire(wm_job);
-
- if (wm_job->endjob) {
- wm_job->endjob(wm_job->run_customdata);
- }
+ wm_job_end(wm_job);
}
if (wm_job->wt) {
@@ -600,9 +638,7 @@ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
}
if (wm_job->ready) {
- if (wm_job->endjob) {
- wm_job->endjob(wm_job->run_customdata);
- }
+ wm_job_end(wm_job);
/* free own data */
wm_job->run_free(wm_job->run_customdata);
@@ -670,3 +706,13 @@ bool WM_jobs_has_running(const wmWindowManager *wm)
return false;
}
+
+bool WM_jobs_has_running_type(const struct wmWindowManager *wm, int job_type)
+{
+ LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) {
+ if (wm_job->running && wm_job->job_type == job_type) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 1fa5e64093f..acacbd77f9e 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -445,7 +445,10 @@ bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
* When developing a customized Blender though you may want empty keymaps. */
if (!U.app_template[0] &&
/* Fallback key-maps may be intentionally empty, don't flood the output. */
- !BLI_str_endswith(keymap->idname, " (fallback)")) {
+ !BLI_str_endswith(keymap->idname, " (fallback)") &&
+ /* This is an exception which may be empty.
+ * Longer term we might want a flag to indicate an empty key-map is intended. */
+ !STREQ(keymap->idname, "Node Tool: Tweak")) {
CLOG_WARN(WM_LOG_KEYMAPS, "empty keymap '%s'", keymap->idname);
}
}
diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c
index f3333ca371d..a4cc8ff631a 100644
--- a/source/blender/windowmanager/intern/wm_keymap_utils.c
+++ b/source/blender/windowmanager/intern/wm_keymap_utils.c
@@ -270,6 +270,12 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
+ else if (STRPREFIX(opname, "CURVES_OT")) {
+ km = WM_keymap_find_all(wm, "Curves", 0, 0);
+ }
+ else if (STRPREFIX(opname, "SCULPT_CURVES_OT")) {
+ km = WM_keymap_find_all(wm, "Sculpt Curves", 0, 0);
+ }
else if (STRPREFIX(opname, "MBALL_OT")) {
km = WM_keymap_find_all(wm, "Metaball", 0, 0);
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 307d3282659..33c69a23558 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1308,6 +1308,10 @@ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short i
return id;
}
+ if (!WM_operator_properties_id_lookup_is_set(op->ptr)) {
+ return NULL;
+ }
+
/* Lookup an already existing ID. */
id = WM_operator_properties_id_lookup_from_name_or_session_uuid(bmain, op->ptr, idcode);
@@ -2068,7 +2072,7 @@ static void WM_OT_quit_blender(wmOperatorType *ot)
static int wm_console_toggle_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
- setConsoleWindowState(GHOST_kConsoleWindowStateToggle);
+ GHOST_setConsoleWindowState(GHOST_kConsoleWindowStateToggle);
return OPERATOR_FINISHED;
}
@@ -3898,7 +3902,7 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_clip_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_box");
- /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */
+ /* XXX TODO: zoom border should perhaps map right-mouse to zoom out instead of in+cancel. */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border");
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 95879829d42..99f117f267a 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -33,6 +33,7 @@
#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "IMB_colormanagement.h"
@@ -211,7 +212,7 @@ static void playanim_gl_matrix(void)
/* implementation */
static void playanim_event_qual_update(void)
{
- int val;
+ bool val;
/* Shift */
GHOST_GetModifierKeyState(g_WS.ghost_system, GHOST_kModifierKeyLeftShift, &val);
@@ -673,7 +674,7 @@ static void build_pict_list_ex(
*
* If set, all reads and writes on the resulting file descriptor will
* be performed directly to or from the user program buffer, provided
- * appropriate size and alignment restrictions are met. Refer to the
+ * appropriate size and alignment restrictions are met. Refer to the
* F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
* information about how to determine the alignment constraints.
* O_DIRECT is a Silicon Graphics extension and is only supported on
@@ -870,7 +871,7 @@ static void change_frame(PlayState *ps)
ps->need_frame_update = false;
}
-static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
+static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
{
PlayState *ps = (PlayState *)ps_void;
const GHOST_TEventType type = GHOST_GetEventType(evt);
@@ -901,7 +902,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
default:
break;
}
- return 1;
+ return true;
}
if (ps->wait2 && ps->stopped == false) {
@@ -1216,8 +1217,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
GHOST_TEventButtonData *bd = GHOST_GetEventData(evt);
int cx, cy, sizex, sizey, inside_window;
- GHOST_GetCursorPosition(g_WS.ghost_system, &cx, &cy);
- GHOST_ScreenToClient(g_WS.ghost_window, cx, cy, &cx, &cy);
+ GHOST_GetCursorPosition(g_WS.ghost_system, g_WS.ghost_window, &cx, &cy);
playanim_window_get_size(&sizex, &sizey);
inside_window = (cx >= 0 && cx < sizex && cy >= 0 && cy <= sizey);
@@ -1266,15 +1266,15 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
* however the API currently doesn't support this. */
{
int x_test, y_test;
- GHOST_GetCursorPosition(g_WS.ghost_system, &x_test, &y_test);
- if (x_test != cd->x || y_test != cd->y) {
+ GHOST_GetCursorPosition(g_WS.ghost_system, g_WS.ghost_window, &cx, &cy);
+ GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &x_test, &y_test);
+
+ if (cx != x_test || cy != y_test) {
/* we're not the last event... skipping */
break;
}
}
- GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
-
tag_change_frame(ps, cx);
}
break;
@@ -1334,7 +1334,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
break;
}
- return 1;
+ return true;
}
static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey)
@@ -1536,6 +1536,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, &ps);
+ GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
+
g_WS.ghost_system = GHOST_CreateSystem();
GHOST_AddEventConsumer(g_WS.ghost_system, consumer);
@@ -1552,6 +1554,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
/* initialize the font */
BLF_init();
+ BLF_load_font_stack();
ps.fontid = BLF_load_mono_default(false);
BLF_size(ps.fontid, 11.0f, 72);
@@ -1852,7 +1855,7 @@ void WM_main_playanim(int argc, const char **argv)
AUD_DeviceSpecs specs;
specs.rate = AUD_RATE_48000;
- specs.format = AUD_FORMAT_S16;
+ specs.format = AUD_FORMAT_FLOAT32;
specs.channels = AUD_CHANNELS_STEREO;
AUD_initOnce();
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c
index 88eacf9013b..6dd64b89eb6 100644
--- a/source/blender/windowmanager/intern/wm_uilist_type.c
+++ b/source/blender/windowmanager/intern/wm_uilist_type.c
@@ -20,7 +20,6 @@
#include "UI_interface.h"
#include "BLI_ghash.h"
-#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index c0427f9be9a..d2182f759e5 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -23,6 +23,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -919,25 +920,33 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
/* ************ events *************** */
-void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y)
+void wm_cursor_position_from_ghost_client_coords(wmWindow *win, int *x, int *y)
{
float fac = GHOST_GetNativePixelSize(win->ghostwin);
-
- GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
*x *= fac;
*y = (win->sizey - 1) - *y;
*y *= fac;
}
-void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y)
+void wm_cursor_position_to_ghost_client_coords(wmWindow *win, int *x, int *y)
{
float fac = GHOST_GetNativePixelSize(win->ghostwin);
*x /= fac;
*y /= fac;
*y = win->sizey - *y - 1;
+}
+void wm_cursor_position_from_ghost_screen_coords(wmWindow *win, int *x, int *y)
+{
+ GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
+ wm_cursor_position_from_ghost_client_coords(win, x, y);
+}
+
+void wm_cursor_position_to_ghost_screen_coords(wmWindow *win, int *x, int *y)
+{
+ wm_cursor_position_to_ghost_client_coords(win, x, y);
GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y);
}
@@ -948,8 +957,8 @@ void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
*r_y = win->eventstate->xy[1];
return;
}
- GHOST_GetCursorPosition(g_system, r_x, r_y);
- wm_cursor_position_from_ghost(win, r_x, r_y);
+ GHOST_GetCursorPosition(g_system, win->ghostwin, r_x, r_y);
+ wm_cursor_position_from_ghost_client_coords(win, r_x, r_y);
}
typedef enum {
@@ -962,7 +971,7 @@ typedef enum {
/* check if specified modifier key type is pressed */
static int query_qual(modifierKeyType qual)
{
- GHOST_TModifierKeyMask left, right;
+ GHOST_TModifierKey left, right;
switch (qual) {
case SHIFT:
left = GHOST_kModifierKeyLeftShift;
@@ -982,7 +991,7 @@ static int query_qual(modifierKeyType qual)
break;
}
- int val = 0;
+ bool val = false;
GHOST_GetModifierKeyState(g_system, left, &val);
if (!val) {
GHOST_GetModifierKeyState(g_system, right, &val);
@@ -1052,7 +1061,7 @@ void wm_window_reset_drawable(void)
*
* Mouse coordinate conversion happens here.
*/
-static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
+static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
{
bContext *C = C_void_ptr;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -1090,17 +1099,17 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
* but it should return if WM didn't initialize yet.
* Can happen on file read (especially full size window). */
if ((wm->initialized & WM_WINDOW_IS_INIT) == 0) {
- return 1;
+ return true;
}
if (!ghostwin) {
/* XXX: should be checked, why are we getting an event here, and what is it? */
puts("<!> event has no window");
- return 1;
+ return true;
}
if (!GHOST_ValidWindow(g_system, ghostwin)) {
/* XXX: should be checked, why are we getting an event here, and what is it? */
puts("<!> event has invalid window");
- return 1;
+ return true;
}
wmWindow *win = GHOST_GetWindowUserData(ghostwin);
@@ -1115,7 +1124,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
break;
case GHOST_kEventWindowActivate: {
- GHOST_TEventKeyData kdata;
const int keymodifier = ((query_qual(SHIFT) ? KM_SHIFT : 0) |
(query_qual(CONTROL) ? KM_CTRL : 0) |
(query_qual(ALT) ? KM_ALT : 0) | (query_qual(OS) ? KM_OSKEY : 0));
@@ -1138,9 +1146,11 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
*
* For now don't send GHOST_kEventKeyDown events, just set the 'eventstate'.
*/
- kdata.ascii = '\0';
- kdata.utf8_buf[0] = '\0';
-
+ GHOST_TEventKeyData kdata = {
+ .key = GHOST_kKeyUnknown,
+ .utf8_buf = {'\0'},
+ .is_repeat = false,
+ };
if (win->eventstate->modifier & KM_SHIFT) {
if ((keymodifier & KM_SHIFT) == 0) {
kdata.key = GHOST_kKeyLeftShift;
@@ -1352,6 +1362,11 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
event.type = MOUSEMOVE;
event.val = KM_NOTHING;
copy_v2_v2_int(event.prev_xy, event.xy);
+
+ wm_cursor_position_from_ghost_screen_coords(win, &ddd->x, &ddd->y);
+ event.xy[0] = ddd->x;
+ event.xy[1] = ddd->y;
+
event.flag = 0;
/* No context change! C->wm->windrawable is drawable, or for area queues. */
@@ -1415,14 +1430,14 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventTrackpad: {
GHOST_TEventTrackpadData *pd = data;
- wm_cursor_position_from_ghost(win, &pd->x, &pd->y);
+ wm_cursor_position_from_ghost_screen_coords(win, &pd->x, &pd->y);
wm_event_add_ghostevent(wm, win, type, data);
break;
}
case GHOST_kEventCursorMove: {
GHOST_TEventCursorData *cd = data;
- wm_cursor_position_from_ghost(win, &cd->x, &cd->y);
+ wm_cursor_position_from_ghost_screen_coords(win, &cd->x, &cd->y);
wm_event_add_ghostevent(wm, win, type, data);
break;
}
@@ -1443,7 +1458,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
}
}
- return 1;
+ return true;
}
/**
@@ -1543,6 +1558,8 @@ void wm_ghost_init(bContext *C)
consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
}
+ GHOST_SetBacktraceHandler((GHOST_TBacktraceFn)BLI_system_backtrace);
+
g_system = GHOST_CreateSystem();
GHOST_Debug debug = {0};
@@ -1861,7 +1878,7 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv
{
int tmp[2];
copy_v2_v2_int(tmp, mval);
- wm_cursor_position_to_ghost(win, &tmp[0], &tmp[1]);
+ wm_cursor_position_to_ghost_screen_coords(win, &tmp[0], &tmp[1]);
GHOST_WindowHandle ghostwin = GHOST_GetWindowUnderCursor(g_system, tmp[0], tmp[1]);
@@ -1869,11 +1886,10 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv
return NULL;
}
- wmWindow *r_win = GHOST_GetWindowUserData(ghostwin);
- wm_cursor_position_from_ghost(r_win, &tmp[0], &tmp[1]);
+ wmWindow *win_other = GHOST_GetWindowUserData(ghostwin);
+ wm_cursor_position_from_ghost_screen_coords(win_other, &tmp[0], &tmp[1]);
copy_v2_v2_int(r_mval, tmp);
-
- return r_win;
+ return win_other;
}
void WM_window_pixel_sample_read(const wmWindowManager *wm,
@@ -2011,8 +2027,8 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
if (win && win->ghostwin) {
int oldx = x, oldy = y;
- wm_cursor_position_to_ghost(win, &x, &y);
- GHOST_SetCursorPosition(g_system, x, y);
+ wm_cursor_position_to_ghost_client_coords(win, &x, &y);
+ GHOST_SetCursorPosition(g_system, win->ghostwin, x, y);
win->eventstate->prev_xy[0] = oldx;
win->eventstate->prev_xy[1] = oldy;
@@ -2022,15 +2038,6 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
}
}
-void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
-{
- float f = GHOST_GetNativePixelSize(win->ghostwin);
- if (f != 1.0f) {
- *x = (int)(*x / f) * f;
- *y = (int)(*y / f) * f;
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 2d3624704d0..edac3ada73b 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -358,12 +358,6 @@ enum {
/** Test whether the event is timer event. */
#define ISTIMER(event_type) ((event_type) >= TIMER && (event_type) <= TIMERF)
-/* for event checks */
-/* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */
-/* Unused, see #wm_eventmatch, see: T30479. */
-// #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 (including modifier keys). */
#define ISKEYBOARD(event_type) \
(((event_type) >= _EVT_KEYBOARD_MIN && (event_type) <= _EVT_KEYBOARD_MAX) || \
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index 67557768413..3644aa085f7 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -100,8 +100,11 @@ void wm_window_set_swap_interval(wmWindow *win, int interval);
bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y);
-void wm_cursor_position_from_ghost(wmWindow *win, int *r_x, int *r_y);
-void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y);
+void wm_cursor_position_from_ghost_screen_coords(wmWindow *win, int *r_x, int *r_y);
+void wm_cursor_position_to_ghost_screen_coords(wmWindow *win, int *x, int *y);
+
+void wm_cursor_position_from_ghost_client_coords(wmWindow *win, int *x, int *y);
+void wm_cursor_position_to_ghost_client_coords(wmWindow *win, int *x, int *y);
#ifdef WITH_INPUT_IME
void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_action.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c
index 6750e7a7d77..a83415c98af 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_action.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_action.c
@@ -391,13 +391,20 @@ void WM_xr_action_binding_destroy(wmXrData *xr,
xr->runtime->context, action_set_name, 1, &action_name, &profile_path);
}
-bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name)
+bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name, bool delayed)
{
wmXrActionSet *action_set = action_set_find(xr, action_set_name);
if (!action_set) {
return false;
}
+ if (delayed) {
+ /* Save name to activate action set later, before next actions sync
+ * (see #wm_xr_session_actions_update()). */
+ strcpy(xr->runtime->session_state.active_action_set_next, action_set_name);
+ return true;
+ }
+
{
/* Clear any active modal/haptic actions. */
wmXrActionSet *active_action_set = xr->runtime->session_state.active_action_set;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index 3fc1f362541..8ad694b6fd2 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -54,9 +54,11 @@ typedef struct wmXrSessionState {
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
+ * #wm_xr_session_actions_update(). If NULL, all action sets will be treated as active and
* updated. */
struct wmXrActionSet *active_action_set;
+ /* Name of the action set (if any) to activate before the next actions sync. */
+ char active_action_set_next[64]; /* MAX_NAME */
} wmXrSessionState;
typedef struct wmXrRuntimeData {
@@ -107,7 +109,7 @@ typedef struct wmXrDrawData {
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
+ /** Offset to _subtract_ 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. */
} wmXrDrawData;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
index 3c090423c41..3f0c72a4a05 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -731,8 +731,9 @@ static void wm_xr_raycast(Scene *scene,
sctx,
depsgraph,
NULL,
- &(const struct SnapObjectParams){
- .snap_select = (selectable_only ? SNAP_SELECTABLE : SNAP_ALL)},
+ &(const struct SnapObjectParams){.snap_target_select = (selectable_only ?
+ SCE_SNAP_TARGET_ONLY_SELECTABLE :
+ SCE_SNAP_TARGET_ALL)},
origin,
direction,
ray_dist,
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 2a829e274d9..a4d2a65830f 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -1175,7 +1175,6 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
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));
@@ -1192,6 +1191,13 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
&state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat);
}
+ /* Set active action set if requested previously. */
+ if (state->active_action_set_next[0]) {
+ WM_xr_active_action_set_set(xr, state->active_action_set_next, false);
+ state->active_action_set_next[0] = '\0';
+ }
+ wmXrActionSet *active_action_set = state->active_action_set;
+
const bool synced = GHOST_XrSyncActions(xr_context,
active_action_set ? active_action_set->name : NULL);
if (!synced) {
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 7457358698d..278cd4362c3 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -511,7 +511,7 @@ if(UNIX AND NOT APPLE)
endif()
if(EXISTS ${LIBDIR}/mesa)
- install(DIRECTORY ${LIBDIR}/mesa/lib DESTINATION ".")
+ install(DIRECTORY ${LIBDIR}/mesa/lib/ DESTINATION "lib/mesa/")
install(
PROGRAMS
diff --git a/source/creator/blender.map b/source/creator/blender.map
index a817908acfb..500892a20f3 100644
--- a/source/creator/blender.map
+++ b/source/creator/blender.map
@@ -9,6 +9,9 @@ global:
*;
*_boost*;
local:
+ __once_proxy;
+ _ZSt11__once_call;
+ _ZSt15__once_callable;
al*;
*Alembic*;
av*;
diff --git a/source/tools b/source/tools
-Subproject ccc8fceb6bd83ffbf6e5207247fb8f76fc47a5b
+Subproject da8bdd7244c7b6c2eadf4c949ff391d0cc43027
diff --git a/tests/performance/tests/eevee.py b/tests/performance/tests/eevee.py
new file mode 100644
index 00000000000..df7cac695da
--- /dev/null
+++ b/tests/performance/tests/eevee.py
@@ -0,0 +1,129 @@
+# SPDX-License-Identifier: Apache-2.0
+
+import os
+import enum
+import time
+
+
+class RecordStage(enum.Enum):
+ INIT = 0,
+ WAIT_SHADERS = 1,
+ WARMUP = 2,
+ RECORD = 3,
+ FINISHED = 4
+
+
+WARMUP_SECONDS = 3
+WARMUP_FRAMES = 10
+SHADER_FALLBACK_SECONDS = 60
+RECORD_PLAYBACK_ITER = 3
+LOG_KEY = "ANIMATION_PERFORMANCE: "
+
+
+def _run(args):
+ import bpy
+
+ global record_stage
+ record_stage = RecordStage.INIT
+
+ bpy.app.handlers.frame_change_post.append(frame_change_handler)
+ bpy.ops.screen.animation_play()
+
+
+def frame_change_handler(scene):
+ import bpy
+
+ global record_stage
+ global start_time
+ global start_record_time
+ global start_warmup_time
+ global warmup_frame
+ global stop_record_time
+ global playback_iteration
+
+ if record_stage == RecordStage.INIT:
+ screen = bpy.context.window_manager.windows[0].screen
+ bpy.context.scene.sync_mode = 'NONE'
+
+ for area in screen.areas:
+ if area.type == 'VIEW_3D':
+ space = area.spaces[0]
+ space.shading.type = 'RENDERED'
+ space.overlay.show_overlays = False
+
+ start_time = time.perf_counter()
+ record_stage = RecordStage.WAIT_SHADERS
+
+ elif record_stage == RecordStage.WAIT_SHADERS:
+ shaders_compiled = False
+ if hasattr(bpy.app, 'is_job_running'):
+ shaders_compiled = not bpy.app.is_job_running("SHADER_COMPILATION")
+ else:
+ # Fallback when is_job_running doesn't exists by waiting for a time.
+ shaders_compiled = time.perf_counter() - start_time > SHADER_FALLBACK_SECONDS
+
+ if shaders_compiled:
+ start_warmup_time = time.perf_counter()
+ warmup_frame = 0
+ record_stage = RecordStage.WARMUP
+
+ elif record_stage == RecordStage.WARMUP:
+ warmup_frame += 1
+ if time.perf_counter() - start_warmup_time > WARMUP_SECONDS and warmup_frame > WARMUP_FRAMES:
+ start_record_time = time.perf_counter()
+ playback_iteration = 0
+ scene = bpy.context.scene
+ scene.frame_set(scene.frame_start)
+ record_stage = RecordStage.RECORD
+
+ elif record_stage == RecordStage.RECORD:
+ current_time = time.perf_counter()
+ scene = bpy.context.scene
+ if scene.frame_current == scene.frame_end:
+ playback_iteration += 1
+
+ if playback_iteration >= RECORD_PLAYBACK_ITER:
+ stop_record_time = current_time
+ record_stage = RecordStage.FINISHED
+
+ elif record_stage == RecordStage.FINISHED:
+ bpy.ops.screen.animation_cancel()
+ num_frames = RECORD_PLAYBACK_ITER * ((scene.frame_end - scene.frame_start) + 1)
+ elapse_seconds = stop_record_time - start_record_time
+ avg_frame_time = elapse_seconds / num_frames
+ fps = 1.0 / avg_frame_time
+ print(f"{LOG_KEY}{{'time': {avg_frame_time}, 'fps': {fps} }}")
+ bpy.app.handlers.frame_change_post.remove(frame_change_handler)
+ bpy.ops.wm.quit_blender()
+
+
+if __name__ == '__main__':
+ _run(None)
+
+else:
+ import api
+
+ class EeveeTest(api.Test):
+ def __init__(self, filepath):
+ self.filepath = filepath
+
+ def name(self):
+ return self.filepath.stem
+
+ def category(self):
+ return "eevee"
+
+ def run(self, env, device_id):
+ args = {}
+ _, log = env.run_in_blender(_run, args, [self.filepath], foreground=True)
+ for line in log:
+ if line.startswith(LOG_KEY):
+ result_str = line[len(LOG_KEY):]
+ result = eval(result_str)
+ return result
+
+ raise Exception("No playback performance result found in log.")
+
+ def generate(env):
+ filepaths = env.find_blend_files('eevee/*')
+ return [EeveeTest(filepath) for filepath in filepaths]
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 38c3fc4389a..d95f2cd2644 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -102,6 +102,11 @@ add_blender_test(
)
add_blender_test(
+ script_pyapi_bpy_driver_secure_eval
+ --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_bpy_driver_secure_eval.py
+)
+
+add_blender_test(
script_pyapi_idprop
--python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_idprop.py
)
diff --git a/tests/python/alembic_export_tests.py b/tests/python/alembic_export_tests.py
index f6c05d955c9..95ae3ee9feb 100644
--- a/tests/python/alembic_export_tests.py
+++ b/tests/python/alembic_export_tests.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Alembic Export Tests
diff --git a/tests/python/batch_import.py b/tests/python/batch_import.py
index a6b44bc7478..811b070b0ca 100644
--- a/tests/python/batch_import.py
+++ b/tests/python/batch_import.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
Example Usage:
diff --git a/tests/python/bl_alembic_io_test.py b/tests/python/bl_alembic_io_test.py
index f3480380911..4cfda239bd1 100644
--- a/tests/python/bl_alembic_io_test.py
+++ b/tests/python/bl_alembic_io_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
./blender.bin --background -noaudio --factory-startup --python tests/python/bl_alembic_io_test.py -- --testdir /path/to/lib/tests/alembic
"""
diff --git a/tests/python/bl_animation_fcurves.py b/tests/python/bl_animation_fcurves.py
index 449f17ebfec..931db3f2d22 100644
--- a/tests/python/bl_animation_fcurves.py
+++ b/tests/python/bl_animation_fcurves.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
blender -b -noaudio --factory-startup --python tests/python/bl_animation_fcurves.py -- --testdir /path/to/lib/tests/animation
"""
diff --git a/tests/python/bl_blendfile_library_overrides.py b/tests/python/bl_blendfile_library_overrides.py
index 1acc1e4d862..3ba99bd61e4 100644
--- a/tests/python/bl_blendfile_library_overrides.py
+++ b/tests/python/bl_blendfile_library_overrides.py
@@ -181,9 +181,125 @@ class TestLibraryTemplate(TestHelper, unittest.TestCase):
assert(operation.operation == 'NOOP')
+class TestLibraryOverridesResync(TestHelper, unittest.TestCase):
+ DATA_NAME_CONTAINER = "LibCollection"
+ DATA_NAME_RIGGED = "LibRigged"
+ DATA_NAME_RIG = "LibRig"
+ DATA_NAME_CONTROLLER_1 = "LibController1"
+ DATA_NAME_CONTROLLER_2 = "LibController2"
+
+ def __init__(self, args):
+ self.args = args
+
+ output_dir = pathlib.Path(self.args.output_dir)
+ self.ensure_path(str(output_dir))
+ self.output_path = output_dir / "blendlib_overrides.blend"
+ self.test_output_path = output_dir / "blendlib_overrides_test.blend"
+
+ bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True)
+
+ collection_container = bpy.data.collections.new(TestLibraryOverridesResync.DATA_NAME_CONTAINER)
+ bpy.context.collection.children.link(collection_container)
+
+ mesh = bpy.data.meshes.new(TestLibraryOverridesResync.DATA_NAME_RIGGED)
+ obj_child = bpy.data.objects.new(TestLibraryOverridesResync.DATA_NAME_RIGGED, object_data=mesh)
+ collection_container.objects.link(obj_child)
+ armature = bpy.data.armatures.new(TestLibraryOverridesResync.DATA_NAME_RIG)
+ obj_armature = bpy.data.objects.new(TestLibraryOverridesResync.DATA_NAME_RIG, object_data=armature)
+ obj_child.parent = obj_armature
+ collection_container.objects.link(obj_armature)
+
+ obj_child_modifier = obj_child.modifiers.new("", 'ARMATURE')
+ obj_child_modifier.object = obj_armature
+
+ obj_ctrl1 = bpy.data.objects.new(TestLibraryOverridesResync.DATA_NAME_CONTROLLER_1, object_data=None)
+ collection_container.objects.link(obj_ctrl1)
+
+ obj_armature_constraint = obj_armature.constraints.new('COPY_LOCATION')
+ obj_armature_constraint.target = obj_ctrl1
+
+ collection_sub = bpy.data.collections.new(TestLibraryOverridesResync.DATA_NAME_CONTROLLER_2)
+ collection_container.children.link(collection_sub)
+ obj_ctrl2 = bpy.data.objects.new(TestLibraryOverridesResync.DATA_NAME_CONTROLLER_2, object_data=None)
+ collection_sub.objects.link(obj_ctrl2)
+
+ bpy.ops.wm.save_as_mainfile(filepath=str(self.output_path), check_existing=False, compress=False)
+
+ def test_link_and_override_resync(self):
+ bpy.ops.wm.read_homefile(use_empty=True, use_factory_startup=True)
+ bpy.data.orphans_purge()
+
+ link_dir = self.output_path / "Collection"
+ bpy.ops.wm.link(
+ directory=str(link_dir),
+ filename=TestLibraryOverridesResync.DATA_NAME_CONTAINER,
+ instance_collections=False,
+ )
+
+ linked_collection_container = bpy.data.collections[TestLibraryOverridesResync.DATA_NAME_CONTAINER]
+ assert(linked_collection_container.library is not None)
+ assert(linked_collection_container.override_library is None)
+ assert(len(bpy.data.collections) == 2)
+ assert(all(id_.library is not None for id_ in bpy.data.collections))
+ assert(len(bpy.data.objects) == 4)
+ assert(all(id_.library is not None for id_ in bpy.data.objects))
+ assert(len(bpy.data.meshes) == 1)
+ assert(all(id_.library is not None for id_ in bpy.data.meshes))
+ assert(len(bpy.data.armatures) == 1)
+ assert(all(id_.library is not None for id_ in bpy.data.armatures))
+
+ override_collection_container = linked_collection_container.override_hierarchy_create(
+ bpy.context.scene,
+ bpy.context.view_layer,
+ )
+ assert(override_collection_container.library is None)
+ assert(override_collection_container.override_library is not None)
+ # Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data.
+ assert(len(bpy.data.collections) == 4)
+ assert(all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:2]))
+ assert(len(bpy.data.objects) == 8)
+ assert(all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:4]))
+ assert(len(bpy.data.meshes) == 1)
+ assert(len(bpy.data.armatures) == 1)
+
+ bpy.ops.wm.save_as_mainfile(filepath=str(self.test_output_path), check_existing=False, compress=False)
+
+ # Re-open the lib file, and change its ID relationships.
+ bpy.ops.wm.open_mainfile(filepath=str(self.output_path))
+
+ obj_armature = bpy.data.objects[TestLibraryOverridesResync.DATA_NAME_RIG]
+ obj_armature_constraint = obj_armature.constraints[0]
+ obj_ctrl2 = bpy.data.objects[TestLibraryOverridesResync.DATA_NAME_CONTROLLER_2]
+ obj_armature_constraint.target = obj_ctrl2
+
+ bpy.ops.wm.save_as_mainfile(filepath=str(self.output_path), check_existing=False, compress=False)
+
+ # Re-open the main file, and check that automatic resync did its work correctly, remapping the target of the
+ # armature constraint to controller 2, without creating unexpected garbage IDs along the line.
+ bpy.ops.wm.open_mainfile(filepath=str(self.test_output_path))
+
+ override_collection_container = bpy.data.collections[TestLibraryOverridesResync.DATA_NAME_CONTAINER]
+ assert(override_collection_container.library is None)
+ assert(override_collection_container.override_library is not None)
+ # Objects and collections are duplicated as overrides, but meshes and armatures remain only linked data.
+ assert(len(bpy.data.collections) == 4)
+ assert(all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.collections[:2]))
+ assert(len(bpy.data.objects) == 8)
+ assert(all((id_.library is None and id_.override_library is not None) for id_ in bpy.data.objects[:4]))
+ assert(len(bpy.data.meshes) == 1)
+ assert(len(bpy.data.armatures) == 1)
+
+ obj_armature = bpy.data.objects[TestLibraryOverridesResync.DATA_NAME_RIG]
+ obj_ctrl2 = bpy.data.objects[TestLibraryOverridesResync.DATA_NAME_CONTROLLER_2]
+ assert(obj_armature.library is None and obj_armature.override_library is not None)
+ assert(obj_ctrl2.library is None and obj_ctrl2.override_library is not None)
+ assert(obj_armature.constraints[0].target == obj_ctrl2)
+
+
TESTS = (
TestLibraryOverrides,
TestLibraryTemplate,
+ TestLibraryOverridesResync,
)
diff --git a/tests/python/bl_bundled_modules.py b/tests/python/bl_bundled_modules.py
index 4a055960f83..7728a2deb47 100644
--- a/tests/python/bl_bundled_modules.py
+++ b/tests/python/bl_bundled_modules.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Test that modules we ship with our Python installation are available
import bz2
diff --git a/tests/python/bl_keymap_completeness.py b/tests/python/bl_keymap_completeness.py
index ee24a531f53..97335a94c01 100644
--- a/tests/python/bl_keymap_completeness.py
+++ b/tests/python/bl_keymap_completeness.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# simple script to test 'bl_keymap_utils.keymap_hierarchy' contains correct values.
# Needed for 'bl_keymap_utils.keymap_hierarchy' which inspects tools.
diff --git a/tests/python/bl_keymap_validate.py b/tests/python/bl_keymap_validate.py
index b87eed0c0df..83d41c8a9f6 100644
--- a/tests/python/bl_keymap_validate.py
+++ b/tests/python/bl_keymap_validate.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# ./blender.bin --background -noaudio --factory-startup --python tests/python/bl_keymap_validate.py
#
diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py
index 8fee31f7a2b..b94c56541af 100644
--- a/tests/python/bl_load_addons.py
+++ b/tests/python/bl_load_addons.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# simple script to enable all addons, and disable
"""
diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py
index 4d4196d1f64..7ad5895ce86 100644
--- a/tests/python/bl_load_py_modules.py
+++ b/tests/python/bl_load_py_modules.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# simple script to enable all addons, and disable
"""
diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py
index 3b653402083..640cf1c30f2 100644
--- a/tests/python/bl_mesh_modifiers.py
+++ b/tests/python/bl_mesh_modifiers.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Currently this script only generates images from different modifier
# combinations and does not validate they work correctly,
# this is because we don't get 1:1 match with bmesh.
diff --git a/tests/python/bl_mesh_validate.py b/tests/python/bl_mesh_validate.py
index 9a9384ce777..9e093608406 100644
--- a/tests/python/bl_mesh_validate.py
+++ b/tests/python/bl_mesh_validate.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Simple script to check mash validate code.
# XXX Should be extended with many more "wrong cases"!
diff --git a/tests/python/bl_pyapi_bpy_driver_secure_eval.py b/tests/python/bl_pyapi_bpy_driver_secure_eval.py
new file mode 100644
index 00000000000..953dbcd5381
--- /dev/null
+++ b/tests/python/bl_pyapi_bpy_driver_secure_eval.py
@@ -0,0 +1,220 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_bpy_driver_secure_eval.py -- --verbose
+import bpy
+import unittest
+import builtins
+from types import ModuleType
+
+
+# -----------------------------------------------------------------------------
+# Mock Environment
+
+
+expect_unreachable_msg = "This function should _NEVER_ run!"
+# Internal check, to ensure this actually runs as expected.
+expect_unreachable_count = 0
+
+
+def expect_os_unreachable():
+ global expect_unreachable_count
+ expect_unreachable_count += 1
+ raise Exception(expect_unreachable_msg)
+
+
+__import__("os").expect_os_unreachable = expect_os_unreachable
+
+
+expect_open_unreachable_count = 0
+
+
+def open_expect_unreachable(*args, **kwargs):
+ global expect_open_unreachable_count
+ expect_open_unreachable_count += 1
+ raise Exception(expect_unreachable_msg)
+
+
+mock_builtins = {**builtins.__dict__, **{"open": open_expect_unreachable}}
+
+
+# -----------------------------------------------------------------------------
+# Utility Functions
+
+
+def is_expression_secure(expr_str, verbose):
+ """
+ Return (ok, code) where ok is true if expr_str is considered secure.
+ """
+ # Internal function only for testing (not part of the public API).
+ from _bpy import _driver_secure_code_test
+ expr_code = compile(expr_str, "<is_expression_secure>", 'eval')
+ ok = _driver_secure_code_test(expr_code, verbose=verbose)
+ return ok, expr_code
+
+
+# -----------------------------------------------------------------------------
+# Tests (Accept)
+
+
+class _TestExprMixIn:
+ """
+ Sub-classes must define:
+ - expressions_expect_secure: boolean, the expected secure state.
+ - expressions: A sequence of expressions that must evaluate in the driver name-space.
+
+ Optionally:
+ - expressions_expect_unreachable:
+ A boolean, when true, it's expected each expression should call
+ ``expect_os_unreachable`` or ``expect_open_unreachable``.
+ """
+
+ # Sub-class may override.
+ expressions_expect_unreachable = False
+
+ def assertSecure(self, expect_secure, expr_str):
+ is_secure, expr_code = is_expression_secure(
+ expr_str,
+ # Only verbose when secure as this is will result in an failure,
+ # in that case it's useful to know which op-codes caused the test to unexpectedly fail.
+ verbose=expect_secure,
+ )
+ if is_secure != expect_secure:
+ raise self.failureException(
+ "Expression \"%s\" was expected to be %s" %
+ (expr_str, "secure" if expect_secure else "insecure"))
+ # NOTE: executing is not essential, it's just better to ensure the expressions make sense.
+ try:
+ exec(
+ expr_code,
+ {"__builtins__": mock_builtins},
+ {**bpy.app.driver_namespace, **{"__builtins__": mock_builtins}},
+ )
+ # exec(expr_code, {}, bpy.app.driver_namespace)
+ ex = None
+ except BaseException as ex_test:
+ ex = ex_test
+
+ if self.expressions_expect_unreachable:
+ if ex and ex.args == (expect_unreachable_msg,):
+ ex = None
+ elif not ex:
+ raise self.failureException("Expression \"%s\" failed to run `os.expect_os_unreachable`" % (expr_str,))
+ else:
+ # An unknown exception was raised, use the exception below.
+ pass
+
+ if ex:
+ raise self.failureException("Expression \"%s\" failed to evaluate with error: %r" % (expr_str, ex))
+
+ def test_expr(self):
+ expect_secure = self.expressions_expect_secure
+ for expr_str in self.expressions:
+ self.assertSecure(expect_secure, expr_str)
+
+
+class TestExprMixIn_Accept(_TestExprMixIn):
+ expressions_expect_secure = True
+
+
+class TestExprMixIn_Reject(_TestExprMixIn):
+ expressions_expect_secure = False
+
+
+class TestAcceptLiteralNumbers(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("1", "1_1", "1.1", "1j", "0x1", "0o1", "0b1")
+
+
+class TestAcceptLiteralStrings(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("''", "'_'", "r''", "r'_'", "'''_'''")
+
+
+class TestAcceptSequencesEmpty(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("()", "[]", "{}", "[[]]", "(())")
+
+
+class TestAcceptSequencesSimple(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("('', '')", "['', '_']", "{'', '_'}", "{'': '_'}")
+
+
+class TestAcceptSequencesExpand(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("(*('', '_'),)", "[*(), *[]]", "{*{1, 2}}")
+
+
+class TestAcceptSequencesComplex(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("[1, 2, 3][-1:0:-1][0]", "1 in (1, 2)", "False if 1 in {1, 2} else True")
+
+
+class TestAcceptMathOperators(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("4 / 4", "4 * 4", "4 // 4", "2 ** 2", "4 ^ -1", "4 & 1", "4 % 1")
+
+
+class TestAcceptMathFunctionsSimple(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("sin(pi)", "degrees(pi / 2)", "clamp(4, 0, 1)")
+
+
+class TestAcceptMathFunctionsComplex(unittest.TestCase, TestExprMixIn_Accept):
+ expressions = ("-(sin(pi) ** 2) / 2", "floor(22 / 7)", "ceil(pi + 1)")
+
+
+# -----------------------------------------------------------------------------
+# Tests (Reject)
+
+class TestRejectLiteralFStrings(unittest.TestCase, TestExprMixIn_Reject):
+ # F-String's are not supported as `BUILD_STRING` op-code is disabled,
+ # while it may be safe to enable that needs to be double-checked.
+ # Further it doesn't seem useful for typical math expressions used in drivers.
+ expressions = ("f''", "f'{1}'", "f'{\"_\"}'")
+
+
+class TestRejectModuleAccess(unittest.TestCase, TestExprMixIn_Reject):
+ # Each of these commands _must_ run `expect_os_unreachable`,
+ # and must also be rejected as insecure - otherwise we have problems.
+ expressions_expect_unreachable = True
+ expressions = (
+ "__import__('os').expect_os_unreachable()",
+ "exec(\"__import__('os').expect_os_unreachable()\")",
+ "(globals().update(__import__('os').__dict__), expect_os_unreachable())",
+ )
+
+ # Ensure the functions are actually called.
+ def setUp(self):
+ self._count = expect_unreachable_count
+
+ def tearDown(self):
+ count_actual = expect_unreachable_count - self._count
+ count_expect = len(self.expressions)
+ if count_actual != count_expect:
+ raise Exception(
+ "Expected 'os.expect_os_unreachable' to be called %d times but was called %d times" %
+ (count_expect, count_actual),
+ )
+
+
+class TestRejectOpenAccess(unittest.TestCase, TestExprMixIn_Reject):
+ # Each of these commands _must_ run `expect_open_unreachable`,
+ # and must also be rejected as insecure - otherwise we have problems.
+ expressions_expect_unreachable = True
+ expressions = (
+ "open('file.txt', 'r')",
+ "exec(\"open('file.txt', 'r')\")",
+ "(globals().update({'fake_open': __builtins__['open']}), fake_open())",
+ )
+
+ # Ensure the functions are actually called.
+ def setUp(self):
+ self._count = expect_open_unreachable_count
+
+ def tearDown(self):
+ count_actual = expect_open_unreachable_count - self._count
+ count_expect = len(self.expressions)
+ if count_actual != count_expect:
+ raise Exception(
+ "Expected 'open' to be called %d times but was called %d times" %
+ (count_expect, count_actual),
+ )
+
+
+if __name__ == '__main__':
+ import sys
+ sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
+ unittest.main()
diff --git a/tests/python/bl_rigging_symmetrize.py b/tests/python/bl_rigging_symmetrize.py
index 6531b4df85f..10ba99ac6e9 100644
--- a/tests/python/bl_rigging_symmetrize.py
+++ b/tests/python/bl_rigging_symmetrize.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
"""
blender -b -noaudio --factory-startup --python tests/python/bl_rigging_symmetrize.py -- --testdir /path/to/lib/tests/animation
"""
@@ -42,7 +40,7 @@ def check_loc_rot_scale(self, bone, exp_bone):
def check_parent(self, bone, exp_bone):
self.assertEqual(type(bone.parent), type(exp_bone.parent),
- "Missmatching types in pose.bones[%s].parent" % (bone.name))
+ "Mismatching types in pose.bones[%s].parent" % (bone.name))
self.assertTrue(bone.parent is None or bone.parent.name == exp_bone.parent.name,
"Bone parent does not match on bone %s" % (bone.name))
@@ -58,17 +56,17 @@ def check_bendy_bones(self, bone, exp_bone):
exp_value = getattr(exp_bone, var)
self.assertEqual(type(value), type(exp_value),
- "Missmatching types in pose.bones[%s].%s" % (bone.name, var))
+ "Mismatching types in pose.bones[%s].%s" % (bone.name, var))
if isinstance(value, str):
self.assertEqual(value, exp_value,
- "Missmatching value in pose.bones[%s].%s" % (bone.name, var))
+ "Mismatching value in pose.bones[%s].%s" % (bone.name, var))
elif hasattr(value, "name"):
self.assertEqual(value.name, exp_value.name,
- "Missmatching value in pose.bones[%s].%s" % (bone.name, var))
+ "Mismatching value in pose.bones[%s].%s" % (bone.name, var))
else:
self.assertAlmostEqual(value, exp_value,
- "Missmatching value in pose.bones[%s].%s" % (bone.name, var))
+ "Mismatching value in pose.bones[%s].%s" % (bone.name, var))
def check_ik(self, bone, exp_bone):
@@ -83,7 +81,7 @@ def check_ik(self, bone, exp_bone):
value = getattr(bone, var)
exp_value = getattr(exp_bone, var)
self.assertAlmostEqual(value, exp_value,
- "Missmatching value in pose.bones[%s].%s" % (bone.name, var))
+ "Mismatching value in pose.bones[%s].%s" % (bone.name, var))
def check_constraints(self, input_arm, expected_arm, bone, exp_bone):
@@ -91,7 +89,7 @@ def check_constraints(self, input_arm, expected_arm, bone, exp_bone):
expo_const_len = len(exp_bone.constraints)
self.assertEqual(const_len, expo_const_len,
- "Constraints missmatch on bone %s" % (bone.name))
+ "Constraints mismatch on bone %s" % (bone.name))
for exp_constraint in exp_bone.constraints:
const_name = exp_constraint.name
@@ -113,28 +111,28 @@ def check_constraints(self, input_arm, expected_arm, bone, exp_bone):
exp_value = getattr(exp_constraint, var)
self.assertEqual(type(value), type(exp_value),
- "Missmatching constraint value types in pose.bones[%s].constraints[%s].%s" % (
+ "Mismatching constraint value types in pose.bones[%s].constraints[%s].%s" % (
bone.name, const_name, var))
if isinstance(value, str):
self.assertEqual(value, exp_value,
- "Missmatching constraint value in pose.bones[%s].constraints[%s].%s" % (
+ "Mismatching constraint value in pose.bones[%s].constraints[%s].%s" % (
bone.name, const_name, var))
elif hasattr(value, "name"):
- # Some constraints targets the armature itself, so the armature name should missmatch.
+ # Some constraints targets the armature itself, so the armature name should mismatch.
if value.name == input_arm.name and exp_value.name == expected_arm.name:
continue
self.assertEqual(value.name, exp_value.name,
- "Missmatching constraint value in pose.bones[%s].constraints[%s].%s" % (
+ "Mismatching constraint value in pose.bones[%s].constraints[%s].%s" % (
bone.name, const_name, var))
elif isinstance(value, bool):
self.assertEqual(value, exp_value,
- "Missmatching constraint boolean in pose.bones[%s].constraints[%s].%s" % (
+ "Mismatching constraint boolean in pose.bones[%s].constraints[%s].%s" % (
bone.name, const_name, var))
else:
- msg = "Missmatching constraint value in pose.bones[%s].constraints[%s].%s" % (
+ msg = "Mismatching constraint value in pose.bones[%s].constraints[%s].%s" % (
bone.name, const_name, var)
self.assertAlmostEqual(value, exp_value, places=6, msg=msg)
diff --git a/tests/python/bl_rna_manual_reference.py b/tests/python/bl_rna_manual_reference.py
index 70f218f0bb2..257c8b7601a 100644
--- a/tests/python/bl_rna_manual_reference.py
+++ b/tests/python/bl_rna_manual_reference.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Use for validating our manual interlinking.
# ./blender.bin --background -noaudio --python tests/python/bl_rna_manual_reference.py
#
diff --git a/tests/python/bl_rst_completeness.py b/tests/python/bl_rst_completeness.py
index 59e532c433b..4846e65b78f 100644
--- a/tests/python/bl_rst_completeness.py
+++ b/tests/python/bl_rst_completeness.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# run this script in the game engine.
# or on the command line with...
# ./blender.bin --background -noaudio --python tests/python/bl_rst_completeness.py
diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py
index 7e73ec163a4..a2478bd7547 100644
--- a/tests/python/bl_run_operators.py
+++ b/tests/python/bl_run_operators.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# semi-useful script, runs all operators in a number of different
# contexts, cheap way to find misc small bugs but is in no way a complete test.
#
diff --git a/tests/python/bl_run_operators_event_simulate.py b/tests/python/bl_run_operators_event_simulate.py
index 56f96847d0b..d218e6b1bc0 100644
--- a/tests/python/bl_run_operators_event_simulate.py
+++ b/tests/python/bl_run_operators_event_simulate.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
r"""
Overview
========
diff --git a/tests/python/bl_test.py b/tests/python/bl_test.py
index 7e79639a226..b71ebd2a7a7 100644
--- a/tests/python/bl_test.py
+++ b/tests/python/bl_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import sys
import os
diff --git a/tests/python/bl_usd_import_test.py b/tests/python/bl_usd_import_test.py
index 1ba9b4f1edf..95b2328b2aa 100644
--- a/tests/python/bl_usd_import_test.py
+++ b/tests/python/bl_usd_import_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import pathlib
import sys
import unittest
diff --git a/tests/python/boolean_operator.py b/tests/python/boolean_operator.py
index fed0b2bddfd..8b93226ab93 100644
--- a/tests/python/boolean_operator.py
+++ b/tests/python/boolean_operator.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# To run all tests, use
# BLENDER_VERBOSE=1 blender path/to/bool_regression.blend --python path/to/boolean_operator.py -- --run-all-tests
# To run one test, use
diff --git a/tests/python/deform_modifiers.py b/tests/python/deform_modifiers.py
index 40cd9d4839c..e5be133a3ef 100644
--- a/tests/python/deform_modifiers.py
+++ b/tests/python/deform_modifiers.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# To run the test type: blender -b /path/to/the/blend/file --python path/to/this/py/file -- --run-all-tests -- --verbose
# Type the above line in cmd/terminal, for example, look below
# blender -b c:\blender-lib\deform_modifiers.blend --python c:\deform_modifiers.py -- --run-all-tests -- --verbose
diff --git a/tests/python/eevee_render_tests.py b/tests/python/eevee_render_tests.py
index 8c6f08ae76e..68895291044 100644
--- a/tests/python/eevee_render_tests.py
+++ b/tests/python/eevee_render_tests.py
@@ -7,6 +7,7 @@ import shlex
import shutil
import subprocess
import sys
+from pathlib import Path
def setup():
@@ -138,6 +139,11 @@ def main():
report.set_pixelated(True)
report.set_reference_dir("eevee_renders")
report.set_compare_engine('cycles', 'CPU')
+
+ test_dir_name = Path(test_dir).name
+ if test_dir_name.startswith('image'):
+ report.set_fail_threshold(0.051)
+
ok = report.run(test_dir, blender, get_arguments, batch=True)
sys.exit(not ok)
diff --git a/tests/python/ffmpeg_tests.py b/tests/python/ffmpeg_tests.py
index abbe38193b5..b40b8030f7e 100644
--- a/tests/python/ffmpeg_tests.py
+++ b/tests/python/ffmpeg_tests.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import argparse
import pathlib
import sys
diff --git a/tests/python/geo_node_test.py b/tests/python/geo_node_test.py
index 9d7c634db76..0842dd001da 100644
--- a/tests/python/geo_node_test.py
+++ b/tests/python/geo_node_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/modifiers.py b/tests/python/modifiers.py
index 8f8b5c6498c..11d696c3bed 100644
--- a/tests/python/modifiers.py
+++ b/tests/python/modifiers.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import math
import os
import sys
@@ -215,7 +213,6 @@ def main():
SpecMeshTest("MergedNoneWeld", "testMergedNoneWeld", "expectedMergedNoneWeld",
[ModifierSpec("weld", 'WELD', {"merge_threshold": 0.019})]),
-
#############################################
# One 'Deform' modifier on primitive meshes
#############################################
@@ -327,6 +324,22 @@ def main():
]
+ boolean_basename = "CubeBooleanDiffBMeshObject"
+ tests.append(SpecMeshTest("BooleandDiffBMeshObject", "test" + boolean_basename, "expected" + boolean_basename,
+ [ModifierSpec("boolean", 'BOOLEAN',
+ {"solver": 'FAST', "operation": 'DIFFERENCE', "operand_type": 'OBJECT',
+ "object": bpy.data.objects["test" + boolean_basename + "Operand"]})]))
+ boolean_basename = "CubeBooleanDiffBMeshCollection"
+ tests.append(SpecMeshTest("BooleandDiffBMeshCollection",
+ "test" + boolean_basename,
+ "expected" + boolean_basename,
+ [ModifierSpec("boolean",
+ 'BOOLEAN',
+ {"solver": 'FAST',
+ "operation": 'DIFFERENCE',
+ "operand_type": 'COLLECTION',
+ "collection": bpy.data.collections["test" + boolean_basename + "Operands"]})]))
+
modifiers_test = RunTest(tests)
command = list(sys.argv)
diff --git a/tests/python/modules/mesh_test.py b/tests/python/modules/mesh_test.py
index 873ab779d65..5b01bfeee94 100644
--- a/tests/python/modules/mesh_test.py
+++ b/tests/python/modules/mesh_test.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# A framework to run regression tests on mesh modifiers and operators based on howardt's mesh_ops_test.py
#
# General idea:
diff --git a/tests/python/modules/render_report.py b/tests/python/modules/render_report.py
index cae81af3144..15441918800 100755
--- a/tests/python/modules/render_report.py
+++ b/tests/python/modules/render_report.py
@@ -253,8 +253,11 @@ class Report:
failed = len(failed_tests) > 0
if failed:
message = """<div class="alert alert-danger" role="alert">"""
- message += """Run this command to update reference images for failed tests, or create images for new tests:<br>"""
- message += """<tt>BLENDER_TEST_UPDATE=1 ctest -R %s</tt>""" % self.title.lower()
+ message += """<p>Run this command to regenerate reference (ground truth) images:</p>"""
+ message += """<p><tt>BLENDER_TEST_UPDATE=1 ctest -R %s</tt></p>""" % self.title.lower()
+ message += """<p>This then happens for new and failing tests; reference images of """ \
+ """passing test cases will not be updated. Be sure to commit the new reference """ \
+ """images to the SVN repository afterwards.</p>"""
message += """</div>"""
else:
message = ""
@@ -294,6 +297,7 @@ class Report:
background-position:0 0, 25px 0, 25px -25px, 0px 25px;
}}
table td:first-child {{ width: 256px; }}
+ p {{ margin-bottom: 0.5rem; }}
</style>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
diff --git a/tests/python/modules/test_utils.py b/tests/python/modules/test_utils.py
index d5cd743cde9..6aba3a75263 100755
--- a/tests/python/modules/test_utils.py
+++ b/tests/python/modules/test_utils.py
@@ -1,8 +1,6 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import functools
import shutil
import pathlib
diff --git a/tests/python/operators.py b/tests/python/operators.py
index 6ccc96dba5d..548a2b50b05 100644
--- a/tests/python/operators.py
+++ b/tests/python/operators.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import bpy
import os
import sys
diff --git a/tests/python/pep8.py b/tests/python/pep8.py
index 9a2871c9ed5..2583bec8256 100644
--- a/tests/python/pep8.py
+++ b/tests/python/pep8.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8-80 compliant>
-
import os
import subprocess
import shutil
@@ -22,7 +20,6 @@ import shutil
# how many lines to read into the file, pep8 comment
# should be directly after the license header, ~20 in most cases
-PEP8_SEEK_COMMENT = 40
SKIP_PREFIX = "./tools", "./config", "./extern"
SKIP_ADDONS = True
FORCE_PEP8_ALL = False
@@ -39,22 +36,8 @@ def is_pep8(path):
print(path)
if open(path, 'rb').read(3) == b'\xef\xbb\xbf':
print("\nfile contains BOM, remove first 3 bytes: %r\n" % path)
-
- # templates don't have a header but should be pep8
- for d in ("presets", "templates_py", "examples"):
- if ("%s%s%s" % (os.sep, d, os.sep)) in path:
- return 1
-
- f = open(path, 'r', encoding="utf8")
- for _ in range(PEP8_SEEK_COMMENT):
- line = f.readline()
- if line.startswith("# <pep8"):
- if line.startswith("# <pep8 compliant>"):
- return 1
- elif line.startswith("# <pep8-80 compliant>"):
- return 2
- f.close()
- return 0
+ # Currently all scripts assumed to be pep8.
+ return 1
def check_files_flake8(files):
diff --git a/tests/python/physics_cloth.py b/tests/python/physics_cloth.py
index e453b4dd68b..fbd33392371 100644
--- a/tests/python/physics_cloth.py
+++ b/tests/python/physics_cloth.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/physics_dynamic_paint.py b/tests/python/physics_dynamic_paint.py
index 57b96ccffba..132c7b8c46d 100644
--- a/tests/python/physics_dynamic_paint.py
+++ b/tests/python/physics_dynamic_paint.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/physics_ocean.py b/tests/python/physics_ocean.py
index 20d563f782b..54cf8d65a9d 100644
--- a/tests/python/physics_ocean.py
+++ b/tests/python/physics_ocean.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/physics_particle_instance.py b/tests/python/physics_particle_instance.py
index 353c0d868c8..3cd52fd9fa0 100644
--- a/tests/python/physics_particle_instance.py
+++ b/tests/python/physics_particle_instance.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/physics_particle_system.py b/tests/python/physics_particle_system.py
index 37e3df781b0..51afae68a7b 100644
--- a/tests/python/physics_particle_system.py
+++ b/tests/python/physics_particle_system.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
import bpy
diff --git a/tests/python/physics_softbody.py b/tests/python/physics_softbody.py
index 00d2a637cf7..ebb9fbb724f 100644
--- a/tests/python/physics_softbody.py
+++ b/tests/python/physics_softbody.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
import os
import sys
diff --git a/tests/python/rna_info_dump.py b/tests/python/rna_info_dump.py
index afedf670f2f..af00ef54de9 100644
--- a/tests/python/rna_info_dump.py
+++ b/tests/python/rna_info_dump.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Used for generating API diffs between releases
# ./blender.bin --background -noaudio --python tests/python/rna_info_dump.py
diff --git a/tests/python/rst_to_doctree_mini.py b/tests/python/rst_to_doctree_mini.py
index 3466c915aa0..43116922fe5 100644
--- a/tests/python/rst_to_doctree_mini.py
+++ b/tests/python/rst_to_doctree_mini.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-or-later
-# <pep8 compliant>
-
# Module with function to extract a doctree from an reStructuredText file.
# Named 'Mini' because we only parse the minimum data needed to check
# Python classes, methods and attributes match up to those in existing modules.
diff --git a/tests/python/workbench_render_tests.py b/tests/python/workbench_render_tests.py
index 3ceb0fb3226..e182b2a41e2 100644
--- a/tests/python/workbench_render_tests.py
+++ b/tests/python/workbench_render_tests.py
@@ -3,10 +3,12 @@
import argparse
import os
+import platform
import shlex
import shutil
import subprocess
import sys
+from pathlib import Path
def setup():
@@ -73,6 +75,11 @@ def main():
report.set_pixelated(True)
report.set_reference_dir("workbench_renders")
report.set_compare_engine('eevee')
+
+ test_dir_name = Path(test_dir).name
+ if test_dir_name.startswith('hair') and platform.system() == "Darwin":
+ report.set_fail_threshold(0.050)
+
ok = report.run(test_dir, blender, get_arguments, batch=True)
sys.exit(not ok)